OSDN Git Service

1b1ea106f52332a74913fb321ee2e969e5f78281
[csp-qt/common_source_project-fm7.git] / source / src / vm / fm16beta / fm16beta.cpp
1 /*
2         FUJITSU FM16beta Emulator 'eFM16beta'
3
4         Author : Takeda.Toshiya
5         Date   : 2017.12.28-
6
7         [ virtual machine ]
8 */
9
10 #include "fm16beta.h"
11 #include "../../emu.h"
12 #include "../device.h"
13 #include "../event.h"
14
15 #include "../disk.h"
16 #include "../hd46505.h"
17 #include "../i8237.h"
18 #include "../i8251.h"
19 #include "../i8259.h"
20 #include "../i286.h"
21 #include "../io.h"
22 #include "../mb8877.h"
23 #include "../mc6809.h"
24 #include "../mc6840.h"
25 #include "../msm58321.h"
26 #include "../noise.h"
27 #include "../pcm1bit.h"
28
29 #ifdef USE_DEBUGGER
30 #include "../debugger.h"
31 #endif
32
33 #include "cmos.h"
34 #include "keyboard.h"
35 #include "mainbus.h"
36 #include "sub.h"
37
38 // ----------------------------------------------------------------------------
39 // initialize
40 // ----------------------------------------------------------------------------
41
42 VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
43 {
44         // create devices
45         first_device = last_device = NULL;
46         dummy = new DEVICE(this, emu);  // must be 1st device
47         event = new EVENT(this, emu);   // must be 2nd device
48         
49         crtc = new HD46505(this, emu);
50         cpu = new I286(this, emu);
51         io = new IO(this, emu);
52         dma = new I8237(this, emu);
53         sio = new I8251(this, emu);
54         pic = new I8259(this, emu);
55         fdc_2hd = new MB8877(this, emu);
56         fdc_2hd->set_context_noise_seek(new NOISE(this, emu));
57         fdc_2hd->set_context_noise_head_down(new NOISE(this, emu));
58         fdc_2hd->set_context_noise_head_up(new NOISE(this, emu));
59         fdc_2d = new MB8877(this, emu);
60         fdc_2d->set_context_noise_seek(new NOISE(this, emu));
61         fdc_2d->set_context_noise_head_down(new NOISE(this, emu));
62         fdc_2d->set_context_noise_head_up(new NOISE(this, emu));
63         subcpu = new MC6809(this, emu);
64         ptm = new MC6840(this, emu);
65         rtc = new MSM58321(this, emu);
66         pcm = new PCM1BIT(this, emu);
67
68         cmos = new CMOS(this, emu);
69         keyboard = new KEYBOARD(this, emu);
70         mainbus = new MAINBUS(this, emu);
71         
72
73         
74         
75         
76         subbus = new SUB(this, emu);
77         
78         // set contexts
79         event->set_context_cpu(cpu, 8000000);
80         event->set_context_cpu(subcpu, 2000000);
81         event->set_context_sound(pcm);
82         event->set_context_sound(fdc_2hd->get_context_noise_seek());
83         event->set_context_sound(fdc_2hd->get_context_noise_head_down());
84         event->set_context_sound(fdc_2hd->get_context_noise_head_up());
85         event->set_context_sound(fdc_2d->get_context_noise_seek());
86         event->set_context_sound(fdc_2d->get_context_noise_head_down());
87         event->set_context_sound(fdc_2d->get_context_noise_head_up());
88         
89         keyboard->set_context_main(mainbus);
90 #ifdef HAS_I286
91         mainbus->set_context_cpu(cpu);
92 #endif
93         mainbus->set_context_dma(dma);
94         mainbus->set_context_fdc_2hd(fdc_2hd);
95         mainbus->set_context_fdc_2d(fdc_2d);
96         mainbus->set_context_pic(pic);
97         mainbus->set_context_pcm(pcm);
98         mainbus->set_context_rtc(rtc);
99         mainbus->set_context_sub(subbus);
100         mainbus->set_context_keyboard(keyboard);
101
102         dma->set_context_memory(mainbus);
103         dma->set_context_ch0(fdc_2d);
104         dma->set_context_ch1(fdc_2hd);
105
106         sio->set_context_txrdy(mainbus, SIG_MAIN_IRQ0_TX, 1);
107         sio->set_context_rxrdy(mainbus, SIG_MAIN_IRQ0_RX, 1);
108         sio->set_context_syndet(mainbus, SIG_MAIN_IRQ0_SYN, 1);
109
110         fdc_2hd->set_context_irq(mainbus, SIG_MAIN_IRQ5, 1);
111         fdc_2hd->set_context_drq(mainbus, SIG_MAIN_DRQ_2HD, 1);
112         fdc_2hd->set_context_drq(dma, SIG_I8237_CH1, 1);
113
114         fdc_2d->set_context_irq(mainbus, SIG_MAIN_IRQ4, 1);
115         fdc_2d->set_context_drq(mainbus, SIG_MAIN_DRQ_2D, 1);
116         fdc_2d->set_context_drq(dma, SIG_I8237_CH0, 1);
117
118         ptm->set_context_ch0(pcm, SIG_PCM1BIT_SIGNAL, 1);
119         ptm->set_context_irq(mainbus, SIG_MAIN_IRQ8, 1);
120         ptm->set_internal_clock(19200); // temporary
121         ptm->set_external_clock(0, 19200);
122         ptm->set_external_clock(1, 19200);
123         ptm->set_external_clock(2, 19200);
124
125         rtc->set_context_data(mainbus, SIG_MAIN_RTC_DATA, 0x0f, 0);
126         rtc->set_context_busy(mainbus, SIG_MAIN_RTC_BUSY, 0x80);
127
128         crtc->set_context_disp(subbus, SIG_SUB_DISP, 1);
129         crtc->set_context_vsync(subbus, SIG_SUB_VSYNC, 1);
130         
131         subbus->addr_max = 0x10000;
132         subbus->bank_size = 0x80;
133         subbus->set_context_crtc(crtc);
134         subbus->set_chregs_ptr(crtc->get_regs());
135         subbus->set_context_pcm(pcm);
136         subbus->set_context_main(mainbus);
137         subbus->set_context_subcpu(subcpu);
138         subbus->set_context_keyboard(keyboard);
139
140         // cpu bus
141         cpu->set_context_mem(mainbus);
142         cpu->set_context_io(io);
143         cpu->set_context_intr(pic);
144 #ifdef SINGLE_MODE_DMA
145         cpu->set_context_dma(dma);
146 #endif
147         subcpu->set_context_mem(subbus);
148 #ifdef USE_DEBUGGER
149         cpu->set_context_debugger(new DEBUGGER(this, emu));
150         subcpu->set_context_debugger(new DEBUGGER(this, emu));
151 #endif
152         
153         
154         // i/o bus
155         io->set_iomap_range_rw(0x0000, 0x0001, pic);
156         io->set_iomap_range_rw(0x0010, 0x001f, dma);
157         io->set_iomap_range_w(0x0020, 0x0023, mainbus); // dma bank regs
158 #ifdef HAS_I286
159         io->set_iomap_single_rw(0x0060, mainbus);               // reset
160 #endif
161
162         io->set_iomap_range_rw(0xf000, 0xf7ff, cmos);
163         io->set_iomap_range_rw(0xfc80, 0xfcff, subbus); // shared ram
164
165         io->set_iomap_range_r(0xfd00, 0xfd01, keyboard);
166         io->set_iomap_range_rw(0xfd02, 0xfd05, mainbus);
167
168         io->set_iomap_range_rw(0xfd06, 0xfd07, sio);
169
170         io->set_iomap_single_rw(0xfd0f, mainbus);
171
172         io->set_iomap_range_rw(0xfd10, 0xfd11, mainbus);
173
174         io->set_iomap_range_rw(0xfd18, 0xfd1b, fdc_2d);
175         io->set_iomap_range_rw(0xfd1c, 0xfd1f, mainbus);
176
177         io->set_iomap_range_r(0xfd20, 0xfd22, subbus);  // attention
178
179         io->set_iomap_single_rw(0xfd2c, mainbus);
180
181         io->set_iomap_range_rw(0xfd30, 0xfd33, fdc_2hd);
182         io->set_iomap_range_rw(0xfd34, 0xfd37, mainbus);
183
184         io->set_iomap_range_rw(0xfd38, 0xfd3f, ptm);
185         io->set_iomap_range_rw(0xfd98, 0xfd9f, subbus);
186         io->set_iomap_single_w(0xfda0, subbus);
187         io->set_iomap_single_r(0xfda0, mainbus);
188
189         
190         // initialize all devices
191         for(DEVICE* device = first_device; device; device = device->next_device) {
192                 device->initialize();
193         }
194         decl_state();
195         
196         for(int i = 0; i < 4; i++) {
197                 fdc_2hd->set_drive_type(i, DRIVE_TYPE_2HD);
198                 fdc_2d->set_drive_type(i, DRIVE_TYPE_2D);
199         }
200         fdc_2hd->get_disk_handler(0)->drive_num = 0;
201         fdc_2hd->get_disk_handler(1)->drive_num = 1;
202         fdc_2d->get_disk_handler(0)->drive_num = 2;
203         fdc_2d->get_disk_handler(1)->drive_num = 3;
204 }
205
206 VM::~VM()
207 {
208         // delete all devices
209         for(DEVICE* device = first_device; device;) {
210                 DEVICE *next_device = device->next_device;
211                 device->release();
212                 delete device;
213                 device = next_device;
214         }
215 }
216
217 DEVICE* VM::get_device(int id)
218 {
219         for(DEVICE* device = first_device; device; device = device->next_device) {
220                 if(device->this_device_id == id) {
221                         return device;
222                 }
223         }
224         return NULL;
225 }
226
227 // ----------------------------------------------------------------------------
228 // drive virtual machine
229 // ----------------------------------------------------------------------------
230
231 void VM::reset()
232 {
233         // reset all devices
234         for(DEVICE* device = first_device; device; device = device->next_device) {
235                 device->reset();
236         }
237
238         emu->out_debug_log(_T("----- RESET -----\n"));
239
240 }
241
242 void VM::run()
243 {
244         event->drive();
245 }
246
247 // ----------------------------------------------------------------------------
248 // debugger
249 // ----------------------------------------------------------------------------
250
251 #ifdef USE_DEBUGGER
252 DEVICE *VM::get_cpu(int index)
253 {
254         if(index == 0) {
255                 return cpu;
256         } else if(index == 1) {
257                 return subcpu;
258         }
259         return NULL;
260 }
261 #endif
262
263 // ----------------------------------------------------------------------------
264 // draw screen
265 // ----------------------------------------------------------------------------
266
267 void VM::draw_screen()
268 {
269         subbus->draw_screen();
270 }
271
272 // ----------------------------------------------------------------------------
273 // soud manager
274 // ----------------------------------------------------------------------------
275
276 void VM::initialize_sound(int rate, int samples)
277 {
278         // init sound manager
279         event->initialize_sound(rate, samples);
280         
281         // init sound gen
282         pcm->initialize_sound(rate, 8000);
283 }
284
285 uint16_t* VM::create_sound(int* extra_frames)
286 {
287         return event->create_sound(extra_frames);
288 }
289
290 int VM::get_sound_buffer_ptr()
291 {
292         return event->get_sound_buffer_ptr();
293 }
294
295 #ifdef USE_SOUND_VOLUME
296 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
297 {
298         if(ch == 0) {
299                 pcm->set_volume(0, decibel_l, decibel_r);
300         } else if(ch == 1) {
301                 fdc_2hd->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
302                 fdc_2hd->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
303                 fdc_2hd->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
304                 fdc_2d->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
305                 fdc_2d->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
306                 fdc_2d->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
307         }
308 }
309 #endif
310
311 // ----------------------------------------------------------------------------
312 // notify key
313 // ----------------------------------------------------------------------------
314
315 void VM::key_down(int code, bool repeat)
316 {
317         keyboard->key_down(code);
318 }
319
320 void VM::key_up(int code)
321 {
322         keyboard->key_up(code);
323 }
324
325 // ----------------------------------------------------------------------------
326 // user interface
327 // ----------------------------------------------------------------------------
328
329 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
330 {
331         if(drv < 2) {
332                 fdc_2hd->open_disk(drv, file_path, bank);
333         } else if(drv < 4) {
334                 fdc_2d->open_disk(drv - 2, file_path, bank);
335         }
336 }
337
338 void VM::close_floppy_disk(int drv)
339 {
340         if(drv < 2) {
341                 fdc_2hd->close_disk(drv);
342         } else if(drv < 4) {
343                 fdc_2d->close_disk(drv - 2);
344         }
345 }
346
347 bool VM::is_floppy_disk_inserted(int drv)
348 {
349         if(drv < 2) {
350                 return fdc_2hd->is_disk_inserted(drv);
351         } else if(drv < 4) {
352                 return fdc_2d->is_disk_inserted(drv - 2);
353         }
354         return false;
355 }
356
357 void VM::is_floppy_disk_protected(int drv, bool value)
358 {
359         if(drv < 2) {
360                 fdc_2hd->is_disk_protected(drv, value);
361         } else if(drv < 4) {
362                 fdc_2d->is_disk_protected(drv - 2, value);
363         }
364 }
365
366 bool VM::is_floppy_disk_protected(int drv)
367 {
368         if(drv < 2) {
369                 return fdc_2hd->is_disk_protected(drv);
370         } else if(drv < 4) {
371                 return fdc_2d->is_disk_protected(drv - 2);
372         }
373         return false;
374 }
375
376 uint32_t VM::is_floppy_disk_accessed()
377 {
378         return (fdc_2hd->read_signal(0) & 3) | ((fdc_2d->read_signal(0) & 3) << 2);
379 }
380
381 bool VM::is_frame_skippable()
382 {
383         return event->is_frame_skippable();
384 }
385
386 void VM::update_config()
387 {
388         for(DEVICE* device = first_device; device; device = device->next_device) {
389                 device->update_config();
390         }
391 }
392
393 #define STATE_VERSION   1
394
395 #include "../../statesub.h"
396 #include "../../qt/gui/csp_logger.h"
397 extern CSP_Logger DLL_PREFIX_I *csp_logger;
398
399 void VM::decl_state(void)
400 {
401         state_entry = new csp_state_utils(STATE_VERSION, 0, (_TCHAR *)(_T("CSP::FM16BETA_HEAD")), csp_logger);
402         for(DEVICE* device = first_device; device; device = device->next_device) {
403                 device->decl_state();
404         }
405 }
406
407 void VM::save_state(FILEIO* state_fio)
408 {
409         //state_fio->FputUint32(STATE_VERSION);
410         
411         if(state_entry != NULL) {
412                 state_entry->save_state(state_fio);
413         }
414         for(DEVICE* device = first_device; device; device = device->next_device) {
415                 device->save_state(state_fio);
416         }
417 }
418
419 bool VM::load_state(FILEIO* state_fio)
420 {
421         //if(state_fio->FgetUint32() != STATE_VERSION) {
422         //      return false;
423         //}
424         bool mb = false;
425         if(state_entry != NULL) {
426                 mb = state_entry->load_state(state_fio);
427         }
428         if(!mb) {
429                 emu->out_debug_log("INFO: HEADER DATA ERROR");
430                 return false;
431         }
432         for(DEVICE* device = first_device; device; device = device->next_device) {
433                 if(!device->load_state(state_fio)) {
434                         return false;
435                 }
436         }
437         return true;
438 }
439