OSDN Git Service

[VM] TRY:Use namespace {VMNAME} to separate around VMs. This feature still apply...
[csp-qt/common_source_project-fm7.git] / source / src / vm / bubcom80 / bubcom80.cpp
1 /*
2         Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3
4         Author : Takeda.Toshiya
5         Date   : 2018.05.08-
6
7         [ virtual machine ]
8 */
9
10 #include "bubcom80.h"
11 #include "../../emu.h"
12 #include "../device.h"
13 #include "../event.h"
14
15 #include "../disk.h"
16 #include "../io.h"
17 #include "../ls393.h"
18 #include "../mb8877.h"
19 #include "../mc6850.h"
20 #include "../noise.h"
21 #include "../pcm1bit.h"
22 #include "../prnfile.h"
23 #include "../z80.h"
24 #include "../z80ctc.h"
25
26 #ifdef USE_DEBUGGER
27 #include "../debugger.h"
28 #endif
29
30 #include "bubblecasette.h"
31 #include "cmt.h"
32 #include "display.h"
33 #include "floppy.h"
34 #include "keyboard.h"
35 #include "membus.h"
36 #include "rtc.h"
37
38 // ----------------------------------------------------------------------------
39 // initialize
40 // ----------------------------------------------------------------------------
41
42 using BUBCOM80::BUBBLECASETTE;
43 using BUBCOM80::CMT;
44 using BUBCOM80::DISPLAY;
45 using BUBCOM80::FLOPPY;
46 using BUBCOM80::KEYBOARD;
47 using BUBCOM80::MEMBUS;
48 using BUBCOM80::RTC;
49
50 VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
51 {
52         // create devices
53         first_device = last_device = NULL;
54         dummy = new DEVICE(this, emu);  // must be 1st device
55         event = new EVENT(this, emu);   // must be 2nd device
56         
57         io = new IO(this, emu);
58         flipflop = new LS393(this, emu);
59         fdc = new MB8877(this, emu);
60         fdc->set_context_noise_seek(new NOISE(this, emu));
61         fdc->set_context_noise_head_down(new NOISE(this, emu));
62         fdc->set_context_noise_head_up(new NOISE(this, emu));
63 //      sio_rs = new MC6850(this, emu);
64         sio_cmt = new MC6850(this, emu);
65 //      sio_key = new MC6850(this, emu);
66         pcm = new PCM1BIT(this, emu);
67         cpu = new Z80(this, emu);
68         ctc = new Z80CTC(this, emu);
69         
70         bubblecasette[0] = new BUBBLECASETTE(this, emu);
71         bubblecasette[1] = new BUBBLECASETTE(this, emu);
72         cmt = new CMT(this, emu);
73         if(config.printer_type == 0) {
74                 printer = new PRNFILE(this, emu);
75 //      } else if(config.printer_type == 1) {
76 //              printer = new BC861(this, emu);
77         } else {
78                 printer = dummy;
79         }
80         display = new DISPLAY(this, emu);
81         floppy = new FLOPPY(this, emu);
82         keyboard = new KEYBOARD(this, emu);
83         membus = new MEMBUS(this, emu);
84         rtc = new RTC(this, emu);
85         
86         // set contexts
87         event->set_context_cpu(cpu);
88         event->set_context_sound(pcm);
89         event->set_context_sound(fdc->get_context_noise_seek());
90         event->set_context_sound(fdc->get_context_noise_head_down());
91         event->set_context_sound(fdc->get_context_noise_head_up());
92         
93         flipflop->set_context_1qa(pcm, SIG_PCM1BIT_SIGNAL, 1);
94         fdc->set_context_drq(display, SIG_DISPLAY_DMAC_CH0, 1);
95         sio_cmt->set_context_out(cmt, SIG_CMT_OUT);
96         ctc->set_context_zc0(flipflop, SIG_LS393_CLK, 1);
97         ctc->set_constant_clock(0, CPU_CLOCKS);
98         ctc->set_constant_clock(1, CPU_CLOCKS);
99         ctc->set_constant_clock(2, CPU_CLOCKS);
100         
101         cmt->set_context_sio(sio_cmt);
102         display->set_context_cpu(cpu);
103         display->set_context_cmt(cmt);
104         display->set_context_pcm(pcm);
105         display->set_context_prn(printer);
106         display->set_context_dmac_mem(membus);
107         display->set_context_dmac_ch0(fdc);
108         display->set_context_dmac_ch2(display); // crtc
109         floppy->set_context_fdc(floppy);
110         
111         // cpu bus
112         cpu->set_context_mem(membus);
113         cpu->set_context_io(io);
114         cpu->set_context_intr(ctc);
115 #ifdef USE_DEBUGGER
116         cpu->set_context_debugger(new DEBUGGER(this, emu));
117 #endif
118         
119         // z80 family daisy chain
120         ctc->set_context_intr(cpu, 0);
121         
122         // i/o bus
123         io->set_iomap_range_rw(0x0000, 0x0008, bubblecasette[0]);
124         io->set_iomap_range_rw(0x000c, 0x000d, membus);
125         io->set_iomap_range_rw(0x0010, 0x0011, display);
126         io->set_iomap_single_rw(0x0020, display);
127         io->set_iomap_range_rw(0x0030, 0x0031, sio_cmt);
128         io->set_iomap_range_rw(0x0040, 0x0043, ctc);
129         io->set_iomap_single_rw(0x0050, display);
130         io->set_iomap_range_rw(0x0060, 0x0068, display);
131         io->set_iomap_single_w(0x0080, membus);
132         io->set_iomap_range_r(0x0400, 0x047f, keyboard);
133         io->set_iomap_range_rw(0x0800, 0x0fff, display);
134         io->set_iomap_range_rw(0x3fd0, 0x3fd3, fdc);
135         io->set_iomap_single_w(0x3fd8, floppy);
136         io->set_iomap_range_rw(0x3fe0, 0x3fed, rtc);
137         io->set_iomap_single_rw(0x3ff0, display);
138         io->set_iomap_range_rw(0x4000, 0xffff, display);
139         
140         // initialize all devices
141 #if defined(__GIT_REPO_VERSION)
142         strncpy(_git_revision, __GIT_REPO_VERSION, sizeof(_git_revision) - 1);
143 #endif
144         for(DEVICE* device = first_device; device; device = device->next_device) {
145                 device->initialize();
146         }
147         
148         for(int i = 0; i < MAX_DRIVE; i++) {
149                 fdc->set_drive_type(i, DRIVE_TYPE_2HD); // 8inch 2D
150         }
151         fdc->write_signal(SIG_MB8877_MOTOR, 1, 1);
152 }
153
154 VM::~VM()
155 {
156         // delete all devices
157         for(DEVICE* device = first_device; device;) {
158                 DEVICE *next_device = device->next_device;
159                 device->release();
160                 delete device;
161                 device = next_device;
162         }
163 }
164
165 DEVICE* VM::get_device(int id)
166 {
167         for(DEVICE* device = first_device; device; device = device->next_device) {
168                 if(device->this_device_id == id) {
169                         return device;
170                 }
171         }
172         return NULL;
173 }
174
175 // ----------------------------------------------------------------------------
176 // drive virtual machine
177 // ----------------------------------------------------------------------------
178
179 void VM::reset()
180 {
181         // reset all devices
182         for(DEVICE* device = first_device; device; device = device->next_device) {
183                 device->reset();
184         }
185         ctc->write_io8(0, 0x07); // default frequency for beep
186         ctc->write_io8(0, 0xef);
187         pcm->write_signal(SIG_PCM1BIT_ON, 0, 0); // beep off
188 }
189
190 void VM::run()
191 {
192         event->drive();
193 }
194
195 double VM::get_frame_rate()
196 {
197         return event->get_frame_rate();
198 }
199
200 // ----------------------------------------------------------------------------
201 // debugger
202 // ----------------------------------------------------------------------------
203
204 #ifdef USE_DEBUGGER
205 DEVICE *VM::get_cpu(int index)
206 {
207         if(index == 0) {
208                 return cpu;
209         }
210         return NULL;
211 }
212 #endif
213
214 // ----------------------------------------------------------------------------
215 // draw screen
216 // ----------------------------------------------------------------------------
217
218 void VM::draw_screen()
219 {
220         display->draw_screen();
221 }
222
223 // ----------------------------------------------------------------------------
224 // soud manager
225 // ----------------------------------------------------------------------------
226
227 void VM::initialize_sound(int rate, int samples)
228 {
229         // init sound manager
230         event->initialize_sound(rate, samples);
231         
232         // init sound gen
233         pcm->initialize_sound(rate, 8000);
234 }
235
236 uint16_t* VM::create_sound(int* extra_frames)
237 {
238         return event->create_sound(extra_frames);
239 }
240
241 int VM::get_sound_buffer_ptr()
242 {
243         return event->get_sound_buffer_ptr();
244 }
245
246 #ifdef USE_SOUND_VOLUME
247 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
248 {
249         if(ch == 0) {
250                 pcm->set_volume(0, decibel_l, decibel_r);
251         } else if(ch == 1) {
252                 fdc->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
253                 fdc->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
254                 fdc->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
255         }
256 }
257 #endif
258
259 // ----------------------------------------------------------------------------
260 // user interface
261 // ----------------------------------------------------------------------------
262
263 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
264 {
265         fdc->open_disk(drv, file_path, bank);
266 }
267
268 void VM::close_floppy_disk(int drv)
269 {
270         fdc->close_disk(drv);
271 }
272
273 bool VM::is_floppy_disk_inserted(int drv)
274 {
275         return fdc->is_disk_inserted(drv);
276 }
277
278 void VM::is_floppy_disk_protected(int drv, bool value)
279 {
280         fdc->is_disk_protected(drv, value);
281 }
282
283 bool VM::is_floppy_disk_protected(int drv)
284 {
285         return fdc->is_disk_protected(drv);
286 }
287
288 uint32_t VM::is_floppy_disk_accessed()
289 {
290         return fdc->read_signal(0);
291 }
292
293 void VM::play_tape(int drv, const _TCHAR* file_path)
294 {
295         cmt->play_tape(file_path);
296 }
297
298 void VM::rec_tape(int drv, const _TCHAR* file_path)
299 {
300         cmt->rec_tape(file_path);
301 }
302
303 void VM::close_tape(int drv)
304 {
305         cmt->close_tape();
306 }
307
308 bool VM::is_tape_inserted(int drv)
309 {
310         return cmt->is_tape_inserted();
311 }
312
313 void VM::open_bubble_casette(int drv, const _TCHAR *path, int bank)
314 {
315         if(drv < 2 && bubblecasette[drv] != NULL) {
316                 bubblecasette[drv]->open((_TCHAR *)path, bank);
317         }
318 }
319
320 void VM::close_bubble_casette(int drv)
321 {
322         if(drv < 2 && bubblecasette[drv] != NULL) {
323                 bubblecasette[drv]->close();
324         }
325 }
326
327 bool VM::is_bubble_casette_inserted(int drv)
328 {
329         if(drv < 2 && bubblecasette[drv] != NULL) {
330                 return bubblecasette[drv]->is_bubble_inserted();
331         }
332         return false;
333 }
334
335 bool VM::is_bubble_casette_protected(int drv)
336 {
337         if(drv < 2 && bubblecasette[drv] != NULL) {
338                 return bubblecasette[drv]->is_bubble_protected();
339         }
340         return false;
341 }
342
343 void VM::is_bubble_casette_protected(int drv, bool flag)
344 {
345         if(drv < 2 && bubblecasette[drv] != NULL) {
346                 bubblecasette[drv]->set_bubble_protect(flag);
347         }
348 }
349
350 bool VM::is_frame_skippable()
351 {
352         return event->is_frame_skippable();
353 }
354
355 void VM::update_config()
356 {
357         for(DEVICE* device = first_device; device; device = device->next_device) {
358                 device->update_config();
359         }
360 }
361
362 #define STATE_VERSION   1
363
364 bool VM::process_state(FILEIO* state_fio, bool loading)
365 {
366         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
367                 return false;
368         }
369         for(DEVICE* device = first_device; device; device = device->next_device) {
370                 // Note: typeid(foo).name is fixed by recent ABI.Not dec 6.
371                 // const char *name = typeid(*device).name();
372                 //       But, using get_device_name() instead of typeid(foo).name() 20181008 K.O
373                 const char *name = device->get_device_name();
374                 int len = strlen(name);
375                 
376                 if(!state_fio->StateCheckInt32(len)) {
377                         if(loading) {
378                                 printf("Class name len Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
379                         }
380                         return false;
381                 }
382                 if(!state_fio->StateCheckBuffer(name, len, 1)) {
383                         if(loading) {
384                                 printf("Class name Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
385                         }
386                         return false;
387                 }
388                 if(!device->process_state(state_fio, loading)) {
389                         if(loading) {
390                                 printf("Data loading Error: DEVID=%d\n", device->this_device_id);
391                         }
392                         return false;
393                 }
394         }
395         // Machine specified.
396         if(loading) {
397                 update_config();
398         }
399         //mainio->restore_opn();
400         return true;
401 }