OSDN Git Service

[General][WIP] Merge Upstream 2017-03-11.
[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) : emu(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 #if defined(USE_SOUND_FILES)
110 #if defined(USE_FD1)
111         //if(memory->load_sound_data(MEMORY_SND_TYPE_DISK_SEEK, _T("FDDSEEK.WAV"))) {
112         //      event->set_context_sound(memory);
113         //}
114 #endif
115         //drec->load_sound_data(DATAREC_SNDFILE_EJECT, _T("CMTEJECT.WAV"));
116         drec->load_sound_data(DATAREC_SNDFILE_RELAY_ON, _T("RELAY_ON.WAV"));
117         drec->load_sound_data(DATAREC_SNDFILE_RELAY_OFF, _T("RELAYOFF.WAV"));
118 #endif
119         event->set_context_sound(drec->get_context_noise_play());
120         event->set_context_sound(drec->get_context_noise_stop());
121         event->set_context_sound(drec->get_context_noise_fast());
122         
123         drec->set_context_ear(psg, SIG_AY_3_891X_PORT_A, 0x80);
124         pio->set_context_port_a(memory, SIG_MEMORY_SEL, 0xff, 0);
125         pio->set_context_port_c(keyboard, SIG_KEYBOARD_COLUMN, 0x0f, 0);
126         pio->set_context_port_c(not_remote, SIG_NOT_INPUT, 0x10, 0);
127         not_remote->set_context_out(drec, SIG_DATAREC_REMOTE, 1);
128         pio->set_context_port_c(drec, SIG_DATAREC_MIC, 0x20, 0);
129         pio->set_context_port_c(pcm, SIG_PCM1BIT_SIGNAL, 0x80, 0);
130         psg->set_context_port_b(joystick, SIG_JOYSTICK_SEL, 0x40, 0);
131         vdp->set_context_irq(cpu, SIG_CPU_IRQ, 1);
132
133 #if defined(_PX7)
134         pio->set_context_port_c(slot2, SIG_SLOT2_MUTE, 0x10, 0);
135         ldp->set_context_exv(slot2, SIG_SLOT2_EXV, 1);
136         ldp->set_context_ack(slot2, SIG_SLOT2_ACK, 1);
137         ldp->set_context_sound(psg, SIG_AY_3_891X_PORT_A, 0x80);
138 #endif
139         joystick->set_context_psg(psg);
140 //      keyboard->set_context_cpu(cpu);
141         keyboard->set_context_pio(pio);
142         memory->set_context_slot(0, slot0);
143         memory->set_context_slot(1, slot1);
144         memory->set_context_slot(2, slot2);
145         memory->set_context_slot(3, slot3);
146 #if defined(_MSX2)
147         rtcif->set_context_rtc(rtc);
148 #endif
149 #if defined(_PX7)
150         slot2->set_context_cpu(cpu);
151         slot2->set_context_ldp(ldp);
152         slot2->set_context_vdp(vdp);
153 #endif
154         
155         // cpu bus
156         cpu->set_context_mem(memory);
157         cpu->set_context_io(io);
158         cpu->set_context_intr(dummy);
159 #if !defined(_PX7)
160         cpu->set_context_bios(memory);
161 #endif
162 #ifdef USE_DEBUGGER
163         cpu->set_context_debugger(new DEBUGGER(this, emu));
164 #endif
165         
166         // i/o bus
167 #ifdef _MSX2
168         io->set_iomap_range_rw(0xb4, 0xb5, rtcif);
169         io->set_iomap_range_rw(0x98, 0x9b, vdp);
170 #else
171         io->set_iomap_range_rw(0x98, 0x99, vdp);
172 #endif
173         io->set_iomap_range_rw(0xa8, 0xab, pio);
174         io->set_iomap_alias_w(0xa0, psg, 0);    // PSG ch
175         io->set_iomap_alias_w(0xa1, psg, 1);    // PSG data
176         io->set_iomap_alias_r(0xa2, psg, 1);    // PSG data
177         io->set_iomap_range_rw(0xfc, 0xff, memory);
178         
179         // initialize all devices
180         for(DEVICE* device = first_device; device; device = device->next_device) {
181                 device->initialize();
182         }
183 }
184
185 VM::~VM()
186 {
187         // delete all devices
188         for(DEVICE* device = first_device; device;) {
189                 DEVICE *next_device = device->next_device;
190                 device->release();
191                 delete device;
192                 device = next_device;
193         }
194 }
195
196 DEVICE* VM::get_device(int id)
197 {
198         for(DEVICE* device = first_device; device; device = device->next_device) {
199                 if(device->this_device_id == id) {
200                         return device;
201                 }
202         }
203         return NULL;
204 }
205
206 // ----------------------------------------------------------------------------
207 // drive virtual machine
208 // ----------------------------------------------------------------------------
209
210 void VM::reset()
211 {
212         // reset all devices
213         for(DEVICE* device = first_device; device; device = device->next_device) {
214                 device->reset();
215         }
216 }
217
218 void VM::run()
219 {
220         event->drive();
221 }
222
223 // ----------------------------------------------------------------------------
224 // debugger
225 // ----------------------------------------------------------------------------
226
227 #ifdef USE_DEBUGGER
228 DEVICE *VM::get_cpu(int index)
229 {
230         if(index == 0) {
231                 return cpu;
232         }
233         return NULL;
234 }
235 #endif
236
237 // ----------------------------------------------------------------------------
238 // draw screen
239 // ----------------------------------------------------------------------------
240
241 void VM::draw_screen()
242 {
243         vdp->draw_screen();
244 }
245
246 // ----------------------------------------------------------------------------
247 // soud manager
248 // ----------------------------------------------------------------------------
249
250 void VM::initialize_sound(int rate, int samples)
251 {
252         // init sound manager
253         event->initialize_sound(rate, samples);
254         
255         // init sound gen
256         psg->initialize_sound(rate, 3579545, samples, 0, 0);
257         pcm->initialize_sound(rate, 8000);
258 #if defined(_PX7)
259         ldp->initialize_sound(rate, samples);
260 #endif
261 }
262
263 uint16_t* VM::create_sound(int* extra_frames)
264 {
265         return event->create_sound(extra_frames);
266 }
267
268 int VM::get_sound_buffer_ptr()
269 {
270         return event->get_sound_buffer_ptr();
271 }
272
273 #if defined(_PX7)
274 void VM::movie_sound_callback(uint8_t *buffer, long size)
275 {
276         ldp->movie_sound_callback(buffer, size);
277 }
278 #endif
279
280 #ifdef USE_SOUND_VOLUME
281 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
282 {
283         if(ch == 0) {
284                 psg->set_volume(1, decibel_l, decibel_r);
285         } else if(ch == 1) {
286                 pcm->set_volume(0, decibel_l, decibel_r);
287         } else if(ch == 2) {
288                 drec->set_volume(0, decibel_l, decibel_r);
289 #if defined(_PX7)
290         } else if(ch == 3) {
291                 ldp->set_volume(0, decibel_l, decibel_r);
292 #endif
293 #if defined(USE_SOUND_FILES)
294 #if defined(USE_FD1)
295                 //} else if(ch == 3) {
296                 //memory->set_volume(MEMORY_SND_TYPE_FDD_SEEK, decibel_l, decibel_r);
297 #endif
298 #if defined(_PX7)
299         } else if(ch == 4) {
300                 drec->set_volume(2 + DATAREC_SNDFILE_RELAY_ON, decibel_l, decibel_r);
301                 drec->set_volume(2 + DATAREC_SNDFILE_RELAY_OFF, decibel_l, decibel_r);
302                 //drec->set_volume(2 + DATAREC_SNDFILE_EJECT, decibel_l, decibel_r);
303 #else
304         } else if(ch == 3) {
305                 drec->set_volume(2 + DATAREC_SNDFILE_RELAY_ON, decibel_l, decibel_r);
306                 drec->set_volume(2 + DATAREC_SNDFILE_RELAY_OFF, decibel_l, decibel_r);
307                 //drec->set_volume(2 + DATAREC_SNDFILE_EJECT, decibel_l, decibel_r);
308 #endif
309 #endif
310         }
311 }
312 #endif
313
314 // ----------------------------------------------------------------------------
315 // user interface
316 // ----------------------------------------------------------------------------
317
318 void VM::open_cart(int drv, const _TCHAR* file_path)
319 {
320         if(drv == 0) {
321                 slot1->open_cart(file_path);
322         } else {
323                 slot3->open_cart(file_path);
324         }
325         reset();
326 }
327
328 void VM::close_cart(int drv)
329 {
330         if(drv == 0) {
331                 slot1->close_cart();
332         } else {
333                 slot3->close_cart();
334         }
335         reset();
336 }
337
338 bool VM::is_cart_inserted(int drv)
339 {
340         if(drv == 0) {
341                 return slot1->is_cart_inserted();
342         } else {
343                 return slot3->is_cart_inserted();
344         }
345 }
346
347 void VM::play_tape(const _TCHAR* file_path)
348 {
349         drec->play_tape(file_path);
350 }
351
352 void VM::rec_tape(const _TCHAR* file_path)
353 {
354         drec->rec_tape(file_path);
355 }
356
357 void VM::close_tape()
358 {
359 #if defined(USE_SOUND_FILES)
360         //drec->write_signal(SIG_SOUNDER_ADD + DATAREC_SNDFILE_EJECT, 1, 1);
361 #endif
362         emu->lock_vm();
363         drec->close_tape();
364         emu->unlock_vm();
365 }
366
367 bool VM::is_tape_inserted()
368 {
369         return drec->is_tape_inserted();
370 }
371
372 bool VM::is_tape_playing()
373 {
374         return drec->is_tape_playing();
375 }
376
377 bool VM::is_tape_recording()
378 {
379         return drec->is_tape_recording();
380 }
381
382 int VM::get_tape_position()
383 {
384         return drec->get_tape_position();
385 }
386
387 #if defined(_PX7)
388 void VM::open_laser_disc(const _TCHAR* file_path)
389 {
390         ldp->open_disc(file_path);
391 }
392
393 void VM::close_laser_disc()
394 {
395         ldp->close_disc();
396 }
397
398 bool VM::is_laser_disc_inserted()
399 {
400         return ldp->is_disc_inserted();
401 }
402 #else
403 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
404 {
405         memory->open_disk(drv, file_path, bank);
406 }
407
408 void VM::close_floppy_disk(int drv)
409 {
410         memory->close_disk(drv);
411 }
412
413 bool VM::is_floppy_disk_inserted(int drv)
414 {
415         return memory->is_disk_inserted(drv);
416 }
417
418 void VM::is_floppy_disk_protected(int drv, bool value)
419 {
420         memory->is_disk_protected(drv, value);
421 }
422
423 bool VM::is_floppy_disk_protected(int drv)
424 {
425         return memory->is_disk_protected(drv);
426 }
427 #endif
428
429 bool VM::is_frame_skippable()
430 {
431         return event->is_frame_skippable();
432 }
433
434 void VM::update_config()
435 {
436         for(DEVICE* device = first_device; device; device = device->next_device) {
437                 device->update_config();
438         }
439 }
440
441 #define STATE_VERSION   3
442
443 void VM::save_state(FILEIO* state_fio)
444 {
445         state_fio->FputUint32(STATE_VERSION);
446         
447         for(DEVICE* device = first_device; device; device = device->next_device) {
448                 device->save_state(state_fio);
449         }
450 }
451
452 bool VM::load_state(FILEIO* state_fio)
453 {
454         if(state_fio->FgetUint32() != STATE_VERSION) {
455                 return false;
456         }
457         for(DEVICE* device = first_device; device; device = device->next_device) {
458                 if(!device->load_state(state_fio)) {
459                         return false;
460                 }
461         }
462         return true;
463 }
464