OSDN Git Service

[BUILD] Set SOVERSION and GIT hash automatically.
[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 // ----------------------------------------------------------------------------
51 // initialize
52 // ----------------------------------------------------------------------------
53
54 VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
55 {
56         // create devices
57         first_device = last_device = NULL;
58         dummy = new DEVICE(this, emu);  // must be 1st device
59         event = new EVENT(this, emu);   // must be 2nd device
60         dummy->set_device_name(_T("1st Dummy"));
61         event->set_device_name(_T("EVENT"));
62         
63         drec = new DATAREC(this, emu);
64         drec->set_context_noise_play(new NOISE(this, emu));
65         drec->set_context_noise_stop(new NOISE(this, emu));
66         drec->set_context_noise_fast(new NOISE(this, emu));
67         pio = new I8255(this, emu);
68         io = new IO(this, emu);
69 #if defined(_PX7)
70         ldp = new LD700(this, emu);
71 #endif
72         not_remote = new NOT(this, emu);
73 //      psg = new YM2203(this, emu);
74         psg = new AY_3_891X(this, emu);
75         pcm = new PCM1BIT(this, emu);
76         not_remote->set_device_name(_T("NOT Gate (REMOTE)"));
77
78 #if defined(_MSX2)
79         rtc = new RP5C01(this, emu);
80         vdp = new V99X8(this, emu);
81 #else
82         vdp = new TMS9918A(this, emu);
83 #endif
84         cpu = new Z80(this, emu);
85         joystick = new JOYSTICK(this, emu);
86         keyboard = new KEYBOARD(this, emu);
87         memory = new MEMORY(this, emu);
88 #if defined(_MSX2)
89         rtcif = new RTCIF(this, emu);
90 #endif
91         slot0 = new SLOT0(this, emu);   // #0: main memory
92         slot1 = new SLOT1(this, emu);   // #1: rom-cartridge or msx-dos
93         slot2 = new SLOT2(this, emu);   // #2: fdd-cartridge or p-basic
94         slot3 = new SLOT3(this, emu);   // #3: rom-cartridge or ram-cartridge
95
96         slot0->set_device_name(_T("SLOT#0 MAIN MEMORY"));
97         slot1->set_device_name(_T("SLOT#1 ROM CARTRIDGE"));
98         slot2->set_device_name(_T("SLOT#2 FDD CARTRIDGE"));
99         slot3->set_device_name(_T("SLOT#3 ROM CARTRIDGE"));
100
101         // set contexts
102         event->set_context_cpu(cpu);
103         event->set_context_sound(psg);
104         event->set_context_sound(pcm);
105         event->set_context_sound(drec);
106 #if defined(_PX7)
107         event->set_context_sound(ldp);
108 #endif
109         event->set_context_sound(drec->get_context_noise_play());
110         event->set_context_sound(drec->get_context_noise_stop());
111         event->set_context_sound(drec->get_context_noise_fast());
112         
113         drec->set_context_ear(psg, SIG_AY_3_891X_PORT_A, 0x80);
114         pio->set_context_port_a(memory, SIG_MEMORY_SEL, 0xff, 0);
115         pio->set_context_port_c(keyboard, SIG_KEYBOARD_COLUMN, 0x0f, 0);
116         pio->set_context_port_c(not_remote, SIG_NOT_INPUT, 0x10, 0);
117         not_remote->set_context_out(drec, SIG_DATAREC_REMOTE, 1);
118         pio->set_context_port_c(drec, SIG_DATAREC_MIC, 0x20, 0);
119         pio->set_context_port_c(pcm, SIG_PCM1BIT_SIGNAL, 0x80, 0);
120         psg->set_context_port_b(joystick, SIG_JOYSTICK_SEL, 0x40, 0);
121         vdp->set_context_irq(cpu, SIG_CPU_IRQ, 1);
122
123 #if defined(_PX7)
124         pio->set_context_port_c(slot2, SIG_SLOT2_MUTE, 0x10, 0);
125         ldp->set_context_exv(slot2, SIG_SLOT2_EXV, 1);
126         ldp->set_context_ack(slot2, SIG_SLOT2_ACK, 1);
127         ldp->set_context_sound(psg, SIG_AY_3_891X_PORT_A, 0x80);
128 #endif
129         joystick->set_context_psg(psg);
130 //      keyboard->set_context_cpu(cpu);
131         keyboard->set_context_pio(pio);
132         memory->set_context_slot(0, slot0);
133         memory->set_context_slot(1, slot1);
134         memory->set_context_slot(2, slot2);
135         memory->set_context_slot(3, slot3);
136 #if defined(_MSX2)
137         rtcif->set_context_rtc(rtc);
138 #endif
139 #if defined(_PX7)
140         slot2->set_context_cpu(cpu);
141         slot2->set_context_ldp(ldp);
142         slot2->set_context_vdp(vdp);
143 #endif
144         
145         // cpu bus
146         cpu->set_context_mem(memory);
147         cpu->set_context_io(io);
148         cpu->set_context_intr(dummy);
149 #if !defined(_PX7)
150         cpu->set_context_bios(memory);
151 #endif
152 #ifdef USE_DEBUGGER
153         cpu->set_context_debugger(new DEBUGGER(this, emu));
154 #endif
155         
156         // i/o bus
157 #ifdef _MSX2
158         io->set_iomap_range_rw(0xb4, 0xb5, rtcif);
159         io->set_iomap_range_rw(0x98, 0x9b, vdp);
160 #else
161         io->set_iomap_range_rw(0x98, 0x99, vdp);
162 #endif
163         io->set_iomap_range_rw(0xa8, 0xab, pio);
164         io->set_iomap_alias_w(0xa0, psg, 0);    // PSG ch
165         io->set_iomap_alias_w(0xa1, psg, 1);    // PSG data
166         io->set_iomap_alias_r(0xa2, psg, 1);    // PSG data
167         io->set_iomap_range_rw(0xfc, 0xff, memory);
168         
169         // initialize all devices
170 #if defined(__GIT_REPO_VERSION)
171         strncpy(_git_revision, __GIT_REPO_VERSION, sizeof(_git_revision) - 1);
172 #endif
173         for(DEVICE* device = first_device; device; device = device->next_device) {
174                 device->initialize();
175         }
176 }
177
178 VM::~VM()
179 {
180         // delete all devices
181         for(DEVICE* device = first_device; device;) {
182                 DEVICE *next_device = device->next_device;
183                 device->release();
184                 delete device;
185                 device = next_device;
186         }
187 }
188
189 DEVICE* VM::get_device(int id)
190 {
191         for(DEVICE* device = first_device; device; device = device->next_device) {
192                 if(device->this_device_id == id) {
193                         return device;
194                 }
195         }
196         return NULL;
197 }
198
199 // ----------------------------------------------------------------------------
200 // drive virtual machine
201 // ----------------------------------------------------------------------------
202
203 void VM::reset()
204 {
205         // reset all devices
206         for(DEVICE* device = first_device; device; device = device->next_device) {
207                 device->reset();
208         }
209 }
210
211 void VM::run()
212 {
213         event->drive();
214 }
215
216 // ----------------------------------------------------------------------------
217 // debugger
218 // ----------------------------------------------------------------------------
219
220 #ifdef USE_DEBUGGER
221 DEVICE *VM::get_cpu(int index)
222 {
223         if(index == 0) {
224                 return cpu;
225         }
226         return NULL;
227 }
228 #endif
229
230 // ----------------------------------------------------------------------------
231 // draw screen
232 // ----------------------------------------------------------------------------
233
234 void VM::draw_screen()
235 {
236         vdp->draw_screen();
237 }
238
239 // ----------------------------------------------------------------------------
240 // soud manager
241 // ----------------------------------------------------------------------------
242
243 void VM::initialize_sound(int rate, int samples)
244 {
245         // init sound manager
246         event->initialize_sound(rate, samples);
247         
248         // init sound gen
249         psg->initialize_sound(rate, 3579545, samples, 0, 0);
250         pcm->initialize_sound(rate, 8000);
251 #if defined(_PX7)
252         ldp->initialize_sound(rate, samples);
253 #endif
254 }
255
256 uint16_t* VM::create_sound(int* extra_frames)
257 {
258         return event->create_sound(extra_frames);
259 }
260
261 int VM::get_sound_buffer_ptr()
262 {
263         return event->get_sound_buffer_ptr();
264 }
265
266 #if defined(_PX7)
267 void VM::movie_sound_callback(uint8_t *buffer, long size)
268 {
269         ldp->movie_sound_callback(buffer, size);
270 }
271 #endif
272
273 #ifdef USE_SOUND_VOLUME
274 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
275 {
276         if(ch-- == 0) {
277                 psg->set_volume(1, decibel_l, decibel_r);
278         } else if(ch-- == 0) {
279                 pcm->set_volume(0, decibel_l, decibel_r);
280         } else if(ch-- == 0) {
281                 drec->set_volume(0, decibel_l, decibel_r);
282 #if defined(_PX7)
283         } else if(ch-- == 0) {
284                 ldp->set_volume(0, decibel_l, decibel_r);
285 #endif
286         } else if(ch-- == 0) {
287                 drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
288                 drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
289                 drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
290         }
291 }
292 #endif
293
294 // ----------------------------------------------------------------------------
295 // user interface
296 // ----------------------------------------------------------------------------
297
298 void VM::open_cart(int drv, const _TCHAR* file_path)
299 {
300         if(drv == 0) {
301                 slot1->open_cart(file_path);
302         } else {
303                 slot3->open_cart(file_path);
304         }
305         reset();
306 }
307
308 void VM::close_cart(int drv)
309 {
310         if(drv == 0) {
311                 slot1->close_cart();
312         } else {
313                 slot3->close_cart();
314         }
315         reset();
316 }
317
318 bool VM::is_cart_inserted(int drv)
319 {
320         if(drv == 0) {
321                 return slot1->is_cart_inserted();
322         } else {
323                 return slot3->is_cart_inserted();
324         }
325 }
326
327 void VM::play_tape(int drv, const _TCHAR* file_path)
328 {
329         drec->play_tape(file_path);
330 //      drec->set_remote(true);
331 }
332
333 void VM::rec_tape(int drv, const _TCHAR* file_path)
334 {
335         drec->rec_tape(file_path);
336 //      drec->set_remote(true);
337 }
338
339 void VM::close_tape(int drv)
340 {
341         emu->lock_vm();
342         drec->close_tape();
343         emu->unlock_vm();
344 //      drec->set_remote(false);
345 }
346
347 bool VM::is_tape_inserted(int drv)
348 {
349         return drec->is_tape_inserted();
350 }
351
352 bool VM::is_tape_playing(int drv)
353 {
354         return drec->is_tape_playing();
355 }
356
357 bool VM::is_tape_recording(int drv)
358 {
359         return drec->is_tape_recording();
360 }
361
362 int VM::get_tape_position(int drv)
363 {
364         return drec->get_tape_position();
365 }
366
367 const _TCHAR* VM::get_tape_message(int drv)
368 {
369         return drec->get_message();
370 }
371
372 void VM::push_play(int drv)
373 {
374         drec->set_ff_rew(0);
375         drec->set_remote(true);
376 }
377
378 void VM::push_stop(int drv)
379 {
380         drec->set_remote(false);
381 }
382
383 void VM::push_fast_forward(int drv)
384 {
385         drec->set_ff_rew(1);
386         drec->set_remote(true);
387 }
388
389 void VM::push_fast_rewind(int drv)
390 {
391         drec->set_ff_rew(-1);
392         drec->set_remote(true);
393 }
394
395 void VM::load_binary(int drv, const _TCHAR* file_path)
396 {
397         if(drv == 0) {
398                 pac2->open_rampac2(file_path);
399         }
400 }
401
402 #if defined(_PX7)
403 void VM::open_laser_disc(int drv, const _TCHAR* file_path)
404 {
405         ldp->open_disc(file_path);
406 }
407
408 void VM::close_laser_disc(int drv)
409 {
410         ldp->close_disc();
411 }
412
413 bool VM::is_laser_disc_inserted(int drv)
414 {
415         return ldp->is_disc_inserted();
416 }
417
418 uint32_t VM::is_laser_disc_accessed()
419 {
420         return lpd->read_signal(0);
421 }
422 #else
423 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
424 {
425         memory->open_disk(drv, file_path, bank);
426 }
427
428 void VM::close_floppy_disk(int drv)
429 {
430         memory->close_disk(drv);
431 }
432
433 bool VM::is_floppy_disk_inserted(int drv)
434 {
435         return memory->is_disk_inserted(drv);
436 }
437
438 void VM::is_floppy_disk_protected(int drv, bool value)
439 {
440         memory->is_disk_protected(drv, value);
441 }
442
443 bool VM::is_floppy_disk_protected(int drv)
444 {
445         return memory->is_disk_protected(drv);
446 }
447
448 uint32_t VM::is_floppy_disk_accessed()
449 {
450         return memory->read_signal(0);
451 }
452 #endif
453
454 bool VM::is_frame_skippable()
455 {
456         return event->is_frame_skippable();
457 }
458
459 void VM::update_config()
460 {
461         for(DEVICE* device = first_device; device; device = device->next_device) {
462                 device->update_config();
463         }
464 }
465
466 #define STATE_VERSION   4
467
468 void VM::save_state(FILEIO* state_fio)
469 {
470         state_fio->FputUint32(STATE_VERSION);
471         
472         for(DEVICE* device = first_device; device; device = device->next_device) {
473                 device->save_state(state_fio);
474         }
475 }
476
477 bool VM::load_state(FILEIO* state_fio)
478 {
479         if(state_fio->FgetUint32() != STATE_VERSION) {
480                 return false;
481         }
482         for(DEVICE* device = first_device; device; device = device->next_device) {
483                 if(!device->load_state(state_fio)) {
484                         return false;
485                 }
486         }
487         return true;
488 }
489