OSDN Git Service

cd972272c390063a18b240721b425d0a26eda5cb
[csp-qt/common_source_project-fm7.git] / source / src / vm / x1 / x1.cpp
1 /*
2         SHARP X1 Emulator 'eX1'
3         SHARP X1twin Emulator 'eX1twin'
4         SHARP X1turbo Emulator 'eX1turbo'
5         SHARP X1turboZ Emulator 'eX1turboZ'
6
7         Author : Takeda.Toshiya
8         Date   : 2009.03.11-
9
10         [ virtual machine ]
11 */
12
13 #include "x1.h"
14 #include "../../emu.h"
15 #include "../device.h"
16 #include "../event.h"
17
18 #include "../datarec.h"
19 #include "../disk.h"
20 #include "../harddisk.h"
21 #include "../hd46505.h"
22 #include "../i8255.h"
23 #include "../io.h"
24 #include "../mb8877.h"
25 #include "../mz1p17.h"
26 #include "../noise.h"
27 //#include "../pcpr201.h"
28 #include "../prnfile.h"
29 #include "../scsi_hdd.h"
30 #include "../scsi_host.h"
31 #include "../ym2151.h"
32 //#include "../ym2203.h"
33 #include "../ay_3_891x.h"
34 #include "../z80.h"
35 #include "../z80ctc.h"
36 #include "../z80sio.h"
37 #ifdef _X1TURBO_FEATURE
38 #include "../z80dma.h"
39 #endif
40
41 #ifdef USE_DEBUGGER
42 #include "../debugger.h"
43 #endif
44
45 #include "display.h"
46 #include "emm.h"
47 #include "floppy.h"
48 #include "iobus.h"
49 #include "joystick.h"
50 #include "./memory.h"
51 #include "mouse.h"
52 #include "psub.h"
53 #include "sasi.h"
54
55 #include "../mcs48.h"
56 #include "../upd1990a.h"
57 #include "sub.h"
58 #include "keyboard.h"
59
60 #ifdef _X1TWIN
61 #include "../huc6280.h"
62 #include "../pcengine/pce.h"
63 #endif
64 #if defined(Q_OS_WIN)
65 DLL_PREFIX_I struct cur_time_s cur_time;
66 #endif
67
68 using X1::DISPLAY;
69 using X1::EMM;
70 using X1::FLOPPY;
71 using X1::IOBUS;
72 using X1::JOYSTICK;
73 using X1::MEMORY;
74 using X1::MOUSE;
75 using X1::PSUB;
76 using X1::SASI;
77 using X1::SUB;
78 using X1::KEYBOARD;
79 #ifdef _X1TWIN
80 using PCEDEV::PCE;
81 #endif
82 // ----------------------------------------------------------------------------
83 // initialize
84 // ----------------------------------------------------------------------------
85
86 VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
87 {
88         pseudo_sub_cpu = !(FILEIO::IsFileExisting(create_local_path(SUB_ROM_FILE_NAME)) && FILEIO::IsFileExisting(create_local_path(KBD_ROM_FILE_NAME)));
89         
90         sound_type = config.sound_type;
91         
92         // create devices
93         first_device = last_device = NULL;
94         dummy = new DEVICE(this, emu);  // must be 1st device
95         event = new EVENT(this, emu);   // must be 2nd device
96         dummy->set_device_name(_T("1st Dummy"));
97         
98         drec = new DATAREC(this, emu);
99         drec->set_context_noise_play(new NOISE(this, emu));
100         drec->set_context_noise_stop(new NOISE(this, emu));
101         drec->set_context_noise_fast(new NOISE(this, emu));
102         crtc = new HD46505(this, emu);
103         pio = new I8255(this, emu);
104         io = new IO(this, emu);
105         fdc = new MB8877(this, emu);
106         fdc->set_context_noise_seek(new NOISE(this, emu));
107         fdc->set_context_noise_head_down(new NOISE(this, emu));
108         fdc->set_context_noise_head_up(new NOISE(this, emu));
109         sasi_host = new SCSI_HOST(this, emu);
110         for(int i = 0; i < array_length(sasi_hdd); i++) {
111                 sasi_hdd[i] = new SASI_HDD(this, emu);
112                 sasi_hdd[i]->set_device_name(_T("SASI Hard Disk Drive #%d"), i + 1);
113                 sasi_hdd[i]->scsi_id = i;
114                 sasi_hdd[i]->bytes_per_sec = 32 * 1024; // 32KB/s
115                 sasi_hdd[i]->set_context_interface(sasi_host);
116                 sasi_host->set_context_target(sasi_hdd[i]);
117         }
118         for(int drv = 0; drv < USE_HARD_DISK; drv++) {
119                 sasi_hdd[drv >> 1]->set_disk_handler(drv & 1, new HARDDISK(emu));
120         }
121 //      psg = new YM2203(this, emu);
122         psg = new AY_3_891X(this, emu);
123         cpu = new Z80(this, emu);
124         ctc = new Z80CTC(this, emu);
125         sio = new Z80SIO(this, emu);
126         if(sound_type >= 1) {
127                 opm1 = new YM2151(this, emu);
128                 opm1->set_device_name(_T("YM2151 OPM (CZ-8BS1 #1)"));
129                 ctc1 = new Z80CTC(this, emu);
130                 ctc1->set_device_name(_T("Z80 CTC (CZ-8BS1 #1)"));
131         }
132         if(sound_type == 2) {
133                 opm2 = new YM2151(this, emu);
134                 opm2->set_device_name(_T("YM2151 OPM (CZ-8BS1 #2)"));
135                 ctc2 = new Z80CTC(this, emu);
136                 ctc2->set_device_name(_T("Z80 CTC (CZ-8BS1 #2)"));
137         }
138         if(config.printer_type == 0) {
139                 printer = new PRNFILE(this, emu);
140         } else if(config.printer_type == 1) {
141                 printer = new MZ1P17(this, emu);
142 //      } else if(config.printer_type == 2) {
143 //              printer = new PCPR201(this, emu);
144         } else {
145                 printer = dummy;
146         }
147 #ifdef _X1TURBO_FEATURE
148         dma = new Z80DMA(this, emu);
149 #endif
150         
151         display = new DISPLAY(this, emu);
152         emm = new EMM(this, emu);
153         floppy = new FLOPPY(this, emu);
154         iobus = new IOBUS(this, emu);
155         joy = new JOYSTICK(this, emu);
156         memory = new MEMORY(this, emu);
157         mouse = new MOUSE(this, emu);
158         sasi = new SASI(this, emu);
159         
160         if(pseudo_sub_cpu) {
161                 psub = new PSUB(this, emu);
162                 cpu_sub = NULL;
163                 cpu_kbd = NULL;
164         } else {
165                 // sub cpu
166                 cpu_sub = new MCS48(this, emu);
167                 cpu_sub->set_device_name(_T("MCS48 MCU (Sub)"));
168                 pio_sub = new I8255(this, emu);
169                 pio_sub->set_device_name(_T("i8255 PIO (Sub)"));
170                 rtc_sub = new UPD1990A(this, emu);
171                 rtc_sub->set_device_name(_T("uPD1990A RTC (Sub)"));
172                 sub = new SUB(this, emu);
173
174                 // keyboard
175                 cpu_kbd = new MCS48(this, emu);
176                 cpu_kbd->set_device_name(_T("MCS48 MCU (Keyboard)"));
177                 kbd = new KEYBOARD(this, emu);
178         }
179         
180         // set contexts
181         event->set_context_cpu(cpu);
182         if(!pseudo_sub_cpu) {
183                 event->set_context_cpu(cpu_sub, 6000000);
184                 event->set_context_cpu(cpu_kbd, 6000000);
185         }
186         if(sound_type >= 1) {
187                 event->set_context_sound(opm1);
188         }
189         if(sound_type == 2) {
190                 event->set_context_sound(opm2);
191         }
192         event->set_context_sound(psg);
193         event->set_context_sound(drec);
194         event->set_context_sound(fdc->get_context_noise_seek());
195         event->set_context_sound(fdc->get_context_noise_head_down());
196         event->set_context_sound(fdc->get_context_noise_head_up());
197         event->set_context_sound(drec->get_context_noise_play());
198         event->set_context_sound(drec->get_context_noise_stop());
199         event->set_context_sound(drec->get_context_noise_fast());
200         
201         drec->set_context_ear(pio, SIG_I8255_PORT_B, 0x02);
202         crtc->set_context_vblank(display, SIG_DISPLAY_VBLANK, 1);
203         crtc->set_context_disp(display, SIG_DISPLAY_DISP, 1);
204         crtc->set_context_vblank(pio, SIG_I8255_PORT_B, 0x80);
205         crtc->set_context_vsync(pio, SIG_I8255_PORT_B, 0x04);
206         pio->set_context_port_a(printer, SIG_PRINTER_DATA, 0xff, 0);
207         pio->set_context_port_c(drec, SIG_DATAREC_MIC, 0x01, 0);
208         pio->set_context_port_c(display, SIG_DISPLAY_COLUMN40, 0x40, 0);
209         pio->set_context_port_c(iobus, SIG_IOBUS_MODE, 0x60, 0);
210         pio->set_context_port_c(printer, SIG_PRINTER_STROBE, 0x80, 0);
211 #ifdef _X1TURBO_FEATURE
212         fdc->set_context_drq(dma, SIG_Z80DMA_READY, 1);
213 #endif
214         sasi_host->set_context_irq(sasi, SIG_SASI_IRQ, 1);
215         sasi_host->set_context_drq(sasi, SIG_SASI_DRQ, 1);
216         ctc->set_context_zc0(ctc, SIG_Z80CTC_TRIG_3, 1);
217         ctc->set_context_zc1(sio, SIG_Z80SIO_TX_CLK_CH0, 1);
218         ctc->set_context_zc1(sio, SIG_Z80SIO_RX_CLK_CH0, 1);
219         ctc->set_context_zc2(sio, SIG_Z80SIO_TX_CLK_CH1, 1);
220         ctc->set_context_zc2(sio, SIG_Z80SIO_RX_CLK_CH1, 1);
221         ctc->set_constant_clock(1, CPU_CLOCKS >> 1);
222         ctc->set_constant_clock(2, CPU_CLOCKS >> 1);
223         sio->set_context_rts(1, mouse, SIG_MOUSE_RTS, 1);
224 //      sio->set_tx_clock(0, 9600 * 16);        // 9600 baud for RS-232C
225 //      sio->set_rx_clock(0, 9600 * 16);        // clock is from Z-80CTC ch1 (2MHz/13)
226 //      sio->set_tx_clock(1, 4800 * 16);        // 4800 baud for mouse
227 //      sio->set_rx_clock(1, 4800 * 16);        // clock is from Z-80CTC ch2 (2MHz/26)
228         
229         if(sound_type >= 1) {
230                 ctc1->set_context_zc0(ctc1, SIG_Z80CTC_TRIG_3, 1);
231 //              ctc1->set_constant_clock(1, CPU_CLOCKS >> 1);
232 //              ctc1->set_constant_clock(2, CPU_CLOCKS >> 1);
233         }
234         if(sound_type == 2) {
235                 ctc2->set_context_zc0(ctc2, SIG_Z80CTC_TRIG_3, 1);
236 //              ctc2->set_constant_clock(1, CPU_CLOCKS >> 1);
237 //              ctc2->set_constant_clock(2, CPU_CLOCKS >> 1);
238         }
239         if(config.printer_type == 0) {
240                 PRNFILE *prnfile = (PRNFILE *)printer;
241                 prnfile->set_context_busy(pio, SIG_I8255_PORT_B, 0x08);
242         } else if(config.printer_type == 1) {
243                 MZ1P17 *mz1p17 = (MZ1P17 *)printer;
244                 mz1p17->mode = MZ1P17_MODE_X1;
245                 mz1p17->set_context_busy(pio, SIG_I8255_PORT_B, 0x08);
246 //      } else if(config.printer_type == 2) {
247 //              PCPR201 *pcpr201 = (PCPR201 *)printer;
248 //              pcpr201->set_context_busy(pio, SIG_I8255_PORT_B, 0x08);
249         }
250 #ifdef _X1TURBO_FEATURE
251         dma->set_context_memory(memory);
252         dma->set_context_io(iobus);
253 #endif
254         
255 #ifdef _X1TURBO_FEATURE
256         display->set_context_cpu(cpu);
257 #endif
258         display->set_context_crtc(crtc);
259         display->set_vram_ptr(iobus->get_vram());
260         display->set_regs_ptr(crtc->get_regs());
261         floppy->set_context_fdc(fdc);
262         iobus->set_context_cpu(cpu);
263         iobus->set_context_display(display);
264         iobus->set_context_io(io);
265         joy->set_context_psg(psg);
266 #ifdef _X1TURBO_FEATURE
267         memory->set_context_pio(pio);
268 #endif
269         mouse->set_context_sio(sio);
270         sasi->set_context_host(sasi_host);
271 #ifdef _X1TURBO_FEATURE
272         sasi->set_context_dma(dma);
273 #endif
274         
275         if(pseudo_sub_cpu) {
276                 drec->set_context_remote(psub, SIG_PSUB_TAPE_REMOTE, 1);
277                 drec->set_context_end(psub, SIG_PSUB_TAPE_END, 1);
278                 psub->set_context_pio(pio);
279                 psub->set_context_drec(drec);
280         } else {
281                 // sub cpu
282                 cpu_sub->set_context_mem(new MCS48MEM(this, emu));
283                 cpu_sub->set_context_io(sub);
284 #ifdef USE_DEBUGGER
285                 cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
286 #endif
287                 drec->set_context_end(sub, SIG_SUB_TAPE_END, 1);
288                 drec->set_context_apss(sub, SIG_SUB_TAPE_APSS, 1);
289                 pio_sub->set_context_port_c(sub, SIG_SUB_PIO_PORT_C, 0x80, 0);
290                 // pc1:break -> pb0 of 8255(main)
291                 pio_sub->set_context_port_c(pio, SIG_I8255_PORT_B, 0x02, -1);
292                 // pc5:ibf -> pb6 of 8255(main)
293                 pio_sub->set_context_port_c(pio, SIG_I8255_PORT_B, 0x20, 1);
294                 // pc7:obf -> pb5 of 8255(main)
295                 pio_sub->set_context_port_c(pio, SIG_I8255_PORT_B, 0x80, -2);
296                 // pc7:obf -> pb7 of 8255(sub)
297                 pio_sub->set_context_port_c(pio_sub, SIG_I8255_PORT_B, 0x80, 0);
298                 
299                 sub->set_context_pio(pio_sub);
300                 sub->set_context_rtc(rtc_sub);
301                 sub->set_context_drec(drec);
302                 
303                 // keyboard
304                 cpu_kbd->set_context_mem(new MCS48MEM(this, emu));
305                 cpu_kbd->set_context_io(kbd);
306 #ifdef USE_DEBUGGER
307                 cpu_kbd->set_context_debugger(new DEBUGGER(this, emu));
308 #endif
309                 kbd->set_context_cpu(cpu_sub);
310         }
311         
312         // cpu bus
313         cpu->set_context_mem(memory);
314         cpu->set_context_io(iobus);
315 #if defined(_X1TURBO_FEATURE) && defined(SINGLE_MODE_DMA)
316         cpu->set_context_dma(dma);
317 #endif
318 #ifdef USE_DEBUGGER
319         cpu->set_context_debugger(new DEBUGGER(this, emu));
320 #endif
321         
322         // z80 family daisy chain
323         DEVICE* parent_dev = NULL;
324         int level = 0;
325         
326         #define Z80_DAISY_CHAIN(dev) { \
327                 if(parent_dev == NULL) { \
328                         cpu->set_context_intr(dev); \
329                 } else { \
330                         parent_dev->set_context_child(dev); \
331                 } \
332                 dev->set_context_intr(cpu, level++); \
333                 parent_dev = dev; \
334         }
335 #ifndef _X1TURBO_FEATURE
336         Z80_DAISY_CHAIN(sio);   // CZ-8BM2
337         Z80_DAISY_CHAIN(ctc);
338 #endif
339         if(sound_type >= 1) {
340                 Z80_DAISY_CHAIN(ctc1);
341         }
342         if(sound_type == 2) {
343                 Z80_DAISY_CHAIN(ctc2);
344         }
345 #ifdef _X1TURBO_FEATURE
346         Z80_DAISY_CHAIN(sio);
347         Z80_DAISY_CHAIN(dma);
348         Z80_DAISY_CHAIN(ctc);
349 #endif
350         if(pseudo_sub_cpu) {
351                 Z80_DAISY_CHAIN(psub);
352         } else {
353                 Z80_DAISY_CHAIN(sub);
354         }
355         
356         // i/o bus
357         if(sound_type >= 1) {
358                 io->set_iomap_single_w(0x700, opm1);
359                 io->set_iovalue_single_r(0x700, 0x00);
360                 io->set_iomap_single_rw(0x701, opm1);
361 #ifdef _X1TURBOZ
362                 io->set_flipflop_single_rw(0x704, 0x00);
363 #else
364                 io->set_iomap_range_rw(0x704, 0x707, ctc1);
365 #endif
366         }
367         if(sound_type == 2) {
368                 io->set_iomap_single_w(0x708, opm2);
369                 io->set_iovalue_single_r(0x708, 0x00);
370                 io->set_iomap_single_rw(0x709, opm2);
371                 io->set_iomap_range_rw(0x70c, 0x70f, ctc2);
372         }
373 #ifdef _X1TURBO_FEATURE
374         io->set_iomap_single_rw(0xb00, memory);
375 #endif
376         io->set_iomap_range_rw(0xd00, 0xd03, emm);
377         io->set_iomap_range_r(0xe80, 0xe81, display);
378         io->set_iomap_range_w(0xe80, 0xe82, display);
379         io->set_iomap_range_rw(0xfd0, 0xfd3, sasi);
380         io->set_iomap_range_rw(0xff8, 0xffb, fdc);
381         io->set_iomap_single_w(0xffc, floppy);
382 #ifdef _X1TURBO_FEATURE
383         io->set_iomap_range_r(0xffc, 0xfff, floppy);
384 #endif
385         io->set_iomap_range_rw(0x1000, 0x17ff, display);
386         for(int i = 0x1800; i <= 0x18ff; i += 0x10) {
387                 io->set_iomap_range_rw(i, i + 1, crtc);
388         }
389         if(pseudo_sub_cpu) {
390                 io->set_iomap_range_rw(0x1900, 0x19ff, psub);
391         } else {
392                 io->set_iomap_range_rw(0x1900, 0x19ff, sub);
393         }
394         for(int i = 0x1a00; i <= 0x1aff; i += 4) {
395                 io->set_iomap_range_rw(i, i + 3, pio);
396         }
397         for(int i = 0x1b00; i <= 0x1bff; i++) {
398                 io->set_iomap_alias_rw(i, psg, 1);
399         }
400         for(int i = 0x1c00; i <= 0x1cff; i++) {
401                 io->set_iomap_alias_w(i, psg, 0);
402         }
403         io->set_iomap_range_r(0x1e00, 0x1eff, memory);
404         io->set_iomap_range_w(0x1d00, 0x1eff, memory);
405 #ifdef _X1TURBO_FEATURE
406         io->set_iomap_range_rw(0x1f80, 0x1f8f, dma);
407         io->set_iomap_range_rw(0x1f90, 0x1f93, sio);
408         io->set_iomap_range_rw(0x1fa0, 0x1fa3, ctc);
409 #ifdef _X1TURBOZ
410         io->set_iomap_single_rw(0x1fb0, display);
411         io->set_iomap_range_rw(0x1fb9, 0x1fc5, display);
412         io->set_iomap_single_rw(0x1fd0, display);
413         io->set_iomap_single_rw(0x1fe0, display);
414 #else
415         io->set_iomap_single_w(0x1fd0, display);
416         io->set_iomap_single_w(0x1fe0, display);
417 #endif
418         // 0x1ff0: dipswitch
419 //      io->set_iovalue_single_r(0x1ff0, 0x00);
420         update_dipswitch();
421 #else
422         io->set_iomap_range_rw(0x1f98, 0x1f9b, sio);    // CZ-8BM2
423         io->set_iomap_range_rw(0x1fa8, 0x1fab, ctc);
424 #endif
425         io->set_iomap_range_rw(0x2000, 0x3fff, display);        // tvram
426         
427 #ifdef _X1TWIN
428         // init PC Engine
429         pceevent = new EVENT(this, emu);
430         pceevent->set_frames_per_sec(PCE_FRAMES_PER_SEC);
431         pceevent->set_lines_per_frame(PCE_LINES_PER_FRAME);
432         pceevent->set_device_name(_T("EVENT (PC-ENGINE)"));
433         pcecpu = new HUC6280(this, emu);
434         pcecpu->set_device_name(_T("HuC6820 CPU (PC-ENGINE)"));
435         pcecpu->set_context_event_manager(pceevent);
436         pce = new PCE(this, emu);
437         pce->set_device_name(_T("SUB SYSTEM (PC-ENGINE)"));
438         pce->set_context_event_manager(pceevent);
439
440         pceevent->set_context_cpu(pcecpu, PCE_CPU_CLOCKS);
441         pceevent->set_context_sound(pce);
442         
443         pcecpu->set_context_mem(pce);
444         pcecpu->set_context_io(pce);
445 #ifdef USE_DEBUGGER
446         pcecpu->set_context_debugger(new DEBUGGER(this, emu));
447 #endif
448         pce->set_context_cpu(pcecpu);
449 #endif
450         
451         // initialize all devices
452 #if defined(__GIT_REPO_VERSION)
453         strncpy(_git_revision, __GIT_REPO_VERSION, sizeof(_git_revision) - 1);
454 #endif
455         for(DEVICE* device = first_device; device; device = device->next_device) {
456                 device->initialize();
457         }
458         if(!pseudo_sub_cpu) {
459                 // load rom images after cpustate is allocated
460                 cpu_sub->load_rom_image(create_local_path(SUB_ROM_FILE_NAME));
461                 cpu_kbd->load_rom_image(create_local_path(KBD_ROM_FILE_NAME));
462                 
463                 // patch to set the current year
464                 uint8_t *rom = cpu_sub->get_rom_ptr();
465                 sub->rom_crc32 = get_crc32(rom, 0x800); // 2KB
466                 if(rom[0x23] == 0xb9 && rom[0x24] == 0x35 && rom[0x25] == 0xb1) {
467                         //dll_cur_time_t cur_time;
468                         cur_time_t cur_time;
469                         get_host_time(&cur_time);
470                         rom[0x26] = TO_BCD(cur_time.year);
471                 }
472         }
473         for(int drv = 0; drv < MAX_DRIVE; drv++) {
474 //#ifdef _X1TURBO_FEATURE
475 //              if(config.drive_type == 2) {
476 //                      fdc->set_drive_type(drv, DRIVE_TYPE_2HD);
477 //              } else
478 ///#ndif
479                 fdc->set_drive_type(drv, DRIVE_TYPE_2D);
480 //              fdc->set_drive_rpm(drv, 300);
481 //              fdc->set_drive_mfm(drv, true);
482         }
483         for(int drv = 0; drv < USE_HARD_DISK; drv++) {
484                 if(!(config.last_hard_disk_path[drv][0] != _T('\0') && FILEIO::IsFileExisting(config.last_hard_disk_path[drv]))) {
485                         create_local_path(config.last_hard_disk_path[drv], _MAX_PATH, _T("SASI%d.DAT"), drv);
486                 }
487         }
488 }
489
490 VM::~VM()
491 {
492         // delete all devices
493         for(DEVICE* device = first_device; device;) {
494                 DEVICE *next_device = device->next_device;
495                 device->release();
496                 delete device;
497                 device = next_device;
498         }
499 }
500
501 DEVICE* VM::get_device(int id)
502 {
503         for(DEVICE* device = first_device; device; device = device->next_device) {
504                 if(device->this_device_id == id) {
505                         return device;
506                 }
507         }
508         return NULL;
509 }
510
511 // ----------------------------------------------------------------------------
512 // drive virtual machine
513 // ----------------------------------------------------------------------------
514
515 void VM::reset()
516 {
517         // reset all devices
518         for(DEVICE* device = first_device; device; device = device->next_device) {
519                 device->reset();
520         }
521         pio->write_signal(SIG_I8255_PORT_B, 0x00, 0x08);        // busy = low
522         psg->set_reg(0x2e, 0);  // set prescaler
523 }
524
525 void VM::special_reset()
526 {
527         // nmi reset
528         cpu->write_signal(SIG_CPU_NMI, 1, 1);
529 }
530
531 void VM::run()
532 {
533         event->drive();
534 #ifdef _X1TWIN
535         if(pce->is_cart_inserted()) {
536                 pceevent->drive();
537         }
538 #endif
539 }
540
541 double VM::get_frame_rate()
542 {
543 #ifdef _X1TWIN
544         if(pce->is_cart_inserted()) {
545                 return pceevent->get_frame_rate();
546         }
547 #endif
548         return event->get_frame_rate();
549 }
550
551 // ----------------------------------------------------------------------------
552 // debugger
553 // ----------------------------------------------------------------------------
554
555 #ifdef USE_DEBUGGER
556 DEVICE *VM::get_cpu(int index)
557 {
558         if(index == 0) {
559                 return cpu;
560         } else if(index == 1) {
561                 return cpu_sub;
562         } else if(index == 2) {
563                 return cpu_kbd;
564 #ifdef _X1TWIN
565         } else if(index == 3 && pce->is_cart_inserted()) {
566                 return pcecpu;
567 #endif
568         }
569         return NULL;
570 }
571 #endif
572
573 // ----------------------------------------------------------------------------
574 // draw screen
575 // ----------------------------------------------------------------------------
576
577 void VM::draw_screen()
578 {
579         display->draw_screen();
580 #ifdef _X1TWIN
581         if(pce->is_cart_inserted()) {
582                 pce->draw_screen();
583         }
584 #endif
585 }
586
587 // ----------------------------------------------------------------------------
588 // soud manager
589 // ----------------------------------------------------------------------------
590
591 void VM::initialize_sound(int rate, int samples)
592 {
593         // init sound manager
594         event->initialize_sound(rate, samples);
595 #ifdef _X1TWIN
596         pceevent->initialize_sound(rate, samples);
597 #endif
598         
599         // init sound gen
600         if(sound_type >= 1) {
601                 opm1->initialize_sound(rate, 4000000, samples, 0);
602         }
603         if(sound_type == 2) {
604                 opm2->initialize_sound(rate, 4000000, samples, 0);
605         }
606         psg->initialize_sound(rate, 2000000, samples, 0, 0);
607 #ifdef _X1TWIN
608         pce->initialize_sound(rate);
609 #endif
610 }
611
612 uint16_t* VM::create_sound(int* extra_frames)
613 {
614 #ifdef _X1TWIN
615         if(pce->is_cart_inserted()) {
616                 uint16_t* buffer = pceevent->create_sound(extra_frames);
617                 for(int i = 0; i < *extra_frames; i++) {
618                         event->drive();
619                 }
620                 return buffer;
621         }
622 #endif
623         return event->create_sound(extra_frames);
624 }
625
626 int VM::get_sound_buffer_ptr()
627 {
628 #ifdef _X1TWIN
629         if(pce->is_cart_inserted()) {
630                 return pceevent->get_sound_buffer_ptr();
631         }
632 #endif
633         return event->get_sound_buffer_ptr();
634 }
635
636 #ifdef USE_SOUND_VOLUME
637 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
638 {
639         if(ch == 0) {
640                 psg->set_volume(1, decibel_l, decibel_r);
641         } else if(ch == 1) {
642                 if(sound_type >= 1) {
643                         opm1->set_volume(0, decibel_l, decibel_r);
644                 }
645         } else if(ch == 2) {
646                 if(sound_type >= 2) {
647                         opm2->set_volume(0, decibel_l, decibel_r);
648                 }
649         } else if(ch == 3) {
650                 drec->set_volume(0, decibel_l, decibel_r);
651         } else if(ch == 4) {
652                 fdc->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
653                 fdc->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
654                 fdc->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
655         } else if(ch == 5) {
656                 drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
657                 drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
658                 drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
659 #if defined(_X1TWIN)
660         } else if(ch == 6) {
661                 pce->set_volume(0, decibel_l, decibel_r);
662 #endif
663         }
664 }
665 #endif
666
667 // ----------------------------------------------------------------------------
668 // notify key
669 // ----------------------------------------------------------------------------
670
671 void VM::key_down(int code, bool repeat)
672 {
673 #ifdef _X1TWIN
674         if(!repeat && !pce->is_cart_inserted()) {
675 #else
676         if(!repeat) {
677 #endif
678                 if(pseudo_sub_cpu) {
679                         psub->key_down(code, false);
680                 } else {
681                         kbd->key_down(code, false);
682                 }
683         }
684 }
685
686 void VM::key_up(int code)
687 {
688 #ifdef _X1TWIN
689         if(!pce->is_cart_inserted()) {
690 #endif
691                 if(pseudo_sub_cpu) {
692                         psub->key_up(code);
693                 } else {
694                         //kbd->key_up(code);
695                 }
696 #ifdef _X1TWIN
697         }
698 #endif
699 }
700
701 bool VM::get_caps_locked()
702 {
703 #ifdef _X1TWIN
704         if(!pce->is_cart_inserted()) {
705 #endif
706                 if(pseudo_sub_cpu) {
707                         return psub->get_caps_locked();
708                 } else {
709                         return kbd->get_caps_locked();
710                 }
711 #ifdef _X1TWIN
712         }
713         return false;
714 #endif
715 }
716
717 bool VM::get_kana_locked()
718 {
719 #ifdef _X1TWIN
720         if(!pce->is_cart_inserted()) {
721 #endif
722                 if(pseudo_sub_cpu) {
723                         return psub->get_kana_locked();
724                 } else {
725                         return kbd->get_kana_locked();
726                 }
727 #ifdef _X1TWIN
728         }
729         return false;
730 #endif
731 }
732
733 // ----------------------------------------------------------------------------
734 // user interface
735 // ----------------------------------------------------------------------------
736
737 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
738 {
739         fdc->open_disk(drv, file_path, bank);
740         
741 #ifdef _X1TURBO_FEATURE
742         if(fdc->get_media_type(drv) == MEDIA_TYPE_2DD) {
743                 if(fdc->get_drive_type(drv) == DRIVE_TYPE_2D) {
744                         fdc->set_drive_type(drv, DRIVE_TYPE_2DD);
745                 }
746         } else if(fdc->get_media_type(drv) == MEDIA_TYPE_2D) {
747                 if(fdc->get_drive_type(drv) == DRIVE_TYPE_2DD) {
748                         fdc->set_drive_type(drv, DRIVE_TYPE_2D);
749                 }
750         }
751 #endif
752 }
753
754 void VM::close_floppy_disk(int drv)
755 {
756         fdc->close_disk(drv);
757 }
758
759 bool VM::is_floppy_disk_inserted(int drv)
760 {
761         return fdc->is_disk_inserted(drv);
762 }
763
764 void VM::is_floppy_disk_protected(int drv, bool value)
765 {
766         fdc->is_disk_protected(drv, value);
767 }
768
769 bool VM::is_floppy_disk_protected(int drv)
770 {
771         return fdc->is_disk_protected(drv);
772 }
773
774 uint32_t VM::is_floppy_disk_accessed()
775 {
776         return fdc->read_signal(0);
777 }
778
779 void VM::open_hard_disk(int drv, const _TCHAR* file_path)
780 {
781         if(drv < USE_HARD_DISK) {
782                 sasi_hdd[drv >> 1]->open(drv & 1, file_path, 256);
783         }
784 }
785
786 void VM::close_hard_disk(int drv)
787 {
788         if(drv < USE_HARD_DISK) {
789                 sasi_hdd[drv >> 1]->close(drv & 1);
790         }
791 }
792
793 bool VM::is_hard_disk_inserted(int drv)
794 {
795         if(drv < USE_HARD_DISK) {
796                 return sasi_hdd[drv >> 1]->mounted(drv & 1);
797         }
798         return false;
799 }
800
801 uint32_t VM::is_hard_disk_accessed()
802 {
803         uint32_t status = 0;
804         
805         for(int drv = 0; drv < USE_HARD_DISK; drv++) {
806                 if(sasi_hdd[drv >> 1]->accessed(drv & 1)) {
807                         status |= 1 << drv;
808                 }
809         }
810         return status;
811 }
812
813 void VM::play_tape(int drv, const _TCHAR* file_path)
814 {
815         bool value = drec->play_tape(file_path);
816         if(pseudo_sub_cpu) {
817                 psub->close_tape();
818                 psub->play_tape(value);
819         } else {
820                 sub->close_tape();
821                 sub->play_tape(value);
822         }
823 }
824
825 void VM::rec_tape(int drv, const _TCHAR* file_path)
826 {
827         bool value = drec->rec_tape(file_path);
828         if(pseudo_sub_cpu) {
829                 psub->close_tape();
830                 psub->rec_tape(value);
831         } else {
832                 sub->close_tape();
833                 sub->rec_tape(value);
834         }
835 }
836
837 void VM::close_tape(int drv)
838 {
839         emu->lock_vm();
840         drec->close_tape();
841         emu->unlock_vm();
842         if(pseudo_sub_cpu) {
843                 psub->close_tape();
844         } else {
845                 sub->close_tape();
846         }
847 }
848
849 bool VM::is_tape_inserted(int drv)
850 {
851         return drec->is_tape_inserted();
852 }
853
854 bool VM::is_tape_playing(int drv)
855 {
856         return drec->is_tape_playing();
857 }
858
859 bool VM::is_tape_recording(int drv)
860 {
861         return drec->is_tape_recording();
862 }
863
864 int VM::get_tape_position(int drv)
865 {
866         return drec->get_tape_position();
867 }
868
869 const _TCHAR* VM::get_tape_message(int drv)
870 {
871         return drec->get_message();
872 }
873
874 void VM::push_play(int drv)
875 {
876         drec->set_ff_rew(0);
877         drec->set_remote(true);
878 }
879
880 void VM::push_stop(int drv)
881 {
882         drec->set_remote(false);
883 }
884
885 void VM::push_fast_forward(int drv)
886 {
887         drec->set_ff_rew(1);
888         drec->set_remote(true);
889 }
890
891 void VM::push_fast_rewind(int drv)
892 {
893         drec->set_ff_rew(-1);
894         drec->set_remote(true);
895 }
896
897 void VM::push_apss_forward(int drv)
898 {
899         drec->do_apss(1);
900 }
901
902 void VM::push_apss_rewind(int drv)
903 {
904         drec->do_apss(-1);
905 }
906
907 bool VM::is_frame_skippable()
908 {
909 #ifdef _X1TWIN
910         if(pce->is_cart_inserted()) {
911                 return pceevent->is_frame_skippable();
912         }
913 #endif
914         return event->is_frame_skippable();
915 }
916
917 #ifdef _X1TWIN
918 void VM::open_cart(int drv, const _TCHAR* file_path)
919 {
920         if(drv == 0) {
921                 pce->open_cart(file_path);
922                 pce->reset();
923                 pcecpu->reset();
924         }
925 }
926
927 void VM::close_cart(int drv)
928 {
929         if(drv == 0) {
930                 pce->close_cart();
931                 pce->reset();
932                 pcecpu->reset();
933         }
934 }
935
936 bool VM::is_cart_inserted(int drv)
937 {
938         if(drv == 0) {
939                 return pce->is_cart_inserted();
940         } else {
941                 return false;
942         }
943 }
944 #endif
945
946 void VM::update_config()
947 {
948         for(DEVICE* device = first_device; device; device = device->next_device) {
949                 device->update_config();
950         }
951 #ifdef _X1TURBO_FEATURE
952         update_dipswitch();
953 #endif
954 }
955
956 #ifdef _X1TURBO_FEATURE
957 void VM::update_dipswitch()
958 {
959         // bit0         0=High 1=Standard
960         // bit1-3       000=5"2D 001=5"2DD 010=5"2HD
961         io->set_iovalue_single_r(0x1ff0, (config.monitor_type & 1) | ((config.drive_type & 7) << 1));
962 }
963 #endif
964
965 #define STATE_VERSION   10
966
967 bool VM::process_state(FILEIO* state_fio, bool loading)
968 {
969         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
970                 return false;
971         }
972         for(DEVICE* device = first_device; device; device = device->next_device) {
973                 // Note: typeid(foo).name is fixed by recent ABI.Not decr. 6.
974                 // const char *name = typeid(*device).name();
975                 //       But, using get_device_name() instead of typeid(foo).name() 20181008 K.O
976                 const char *name = device->get_device_name();
977                 int len = strlen(name);
978                 if(!state_fio->StateCheckInt32(len)) {
979                         return false;
980                 }
981                 if(!state_fio->StateCheckBuffer(name, len, 1)) {
982                         return false;
983                 }
984                 if(!device->process_state(state_fio, loading)) {
985                         if(loading) {
986                                 printf("Data loading Error: DEVID=%d\n", device->this_device_id);
987                         }
988                         return false;
989                 }
990         }
991         state_fio->StateBool(pseudo_sub_cpu);
992         state_fio->StateInt32(sound_type);
993         
994 #ifdef _X1TURBO_FEATURE
995         // post process
996         if(loading) {
997                 update_dipswitch();
998         }
999 #endif
1000         return true;
1001 }