OSDN Git Service

[VM][PC8801][PC9801][UI][I8251][UPD765A] Merge upstream 2022-11-14 .
[csp-qt/common_source_project-fm7.git] / source / src / vm / pc8801 / pc8801.cpp
1
2 /*
3         NEC PC-8001 Emulator 'ePC-8001'
4         NEC PC-8001mkII Emulator 'ePC-8001mkII'
5         NEC PC-8001mkIISR Emulator 'ePC-8001mkIISR'
6         NEC PC-8801 Emulator 'ePC-8801'
7         NEC PC-8801mkII Emulator 'ePC-8801mkII'
8         NEC PC-8801MA Emulator 'ePC-8801MA'
9
10         Author : Takeda.Toshiya
11         Date   : 2012.02.16-
12
13         [ virtual machine ]
14 */
15
16 #include "pc8801.h"
17 #include "../../emu.h"
18 #include "../device.h"
19 #include "../event.h"
20
21 #include "../i8251.h"
22 #include "../i8255.h"
23 #include "../pcm1bit.h"
24 //#include "../pcpr201.h"
25 #include "../prnfile.h"
26 #include "../upd1990a.h"
27 #if defined(SUPPORT_PC88_OPN1) || defined(SUPPORT_PC88_OPN2)
28 #include "../ym2203.h"
29 #endif
30 #include "../z80.h"
31
32 #include "../disk.h"
33 #include "../noise.h"
34 #include "../pc80s31k.h"
35 #include "../upd765a.h"
36
37 #ifdef USE_DEBUGGER
38 #include "../debugger.h"
39 #endif
40
41 #ifdef SUPPORT_PC88_CDROM
42 #include "../scsi_cdrom.h"
43 #include "../scsi_host.h"
44 #endif
45
46 #ifdef SUPPORT_PC88_HMB20
47 #include "../ym2151.h"
48 #endif
49
50 #ifdef SUPPORT_PC88_GSX8800
51 #include "../ay_3_891x.h"
52 #endif
53
54 #if defined(SUPPORT_PC88_GSX8800) || defined(SUPPORT_PC88_PCG8100) || defined(SUPPORT_PC88_16BIT)
55 #include "../i8253.h"
56 #endif
57
58 #ifdef SUPPORT_PC88_JAST
59 #include "../pcm8bit.h"
60 #endif
61
62 #if defined(SUPPORT_PC88_16BIT)
63 #include "../i8259.h"
64 #include "../i86.h"
65 #include "../io.h"
66 #include "../memory.h"
67 #endif
68
69 #ifdef SUPPORT_M88_DISKDRV
70 #include "diskio.h"
71 #endif
72
73 #include "pc88.h"
74
75 using PC88DEV::PC88;
76 #ifdef SUPPORT_M88_DISKDRV
77 using PC88DEV::DiskIO;
78 #endif
79 // ----------------------------------------------------------------------------
80 // initialize
81 // ----------------------------------------------------------------------------
82
83 VM::VM(EMU_TEMPLATE* parent_emu) : VM_TEMPLATE(parent_emu)
84 {
85         // check configs
86 #if defined(PC8001_VARIANT)
87 #if defined(_PC8001)
88         if(config.boot_mode != MODE_PC80_N) {
89                 config.boot_mode = MODE_PC80_N;
90         }
91         // 8inch floppy drives are not supported
92         config.dipswitch &= ~DIPSWITCH_FDD_8INCH;
93 #elif defined(_PC8001MK2)
94         if(config.boot_mode == MODE_PC80_V2) {
95                 config.boot_mode = MODE_PC80_V1;
96         }
97 #endif
98 #else
99 #if !defined(PC8801SR_VARIANT)
100         if(config.boot_mode == MODE_PC88_V1H || config.boot_mode == MODE_PC88_V2 || config.boot_mode == MODE_PC88_V2CD) {
101                 config.boot_mode = MODE_PC88_V1S;
102         }
103 #endif
104 #if defined(_PC8801MK2) || defined(PC8801SR_VARIANT)
105         // 5inch floppy drives are always existing
106         config.dipswitch |= DIPSWITCH_FDD_5INCH;
107 #endif
108 #endif
109         boot_mode = config.boot_mode;
110
111         // create devices
112         first_device = last_device = NULL;
113         dummy = new DEVICE(this, emu);  // must be 1st device
114
115         pc88event = new EVENT(this, emu);
116
117         pc88 = new PC88(this, emu);
118         pc88sio = new I8251(this, emu);
119         pc88pio = new I8255(this, emu);
120         pc88pcm = new PCM1BIT(this, emu);
121 #ifdef USE_DEBUGGER
122 //      pc88pcm->set_context_debugger(new DEBUGGER(this, emu));
123 #endif
124         pc88rtc = new UPD1990A(this, emu);
125 //      pc88rtc->set_device_name(_T("uPD1990A RTC (PC-8801)"));
126 //      pc88rtc->set_context_event_manager(pc88event);
127         if(config.printer_type == 0) {
128                 pc88prn = new PRNFILE(this, emu);
129 //              pc88prn->set_context_event_manager(pc88event);
130 //      } else if(config.printer_type == 1) {
131 //              pc88prn = new PCPR201(this, emu);
132 //              pc88prn->set_context_event_manager(pc88event);
133 #ifdef SUPPORT_PC88_JAST
134         } else if(config.printer_type == 2) {
135                 pc88prn = new PCM8BIT(this, emu);
136 //              pc88prn->set_context_event_manager(pc88event);
137 #endif
138         } else {
139                 pc88prn = dummy;
140         }
141         pc88cpu = new Z80(this, emu);
142 //      pc88cpu->set_context_event_manager(pc88event);
143
144         if(config.dipswitch & DIPSWITCH_FDD_5INCH) {
145                 pc88sub = new PC80S31K(this, emu);
146                 pc88sub->set_device_name(_T("PC-80S31K (Sub)"));
147 //              pc88sub->set_context_event_manager(pc88event);
148                 pc88pio_sub = new I8255(this, emu);
149                 pc88pio_sub->set_device_name(_T("8255 PIO (Sub)"));
150 //              pc88pio_sub->set_context_event_manager(pc88event);
151                 pc88fdc_sub = new UPD765A(this, emu);
152                 pc88fdc_sub->set_device_name(_T("uPD765A FDC (Sub)"));
153 //              pc88fdc_sub->set_context_event_manager(pc88event);
154                 pc88noise_seek = new NOISE(this, emu);
155 //              pc88noise_seek->set_context_event_manager(pc88event);
156                 pc88noise_head_down = new NOISE(this, emu);
157 //              pc88noise_head_down->set_context_event_manager(pc88event);
158                 pc88noise_head_up = new NOISE(this, emu);
159 //              pc88noise_head_up->set_context_event_manager(pc88event);
160                 pc88cpu_sub = new Z80(this, emu);
161                 pc88cpu_sub->set_device_name(_T("Z80 CPU (Sub)"));
162 //              pc88cpu_sub->set_context_event_manager(pc88event);
163         } else {
164                 pc88sub = NULL;
165                 pc88pio_sub = NULL;
166                 pc88fdc_sub = NULL;
167                 pc88noise_seek = pc88noise_head_down = pc88noise_head_up = NULL;
168                 pc88cpu_sub = NULL;
169         }
170 #ifdef SUPPORT_PC88_FDD_8INCH
171         if(config.dipswitch & DIPSWITCH_FDD_8INCH) {
172                 pc88fdc_8inch = new UPD765A(this, emu);
173                 pc88fdc_8inch->set_device_name(_T("uPD765A FDC (8inch)"));
174 //              pc88fdc_8inch->set_context_event_manager(pc88event);
175                 pc88noise_8inch_seek = new NOISE(this, emu);
176 //              pc88noise_8inch_seek->set_context_event_manager(pc88event);
177                 pc88noise_8inch_head_down = new NOISE(this, emu);
178 //              pc88noise_8inch_head_down->set_context_event_manager(pc88event);
179                 pc88noise_8inch_head_up = new NOISE(this, emu);
180 //              pc88noise_8inch_head_up->set_context_event_manager(pc88event);
181         } else {
182                 pc88fdc_8inch = NULL;
183                 pc88noise_8inch_seek = pc88noise_8inch_head_down = pc88noise_8inch_head_up = NULL;
184         }
185 #endif
186 #ifdef SUPPORT_PC88_CDROM
187         pc88scsi_host = new SCSI_HOST(this, emu);
188 //      pc88scsi_host->set_context_event_manager(pc88event);
189         pc88scsi_cdrom = new SCSI_CDROM(this, emu);
190 //      pc88scsi_cdrom->set_context_event_manager(pc88event);
191 #endif
192 #if defined(_PC8801MA)
193         // config.sound_type
194         //      0: 44h:OPNA A4h:None            PC-8801FH/MH or later
195         //      1: 44h:OPN  A4h:None            PC-8801mkIISR/TR/FR/MR
196         //      2: 44h:OPN  A4h:OPNA            PC-8801mkIISR/TR/FR/MR + PC-8801-23
197         //      3: 44h:OPN  A4h:OPN             PC-8801mkIISR/TR/FR/MR + PC-8801-11
198         //      4: 44h:OPNA A4h:OPNA            PC-8801FH/MH or later  + PC-8801-24
199         //      5: 44h:OPNA A4h:OPN             PC-8801FH/MH or later  + PC-8801-11
200         pc88opn1 = new YM2203(this, emu);
201         if(config.sound_type == 0 || config.sound_type == 4 || config.sound_type == 5) {
202                 pc88opn1->is_ym2608 = true;
203                 pc88opn1->set_device_name(_T("YM2608 OPNA #1"));
204         } else {
205                 pc88opn1->is_ym2608 = false;
206                 pc88opn1->set_device_name(_T("YM2203 OPN #1"));
207         }
208         if(config.sound_type >= 2) {
209                 pc88opn2 = new YM2203(this, emu);
210                 if(config.sound_type == 2 || config.sound_type == 4) {
211                         pc88opn2->is_ym2608 = true;
212                         pc88opn2->set_device_name(_T("YM2608 OPNA #2"));
213                 } else if(config.sound_type == 3 || config.sound_type == 5) {
214                         pc88opn2->is_ym2608 = false;
215                         pc88opn2->set_device_name(_T("YM2203 OPN #2"));
216                 }
217         } else {
218                 pc88opn2 = NULL;
219         }
220 #elif defined(_PC8001SR)
221         // config.sound_type
222         //      0: 44h:OPN  A4h:None            PC-8001mkIISR
223         //      1: 44h:OPN  A4h:OPN             PC-8001mkIISR + PC-8801-11
224         pc88opn1 = new YM2203(this, emu);
225         pc88opn1->is_ym2608 = false;
226         pc88opn1->set_device_name(_T("YM2203 OPN #1"));
227         if(config.sound_type == 1) {
228                 pc88opn2 = new YM2203(this, emu);
229 //              pc88opn2->set_context_event_manager(pc88event);
230                 pc88opn2->is_ym2608 = false;
231                 pc88opn2->set_device_name(_T("YM2203 OPN #2"));
232         } else {
233                 pc88opn2 = NULL;
234         }
235 #elif defined(_PC8001MK2) || defined(_PC8801) || defined(_PC8801MK2)
236         //      0: 44h:None A4h:None            PC-8001mkII
237         //      1: 44h:None A4h:OPN             PC-8001mkII + PC-8801-11
238         if(config.sound_type == 1) {
239                 pc88opn2 = new YM2203(this, emu);
240                 pc88opn2->is_ym2608 = false;
241                 pc88opn2->set_device_name(_T("YM2203 OPN #2"));
242         } else {
243                 pc88opn2 = NULL;
244         }
245 #else
246         #if defined(SUPPORT_PC88_OPN1)
247                 pc88opn1 = new YM2203(this, emu);
248                 #if defined(SUPPORT_PC88_OPNA)
249                         pc88opn1->is_ym2608 = true;
250                         pc88opn1->set_device_name(_T("YM2608 OPNA #1"));
251                 #else
252                         pc88opn1->is_ym2608 = false;
253                         pc88opn1->set_device_name(_T("YM2203 OPN #1"));
254                 #endif
255         #endif
256         #if defined(SUPPORT_PC88_OPN2)
257                 pc88opn2 = new YM2203(this, emu);
258                 #if defined(SUPPORT_PC88_OPNA)
259                         pc88opn2->is_ym2608 = true;
260                         pc88opn2->set_device_name(_T("YM2608 OPNA #2"));
261                 #else
262                         pc88opn2->is_ym2608 = false;
263                         pc88opn2->set_device_name(_T("YM2203 OPN #2"));
264                 #endif
265         #endif
266 #endif
267 #ifdef USE_DEBUGGER
268 #ifdef SUPPORT_PC88_OPN1
269         if(pc88opn1 != NULL) {
270                 pc88opn1->set_context_debugger(new DEBUGGER(this, emu));
271         }
272 #endif
273 #ifdef SUPPORT_PC88_OPN2
274         if(pc88opn2 != NULL) {
275                 pc88opn2->set_context_debugger(new DEBUGGER(this, emu));
276         }
277 #endif
278 #endif
279 #ifdef SUPPORT_PC88_HMB20
280         if(config.dipswitch & DIPSWITCH_HMB20) {
281                 pc88opm = new YM2151(this, emu);
282 #ifdef USE_DEBUGGER
283                 pc88opm->set_context_debugger(new DEBUGGER(this, emu));
284 #endif
285                 pc88opm->set_device_name(_T("YM2151 OPM (HMB-20)"));
286         } else {
287                 pc88opm = NULL;
288         }
289 #endif
290 #ifdef SUPPORT_PC88_GSX8800
291         if(config.dipswitch & DIPSWITCH_GSX8800) {
292 //              pc88gsx_pit = new I8253(this, emu);
293 //              pc88gsx_pit->set_device_name(_T("8253 PIT (GSX-8800)"));
294 //              pc88gsx_pit->set_context_event_manager(pc88event);
295                 pc88gsx_psg1 = new AY_3_891X(this, emu);
296                 pc88gsx_psg1->set_device_name(_T("AY-3-8910 PSG #1 (GSX-8800)"));
297                 pc88gsx_psg2 = new AY_3_891X(this, emu);
298                 pc88gsx_psg2->set_device_name(_T("AY-3-8910 PSG #2 (GSX-8800)"));
299                 pc88gsx_psg3 = new AY_3_891X(this, emu);
300                 pc88gsx_psg3->set_device_name(_T("AY-3-8910 PSG #3 (GSX-8800)"));
301                 pc88gsx_psg4 = new AY_3_891X(this, emu);
302                 pc88gsx_psg4->set_device_name(_T("AY-3-8910 PSG #4 (GSX-8800)"));
303 #ifdef USE_DEBUGGER
304                 pc88gsx_psg1->set_context_debugger(new DEBUGGER(this, emu));
305                 pc88gsx_psg2->set_context_debugger(new DEBUGGER(this, emu));
306                 pc88gsx_psg3->set_context_debugger(new DEBUGGER(this, emu));
307                 pc88gsx_psg4->set_context_debugger(new DEBUGGER(this, emu));
308 #endif
309         } else {
310 //              pc88gsx_pit = NULL;
311                 pc88gsx_psg1 = pc88gsx_psg2 = pc88gsx_psg3 = pc88gsx_psg4 = NULL;
312         }
313 #endif
314 #ifdef SUPPORT_PC88_PCG8100
315         if(config.dipswitch & DIPSWITCH_PCG8100) {
316                 pc88pcg_pit = new I8253(this, emu);
317                 pc88pcg_pit->set_device_name(_T("8253 PIT (PCG-8100)"));
318                 pc88pcg_pcm1 = new PCM1BIT(this, emu);
319                 pc88pcg_pcm1->set_device_name(_T("1-Bit PCM Sound (PCG-8100 #1)"));
320                 pc88pcg_pcm2 = new PCM1BIT(this, emu);
321                 pc88pcg_pcm2->set_device_name(_T("1-Bit PCM Sound (PCG-8100 #2)"));
322                 pc88pcg_pcm3 = new PCM1BIT(this, emu);
323                 pc88pcg_pcm3->set_device_name(_T("1-Bit PCM Sound (PCG-8100 #3)"));
324         } else {
325                 pc88pcg_pit = NULL;
326                 pc88pcg_pcm1 = pc88pcg_pcm2 = pc88pcg_pcm3 = NULL;
327         }
328 #endif
329 #ifdef SUPPORT_PC88_16BIT
330         if(config.dipswitch & DIPSWITCH_16BIT) {
331                 pc88pit_16bit = new I8253(this, emu);
332                 pc88pio_16bit = new I8255(this, emu);
333                 pc88pic_16bit = new I8259(this, emu);
334                 pc88cpu_16bit = new I86(this, emu);
335                 pc88cpu_16bit->device_model = INTEL_8086;
336                 pc88io_16bit = new IO(this, emu);
337                 pc88mem_16bit = new MEMORY(this, emu);
338         } else {
339                 pc88cpu_16bit = NULL;
340         }
341 #endif
342 #ifdef SUPPORT_M88_DISKDRV
343         if(config.dipswitch & DIPSWITCH_M88_DISKDRV) {
344                 pc88diskio = new DiskIO(this, emu);
345 //              pc88diskio->set_context_event_manager(pc88event);
346         } else {
347                 pc88diskio = NULL;
348         }
349 #endif
350
351         // set cpu device contexts
352 #ifdef SUPPORT_PC88_HIGH_CLOCK
353         pc88event->set_context_cpu(pc88cpu, (config.cpu_type == 1) ? 3993624 : 7987248);
354 #else
355         pc88event->set_context_cpu(pc88cpu, 3993624);
356 #endif
357         if(pc88cpu_sub != NULL) {
358                 pc88event->set_context_cpu(pc88cpu_sub, 3993624);
359         }
360 #ifdef SUPPORT_PC88_16BIT
361         if(pc88cpu_16bit != NULL) {
362                 pc88event->set_context_cpu(pc88cpu_16bit, 7987248);
363         }
364 #endif
365
366         // set sound device contexts
367         pc88event->set_context_sound(pc88pcm);
368 #ifdef SUPPORT_PC88_CDROM
369         pc88event->set_context_sound(pc88scsi_cdrom);
370 #endif
371 #ifdef SUPPORT_PC88_OPN1
372         if(pc88opn1 != NULL) {
373                 pc88event->set_context_sound(pc88opn1);
374         }
375 #endif
376 #ifdef SUPPORT_PC88_OPN2
377         if(pc88opn2 != NULL) {
378                 pc88event->set_context_sound(pc88opn2);
379         }
380 #endif
381 #ifdef SUPPORT_PC88_HMB20
382         if(config.dipswitch & DIPSWITCH_HMB20) {
383                 pc88event->set_context_sound(pc88opm);
384         }
385 #endif
386 #ifdef SUPPORT_PC88_GSX8800
387         if(config.dipswitch & DIPSWITCH_GSX8800) {
388                 pc88event->set_context_sound(pc88gsx_psg1);
389                 pc88event->set_context_sound(pc88gsx_psg2);
390                 pc88event->set_context_sound(pc88gsx_psg3);
391                 pc88event->set_context_sound(pc88gsx_psg4);
392         }
393 #endif
394 #ifdef SUPPORT_PC88_PCG8100
395         if(config.dipswitch & DIPSWITCH_PCG8100) {
396                 pc88event->set_context_sound(pc88pcg_pcm1);
397                 pc88event->set_context_sound(pc88pcg_pcm2);
398                 pc88event->set_context_sound(pc88pcg_pcm3);
399         }
400 #endif
401 #ifdef SUPPORT_PC88_JAST
402         if(config.printer_type == 2) {
403                 pc88event->set_context_sound(pc88prn);
404         }
405 #endif
406         if(config.dipswitch & DIPSWITCH_FDD_5INCH) {
407                 pc88event->set_context_sound(pc88noise_seek);
408                 pc88event->set_context_sound(pc88noise_head_down);
409                 pc88event->set_context_sound(pc88noise_head_up);
410         }
411 #ifdef SUPPORT_PC88_FDD_8INCH
412         if(config.dipswitch & DIPSWITCH_FDD_8INCH) {
413                 pc88event->set_context_sound(pc88noise_8inch_seek);
414                 pc88event->set_context_sound(pc88noise_8inch_head_down);
415                 pc88event->set_context_sound(pc88noise_8inch_head_up);
416         }
417 #endif
418
419         // set other device contexts
420         pc88->set_context_cpu(pc88cpu);
421         pc88->set_context_pcm(pc88pcm);
422         pc88->set_context_pio(pc88pio);
423         pc88->set_context_prn(pc88prn);
424         pc88->set_context_rtc(pc88rtc);
425         pc88->set_context_sio(pc88sio);
426 #ifdef SUPPORT_PC88_FDD_8INCH
427         if(config.dipswitch & DIPSWITCH_FDD_8INCH) {
428                 pc88->set_context_fdc_8inch(pc88fdc_8inch);
429         }
430 #endif
431 #ifdef SUPPORT_PC88_CDROM
432         pc88->set_context_scsi_host(pc88scsi_host);
433         pc88->set_context_scsi_cdrom(pc88scsi_cdrom);
434 #endif
435 #ifdef SUPPORT_PC88_OPN1
436         if(pc88opn1 != NULL) {
437                 pc88->set_context_opn1(pc88opn1);
438         }
439 #endif
440 #ifdef SUPPORT_PC88_OPN2
441         if(pc88opn2 != NULL) {
442                 pc88->set_context_opn2(pc88opn2);
443         }
444 #endif
445 #ifdef SUPPORT_PC88_HMB20
446         if(config.dipswitch & DIPSWITCH_HMB20) {
447                 pc88->set_context_opm(pc88opm);
448         }
449 #endif
450 #ifdef SUPPORT_PC88_GSX8800
451         if(config.dipswitch & DIPSWITCH_GSX8800) {
452 //              pc88->set_context_gsx_pit(pc88gsx_pit);
453                 pc88->set_context_gsx_psg1(pc88gsx_psg1);
454                 pc88->set_context_gsx_psg2(pc88gsx_psg2);
455                 pc88->set_context_gsx_psg3(pc88gsx_psg3);
456                 pc88->set_context_gsx_psg4(pc88gsx_psg4);
457         }
458 #endif
459 #ifdef SUPPORT_PC88_PCG8100
460         if(config.dipswitch & DIPSWITCH_PCG8100) {
461                 pc88->set_context_pcg_pit(pc88pcg_pit);
462                 pc88->set_context_pcg_pcm1(pc88pcg_pcm1);
463                 pc88->set_context_pcg_pcm2(pc88pcg_pcm2);
464                 pc88->set_context_pcg_pcm3(pc88pcg_pcm3);
465         }
466 #endif
467 #ifdef SUPPORT_PC88_16BIT
468         if(config.dipswitch & DIPSWITCH_16BIT) {
469                 pc88->set_context_pio_16bit(pc88pio_16bit);
470         }
471 #endif
472 #ifdef SUPPORT_M88_DISKDRV
473         if(config.dipswitch & DIPSWITCH_M88_DISKDRV) {
474                 pc88->set_context_diskio(pc88diskio);
475         }
476 #endif
477         pc88cpu->set_context_mem(pc88);
478         pc88cpu->set_context_io(pc88);
479         pc88cpu->set_context_intr(pc88);
480 #ifdef USE_DEBUGGER
481         pc88cpu->set_context_debugger(new DEBUGGER(this, emu));
482 #endif
483         pc88sio->set_context_rxrdy(pc88, SIG_PC88_USART_IRQ, 1);
484         pc88sio->set_context_out(pc88, SIG_PC88_USART_OUT);
485
486         if(config.dipswitch & DIPSWITCH_FDD_5INCH) {
487                 pc88sub->set_context_cpu(pc88cpu_sub);
488                 pc88sub->set_context_fdc(pc88fdc_sub);
489                 pc88sub->set_context_pio(pc88pio_sub);
490                 pc88pio->set_context_port_a(pc88pio_sub, SIG_I8255_PORT_B, 0xff, 0);
491                 pc88pio->set_context_port_b(pc88pio_sub, SIG_I8255_PORT_A, 0xff, 0);
492                 pc88pio->set_context_port_c(pc88pio_sub, SIG_I8255_PORT_C, 0x0f, 4);
493                 pc88pio->set_context_port_c(pc88pio_sub, SIG_I8255_PORT_C, 0xf0, -4);
494                 pc88pio->clear_ports_by_cmdreg = true;
495                 pc88pio_sub->set_context_port_a(pc88pio, SIG_I8255_PORT_B, 0xff, 0);
496                 pc88pio_sub->set_context_port_b(pc88pio, SIG_I8255_PORT_A, 0xff, 0);
497                 pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0x0f, 4);
498                 pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0xf0, -4);
499                 pc88pio_sub->clear_ports_by_cmdreg = true;
500                 pc88fdc_sub->set_context_irq(pc88cpu_sub, SIG_CPU_IRQ, 1);
501                 pc88fdc_sub->set_context_noise_seek(pc88noise_seek);
502                 pc88fdc_sub->set_context_noise_head_down(pc88noise_head_down);
503                 pc88fdc_sub->set_context_noise_head_up(pc88noise_head_up);
504                 pc88cpu_sub->set_context_mem(pc88sub);
505                 pc88cpu_sub->set_context_io(pc88sub);
506                 pc88cpu_sub->set_context_intr(pc88sub);
507 #ifdef USE_DEBUGGER
508                 pc88cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
509 #endif
510         }
511
512 #ifdef SUPPORT_PC88_FDD_8INCH
513         if(config.dipswitch & DIPSWITCH_FDD_8INCH) {
514                 pc88fdc_8inch->set_context_irq(pc88, SIG_PC88_8INCH_IRQ, 1);
515                 pc88fdc_8inch->set_context_drq(pc88, SIG_PC88_8INCH_DRQ, 1);
516                 pc88fdc_8inch->set_context_noise_seek(pc88noise_8inch_seek);
517                 pc88fdc_8inch->set_context_noise_head_down(pc88noise_8inch_head_down);
518                 pc88fdc_8inch->set_context_noise_head_up(pc88noise_8inch_head_up);
519         }
520 #endif
521 #ifdef SUPPORT_PC88_CDROM
522         pc88scsi_cdrom->scsi_id = 0;
523         pc88scsi_cdrom->set_context_interface(pc88scsi_host);
524         pc88scsi_host->set_context_target(pc88scsi_cdrom);
525         pc88scsi_host->set_context_drq(pc88, SIG_PC88_SCSI_DRQ, 1);
526 #endif
527 #ifdef SUPPORT_PC88_OPN1
528         if(pc88opn1 != NULL) {
529                 pc88opn1->set_context_irq(pc88, SIG_PC88_OPN1_IRQ, 1);
530         }
531 #endif
532 #ifdef SUPPORT_PC88_OPN2
533         if(pc88opn2 != NULL) {
534                 pc88opn2->set_context_irq(pc88, SIG_PC88_OPN2_IRQ, 1);
535         }
536 #endif
537 #ifdef SUPPORT_PC88_GSX8800
538 //      if(config.dipswitch & DIPSWITCH_GSX8800) {
539 //              pc88gsx_pit->set_context_ch0(pc88, SIG_PC88_GSX_IRQ, 1);
540 //              pc88gsx_pit->set_context_ch1(pc88gsx_pit, SIG_I8253_CLOCK_2, 1);
541 //              pc88gsx_pit->set_constant_clock(0, 1996800);
542 //              pc88gsx_pit->set_constant_clock(1, 1996800);
543 //      }
544 #endif
545 #ifdef SUPPORT_PC88_PCG8100
546         if(config.dipswitch & DIPSWITCH_PCG8100) {
547                 pc88pcg_pit->set_context_ch0(pc88pcg_pcm1, SIG_PCM1BIT_SIGNAL, 1);
548                 pc88pcg_pit->set_context_ch1(pc88pcg_pcm2, SIG_PCM1BIT_SIGNAL, 1);
549                 pc88pcg_pit->set_context_ch2(pc88pcg_pcm3, SIG_PCM1BIT_SIGNAL, 1);
550                 pc88pcg_pit->set_constant_clock(0, 3993624);
551                 pc88pcg_pit->set_constant_clock(1, 3993624);
552                 pc88pcg_pit->set_constant_clock(2, 3993624);
553         }
554 #endif
555 #ifdef SUPPORT_PC88_16BIT
556         if(config.dipswitch & DIPSWITCH_16BIT) {
557                 memset(pc88rom_16bit, 0xff, sizeof(pc88rom_16bit));
558                 memset(pc88ram_16bit, 0x00, sizeof(pc88ram_16bit));
559
560                 FILEIO* fio = new FILEIO();
561                 if(fio->Fopen(create_local_path(_T("PC-8801-16_I86.ROM")), FILEIO_READ_BINARY)) {
562                         fio->Fread(pc88rom_16bit, sizeof(pc88rom_16bit), 1);
563                         fio->Fclose();
564                 }
565                 delete fio;
566
567                 pc88mem_16bit->set_memory_rw(0, sizeof(pc88ram_16bit) - 1, pc88ram_16bit);
568                 pc88mem_16bit->set_memory_r(0xff000, 0xfffff, pc88rom_16bit);
569
570                 pc88io_16bit->set_iomap_alias_rw(0x00, pc88pit_16bit, 0);
571                 pc88io_16bit->set_iomap_alias_rw(0x02, pc88pit_16bit, 1);
572                 pc88io_16bit->set_iomap_alias_rw(0x04, pc88pit_16bit, 2);
573                 pc88io_16bit->set_iomap_alias_w (0x06, pc88pit_16bit, 3);
574                 pc88io_16bit->set_iomap_alias_rw(0x10, pc88pio_16bit, 0);
575                 pc88io_16bit->set_iomap_alias_rw(0x12, pc88pio_16bit, 1);
576                 pc88io_16bit->set_iomap_alias_rw(0x14, pc88pio_16bit, 2);
577                 pc88io_16bit->set_iomap_alias_w (0x16, pc88pio_16bit, 3);
578                 pc88io_16bit->set_iomap_alias_rw(0x20, pc88pic_16bit, 0);
579                 pc88io_16bit->set_iomap_alias_rw(0x22, pc88pic_16bit, 1);
580
581                 pc88pit_16bit->set_context_ch0(pc88pic_16bit, SIG_I8259_IR0, 1);
582                 pc88pit_16bit->set_context_ch1(pc88pit_16bit, SIG_I8253_CLOCK_2, 1);
583                 pc88pit_16bit->set_context_ch2(pc88pic_16bit, SIG_I8259_IR7, 1);
584                 pc88pit_16bit->set_constant_clock(0, 2995218);
585                 pc88pit_16bit->set_constant_clock(1, 2995218);
586                 pc88pio_16bit->set_context_port_a(pc88, SIG_PC88_16BIT_PORTA, 0xff, 0);
587                 pc88pio_16bit->set_context_port_c(pc88, SIG_PC88_16BIT_PORTC, 0x82, 0); // PC7+PC1
588                 pc88pio_16bit->set_context_port_c(pc88pic_16bit, SIG_I8259_IR1, 0x01, 0); // PC0
589                 pc88pio_16bit->set_context_port_c(pc88pic_16bit, SIG_I8259_IR2, 0x08, 0); // PC3
590                 pc88pic_16bit->set_context_cpu(pc88cpu_16bit);
591                 pc88cpu_16bit->set_context_mem(pc88mem_16bit);
592                 pc88cpu_16bit->set_context_io(pc88io_16bit);
593                 pc88cpu_16bit->set_context_intr(pc88pic_16bit);
594 #ifdef USE_DEBUGGER
595                 pc88cpu_16bit->set_context_debugger(new DEBUGGER(this, emu));
596 #endif
597
598         }
599 #endif
600
601         // initialize all devices
602 #if defined(__GIT_REPO_VERSION)
603         set_git_repo_version(__GIT_REPO_VERSION);
604 #endif
605         initialize_devices();
606
607 //      for(DEVICE* device = first_device; device; device = device->next_device) {
608 //              printf("DEV NAME=%s ID=%d\n", device->this_device_name, device->this_device_id);
609 //              device->initialize();
610 //      }
611 #ifdef SUPPORT_PC88_FDD_8INCH
612         if(config.dipswitch & DIPSWITCH_FDD_8INCH) {
613                 pc88fdc_8inch->set_drive_type(0, DRIVE_TYPE_2HD);
614                 pc88fdc_8inch->set_drive_type(1, DRIVE_TYPE_2HD);
615 //              pc88fdc_8inch->write_signal(SIG_UPD765A_MOTOR, 1, 1);
616         }
617 #endif
618 }
619
620 VM::~VM()
621 {
622         // delete all devices
623         release_devices();
624 //      for(DEVICE* device = first_device; device;) {
625 //              DEVICE *next_device = device->next_device;
626 //              device->release();
627 //              delete device;
628 //              device = next_device;
629 //      }
630 }
631
632
633 // ----------------------------------------------------------------------------
634 // drive virtual machine
635 // ----------------------------------------------------------------------------
636
637 void VM::reset()
638 {
639         // reset all devices
640         for(DEVICE* device = first_device; device; device = device->next_device) {
641                 device->reset();
642         }
643         for(DEVICE* device = first_device; device; device = device->next_device) {
644                 device->reset();
645         }
646
647         // initial device settings
648 #ifdef SUPPORT_PC88_OPN1
649         if(pc88opn1 != NULL) {
650                 pc88opn1->set_reg(0x29, 3); // for Misty Blue
651         }
652 #endif
653         if(pc88pio_sub != NULL) {
654                 pc88pio_sub->write_signal(SIG_I8255_PORT_C, 0, 0xff);
655         }
656         pc88pio->write_signal(SIG_I8255_PORT_C, 0, 0xff);
657 }
658
659 void VM::run()
660 {
661         pc88event->drive();
662 }
663
664 double VM::get_frame_rate()
665 {
666         return pc88event->get_frame_rate();
667 }
668
669 // ----------------------------------------------------------------------------
670 // debugger
671 // ----------------------------------------------------------------------------
672
673 #ifdef USE_DEBUGGER
674 DEVICE *VM::get_cpu(int index)
675 {
676         if(index == 0) {
677                 return pc88cpu;
678         } else if(index == 1) {
679                 return pc88cpu_sub;
680 #ifdef SUPPORT_PC88_16BIT
681         } else if(index == 2) {
682                 return pc88cpu_16bit;
683 #endif
684         }
685         return NULL;
686 }
687 #endif
688
689 // ----------------------------------------------------------------------------
690 // draw screen
691 // ----------------------------------------------------------------------------
692
693 void VM::draw_screen()
694 {
695         pc88->draw_screen();
696 }
697
698 // ----------------------------------------------------------------------------
699 // soud manager
700 // ----------------------------------------------------------------------------
701
702 void VM::initialize_sound(int rate, int samples)
703 {
704         // init sound manager
705         pc88event->initialize_sound(rate, samples);
706
707         // init sound gen
708         pc88pcm->initialize_sound(rate, 8000);
709 #ifdef SUPPORT_PC88_OPN1
710         if(pc88opn1 != NULL) {
711                 if(pc88opn1->is_ym2608) {
712                         pc88opn1->initialize_sound(rate, 7987248, samples, 0, 0);
713                 } else {
714                         pc88opn1->initialize_sound(rate, 3993624, samples, 0, 0);
715                 }
716         }
717 #endif
718 #ifdef SUPPORT_PC88_OPN2
719         if(pc88opn2 != NULL) {
720                 if(pc88opn2->is_ym2608) {
721                         pc88opn2->initialize_sound(rate, 7987248, samples, 0, 0);
722                 } else {
723                         pc88opn2->initialize_sound(rate, 3993624, samples, 0, 0);
724                 }
725         }
726 #endif
727 #ifdef SUPPORT_PC88_HMB20
728         if(config.dipswitch & DIPSWITCH_HMB20) {
729                 pc88opm->initialize_sound(rate, 4000000, samples, 0);
730         }
731 #endif
732 #ifdef SUPPORT_PC88_GSX8800
733         if(config.dipswitch & DIPSWITCH_GSX8800) {
734                 pc88gsx_psg1->initialize_sound(rate, 3993624, samples, 0, 0);
735                 pc88gsx_psg2->initialize_sound(rate, 3993624, samples, 0, 0);
736                 pc88gsx_psg3->initialize_sound(rate, 3993624, samples, 0, 0);
737                 pc88gsx_psg4->initialize_sound(rate, 3993624, samples, 0, 0);
738         }
739 #endif
740 #ifdef SUPPORT_PC88_PCG8100
741         if(config.dipswitch & DIPSWITCH_PCG8100) {
742                 pc88pcg_pcm1->initialize_sound(rate, 8000);
743                 pc88pcg_pcm2->initialize_sound(rate, 8000);
744                 pc88pcg_pcm3->initialize_sound(rate, 8000);
745         }
746 #endif
747 #ifdef SUPPORT_PC88_JAST
748         if(config.printer_type == 2) {
749                 PCM8BIT *pcm8 = (PCM8BIT *)pc88prn;
750                 pcm8->initialize_sound(rate, 32000);
751         }
752 #endif
753 }
754
755 uint16_t* VM::create_sound(int* extra_frames)
756 {
757         return pc88event->create_sound(extra_frames);
758 }
759
760 int VM::get_sound_buffer_ptr()
761 {
762         return pc88event->get_sound_buffer_ptr();
763 }
764
765 #ifdef USE_SOUND_VOLUME
766 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
767 {
768 #ifdef SUPPORT_PC88_OPN1
769         if(ch-- == 0) {
770                 if(pc88opn1 != NULL) {
771                         pc88opn1->set_volume(0, decibel_l, decibel_r);
772                 }
773                 return;
774         }
775         if(ch-- == 0) {
776                 if(pc88opn1 != NULL) {
777                         pc88opn1->set_volume(1, decibel_l, decibel_r);
778                 }
779                 return;
780         }
781 #ifdef SUPPORT_PC88_OPNA
782         if(ch-- == 0) {
783                 if(pc88opn1 != NULL && pc88opn1->is_ym2608) {
784                         pc88opn1->set_volume(2, decibel_l, decibel_r);
785                 }
786                 return;
787         }
788         if(ch-- == 0) {
789                 if(pc88opn1 != NULL && pc88opn1->is_ym2608) {
790                         pc88opn1->set_volume(3, decibel_l, decibel_r);
791                 }
792                 return;
793         }
794 #endif
795 #endif
796 #ifdef SUPPORT_PC88_OPN2
797         if(ch-- == 0) {
798                 if(pc88opn2 != NULL) {
799                         pc88opn2->set_volume(0, decibel_l, decibel_r);
800                 }
801                 return;
802         }
803         if(ch-- == 0) {
804                 if(pc88opn2 != NULL) {
805                         pc88opn2->set_volume(1, decibel_l, decibel_r);
806                 }
807                 return;
808         }
809 #ifdef SUPPORT_PC88_OPNA
810         if(ch-- == 0) {
811                 if(pc88opn2 != NULL && pc88opn2->is_ym2608) {
812                         pc88opn2->set_volume(2, decibel_l, decibel_r);
813                 }
814                 return;
815         }
816         if(ch-- == 0) {
817                 if(pc88opn2 != NULL && pc88opn2->is_ym2608) {
818                         pc88opn2->set_volume(3, decibel_l, decibel_r);
819                 }
820                 return;
821         }
822 #endif
823 #endif
824 #ifdef SUPPORT_PC88_CDROM
825         if(ch-- == 0) {
826                 pc88scsi_cdrom->set_volume(0, decibel_l, decibel_r);
827                 return;
828         }
829 #endif
830 #ifdef SUPPORT_PC88_HMB20
831         if(ch-- == 0) {
832                 if(pc88opm != NULL) {
833                         pc88opm->set_volume(0, decibel_l, decibel_r);
834                 }
835                 return;
836         }
837 #endif
838 #ifdef SUPPORT_PC88_GSX8800
839         if(ch-- == 0) {
840                 if(pc88gsx_psg1 != NULL) {
841                         pc88gsx_psg1->set_volume(0, decibel_l, decibel_r);
842                 }
843                 if(pc88gsx_psg2 != NULL) {
844                         pc88gsx_psg2->set_volume(0, decibel_l, decibel_r);
845                 }
846                 if(pc88gsx_psg3 != NULL) {
847                         pc88gsx_psg3->set_volume(0, decibel_l, decibel_r);
848                 }
849                 if(pc88gsx_psg4 != NULL) {
850                         pc88gsx_psg4->set_volume(0, decibel_l, decibel_r);
851                 }
852                 return;
853         }
854 #endif
855 #ifdef SUPPORT_PC88_PCG8100
856         if(ch-- == 0) {
857                 if(pc88pcg_pcm1 != NULL) {
858                         pc88pcg_pcm1->set_volume(0, decibel_l, decibel_r);
859                 }
860                 if(pc88pcg_pcm2 != NULL) {
861                         pc88pcg_pcm2->set_volume(0, decibel_l, decibel_r);
862                 }
863                 if(pc88pcg_pcm3 != NULL) {
864                         pc88pcg_pcm3->set_volume(0, decibel_l, decibel_r);
865                 }
866                 return;
867         }
868 #endif
869 #ifdef SUPPORT_PC88_JAST
870         if(ch-- == 0) {
871                 if(config.printer_type == 2) {
872                         PCM8BIT *pcm8 = (PCM8BIT *)pc88prn;
873                         pcm8->set_volume(0, decibel_l, decibel_r);
874                 }
875                 return;
876         }
877 #endif
878         if(ch-- == 0) {
879                 pc88pcm->set_volume(0, decibel_l, decibel_r);
880                 return;
881         }
882         if(ch-- == 0) {
883                 if(pc88noise_seek != NULL) {
884                         pc88noise_seek->set_volume(0, decibel_l, decibel_r);
885                 }
886                 if(pc88noise_head_down != NULL) {
887                         pc88noise_head_down->set_volume(0, decibel_l, decibel_r);
888                 }
889                 if(pc88noise_head_up != NULL) {
890                         pc88noise_head_up->set_volume(0, decibel_l, decibel_r);
891                 }
892 #ifdef SUPPORT_PC88_FDD_8INCH
893                 if(pc88noise_8inch_seek != NULL) {
894                         pc88noise_8inch_seek->set_volume(0, decibel_l, decibel_r);
895                 }
896                 if(pc88noise_8inch_head_down != NULL) {
897                         pc88noise_8inch_head_down->set_volume(0, decibel_l, decibel_r);
898                 }
899                 if(pc88noise_8inch_head_up != NULL) {
900                         pc88noise_8inch_head_up->set_volume(0, decibel_l, decibel_r);
901                 }
902 #endif
903                 return;
904         }
905 }
906 #endif
907
908 // ----------------------------------------------------------------------------
909 // notify key
910 // ----------------------------------------------------------------------------
911
912 void VM::key_down(int code, bool repeat)
913 {
914         pc88->key_down(code, repeat);
915 }
916
917 void VM::key_up(int code)
918 {
919 }
920
921 bool VM::get_caps_locked()
922 {
923         return pc88->get_caps_locked();
924 }
925
926 bool VM::get_kana_locked()
927 {
928         return pc88->get_kana_locked();
929 }
930
931 // ----------------------------------------------------------------------------
932 // user interface
933 // ----------------------------------------------------------------------------
934
935 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
936 {
937         UPD765A *controller = get_floppy_disk_controller(drv);
938
939         if(controller != NULL) {
940                 controller->open_disk(drv & 1, file_path, bank);
941         }
942 }
943
944 void VM::close_floppy_disk(int drv)
945 {
946         UPD765A *controller = get_floppy_disk_controller(drv);
947
948         if(controller != NULL) {
949                 controller->close_disk(drv & 1);
950         }
951 }
952
953 bool VM::is_floppy_disk_connected(int drv)
954 {
955         DISK *handler = get_floppy_disk_handler(drv);
956
957         return (handler != NULL);
958 }
959
960 bool VM::is_floppy_disk_inserted(int drv)
961 {
962         DISK *handler = get_floppy_disk_handler(drv);
963
964         if(handler != NULL) {
965                 return handler->inserted;
966         }
967         return false;
968 }
969
970 void VM::is_floppy_disk_protected(int drv, bool value)
971 {
972         DISK *handler = get_floppy_disk_handler(drv);
973
974         if(handler != NULL) {
975                 handler->write_protected = value;
976         }
977 }
978
979 bool VM::is_floppy_disk_protected(int drv)
980 {
981         DISK *handler = get_floppy_disk_handler(drv);
982
983         if(handler != NULL) {
984                 return handler->write_protected;
985         }
986         return false;
987 }
988
989 uint32_t VM::is_floppy_disk_accessed()
990 {
991         uint32_t status = 0;
992
993         for(int drv = 0; drv < USE_FLOPPY_DISK; drv += 2) {
994                 UPD765A *controller = get_floppy_disk_controller(drv);
995
996                 if(controller != NULL) {
997                         status |= (controller->read_signal(0) & 3) << drv;
998                 }
999         }
1000         return status;
1001 }
1002
1003 uint32_t VM::floppy_disk_indicator_color()
1004 {
1005         if(pc88fdc_sub != nullptr) {
1006                 return ((pc88fdc_sub->get_drive_type(0) == DRIVE_TYPE_2HD) ? 1 : 0) |
1007                         ((pc88fdc_sub->get_drive_type(1) == DRIVE_TYPE_2HD) ? 2 : 0);
1008         }
1009         return 0;
1010 }
1011
1012 UPD765A *VM::get_floppy_disk_controller(int drv)
1013 {
1014         if(drv == 0 || drv == 1) {
1015                 return pc88fdc_sub;
1016         }
1017 #ifdef SUPPORT_PC88_FDD_8INCH
1018         if(drv == 2 || drv == 3) {
1019                 return pc88fdc_8inch;
1020         }
1021 #endif
1022         return NULL;
1023 }
1024
1025 DISK *VM::get_floppy_disk_handler(int drv)
1026 {
1027         UPD765A *controller = get_floppy_disk_controller(drv);
1028
1029         if(controller != NULL) {
1030                 return controller->get_disk_handler(drv & 1);
1031         }
1032         return NULL;
1033 }
1034
1035 void VM::play_tape(int drv, const _TCHAR* file_path)
1036 {
1037         pc88->play_tape(file_path);
1038 }
1039
1040 void VM::rec_tape(int drv, const _TCHAR* file_path)
1041 {
1042         pc88->rec_tape(file_path);
1043 }
1044
1045 void VM::close_tape(int drv)
1046 {
1047         pc88->close_tape();
1048 }
1049
1050 bool VM::is_tape_inserted(int drv)
1051 {
1052         return pc88->is_tape_inserted();
1053 }
1054
1055 #ifdef SUPPORT_PC88_CDROM
1056 void VM::open_compact_disc(int drv, const _TCHAR* file_path)
1057 {
1058         pc88scsi_cdrom->open(file_path);
1059 }
1060
1061 void VM::close_compact_disc(int drv)
1062 {
1063         pc88scsi_cdrom->close();
1064 }
1065
1066 bool VM::is_compact_disc_inserted(int drv)
1067 {
1068         return pc88scsi_cdrom->mounted();
1069 }
1070
1071 uint32_t VM::is_compact_disc_accessed()
1072 {
1073         return pc88scsi_cdrom->accessed();
1074 }
1075 #endif
1076
1077 bool VM::is_frame_skippable()
1078 {
1079 //      return event->is_frame_skippable();
1080         return pc88->is_frame_skippable();
1081 }
1082
1083 void VM::update_config()
1084 {
1085         if(boot_mode != config.boot_mode) {
1086                 // boot mode is changed !!!
1087                 boot_mode = config.boot_mode;
1088                 reset();
1089         } else {
1090                 for(DEVICE* device = first_device; device; device = device->next_device) {
1091                         device->update_config();
1092                 }
1093         }
1094 }
1095
1096 double VM::get_current_usec()
1097 {
1098         if(pc88event == NULL) return 0.0;
1099         return pc88event->get_current_usec();
1100 }
1101
1102 uint64_t VM::get_current_clock_uint64()
1103 {
1104         if(pc88event == NULL) return (uint64_t)0;
1105         return pc88event->get_current_clock_uint64();
1106 }
1107
1108 #define STATE_VERSION   13
1109
1110 bool VM::process_state(FILEIO* state_fio, bool loading)
1111 {
1112         if(!(VM_TEMPLATE::process_state_core(state_fio, loading, STATE_VERSION))) {
1113                 return false;
1114         }
1115         // Machine specified.
1116 #ifdef SUPPORT_PC88_16BIT
1117         state_fio->StateArray(pc88ram_16bit, sizeof(pc88ram_16bit), 1);
1118 #endif
1119         state_fio->StateValue(boot_mode);
1120         return true;
1121 }