OSDN Git Service

0133c9d95d8db82d7da99989aaab0e3aacf87620
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmtowns / fmtowns.cpp
1 /*
2         FUJITSU FM-Towns Emulator 'eFMR-60'
3
4         Author : Kyuma Ohta <whatisthis.sowhat _at_ gmail.com>
5         Date   : 216.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 "towns_crtc.h"
18 //#include "../hd46505.h"
19 #include "../i8251.h"
20 #include "../i8253.h"
21 #include "../i8259.h"
22
23 #include "../i386.h"
24
25 #include "../io.h"
26 #include "../mb8877.h"
27 #include "../msm58321.h"
28 #include "../pcm1bit.h"
29 #include "../scsi_hdd.h"
30 #include "../scsi_host.h"
31 #include "../upd71071.h"
32
33 // Electric Volume
34 //#include "mb87078.h"
35 //YM-2612 "OPN2"
36 //#include "../ym2612.h"
37 //RF5C68 PCM
38 //#include "rp5c68.h"
39 //AD7820 ADC
40 //#include "ad7820.h"
41 // 80387?
42
43 #ifdef USE_DEBUGGER
44 #include "../debugger.h"
45 #endif
46
47 #include "bios.h"
48 #include "cmos.h"
49 #include "floppy.h"
50 #include "keyboard.h"
51 #include "memory.h"
52 #include "scsi.h"
53 //#include "serial.h"
54 #include "timer.h"
55
56 // ----------------------------------------------------------------------------
57 // initialize
58 // ----------------------------------------------------------------------------
59
60 VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
61 {
62 /*
63         Machine ID & CPU ID
64
65         FMR-50FD/HD/LT  0xF8
66         FMR-50FX/HX     0xE0
67         FMR-50SFX/SHX   0xE8
68         FMR-50LT        0xF8
69         FMR-50NBX       0x28
70         FMR-50NB        0x60
71         FMR-50NE/T      0x08
72         FMR-CARD        0x70
73
74         80286           0x00
75         80386           0x01
76         80386SX         0x03
77         80486           0x02
78 */
79         static const int cpu_clock[] = {
80 #if defined(HAS_I386)
81                 16000000, 20000000
82 #elif defined(HAS_I486)
83                 20000000, 25000000
84 #endif
85         };
86         
87 #if defined(_FMR60) && (defined(HAS_I386) || defined(HAS_I486) || defined(HAS_PENTIUM))
88         uint8_t machine_id = 0xf0;      // FMR-70/80
89 #else
90         uint8_t machine_id = 0xf8;      // FMR-50/60
91 #endif
92         
93         FILEIO* fio = new FILEIO();
94         if(fio->Fopen(create_local_path(_T("MACHINE.ID")), FILEIO_READ_BINARY)) {
95                 machine_id = fio->Fgetc();
96                 fio->Fclose();
97         }
98         delete fio;
99         
100         machine_id &= ~7;
101 #if defined(HAS_I286)
102         machine_id |= 0;        // 286
103 #elif defined(HAS_I386)
104 //      machine_id |= 1;        // 386DX
105         machine_id |= 3;        // 386SX
106 #elif defined(HAS_I486)
107         machine_id |= 2;        // 486SX/DX
108 #endif
109         
110         // create devices
111         first_device = last_device = NULL;
112         dummy = new DEVICE(this, emu);  // must be 1st device
113         event = new EVENT(this, emu);   // must be 2nd device
114 #if defined(_USE_QT)
115         dummy->set_device_name(_T("1st Dummy"));
116         event->set_device_name(_T("EVENT"));
117 #endif  
118
119         cpu = new I386(this, emu);
120 #if defined(_USE_QT)
121   #if defined(HAS_I386)
122         cpu->set_device_name(_T("CPU(i386)"));
123   #elif defined(HAS_I486)
124         cpu->set_device_name(_T("CPU(i486)"));
125   #elif defined(HAS_PENTIUM)
126         cpu->set_device_name(_T("CPU(Pentium)"));
127   #endif
128 #endif  
129
130         crtc = new TOWNS_CRTC(this, emu);
131         
132 #if defined(_USE_QT)
133         crtc->set_device_name(_T("TOWNS CRTC"));
134 #endif
135         
136         sio = new I8251(this, emu);
137         pit0 = new I8253(this, emu);
138         pit1 = new I8253(this, emu);
139         pic = new I8259(this, emu);
140         io = new IO(this, emu);
141         fdc = new MB8877(this, emu);
142         rtc = new MSM58321(this, emu);
143         pcm = new PCM1BIT(this, emu);
144 #if defined(_USE_QT)    
145         sio->set_device_name(_T("i8251 SIO"));
146         pit0->set_device_name(_T("i8253 PIT #0"));
147         pit1->set_device_name(_T("i8253 PIT #1"));
148         pic->set_device_name(_T("i8259 PIC"));
149         rtc->set_device_name(_T("MSM58321 RTC"));
150         pcm->set_device_name(_T("PCM SOUND"));
151 #endif
152         
153         scsi_host = new SCSI_HOST(this, emu);
154 #if defined(_USE_QT)    
155         scsi_host->set_device_name(_T("SCSI HOST"));
156 #endif  
157         for(int i = 0; i < 7; i++) {
158                 if(FILEIO::IsFileExisting(create_local_path(_T("SCSI%d.DAT"), i))) {
159                         SCSI_HDD* scsi_hdd = new SCSI_HDD(this, emu);
160 #if defined(_USE_QT)
161                         char d_name[64] = {0};
162                         snprintf(d_name, 64, "SCSI DISK #%d", i + 1);
163                         scsi_hdd->set_device_name(d_name);
164 #endif                  
165                         scsi_hdd->scsi_id = i;
166                         scsi_hdd->set_context_interface(scsi_host);
167                         scsi_host->set_context_target(scsi_hdd);
168                 }
169         }
170         dma = new UPD71071(this, emu);
171 #if defined(_USE_QT)    
172         dma->set_device_name(_T("uPD71071 DMAC"));
173 #endif  
174         if(FILEIO::IsFileExisting(create_local_path(_T("IPL.ROM")))) {
175                 bios = NULL;
176         } else {
177                 bios = new BIOS(this, emu);
178 #if defined(_USE_QT)
179                 bios->set_device_name(_T("PSEUDO BIOS"));
180 #endif
181         }
182         cmos = new CMOS(this, emu);
183         floppy = new FLOPPY(this, emu);
184         keyboard = new KEYBOARD(this, emu);
185         memory = new MEMORY(this, emu);
186         scsi = new SCSI(this, emu);
187 //      serial = new SERIAL(this, emu);
188         timer = new TIMER(this, emu);
189 #if defined(_USE_QT)
190         cmos->set_device_name(_T("CMOS RAM"));
191         floppy->set_device_name(_T("FLOPPY I/F"));
192         keyboard->set_device_name(_T("KEYBOARD"));
193         memory->set_device_name(_T("MEMORY"));
194         scsi->set_device_name(_T("SCSI I/F"));
195         //serial->set_device_name(_T("SERIAL I/F"));
196         timer->set_device_name(_T("TIMER I/F"));
197 #endif
198         
199         // set contexts
200         event->set_context_cpu(cpu, cpu_clock[config.cpu_type & 1]);
201         event->set_context_sound(pcm);
202 #if defined(USE_SOUND_FILES)
203         if(fdc->load_sound_data(MB8877_SND_TYPE_SEEK, _T("FDDSEEK.WAV"))) {
204                 event->set_context_sound(fdc);
205         }
206 #endif
207         
208 /*      pic     0       timer
209                 1       keyboard
210                 2       rs-232c
211                 3       ex rs-232c
212                 4       (option)
213                 5       (option)
214                 6       floppy drive or dma ???
215                 7       (slave)
216                 8       scsi
217                 9       (option)
218                 10      (option)
219                 11      (option)
220                 12      printer
221                 13      (option)
222                 14      (option)
223                 15      (reserve)
224
225         dma     0       floppy drive
226                 1       hard drive
227                 2       (option)
228                 3       (reserve)
229 */
230         crtc->set_context_disp(memory, SIG_MEMORY_DISP, 1);
231         crtc->set_context_vsync(memory, SIG_MEMORY_VSYNC, 1);
232 #ifdef _FMR60
233         acrtc->set_vram_ptr((uint16_t*)memory->get_vram(), 0x80000);
234 #endif
235         pit0->set_context_ch0(timer, SIG_TIMER_CH0, 1);
236         pit0->set_context_ch1(timer, SIG_TIMER_CH1, 1);
237         pit0->set_context_ch2(pcm, SIG_PCM1BIT_SIGNAL, 1);
238         pit0->set_constant_clock(0, 307200);
239         pit0->set_constant_clock(1, 307200);
240         pit0->set_constant_clock(2, 307200);
241         pit1->set_constant_clock(1, 1228800);
242         pic->set_context_cpu(cpu);
243         fdc->set_context_drq(dma, SIG_UPD71071_CH0, 1);
244         fdc->set_context_irq(floppy, SIG_FLOPPY_IRQ, 1);
245         rtc->set_context_data(timer, SIG_TIMER_RTC, 0x0f, 0);
246         rtc->set_context_busy(timer, SIG_TIMER_RTC, 0x80);
247         scsi_host->set_context_irq(scsi, SIG_SCSI_IRQ, 1);
248         scsi_host->set_context_drq(scsi, SIG_SCSI_DRQ, 1);
249         dma->set_context_memory(memory);
250         dma->set_context_ch0(fdc);
251         dma->set_context_ch1(scsi_host);
252         
253         floppy->set_context_fdc(fdc);
254         floppy->set_context_pic(pic);
255         keyboard->set_context_pic(pic);
256         memory->set_context_cpu(cpu);
257         memory->set_machine_id(machine_id);
258         memory->set_context_crtc(crtc);
259         memory->set_chregs_ptr(crtc->get_regs());
260         scsi->set_context_dma(dma);
261         scsi->set_context_pic(pic);
262         scsi->set_context_host(scsi_host);
263         timer->set_context_pcm(pcm);
264         timer->set_context_pic(pic);
265         timer->set_context_rtc(rtc);
266         
267         // cpu bus
268         cpu->set_context_mem(memory);
269         cpu->set_context_io(io);
270         cpu->set_context_intr(pic);
271         if(bios) {
272                 bios->set_context_mem(memory);
273                 bios->set_context_io(io);
274                 bios->set_cmos_ptr(cmos->get_cmos());
275                 bios->set_vram_ptr(memory->get_vram());
276                 bios->set_cvram_ptr(memory->get_cvram());
277 #ifdef _FMR60
278                 bios->set_avram_ptr(memory->get_avram());
279 #else
280                 bios->set_kvram_ptr(memory->get_kvram());
281 #endif
282                 cpu->set_context_bios(bios);
283         }
284 #ifdef SINGLE_MODE_DMA
285         cpu->set_context_dma(dma);
286 #endif
287 #ifdef USE_DEBUGGER
288         cpu->set_context_debugger(new DEBUGGER(this, emu));
289 #endif
290         
291         // i/o bus
292         io->set_iomap_alias_rw(0x00, pic, I8259_ADDR_CHIP0 | 0);
293         io->set_iomap_alias_rw(0x02, pic, I8259_ADDR_CHIP0 | 1);
294         io->set_iomap_alias_rw(0x10, pic, I8259_ADDR_CHIP1 | 0);
295         io->set_iomap_alias_rw(0x12, pic, I8259_ADDR_CHIP1 | 1);
296         io->set_iomap_single_rw(0x20, memory);  // reset
297         io->set_iomap_single_r(0x21, memory);   // cpu misc
298         io->set_iomap_single_w(0x22, memory);   // dma
299         io->set_iomap_single_rw(0x24, memory);  // dma
300         io->set_iomap_single_r(0x26, timer);
301         io->set_iomap_single_r(0x27, timer);
302         io->set_iomap_single_r(0x30, memory);   // cpu id
303         io->set_iomap_alias_rw(0x40, pit0, 0);
304         io->set_iomap_alias_rw(0x42, pit0, 1);
305         io->set_iomap_alias_rw(0x44, pit0, 2);
306         io->set_iomap_alias_rw(0x46, pit0, 3);
307         io->set_iomap_alias_rw(0x50, pit1, 0);
308         io->set_iomap_alias_rw(0x52, pit1, 1);
309         io->set_iomap_alias_rw(0x54, pit1, 2);
310         io->set_iomap_alias_rw(0x56, pit1, 3);
311         io->set_iomap_single_rw(0x60, timer);
312         io->set_iomap_single_rw(0x70, timer);
313         io->set_iomap_single_w(0x80, timer);
314 #ifdef _FMRCARD
315         io->set_iomap_single_w(0x90, cmos);
316 #endif
317         io->set_iomap_range_rw(0xa0, 0xaf, dma);
318         io->set_iomap_alias_rw(0x200, fdc, 0);
319         io->set_iomap_alias_rw(0x202, fdc, 1);
320         io->set_iomap_alias_rw(0x204, fdc, 2);
321         io->set_iomap_alias_rw(0x206, fdc, 3);
322         io->set_iomap_single_rw(0x208, floppy);
323         io->set_iomap_single_rw(0x20c, floppy);
324         io->set_iomap_single_rw(0x400, memory); // crtc
325         io->set_iomap_single_rw(0x402, memory); // crtc
326         io->set_iomap_single_rw(0x404, memory); // crtc
327         io->set_iomap_single_w(0x408, memory);  // crtc
328         io->set_iomap_single_rw(0x40a, memory); // crtc
329         io->set_iomap_single_rw(0x40c, memory); // crtc
330         io->set_iomap_single_rw(0x40e, memory); // crtc
331         io->set_iomap_alias_rw(0x500, crtc, 0);
332         io->set_iomap_alias_rw(0x502, crtc, 1);
333 #ifdef _FMR60
334         io->set_iomap_range_rw(0x520, 0x523, acrtc);
335 #endif
336         io->set_iomap_single_rw(0x600, keyboard);
337         io->set_iomap_single_rw(0x602, keyboard);
338         io->set_iomap_single_rw(0x604, keyboard);
339         io->set_iomap_alias_rw(0xa00, sio, 0);
340         io->set_iomap_alias_rw(0xa02, sio, 1);
341 //      io->set_iomap_single_r(0xa04, serial);
342 //      io->set_iomap_single_r(0xa06, serial);
343 //      io->set_iomap_single_w(0xa08, serial);
344         io->set_iomap_single_rw(0xc30, scsi);
345         io->set_iomap_single_rw(0xc32, scsi);
346         io->set_iomap_range_rw(0x3000, 0x3fff, cmos);
347         io->set_iomap_range_rw(0xfd98, 0xfd9f, memory); // crtc
348         io->set_iomap_single_rw(0xfda0, memory);        // crtc
349         
350         // initialize all devices
351         for(DEVICE* device = first_device; device; device = device->next_device) {
352                 device->initialize();
353         }
354         if(bios) {
355                 for(int i = 0; i < MAX_DRIVE; i++) {
356                         bios->set_disk_handler(i, fdc->get_disk_handler(i));
357                 }
358         }
359 }
360
361 VM::~VM()
362 {
363         // delete all devices
364         for(DEVICE* device = first_device; device;) {
365                 DEVICE *next_device = device->next_device;
366                 device->release();
367                 delete device;
368                 device = next_device;
369         }
370 }
371
372 DEVICE* VM::get_device(int id)
373 {
374         for(DEVICE* device = first_device; device; device = device->next_device) {
375                 if(device->this_device_id == id) {
376                         return device;
377                 }
378         }
379         return NULL;
380 }
381
382 // ----------------------------------------------------------------------------
383 // drive virtual machine
384 // ----------------------------------------------------------------------------
385
386 void VM::reset()
387 {
388         // reset all devices
389         for(DEVICE* device = first_device; device; device = device->next_device) {
390                 device->reset();
391         }
392         // temporary fix...
393         for(DEVICE* device = first_device; device; device = device->next_device) {
394                 device->reset();
395         }
396 }
397
398 void VM::run()
399 {
400         event->drive();
401 }
402
403 // ----------------------------------------------------------------------------
404 // debugger
405 // ----------------------------------------------------------------------------
406
407 #ifdef USE_DEBUGGER
408 DEVICE *VM::get_cpu(int index)
409 {
410         if(index == 0) {
411                 return cpu;
412         }
413         return NULL;
414 }
415 #endif
416
417 // ----------------------------------------------------------------------------
418 // draw screen
419 // ----------------------------------------------------------------------------
420
421 void VM::draw_screen()
422 {
423         memory->draw_screen();
424 }
425
426 uint32_t VM::is_floppy_disk_accessed()
427 {
428         return fdc->read_signal(0);
429 }
430
431 // ----------------------------------------------------------------------------
432 // soud manager
433 // ----------------------------------------------------------------------------
434
435 void VM::initialize_sound(int rate, int samples)
436 {
437         // init sound manager
438         event->initialize_sound(rate, samples);
439         
440         // init sound gen
441         pcm->initialize_sound(rate, 8000);
442 }
443
444 uint16_t* VM::create_sound(int* extra_frames)
445 {
446         return event->create_sound(extra_frames);
447 }
448
449 int VM::get_sound_buffer_ptr()
450 {
451         return event->get_sound_buffer_ptr();
452 }
453
454 #ifdef USE_SOUND_VOLUME
455 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
456 {
457         if(ch == 0) {
458                 pcm->set_volume(0, decibel_l, decibel_r);
459         }
460 #if defined(USE_SOUND_FILES)
461         else if(ch == 1) {
462                 fdc->set_volume(0, decibel_l, decibel_r);
463         }
464 #endif
465 }
466 #endif
467
468 // ----------------------------------------------------------------------------
469 // notify key
470 // ----------------------------------------------------------------------------
471
472 void VM::key_down(int code, bool repeat)
473 {
474         keyboard->key_down(code);
475 }
476
477 void VM::key_up(int code)
478 {
479         keyboard->key_up(code);
480 }
481
482 // ----------------------------------------------------------------------------
483 // user interface
484 // ----------------------------------------------------------------------------
485
486 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
487 {
488         fdc->open_disk(drv, file_path, bank);
489         floppy->change_disk(drv);
490 }
491
492 void VM::close_floppy_disk(int drv)
493 {
494         fdc->close_disk(drv);
495 }
496
497 bool VM::is_floppy_disk_inserted(int drv)
498 {
499         return fdc->is_disk_inserted(drv);
500 }
501
502 void VM::is_floppy_disk_protected(int drv, bool value)
503 {
504         fdc->is_disk_protected(drv, value);
505 }
506
507 bool VM::is_floppy_disk_protected(int drv)
508 {
509         return fdc->is_disk_protected(drv);
510 }
511
512 bool VM::is_frame_skippable()
513 {
514         return event->is_frame_skippable();
515 }
516
517 void VM::update_config()
518 {
519         for(DEVICE* device = first_device; device; device = device->next_device) {
520                 device->update_config();
521         }
522 }
523
524 #define STATE_VERSION   3
525
526 void VM::save_state(FILEIO* state_fio)
527 {
528         state_fio->FputUint32(STATE_VERSION);
529         
530         for(DEVICE* device = first_device; device; device = device->next_device) {
531                 device->save_state(state_fio);
532         }
533 }
534
535 bool VM::load_state(FILEIO* state_fio)
536 {
537         if(state_fio->FgetUint32() != STATE_VERSION) {
538                 return false;
539         }
540         for(DEVICE* device = first_device; device; device = device->next_device) {
541                 if(!device->load_state(state_fio)) {
542                         return false;
543                 }
544         }
545         return true;
546 }
547