OSDN Git Service

[VM][STATE] Remove typeid() from state data, this seems to be buggy.
[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) : emu(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         for(int i = 0; i < 4; i++) {
190                 fdc->set_drive_type(i, DRIVE_TYPE_2D);
191         }
192 }
193
194 VM::~VM()
195 {
196         // delete all devices
197         for(DEVICE* device = first_device; device;) {
198                 DEVICE *next_device = device->next_device;
199                 device->release();
200                 delete device;
201                 device = next_device;
202         }
203 }
204
205 DEVICE* VM::get_device(int id)
206 {
207         for(DEVICE* device = first_device; device; device = device->next_device) {
208                 if(device->this_device_id == id) {
209                         return device;
210                 }
211         }
212         return NULL;
213 }
214
215 // ----------------------------------------------------------------------------
216 // drive virtual machine
217 // ----------------------------------------------------------------------------
218
219 void VM::reset()
220 {
221         // reset all devices
222         for(DEVICE* device = first_device; device; device = device->next_device) {
223                 device->reset();
224         }
225         
226         // set initial port status
227 #ifdef _LCD
228         pio1->write_signal(SIG_I8255_PORT_B, 0, 0x10);
229 #else
230         pio1->write_signal(SIG_I8255_PORT_B, 0xffffffff, 0x10);
231 #endif
232         pcm->write_signal(SIG_PCM1BIT_ON, 0, 1);
233 }
234
235 void VM::run()
236 {
237         event->drive();
238 }
239
240 double VM::get_frame_rate()
241 {
242         return event->get_frame_rate();
243 }
244
245 // ----------------------------------------------------------------------------
246 // debugger
247 // ----------------------------------------------------------------------------
248
249 #ifdef USE_DEBUGGER
250 DEVICE *VM::get_cpu(int index)
251 {
252         if(index == 0) {
253                 return cpu;
254         }
255         return NULL;
256 }
257 #endif
258
259 // ----------------------------------------------------------------------------
260 // draw screen
261 // ----------------------------------------------------------------------------
262
263 void VM::draw_screen()
264 {
265         display->draw_screen();
266 }
267
268 // ----------------------------------------------------------------------------
269 // soud manager
270 // ----------------------------------------------------------------------------
271
272 void VM::initialize_sound(int rate, int samples)
273 {
274         // init sound manager
275         event->initialize_sound(rate, samples);
276         
277         // init sound gen
278         pcm->initialize_sound(rate, 8000);
279 }
280
281 uint16_t* VM::create_sound(int* extra_frames)
282 {
283         return event->create_sound(extra_frames);
284 }
285
286 int VM::get_sound_buffer_ptr()
287 {
288         return event->get_sound_buffer_ptr();
289 }
290
291 #ifdef USE_SOUND_VOLUME
292 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
293 {
294         if(ch == 0) {
295                 pcm->set_volume(0, decibel_l, decibel_r);
296         } else if(ch == 1) {
297                 drec->set_volume(0, decibel_l, decibel_r);
298         } else if(ch == 2) {
299                 fdc->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
300                 fdc->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
301                 fdc->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
302         } else if(ch == 3) {
303                 drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
304                 drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
305                 drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
306         }
307 }
308 #endif
309
310 // ----------------------------------------------------------------------------
311 // user interface
312 // ----------------------------------------------------------------------------
313
314 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
315 {
316         fdc->open_disk(drv, file_path, bank);
317 }
318
319 void VM::close_floppy_disk(int drv)
320 {
321         fdc->close_disk(drv);
322 }
323
324 bool VM::is_floppy_disk_inserted(int drv)
325 {
326         return fdc->is_disk_inserted(drv);
327 }
328
329 void VM::is_floppy_disk_protected(int drv, bool value)
330 {
331         fdc->is_disk_protected(drv, value);
332 }
333
334 bool VM::is_floppy_disk_protected(int drv)
335 {
336         return fdc->is_disk_protected(drv);
337 }
338
339 uint32_t VM::is_floppy_disk_accessed()
340 {
341         return fdc->read_signal(0);
342 }
343
344 void VM::play_tape(int drv, const _TCHAR* file_path)
345 {
346         drec->play_tape(file_path);
347 }
348
349 void VM::rec_tape(int drv, const _TCHAR* file_path)
350 {
351         drec->rec_tape(file_path);
352 }
353
354 void VM::close_tape(int drv)
355 {
356         emu->lock_vm();
357         drec->close_tape();
358         emu->unlock_vm();
359 }
360
361 bool VM::is_tape_inserted(int drv)
362 {
363         return drec->is_tape_inserted();
364 }
365
366 bool VM::is_tape_playing(int drv)
367 {
368         return drec->is_tape_playing();
369 }
370
371 bool VM::is_tape_recording(int drv)
372 {
373         return drec->is_tape_recording();
374 }
375
376 int VM::get_tape_position(int drv)
377 {
378         return drec->get_tape_position();
379 }
380
381 const _TCHAR* VM::get_tape_message(int drv)
382 {
383         return drec->get_message();
384 }
385
386 void VM::load_binary(int drv, const _TCHAR* file_path)
387 {
388         if(drv == 0) {
389                 pac2->open_rampac2(file_path);
390         }
391 }
392
393 bool VM::is_frame_skippable()
394 {
395         return event->is_frame_skippable();
396 }
397
398 void VM::update_config()
399 {
400         if(boot_mode != config.boot_mode) {
401                 // boot mode is changed !!!
402                 boot_mode = config.boot_mode;
403                 memory->load_ipl();
404                 floppy->supported = (boot_mode != MODE_OABASIC_NO_DISK);
405                 // reset virtual machine
406                 reset();
407         } else {
408                 for(DEVICE* device = first_device; device; device = device->next_device) {
409                         device->update_config();
410                 }
411         }
412 }
413
414 #define STATE_VERSION   3
415
416 void VM::save_state(FILEIO* state_fio)
417 {
418         state_fio->FputUint32(STATE_VERSION);
419         
420         for(DEVICE* device = first_device; device; device = device->next_device) {
421                 device->save_state(state_fio);
422         }
423         state_fio->FputInt32(boot_mode);
424 }
425
426 bool VM::load_state(FILEIO* state_fio)
427 {
428         if(state_fio->FgetUint32() != STATE_VERSION) {
429                 return false;
430         }
431         for(DEVICE* device = first_device; device; device = device->next_device) {
432                 if(!device->load_state(state_fio)) {
433                         return false;
434                 }
435         }
436         boot_mode = state_fio->FgetInt32();
437         return true;
438 }
439