OSDN Git Service

[BUILD] Set SOVERSION and GIT hash automatically.
[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 #if defined(__GIT_REPO_VERSION)
352         strncpy(_git_revision, __GIT_REPO_VERSION, sizeof(_git_revision) - 1);
353 #endif
354         for(DEVICE* device = first_device; device; device = device->next_device) {
355                 device->initialize();
356         }
357         if(bios) {
358                 for(int i = 0; i < MAX_DRIVE; i++) {
359                         bios->set_disk_handler(i, fdc->get_disk_handler(i));
360                 }
361         }
362 }
363
364 VM::~VM()
365 {
366         // delete all devices
367         for(DEVICE* device = first_device; device;) {
368                 DEVICE *next_device = device->next_device;
369                 device->release();
370                 delete device;
371                 device = next_device;
372         }
373 }
374
375 DEVICE* VM::get_device(int id)
376 {
377         for(DEVICE* device = first_device; device; device = device->next_device) {
378                 if(device->this_device_id == id) {
379                         return device;
380                 }
381         }
382         return NULL;
383 }
384
385 // ----------------------------------------------------------------------------
386 // drive virtual machine
387 // ----------------------------------------------------------------------------
388
389 void VM::reset()
390 {
391         // reset all devices
392         for(DEVICE* device = first_device; device; device = device->next_device) {
393                 device->reset();
394         }
395         // temporary fix...
396         for(DEVICE* device = first_device; device; device = device->next_device) {
397                 device->reset();
398         }
399 }
400
401 void VM::run()
402 {
403         event->drive();
404 }
405
406 // ----------------------------------------------------------------------------
407 // debugger
408 // ----------------------------------------------------------------------------
409
410 #ifdef USE_DEBUGGER
411 DEVICE *VM::get_cpu(int index)
412 {
413         if(index == 0) {
414                 return cpu;
415         }
416         return NULL;
417 }
418 #endif
419
420 // ----------------------------------------------------------------------------
421 // draw screen
422 // ----------------------------------------------------------------------------
423
424 void VM::draw_screen()
425 {
426         memory->draw_screen();
427 }
428
429 uint32_t VM::is_floppy_disk_accessed()
430 {
431         return fdc->read_signal(0);
432 }
433
434 // ----------------------------------------------------------------------------
435 // soud manager
436 // ----------------------------------------------------------------------------
437
438 void VM::initialize_sound(int rate, int samples)
439 {
440         // init sound manager
441         event->initialize_sound(rate, samples);
442         
443         // init sound gen
444         pcm->initialize_sound(rate, 8000);
445 }
446
447 uint16_t* VM::create_sound(int* extra_frames)
448 {
449         return event->create_sound(extra_frames);
450 }
451
452 int VM::get_sound_buffer_ptr()
453 {
454         return event->get_sound_buffer_ptr();
455 }
456
457 #ifdef USE_SOUND_VOLUME
458 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
459 {
460         if(ch == 0) {
461                 pcm->set_volume(0, decibel_l, decibel_r);
462         }
463 #if defined(USE_SOUND_FILES)
464         else if(ch == 1) {
465                 fdc->set_volume(0, decibel_l, decibel_r);
466         }
467 #endif
468 }
469 #endif
470
471 // ----------------------------------------------------------------------------
472 // notify key
473 // ----------------------------------------------------------------------------
474
475 void VM::key_down(int code, bool repeat)
476 {
477         keyboard->key_down(code);
478 }
479
480 void VM::key_up(int code)
481 {
482         keyboard->key_up(code);
483 }
484
485 // ----------------------------------------------------------------------------
486 // user interface
487 // ----------------------------------------------------------------------------
488
489 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
490 {
491         fdc->open_disk(drv, file_path, bank);
492         floppy->change_disk(drv);
493 }
494
495 void VM::close_floppy_disk(int drv)
496 {
497         fdc->close_disk(drv);
498 }
499
500 bool VM::is_floppy_disk_inserted(int drv)
501 {
502         return fdc->is_disk_inserted(drv);
503 }
504
505 void VM::is_floppy_disk_protected(int drv, bool value)
506 {
507         fdc->is_disk_protected(drv, value);
508 }
509
510 bool VM::is_floppy_disk_protected(int drv)
511 {
512         return fdc->is_disk_protected(drv);
513 }
514
515 bool VM::is_frame_skippable()
516 {
517         return event->is_frame_skippable();
518 }
519
520 void VM::update_config()
521 {
522         for(DEVICE* device = first_device; device; device = device->next_device) {
523                 device->update_config();
524         }
525 }
526
527 #define STATE_VERSION   3
528
529 void VM::save_state(FILEIO* state_fio)
530 {
531         state_fio->FputUint32(STATE_VERSION);
532         
533         for(DEVICE* device = first_device; device; device = device->next_device) {
534                 device->save_state(state_fio);
535         }
536 }
537
538 bool VM::load_state(FILEIO* state_fio)
539 {
540         if(state_fio->FgetUint32() != STATE_VERSION) {
541                 return false;
542         }
543         for(DEVICE* device = first_device; device; device = device->next_device) {
544                 if(!device->load_state(state_fio)) {
545                         return false;
546                 }
547         }
548         return true;
549 }
550