OSDN Git Service

[VM][COMMON_VM] Include IO:: class to common_vm.
[csp-qt/common_source_project-fm7.git] / source / src / vm / cefucom21 / cefucom21.cpp
1 /*
2         Hino Electronics CEFUCOM-21 Emulator 'eCEFUCOM-21'
3
4         Author : Takeda.Toshiya
5         Date   : 2019.03.28-
6
7         [ virtual machine ]
8 */
9
10 #include "cefucom21.h"
11 #include "../../emu.h"
12 #include "../device.h"
13 #include "../event.h"
14
15 #include "../ay_3_891x.h"
16 #include "../datarec.h"
17 #include "../i8255.h"
18 #include "../io.h"
19 #include "../mc6847.h"
20 #include "../noise.h"
21 #include "../memory.h"
22 #include "../not.h"
23 #include "../rp5c01.h"
24 #include "../z80.h"
25 #include "../z80ctc.h"
26 #include "../z80pio.h"
27
28 #ifdef USE_DEBUGGER
29 #include "../debugger.h"
30 #endif
31
32 #include "mcu.h"
33 #include "pcu.h"
34
35 //#define BOOT_BASIC
36
37 // ----------------------------------------------------------------------------
38 // initialize
39 // ----------------------------------------------------------------------------
40
41 VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
42 {
43         // create devices
44         first_device = last_device = NULL;
45         dummy = new DEVICE(this, emu);  // must be 1st device
46         event = new EVENT(this, emu);   // must be 2nd device
47         
48         mcu_psg = new AY_3_891X(this, emu);
49 #ifdef USE_DEBUGGER
50         mcu_psg->set_context_debugger(new DEBUGGER(this, emu));
51 #endif
52         mcu_drec = new DATAREC(this, emu);
53         mcu_drec->set_context_noise_play(new NOISE(this, emu));
54         mcu_drec->set_context_noise_stop(new NOISE(this, emu));
55         mcu_drec->set_context_noise_fast(new NOISE(this, emu));
56         mcu_io = new IO(this, emu);
57         mcu_vdp = new MC6847(this, emu);
58         mcu_mem = new MEMORY(this, emu);
59         
60         mcu_not = new NOT(this, emu);
61         mcu_cpu = new Z80(this, emu);
62         mcu_pio = new Z80PIO(this, emu);
63         mcu = new MCU(this, emu);
64         
65         pcu_pio1 = new I8255(this, emu);
66         pcu_pio2 = new I8255(this, emu);
67         pcu_pio3 = new I8255(this, emu);
68         pcu_io = new IO(this, emu);
69         pcu_mem = new MEMORY(this, emu);
70         
71         pcu_rtc = new RP5C01(this, emu);
72         pcu_cpu = new Z80(this, emu);
73         pcu_ctc1 = new Z80CTC(this, emu);
74         pcu_ctc2 = new Z80CTC(this, emu);
75         pcu_pio = new Z80PIO(this, emu);
76         pcu = new PCU(this, emu);
77         
78         // set contexts
79         event->set_context_cpu(mcu_cpu);
80         event->set_context_cpu(pcu_cpu);
81         event->set_context_sound(mcu_psg);
82         event->set_context_sound(mcu_drec);
83         event->set_context_sound(mcu_drec->get_context_noise_play());
84         event->set_context_sound(mcu_drec->get_context_noise_stop());
85         event->set_context_sound(mcu_drec->get_context_noise_fast());
86         
87         mcu_vdp->load_font_image(create_local_path(_T("FONT.ROM")));
88         mcu_vdp->set_vram_ptr(vram, 0x1800);
89 #ifdef BOOT_BASIC
90         mcu_vdp->set_context_vsync(mcu_not, SIG_NOT_INPUT, 1);
91         mcu_not->set_context_out(mcu_cpu, SIG_CPU_IRQ, 1);
92 #endif
93         
94         mcu_vdp->set_context_vsync(mcu, SIG_MCU_SYSPORT, 0x10);
95         mcu_drec->set_context_ear(mcu, SIG_MCU_SYSPORT, 0x20);
96         // bit6: printer busy
97         mcu_vdp->set_context_hsync(mcu, SIG_MCU_SYSPORT, 0x80);
98         
99 //      mcu_vdp->set_context_vsync(pcu_ctc1, SIG_Z80CTC_TRIG_1, 1);
100 //      mcu_vdp->set_context_vsync(pcu_ctc2, SIG_Z80CTC_TRIG_1, 1);
101         mcu_vdp->set_context_vsync(mcu_pio, SIG_Z80PIO_PORT_A, 0x40);
102         
103         mcu_pio->set_context_port_a(pcu_pio, SIG_Z80PIO_PORT_A, 0x38, -3);
104         mcu_pio->set_context_port_b(pcu_pio, SIG_Z80PIO_PORT_B, 0xff,  0);
105         mcu_pio->set_context_ready_a(pcu_pio, SIG_Z80PIO_STROBE_A, 1);
106         mcu_pio->set_context_ready_b(pcu_pio, SIG_Z80PIO_STROBE_B, 1);
107         mcu_pio->set_hand_shake(0, true);
108         mcu_pio->set_hand_shake(1, true);
109         
110         mcu->set_context_drec(mcu_drec);
111         mcu->set_context_psg(mcu_psg);
112         mcu->set_context_vdp(mcu_vdp);
113         
114         pcu_pio->set_context_port_a(mcu_pio, SIG_Z80PIO_PORT_A, 0x38, -3);
115         pcu_pio->set_context_port_b(mcu_pio, SIG_Z80PIO_PORT_B, 0xff,  0);
116         pcu_pio->set_context_ready_a(mcu_pio, SIG_Z80PIO_STROBE_A, 1);
117         pcu_pio->set_context_ready_b(mcu_pio, SIG_Z80PIO_STROBE_B, 1);
118         pcu_pio->set_hand_shake(0, true);
119         pcu_pio->set_hand_shake(1, true);
120         
121         // cpu bus
122         mcu_cpu->set_context_mem(mcu_mem);
123         mcu_cpu->set_context_io(mcu_io);
124         mcu_cpu->set_context_intr(dummy);
125 #ifdef USE_DEBUGGER
126         mcu_cpu->set_context_debugger(new DEBUGGER(this, emu));
127 #endif
128         
129         pcu_cpu->set_context_mem(pcu_mem);
130         pcu_cpu->set_context_io(pcu_io);
131         pcu_cpu->set_context_intr(dummy);
132 #ifdef USE_DEBUGGER
133         pcu_cpu->set_context_debugger(new DEBUGGER(this, emu));
134 #endif
135         
136         // z80 family daisy chain
137         DEVICE* parent_dev = NULL;
138         int level = 0;
139         
140         #define Z80_DAISY_CHAIN(cpu, dev) { \
141                 if(parent_dev == NULL) { \
142                         cpu->set_context_intr(dev); \
143                 } else { \
144                         parent_dev->set_context_child(dev); \
145                 } \
146                 dev->set_context_intr(cpu, level++); \
147                 parent_dev = dev; \
148         }
149         Z80_DAISY_CHAIN(pcu_cpu, pcu_ctc1);
150         Z80_DAISY_CHAIN(pcu_cpu, pcu_ctc2);
151         Z80_DAISY_CHAIN(pcu_cpu, pcu_pio );
152 #ifndef BOOT_BASIC
153         parent_dev = NULL;
154         Z80_DAISY_CHAIN(mcu_cpu, mcu_pio );
155 #endif
156         
157         // memory bus
158         memset(mcu_rom, 0xff, sizeof(mcu_rom));
159         memset(mcu_ram, 0x00, sizeof(mcu_ram));
160         memset(pcu_rom, 0xff, sizeof(pcu_rom));
161         memset(pcu_ram, 0x00, sizeof(pcu_ram));
162         
163         memset(vram, 0x00, sizeof(vram));
164         memset(cram, 0x00, sizeof(cram));
165         
166         mcu_mem->read_bios(_T("BASIC.ROM"), mcu_rom, sizeof(mcu_rom));
167 #ifdef BOOT_BASIC
168         memset(mcu_rom + 0x7800, 0, 0x800);
169 #else
170 //      memset(mcu_rom, 0, 0x8000);
171 #endif
172         mcu_mem->set_memory_r (0x0000, 0x6fff, mcu_rom);
173         mcu_mem->set_memory_rw(0x6000, 0x77ff, vram);
174         mcu_mem->set_memory_r (0x7800, 0x7fff, mcu_rom + 0x7800);
175 //      mcu_mem->set_memory_rw(0x8000, 0xffff, mcu_ram);
176         mcu_mem->set_memory_rw(0x8000, 0xefff, mcu_ram);
177         mcu_mem->set_memory_rw(0xf000, 0xffff, cram);
178         
179         pcu_mem->read_bios(_T("MENU.ROM"), pcu_rom, sizeof(pcu_rom));
180 #ifdef BOOT_BASIC
181         memset(pcu_rom, 0, 0x8000);
182 #endif
183         pcu_mem->set_memory_r (0x0000, 0x7fff, pcu_rom);
184         pcu_mem->set_memory_rw(0x8000, 0xffff, pcu_ram);
185         pcu_mem->set_memory_rw(0xc000, 0xcfff, cram);
186         
187         // i/o bus
188         mcu_io->set_iomap_single_rw(0x40, mcu);
189         mcu_io->set_iomap_range_r  (0x80, 0x89, mcu);
190         mcu_io->set_iomap_alias_w  (0xc0, mcu_psg, 1);  // PSG data
191         mcu_io->set_iomap_alias_w  (0xc1, mcu_psg, 0);  // PSG ch
192 //      mcu_io->set_iomap_alias_r  (0xc0, mcu_psg, 1);
193         mcu_io->set_iomap_alias_r  (0xc1, mcu_psg, 1);  // PSG data
194         mcu_io->set_iomap_range_rw (0xe0, 0xe3, mcu_pio);
195 #ifdef _IO_DEBUG_LOG
196         pcu_io->cpu_index = 1;
197 #endif
198         pcu_io->set_iomap_range_rw (0x00, 0x03, pcu_ctc1);
199         pcu_io->set_iomap_range_rw (0x08, 0x0b, pcu_ctc2);
200         pcu_io->set_iomap_alias_rw (0x10, pcu_pio, 0);
201         pcu_io->set_iomap_alias_rw (0x11, pcu_pio, 2);
202         pcu_io->set_iomap_alias_rw (0x12, pcu_pio, 1);
203         pcu_io->set_iomap_alias_rw (0x13, pcu_pio, 3);
204         pcu_io->set_iomap_range_rw (0x20, 0x2f, pcu_rtc);
205         pcu_io->set_iomap_range_rw (0x38, 0x39, pcu);
206         pcu_io->set_iomap_range_rw (0x60, 0x63, pcu_pio1);
207         pcu_io->set_iomap_range_rw (0x64, 0x67, pcu_pio2);
208         pcu_io->set_iomap_range_rw (0x68, 0x6b, pcu_pio3);
209         
210         // initialize all devices
211         for(DEVICE* device = first_device; device; device = device->next_device) {
212                 device->initialize();
213         }
214 }
215
216 VM::~VM()
217 {
218         // delete all devices
219         for(DEVICE* device = first_device; device;) {
220                 DEVICE *next_device = device->next_device;
221                 device->release();
222                 delete device;
223                 device = next_device;
224         }
225 }
226
227 DEVICE* VM::get_device(int id)
228 {
229         for(DEVICE* device = first_device; device; device = device->next_device) {
230                 if(device->this_device_id == id) {
231                         return device;
232                 }
233         }
234         return NULL;
235 }
236
237 // ----------------------------------------------------------------------------
238 // drive virtual machine
239 // ----------------------------------------------------------------------------
240
241 void VM::reset()
242 {
243         // reset all devices
244         for(DEVICE* device = first_device; device; device = device->next_device) {
245                 device->reset();
246         }
247         mcu_vdp->write_signal(SIG_MC6847_GM,  6, 7);
248         mcu_vdp->write_signal(SIG_MC6847_CSS, 0, 0);
249         mcu_vdp->write_signal(SIG_MC6847_AG,  0, 0);
250
251 //      pcu_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
252 }
253
254 void VM::run()
255 {
256         event->drive();
257 }
258
259 // ----------------------------------------------------------------------------
260 // debugger
261 // ----------------------------------------------------------------------------
262
263 #ifdef USE_DEBUGGER
264 DEVICE *VM::get_cpu(int index)
265 {
266         if(index == 0) {
267                 return mcu_cpu;
268         } else if(index == 1) {
269                 return pcu_cpu;
270         }
271         return NULL;
272 }
273 #endif
274
275 // ----------------------------------------------------------------------------
276 // draw screen
277 // ----------------------------------------------------------------------------
278
279 void VM::draw_screen()
280 {
281         mcu_vdp->draw_screen();
282 }
283
284 // ----------------------------------------------------------------------------
285 // soud manager
286 // ----------------------------------------------------------------------------
287
288 void VM::initialize_sound(int rate, int samples)
289 {
290         // init sound manager
291         event->initialize_sound(rate, samples);
292         
293         // init sound gen
294         mcu_psg->initialize_sound(rate, 1996750, samples, 0, 0);
295 }
296
297 uint16_t* VM::create_sound(int* extra_frames)
298 {
299         return event->create_sound(extra_frames);
300 }
301
302 int VM::get_sound_buffer_ptr()
303 {
304         return event->get_sound_buffer_ptr();
305 }
306
307 #ifdef USE_SOUND_VOLUME
308 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
309 {
310         if(ch == 0) {
311                 mcu_psg->set_volume(1, decibel_l, decibel_r);
312         } else if(ch == 1) {
313                 mcu_drec->set_volume(0, decibel_l, decibel_r);
314         } else if(ch == 2) {
315                 mcu_drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
316                 mcu_drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
317                 mcu_drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
318         }
319 }
320 #endif
321
322 // ----------------------------------------------------------------------------
323 // user interface
324 // ----------------------------------------------------------------------------
325
326 void VM::play_tape(int drv, const _TCHAR* file_path)
327 {
328         bool remote = mcu_drec->get_remote();
329         
330         if(mcu_drec->play_tape(file_path) && remote) {
331                 // if machine already sets remote on, start playing now
332                 push_play(drv);
333         }
334 }
335
336 void VM::rec_tape(int drv, const _TCHAR* file_path)
337 {
338         bool remote = mcu_drec->get_remote();
339         
340         if(mcu_drec->rec_tape(file_path) && remote) {
341                 // if machine already sets remote on, start recording now
342                 push_play(drv);
343         }
344 }
345
346 void VM::close_tape(int drv)
347 {
348         emu->lock_vm();
349         mcu_drec->close_tape();
350         emu->unlock_vm();
351         mcu_drec->set_remote(false);
352 }
353
354 bool VM::is_tape_inserted(int drv)
355 {
356         return mcu_drec->is_tape_inserted();
357 }
358
359 bool VM::is_tape_playing(int drv)
360 {
361         return mcu_drec->is_tape_playing();
362 }
363
364 bool VM::is_tape_recording(int drv)
365 {
366         return mcu_drec->is_tape_recording();
367 }
368
369 int VM::get_tape_position(int drv)
370 {
371         return mcu_drec->get_tape_position();
372 }
373
374 const _TCHAR* VM::get_tape_message(int drv)
375 {
376         return mcu_drec->get_message();
377 }
378
379 void VM::push_play(int drv)
380 {
381         mcu_drec->set_remote(false);
382         mcu_drec->set_ff_rew(0);
383         mcu_drec->set_remote(true);
384 }
385
386 void VM::push_stop(int drv)
387 {
388         mcu_drec->set_remote(false);
389 }
390
391 void VM::push_fast_forward(int drv)
392 {
393         mcu_drec->set_remote(false);
394         mcu_drec->set_ff_rew(1);
395         mcu_drec->set_remote(true);
396 }
397
398 void VM::push_fast_rewind(int drv)
399 {
400         mcu_drec->set_remote(false);
401         mcu_drec->set_ff_rew(-1);
402         mcu_drec->set_remote(true);
403 }
404
405 bool VM::is_frame_skippable()
406 {
407         return event->is_frame_skippable();
408 }
409
410 void VM::update_config()
411 {
412         for(DEVICE* device = first_device; device; device = device->next_device) {
413                 device->update_config();
414         }
415 }
416
417 #define STATE_VERSION   5
418
419 bool VM::process_state(FILEIO* state_fio, bool loading)
420 {
421         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
422                 return false;
423         }
424         for(DEVICE* device = first_device; device; device = device->next_device) {
425                 const char *name = typeid(*device).name() + 6; // skip "class "
426                 int len = strlen(name);
427                 
428                 if(!state_fio->StateCheckInt32(len)) {
429                         return false;
430                 }
431                 if(!state_fio->StateCheckBuffer(name, len, 1)) {
432                         return false;
433                 }
434                 if(!device->process_state(state_fio, loading)) {
435                         return false;
436                 }
437         }
438         return true;
439 }
440