OSDN Git Service

[LIBNEWDEV][I8086] Apply to FM16pi, FM-R30, PC-100 and PC98HA.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmr30 / fmr30.cpp
1 /*
2         FUJITSU FMR-30 Emulator 'eFMR-30'
3
4         Author : Takeda.Toshiya
5         Date   : 2008.12.29 -
6
7         [ virtual machine ]
8 */
9
10 #include "fmr30.h"
11 #include "../../emu.h"
12 #include "../device.h"
13 #include "../event.h"
14
15 #include "../i8237.h"
16 #include "../i8251.h"
17 #include "../i8253.h"
18 #include "../i8259.h"
19 #include "../i86.h"
20 #include "../io.h"
21 #include "../mb8877.h"
22 #include "../scsi_hdd.h"
23 #include "../scsi_host.h"
24 #include "../sn76489an.h"
25
26 #ifdef USE_DEBUGGER
27 #include "../debugger.h"
28 #endif
29
30 #include "../fmr50/bios.h"
31 #include "cmos.h"
32 #include "floppy.h"
33 #include "keyboard.h"
34 #include "memory.h"
35 #include "rtc.h"
36 #include "scsi.h"
37 #include "serial.h"
38 #include "system.h"
39 #include "timer.h"
40
41 // ----------------------------------------------------------------------------
42 // initialize
43 // ----------------------------------------------------------------------------
44
45 VM::VM(EMU* parent_emu) : emu(parent_emu)
46 {
47         // create devices
48         first_device = last_device = NULL;
49         dummy = new DEVICE(this, emu);  // must be 1st device
50         event = new EVENT(this, emu);   // must be 2nd device
51         
52         dma = new I8237(this, emu);
53         sio_kb = new I8251(this, emu);  // keyboard
54         sio_sub = new I8251(this, emu); // sub display
55         sio_ch1 = new I8251(this, emu); // RS-232C ch.1
56         sio_ch2 = new I8251(this, emu); // RS-232C ch.2
57         pit = new I8253(this, emu);
58         pic = new I8259(this, emu);
59         cpu = new I86(this, emu);
60         io = new IO(this, emu);
61         fdc = new MB8877(this, emu);
62 #if defined(_USE_QT)
63         dummy->set_device_name(_T("1st Dummy"));
64         event->set_device_name(_T("EVENT"));
65
66         dma->set_device_name(_T("i8237 DMAC"));
67         sio_kb->set_device_name(_T("i8251 SIO(KEYBOARD)"));
68         sio_sub->set_device_name(_T("i8251 SIO(SUB SYSTEM)"));
69         sio_ch1->set_device_name(_T("i8251 SIO(RS-232C #1)"));
70         sio_ch2->set_device_name(_T("i8251 SIO(RS-232C #2)"));
71         pit->set_device_name(_T("i8253 PIT"));
72         pic->set_device_name(_T("i8259 PIC"));
73         cpu->set_device_name(_T("CPU(80C86)"));
74 #endif
75         
76         scsi_host = new SCSI_HOST(this, emu);
77 #if defined(_USE_QT)
78         scsi_host->set_device_name(_T("SCSI HOST"));
79 #endif  
80         for(int i = 0; i < 7; i++) {
81                 if(FILEIO::IsFileExisting(create_local_path(_T("SCSI%d.DAT"), i))) {
82                         SCSI_HDD* scsi_hdd = new SCSI_HDD(this, emu);
83 #if defined(_USE_QT)
84                         char d_name[64] = {0};
85                         snprintf(d_name, 64, "SCSI DISK #%d", i + 1);
86                         scsi_hdd->set_device_name(d_name);
87 #endif                  
88                         scsi_hdd->scsi_id = i;
89                         scsi_hdd->set_context_interface(scsi_host);
90                         scsi_host->set_context_target(scsi_hdd);
91                 }
92         }
93         psg = new SN76489AN(this, emu);
94 #if defined(_USE_QT)
95         psg->set_device_name(_T("SN76489 PSG"));
96 #endif  
97         if(FILEIO::IsFileExisting(create_local_path(_T("IPL.ROM")))) {
98                 bios = NULL;
99         } else {
100                 bios = new BIOS(this, emu);
101 #if defined(_USE_QT)
102                 bios->set_device_name(_T("PSEUDO BIOS"));
103 #endif  
104         }
105         cmos = new CMOS(this, emu);
106         floppy = new FLOPPY(this, emu);
107         keyboard = new KEYBOARD(this, emu);
108         memory = new MEMORY(this, emu);
109         rtc = new RTC(this, emu);
110         scsi = new SCSI(this, emu);
111         serial = new SERIAL(this, emu);
112         system = new SYSTEM(this, emu);
113         timer = new TIMER(this, emu);
114 #if defined(_USE_QT)
115         cmos->set_device_name(_T("CMOS RAM"));
116         floppy->set_device_name(_T("FLOPPY I/F"));
117         keyboard->set_device_name(_T("KEYBOARD"));
118         memory->set_device_name(_T("MEMORY"));
119         rtc->set_device_name(_T("RTC"));
120         scsi->set_device_name(_T("SCSI I/F"));
121         serial->set_device_name(_T("SERIAL I/F"));
122         system->set_device_name(_T("SYSTEM I/O"));
123         timer->set_device_name(_T("TIMER I/F"));
124 #endif
125         // set contexts
126         event->set_context_cpu(cpu);
127         event->set_context_sound(psg);
128 #if defined(USE_SOUND_FILES)
129         if(fdc->load_sound_data(MB8877_SND_TYPE_SEEK, _T("FDDSEEK.WAV"))) {
130                 event->set_context_sound(fdc);
131         }
132 #endif
133         
134         dma->set_context_memory(memory);
135         dma->set_context_ch0(fdc);
136         dma->set_context_ch1(scsi_host);
137         dma->set_context_tc1(scsi, SIG_SCSI_TC, 1);
138         sio_kb->set_context_rxrdy(serial, SIG_SERIAL_RXRDY_KB, 1);
139         sio_kb->set_context_txrdy(serial, SIG_SERIAL_TXRDY_KB, 1);
140         sio_sub->set_context_rxrdy(serial, SIG_SERIAL_RXRDY_SUB, 1);
141         sio_sub->set_context_txrdy(serial, SIG_SERIAL_TXRDY_SUB, 1);
142         sio_ch1->set_context_rxrdy(serial, SIG_SERIAL_RXRDY_CH1, 1);
143         sio_ch1->set_context_txrdy(serial, SIG_SERIAL_TXRDY_CH1, 1);
144         sio_ch2->set_context_rxrdy(serial, SIG_SERIAL_RXRDY_CH2, 1);
145         sio_ch2->set_context_txrdy(serial, SIG_SERIAL_TXRDY_CH2, 1);
146         pit->set_context_ch0(timer, SIG_TIMER_CH0, 1);
147         pit->set_context_ch1(timer, SIG_TIMER_CH1, 1);
148         pit->set_constant_clock(0, 1000000);
149         pit->set_constant_clock(1, 1000000);
150         pic->set_context_cpu(cpu);
151         fdc->set_context_drq(dma, SIG_I8237_CH0, 1);
152         fdc->set_context_irq(floppy, SIG_FLOPPY_IRQ, 1);
153         scsi_host->set_context_irq(scsi, SIG_SCSI_IRQ, 1);
154         scsi_host->set_context_drq(scsi, SIG_SCSI_DRQ, 1);
155         
156         floppy->set_context_fdc(fdc);
157         floppy->set_context_pic(pic);
158         keyboard->set_context_sio(sio_kb);
159         memory->set_context_cpu(cpu);
160         memory->set_context_dma(dma);
161         rtc->set_context_pic(pic);
162         scsi->set_context_dma(dma);
163         scsi->set_context_pic(pic);
164         scsi->set_context_host(scsi_host);
165         serial->set_context_pic(pic);
166         serial->set_context_sio(sio_kb, sio_sub, sio_ch1, sio_ch2);
167         timer->set_context_pic(pic);
168         
169         // cpu bus
170         cpu->set_context_mem(memory);
171         cpu->set_context_io(io);
172         cpu->set_context_intr(pic);
173         if(bios) {
174                 bios->set_context_mem(memory);
175                 bios->set_context_io(io);
176                 bios->set_cmos_ptr(cmos->get_cmos());
177                 bios->set_vram_ptr(memory->get_vram());
178                 bios->set_cvram_ptr(memory->get_cvram());
179                 bios->set_kvram_ptr(memory->get_kvram());
180                 cpu->set_context_bios(bios);
181         }
182 #ifdef SINGLE_MODE_DMA
183         cpu->set_context_dma(dma);
184 #endif
185 #ifdef USE_DEBUGGER
186         cpu->set_context_debugger(new DEBUGGER(this, emu));
187 #endif
188         
189         // i/o bus
190         io->set_iomap_range_rw(0x00, 0x07, rtc);
191         io->set_iomap_range_rw(0x08, 0x09, sio_kb);
192         io->set_iomap_range_rw(0x0a, 0x0b, serial);
193         io->set_iomap_range_rw(0x10, 0x11, sio_sub);
194         io->set_iomap_range_rw(0x12, 0x13, serial);
195         io->set_iomap_single_r(0x18, system);
196         io->set_iomap_range_rw(0x1d, 0x1e, memory);
197         io->set_iomap_range_r(0x20, 0x21, system);
198         io->set_iomap_single_rw(0x26, memory);
199         io->set_iomap_range_rw(0x30, 0x33, fdc);
200         io->set_iomap_range_rw(0x34, 0x36, floppy);
201         io->set_iomap_single_w(0x40, psg);
202         io->set_iomap_range_rw(0x42, 0x43, timer);
203         io->set_iomap_range_rw(0x46, 0x47, system);
204         io->set_iomap_range_rw(0x60, 0x61, sio_ch1);
205         io->set_iomap_range_rw(0x62, 0x66, serial);
206         io->set_iomap_range_rw(0x70, 0x71, sio_ch2);
207         io->set_iomap_range_rw(0x72, 0x76, serial);
208         io->set_iomap_alias_rw(0x100, pic, I8259_ADDR_CHIP0 | 0);
209         io->set_iomap_alias_rw(0x101, pic, I8259_ADDR_CHIP0 | 1);
210         io->set_iomap_alias_rw(0x108, pic, I8259_ADDR_CHIP1 | 0);
211         io->set_iomap_alias_rw(0x10a, pic, I8259_ADDR_CHIP1 | 1);
212         io->set_iomap_range_rw(0x110, 0x11f, dma);
213         io->set_iomap_range_w(0x120, 0x123, memory);
214         io->set_iomap_range_rw(0x130, 0x133, pit);
215         io->set_iomap_range_rw(0x2f0, 0x2f3, scsi);
216         io->set_iomap_range_rw(0x300, 0x30f, memory);
217         io->set_iomap_range_rw(0xc000, 0xdfff, cmos);
218         io->set_iomap_single_rw(0xff00, system);
219         
220         // initialize all devices
221         for(DEVICE* device = first_device; device; device = device->next_device) {
222                 device->initialize();
223         }
224         if(bios) {
225                 for(int i = 0; i < MAX_DRIVE; i++) {
226                         bios->set_disk_handler(i, fdc->get_disk_handler(i));
227                 }
228         }
229 }
230
231 VM::~VM()
232 {
233         // delete all devices
234         for(DEVICE* device = first_device; device;) {
235                 DEVICE *next_device = device->next_device;
236                 device->release();
237                 delete device;
238                 device = next_device;
239         }
240 }
241
242 DEVICE* VM::get_device(int id)
243 {
244         for(DEVICE* device = first_device; device; device = device->next_device) {
245                 if(device->this_device_id == id) {
246                         return device;
247                 }
248         }
249         return NULL;
250 }
251
252 // ----------------------------------------------------------------------------
253 // drive virtual machine
254 // ----------------------------------------------------------------------------
255
256 void VM::reset()
257 {
258         // reset all devices
259         for(DEVICE* device = first_device; device; device = device->next_device) {
260                 device->reset();
261         }
262         // temporary fix...
263         for(DEVICE* device = first_device; device; device = device->next_device) {
264                 device->reset();
265         }
266         
267         // set devices
268         sio_kb->write_signal(SIG_I8251_DSR, 1, 1);
269         sio_sub->write_signal(SIG_I8251_DSR, 0, 0);
270 }
271
272 void VM::run()
273 {
274         event->drive();
275 }
276
277 // ----------------------------------------------------------------------------
278 // debugger
279 // ----------------------------------------------------------------------------
280
281 #ifdef USE_DEBUGGER
282 DEVICE *VM::get_cpu(int index)
283 {
284         if(index == 0) {
285                 return cpu;
286         }
287         return NULL;
288 }
289 #endif
290
291 // ----------------------------------------------------------------------------
292 // draw screen
293 // ----------------------------------------------------------------------------
294
295 void VM::draw_screen()
296 {
297         memory->draw_screen();
298 }
299
300 uint32_t VM::get_access_lamp_status()
301 {
302         uint32_t status_fdd = fdc->read_signal(0);
303         uint32_t status_hdd = scsi_host->read_signal(0);
304         if(bios) {
305                 uint32_t status = bios->read_signal(0);
306                 status_fdd |= status & 0x0f;
307                 status_hdd |= status >> 4;
308         }
309         return (status_hdd) ? 4 : (status_fdd & (1 | 4)) ? 1 : (status_fdd & (2 | 8)) ? 2 : 0;
310 }
311
312 // ----------------------------------------------------------------------------
313 // soud manager
314 // ----------------------------------------------------------------------------
315
316 void VM::initialize_sound(int rate, int samples)
317 {
318         // init sound manager
319         event->initialize_sound(rate, samples);
320         
321         // init sound gen
322         psg->initialize_sound(rate, 125000, 10000);
323 }
324
325 uint16_t* VM::create_sound(int* extra_frames)
326 {
327         return event->create_sound(extra_frames);
328 }
329
330 int VM::get_sound_buffer_ptr()
331 {
332         return event->get_sound_buffer_ptr();
333 }
334
335 #ifdef USE_SOUND_VOLUME
336 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
337 {
338         if(ch == 0) {
339                 psg->set_volume(0, decibel_l, decibel_r);
340         }
341 #if defined(USE_SOUND_FILES)
342         else if(ch == 1) {
343                 fdc->set_volume(0, decibel_l, decibel_r);
344         }
345 #endif
346 }
347 #endif
348
349 // ----------------------------------------------------------------------------
350 // notify key
351 // ----------------------------------------------------------------------------
352
353 void VM::key_down(int code, bool repeat)
354 {
355         keyboard->key_down(code);
356 }
357
358 void VM::key_up(int code)
359 {
360         keyboard->key_up(code);
361 }
362
363 // ----------------------------------------------------------------------------
364 // user interface
365 // ----------------------------------------------------------------------------
366
367 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
368 {
369         fdc->open_disk(drv, file_path, bank);
370         floppy->change_disk(drv);
371 }
372
373 void VM::close_floppy_disk(int drv)
374 {
375         fdc->close_disk(drv);
376 }
377
378 bool VM::is_floppy_disk_inserted(int drv)
379 {
380         return fdc->is_disk_inserted(drv);
381 }
382
383 void VM::is_floppy_disk_protected(int drv, bool value)
384 {
385         fdc->is_disk_protected(drv, value);
386 }
387
388 bool VM::is_floppy_disk_protected(int drv)
389 {
390         return fdc->is_disk_protected(drv);
391 }
392
393 bool VM::is_frame_skippable()
394 {
395         return event->is_frame_skippable();
396 }
397
398 void VM::update_config()
399 {
400         for(DEVICE* device = first_device; device; device = device->next_device) {
401                 device->update_config();
402         }
403 }
404
405 #define STATE_VERSION   3
406
407 void VM::save_state(FILEIO* state_fio)
408 {
409         state_fio->FputUint32(STATE_VERSION);
410         
411         for(DEVICE* device = first_device; device; device = device->next_device) {
412                 device->save_state(state_fio);
413         }
414 }
415
416 bool VM::load_state(FILEIO* state_fio)
417 {
418         if(state_fio->FgetUint32() != STATE_VERSION) {
419                 return false;
420         }
421         for(DEVICE* device = first_device; device; device = device->next_device) {
422                 if(!device->load_state(state_fio)) {
423                         return false;
424                 }
425         }
426         return true;
427 }
428