OSDN Git Service

b2baa5bf963c973c3f82d6b16c1e0259d42ef0bf
[csp-qt/common_source_project-fm7.git] / source / src / vm / pc9801 / pc9801.cpp
1 /*\r
2         NEC PC-9801 Emulator 'ePC-9801'\r
3         NEC PC-9801E/F/M Emulator 'ePC-9801E'\r
4         NEC PC-98DO Emulator 'ePC-98DO'\r
5 \r
6         Author : Takeda.Toshiya\r
7         Date   : 2010.09.15-\r
8 \r
9         [ virtual machine ]\r
10 */\r
11 \r
12 #include "pc9801.h"\r
13 #include "../../emu.h"\r
14 #include "../device.h"\r
15 #include "../event.h"\r
16 \r
17 #if defined(SUPPORT_OLD_BUZZER)\r
18 #include "../beep.h"\r
19 #endif\r
20 #include "../disk.h"\r
21 #include "../i8237.h"\r
22 #include "../i8251.h"\r
23 #include "../i8253.h"\r
24 #include "../i8255.h"\r
25 #include "../i8259.h"\r
26 #if defined(HAS_V30)\r
27 #include "../i86.h"\r
28 #else\r
29 #include "../i286.h"\r
30 #endif\r
31 #include "../io.h"\r
32 #include "../ls244.h"\r
33 #include "../memory.h"\r
34 #if defined(HAS_I86) || defined(HAS_V30)\r
35 #include "../not.h"\r
36 #endif\r
37 #if !defined(SUPPORT_OLD_BUZZER)\r
38 #include "../pcm1bit.h"\r
39 #endif\r
40 #include "../upd1990a.h"\r
41 #include "../upd7220.h"\r
42 #include "../upd765a.h"\r
43 #include "../ym2203.h"\r
44 \r
45 #ifdef USE_DEBUGGER\r
46 #include "../debugger.h"\r
47 #endif\r
48 \r
49 #include "display.h"\r
50 #include "floppy.h"\r
51 #include "fmsound.h"\r
52 #include "joystick.h"\r
53 #include "keyboard.h"\r
54 #include "mouse.h"\r
55 #include "printer.h"\r
56 \r
57 #if defined(SUPPORT_320KB_FDD_IF)\r
58 #include "../pc80s31k.h"\r
59 #include "../z80.h"\r
60 #endif\r
61 #if defined(SUPPORT_CMT_IF)\r
62 #include "cmt.h"\r
63 #endif\r
64 \r
65 #if defined(_PC98DO)\r
66 #include "../beep.h"\r
67 #include "../pc80s31k.h"\r
68 #include "../z80.h"\r
69 #include "../pc8801/pc88.h"\r
70 #endif\r
71 \r
72 #include "../../fileio.h"\r
73 \r
74 // ----------------------------------------------------------------------------\r
75 // initialize\r
76 // ----------------------------------------------------------------------------\r
77 \r
78 VM::VM(EMU* parent_emu) : emu(parent_emu)\r
79 {\r
80         // check configs\r
81 #if defined(_PC98DO)\r
82         boot_mode = config.boot_mode;\r
83 #endif\r
84         int cpu_clocks = CPU_CLOCKS;\r
85 #if defined(PIT_CLOCK_8MHZ)\r
86         pit_clock_8mhz = true;\r
87 #else\r
88         pit_clock_8mhz = false;\r
89 #endif\r
90 #if defined(_PC9801E)\r
91         if(config.cpu_type != 0) {\r
92                 // 8MHz -> 5MHz\r
93                 cpu_clocks = 4992030;\r
94                 pit_clock_8mhz = false;\r
95         }\r
96 #elif defined(_PC9801VM) || defined(_PC98DO)\r
97         if(config.cpu_type != 0) {\r
98                 // 10MHz -> 8MHz\r
99                 cpu_clocks = 7987248;\r
100                 pit_clock_8mhz = true;\r
101         }\r
102 #endif\r
103         int pit_clocks = pit_clock_8mhz ? 1996812 : 2457600;\r
104         \r
105         // create devices\r
106         first_device = last_device = NULL;\r
107         dummy = new DEVICE(this, emu);  // must be 1st device\r
108         event = new EVENT(this, emu);   // must be 2nd device\r
109         \r
110 #if defined(SUPPORT_OLD_BUZZER)\r
111         beep = new BEEP(this, emu);\r
112 #else\r
113         beep = new PCM1BIT(this, emu);\r
114 #endif\r
115         dma = new I8237(this, emu);\r
116 #if defined(SUPPORT_CMT_IF)\r
117         sio_cmt = new I8251(this, emu);         // for cmt\r
118 #endif\r
119         sio_rs = new I8251(this, emu);          // for rs232c\r
120         sio_kbd = new I8251(this, emu);         // for keyboard\r
121         pit = new I8253(this, emu);\r
122 #if defined(SUPPORT_320KB_FDD_IF)\r
123         pio_fdd = new I8255(this, emu);         // for 320kb fdd i/f\r
124 #endif\r
125         pio_mouse = new I8255(this, emu);       // for mouse\r
126         pio_sys = new I8255(this, emu);         // for system port\r
127         pio_prn = new I8255(this, emu);         // for printer\r
128         pic = new I8259(this, emu);\r
129 #if defined(HAS_V30)\r
130         cpu = new I86(this, emu);\r
131 #else\r
132         cpu = new I286(this, emu);\r
133 #endif\r
134         io = new IO(this, emu);\r
135         dmareg1 = new LS244(this, emu);\r
136         dmareg2 = new LS244(this, emu);\r
137         dmareg3 = new LS244(this, emu);\r
138         dmareg0 = new LS244(this, emu);\r
139         rtcreg = new LS244(this, emu);\r
140         memory = new MEMORY(this, emu);\r
141 #if defined(HAS_I86) || defined(HAS_V30)\r
142         not = new NOT(this, emu);\r
143 #endif\r
144         rtc = new UPD1990A(this, emu);\r
145 #if defined(SUPPORT_2HD_FDD_IF)\r
146         fdc_2hd = new UPD765A(this, emu);\r
147 #endif\r
148 #if defined(SUPPORT_2DD_FDD_IF)\r
149         fdc_2dd = new UPD765A(this, emu);\r
150 #endif\r
151 #if defined(SUPPORT_2HD_2DD_FDD_IF)\r
152         fdc = new UPD765A(this, emu);\r
153 #endif\r
154         gdc_chr = new UPD7220(this, emu);\r
155         gdc_gfx = new UPD7220(this, emu);\r
156         opn = new YM2203(this, emu);\r
157         \r
158 #if defined(SUPPORT_CMT_IF)\r
159         cmt = new CMT(this, emu);\r
160 #endif\r
161         display = new DISPLAY(this, emu);\r
162         floppy = new FLOPPY(this, emu);\r
163         fmsound = new FMSOUND(this, emu);\r
164         joystick = new JOYSTICK(this, emu);\r
165         keyboard = new KEYBOARD(this, emu);\r
166         mouse = new MOUSE(this, emu);\r
167         printer = new PRINTER(this, emu);\r
168         \r
169 #if defined(SUPPORT_320KB_FDD_IF)\r
170         // 320kb fdd drives\r
171         pio_sub = new I8255(this, emu);\r
172         pc80s31k = new PC80S31K(this, emu);\r
173         fdc_sub = new UPD765A(this, emu);\r
174         cpu_sub = new Z80(this, emu);\r
175 #endif\r
176         \r
177         /* IRQ  0  PIT\r
178                 1  KEYBOARD\r
179                 2  CRTV\r
180                 3  \r
181                 4  RS-232C\r
182                 5  \r
183                 6  \r
184                 7  SLAVE PIC\r
185                 8  PRINTER\r
186                 9  \r
187                 10 FDC (640KB I/F)\r
188                 11 FDC (1MB I/F)\r
189                 12 PC-9801-26(K)\r
190                 13 MOUSE\r
191                 14 \r
192                 15 (RESERVED)\r
193         */\r
194         \r
195         // set contexts\r
196         event->set_context_cpu(cpu, cpu_clocks);\r
197 #if defined(SUPPORT_320KB_FDD_IF)\r
198         event->set_context_cpu(cpu_sub, 4000000);\r
199 #endif\r
200         event->set_context_sound(beep);\r
201         event->set_context_sound(opn);\r
202         \r
203         dma->set_context_memory(memory);\r
204         // dma ch.0: sasi\r
205         // dma ch.1: memory refresh\r
206 #if defined(SUPPORT_2HD_FDD_IF)\r
207         dma->set_context_ch2(fdc_2hd);\r
208 #endif\r
209 #if defined(SUPPORT_2DD_FDD_IF)\r
210         dma->set_context_ch3(fdc_2dd);\r
211 #endif\r
212 #if defined(SUPPORT_2HD_2DD_FDD_IF)\r
213         dma->set_context_ch2(fdc);\r
214         dma->set_context_ch3(fdc);\r
215 #endif\r
216 //      sio_rs->set_context_rxrdy(pic, SIG_I8259_CHIP0 | SIG_I8259_IR4, 1);\r
217         sio_kbd->set_context_rxrdy(pic, SIG_I8259_CHIP0 | SIG_I8259_IR1, 1);\r
218         pit->set_context_ch0(pic, SIG_I8259_CHIP0 | SIG_I8259_IR0, 1);\r
219 #if defined(SUPPORT_OLD_BUZZER)\r
220         // pit ch.1: memory refresh\r
221 #else\r
222         // pit ch.1: buzzer\r
223         pit->set_context_ch1(beep, SIG_PCM1BIT_SIGNAL, 1);\r
224 #endif\r
225         // pit ch.2: rs-232c\r
226         pit->set_constant_clock(0, pit_clocks);\r
227         pit->set_constant_clock(1, pit_clocks);\r
228         pit->set_constant_clock(2, pit_clocks);\r
229         pio_mouse->set_context_port_c(mouse, SIG_MOUSE_PORT_C, 0xf0, 0);\r
230         // sysport port.c bit6: printer strobe\r
231 #if defined(SUPPORT_OLD_BUZZER)\r
232         pio_sys->set_context_port_c(beep, SIG_BEEP_MUTE, 8, 0);\r
233 #else\r
234         pio_sys->set_context_port_c(beep, SIG_PCM1BIT_MUTE, 8, 0);\r
235 #endif\r
236         // sysport port.c bit2: enable txrdy interrupt\r
237         // sysport port.c bit1: enable txempty interrupt\r
238         // sysport port.c bit0: enable rxrdy interrupt\r
239         pio_prn->set_context_port_a(printer, SIG_PRINTER_OUT, 0xff, 0);\r
240         pio_prn->set_context_port_c(printer, SIG_PRINTER_STB, 0x80, 0);\r
241 #if defined(HAS_I86) || defined(HAS_V30)\r
242         pio_prn->set_context_port_c(not, SIG_NOT_INPUT, 8, 0);\r
243         not->set_context_out(pic, SIG_I8259_CHIP1 | SIG_I8259_IR0, 1);\r
244 #endif\r
245         dmareg1->set_context_output(dma, SIG_I8237_BANK1, 0x0f, 0);\r
246         dmareg2->set_context_output(dma, SIG_I8237_BANK2, 0x0f, 0);\r
247         dmareg3->set_context_output(dma, SIG_I8237_BANK3, 0x0f, 0);\r
248         dmareg0->set_context_output(dma, SIG_I8237_BANK0, 0x0f, 0);\r
249         rtcreg->set_context_output(rtc, SIG_UPD1990A_CMD, 0x07, 0);\r
250         rtcreg->set_context_output(rtc, SIG_UPD1990A_DIN, 0x20, 0);\r
251         rtcreg->set_context_output(rtc, SIG_UPD1990A_STB, 0x08, 0);\r
252         rtcreg->set_context_output(rtc, SIG_UPD1990A_CLK, 0x10, 0);\r
253         pic->set_context_cpu(cpu);\r
254         rtc->set_context_dout(pio_sys, SIG_I8255_PORT_B, 1);\r
255         opn->set_context_irq(pic, SIG_I8259_CHIP1 | SIG_I8259_IR4, 1);\r
256         opn->set_context_port_b(joystick, SIG_JOYSTICK_SELECT, 0xc0, 0);\r
257         \r
258         display->set_context_pic(pic);\r
259         display->set_context_gdc_chr(gdc_chr, gdc_chr->get_ra());\r
260         display->set_context_gdc_gfx(gdc_gfx, gdc_gfx->get_ra(), gdc_gfx->get_cs());\r
261         fmsound->set_context_opn(opn);\r
262         joystick->set_context_opn(opn);\r
263         keyboard->set_context_sio(sio_kbd);\r
264         mouse->set_context_pic(pic);\r
265         mouse->set_context_pio(pio_mouse);\r
266         \r
267 #if defined(SUPPORT_2HD_FDD_IF)\r
268         fdc_2hd->set_context_irq(floppy, SIG_FLOPPY_2HD_IRQ, 1);\r
269         fdc_2hd->set_context_drq(floppy, SIG_FLOPPY_2HD_DRQ, 1);\r
270         fdc_2hd->raise_irq_when_media_changed = true;\r
271         floppy->set_context_fdc_2hd(fdc_2hd);\r
272 #endif\r
273 #if defined(SUPPORT_2DD_FDD_IF)\r
274         fdc_2dd->set_context_irq(floppy, SIG_FLOPPY_2DD_IRQ, 1);\r
275         fdc_2dd->set_context_drq(floppy, SIG_FLOPPY_2DD_DRQ, 1);\r
276         fdc_2dd->raise_irq_when_media_changed = true;\r
277         floppy->set_context_fdc_2dd(fdc_2dd);\r
278 #endif\r
279 #if defined(SUPPORT_2HD_2DD_FDD_IF)\r
280         fdc->set_context_irq(floppy, SIG_FLOPPY_IRQ, 1);\r
281         fdc->set_context_drq(floppy, SIG_FLOPPY_DRQ, 1);\r
282         fdc->raise_irq_when_media_changed = true;\r
283         floppy->set_context_fdc(fdc);\r
284 #endif\r
285         floppy->set_context_dma(dma);\r
286         floppy->set_context_pic(pic);\r
287         \r
288 #if defined(SUPPORT_CMT_IF)\r
289         sio_cmt->set_context_out(cmt, SIG_CMT_OUT);\r
290 //      sio_cmt->set_context_txrdy(cmt, SIG_CMT_TXRDY, 1);\r
291 //      sio_cmt->set_context_rxrdy(cmt, SIG_CMT_RXRDY, 1);\r
292 //      sio_cmt->set_context_txe(cmt, SIG_CMT_TXEMP, 1);\r
293         cmt->set_context_sio(sio_cmt);\r
294 #endif\r
295         \r
296         // cpu bus\r
297         cpu->set_context_mem(memory);\r
298         cpu->set_context_io(io);\r
299         cpu->set_context_intr(pic);\r
300 #ifdef SINGLE_MODE_DMA\r
301         cpu->set_context_dma(dma);\r
302 #endif\r
303 #ifdef USE_DEBUGGER\r
304         cpu->set_context_debugger(new DEBUGGER(this, emu));\r
305 #endif\r
306         \r
307 #if defined(SUPPORT_320KB_FDD_IF)\r
308         // 320kb fdd drives\r
309         pc80s31k->set_context_cpu(cpu_sub);\r
310         pc80s31k->set_context_fdc(fdc_sub);\r
311         pc80s31k->set_context_pio(pio_sub);\r
312         pio_fdd->set_context_port_a(pio_sub, SIG_I8255_PORT_A, 0xff, 0);\r
313         pio_fdd->set_context_port_b(pio_sub, SIG_I8255_PORT_A, 0xff, 0);\r
314         pio_fdd->set_context_port_c(pio_sub, SIG_I8255_PORT_C, 0x0f, 4);\r
315         pio_fdd->set_context_port_c(pio_sub, SIG_I8255_PORT_C, 0xf0, -4);\r
316         pio_fdd->clear_ports_by_cmdreg = true;\r
317         pio_sub->set_context_port_a(pio_fdd, SIG_I8255_PORT_B, 0xff, 0);\r
318         pio_sub->set_context_port_b(pio_fdd, SIG_I8255_PORT_A, 0xff, 0);\r
319         pio_sub->set_context_port_c(pio_fdd, SIG_I8255_PORT_C, 0x0f, 4);\r
320         pio_sub->set_context_port_c(pio_fdd, SIG_I8255_PORT_C, 0xf0, -4);\r
321         pio_sub->clear_ports_by_cmdreg = true;\r
322         fdc_sub->set_context_irq(cpu_sub, SIG_CPU_IRQ, 1);\r
323         cpu_sub->set_context_mem(pc80s31k);\r
324         cpu_sub->set_context_io(pc80s31k);\r
325         cpu_sub->set_context_intr(pc80s31k);\r
326 #ifdef USE_DEBUGGER\r
327         cpu_sub->set_context_debugger(new DEBUGGER(this, emu));\r
328 #endif\r
329 #endif\r
330         \r
331         // memory bus\r
332         memset(ram, 0, sizeof(ram));\r
333         memset(ipl, 0xff, sizeof(ipl));\r
334         memset(sound_bios, 0xff, sizeof(sound_bios));\r
335 #if defined(_PC9801) || defined(_PC9801E)\r
336         memset(fd_bios_2hd, 0xff, sizeof(fd_bios_2hd));\r
337         memset(fd_bios_2dd, 0xff, sizeof(fd_bios_2dd));\r
338 #endif\r
339         \r
340         memory->read_bios(_T("IPL.ROM"), ipl, sizeof(ipl));\r
341         int sound_bios_ok = memory->read_bios(_T("SOUND.ROM"), sound_bios, sizeof(sound_bios));\r
342 #if defined(_PC9801) || defined(_PC9801E)\r
343         memory->read_bios(_T("2HDIF.ROM"), fd_bios_2hd, sizeof(fd_bios_2hd));\r
344         memory->read_bios(_T("2DDIF.ROM"), fd_bios_2dd, sizeof(fd_bios_2dd));\r
345 #endif\r
346         \r
347         memory->set_memory_rw(0x00000, 0x9ffff, ram);\r
348         // A0000h - A1FFFh: TEXT VRAM\r
349         // A2000h - A3FFFh: ATTRIBUTE\r
350         memory->set_memory_mapped_io_rw(0xa0000, 0xa3fff, display);\r
351         // A8000h - BFFFFh: VRAM\r
352         memory->set_memory_mapped_io_rw(0xa8000, 0xbffff, display);\r
353         memory->set_memory_r(0xcc000, 0xcffff, sound_bios);\r
354 #if defined(_PC9801) || defined(_PC9801E)\r
355         memory->set_memory_r(0xd6000, 0xd6fff, fd_bios_2dd);\r
356         memory->set_memory_r(0xd7000, 0xd7fff, fd_bios_2hd);\r
357 #endif\r
358 #if defined(SUPPORT_16_COLORS)\r
359         // E0000h - E7FFFh: VRAM\r
360         memory->set_memory_mapped_io_rw(0xe0000, 0xe7fff, display);\r
361 #endif\r
362         memory->set_memory_r(0xe8000, 0xfffff, ipl);\r
363         \r
364         display->sound_bios_ok = (sound_bios_ok != 0);  // memory switch\r
365         \r
366         // i/o bus\r
367         io->set_iomap_alias_rw(0x00, pic, 0);\r
368         io->set_iomap_alias_rw(0x02, pic, 1);\r
369         io->set_iomap_alias_rw(0x08, pic, 2);\r
370         io->set_iomap_alias_rw(0x0a, pic, 3);\r
371         \r
372         io->set_iomap_alias_rw(0x01, dma, 0x00);\r
373         io->set_iomap_alias_rw(0x03, dma, 0x01);\r
374         io->set_iomap_alias_rw(0x05, dma, 0x02);\r
375         io->set_iomap_alias_rw(0x07, dma, 0x03);\r
376         io->set_iomap_alias_rw(0x09, dma, 0x04);\r
377         io->set_iomap_alias_rw(0x0b, dma, 0x05);\r
378         io->set_iomap_alias_rw(0x0d, dma, 0x06);\r
379         io->set_iomap_alias_rw(0x0f, dma, 0x07);\r
380         io->set_iomap_alias_rw(0x11, dma, 0x08);\r
381         io->set_iomap_alias_w(0x13, dma, 0x09);\r
382         io->set_iomap_alias_w(0x15, dma, 0x0a);\r
383         io->set_iomap_alias_w(0x17, dma, 0x0b);\r
384         io->set_iomap_alias_w(0x19, dma, 0x0c);\r
385         io->set_iomap_alias_rw(0x1b, dma, 0x0d);\r
386         io->set_iomap_alias_w(0x1d, dma, 0x0e);\r
387         io->set_iomap_alias_w(0x1f, dma, 0x0f);\r
388         io->set_iomap_single_w(0x21, dmareg1);\r
389         io->set_iomap_single_w(0x23, dmareg2);\r
390         io->set_iomap_single_w(0x25, dmareg3);\r
391         io->set_iomap_single_w(0x27, dmareg0);\r
392         \r
393         io->set_iomap_single_w(0x20, rtcreg);\r
394         \r
395         io->set_iomap_alias_rw(0x30, sio_rs, 0);\r
396         io->set_iomap_alias_rw(0x32, sio_rs, 1);\r
397         \r
398         io->set_iomap_alias_rw(0x31, pio_sys, 0);\r
399         io->set_iomap_alias_rw(0x33, pio_sys, 1);\r
400         io->set_iomap_alias_rw(0x35, pio_sys, 2);\r
401         io->set_iomap_alias_w(0x37, pio_sys, 3);\r
402         \r
403         io->set_iomap_alias_rw(0x40, pio_prn, 0);\r
404         io->set_iomap_alias_rw(0x42, pio_prn, 1);\r
405         io->set_iomap_alias_rw(0x44, pio_prn, 2);\r
406         io->set_iomap_alias_w(0x46, pio_prn, 3);\r
407         \r
408         io->set_iomap_alias_rw(0x41, sio_kbd, 0);\r
409         io->set_iomap_alias_rw(0x43, sio_kbd, 1);\r
410         \r
411         // 50h, 52h: NMI Flip Flop\r
412         \r
413 #if defined(SUPPORT_320KB_FDD_IF)\r
414         io->set_iomap_alias_rw(0x51, pio_fdd, 0);\r
415         io->set_iomap_alias_rw(0x53, pio_fdd, 1);\r
416         io->set_iomap_alias_rw(0x55, pio_fdd, 2);\r
417         io->set_iomap_alias_w(0x57, pio_fdd, 3);\r
418 #endif\r
419         \r
420         io->set_iomap_alias_rw(0x60, gdc_chr, 0);\r
421         io->set_iomap_alias_rw(0x62, gdc_chr, 1);\r
422         \r
423         io->set_iomap_single_w(0x64, display);\r
424         io->set_iomap_single_w(0x68, display);\r
425 #if defined(SUPPORT_16_COLORS)\r
426         io->set_iomap_single_w(0x6a, display);\r
427 #endif\r
428         io->set_iomap_single_w(0x6c, display);\r
429         io->set_iomap_single_w(0x6e, display);\r
430         \r
431         io->set_iomap_single_w(0x70, display);\r
432         io->set_iomap_single_w(0x72, display);\r
433         io->set_iomap_single_w(0x74, display);\r
434         io->set_iomap_single_w(0x76, display);\r
435         io->set_iomap_single_w(0x78, display);\r
436         io->set_iomap_single_w(0x7a, display);\r
437 #if defined(SUPPORT_16_COLORS)\r
438         io->set_iomap_single_w(0x7c, display);\r
439         io->set_iomap_single_w(0x7e, display);\r
440 #endif\r
441         \r
442         io->set_iomap_alias_rw(0x71, pit, 0);\r
443         io->set_iomap_alias_rw(0x73, pit, 1);\r
444         io->set_iomap_alias_rw(0x75, pit, 2);\r
445         io->set_iomap_alias_w(0x77, pit, 3);\r
446         \r
447         // 80h, 82h: SASI\r
448         \r
449         io->set_iomap_single_rw(0x90, floppy);\r
450         io->set_iomap_single_rw(0x92, floppy);\r
451         io->set_iomap_single_rw(0x94, floppy);\r
452         \r
453 #if defined(SUPPORT_CMT_IF)\r
454         io->set_iomap_alias_rw(0x91, sio_cmt, 0);\r
455         io->set_iomap_alias_rw(0x93, sio_cmt, 1);\r
456         io->set_iomap_single_w(0x95, cmt);\r
457         io->set_iomap_single_w(0x97, cmt);\r
458 #endif\r
459         \r
460         io->set_iomap_alias_rw(0xa0, gdc_gfx, 0);\r
461         io->set_iomap_alias_rw(0xa2, gdc_gfx, 1);\r
462         \r
463 #if defined(SUPPORT_2ND_VRAM)\r
464         io->set_iomap_single_w(0xa4, display);\r
465         io->set_iomap_single_w(0xa6, display);\r
466 #endif\r
467         io->set_iomap_single_rw(0xa8, display);\r
468         io->set_iomap_single_rw(0xaa, display);\r
469         io->set_iomap_single_rw(0xac, display);\r
470         io->set_iomap_single_rw(0xae, display);\r
471         \r
472         io->set_iomap_single_w(0xa1, display);\r
473         io->set_iomap_single_w(0xa3, display);\r
474         io->set_iomap_single_w(0xa5, display);\r
475         io->set_iomap_single_rw(0xa9, display);\r
476         \r
477 #if defined(SUPPORT_2HD_2DD_FDD_IF)\r
478         io->set_iomap_single_rw(0xbe, floppy);\r
479 #endif\r
480         io->set_iomap_single_rw(0xc8, floppy);\r
481         io->set_iomap_single_rw(0xca, floppy);\r
482         io->set_iomap_single_rw(0xcc, floppy);\r
483         \r
484         io->set_iomap_single_rw(0x188, fmsound);\r
485         io->set_iomap_single_rw(0x18a, fmsound);\r
486 #ifdef HAS_YM2608\r
487         io->set_iomap_single_rw(0x18c, fmsound);\r
488         io->set_iomap_single_rw(0x18e, fmsound);\r
489         io->set_iomap_single_rw(0xa460, fmsound);\r
490 #endif\r
491         \r
492 #if !defined(SUPPORT_OLD_BUZZER)\r
493         io->set_iomap_alias_rw(0x3fd9, pit, 0);\r
494         io->set_iomap_alias_rw(0x3fdb, pit, 1);\r
495         io->set_iomap_alias_rw(0x3fdd, pit, 2);\r
496         io->set_iomap_alias_w(0x3fdf, pit, 3);\r
497 #endif\r
498         \r
499         io->set_iomap_alias_rw(0x7fd9, pio_mouse, 0);\r
500         io->set_iomap_alias_rw(0x7fdb, pio_mouse, 1);\r
501         io->set_iomap_alias_rw(0x7fdd, pio_mouse, 2);\r
502         io->set_iomap_alias_w(0x7fdf, pio_mouse, 3);\r
503 #if !(defined(_PC9801) || defined(_PC9801E))\r
504         io->set_iomap_single_w(0xbfdb, mouse);\r
505 #endif\r
506         \r
507 #if defined(_PC98DO)\r
508         pc88event = new EVENT(this, emu);\r
509         pc88event->set_frames_per_sec(60);\r
510         pc88event->set_lines_per_frame(260);\r
511         \r
512         pc88 = new PC88(this, emu);\r
513         pc88->set_context_event_manager(pc88event);\r
514         pc88beep = new BEEP(this, emu);\r
515         pc88beep->set_context_event_manager(pc88event);\r
516         pc88sio = new I8251(this, emu);\r
517         pc88sio->set_context_event_manager(pc88event);\r
518         pc88pio = new I8255(this, emu);\r
519         pc88pio->set_context_event_manager(pc88event);\r
520         pc88pcm = new PCM1BIT(this, emu);\r
521         pc88pcm->set_context_event_manager(pc88event);\r
522         pc88rtc = new UPD1990A(this, emu);\r
523         pc88rtc->set_context_event_manager(pc88event);\r
524         pc88opn = new YM2203(this, emu);\r
525         pc88opn->set_context_event_manager(pc88event);\r
526         pc88cpu = new Z80(this, emu);\r
527         pc88cpu->set_context_event_manager(pc88event);\r
528         \r
529         pc88sub = new PC80S31K(this, emu);\r
530         pc88sub->set_context_event_manager(pc88event);\r
531         pc88pio_sub = new I8255(this, emu);\r
532         pc88pio_sub->set_context_event_manager(pc88event);\r
533         pc88fdc_sub = new UPD765A(this, emu);\r
534         pc88fdc_sub->set_context_event_manager(pc88event);\r
535         pc88cpu_sub = new Z80(this, emu);\r
536         pc88cpu_sub->set_context_event_manager(pc88event);\r
537         \r
538         pc88event->set_context_cpu(pc88cpu, (config.cpu_type != 0) ? 3993624 : 7987248);\r
539         pc88event->set_context_cpu(pc88cpu_sub, 3993624);\r
540         pc88event->set_context_sound(pc88beep);\r
541         pc88event->set_context_sound(pc88opn);\r
542         pc88event->set_context_sound(pc88pcm);\r
543         \r
544         pc88->set_context_beep(pc88beep);\r
545         pc88->set_context_cpu(pc88cpu);\r
546         pc88->set_context_opn(pc88opn);\r
547         pc88->set_context_pcm(pc88pcm);\r
548         pc88->set_context_pio(pc88pio);\r
549         pc88->set_context_rtc(pc88rtc);\r
550         pc88->set_context_sio(pc88sio);\r
551         pc88cpu->set_context_mem(pc88);\r
552         pc88cpu->set_context_io(pc88);\r
553         pc88cpu->set_context_intr(pc88);\r
554 #ifdef USE_DEBUGGER\r
555         pc88cpu->set_context_debugger(new DEBUGGER(this, emu));\r
556 #endif\r
557         pc88opn->set_context_irq(pc88, SIG_PC88_SOUND_IRQ, 1);\r
558         pc88sio->set_context_rxrdy(pc88, SIG_PC88_USART_IRQ, 1);\r
559         pc88sio->set_context_out(pc88, SIG_PC88_USART_OUT);\r
560         \r
561         pc88sub->set_context_cpu(pc88cpu_sub);\r
562         pc88sub->set_context_fdc(pc88fdc_sub);\r
563         pc88sub->set_context_pio(pc88pio_sub);\r
564         pc88pio->set_context_port_a(pc88pio_sub, SIG_I8255_PORT_B, 0xff, 0);\r
565         pc88pio->set_context_port_b(pc88pio_sub, SIG_I8255_PORT_A, 0xff, 0);\r
566         pc88pio->set_context_port_c(pc88pio_sub, SIG_I8255_PORT_C, 0x0f, 4);\r
567         pc88pio->set_context_port_c(pc88pio_sub, SIG_I8255_PORT_C, 0xf0, -4);\r
568         pc88pio->clear_ports_by_cmdreg = true;\r
569         pc88pio_sub->set_context_port_a(pc88pio, SIG_I8255_PORT_B, 0xff, 0);\r
570         pc88pio_sub->set_context_port_b(pc88pio, SIG_I8255_PORT_A, 0xff, 0);\r
571         pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0x0f, 4);\r
572         pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0xf0, -4);\r
573         pc88pio_sub->clear_ports_by_cmdreg = true;\r
574         pc88fdc_sub->set_context_irq(pc88cpu_sub, SIG_CPU_IRQ, 1);\r
575         pc88cpu_sub->set_context_mem(pc88sub);\r
576         pc88cpu_sub->set_context_io(pc88sub);\r
577         pc88cpu_sub->set_context_intr(pc88sub);\r
578 #ifdef USE_DEBUGGER\r
579         pc88cpu_sub->set_context_debugger(new DEBUGGER(this, emu));\r
580 #endif\r
581 #endif\r
582         \r
583         // initialize all devices\r
584         for(DEVICE* device = first_device; device; device = device->next_device) {\r
585                 device->initialize();\r
586         }\r
587 }\r
588 \r
589 VM::~VM()\r
590 {\r
591         // delete all devices\r
592         for(DEVICE* device = first_device; device;) {\r
593                 DEVICE *next_device = device->next_device;\r
594                 device->release();\r
595                 delete device;\r
596                 device = next_device;\r
597         }\r
598 }\r
599 \r
600 DEVICE* VM::get_device(int id)\r
601 {\r
602         for(DEVICE* device = first_device; device; device = device->next_device) {\r
603                 if(device->this_device_id == id) {\r
604                         return device;\r
605                 }\r
606         }\r
607         return NULL;\r
608 }\r
609 \r
610 // ----------------------------------------------------------------------------\r
611 // drive virtual machine\r
612 // ----------------------------------------------------------------------------\r
613 \r
614 void VM::reset()\r
615 {\r
616         // reset all devices\r
617         for(DEVICE* device = first_device; device; device = device->next_device) {\r
618                 device->reset();\r
619         }\r
620 #if defined(_PC98DO)\r
621         for(DEVICE* device = first_device; device; device = device->next_device) {\r
622                 device->reset();\r
623         }\r
624 #endif\r
625         \r
626         // initial device settings\r
627         pio_mouse->write_signal(SIG_I8255_PORT_A, 0xf0, 0xff);  // clear mouse status\r
628         pio_mouse->write_signal(SIG_I8255_PORT_B, 0x40, 0xff);  // cpu high & sw3-6\r
629         uint8 port_c = 0x08;    // normal mode & sw1-5 & sw1-6\r
630 #if defined(HAS_V30) || defined(HAS_V33)\r
631         port_c |= 0x04;         // V30\r
632 #endif\r
633         pio_mouse->write_signal(SIG_I8255_PORT_C, 0x40, 0xff);\r
634         \r
635         pio_sys->write_signal(SIG_I8255_PORT_A, 0xe3, 0xff);\r
636         pio_sys->write_signal(SIG_I8255_PORT_B, 0xf8, 0xff);//0xe8??\r
637         \r
638 #if defined(_PC9801)\r
639         uint8 prn_b = 0x00;     // system type = first PC-9801\r
640 #elif defined(_PC9801U)\r
641         uint8 prn_b = 0xc0;     // system type = PC-9801U,PC-98LT,PC-98HA\r
642 #else\r
643         uint8 prn_b = 0x80;     // system type = others\r
644 #endif\r
645         if(pit_clock_8mhz) {\r
646                 prn_b |= 0x20;          // system clock is 8MHz\r
647         }\r
648         prn_b |= 0x10;          // don't use LCD display\r
649 #if !defined(SUPPORT_16_COLORS)\r
650         prn_b |= 0x08;          // standard graphics\r
651 #endif\r
652         prn_b |= 0x04;          // printer is not busy\r
653 #if defined(HAS_V30) || defined(HAS_V33)\r
654         prn_b |= 0x02;\r
655 #endif\r
656 #if defined(_PC9801VF) || defined(_PC9801U)\r
657         prn_b |= 0x01;          // PC-9801VF or PC-9801U\r
658 #endif\r
659         pio_prn->write_signal(SIG_I8255_PORT_B, prn_b, 0xff);\r
660         \r
661 #if defined(SUPPORT_320KB_FDD_IF)\r
662         pio_fdd->write_signal(SIG_I8255_PORT_A, 0xff, 0xff);\r
663         pio_fdd->write_signal(SIG_I8255_PORT_B, 0xff, 0xff);\r
664         pio_fdd->write_signal(SIG_I8255_PORT_C, 0xff, 0xff);\r
665 #endif\r
666 #if defined(SUPPORT_2DD_FDD_IF)\r
667         fdc_2dd->write_signal(SIG_UPD765A_FREADY, 1, 1);        // 2DD FDC RDY is pulluped\r
668 #endif\r
669         \r
670         opn->write_signal(SIG_YM2203_PORT_A, 0xff, 0xff);       // PC-9801-26(K) IRQ=12\r
671         \r
672 #if defined(SUPPORT_OLD_BUZZER)\r
673         beep->write_signal(SIG_BEEP_ON, 1, 1);\r
674         beep->write_signal(SIG_BEEP_MUTE, 1, 1);\r
675 #else\r
676         beep->write_signal(SIG_PCM1BIT_ON, 1, 1);\r
677         beep->write_signal(SIG_PCM1BIT_MUTE, 1, 1);\r
678 #endif\r
679         \r
680 #if defined(_PC98DO)\r
681         pc88opn->SetReg(0x29, 3); // for Misty Blue\r
682         pc88pio->write_signal(SIG_I8255_PORT_C, 0, 0xff);\r
683         pc88pio_sub->write_signal(SIG_I8255_PORT_C, 0, 0xff);\r
684 #endif\r
685 }\r
686 \r
687 void VM::run()\r
688 {\r
689 #if defined(_PC98DO)\r
690         if(boot_mode != 0) {\r
691                 pc88event->drive();\r
692         } else\r
693 #endif\r
694         event->drive();\r
695 }\r
696 \r
697 double VM::frame_rate()\r
698 {\r
699 #if defined(_PC98DO)\r
700         if(config.boot_mode != 0) {\r
701                 return pc88event->frame_rate();\r
702         } else\r
703 #endif\r
704         return event->frame_rate();\r
705 }\r
706 \r
707 // ----------------------------------------------------------------------------\r
708 // debugger\r
709 // ----------------------------------------------------------------------------\r
710 \r
711 #ifdef USE_DEBUGGER\r
712 DEVICE *VM::get_cpu(int index)\r
713 {\r
714 #if defined(_PC98DO)\r
715         if(index == 0 && boot_mode == 0) {\r
716                 return cpu;\r
717         } else if(index == 1 && boot_mode != 0) {\r
718                 return pc88cpu;\r
719         } else if(index == 2 && boot_mode != 0) {\r
720                 return pc88cpu_sub;\r
721         }\r
722 #else\r
723         if(index == 0) {\r
724                 return cpu;\r
725 #if defined(SUPPORT_320KB_FDD_IF)\r
726         } else if(index == 1) {\r
727                 return cpu_sub;\r
728 #endif\r
729         }\r
730 #endif\r
731         return NULL;\r
732 }\r
733 #endif\r
734 \r
735 // ----------------------------------------------------------------------------\r
736 // draw screen\r
737 // ----------------------------------------------------------------------------\r
738 \r
739 void VM::draw_screen()\r
740 {\r
741 #if defined(_PC98DO)\r
742         if(boot_mode != 0) {\r
743                 pc88->draw_screen();\r
744         } else\r
745 #endif\r
746         display->draw_screen();\r
747 }\r
748 \r
749 int VM::access_lamp()\r
750 {\r
751 #if defined(_PC9801) || defined(_PC9801E)\r
752         return (fdc_2hd->read_signal(0) & 3) | (fdc_2dd->read_signal(0) & 3) | (fdc_sub->read_signal(0) & 3);\r
753 #elif defined(_PC9801VF) || defined(_PC9801U)\r
754         return fdc_2dd->read_signal(0);\r
755 #elif defined(_PC98DO)\r
756         if(boot_mode != 0) {\r
757                 return pc88fdc_sub->read_signal(0);\r
758         } else {\r
759                 return fdc->read_signal(0);\r
760         }\r
761 #else\r
762         return fdc->read_signal(0);\r
763 #endif\r
764 }\r
765 \r
766 // ----------------------------------------------------------------------------\r
767 // soud manager\r
768 // ----------------------------------------------------------------------------\r
769 \r
770 void VM::initialize_sound(int rate, int samples)\r
771 {\r
772         // init sound manager\r
773         event->initialize_sound(rate, samples);\r
774         \r
775         // init sound gen\r
776 #if defined(SUPPORT_OLD_BUZZER)\r
777         beep->init(rate, 2400, 8000);\r
778 #else\r
779         beep->init(rate, 8000);\r
780 #endif\r
781 #ifdef HAS_YM2608\r
782         opn->init(rate, 7987248, samples, 0, 0);\r
783 #else\r
784         opn->init(rate, 3993624, samples, 0, 0);\r
785 #endif\r
786         \r
787 #if defined(_PC98DO)\r
788         // init sound manager\r
789         pc88event->initialize_sound(rate, samples);\r
790         \r
791         // init sound gen\r
792         pc88beep->init(rate, 2400, 8000);\r
793 #ifdef HAS_YM2608\r
794         pc88opn->init(rate, 7987248, samples, 0, 0);\r
795 #else\r
796         pc88opn->init(rate, 3993624, samples, 0, 0);\r
797 #endif\r
798         pc88pcm->init(rate, 8000);\r
799 #endif\r
800 }\r
801 \r
802 uint16* VM::create_sound(int* extra_frames)\r
803 {\r
804 #if defined(_PC98DO)\r
805         if(boot_mode != 0) {\r
806                 return pc88event->create_sound(extra_frames);\r
807         } else\r
808 #endif\r
809         return event->create_sound(extra_frames);\r
810 }\r
811 \r
812 int VM::sound_buffer_ptr()\r
813 {\r
814 #if defined(_PC98DO)\r
815         if(boot_mode != 0) {\r
816                 return pc88event->sound_buffer_ptr();\r
817         } else\r
818 #endif\r
819         return event->sound_buffer_ptr();\r
820 }\r
821 \r
822 // ----------------------------------------------------------------------------\r
823 // notify key\r
824 // ----------------------------------------------------------------------------\r
825 \r
826 void VM::key_down(int code, bool repeat)\r
827 {\r
828 #if defined(_PC98DO)\r
829         if(boot_mode != 0) {\r
830                 pc88->key_down(code, repeat);\r
831         } else\r
832 #endif\r
833         keyboard->key_down(code, repeat);\r
834 }\r
835 \r
836 void VM::key_up(int code)\r
837 {\r
838 #if defined(_PC98DO)\r
839         if(boot_mode != 0) {\r
840 //              pc88->key_up(code);\r
841         } else\r
842 #endif\r
843         keyboard->key_up(code);\r
844 }\r
845 \r
846 // ----------------------------------------------------------------------------\r
847 // user interface\r
848 // ----------------------------------------------------------------------------\r
849 \r
850 void VM::open_disk(int drv, _TCHAR* file_path, int offset)\r
851 {\r
852 #if defined(_PC9801) || defined(_PC9801E)\r
853         if(drv == 0 || drv == 1) {\r
854                 fdc_2hd->open_disk(drv, file_path, offset);\r
855         } else if(drv == 2 || drv == 3) {\r
856                 fdc_2dd->open_disk(drv - 2, file_path, offset);\r
857         } else if(drv == 4 || drv == 5) {\r
858                 fdc_sub->open_disk(drv - 4, file_path, offset);\r
859         }\r
860 #elif defined(_PC9801VF) || defined(_PC9801U)\r
861         if(drv == 0 || drv == 1) {\r
862                 fdc_2dd->open_disk(drv, file_path, offset);\r
863         }\r
864 #elif defined(_PC98DO)\r
865         if(drv == 0 || drv == 1) {\r
866                 fdc->open_disk(drv, file_path, offset);\r
867         } else if(drv == 2 || drv == 3) {\r
868                 pc88fdc_sub->open_disk(drv - 2, file_path, offset);\r
869         }\r
870 #else\r
871         if(drv == 0 || drv == 1) {\r
872                 fdc->open_disk(drv, file_path, offset);\r
873         }\r
874 #endif\r
875 }\r
876 \r
877 void VM::close_disk(int drv)\r
878 {\r
879 #if defined(_PC9801) || defined(_PC9801E)\r
880         if(drv == 0 || drv == 1) {\r
881                 fdc_2hd->close_disk(drv);\r
882         } else if(drv == 2 || drv == 3) {\r
883                 fdc_2dd->close_disk(drv - 2);\r
884         } else if(drv == 4 || drv == 5) {\r
885                 fdc_sub->close_disk(drv - 4);\r
886         }\r
887 #elif defined(_PC9801VF) || defined(_PC9801U)\r
888         if(drv == 0 || drv == 1) {\r
889                 fdc_2dd->close_disk(drv);\r
890         }\r
891 #elif defined(_PC98DO)\r
892         if(drv == 0 || drv == 1) {\r
893                 fdc->close_disk(drv);\r
894         } else if(drv == 2 || drv == 3) {\r
895                 pc88fdc_sub->close_disk(drv - 2);\r
896         }\r
897 #else\r
898         if(drv == 0 || drv == 1) {\r
899                 fdc->close_disk(drv);\r
900         }\r
901 #endif\r
902 }\r
903 \r
904 bool VM::disk_inserted(int drv)\r
905 {\r
906 #if defined(_PC9801) || defined(_PC9801E)\r
907         if(drv == 0 || drv == 1) {\r
908                 return fdc_2hd->disk_inserted(drv);\r
909         } else if(drv == 2 || drv == 3) {\r
910                 return fdc_2dd->disk_inserted(drv - 2);\r
911         } else if(drv == 4 || drv == 5) {\r
912                 return fdc_sub->disk_inserted(drv - 4);\r
913         }\r
914 #elif defined(_PC9801VF) || defined(_PC9801U)\r
915         if(drv == 0 || drv == 1) {\r
916                 return fdc_2dd->disk_inserted(drv);\r
917         }\r
918 #elif defined(_PC98DO)\r
919         if(drv == 0 || drv == 1) {\r
920                 return fdc->disk_inserted(drv);\r
921         } else if(drv == 2 || drv == 3) {\r
922                 return pc88fdc_sub->disk_inserted(drv - 2);\r
923         }\r
924 #else\r
925         if(drv == 0 || drv == 1) {\r
926                 return fdc->disk_inserted(drv);\r
927         }\r
928 #endif\r
929         return false;\r
930 }\r
931 \r
932 #if defined(SUPPORT_CMT_IF) || defined(_PC98DO)\r
933 void VM::play_tape(_TCHAR* file_path)\r
934 {\r
935 #if defined(_PC98DO)\r
936         pc88->play_tape(file_path);\r
937 #else\r
938         cmt->play_tape(file_path);\r
939 #endif\r
940 }\r
941 \r
942 void VM::rec_tape(_TCHAR* file_path)\r
943 {\r
944 #if defined(_PC98DO)\r
945         pc88->rec_tape(file_path);\r
946 #else\r
947         cmt->rec_tape(file_path);\r
948 #endif\r
949 }\r
950 \r
951 void VM::close_tape()\r
952 {\r
953 #if defined(_PC98DO)\r
954         pc88->close_tape();\r
955 #else\r
956         cmt->close_tape();\r
957 #endif\r
958 }\r
959 \r
960 bool VM::tape_inserted()\r
961 {\r
962 #if defined(_PC98DO)\r
963         return pc88->tape_inserted();\r
964 #else\r
965         return cmt->tape_inserted();\r
966 #endif\r
967 }\r
968 #endif\r
969 \r
970 bool VM::now_skip()\r
971 {\r
972 #if defined(_PC98DO)\r
973         if(boot_mode != 0) {\r
974 //              return pc88event->now_skip();\r
975                 return pc88->now_skip();\r
976         } else\r
977 #endif\r
978         return event->now_skip();\r
979 }\r
980 \r
981 void VM::update_config()\r
982 {\r
983 #if defined(_PC98DO)\r
984         if(boot_mode != config.boot_mode) {\r
985                 // boot mode is changed !!!\r
986                 boot_mode = config.boot_mode;\r
987                 reset();\r
988         } else\r
989 #endif\r
990         for(DEVICE* device = first_device; device; device = device->next_device) {\r
991                 device->update_config();\r
992         }\r
993 }\r
994 \r
995 #define STATE_VERSION   1\r
996 \r
997 void VM::save_state(FILEIO* state_fio)\r
998 {\r
999         state_fio->FputUint32(STATE_VERSION);\r
1000         \r
1001         for(DEVICE* device = first_device; device; device = device->next_device) {\r
1002                 device->save_state(state_fio);\r
1003         }\r
1004         state_fio->Fwrite(ram, sizeof(ram), 1);\r
1005         state_fio->FputBool(pit_clock_8mhz);\r
1006 #if defined(_PC98DO)\r
1007         state_fio->FputInt32(boot_mode);\r
1008 #endif\r
1009 }\r
1010 \r
1011 bool VM::load_state(FILEIO* state_fio)\r
1012 {\r
1013         if(state_fio->FgetUint32() != STATE_VERSION) {\r
1014                 return false;\r
1015         }\r
1016         for(DEVICE* device = first_device; device; device = device->next_device) {\r
1017                 if(!device->load_state(state_fio)) {\r
1018                         return false;\r
1019                 }\r
1020         }\r
1021         state_fio->Fread(ram, sizeof(ram), 1);\r
1022         pit_clock_8mhz = state_fio->FgetBool();\r
1023 #if defined(_PC98DO)\r
1024         boot_mode = state_fio->FgetInt32();\r
1025 #endif\r
1026         return true;\r
1027 }\r
1028 \r