OSDN Git Service

[BUILD] Set SOVERSION and GIT hash automatically.
[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 #if defined(__GIT_REPO_VERSION)
192         strncpy(_git_revision, __GIT_REPO_VERSION, sizeof(_git_revision) - 1);
193 #endif
194         for(DEVICE* device = first_device; device; device = device->next_device) {
195                 device->initialize();
196         }
197         decl_state();
198         
199         for(int i = 0; i < 4; i++) {
200                 fdc_2hd->set_drive_type(i, DRIVE_TYPE_2HD);
201                 fdc_2d->set_drive_type(i, DRIVE_TYPE_2D);
202         }
203         fdc_2hd->get_disk_handler(0)->drive_num = 0;
204         fdc_2hd->get_disk_handler(1)->drive_num = 1;
205         fdc_2d->get_disk_handler(0)->drive_num = 2;
206         fdc_2d->get_disk_handler(1)->drive_num = 3;
207 }
208
209 VM::~VM()
210 {
211         // delete all devices
212         for(DEVICE* device = first_device; device;) {
213                 DEVICE *next_device = device->next_device;
214                 device->release();
215                 delete device;
216                 device = next_device;
217         }
218 }
219
220 DEVICE* VM::get_device(int id)
221 {
222         for(DEVICE* device = first_device; device; device = device->next_device) {
223                 if(device->this_device_id == id) {
224                         return device;
225                 }
226         }
227         return NULL;
228 }
229
230 // ----------------------------------------------------------------------------
231 // drive virtual machine
232 // ----------------------------------------------------------------------------
233
234 void VM::reset()
235 {
236         // reset all devices
237         for(DEVICE* device = first_device; device; device = device->next_device) {
238                 device->reset();
239         }
240
241         emu->out_debug_log(_T("----- RESET -----\n"));
242
243 }
244
245 void VM::run()
246 {
247         event->drive();
248 }
249
250 // ----------------------------------------------------------------------------
251 // debugger
252 // ----------------------------------------------------------------------------
253
254 #ifdef USE_DEBUGGER
255 DEVICE *VM::get_cpu(int index)
256 {
257         if(index == 0) {
258                 return cpu;
259         } else if(index == 1) {
260                 return subcpu;
261         }
262         return NULL;
263 }
264 #endif
265
266 // ----------------------------------------------------------------------------
267 // draw screen
268 // ----------------------------------------------------------------------------
269
270 void VM::draw_screen()
271 {
272         subbus->draw_screen();
273 }
274
275 // ----------------------------------------------------------------------------
276 // soud manager
277 // ----------------------------------------------------------------------------
278
279 void VM::initialize_sound(int rate, int samples)
280 {
281         // init sound manager
282         event->initialize_sound(rate, samples);
283         
284         // init sound gen
285         pcm->initialize_sound(rate, 8000);
286 }
287
288 uint16_t* VM::create_sound(int* extra_frames)
289 {
290         return event->create_sound(extra_frames);
291 }
292
293 int VM::get_sound_buffer_ptr()
294 {
295         return event->get_sound_buffer_ptr();
296 }
297
298 #ifdef USE_SOUND_VOLUME
299 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
300 {
301         if(ch == 0) {
302                 pcm->set_volume(0, decibel_l, decibel_r);
303         } else if(ch == 1) {
304                 fdc_2hd->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
305                 fdc_2hd->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
306                 fdc_2hd->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
307                 fdc_2d->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
308                 fdc_2d->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
309                 fdc_2d->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
310         }
311 }
312 #endif
313
314 // ----------------------------------------------------------------------------
315 // notify key
316 // ----------------------------------------------------------------------------
317
318 void VM::key_down(int code, bool repeat)
319 {
320         keyboard->key_down(code);
321 }
322
323 void VM::key_up(int code)
324 {
325         keyboard->key_up(code);
326 }
327
328 // ----------------------------------------------------------------------------
329 // user interface
330 // ----------------------------------------------------------------------------
331
332 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
333 {
334         if(drv < 2) {
335                 fdc_2hd->open_disk(drv, file_path, bank);
336         } else if(drv < 4) {
337                 fdc_2d->open_disk(drv - 2, file_path, bank);
338         }
339 }
340
341 void VM::close_floppy_disk(int drv)
342 {
343         if(drv < 2) {
344                 fdc_2hd->close_disk(drv);
345         } else if(drv < 4) {
346                 fdc_2d->close_disk(drv - 2);
347         }
348 }
349
350 bool VM::is_floppy_disk_inserted(int drv)
351 {
352         if(drv < 2) {
353                 return fdc_2hd->is_disk_inserted(drv);
354         } else if(drv < 4) {
355                 return fdc_2d->is_disk_inserted(drv - 2);
356         }
357         return false;
358 }
359
360 void VM::is_floppy_disk_protected(int drv, bool value)
361 {
362         if(drv < 2) {
363                 fdc_2hd->is_disk_protected(drv, value);
364         } else if(drv < 4) {
365                 fdc_2d->is_disk_protected(drv - 2, value);
366         }
367 }
368
369 bool VM::is_floppy_disk_protected(int drv)
370 {
371         if(drv < 2) {
372                 return fdc_2hd->is_disk_protected(drv);
373         } else if(drv < 4) {
374                 return fdc_2d->is_disk_protected(drv - 2);
375         }
376         return false;
377 }
378
379 uint32_t VM::is_floppy_disk_accessed()
380 {
381         return (fdc_2hd->read_signal(0) & 3) | ((fdc_2d->read_signal(0) & 3) << 2);
382 }
383
384 bool VM::is_frame_skippable()
385 {
386         return event->is_frame_skippable();
387 }
388
389 void VM::update_config()
390 {
391         for(DEVICE* device = first_device; device; device = device->next_device) {
392                 device->update_config();
393         }
394 }
395
396 #define STATE_VERSION   1
397
398 #include "../../statesub.h"
399 #include "../../qt/gui/csp_logger.h"
400 extern CSP_Logger DLL_PREFIX_I *csp_logger;
401
402 void VM::decl_state(void)
403 {
404         state_entry = new csp_state_utils(STATE_VERSION, 0, (_TCHAR *)(_T("CSP::FM16BETA_HEAD")), csp_logger);
405         for(DEVICE* device = first_device; device; device = device->next_device) {
406                 device->decl_state();
407         }
408 }
409
410 void VM::save_state(FILEIO* state_fio)
411 {
412         //state_fio->FputUint32(STATE_VERSION);
413         
414         if(state_entry != NULL) {
415                 state_entry->save_state(state_fio);
416         }
417         for(DEVICE* device = first_device; device; device = device->next_device) {
418                 device->save_state(state_fio);
419         }
420 }
421
422 bool VM::load_state(FILEIO* state_fio)
423 {
424         //if(state_fio->FgetUint32() != STATE_VERSION) {
425         //      return false;
426         //}
427         bool mb = false;
428         if(state_entry != NULL) {
429                 mb = state_entry->load_state(state_fio);
430         }
431         if(!mb) {
432                 emu->out_debug_log("INFO: HEADER DATA ERROR");
433                 return false;
434         }
435         for(DEVICE* device = first_device; device; device = device->next_device) {
436                 if(!device->load_state(state_fio)) {
437                         return false;
438                 }
439         }
440         return true;
441 }
442