OSDN Git Service

543db29cd6339d433cfa4adf2799ea2147508ab7
[csp-qt/common_source_project-fm7.git] / source / src / vm / pasopia / pasopia.cpp
1 /*
2         TOSHIBA PASOPIA Emulator 'EmuPIA'
3
4         Author : Takeda.Toshiya
5         Date   : 2006.12.28 -
6
7         [ virtual machine ]
8 */
9
10 #include "pasopia.h"
11 #include "../../emu.h"
12 #include "../device.h"
13 #include "../event.h"
14
15 #include "../datarec.h"
16 #include "../disk.h"
17 #include "../hd46505.h"
18 #include "../i8255.h"
19 #include "../io.h"
20 #include "../ls393.h"
21 #include "../noise.h"
22 #include "../not.h"
23 #include "../pcm1bit.h"
24 #include "../upd765a.h"
25 #include "../z80.h"
26 #include "../z80ctc.h"
27 #include "../z80pio.h"
28
29 #ifdef USE_DEBUGGER
30 #include "../debugger.h"
31 #endif
32
33 #include "floppy.h"
34 #include "display.h"
35 #include "keyboard.h"
36 #include "memory.h"
37 #include "pac2.h"
38
39 // ----------------------------------------------------------------------------
40 // initialize
41 // ----------------------------------------------------------------------------
42
43 VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
44 {
45         boot_mode = config.boot_mode;
46         
47         // create devices
48         first_device = last_device = NULL;
49         dummy = new DEVICE(this, emu);  // must be 1st device
50         event = new EVENT(this, emu);   // must be 2nd device
51         dummy->set_device_name(_T("1st Dummy"));
52         
53         drec = new DATAREC(this, emu);
54         drec->set_context_noise_play(new NOISE(this, emu));
55         drec->set_context_noise_stop(new NOISE(this, emu));
56         drec->set_context_noise_fast(new NOISE(this, emu));
57         crtc = new HD46505(this, emu);
58         pio0 = new I8255(this, emu);
59         pio0->set_device_name(_T("8255 PIO (Memory)"));
60         pio1 = new I8255(this, emu);
61         pio1->set_device_name(_T("8255 PIO (Memory/Display)"));
62         pio2 = new I8255(this, emu);
63         pio2->set_device_name(_T("8255 PIO (Sound/Data Recorder)"));
64         io = new IO(this, emu);
65         flipflop = new LS393(this, emu); // LS74
66         not_remote = new NOT(this, emu);
67         pcm = new PCM1BIT(this, emu);
68         fdc = new UPD765A(this, emu);
69         fdc->set_context_noise_seek(new NOISE(this, emu));
70         fdc->set_context_noise_head_down(new NOISE(this, emu));
71         fdc->set_context_noise_head_up(new NOISE(this, emu));
72         cpu = new Z80(this, emu);
73         ctc = new Z80CTC(this, emu);
74         pio = new Z80PIO(this, emu);
75         
76         floppy = new FLOPPY(this, emu);
77         display = new DISPLAY(this, emu);
78         key = new KEYBOARD(this, emu);
79         memory = new MEMORY(this, emu);
80         pac2 = new PAC2(this, emu);
81         // set contexts
82         event->set_context_cpu(cpu);
83         event->set_context_sound(pcm);
84         event->set_context_sound(drec);
85         event->set_context_sound(fdc->get_context_noise_seek());
86         event->set_context_sound(fdc->get_context_noise_head_down());
87         event->set_context_sound(fdc->get_context_noise_head_up());
88         event->set_context_sound(drec->get_context_noise_play());
89         event->set_context_sound(drec->get_context_noise_stop());
90         event->set_context_sound(drec->get_context_noise_fast());
91         
92         drec->set_context_ear(pio2, SIG_I8255_PORT_B, 0x20);
93         crtc->set_context_disp(pio1, SIG_I8255_PORT_B, 8);
94         crtc->set_context_vsync(pio1, SIG_I8255_PORT_B, 0x20);
95         crtc->set_context_hsync(pio1, SIG_I8255_PORT_B, 0x40);
96         pio0->set_context_port_a(memory, SIG_MEMORY_I8255_0_A, 0xff, 0);
97         pio0->set_context_port_b(memory, SIG_MEMORY_I8255_0_B, 0xff, 0);
98         pio1->set_context_port_a(display, SIG_DISPLAY_I8255_1_A, 0xff, 0);
99         pio1->set_context_port_c(memory, SIG_MEMORY_I8255_1_C, 0xff, 0);
100         pio2->set_context_port_a(pcm, SIG_PCM1BIT_MUTE, 0x02, 0);
101         pio2->set_context_port_a(drec, SIG_DATAREC_MIC, 0x10, 0);
102         pio2->set_context_port_a(not_remote, SIG_NOT_INPUT, 0x20, 0);
103         flipflop->set_context_1qa(pcm, SIG_PCM1BIT_SIGNAL, 1);
104         not_remote->set_context_out(drec, SIG_DATAREC_REMOTE, 1);
105         fdc->set_context_irq(floppy, SIG_FLOPPY_INTR, 1);
106         ctc->set_context_zc1(flipflop, SIG_LS393_CLK, 1);
107         ctc->set_context_zc2(ctc, SIG_Z80CTC_TRIG_3, 1);
108         ctc->set_constant_clock(0, CPU_CLOCKS);
109         ctc->set_constant_clock(1, CPU_CLOCKS);
110         ctc->set_constant_clock(2, CPU_CLOCKS);
111         pio->set_context_port_a(pcm, SIG_PCM1BIT_ON, 0x80, 0);
112         pio->set_context_port_a(key, SIG_KEYBOARD_Z80PIO_A, 0xff, 0);
113         
114         display->set_context_crtc(crtc);
115         display->set_vram_ptr(memory->get_vram());
116         display->set_attr_ptr(memory->get_attr());
117         display->set_regs_ptr(crtc->get_regs());
118         floppy->set_context_fdc(fdc);
119         floppy->supported = (boot_mode != MODE_OABASIC_NO_DISK);
120         key->set_context_pio(pio);
121         memory->set_context_pio0(pio0);
122         memory->set_context_pio1(pio1);
123         memory->set_context_pio2(pio2);
124         
125         // cpu bus
126         cpu->set_context_mem(memory);
127         cpu->set_context_io(io);
128         cpu->set_context_intr(ctc);
129 #ifdef USE_DEBUGGER
130         cpu->set_context_debugger(new DEBUGGER(this, emu));
131 #endif
132         
133         // z80 family daisy chain
134         ctc->set_context_intr(cpu, 0);
135         ctc->set_context_child(pio);
136         pio->set_context_intr(cpu, 1);
137 /*
138 pio0    0       8255    vram laddr
139         1       8255    vram data
140         2       8255
141         3       8255
142 pio1    8       8255    crtc mode
143         9       8255    
144         a       8255    vram addr, attrib & strobe
145         b       8255
146         10      crtc    index
147         11      crtc    regs
148         18      pac2
149         19      pac2
150         1a      pac2
151         1b      pac2
152 pio2    20      8255    out cmt, sound
153         21      8255    in cmt
154         22      8255    in memory map
155         23      8255
156         28      z80ctc
157         29      z80ctc
158         2a      z80ctc
159         2b      z80ctc
160         30      z80pio
161         31      z80pio
162         32      z80pio
163         33      z80pio
164         38      printer
165         3c      memory  out memory map
166 */
167         // i/o bus
168         io->set_iomap_range_rw(0x00, 0x03, pio0);
169         io->set_iomap_range_rw(0x08, 0x0b, pio1);
170         io->set_iomap_range_r(0x10, 0x11, crtc);
171         io->set_iomap_range_w(0x10, 0x11, display);
172         io->set_iomap_range_rw(0x18, 0x1b, pac2);
173         io->set_iomap_range_rw(0x20, 0x23, pio2);
174         io->set_iomap_range_rw(0x28, 0x2b, ctc);
175         io->set_iomap_alias_rw(0x30, pio, 0);
176         io->set_iomap_alias_rw(0x31, pio, 2);
177         io->set_iomap_alias_w(0x32, pio, 1);
178         io->set_iomap_alias_w(0x33, pio, 3);
179         io->set_iomap_single_w(0x3c, memory);
180         io->set_iomap_single_w(0xe0, floppy);
181         io->set_iomap_single_w(0xe2, floppy);
182         io->set_iomap_range_rw(0xe4, 0xe5, floppy);
183         io->set_iomap_single_rw(0xe6, floppy);
184         
185         // initialize all devices
186         for(DEVICE* device = first_device; device; device = device->next_device) {
187                 device->initialize();
188         }
189         decl_state();
190         for(int i = 0; i < 4; i++) {
191                 fdc->set_drive_type(i, DRIVE_TYPE_2D);
192         }
193 }
194
195 VM::~VM()
196 {
197         // delete all devices
198         for(DEVICE* device = first_device; device;) {
199                 DEVICE *next_device = device->next_device;
200                 device->release();
201                 delete device;
202                 device = next_device;
203         }
204 }
205
206 DEVICE* VM::get_device(int id)
207 {
208         for(DEVICE* device = first_device; device; device = device->next_device) {
209                 if(device->this_device_id == id) {
210                         return device;
211                 }
212         }
213         return NULL;
214 }
215
216 // ----------------------------------------------------------------------------
217 // drive virtual machine
218 // ----------------------------------------------------------------------------
219
220 void VM::reset()
221 {
222         // reset all devices
223         for(DEVICE* device = first_device; device; device = device->next_device) {
224                 device->reset();
225         }
226         
227         // set initial port status
228 #ifdef _LCD
229         pio1->write_signal(SIG_I8255_PORT_B, 0, 0x10);
230 #else
231         pio1->write_signal(SIG_I8255_PORT_B, 0xffffffff, 0x10);
232 #endif
233         pcm->write_signal(SIG_PCM1BIT_ON, 0, 1);
234 }
235
236 void VM::run()
237 {
238         event->drive();
239 }
240
241 double VM::get_frame_rate()
242 {
243         return event->get_frame_rate();
244 }
245
246 // ----------------------------------------------------------------------------
247 // debugger
248 // ----------------------------------------------------------------------------
249
250 #ifdef USE_DEBUGGER
251 DEVICE *VM::get_cpu(int index)
252 {
253         if(index == 0) {
254                 return cpu;
255         }
256         return NULL;
257 }
258 #endif
259
260 // ----------------------------------------------------------------------------
261 // draw screen
262 // ----------------------------------------------------------------------------
263
264 void VM::draw_screen()
265 {
266         display->draw_screen();
267 }
268
269 // ----------------------------------------------------------------------------
270 // soud manager
271 // ----------------------------------------------------------------------------
272
273 void VM::initialize_sound(int rate, int samples)
274 {
275         // init sound manager
276         event->initialize_sound(rate, samples);
277         
278         // init sound gen
279         pcm->initialize_sound(rate, 8000);
280 }
281
282 uint16_t* VM::create_sound(int* extra_frames)
283 {
284         return event->create_sound(extra_frames);
285 }
286
287 int VM::get_sound_buffer_ptr()
288 {
289         return event->get_sound_buffer_ptr();
290 }
291
292 #ifdef USE_SOUND_VOLUME
293 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
294 {
295         if(ch == 0) {
296                 pcm->set_volume(0, decibel_l, decibel_r);
297         } else if(ch == 1) {
298                 drec->set_volume(0, decibel_l, decibel_r);
299         } else if(ch == 2) {
300                 fdc->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
301                 fdc->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
302                 fdc->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
303         } else if(ch == 3) {
304                 drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
305                 drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
306                 drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
307         }
308 }
309 #endif
310
311 // ----------------------------------------------------------------------------
312 // user interface
313 // ----------------------------------------------------------------------------
314
315 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
316 {
317         fdc->open_disk(drv, file_path, bank);
318 }
319
320 void VM::close_floppy_disk(int drv)
321 {
322         fdc->close_disk(drv);
323 }
324
325 bool VM::is_floppy_disk_inserted(int drv)
326 {
327         return fdc->is_disk_inserted(drv);
328 }
329
330 void VM::is_floppy_disk_protected(int drv, bool value)
331 {
332         fdc->is_disk_protected(drv, value);
333 }
334
335 bool VM::is_floppy_disk_protected(int drv)
336 {
337         return fdc->is_disk_protected(drv);
338 }
339
340 uint32_t VM::is_floppy_disk_accessed()
341 {
342         return fdc->read_signal(0);
343 }
344
345 void VM::play_tape(int drv, const _TCHAR* file_path)
346 {
347         drec->play_tape(file_path);
348 //      drec->set_remote(true);
349 }
350
351 void VM::rec_tape(int drv, const _TCHAR* file_path)
352 {
353         drec->rec_tape(file_path);
354 //      drec->set_remote(true);
355 }
356
357 void VM::close_tape(int drv)
358 {
359         emu->lock_vm();
360         drec->close_tape();
361         emu->unlock_vm();
362 //      drec->set_remote(false);
363 }
364
365 bool VM::is_tape_inserted(int drv)
366 {
367         return drec->is_tape_inserted();
368 }
369
370 bool VM::is_tape_playing(int drv)
371 {
372         return drec->is_tape_playing();
373 }
374
375 bool VM::is_tape_recording(int drv)
376 {
377         return drec->is_tape_recording();
378 }
379
380 int VM::get_tape_position(int drv)
381 {
382         return drec->get_tape_position();
383 }
384
385 const _TCHAR* VM::get_tape_message(int drv)
386 {
387         return drec->get_message();
388 }
389
390 void VM::push_play(int drv)
391 {
392         drec->set_ff_rew(0);
393         drec->set_remote(true);
394 }
395
396 void VM::push_stop(int drv)
397 {
398         drec->set_remote(false);
399 }
400
401 void VM::push_fast_forward(int drv)
402 {
403         drec->set_ff_rew(1);
404         drec->set_remote(true);
405 }
406
407 void VM::push_fast_rewind(int drv)
408 {
409         drec->set_ff_rew(-1);
410         drec->set_remote(true);
411 }
412
413 void VM::load_binary(int drv, const _TCHAR* file_path)
414 {
415         if(drv == 0) {
416                 pac2->open_rampac2(file_path);
417         }
418 }
419
420 bool VM::is_frame_skippable()
421 {
422         return event->is_frame_skippable();
423 }
424
425 void VM::update_config()
426 {
427         if(boot_mode != config.boot_mode) {
428                 // boot mode is changed !!!
429                 boot_mode = config.boot_mode;
430                 memory->load_ipl();
431                 floppy->supported = (boot_mode != MODE_OABASIC_NO_DISK);
432                 // reset virtual machine
433                 reset();
434         } else {
435                 for(DEVICE* device = first_device; device; device = device->next_device) {
436                         device->update_config();
437                 }
438         }
439 }
440
441 #define STATE_VERSION   3
442
443 #include "../../statesub.h"
444 #include "../../qt/gui/csp_logger.h"
445 extern CSP_Logger DLL_PREFIX_I *csp_logger;
446
447 void VM::decl_state(void)
448 {
449 #if defined(_LCD)
450         state_entry = new csp_state_utils(STATE_VERSION, 0, (_TCHAR *)(_T("CSP::PASOPIA_WITH_LCD_HEAD")), csp_logger);
451 #else
452         state_entry = new csp_state_utils(STATE_VERSION, 0, (_TCHAR *)(_T("CSP::PASOPIA_HEAD")), csp_logger);
453 #endif  
454         DECL_STATE_ENTRY_INT32(boot_mode);
455         for(DEVICE* device = first_device; device; device = device->next_device) {
456                 device->decl_state();
457         }
458 }
459
460 void VM::save_state(FILEIO* state_fio)
461 {
462         //state_fio->FputUint32(STATE_VERSION);
463         
464         if(state_entry != NULL) {
465                 state_entry->save_state(state_fio);
466         }
467         for(DEVICE* device = first_device; device; device = device->next_device) {
468                 device->save_state(state_fio);
469         }
470         //state_fio->FputInt32(boot_mode);
471 }
472
473 bool VM::load_state(FILEIO* state_fio)
474 {
475         //if(state_fio->FgetUint32() != STATE_VERSION) {
476         //      return false;
477         //}
478         bool mb = false;
479         if(state_entry != NULL) {
480                 mb = state_entry->load_state(state_fio);
481         }
482         if(!mb) {
483                 emu->out_debug_log("INFO: HEADER DATA ERROR");
484                 return false;
485         }
486         for(DEVICE* device = first_device; device; device = device->next_device) {
487                 if(!device->load_state(state_fio)) {
488                         //printf("LOAD ERROR at DEVID#%d\n", device->this_device_id);
489                         return false;
490                 }
491         }
492         //boot_mode = state_fio->FgetInt32();
493         //printf("LOAD STATE OK\n");
494         return true;
495 }
496