OSDN Git Service

[VM][FMTOWNS][DMAC] Revert recent commit, will apply changes of upstream 20221204...
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmtowns / fmtowns.cpp
1 /*
2         FUJITSU FM-Towns Emulator 'eFMTowns'
3
4         Author : Kyuma Ohta <whatisthis.sowhat _at_ gmail.com>
5         Date   : 2016.12.28 -
6
7         [ virtual machine ]
8         History:
9                 2016-12-28 Copy from eFMR-50.
10 */
11
12 #include "fmtowns.h"
13 #include "../../emu.h"
14 #include "../device.h"
15 #include "../event.h"
16
17 //#include "../hd46505.h"
18 #include "../i8251.h"
19 #include "../i8253.h"
20 #include "../i8259.h"
21
22 #include "../i386_np21.h"
23 //#include "../i386.h"
24
25 #include "../io.h"
26 #include "../mb8877.h"
27 #include "../msm58321.h"
28 #include "../noise.h"
29 #include "../pcm1bit.h"
30 #include "../harddisk.h"
31 #include "../scsi_hdd.h"
32 #include "./towns_scsi_host.h"
33 #include "../upd71071.h"
34
35 #include "./cdrom.h"
36 #include "./crtc.h"
37 #include "./dictionary.h"
38 #include "./dmac.h"
39 #include "./towns_memory.h"
40 #include "./sprite.h"
41 #include "./sysrom.h"
42 #include "./vram.h"
43
44 // Electric Volume
45 #include "mb87078.h"
46 //YM-2612 "OPN2"
47 //#include "../ym2612.h"
48 //RF5C68 PCM
49 #include "rf5c68.h"
50 //AD7820 ADC
51 #include "ad7820kr.h"
52 #include "ym2612.h"
53 // 80387?
54
55 #ifdef USE_DEBUGGER
56 #include "../debugger.h"
57 #endif
58
59 #include "./adpcm.h"
60 //#include "./cdc.h"
61 #include "./floppy.h"
62 #include "./fontroms.h"
63 #include "./joystick.h"
64 #include "./joypad_2btn.h"
65 #include "./joypad_6btn.h"
66 #include "./keyboard.h"
67 #include "./mouse.h"
68 #include "./msdosrom.h"
69 #include "./scsi.h"
70 #include "./serialrom.h"
71 #include "./timer.h"
72 #include "./iccard.h"
73
74 #include "./planevram.h"
75
76 // ----------------------------------------------------------------------------
77 // initialize
78 // ----------------------------------------------------------------------------
79 using FMTOWNS::ADPCM;
80 //using FMTOWNS::CDC;
81 using FMTOWNS::DICTIONARY;
82 using FMTOWNS::FLOPPY;
83 using FMTOWNS::FONT_ROMS;
84 using FMTOWNS::JOYSTICK;
85 using FMTOWNS::JOYPAD_2BTN;
86 using FMTOWNS::JOYPAD_6BTN;
87
88 using FMTOWNS::KEYBOARD;
89 using FMTOWNS::MOUSE;
90 using FMTOWNS::MSDOSROM;
91 using FMTOWNS::SCSI;
92 using FMTOWNS::SERIAL_ROM;
93 using FMTOWNS::SYSROM;
94 using FMTOWNS::TIMER;
95 using FMTOWNS::TOWNS_ICCARD;
96
97 using FMTOWNS::TOWNS_CDROM;
98 using FMTOWNS::TOWNS_CRTC;
99 using FMTOWNS::TOWNS_DMAC;
100 using FMTOWNS::TOWNS_MEMORY;
101 using FMTOWNS::TOWNS_SCSI_HOST;
102 using FMTOWNS::TOWNS_SPRITE;
103 using FMTOWNS::TOWNS_VRAM;
104 using FMTOWNS::PLANEVRAM;
105
106
107 VM::VM(EMU_TEMPLATE* parent_emu) : VM_TEMPLATE(parent_emu)
108 {
109 /*
110         Machine ID & CPU ID
111
112         FMR-50FD/HD/LT  0xF8
113         FMR-50FX/HX     0xE0
114         FMR-50SFX/SHX   0xE8
115         FMR-50LT        0xF8
116         FMR-50NBX       0x28
117         FMR-50NB        0x60
118         FMR-50NE/T      0x08
119         FMR-CARD        0x70
120
121         80286           0x00
122         80386           0x01
123         80386SX         0x03
124         80486           0x02
125 */
126
127         // create devices
128         //first_device = last_device = nullptr;
129         dummy = new DEVICE(this, emu);  // must be 1st device
130         event = new EVENT(this, emu);   // must be 2nd device
131 #if defined(_USE_QT)
132         dummy->set_device_name(_T("1st Dummy"));
133         event->set_device_name(_T("EVENT"));
134 #endif
135
136         cpu = new I386(this, emu);
137 #if defined(_USE_QT)
138   #if defined(HAS_I386)
139         cpu->set_device_name(_T("CPU(i386)"));
140   #elif defined(HAS_I486)
141         cpu->set_device_name(_T("CPU(i486)"));
142   #elif defined(HAS_PENTIUM)
143         cpu->set_device_name(_T("CPU(Pentium)"));
144   #endif
145 #endif
146
147         io = new IO(this, emu);
148         io->space = _IO_SPACE;
149         memory->bus_width = _IO_BUS_WIDTH;
150
151         crtc = new TOWNS_CRTC(this, emu);
152         cdrom = new TOWNS_CDROM(this, emu);
153
154         memory = new TOWNS_MEMORY(this, emu);
155         memory->space = _MEMORY_SPACE;
156         memory->bank_size = _MEMORY_BANK_SIZE;
157         memory->bus_width = _MEMORY_BUS_WIDTH;
158
159         vram = new TOWNS_VRAM(this, emu);
160         sprite = new TOWNS_SPRITE(this, emu);
161         sysrom = new SYSROM(this, emu);
162         msdosrom = new MSDOSROM(this, emu);
163         fontrom = new FONT_ROMS(this, emu);
164         dictionary = new DICTIONARY(this, emu);
165 #if defined(HAS_20PIX_FONTS)
166         fontrom_20pix = new FONT_ROM_20PIX(this, emu);
167 #endif
168         serialrom = new SERIAL_ROM(this, emu);
169
170         adpcm = new ADPCM(this, emu);
171 //      mixer = new MIXER(this, emu); // Pseudo mixer.
172
173         planevram = new PLANEVRAM(this, emu);
174
175         adc = new AD7820KR(this, emu);
176         rf5c68 = new RF5C68(this, emu);
177         e_volumes[0] = new MB87078(this, emu);
178         e_volumes[1] = new MB87078(this, emu);
179
180         sio = new I8251(this, emu);
181         pit0 = new I8253(this, emu);
182         pit1 = new I8253(this, emu);
183         pic = new I8259(this, emu);
184         fdc = new MB8877(this, emu);
185         rtc = new MSM58321(this, emu);
186         beep = new PCM1BIT(this, emu);
187         opn2 = new YM2612(this, emu);
188
189         seek_sound = new NOISE(this, emu);
190         head_up_sound = new NOISE(this, emu);
191         head_down_sound = new NOISE(this, emu);
192
193 //      scsi_host = new TOWNS_SCSI_HOST(this, emu);
194         scsi_host = new SCSI_HOST(this, emu);
195
196         for(int i = 0; i < 7; i++) {
197                 scsi_hdd[i] = nullptr;
198         }
199 #if defined(USE_HARD_DISK)
200         for(int i = 0; i < USE_HARD_DISK; i++) {
201                 scsi_hdd[i] = new SCSI_HDD(this, emu);
202                 scsi_hdd[i]->set_device_name(_T("SCSI Hard Disk Drive #%d"), i + 1);
203                 scsi_hdd[i]->scsi_id = i ;
204                 scsi_hdd[i]->set_disk_handler(0, new HARDDISK(emu));
205                 scsi_hdd[i]->set_context_interface(scsi_host);
206                 my_sprintf_s(scsi_hdd[i]->vendor_id, 9, "FUJITSU");
207                 my_sprintf_s(scsi_hdd[i]->product_id, 17, "SCSI-HDD");
208                 scsi_host->set_context_target(scsi_hdd[i]);
209         }
210 #endif
211         dma = new TOWNS_DMAC(this, emu);
212         extra_dma = new TOWNS_DMAC(this, emu);
213
214         floppy = new FLOPPY(this, emu);
215         keyboard = new KEYBOARD(this, emu);
216         joystick = new JOYSTICK(this, emu);
217         scsi = new SCSI(this, emu);
218         timer = new TIMER(this, emu);
219
220         iccard1 = new TOWNS_ICCARD(this, emu);
221 #if 0
222         iccard2 = new TOWNS_ICCARD(this, emu);
223 #else
224         iccard2 = nullptr;
225 #endif
226         for(int i = 0; i < 2; i++) {
227                 joypad_2btn[i] = new JOYPAD_2BTN(this, emu);
228                 joypad_6btn[i] = new JOYPAD_6BTN(this, emu);
229                 mouse[i] = new MOUSE(this, emu);
230         }
231
232         uint16_t machine_id = 0x0100; // FM-Towns1
233         uint16_t cpu_id = 0x0001;     // i386DX
234         uint32_t cpu_clock = 16000 * 1000; // 16MHz
235 #if defined(_FMTOWNS1_2ND_GEN)
236         machine_id = 0x0200;   // 1F/2F/1H/2H
237 #elif defined(_FMTOWNS_UX_VARIANTS)
238         machine_id = 0x0300;   // UX10/20/40
239         cpu_id = 0x0003;       // i386SX
240 #elif defined(_FMTOWNS1_3RD_GEN)
241         machine_id = 0x0400;  // 10F/20F.40H/80H
242 #elif defined(_FMTOWNS2_CX_VARIANTS)
243         machine_id = 0x0500;  // CX10/20/30/40
244 #elif defined(_FMTOWNS_UG_VARIANTS)
245         machine_id = 0x0600;  // UG10/20/40/80
246         cpu_id = 0x0003;      // i386SX
247         cpu_clock = 20000 * 1000; // 20MHz
248 #elif defined(_FMTOWNS_HR_VARIANTS)
249         machine_id = 0x0700;
250         cpu_id = 0x0002;      // i486SX
251         cpu_clock = 20000 * 1000; // 20MHz
252 #elif defined(_FMTOWNS_HG_VARIANTS)
253         machine_id = 0x0800;
254         cpu_clock = 20000 * 1000; // 20MHz
255 #elif defined(_FMTOWNS_SG_VARIANTS)
256         machine_id = 0x0800; // OK?
257 #elif defined(_FMTOWNS_SR_VARIANTS)
258         machine_id = 0x0700; // OK?
259         cpu_id = 0x0002;      // i486SX
260         cpu_clock = 20000 * 1000; // 20MHz
261 #elif defined(_FMTOWNS_UR_VARIANTS)
262         machine_id = 0x0900;  // UR10/20/40/80
263         cpu_id = 0x0002;      // i486DX
264         cpu_clock = 20000 * 1000; // ToDo: Correct frequency.
265 #elif defined(_FMTOWNS_MA_VARIANTS)
266         machine_id = 0x0b00; // OK?
267         cpu_id = 0x0002;      // i486SX
268         cpu_clock = 33000 * 1000; // 33MHz
269 #elif defined(_FMTOWNS_ME_VARIANTS)
270         machine_id = 0x0d00; // OK?
271         cpu_id = 0x0002;      // i486SX
272         cpu_clock = 25000 * 1000; // 25MHz
273 #elif defined(_FMTOWNS_MF_VARIANTS)
274         machine_id = 0x0f00; // OK?
275         cpu_id = 0x0002;      // i486SX
276         cpu_clock = 33000 * 1000; // 33MHz
277 #elif defined(_FMTOWNS_MX_VARIANTS)
278         machine_id = 0x0c00; // OK?
279         cpu_id = 0x0002;      // i486DX (With FPU?)
280         cpu_clock = 66000 * 1000; // 66MHz
281 #elif defined(_FMTOWNS_HC_VARIANTS)
282         // 20210227 K.O
283         // From FMTowns::MachineID()  of TSUGARU,
284         // git 83d4ec2309ac9fcbb8c01f26061ff0d49c5321e4.
285         machine_id = 0x1100; // OK?
286         cpu_id = 0x0002;      // Pentium (With FPU?)
287         cpu_clock = 50000 * 1000; // ToDo: Correctness frequency.
288 #else
289         // ToDo: Pentium Model (After HB).
290
291 #endif
292
293         event->set_frames_per_sec(FRAMES_PER_SEC);
294         event->set_lines_per_frame(LINES_PER_FRAME);
295
296         set_machine_type(machine_id, cpu_id);
297         // set contexts
298         event->set_context_cpu(cpu, cpu_clock);
299
300         adc_in_ch = -1;
301         line_in_ch = -1;
302         modem_in_ch = -1;
303         mic_in_ch = -1;
304
305         // Use pseudo mixer instead of event.Due to using ADC.
306         // Temporally not use mixer.
307         event->set_context_sound(beep);
308         event->set_context_sound(opn2);
309         event->set_context_sound(rf5c68);
310         event->set_context_sound(cdrom);
311
312         fdc->set_context_noise_seek(seek_sound);
313         fdc->set_context_noise_head_down(head_down_sound);
314         fdc->set_context_noise_head_up(head_up_sound);
315         event->set_context_sound(seek_sound);
316         event->set_context_sound(head_down_sound);
317         event->set_context_sound(head_up_sound);
318
319 #ifdef USE_DEBUGGER
320         pit0->set_context_debugger(new DEBUGGER(this, emu));
321         pit1->set_context_debugger(new DEBUGGER(this, emu));
322 #endif
323         pit0->set_context_ch0(timer, SIG_TIMER_CH0, 1);
324         pit0->set_context_ch1(timer, SIG_TIMER_CH1, 1);
325         pit0->set_context_ch2(beep,  SIG_PCM1BIT_SIGNAL, 1);
326         pit0->set_constant_clock(0, 307200);
327         pit0->set_constant_clock(1, 307200);
328         pit0->set_constant_clock(2, 307200);
329         pit1->set_constant_clock(0, 1229900);
330         pit1->set_constant_clock(1, 1229900);
331         pit1->set_constant_clock(2, 1229900);
332 //      pic->set_context_cpu(cpu);
333         pic->set_context_cpu(memory);
334         fdc->set_context_irq(floppy, SIG_FLOPPY_IRQ, 1);
335         rtc->set_context_data(timer, SIG_TIMER_RTC, 0x0f, 0);
336         rtc->set_context_busy(timer, SIG_TIMER_RTC_BUSY, 0x80);
337         scsi_host->set_context_irq(scsi, SIG_SCSI_IRQ, 1);
338         scsi_host->set_context_drq(scsi, SIG_SCSI_DRQ, 1);
339         scsi_host->set_context_drq(keyboard, SIG_KEYBOARD_BOOTSEQ_END, 1);
340
341         dma->set_context_memory(memory);
342         dma->set_context_ch0(fdc);
343         dma->set_context_ch1(scsi_host);
344         //dma->set_context_ch2(printer);
345         dma->set_context_ch3(cdrom);
346         dma->set_context_tc1(scsi, SIG_SCSI_EOT, 0xffffffff);
347         dma->set_context_tc3(cdrom, SIG_TOWNS_CDROM_DMAINT, 0xffffffff);
348         dma->set_context_ack3(cdrom, SIG_TOWNS_CDROM_DMAACK, 0xffffffff);
349
350         dma->set_context_ube1(scsi_host, SIG_SCSI_16BIT_BUS, 0x02);
351
352         dma->set_context_child_dma(extra_dma);
353
354         floppy->set_context_fdc(fdc);
355
356         sprite->set_context_vram(vram);
357         sprite->set_context_font(fontrom);
358         sprite->set_context_crtc(crtc);
359 #ifdef USE_DEBUGGER
360         sprite->set_context_debugger(new DEBUGGER(this, emu));
361 #endif
362
363         planevram->set_context_vram(vram);
364         planevram->set_context_sprite(sprite);
365         planevram->set_context_crtc(crtc);
366
367         crtc->set_context_sprite(sprite);
368         crtc->set_context_vram(vram);
369         crtc->set_context_font(fontrom);
370
371 //      e_volumes[0]->set_context_device(0, line_in, 0,
372 //                                                                       MB87078_TYPE_MASK_LEFT);
373 //      e_volumes[0]->set_context_device(1, line_in, 0,
374 //                                                                       MB87078_TYPE_MASK_RIGHT);
375         e_volumes[1]->set_context_device(0, cdrom, 0,
376                                                                          MB87078_TYPE_SET_LEFT, SIG_TOWNS_CDROM_MUTE_L,
377                                                                          0xffffffff,
378                                                                          0xffffffff,
379                                                                          false
380                 );
381         e_volumes[1]->set_context_device(1, cdrom, 0,
382                                                                          MB87078_TYPE_SET_RIGHT, SIG_TOWNS_CDROM_MUTE_R,
383                                                                          0xffffffff,
384                                                                          0xffffffff,
385                                                                          false
386                 );
387
388         memory->set_context_cpu(cpu);
389         memory->set_context_dmac(dma);
390         memory->set_context_vram(vram);
391         memory->set_context_planevram(planevram);
392         memory->set_context_crtc(crtc);
393         memory->set_context_system_rom(sysrom);
394         memory->set_context_msdos(msdosrom);
395         memory->set_context_dictionary(dictionary);
396         memory->set_context_font_rom(fontrom);
397         memory->set_context_timer(timer);
398         memory->set_context_serial_rom(serialrom);
399         memory->set_context_sprite(sprite);
400         memory->set_context_pcm(rf5c68);
401         memory->set_context_iccard(iccard1, 0);
402         memory->set_context_iccard(iccard2, 1);
403
404         adpcm->set_context_opn2(opn2);
405         adpcm->set_context_rf5c68(rf5c68);
406         adpcm->set_context_adc(adc);
407
408         rf5c68->set_context_interrupt_boundary(adpcm, SIG_ADPCM_WRITE_INTERRUPT, 0xffffffff);
409 #ifdef USE_DEBUGGER
410         rf5c68->set_context_debugger(new DEBUGGER(this, emu));
411 #endif
412         opn2->set_context_irq(adpcm, SIG_ADPCM_OPX_INTR, 0xffffffff);
413
414         adc->set_sample_rate(19200);
415         adc->set_sound_bank(-1);
416         adc->set_context_interrupt(adpcm, SIG_ADPCM_ADC_INTR, 0xffffffff);
417
418         scsi->set_context_dma(dma);
419         scsi->set_context_host(scsi_host);
420         scsi->set_context_pic(pic);
421         timer->set_context_pcm(beep);
422         timer->set_context_rtc(rtc);
423         //timer->set_context_halt_line(cpu, SIG_CPU_HALTREQ, 0xffffffff);
424         timer->set_context_halt_line(cpu, SIG_CPU_BUSREQ, 0xffffffff);
425
426         for(int i = 0; i < 2; i++) {
427                 // type =
428                 // 0: Towns PAD 2buttons
429                 // 1: Towns PAD 6buttons
430                 // 2: Towns MOUSE
431                 // 3: Analog Pad (reserved)
432                 // 4: Libble Rabble stick (reserved)
433                 joystick->set_context_joystick(i, joypad_2btn[i]);
434                 joystick->set_context_joystick(i, joypad_6btn[i]);
435                 joystick->set_context_joystick(i, mouse[i]);
436         }
437 #ifdef USE_DEBUGGER
438         joystick->set_context_debugger(new DEBUGGER(this, emu));
439 #endif
440         // ToDo: Selective by config.
441         for(int i = 0; i < 2; i++) {
442                 joypad_2btn[i]->set_context_pad_num(i);
443                 joypad_2btn[i]->set_context_parent_port(i, joystick, 0, 0xff);
444                 joypad_2btn[i]->set_negative_logic(true);
445                 joypad_2btn[i]->set_enable(true);
446         }
447         for(int i = 0; i < 2; i++) {
448                 joypad_6btn[i]->set_context_pad_num(i);
449                 joypad_6btn[i]->set_context_parent_port(i, joystick, 0, 0xff);
450                 joypad_6btn[i]->set_negative_logic(true);
451                 joypad_6btn[i]->set_enable(false);
452         }
453         for(int i = 0; i < 2; i++) {
454                 mouse[i]->set_context_pad_num(i);
455                 mouse[i]->set_context_parent_port(i, joystick, 0, 0xff);
456                 mouse[i]->set_negative_logic(true);
457                 mouse[i]->set_enable(false);
458         }
459         joystick->set_using_pad(0, -1);
460         joystick->set_using_pad(1, -1);
461
462         // cpu bus
463         cpu->set_context_mem(memory);
464         cpu->set_context_io(io);
465         cpu->set_context_intr(pic);
466         cpu->set_context_dma(dma);
467         cpu->set_context_bios(nullptr);
468         cpu->set_context_extreset(memory, SIG_FMTOWNS_NOTIFY_RESET, 0xffffffff);
469 #ifdef USE_DEBUGGER
470         cpu->set_context_debugger(new DEBUGGER(this, emu));
471 #endif
472         // Interrupts
473         // IRQ0  : TIMER
474         // IRQ1  : KEYBOARD
475         // IRQ2  : USART (ToDo)
476         // IRQ3  : EXTRA USART (ToDo)
477         // IRQ4  : EXTRA I/O (Maybe not implement)
478         // IRQ5  : EXTRA I/O (Maybe not implement)
479         // IRQ6  : FDC
480         // IRQ7  : Deisy chain (to IRQ8 - 15)
481         timer->set_context_intr_line(pic, SIG_I8259_CHIP0 | SIG_I8259_IR0, 0xffffffff);
482         keyboard->set_context_intr_line(pic, SIG_I8259_CHIP0 | SIG_I8259_IR1, 0xffffffff);
483         floppy->set_context_intr_line(pic, SIG_I8259_CHIP0 | SIG_I8259_IR6, 0xffffffff);
484
485         // IRQ8  : SCSI (-> scsi.cpp)
486         // IRQ9  : CDC/CDROM
487         // IRQ10 : EXTRA I/O (Maybe not implement)
488         // IRQ11 : VSYNC
489         // IRQ12 : PRINTER (ToDo)
490         // IRQ13 : ADPCM AND OPN2 (Route to adpcm.cpp)
491         // IRQ14 : EXTRA I/O (Maybe not implement)
492         // IRQ15 : RESERVED.
493         cdrom->set_context_mpuint_line(pic, SIG_I8259_CHIP1 | SIG_I8259_IR1, 0xffffffff);
494         crtc->set_context_vsync(pic, SIG_I8259_CHIP1 | SIG_I8259_IR3, 0xffffffff);
495         adpcm->set_context_intr_line(pic, SIG_I8259_CHIP1 | SIG_I8259_IR5, 0xffffffff);
496
497         // DMA0  : FDC/DRQ
498         // DMA1  : SCSI (-> scsi.cpp)
499         // DMA2  : PRINTER (ToDo)
500         // DMA3  : CDC/CDROM
501         // EXTRA DMA0 : EXTRA SLOT (Maybe not implement)
502         // EXTRA DMA1 : Reserved
503         // EXTRA DMA2 : Reserved
504         // EXTRA DMA3 : Reserved
505         fdc->set_context_drq(dma, SIG_UPD71071_CH0, 1);
506         fdc->set_context_drq(keyboard, SIG_KEYBOARD_BOOTSEQ_END, 1);
507         cdrom->set_context_drq_line(dma, SIG_UPD71071_CH3, 0xff);
508         cdrom->set_context_drq_line(keyboard, SIG_KEYBOARD_BOOTSEQ_END, 1);
509
510         // NMI0 : KEYBOARD (RAS)
511         // NMI1 : Extra SLOT (Maybe not implement)
512         keyboard->set_context_nmi_line(memory, SIG_CPU_NMI, 0xffffffff);
513
514         cdrom->set_context_dmac(dma);
515         // For Debugging, will remove 20200822 K.O
516         cdrom->set_context_cpu(cpu);
517
518         // i/o bus
519         io->set_iowait_range_rw(0x0000, 0xffff, 6); // ToDo: May variable wait.
520
521         io->set_iomap_alias_rw (0x0000, pic, I8259_ADDR_CHIP0 | 0);
522         io->set_iomap_alias_rw (0x0002, pic, I8259_ADDR_CHIP0 | 1);
523         io->set_iomap_alias_rw (0x0010, pic, I8259_ADDR_CHIP1 | 0);
524         io->set_iomap_alias_rw (0x0012, pic, I8259_ADDR_CHIP1 | 1);
525
526         io->set_iomap_range_rw (0x0020, 0x0025, memory);
527         io->set_iomap_range_rw (0x0026, 0x0027, timer);  // Freerun counter
528         io->set_iomap_single_rw(0x0028, memory);
529
530         io->set_iomap_range_r  (0x0030, 0x0031, memory);        // cpu id / machine id
531         io->set_iomap_single_rw(0x0032, memory);        // serial rom (routed from memory)
532         io->set_iomap_single_r (0x0034, scsi);  // ENABLE/ UNABLE to WORD DMA for SCSI
533
534         io->set_iomap_alias_rw(0x0040, pit0, 0);
535         io->set_iomap_alias_rw(0x0042, pit0, 1);
536         io->set_iomap_alias_rw(0x0044, pit0, 2);
537         io->set_iomap_alias_rw(0x0046, pit0, 3);
538         io->set_iomap_alias_rw(0x0050, pit1, 0);
539         io->set_iomap_alias_rw(0x0052, pit1, 1);
540         io->set_iomap_alias_rw(0x0054, pit1, 2);
541         io->set_iomap_alias_rw(0x0056, pit1, 3);
542
543         io->set_iomap_single_rw(0x0060, timer); // Beep and interrupts register
544         io->set_iomap_single_rw(0x0068, timer); // Interval timer register2 (after Towns 10F).
545         io->set_iomap_single_rw(0x006a, timer); // Interval timer register2 (after Towns 10F).
546         io->set_iomap_single_rw(0x006b, timer); // Interval timer register2 (after Towns 10F).
547         io->set_iomap_single_rw(0x006c, timer); // 1uS wait register (after Towns 10F).
548
549         io->set_iomap_single_rw(0x0070, timer); // RTC DATA
550         io->set_iomap_single_w (0x0080, timer); // RTC COMMAND
551
552         io->set_iomap_range_rw (0x00a0, 0x00af, dma);
553         io->set_iomap_range_rw (0x00b0, 0x00bf, extra_dma);
554
555         io->set_iomap_single_rw(0x00c0, memory);   // CACHE CONTROLLER
556         io->set_iomap_single_rw(0x00c2, memory);   // CACHE CONTROLLER
557
558         io->set_iomap_alias_rw (0x0200, fdc, 0);  // STATUS/COMMAND
559         io->set_iomap_alias_rw (0x0202, fdc, 1);  // TRACK
560         io->set_iomap_alias_rw (0x0204, fdc, 2);  // SECTOR
561         io->set_iomap_alias_rw (0x0206, fdc, 3);  // DATA
562         io->set_iomap_single_rw(0x0208, floppy);  // DRIVE STATUS / DRIVE CONTROL
563         io->set_iomap_single_rw(0x020c, floppy);  // DRIVE SELECT
564         io->set_iomap_single_r (0x020d, floppy);  // FDDVEXT (after HG/HR).
565         io->set_iomap_single_rw(0x020e, floppy);  // Towns drive SW
566
567         io->set_iomap_range_rw (0x0400, 0x0404, memory); // System Status
568 //      io->set_iomap_range_rw (0x0406, 0x043f, memory); // Reserved
569
570         io->set_iomap_range_rw(0x0440, 0x0443, crtc); // CRTC
571         io->set_iomap_range_rw(0x0448, 0x044f, crtc); // VIDEO OUT (CRTC)
572
573         io->set_iomap_range_rw(0x0450, 0x0452, sprite); // SPRITE
574
575         io->set_iomap_single_rw(0x0458, vram);         // VRAM ACCESS CONTROLLER (ADDRESS)
576         io->set_iomap_range_rw (0x045a, 0x045b, vram); // VRAM ACCESS CONTROLLER (DATA)
577
578         io->set_iomap_single_rw(0x0480, memory); //  MEMORY REGISTER
579         io->set_iomap_single_rw(0x0484, dictionary); // Dictionary
580
581         io->set_iomap_alias_r(0x48a, iccard1, 0); //
582         //io->set_iomap_alias_rw(0x490, memory_card); // After Towns2
583         //io->set_iomap_alias_rw(0x491, memory_card); // After Towns2
584
585         io->set_iomap_range_rw(0x04c0, 0x04c6, cdrom); // CDROM
586         io->set_iomap_range_r (0x04cc, 0x04cd, cdrom); // CDROM
587         // PAD, Sound
588
589         io->set_iomap_single_r(0x04d0, joystick); // Pad1
590         io->set_iomap_single_r(0x04d2, joystick); // Pad 2
591         io->set_iomap_single_w(0x04d6, joystick); // Pad out
592
593         io->set_iomap_single_rw(0x04d5, adpcm); // mute
594         // OPN2(YM2612)
595         io->set_iomap_alias_rw(0x04d8, opn2, 0); // STATUS(R)/Addrreg 0(W)
596         io->set_iomap_alias_w (0x04da, opn2, 1);  // Datareg 0(W)
597         io->set_iomap_alias_w (0x04dc, opn2, 2);  // Addrreg 1(W)
598         io->set_iomap_alias_w (0x04de, opn2, 3);  // Datareg 1(W)
599         // Electrical volume
600         io->set_iomap_alias_rw(0x04e0, e_volumes[0], 0);
601         io->set_iomap_alias_rw(0x04e1, e_volumes[0], 1);
602         io->set_iomap_alias_rw(0x04e2, e_volumes[1], 0);
603         io->set_iomap_alias_rw(0x04e3, e_volumes[1], 1);
604
605         // ADPCM
606         io->set_iomap_range_rw(0x04e7, 0x04ec, adpcm); // A/D SAMPLING DATA REG
607         io->set_iomap_range_rw(0x04f0, 0x04f8, rf5c68); // A/D SAMPLING DATA REG
608
609         io->set_iomap_single_rw(0x05c0, memory); // NMI MASK
610         io->set_iomap_single_r (0x05c2, memory);  // NMI STATUS
611         io->set_iomap_single_r (0x05c8, sprite); // TVRAM EMULATION
612         io->set_iomap_single_w (0x05ca, crtc); // VSYNC INTERRUPT
613
614         io->set_iomap_single_rw(0x05e0, memory); // Hidden MEMORY WAIT REGISTER from AB.COM (Towns 1/2)
615         io->set_iomap_single_rw(0x05e2, memory); // Hidden MEMORY WAIT REGISTER from AB.COM (After Towns 1H/1F/2H/2F )
616         io->set_iomap_single_rw(0x05e6, memory); // Hidden VRAM WAIT REGISTER from TSUGARU (Maybe after Towns 10H/10F/20H/20F )
617         io->set_iomap_single_r (0x05e8, memory); // RAM capacity register.(later Towns1H/2H/1F/2F).
618         io->set_iomap_single_rw(0x05ec, memory); // RAM Wait register , ofcially after Towns2, but exists after Towns1H.
619         io->set_iomap_single_r (0x05ed, memory); // Maximum clock register (After HR/HG).
620         io->set_iomap_single_rw(0x05ee, vram);   // VRAM CACHE CONTROLLER
621
622         io->set_iomap_single_rw(0x0600, keyboard);
623         io->set_iomap_single_rw(0x0602, keyboard);
624         io->set_iomap_single_rw(0x0604, keyboard);
625
626         //io->set_iomap_single_rw(0x0800, printer);
627         //io->set_iomap_single_rw(0x0802, printer);
628         //io->set_iomap_single_rw(0x0804, printer);
629
630         io->set_iomap_alias_rw (0x0a00, sio, 0);
631         io->set_iomap_alias_rw (0x0a02, sio, 1);
632 //      io->set_iomap_single_r (0x0a04, serial);
633 //      io->set_iomap_single_r (0x0a06, serial);
634 //      io->set_iomap_single_w (0x0a08, serial);
635 //      io->set_iomap_single_rw(0x0a0a, modem);
636
637         io->set_iomap_single_rw(0x0c30, scsi);
638         io->set_iomap_single_rw(0x0c32, scsi);
639         io->set_iomap_single_r (0x0c34, scsi);
640
641         io->set_iomap_range_rw (0x3000, 0x3fff, dictionary); // CMOS
642
643         io->set_iomap_range_rw (0xfd90, 0xfda0, crtc);  // Palette and CRTC
644         io->set_iomap_single_r (0xfda2, crtc);  // CRTC
645         io->set_iomap_single_rw(0xfda4, memory);        // memory
646
647         io->set_iomap_range_rw (0xff80, 0xff83, planevram);     // MMIO
648         io->set_iomap_single_r (0xff84, planevram);     // MMIO
649         io->set_iomap_single_rw(0xff86, planevram);     // MMIO
650         io->set_iomap_single_rw(0xff88, memory);        // MMIO
651         io->set_iomap_range_rw (0xff94, 0xff99, memory);        // MMIO
652         io->set_iomap_range_r  (0xff9c, 0xff9d, memory);        // MMIO
653         io->set_iomap_single_rw(0xff9e, memory);        // MMIO
654         io->set_iomap_single_rw(0xffa0, planevram);     // MMIO
655
656 //      io->set_iomap_range_w (0xff94, 0xff95, fontrom);
657 //      io->set_iomap_range_r (0xff96, 0xff97, fontrom);
658
659         // Vram allocation may be before initialize().
660         // initialize all devices
661 #if defined(__GIT_REPO_VERSION)
662         set_git_repo_version(__GIT_REPO_VERSION);
663 #endif
664         // ToDo : Use config framework
665         int exram_size = config.current_ram_size;
666         if(exram_size < 1) {
667                 if(machine_id < 0x0200) { // Model1 - 2H
668                         exram_size = 6;
669                 } else if(machine_id == 0x0500) { // CX
670                         exram_size = 15;
671                 } else if(machine_id < 0x0700) {  // 10F,20H
672                         exram_size = 8;
673                 } else if(machine_id == 0x0800) { // HG
674                         exram_size = 15;
675                 } else {
676                         exram_size = 31;
677                 }
678         }
679         if(exram_size < MIN_RAM_SIZE) {
680                 exram_size = MIN_RAM_SIZE;
681         }
682
683         memory->set_extra_ram_size(exram_size);
684
685 #if defined(WITH_I386SX)
686         cpu->device_model = INTEL_80386;
687 #elif defined(WITH_I486SX)
688         cpu->device_model = INTEL_I486SX;
689 #elif defined(WITH_I486DX)
690         cpu->device_model = INTEL_I486DX;
691 #elif defined(WITH_PENTIUM)
692         cpu->device_model = INTEL_PENTIUM;
693 #else
694         // I386
695         cpu->device_model = INTEL_80386;
696 #endif
697
698         initialize_devices();
699 //      cpu->set_address_mask(0xffffffff);
700 }
701
702 VM::~VM()
703 {
704         // delete all devices
705         release_devices();
706 }
707
708 void VM::set_machine_type(uint16_t machine_id, uint16_t cpu_id)
709 {
710         if(memory != nullptr) {
711                 memory->set_cpu_id(cpu_id);
712                 memory->set_machine_id(machine_id);
713         }
714         if(crtc != nullptr) {
715                 crtc->set_cpu_id(cpu_id);
716                 crtc->set_machine_id(machine_id);
717         }
718         if(timer != nullptr) {
719                 timer->set_cpu_id(cpu_id);
720                 timer->set_machine_id(machine_id);
721         }
722         if(cdrom != nullptr) {
723                 cdrom->set_cpu_id(cpu_id);
724                 cdrom->set_machine_id(machine_id);
725         }
726         if(scsi != nullptr) {
727                 scsi->set_cpu_id(cpu_id);
728                 scsi->set_machine_id(machine_id);
729         }
730         if(serialrom != nullptr) {
731                 serialrom->set_cpu_id(cpu_id);
732                 serialrom->set_machine_id(machine_id);
733         }
734         if(floppy != nullptr) {
735                 floppy->set_cpu_id(cpu_id);
736                 floppy->set_machine_id(machine_id);
737         }
738 #if defined(HAS_20PIX_FONTS)
739         if(fontrom_20pix != nullptr) {
740                 fontrom_20pix->set_cpu_id(cpu_id);
741                 fontrom_20pix->set_machine_id(machine_id);
742         }
743 #endif
744         if(vram != nullptr) {
745                 vram->set_cpu_id(cpu_id);
746                 vram->set_machine_id(machine_id);
747         }
748
749 }
750
751
752 // ----------------------------------------------------------------------------
753 // drive virtual machine
754 // ----------------------------------------------------------------------------
755
756 void VM::reset()
757 {
758         // reset all devices
759         boot_seq = false;
760         VM_TEMPLATE::reset();
761 //      cpu->set_address_mask(0xffffffff);
762 }
763
764 void VM::special_reset(int num)
765 {
766         boot_seq = true;
767
768         // reset all devices
769         VM_TEMPLATE::reset();
770         //      cpu->set_address_mask(0xffffffff);
771         __LIKELY_IF(keyboard != nullptr) {
772                 keyboard->special_reset(num);
773         }
774 }
775
776 void VM::run()
777 {
778         __LIKELY_IF(event != nullptr) {
779                 event->drive();
780         }
781 }
782 void VM::process_boot_sequence(uint32_t val)
783 {
784         if(boot_seq) {
785                 if(val != 0) {
786                         if(keyboard != nullptr) {
787                                 keyboard->write_signal(SIG_KEYBOARD_BOOTSEQ_END, 0xffffffff, 0xffffffff);
788                         }
789                         boot_seq = false;
790                 }
791         }
792 }
793
794 // ----------------------------------------------------------------------------
795 // debugger
796 // ----------------------------------------------------------------------------
797
798 #ifdef USE_DEBUGGER
799 DEVICE *VM::get_cpu(int index)
800 {
801         if(index == 0) {
802                 return cpu;
803         }
804         return nullptr;
805 }
806 #endif
807
808 // ----------------------------------------------------------------------------
809 // draw screen
810 // ----------------------------------------------------------------------------
811
812 void VM::draw_screen()
813 {
814         __LIKELY_IF(crtc != nullptr) {
815                 crtc->draw_screen();
816         }
817 }
818
819
820 // ----------------------------------------------------------------------------
821 // soud manager
822 // ----------------------------------------------------------------------------
823
824 void VM::initialize_sound(int rate, int samples)
825 {
826 //      emu->lock_vm();
827         // init sound manager
828         event->initialize_sound(rate, samples);
829
830         // init sound gen
831         beep->initialize_sound(rate, 8000);
832
833         // init OPN2
834         // MASTER CLOCK MAYBE 600KHz * 12 = 7200KHz .
835         // From FM-Towns Technical Databook (Rev.2), Page 201
836         opn2->initialize_sound(rate, (int)(600.0e3 * 12.0) , samples, 0.0, 0.0);
837         //opn2->initialize_sound(rate, (int)(8000.0e3) , samples, 0.0, 0.0);
838         //opn2->initialize_sound(rate, (int)(600.0e3 * 6.0) , samples, 0.0, 0.0);
839
840         // init PCM
841         rf5c68->initialize_sound(rate, samples);
842
843         // add_sound_in_source() must add after per initialize_sound().
844         adc_in_ch = event->add_sound_in_source(rate, samples, 2);
845         adc->set_sample_rate(19200);
846         adc->set_sound_bank(adc_in_ch);
847 #if 0
848         mixer->set_context_out_line(adc_in_ch);
849         mixer->set_context_sample_out(adc_in_ch, rate, samples); // Must be 2ch.
850         // ToDo: Check recording sample rate & channels.
851         mic_in_ch = event->add_sound_in_source(rate, samples, 2);
852         mixer->set_context_mic_in(mic_in_ch, rate, samples);
853
854         line_in_ch = event->add_sound_in_source(rate, samples, 2);
855         mixer->set_context_line_in(line_in_ch, rate, samples);
856 #endif
857 //      emu->unlock_vm();
858 }
859
860 uint16_t* VM::create_sound(int* extra_frames)
861 {
862         __LIKELY_IF(event != nullptr) {
863                 return event->create_sound(extra_frames);
864         }
865         return VM_TEMPLATE::create_sound(extra_frames);
866 }
867
868 int VM::get_sound_buffer_ptr()
869 {
870         __LIKELY_IF(event != nullptr) {
871                 return event->get_sound_buffer_ptr();
872         }
873         return VM_TEMPLATE::get_sound_buffer_ptr();
874 }
875
876 void VM::clear_sound_in()
877 {
878         __UNLIKELY_IF(event == nullptr) return;
879
880         event->clear_sound_in_source(adc_in_ch);
881         event->clear_sound_in_source(mic_in_ch);
882         event->clear_sound_in_source(line_in_ch);
883         return;
884 }
885
886 int VM::get_sound_in_data(int ch, int32_t* dst, int expect_samples, int expect_rate, int expect_channels)
887 {
888         if(dst == nullptr) return 0;
889         if(expect_samples <= 0) return 0;
890         int n_ch = -1;
891         switch(ch) {
892         case 0x00:
893                 n_ch = line_in_ch;
894                 break;
895         case 0x01:
896                 n_ch = mic_in_ch;
897                 break;
898         case 0x100:
899                 n_ch = adc_in_ch;
900                 break;
901         }
902         if(n_ch < 0) return 0;
903         int samples = 0;
904         if(event != nullptr) {
905                 samples = event->get_sound_in_data(n_ch, dst, expect_samples, expect_rate, expect_channels);
906         }
907         return samples;
908 }
909
910 // Write to event's buffer
911 int VM::sound_in(int ch, int32_t* src, int samples)
912 {
913         if(ch < 0) return 0;
914         if(ch >= 2) return 0;
915         int n_ch = -1;
916         switch(ch) {
917         case 0x100:  // ADC in from MIXER, not connected.
918                 break;
919         case 0x00: // LINE
920                 n_ch = line_in_ch;
921                 break;
922         case 0x01: // MIC
923                 n_ch = mic_in_ch;
924                 break;
925         }
926         if(n_ch < 0) return 0;
927
928         int ss = 0;
929         if(event != nullptr) {
930                 emu->lock_vm();
931                 ss =  event->write_sound_in_buffer(n_ch, src, samples);
932                 emu->unlock_vm();
933         }
934         return ss;
935 }
936
937 #if defined(USE_HARD_DISK)
938 void VM::open_hard_disk(int drv, const _TCHAR* file_path)
939 {
940         if((drv < USE_HARD_DISK) && (drv < 8) && (drv >= 0)) {
941                 if(scsi_hdd[drv] != nullptr) {
942                         scsi_hdd[drv]->open(0, file_path, 512);
943                 }
944         }
945 }
946
947 void VM::close_hard_disk(int drv)
948 {
949         if((drv < USE_HARD_DISK) && (drv < 8) && (drv >= 0)) {
950                 if(scsi_hdd[drv] != nullptr) {
951                         scsi_hdd[drv]->close(0);
952                 }
953         }
954 }
955
956 bool VM::is_hard_disk_inserted(int drv)
957 {
958         if((drv < USE_HARD_DISK) && (drv < 8) && (drv >= 0)) {
959                 if(scsi_hdd[drv] != nullptr) {
960                         return scsi_hdd[drv]->mounted(0);
961                 }
962         }
963         return false;
964 }
965
966 uint32_t VM::is_hard_disk_accessed()
967 {
968         uint32_t status = 0;
969
970         for(int drv = 0; drv < USE_HARD_DISK; drv++) {
971                 if(scsi_hdd[drv] != nullptr) {
972                         if(scsi_hdd[drv]->accessed(0)) {
973                                 status |= 1 << drv;
974                         }
975                 }
976         }
977         process_boot_sequence(1);
978         return status;
979 }
980 #endif // USE_HARD_DISK
981
982 void VM::open_compact_disc(int drv, const _TCHAR* file_path)
983 {
984         if(cdrom != nullptr) {
985                 cdrom->open(file_path);
986         }
987 }
988
989 void VM::close_compact_disc(int drv)
990 {
991         if(cdrom != nullptr) {
992                 cdrom->close();
993         }
994 }
995
996 bool VM::is_compact_disc_inserted(int drv)
997 {
998         if(cdrom == nullptr) return false;
999         return cdrom->mounted();
1000 }
1001
1002 uint32_t VM::is_compact_disc_accessed()
1003 {
1004         uint32_t status = cdrom->accessed();
1005         process_boot_sequence(1);
1006         return status;
1007 }
1008
1009 #ifdef USE_SOUND_VOLUME
1010 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
1011 {
1012 #ifndef HAS_LINEIN_SOUND
1013 //      if(ch >= 7) ch++;
1014 #endif
1015 #ifndef HAS_MIC_SOUND
1016 //      if(ch >= 8) ch++;
1017 #endif
1018 #ifndef HAS_MODEM_SOUND
1019 //      if(ch >= 9) ch++;
1020 #endif
1021 #ifndef HAS_2ND_ADPCM
1022 //      if(ch >= 10) ch++;
1023 #endif
1024         if(ch == 0) { // BEEP
1025                 if(beep != nullptr) {
1026                         beep->set_volume(0, decibel_l, decibel_r);
1027                 }
1028         }
1029         else if(ch == 1) { // CD-ROM
1030                 if(e_volumes[1] != nullptr) {
1031                         e_volumes[1]->set_volumes(0, decibel_l, 1, decibel_r);
1032                 } else if(cdrom != nullptr) {
1033                         cdrom->set_volume(0, decibel_l, decibel_r);
1034                 }
1035         }
1036         else if(ch == 2) { // OPN2
1037                 if(opn2 != nullptr) {
1038                         opn2->set_volume(0, decibel_l, decibel_r);
1039                 }
1040         }
1041         else if(ch == 3) { // ADPCM
1042                 if(rf5c68 != nullptr) {
1043                         rf5c68->set_volume(0, decibel_l, decibel_r);
1044                 }
1045         }
1046         else if(ch == 4) { // SEEK, HEAD UP / DOWN
1047                 if(seek_sound != nullptr) {
1048                         seek_sound->set_volume(0, decibel_l, decibel_r);
1049                 }
1050                 if(head_up_sound != nullptr) {
1051                         head_up_sound->set_volume(0, decibel_l, decibel_r);
1052                 }
1053                 if(head_down_sound != nullptr) {
1054                         head_down_sound->set_volume(0, decibel_l, decibel_r);
1055                 }
1056         }
1057 }
1058 #endif
1059
1060 // ----------------------------------------------------------------------------
1061 // notify key
1062 // ----------------------------------------------------------------------------
1063
1064 void VM::key_down(int code, bool repeat)
1065 {
1066         __LIKELY_IF(keyboard != nullptr) {
1067                 keyboard->key_down(code);
1068         }
1069 }
1070
1071 void VM::key_up(int code)
1072 {
1073         __LIKELY_IF(keyboard != nullptr) {
1074                 keyboard->key_up(code);
1075         }
1076 }
1077
1078 // ----------------------------------------------------------------------------
1079 // user interface
1080 // ----------------------------------------------------------------------------
1081 void VM::open_cart(int drv, const _TCHAR* file_path)
1082 {
1083         switch(drv) {
1084         case 0:
1085                 if(iccard1 != nullptr) {
1086                         iccard1->open_cart(file_path);
1087                 }
1088                 break;
1089         case 1:
1090                 if(iccard2 != nullptr) {
1091                         iccard2->open_cart(file_path);
1092                 }
1093                 break;
1094         }
1095 }
1096
1097 void VM::close_cart(int drv)
1098 {
1099         switch(drv) {
1100         case 0:
1101                 if(iccard1 != nullptr) {
1102                         iccard1->close_cart();
1103                 }
1104                 break;
1105         case 1:
1106                 if(iccard2 != nullptr) {
1107                         iccard2->close_cart();
1108                 }
1109                 break;
1110         }
1111 }
1112
1113 bool VM::is_cart_inserted(int drv)
1114 {
1115         switch(drv) {
1116         case 0:
1117                 if(iccard1 != nullptr) {
1118                         return iccard1->is_cart_inserted();
1119                 }
1120                 break;
1121         case 1:
1122                 if(iccard2 != nullptr) {
1123                         return iccard2->is_cart_inserted();
1124                 }
1125                 break;
1126         }
1127         return false;
1128 }
1129
1130 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
1131 {
1132
1133         if(fdc != nullptr) {
1134                 fdc->open_disk(drv, file_path, bank);
1135                 floppy->change_disk(drv);
1136         }
1137 }
1138
1139 void VM::close_floppy_disk(int drv)
1140 {
1141         if(fdc != nullptr) {
1142                 fdc->close_disk(drv);
1143         //      floppy->change_disk(drv);
1144         }
1145 }
1146 uint32_t VM::is_floppy_disk_accessed()
1147 {
1148         uint32_t val = fdc->read_signal(0);
1149         process_boot_sequence(val);
1150         return val;
1151 }
1152
1153 bool VM::is_floppy_disk_inserted(int drv)
1154 {
1155         if(fdc != nullptr) {
1156                 return fdc->is_disk_inserted(drv);
1157         }
1158         return VM_TEMPLATE::is_floppy_disk_inserted(drv);
1159 }
1160
1161 void VM::is_floppy_disk_protected(int drv, bool value)
1162 {
1163         __LIKELY_IF(fdc != nullptr) {
1164                 fdc->is_disk_protected(drv, value);
1165         }
1166 }
1167
1168 bool VM::is_floppy_disk_protected(int drv)
1169 {
1170         __LIKELY_IF(fdc != nullptr) {
1171                 return fdc->is_disk_protected(drv);
1172         }
1173         return VM_TEMPLATE::is_floppy_disk_protected(drv);
1174 }
1175
1176 bool VM::is_frame_skippable()
1177 {
1178         __LIKELY_IF(event != nullptr) {
1179                 return event->is_frame_skippable();
1180         }
1181         return VM_TEMPLATE::is_frame_skippable();
1182 }
1183
1184
1185 double VM::get_current_usec()
1186 {
1187         __LIKELY_IF(event != nullptr) {
1188                 return event->get_current_usec();
1189         }
1190         return VM_TEMPLATE::get_current_usec();
1191 }
1192
1193 uint64_t VM::get_current_clock_uint64()
1194 {
1195         __LIKELY_IF(event != nullptr) {
1196                 return event->get_current_clock_uint64();
1197         }
1198         return VM_TEMPLATE::get_current_clock_uint64();
1199 }
1200
1201 #define STATE_VERSION   4
1202
1203 bool VM::process_state(FILEIO* state_fio, bool loading)
1204 {
1205         if(!(VM_TEMPLATE::process_state_core(state_fio, loading, STATE_VERSION))) {
1206                 return false;
1207         }
1208
1209         // Machine specified.
1210         state_fio->StateValue(boot_seq);
1211
1212         if(loading) {
1213                 update_config();
1214         }
1215         return true;
1216 }