OSDN Git Service

716da2fa9d867bd3ae2372b040bc6171de8d854c
[csp-qt/common_source_project-fm7.git] / source / src / vm / msx / msx.cpp
1 /*
2         ASCII MSX1 Emulator 'yaMSX1'
3         ASCII MSX2 Emulator 'yaMSX2'
4         Pioneer PX-7 Emulator 'ePX-7'
5
6         Author : tanam
7         Date   : 2013.06.29-
8
9         modified by Takeda.Toshiya
10         modified by umaiboux
11
12         [ virtual machine ]
13 */
14
15 #include "msx.h"
16 #include "../../emu.h"
17 #include "../device.h"
18 #include "../event.h"
19
20 #include "../datarec.h"
21 #include "../i8255.h"
22 #include "../io.h"
23 #if defined(_PX7)
24 #include "../ld700.h"
25 #endif
26 #include "../noise.h"
27 #include "../not.h"
28 //#include "../ym2203.h"
29 #include "../ay_3_891x.h"
30 #include "../pcm1bit.h"
31 #if defined(_MSX2)
32 #include "../rp5c01.h"
33 #include "../v99x8.h"
34 #else
35 #include "../tms9918a.h"
36 #endif
37 #include "../z80.h"
38
39 #ifdef USE_DEBUGGER
40 #include "../debugger.h"
41 #endif
42
43 #include "joystick.h"
44 #include "keyboard.h"
45 #include "./memory.h"
46 #if defined(_MSX2)
47 #include "rtcif.h"
48 #endif
49
50 using MSX::JOYSTICK;
51 using MSX::KEYBOARD;
52 using MSX::MEMORY;
53 #ifdef _MSX2
54 using MSX::RTCIF;
55 #endif
56 using MSX::SLOT0;
57 using MSX::SLOT1;
58 using MSX::SLOT2;
59 using MSX::SLOT3;
60
61 // ----------------------------------------------------------------------------
62 // initialize
63 // ----------------------------------------------------------------------------
64
65 VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
66 {
67         // create devices
68         first_device = last_device = NULL;
69         dummy = new DEVICE(this, emu);  // must be 1st device
70         event = new EVENT(this, emu);   // must be 2nd device
71         dummy->set_device_name(_T("1st Dummy"));
72         event->set_device_name(_T("EVENT"));
73         
74         drec = new DATAREC(this, emu);
75         drec->set_context_noise_play(new NOISE(this, emu));
76         drec->set_context_noise_stop(new NOISE(this, emu));
77         drec->set_context_noise_fast(new NOISE(this, emu));
78         pio = new I8255(this, emu);
79         io = new IO(this, emu);
80 #if defined(_PX7)
81         ldp = new LD700(this, emu);
82 #endif
83         not_remote = new NOT(this, emu);
84 //      psg = new YM2203(this, emu);
85         psg = new AY_3_891X(this, emu);
86         pcm = new PCM1BIT(this, emu);
87         not_remote->set_device_name(_T("NOT Gate (REMOTE)"));
88
89 #if defined(_MSX2)
90         rtc = new RP5C01(this, emu);
91         vdp = new V99X8(this, emu);
92 #else
93         vdp = new TMS9918A(this, emu);
94 #endif
95         cpu = new Z80(this, emu);
96         joystick = new JOYSTICK(this, emu);
97         keyboard = new KEYBOARD(this, emu);
98         memory = new MSX_MEMORY(this, emu);
99 #if defined(_MSX2)
100         rtcif = new RTCIF(this, emu);
101 #endif
102         slot0 = new SLOT0(this, emu);   // #0: main memory
103         slot1 = new SLOT1(this, emu);   // #1: rom-cartridge or msx-dos
104         slot2 = new SLOT2(this, emu);   // #2: fdd-cartridge or p-basic
105         slot3 = new SLOT3(this, emu);   // #3: rom-cartridge or ram-cartridge
106
107         slot0->set_device_name(_T("SLOT#0 MAIN MEMORY"));
108         slot1->set_device_name(_T("SLOT#1 ROM CARTRIDGE"));
109         slot2->set_device_name(_T("SLOT#2 FDD CARTRIDGE"));
110         slot3->set_device_name(_T("SLOT#3 ROM CARTRIDGE"));
111
112         // set contexts
113         event->set_context_cpu(cpu);
114         event->set_context_sound(psg);
115         event->set_context_sound(pcm);
116         event->set_context_sound(drec);
117 #if defined(_PX7)
118         event->set_context_sound(ldp);
119 #endif
120         event->set_context_sound(drec->get_context_noise_play());
121         event->set_context_sound(drec->get_context_noise_stop());
122         event->set_context_sound(drec->get_context_noise_fast());
123         
124         drec->set_context_ear(psg, SIG_AY_3_891X_PORT_A, 0x80);
125         pio->set_context_port_a(memory, SIG_MEMORY_SEL, 0xff, 0);
126         pio->set_context_port_c(keyboard, SIG_KEYBOARD_COLUMN, 0x0f, 0);
127         pio->set_context_port_c(not_remote, SIG_NOT_INPUT, 0x10, 0);
128         not_remote->set_context_out(drec, SIG_DATAREC_REMOTE, 1);
129         pio->set_context_port_c(drec, SIG_DATAREC_MIC, 0x20, 0);
130         pio->set_context_port_c(pcm, SIG_PCM1BIT_SIGNAL, 0x80, 0);
131         psg->set_context_port_b(joystick, SIG_JOYSTICK_SEL, 0x40, 0);
132         vdp->set_context_irq(cpu, SIG_CPU_IRQ, 1);
133
134 #if defined(_PX7)
135         pio->set_context_port_c(slot2, SIG_SLOT2_MUTE, 0x10, 0);
136         ldp->set_context_exv(slot2, SIG_SLOT2_EXV, 1);
137         ldp->set_context_ack(slot2, SIG_SLOT2_ACK, 1);
138         ldp->set_context_sound(psg, SIG_AY_3_891X_PORT_A, 0x80);
139 #endif
140         joystick->set_context_psg(psg);
141 //      keyboard->set_context_cpu(cpu);
142         keyboard->set_context_pio(pio);
143         memory->set_context_slot(0, slot0);
144         memory->set_context_slot(1, slot1);
145         memory->set_context_slot(2, slot2);
146         memory->set_context_slot(3, slot3);
147 #if defined(_MSX2)
148         rtcif->set_context_rtc(rtc);
149 #endif
150 #if defined(_PX7)
151         slot2->set_context_cpu(cpu);
152         slot2->set_context_ldp(ldp);
153         slot2->set_context_vdp(vdp);
154 #endif
155         
156         // cpu bus
157         cpu->set_context_mem(memory);
158         cpu->set_context_io(io);
159         cpu->set_context_intr(dummy);
160 #if !defined(_PX7)
161         cpu->set_context_bios(memory);
162 #endif
163 #ifdef USE_DEBUGGER
164         cpu->set_context_debugger(new DEBUGGER(this, emu));
165 #endif
166         
167         // i/o bus
168 #ifdef _MSX2
169         io->set_iomap_range_rw(0xb4, 0xb5, rtcif);
170         io->set_iomap_range_rw(0x98, 0x9b, vdp);
171 #else
172         io->set_iomap_range_rw(0x98, 0x99, vdp);
173 #endif
174         io->set_iomap_range_rw(0xa8, 0xab, pio);
175         io->set_iomap_alias_w(0xa0, psg, 0);    // PSG ch
176         io->set_iomap_alias_w(0xa1, psg, 1);    // PSG data
177         io->set_iomap_alias_r(0xa2, psg, 1);    // PSG data
178         io->set_iomap_range_rw(0xfc, 0xff, memory);
179         
180         // initialize all devices
181 #if defined(__GIT_REPO_VERSION)
182         strncpy(_git_revision, __GIT_REPO_VERSION, sizeof(_git_revision) - 1);
183 #endif
184         for(DEVICE* device = first_device; device; device = device->next_device) {
185                 device->initialize();
186         }
187 }
188
189 VM::~VM()
190 {
191         // delete all devices
192         for(DEVICE* device = first_device; device;) {
193                 DEVICE *next_device = device->next_device;
194                 device->release();
195                 delete device;
196                 device = next_device;
197         }
198 }
199
200 DEVICE* VM::get_device(int id)
201 {
202         for(DEVICE* device = first_device; device; device = device->next_device) {
203                 if(device->this_device_id == id) {
204                         return device;
205                 }
206         }
207         return NULL;
208 }
209
210 // ----------------------------------------------------------------------------
211 // drive virtual machine
212 // ----------------------------------------------------------------------------
213
214 void VM::reset()
215 {
216         // reset all devices
217         for(DEVICE* device = first_device; device; device = device->next_device) {
218                 device->reset();
219         }
220 }
221
222 void VM::run()
223 {
224         event->drive();
225 }
226
227 // ----------------------------------------------------------------------------
228 // debugger
229 // ----------------------------------------------------------------------------
230
231 #ifdef USE_DEBUGGER
232 DEVICE *VM::get_cpu(int index)
233 {
234         if(index == 0) {
235                 return cpu;
236         }
237         return NULL;
238 }
239 #endif
240
241 // ----------------------------------------------------------------------------
242 // draw screen
243 // ----------------------------------------------------------------------------
244
245 void VM::draw_screen()
246 {
247         vdp->draw_screen();
248 }
249
250 // ----------------------------------------------------------------------------
251 // soud manager
252 // ----------------------------------------------------------------------------
253
254 void VM::initialize_sound(int rate, int samples)
255 {
256         // init sound manager
257         event->initialize_sound(rate, samples);
258         
259         // init sound gen
260         psg->initialize_sound(rate, 3579545, samples, 0, 0);
261         pcm->initialize_sound(rate, 8000);
262 #if defined(_PX7)
263         ldp->initialize_sound(rate, samples);
264 #endif
265 }
266
267 uint16_t* VM::create_sound(int* extra_frames)
268 {
269         return event->create_sound(extra_frames);
270 }
271
272 int VM::get_sound_buffer_ptr()
273 {
274         return event->get_sound_buffer_ptr();
275 }
276
277 #if defined(_PX7)
278 void VM::movie_sound_callback(uint8_t *buffer, long size)
279 {
280         ldp->movie_sound_callback(buffer, size);
281 }
282 #endif
283
284 #ifdef USE_SOUND_VOLUME
285 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
286 {
287         if(ch-- == 0) {
288                 psg->set_volume(1, decibel_l, decibel_r);
289         } else if(ch-- == 0) {
290                 pcm->set_volume(0, decibel_l, decibel_r);
291         } else if(ch-- == 0) {
292                 drec->set_volume(0, decibel_l, decibel_r);
293 #if defined(_PX7)
294         } else if(ch-- == 0) {
295                 ldp->set_volume(0, decibel_l, decibel_r);
296 #endif
297         } else if(ch-- == 0) {
298                 drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
299                 drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
300                 drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
301         }
302 }
303 #endif
304
305 // ----------------------------------------------------------------------------
306 // user interface
307 // ----------------------------------------------------------------------------
308
309 void VM::open_cart(int drv, const _TCHAR* file_path)
310 {
311         if(drv == 0) {
312                 slot1->open_cart(file_path);
313         } else {
314                 slot3->open_cart(file_path);
315         }
316         reset();
317 }
318
319 void VM::close_cart(int drv)
320 {
321         if(drv == 0) {
322                 slot1->close_cart();
323         } else {
324                 slot3->close_cart();
325         }
326         reset();
327 }
328
329 bool VM::is_cart_inserted(int drv)
330 {
331         if(drv == 0) {
332                 return slot1->is_cart_inserted();
333         } else {
334                 return slot3->is_cart_inserted();
335         }
336 }
337
338 void VM::play_tape(int drv, const _TCHAR* file_path)
339 {
340         bool remote = drec->get_remote();
341         
342         if(drec->play_tape(file_path) && remote) {
343                 // if machine already sets remote on, start playing now
344                 push_play(drv);
345         }
346 }
347
348 void VM::rec_tape(int drv, const _TCHAR* file_path)
349 {
350         bool remote = drec->get_remote();
351         
352         if(drec->rec_tape(file_path) && remote) {
353                 // if machine already sets remote on, start recording now
354                 push_play(drv);
355         }
356 }
357
358 void VM::close_tape(int drv)
359 {
360         emu->lock_vm();
361         drec->close_tape();
362         emu->unlock_vm();
363         drec->set_remote(false);
364 }
365
366 bool VM::is_tape_inserted(int drv)
367 {
368         return drec->is_tape_inserted();
369 }
370
371 bool VM::is_tape_playing(int drv)
372 {
373         return drec->is_tape_playing();
374 }
375
376 bool VM::is_tape_recording(int drv)
377 {
378         return drec->is_tape_recording();
379 }
380
381 int VM::get_tape_position(int drv)
382 {
383         return drec->get_tape_position();
384 }
385
386 const _TCHAR* VM::get_tape_message(int drv)
387 {
388         return drec->get_message();
389 }
390
391 void VM::push_play(int drv)
392 {
393         drec->set_remote(false);
394         drec->set_ff_rew(0);
395         drec->set_remote(true);
396 }
397
398 void VM::push_stop(int drv)
399 {
400         drec->set_remote(false);
401 }
402
403 void VM::push_fast_forward(int drv)
404 {
405         drec->set_remote(false);
406         drec->set_ff_rew(1);
407         drec->set_remote(true);
408 }
409
410 void VM::push_fast_rewind(int drv)
411 {
412         drec->set_remote(false);
413         drec->set_ff_rew(-1);
414         drec->set_remote(true);
415 }
416
417 void VM::load_binary(int drv, const _TCHAR* file_path)
418 {
419         if(drv == 0) {
420                 pac2->open_rampac2(file_path);
421         }
422 }
423
424 #if defined(_PX7)
425 void VM::open_laser_disc(int drv, const _TCHAR* file_path)
426 {
427         ldp->open_disc(file_path);
428 }
429
430 void VM::close_laser_disc(int drv)
431 {
432         ldp->close_disc();
433 }
434
435 bool VM::is_laser_disc_inserted(int drv)
436 {
437         return ldp->is_disc_inserted();
438 }
439
440 uint32_t VM::is_laser_disc_accessed()
441 {
442         return lpd->read_signal(0);
443 }
444 #else
445 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
446 {
447         memory->open_disk(drv, file_path, bank);
448 }
449
450 void VM::close_floppy_disk(int drv)
451 {
452         memory->close_disk(drv);
453 }
454
455 bool VM::is_floppy_disk_inserted(int drv)
456 {
457         return memory->is_disk_inserted(drv);
458 }
459
460 void VM::is_floppy_disk_protected(int drv, bool value)
461 {
462         memory->is_disk_protected(drv, value);
463 }
464
465 bool VM::is_floppy_disk_protected(int drv)
466 {
467         return memory->is_disk_protected(drv);
468 }
469
470 uint32_t VM::is_floppy_disk_accessed()
471 {
472         return memory->read_signal(0);
473 }
474 #endif
475
476 bool VM::is_frame_skippable()
477 {
478         return event->is_frame_skippable();
479 }
480
481 void VM::update_config()
482 {
483         for(DEVICE* device = first_device; device; device = device->next_device) {
484                 device->update_config();
485         }
486 }
487
488 #define STATE_VERSION   4
489
490 void VM::save_state(FILEIO* state_fio)
491 {
492         state_fio->FputUint32(STATE_VERSION);
493         
494         for(DEVICE* device = first_device; device; device = device->next_device) {
495                 device->save_state(state_fio);
496         }
497 }
498
499 bool VM::load_state(FILEIO* state_fio)
500 {
501         if(state_fio->FgetUint32() != STATE_VERSION) {
502                 return false;
503         }
504         for(DEVICE* device = first_device; device; device = device->next_device) {
505                 if(!device->load_state(state_fio)) {
506                         return false;
507                 }
508         }
509         return true;
510 }
511
512 bool VM::process_state(FILEIO* state_fio, bool loading)
513 {
514         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
515                 return false;
516         }
517         for(DEVICE* device = first_device; device; device = device->next_device) {
518                 // Note: typeid(foo).name is fixed by recent ABI.Not dec 6.
519                 // const char *name = typeid(*device).name();
520                 //       But, using get_device_name() instead of typeid(foo).name() 20181008 K.O
521                 const char *name = device->get_device_name();
522                 int len = strlen(name);
523                 
524                 if(!state_fio->StateCheckInt32(len)) {
525                         if(loading) {
526                                 printf("Class name len Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
527                         }
528                         return false;
529                 }
530                 if(!state_fio->StateCheckBuffer(name, len, 1)) {
531                         if(loading) {
532                                 printf("Class name Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
533                         }
534                         return false;
535                 }
536                 if(!device->process_state(state_fio, loading)) {
537                         if(loading) {
538                                 printf("Data loading Error: DEVID=%d\n", device->this_device_id);
539                         }
540                         return false;
541                 }
542         }
543         // Machine specified.
544         return true;
545 }