OSDN Git Service

[VM][WIP] Use namespace to devices per VMs.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmr50 / fmr50.cpp
index 7d28897..e151689 100644 (file)
-/*\r
-       FUJITSU FMR-50 Emulator 'eFMR-50'\r
-       FUJITSU FMR-60 Emulator 'eFMR-60'\r
-\r
-       Author : Takeda.Toshiya\r
-       Date   : 2008.04.28 -\r
-\r
-       [ virtual machine ]\r
-*/\r
-\r
-#include "fmr50.h"\r
-#include "../../emu.h"\r
-#include "../device.h"\r
-#include "../event.h"\r
-\r
-#include "../hd46505.h"\r
-#ifdef _FMR60\r
-#include "../hd63484.h"\r
-#endif\r
-#include "../i8251.h"\r
-#include "../i8253.h"\r
-#include "../i8259.h"\r
-#if defined(HAS_I286)\r
-#include "../i286.h"\r
-#else\r
-#include "../i386.h"\r
-#endif\r
-#include "../io.h"\r
-#include "../mb8877.h"\r
-#include "../msm58321.h"\r
-#include "../pcm1bit.h"\r
-#include "../upd71071.h"\r
-\r
-#ifdef USE_DEBUGGER\r
-#include "../debugger.h"\r
-#endif\r
-\r
-#include "bios.h"\r
-#include "cmos.h"\r
-#include "floppy.h"\r
-#include "keyboard.h"\r
-#include "memory.h"\r
-#include "scsi.h"\r
-//#include "serial.h"\r
-#include "timer.h"\r
-\r
-#include "../../fileio.h"\r
-\r
-// ----------------------------------------------------------------------------\r
-// initialize\r
-// ----------------------------------------------------------------------------\r
-\r
-VM::VM(EMU* parent_emu) : emu(parent_emu)\r
-{\r
-/*\r
-       Machine ID & CPU ID\r
-\r
-       FMR-50FD/HD/LT  0xF8\r
-       FMR-50FX/HX     0xE0\r
-       FMR-50SFX/SHX   0xE8\r
-       FMR-50LT        0xF8\r
-       FMR-50NBX       0x28\r
-       FMR-50NB        0x60\r
-       FMR-50NE/T      0x08\r
-       FMR-CARD        0x70\r
-\r
-       80286           0x00\r
-       80386           0x01\r
-       80386SX         0x03\r
-       80486           0x02\r
-*/\r
-       static const int cpu_clock[] = {\r
-#if defined(HAS_I286)\r
-                8000000, 12000000\r
-#elif defined(HAS_I386)\r
-               16000000, 20000000\r
-#elif defined(HAS_I486)\r
-               20000000, 25000000\r
-#endif\r
-       };\r
-       \r
-#if defined(_FMR60) && (defined(HAS_I386) || defined(HAS_I486) || defined(HAS_PENTIUM))\r
-       uint8 machine_id = 0xf0;        // FMR-70/80\r
-#else\r
-       uint8 machine_id = 0xf8;        // FMR-50/60\r
-#endif\r
-       \r
-       FILEIO* fio = new FILEIO();\r
-       if(fio->Fopen(emu->bios_path(_T("MACHINE.ID")), FILEIO_READ_BINARY)) {\r
-               machine_id = fio->Fgetc();\r
-               fio->Fclose();\r
-       }\r
-       delete fio;\r
-       \r
-       machine_id &= ~7;\r
-#if defined(HAS_I286)\r
-       machine_id |= 0;        // 286\r
-#elif defined(HAS_I386)\r
-//     machine_id |= 1;        // 386DX\r
-       machine_id |= 3;        // 386SX\r
-#elif defined(HAS_I486)\r
-       machine_id |= 2;        // 486SX/DX\r
-#endif\r
-       \r
-       // create devices\r
-       first_device = last_device = NULL;\r
-       dummy = new DEVICE(this, emu);  // must be 1st device\r
-       event = new EVENT(this, emu);   // must be 2nd device\r
-       \r
-#if defined(HAS_I286)\r
-       cpu = new I286(this, emu);\r
-#else\r
-       cpu = new I386(this, emu);\r
-#endif\r
-       crtc = new HD46505(this, emu);\r
-#ifdef _FMR60\r
-       acrtc = new HD63484(this, emu);\r
-#endif\r
-       sio = new I8251(this, emu);\r
-       pit0 = new I8253(this, emu);\r
-       pit1 = new I8253(this, emu);\r
-       pic = new I8259(this, emu);\r
-       io = new IO(this, emu);\r
-       fdc = new MB8877(this, emu);\r
-       rtc = new MSM58321(this, emu);\r
-       pcm = new PCM1BIT(this, emu);\r
-       dma = new UPD71071(this, emu);\r
-       \r
-       bios = new BIOS(this, emu);\r
-       cmos = new CMOS(this, emu);\r
-       floppy = new FLOPPY(this, emu);\r
-       keyboard = new KEYBOARD(this, emu);\r
-       memory = new MEMORY(this, emu);\r
-       scsi = new SCSI(this, emu);\r
-//     serial = new SERIAL(this, emu);\r
-       timer = new TIMER(this, emu);\r
-       \r
-       // set contexts\r
-       event->set_context_cpu(cpu, cpu_clock[config.cpu_type & 1]);\r
-       event->set_context_sound(pcm);\r
-       \r
-/*     pic     0       timer\r
-               1       keyboard\r
-               2       rs-232c\r
-               3       ex rs-232c\r
-               4       (option)\r
-               5       (option)\r
-               6       floppy drive or dma ???\r
-               7       (slave)\r
-               8       scsi\r
-               9       (option)\r
-               10      (option)\r
-               11      (option)\r
-               12      printer\r
-               13      (option)\r
-               14      (option)\r
-               15      (reserve)\r
-\r
-       dma     0       floppy drive\r
-               1       hard drive\r
-               2       (option)\r
-               3       (reserve)\r
-*/\r
-       crtc->set_context_disp(memory, SIG_MEMORY_DISP, 1);\r
-       crtc->set_context_vsync(memory, SIG_MEMORY_VSYNC, 1);\r
-#ifdef _FMR60\r
-       acrtc->set_vram_ptr((uint16*)memory->get_vram(), 0x80000);\r
-#endif\r
-       pit0->set_context_ch0(timer, SIG_TIMER_CH0, 1);\r
-       pit0->set_context_ch1(timer, SIG_TIMER_CH1, 1);\r
-       pit0->set_context_ch2(pcm, SIG_PCM1BIT_SIGNAL, 1);\r
-       pit0->set_constant_clock(0, 307200);\r
-       pit0->set_constant_clock(1, 307200);\r
-       pit0->set_constant_clock(2, 307200);\r
-       pit1->set_constant_clock(1, 1228800);\r
-       pic->set_context_cpu(cpu);\r
-       fdc->set_context_drq(dma, SIG_UPD71071_CH0, 1);\r
-       fdc->set_context_irq(floppy, SIG_FLOPPY_IRQ, 1);\r
-       rtc->set_context_data(timer, SIG_TIMER_RTC, 0x0f, 0);\r
-       rtc->set_context_busy(timer, SIG_TIMER_RTC, 0x80);\r
-       dma->set_context_memory(memory);\r
-       dma->set_context_ch0(fdc);\r
-//     dma->set_context_ch1(scsi);\r
-       \r
-       bios->set_context_mem(memory);\r
-       bios->set_context_io(io);\r
-       bios->set_cmos_ptr(cmos->get_cmos());\r
-       bios->set_vram_ptr(memory->get_vram());\r
-       bios->set_cvram_ptr(memory->get_cvram());\r
-#ifdef _FMR60\r
-       bios->set_avram_ptr(memory->get_avram());\r
-#else\r
-       bios->set_kvram_ptr(memory->get_kvram());\r
-#endif\r
-       floppy->set_context_fdc(fdc);\r
-       floppy->set_context_pic(pic);\r
-       keyboard->set_context_pic(pic);\r
-       memory->set_context_cpu(cpu);\r
-       memory->set_machine_id(machine_id);\r
-       memory->set_context_crtc(crtc);\r
-       memory->set_chregs_ptr(crtc->get_regs());\r
-//     scsi->set_context_dma(dma);\r
-//     scsi->set_context_pic(pic);\r
-       timer->set_context_pcm(pcm);\r
-       timer->set_context_pic(pic);\r
-       timer->set_context_rtc(rtc);\r
-       \r
-       // cpu bus\r
-       cpu->set_context_mem(memory);\r
-       cpu->set_context_io(io);\r
-       cpu->set_context_intr(pic);\r
-       cpu->set_context_bios(bios);\r
-#ifdef SINGLE_MODE_DMA\r
-       cpu->set_context_dma(dma);\r
-#endif\r
-#ifdef USE_DEBUGGER\r
-       cpu->set_context_debugger(new DEBUGGER(this, emu));\r
-#endif\r
-       \r
-       // i/o bus\r
-       io->set_iomap_alias_rw(0x00, pic, I8259_ADDR_CHIP0 | 0);\r
-       io->set_iomap_alias_rw(0x02, pic, I8259_ADDR_CHIP0 | 1);\r
-       io->set_iomap_alias_rw(0x10, pic, I8259_ADDR_CHIP1 | 0);\r
-       io->set_iomap_alias_rw(0x12, pic, I8259_ADDR_CHIP1 | 1);\r
-       io->set_iomap_single_rw(0x20, memory);  // reset\r
-       io->set_iomap_single_r(0x21, memory);   // cpu misc\r
-       io->set_iomap_single_w(0x22, memory);   // dma\r
-       io->set_iomap_single_rw(0x24, memory);  // dma\r
-       io->set_iomap_single_r(0x26, timer);\r
-       io->set_iomap_single_r(0x27, timer);\r
-       io->set_iomap_single_r(0x30, memory);   // cpu id\r
-       io->set_iomap_alias_rw(0x40, pit0, 0);\r
-       io->set_iomap_alias_rw(0x42, pit0, 1);\r
-       io->set_iomap_alias_rw(0x44, pit0, 2);\r
-       io->set_iomap_alias_rw(0x46, pit0, 3);\r
-       io->set_iomap_alias_rw(0x50, pit1, 0);\r
-       io->set_iomap_alias_rw(0x52, pit1, 1);\r
-       io->set_iomap_alias_rw(0x54, pit1, 2);\r
-       io->set_iomap_alias_rw(0x56, pit1, 3);\r
-       io->set_iomap_single_rw(0x60, timer);\r
-       io->set_iomap_single_rw(0x70, timer);\r
-       io->set_iomap_single_w(0x80, timer);\r
-#ifdef _FMRCARD\r
-       io->set_iomap_single_w(0x90, cmos);\r
-#endif\r
-       io->set_iomap_range_rw(0xa0, 0xaf, dma);\r
-       io->set_iomap_alias_rw(0x200, fdc, 0);\r
-       io->set_iomap_alias_rw(0x202, fdc, 1);\r
-       io->set_iomap_alias_rw(0x204, fdc, 2);\r
-       io->set_iomap_alias_rw(0x206, fdc, 3);\r
-       io->set_iomap_single_rw(0x208, floppy);\r
-       io->set_iomap_single_rw(0x20c, floppy);\r
-       io->set_iomap_single_rw(0x400, memory); // crtc\r
-       io->set_iomap_single_rw(0x402, memory); // crtc\r
-       io->set_iomap_single_rw(0x404, memory); // crtc\r
-       io->set_iomap_single_w(0x408, memory);  // crtc\r
-       io->set_iomap_single_rw(0x40a, memory); // crtc\r
-       io->set_iomap_single_rw(0x40c, memory); // crtc\r
-       io->set_iomap_single_rw(0x40e, memory); // crtc\r
-       io->set_iomap_alias_rw(0x500, crtc, 0);\r
-       io->set_iomap_alias_rw(0x502, crtc, 1);\r
-#ifdef _FMR60\r
-       io->set_iomap_range_rw(0x520, 0x523, acrtc);\r
-#endif\r
-       io->set_iomap_single_rw(0x600, keyboard);\r
-       io->set_iomap_single_rw(0x602, keyboard);\r
-       io->set_iomap_single_rw(0x604, keyboard);\r
-       io->set_iomap_alias_rw(0xa00, sio, 0);\r
-       io->set_iomap_alias_rw(0xa02, sio, 1);\r
-//     io->set_iomap_single_r(0xa04, serial);\r
-//     io->set_iomap_single_r(0xa06, serial);\r
-//     io->set_iomap_single_w(0xa08, serial);\r
-       io->set_iomap_single_rw(0xc30, scsi);\r
-       io->set_iomap_single_rw(0xc32, scsi);\r
-       io->set_iomap_range_rw(0x3000, 0x3fff, cmos);\r
-       io->set_iomap_range_rw(0xfd98, 0xfd9f, memory); // crtc\r
-       io->set_iomap_single_rw(0xfda0, memory);        // crtc\r
-       \r
-       // initialize all devices\r
-       for(DEVICE* device = first_device; device; device = device->next_device) {\r
-               device->initialize();\r
-       }\r
-       for(int i = 0; i < MAX_DRIVE; i++) {\r
-               bios->set_disk_handler(i, fdc->get_disk_handler(i));\r
-       }\r
-}\r
-\r
-VM::~VM()\r
-{\r
-       // delete all devices\r
-       for(DEVICE* device = first_device; device;) {\r
-               DEVICE *next_device = device->next_device;\r
-               device->release();\r
-               delete device;\r
-               device = next_device;\r
-       }\r
-}\r
-\r
-DEVICE* VM::get_device(int id)\r
-{\r
-       for(DEVICE* device = first_device; device; device = device->next_device) {\r
-               if(device->this_device_id == id) {\r
-                       return device;\r
-               }\r
-       }\r
-       return NULL;\r
-}\r
-\r
-// ----------------------------------------------------------------------------\r
-// drive virtual machine\r
-// ----------------------------------------------------------------------------\r
-\r
-void VM::reset()\r
-{\r
-       // reset all devices\r
-       for(DEVICE* device = first_device; device; device = device->next_device) {\r
-               device->reset();\r
-       }\r
-       // temporary fix...\r
-       for(DEVICE* device = first_device; device; device = device->next_device) {\r
-               device->reset();\r
-       }\r
-}\r
-\r
-void VM::run()\r
-{\r
-       event->drive();\r
-}\r
-\r
-// ----------------------------------------------------------------------------\r
-// debugger\r
-// ----------------------------------------------------------------------------\r
-\r
-#ifdef USE_DEBUGGER\r
-DEVICE *VM::get_cpu(int index)\r
-{\r
-       if(index == 0) {\r
-               return cpu;\r
-       }\r
-       return NULL;\r
-}\r
-#endif\r
-\r
-// ----------------------------------------------------------------------------\r
-// draw screen\r
-// ----------------------------------------------------------------------------\r
-\r
-void VM::draw_screen()\r
-{\r
-       memory->draw_screen();\r
-}\r
-\r
-int VM::access_lamp()\r
-{\r
-       uint32 status = fdc->read_signal(0) | bios->read_signal(0);\r
-       return (status & 0x10) ? 4 : (status & (1 | 4)) ? 1 : (status & (2 | 8)) ? 2 : 0;\r
-}\r
-\r
-// ----------------------------------------------------------------------------\r
-// soud manager\r
-// ----------------------------------------------------------------------------\r
-\r
-void VM::initialize_sound(int rate, int samples)\r
-{\r
-       // init sound manager\r
-       event->initialize_sound(rate, samples);\r
-       \r
-       // init sound gen\r
-       pcm->init(rate, 8000);\r
-}\r
-\r
-uint16* VM::create_sound(int* extra_frames)\r
-{\r
-       return event->create_sound(extra_frames);\r
-}\r
-\r
-int VM::sound_buffer_ptr()\r
-{\r
-       return event->sound_buffer_ptr();\r
-}\r
-\r
-// ----------------------------------------------------------------------------\r
-// notify key\r
-// ----------------------------------------------------------------------------\r
-\r
-void VM::key_down(int code, bool repeat)\r
-{\r
-       keyboard->key_down(code);\r
-}\r
-\r
-void VM::key_up(int code)\r
-{\r
-       keyboard->key_up(code);\r
-}\r
-\r
-// ----------------------------------------------------------------------------\r
-// user interface\r
-// ----------------------------------------------------------------------------\r
-\r
-void VM::open_disk(int drv, _TCHAR* file_path, int offset)\r
-{\r
-       fdc->open_disk(drv, file_path, offset);\r
-       floppy->change_disk(drv);\r
-}\r
-\r
-void VM::close_disk(int drv)\r
-{\r
-       fdc->close_disk(drv);\r
-}\r
-\r
-bool VM::disk_inserted(int drv)\r
-{\r
-       return fdc->disk_inserted(drv);\r
-}\r
-\r
-bool VM::now_skip()\r
-{\r
-       return event->now_skip();\r
-}\r
-\r
-void VM::update_config()\r
-{\r
-       for(DEVICE* device = first_device; device; device = device->next_device) {\r
-               device->update_config();\r
-       }\r
-}\r
-\r
+/*
+       FUJITSU FMR-50 Emulator 'eFMR-50'
+       FUJITSU FMR-60 Emulator 'eFMR-60'
+
+       Author : Takeda.Toshiya
+       Date   : 2008.04.28 -
+
+       [ virtual machine ]
+*/
+
+#include "fmr50.h"
+#include "../../emu.h"
+#include "../device.h"
+#include "../event.h"
+
+#include "../harddisk.h"
+#include "../hd46505.h"
+#ifdef _FMR60
+#include "../hd63484.h"
+#endif
+#include "../i8251.h"
+#include "../i8253.h"
+#include "../i8259.h"
+#if defined(HAS_I286)
+#include "../i286.h"
+#else
+#include "../i386.h"
+#endif
+#include "../io.h"
+#include "../mb8877.h"
+#include "../msm58321.h"
+#include "../noise.h"
+#include "../pcm1bit.h"
+#include "../scsi_hdd.h"
+#include "../scsi_host.h"
+#include "../upd71071.h"
+
+#ifdef USE_DEBUGGER
+#include "../debugger.h"
+#endif
+
+#include "bios.h"
+#include "cmos.h"
+#include "floppy.h"
+#include "keyboard.h"
+#include "./memory.h"
+#include "scsi.h"
+//#include "serial.h"
+#include "timer.h"
+
+// ----------------------------------------------------------------------------
+// initialize
+// ----------------------------------------------------------------------------
+
+using FMR50::BIOS;
+using FMR50::CMOS;
+using FMR50::FLOPPY;
+using FMR50::KEYBOARD;
+using FMR50::MEMORY;
+using FMR50::SCSI;
+using FMR50::TIMER;
+
+VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
+{
+/*
+       Machine ID & CPU ID
+
+       FMR-50FD/HD/LT  0xF8
+       FMR-50FX/HX     0xE0
+       FMR-50SFX/SHX   0xE8
+       FMR-50LT        0xF8
+       FMR-50NBX       0x28
+       FMR-50NB        0x60
+       FMR-50NE/T      0x08
+       FMR-CARD        0x70
+
+       80286           0x00
+       80386           0x01
+       80386SX         0x03
+       80486           0x02
+*/
+       static const int cpu_clock[] = {
+#if defined(HAS_I286)
+                8000000, 12000000
+#elif defined(HAS_I386)
+               16000000, 20000000
+#elif defined(HAS_I486)
+               20000000, 25000000
+#endif
+       };
+       
+#if defined(_FMR60) && (defined(HAS_I386) || defined(HAS_I486) || defined(HAS_PENTIUM))
+       uint8_t machine_id = 0xf0;      // FMR-70/80
+#else
+       uint8_t machine_id = 0xf8;      // FMR-50/60
+#endif
+       
+       FILEIO* fio = new FILEIO();
+       if(fio->Fopen(create_local_path(_T("MACHINE.ID")), FILEIO_READ_BINARY)) {
+               machine_id = fio->Fgetc();
+               fio->Fclose();
+       }
+       delete fio;
+       
+       machine_id &= ~7;
+#if defined(HAS_I286)
+       machine_id |= 0;        // 286
+#elif defined(HAS_I386)
+//     machine_id |= 1;        // 386DX
+       machine_id |= 3;        // 386SX
+#elif defined(HAS_I486)
+       machine_id |= 2;        // 486SX/DX
+#endif
+       
+       // create devices
+       first_device = last_device = NULL;
+       dummy = new DEVICE(this, emu);  // must be 1st device
+       event = new EVENT(this, emu);   // must be 2nd device
+       dummy->set_device_name(_T("1st Dummy"));
+
+#if defined(HAS_I286)
+       cpu = new I286(this, emu);
+#else
+       cpu = new I386(this, emu);
+#endif
+#if defined(HAS_I286)
+       cpu->set_device_name(_T("CPU(i286)"));
+#elif defined(HAS_I386)
+       cpu->set_device_name(_T("CPU(i386)"));
+#elif defined(HAS_I486)
+       cpu->set_device_name(_T("CPU(i486)"));
+#elif defined(HAS_PENTIUM)
+       cpu->set_device_name(_T("CPU(Pentium)"));
+#endif
+       crtc = new HD46505(this, emu);
+#ifdef _FMR60
+       acrtc = new HD63484(this, emu);
+#endif
+       
+       sio = new I8251(this, emu);
+       pit0 = new I8253(this, emu);
+       pit0->set_device_name(_T("8253 PIT #0"));
+       pit1 = new I8253(this, emu);
+       pit1->set_device_name(_T("8253 PIT #1"));
+       pic = new I8259(this, emu);
+       io = new IO(this, emu);
+       fdc = new MB8877(this, emu);
+       fdc->set_context_noise_seek(new NOISE(this, emu));
+       fdc->set_context_noise_head_down(new NOISE(this, emu));
+       fdc->set_context_noise_head_up(new NOISE(this, emu));
+       rtc = new MSM58321(this, emu);
+       pcm = new PCM1BIT(this, emu);
+       
+       scsi_host = new SCSI_HOST(this, emu);
+       for(int i = 0; i < USE_HARD_DISK; i++) {
+               scsi_hdd[i] = new SCSI_HDD(this, emu);
+               scsi_hdd[i]->set_device_name(_T("SCSI Hard Disk Drive #%d"), i + 1);
+               scsi_hdd[i]->scsi_id = i;
+               scsi_hdd[i]->set_disk_handler(0, new HARDDISK(emu));
+               scsi_hdd[i]->set_context_interface(scsi_host);
+               scsi_host->set_context_target(scsi_hdd[i]);
+       }
+       dma = new UPD71071(this, emu);
+       if(FILEIO::IsFileExisting(create_local_path(_T("IPL.ROM")))) {
+               bios = NULL;
+       } else {
+               bios = new BIOS(this, emu);
+       }
+       cmos = new CMOS(this, emu);
+       floppy = new FLOPPY(this, emu);
+       keyboard = new KEYBOARD(this, emu);
+       memory = new MEMORY(this, emu);
+       scsi = new SCSI(this, emu);
+//     serial = new SERIAL(this, emu);
+       timer = new TIMER(this, emu);
+       // set contexts
+       event->set_context_cpu(cpu, cpu_clock[config.cpu_type & 1]);
+       event->set_context_sound(pcm);
+       event->set_context_sound(fdc->get_context_noise_seek());
+       event->set_context_sound(fdc->get_context_noise_head_down());
+       event->set_context_sound(fdc->get_context_noise_head_up());
+       
+/*     pic     0       timer
+               1       keyboard
+               2       rs-232c
+               3       ex rs-232c
+               4       (option)
+               5       (option)
+               6       floppy drive or dma ???
+               7       (slave)
+               8       scsi
+               9       (option)
+               10      (option)
+               11      (option)
+               12      printer
+               13      (option)
+               14      (option)
+               15      (reserve)
+
+       dma     0       floppy drive
+               1       hard drive
+               2       (option)
+               3       (reserve)
+*/
+       crtc->set_context_disp(memory, SIG_MEMORY_DISP, 1);
+       crtc->set_context_vsync(memory, SIG_MEMORY_VSYNC, 1);
+#ifdef _FMR60
+       acrtc->set_vram_ptr((uint16_t*)memory->get_vram(), 0x80000);
+#endif
+       pit0->set_context_ch0(timer, SIG_TIMER_CH0, 1);
+       pit0->set_context_ch1(timer, SIG_TIMER_CH1, 1);
+       pit0->set_context_ch2(pcm, SIG_PCM1BIT_SIGNAL, 1);
+       pit0->set_constant_clock(0, 307200);
+       pit0->set_constant_clock(1, 307200);
+       pit0->set_constant_clock(2, 307200);
+       pit1->set_constant_clock(1, 1228800);
+       pic->set_context_cpu(cpu);
+       fdc->set_context_drq(dma, SIG_UPD71071_CH0, 1);
+       fdc->set_context_irq(floppy, SIG_FLOPPY_IRQ, 1);
+       rtc->set_context_data(timer, SIG_TIMER_RTC, 0x0f, 0);
+       rtc->set_context_busy(timer, SIG_TIMER_RTC, 0x80);
+       scsi_host->set_context_irq(scsi, SIG_SCSI_IRQ, 1);
+       scsi_host->set_context_drq(scsi, SIG_SCSI_DRQ, 1);
+       dma->set_context_memory(memory);
+       dma->set_context_ch0(fdc);
+       dma->set_context_ch1(scsi_host);
+       
+       floppy->set_context_fdc(fdc);
+       floppy->set_context_pic(pic);
+       keyboard->set_context_pic(pic);
+       memory->set_context_cpu(cpu);
+       memory->set_machine_id(machine_id);
+       memory->set_context_crtc(crtc);
+       memory->set_chregs_ptr(crtc->get_regs());
+       scsi->set_context_dma(dma);
+       scsi->set_context_pic(pic);
+       scsi->set_context_host(scsi_host);
+       timer->set_context_pcm(pcm);
+       timer->set_context_pic(pic);
+       timer->set_context_rtc(rtc);
+       
+       // cpu bus
+       cpu->set_context_mem(memory);
+       cpu->set_context_io(io);
+       cpu->set_context_intr(pic);
+       if(bios) {
+               bios->set_context_mem(memory);
+               bios->set_context_io(io);
+               bios->set_cmos_ptr(cmos->get_cmos());
+               bios->set_vram_ptr(memory->get_vram());
+               bios->set_cvram_ptr(memory->get_cvram());
+#ifdef _FMR60
+               bios->set_avram_ptr(memory->get_avram());
+#else
+               bios->set_kvram_ptr(memory->get_kvram());
+#endif
+               cpu->set_context_bios(bios);
+       }
+#ifdef SINGLE_MODE_DMA
+       cpu->set_context_dma(dma);
+#endif
+#ifdef USE_DEBUGGER
+       cpu->set_context_debugger(new DEBUGGER(this, emu));
+#endif
+       
+       // i/o bus
+       io->set_iomap_alias_rw(0x00, pic, I8259_ADDR_CHIP0 | 0);
+       io->set_iomap_alias_rw(0x02, pic, I8259_ADDR_CHIP0 | 1);
+       io->set_iomap_alias_rw(0x10, pic, I8259_ADDR_CHIP1 | 0);
+       io->set_iomap_alias_rw(0x12, pic, I8259_ADDR_CHIP1 | 1);
+       io->set_iomap_single_rw(0x20, memory);  // reset
+       io->set_iomap_single_r(0x21, memory);   // cpu misc
+       io->set_iomap_single_w(0x22, memory);   // dma
+       io->set_iomap_single_rw(0x24, memory);  // dma
+       io->set_iomap_single_r(0x26, timer);
+       io->set_iomap_single_r(0x27, timer);
+       io->set_iomap_single_r(0x30, memory);   // cpu id
+       io->set_iomap_alias_rw(0x40, pit0, 0);
+       io->set_iomap_alias_rw(0x42, pit0, 1);
+       io->set_iomap_alias_rw(0x44, pit0, 2);
+       io->set_iomap_alias_rw(0x46, pit0, 3);
+       io->set_iomap_alias_rw(0x50, pit1, 0);
+       io->set_iomap_alias_rw(0x52, pit1, 1);
+       io->set_iomap_alias_rw(0x54, pit1, 2);
+       io->set_iomap_alias_rw(0x56, pit1, 3);
+       io->set_iomap_single_rw(0x60, timer);
+       io->set_iomap_single_rw(0x70, timer);
+       io->set_iomap_single_w(0x80, timer);
+#ifdef _FMRCARD
+       io->set_iomap_single_w(0x90, cmos);
+#endif
+       io->set_iomap_range_rw(0xa0, 0xaf, dma);
+       io->set_iomap_alias_rw(0x200, fdc, 0);
+       io->set_iomap_alias_rw(0x202, fdc, 1);
+       io->set_iomap_alias_rw(0x204, fdc, 2);
+       io->set_iomap_alias_rw(0x206, fdc, 3);
+       io->set_iomap_single_rw(0x208, floppy);
+       io->set_iomap_single_rw(0x20c, floppy);
+       io->set_iomap_single_rw(0x400, memory); // crtc
+       io->set_iomap_single_rw(0x402, memory); // crtc
+       io->set_iomap_single_rw(0x404, memory); // crtc
+       io->set_iomap_single_w(0x408, memory);  // crtc
+       io->set_iomap_single_rw(0x40a, memory); // crtc
+       io->set_iomap_single_rw(0x40c, memory); // crtc
+       io->set_iomap_single_rw(0x40e, memory); // crtc
+       io->set_iomap_alias_rw(0x500, crtc, 0);
+       io->set_iomap_alias_rw(0x502, crtc, 1);
+#ifdef _FMR60
+       io->set_iomap_range_rw(0x520, 0x523, acrtc);
+#endif
+       io->set_iomap_single_rw(0x600, keyboard);
+       io->set_iomap_single_rw(0x602, keyboard);
+       io->set_iomap_single_rw(0x604, keyboard);
+       io->set_iomap_alias_rw(0xa00, sio, 0);
+       io->set_iomap_alias_rw(0xa02, sio, 1);
+//     io->set_iomap_single_r(0xa04, serial);
+//     io->set_iomap_single_r(0xa06, serial);
+//     io->set_iomap_single_w(0xa08, serial);
+       io->set_iomap_single_rw(0xc30, scsi);
+       io->set_iomap_single_rw(0xc32, scsi);
+       io->set_iomap_range_rw(0x3000, 0x3fff, cmos);
+       io->set_iomap_range_rw(0xfd98, 0xfd9f, memory); // crtc
+       io->set_iomap_single_rw(0xfda0, memory);        // crtc
+       
+       // initialize all devices
+#if defined(__GIT_REPO_VERSION)
+       strncpy(_git_revision, __GIT_REPO_VERSION, sizeof(_git_revision) - 1);
+#endif
+       for(DEVICE* device = first_device; device; device = device->next_device) {
+               device->initialize();
+       }
+
+       for(int drv = 0; drv < USE_HARD_DISK; drv++) {
+               if(!(config.last_hard_disk_path[drv][0] != _T('\0') && FILEIO::IsFileExisting(config.last_hard_disk_path[drv]))) {
+                       create_local_path(config.last_hard_disk_path[drv], _MAX_PATH, _T("SCSI%d.DAT"), drv);
+               }
+       }
+       if(bios) {
+               for(int drv = 0; drv < MAX_DRIVE; drv++) {
+                       bios->set_floppy_disk_handler(drv, fdc->get_disk_handler(drv));
+               }
+               for(int drv = 0; drv < USE_HARD_DISK; drv++) {
+                       bios->set_hard_disk_handler(drv, scsi_hdd[drv]->get_disk_handler(0));
+               }
+       }
+}
+
+VM::~VM()
+{
+       // delete all devices
+       for(DEVICE* device = first_device; device;) {
+               DEVICE *next_device = device->next_device;
+               device->release();
+               delete device;
+               device = next_device;
+       }
+}
+
+DEVICE* VM::get_device(int id)
+{
+       for(DEVICE* device = first_device; device; device = device->next_device) {
+               if(device->this_device_id == id) {
+                       return device;
+               }
+       }
+       return NULL;
+}
+
+// ----------------------------------------------------------------------------
+// drive virtual machine
+// ----------------------------------------------------------------------------
+
+void VM::reset()
+{
+       // reset all devices
+       for(DEVICE* device = first_device; device; device = device->next_device) {
+               device->reset();
+       }
+       // temporary fix...
+       for(DEVICE* device = first_device; device; device = device->next_device) {
+               device->reset();
+       }
+}
+
+void VM::run()
+{
+       event->drive();
+}
+
+// ----------------------------------------------------------------------------
+// debugger
+// ----------------------------------------------------------------------------
+
+#ifdef USE_DEBUGGER
+DEVICE *VM::get_cpu(int index)
+{
+       if(index == 0) {
+               return cpu;
+       }
+       return NULL;
+}
+#endif
+
+// ----------------------------------------------------------------------------
+// draw screen
+// ----------------------------------------------------------------------------
+
+void VM::draw_screen()
+{
+       memory->draw_screen();
+}
+
+// ----------------------------------------------------------------------------
+// soud manager
+// ----------------------------------------------------------------------------
+
+void VM::initialize_sound(int rate, int samples)
+{
+       // init sound manager
+       event->initialize_sound(rate, samples);
+       
+       // init sound gen
+       pcm->initialize_sound(rate, 8000);
+}
+
+uint16_t* VM::create_sound(int* extra_frames)
+{
+       return event->create_sound(extra_frames);
+}
+
+int VM::get_sound_buffer_ptr()
+{
+       return event->get_sound_buffer_ptr();
+}
+
+#ifdef USE_SOUND_VOLUME
+void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
+{
+       if(ch == 0) {
+               pcm->set_volume(0, decibel_l, decibel_r);
+       } else if(ch == 1) {
+               fdc->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
+               fdc->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
+               fdc->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
+       }
+}
+#endif
+
+// ----------------------------------------------------------------------------
+// notify key
+// ----------------------------------------------------------------------------
+
+void VM::key_down(int code, bool repeat)
+{
+       keyboard->key_down(code);
+}
+
+void VM::key_up(int code)
+{
+       keyboard->key_up(code);
+}
+
+// ----------------------------------------------------------------------------
+// user interface
+// ----------------------------------------------------------------------------
+
+void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
+{
+       fdc->open_disk(drv, file_path, bank);
+       floppy->change_disk(drv);
+}
+
+void VM::close_floppy_disk(int drv)
+{
+       fdc->close_disk(drv);
+}
+
+bool VM::is_floppy_disk_inserted(int drv)
+{
+       return fdc->is_disk_inserted(drv);
+}
+
+void VM::is_floppy_disk_protected(int drv, bool value)
+{
+       fdc->is_disk_protected(drv, value);
+}
+
+bool VM::is_floppy_disk_protected(int drv)
+{
+       return fdc->is_disk_protected(drv);
+}
+
+uint32_t VM::is_floppy_disk_accessed()
+{
+       uint32_t status = fdc->read_signal(0);
+       if(bios) {
+               status |= bios->read_signal(0);
+       }
+       return status;
+}
+
+void VM::open_hard_disk(int drv, const _TCHAR* file_path)
+{
+       if(drv < USE_HARD_DISK) {
+               scsi_hdd[drv]->open(0, file_path, 512);
+       }
+}
+
+void VM::close_hard_disk(int drv)
+{
+       if(drv < USE_HARD_DISK) {
+               scsi_hdd[drv]->close(0);
+       }
+}
+
+bool VM::is_hard_disk_inserted(int drv)
+{
+       if(drv < USE_HARD_DISK) {
+               return scsi_hdd[drv]->mounted(0);
+       }
+       return false;
+}
+
+uint32_t VM::is_hard_disk_accessed()
+{
+       uint32_t status = 0;
+       
+       for(int drv = 0; drv < USE_HARD_DISK; drv++) {
+               if(scsi_hdd[drv]->accessed(0)) {
+                       status |= 1 << drv;
+               }
+       }
+       return status;
+}
+
+bool VM::is_frame_skippable()
+{
+       return event->is_frame_skippable();
+}
+
+void VM::update_config()
+{
+       for(DEVICE* device = first_device; device; device = device->next_device) {
+               device->update_config();
+       }
+}
+
+#define STATE_VERSION  6
+
+bool VM::process_state(FILEIO* state_fio, bool loading)
+{
+       if(!state_fio->StateCheckUint32(STATE_VERSION)) {
+               return false;
+       }
+       for(DEVICE* device = first_device; device; device = device->next_device) {
+               // Note: typeid(foo).name is fixed by recent ABI.Not dec 6.
+               // const char *name = typeid(*device).name();
+               //       But, using get_device_name() instead of typeid(foo).name() 20181008 K.O
+               const char *name = device->get_device_name();
+               int len = strlen(name);
+               
+               if(!state_fio->StateCheckInt32(len)) {
+                       if(loading) {
+                               printf("Class name len Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
+                       }
+                       return false;
+               }
+               if(!state_fio->StateCheckBuffer(name, len, 1)) {
+                       if(loading) {
+                               printf("Class name Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
+                       }
+                       return false;
+               }
+               if(!device->process_state(state_fio, loading)) {
+                       if(loading) {
+                               printf("Data loading Error: DEVID=%d\n", device->this_device_id);
+                       }
+                       return false;
+               }
+       }
+       // Machine specified.
+       return true;
+}