OSDN Git Service

[VM][STATE] Apply new framework to some VMs.
[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 PASOPIA_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 #if defined(__GIT_REPO_VERSION)
187         strncpy(_git_revision, __GIT_REPO_VERSION, sizeof(_git_revision) - 1);
188 #endif
189         for(DEVICE* device = first_device; device; device = device->next_device) {
190                 device->initialize();
191         }
192         for(int i = 0; i < 4; i++) {
193                 fdc->set_drive_type(i, DRIVE_TYPE_2D);
194         }
195 }
196
197 VM::~VM()
198 {
199         // delete all devices
200         for(DEVICE* device = first_device; device;) {
201                 DEVICE *next_device = device->next_device;
202                 device->release();
203                 delete device;
204                 device = next_device;
205         }
206 }
207
208 DEVICE* VM::get_device(int id)
209 {
210         for(DEVICE* device = first_device; device; device = device->next_device) {
211                 if(device->this_device_id == id) {
212                         return device;
213                 }
214         }
215         return NULL;
216 }
217
218 // ----------------------------------------------------------------------------
219 // drive virtual machine
220 // ----------------------------------------------------------------------------
221
222 void VM::reset()
223 {
224         // reset all devices
225         for(DEVICE* device = first_device; device; device = device->next_device) {
226                 device->reset();
227         }
228         
229         // set initial port status
230 #ifdef _LCD
231         pio1->write_signal(SIG_I8255_PORT_B, 0, 0x10);
232 #else
233         pio1->write_signal(SIG_I8255_PORT_B, 0xffffffff, 0x10);
234 #endif
235         pcm->write_signal(SIG_PCM1BIT_ON, 0, 1);
236 }
237
238 void VM::run()
239 {
240         event->drive();
241 }
242
243 double VM::get_frame_rate()
244 {
245         return event->get_frame_rate();
246 }
247
248 // ----------------------------------------------------------------------------
249 // debugger
250 // ----------------------------------------------------------------------------
251
252 #ifdef USE_DEBUGGER
253 DEVICE *VM::get_cpu(int index)
254 {
255         if(index == 0) {
256                 return cpu;
257         }
258         return NULL;
259 }
260 #endif
261
262 // ----------------------------------------------------------------------------
263 // draw screen
264 // ----------------------------------------------------------------------------
265
266 void VM::draw_screen()
267 {
268         display->draw_screen();
269 }
270
271 // ----------------------------------------------------------------------------
272 // soud manager
273 // ----------------------------------------------------------------------------
274
275 void VM::initialize_sound(int rate, int samples)
276 {
277         // init sound manager
278         event->initialize_sound(rate, samples);
279         
280         // init sound gen
281         pcm->initialize_sound(rate, 8000);
282 }
283
284 uint16_t* VM::create_sound(int* extra_frames)
285 {
286         return event->create_sound(extra_frames);
287 }
288
289 int VM::get_sound_buffer_ptr()
290 {
291         return event->get_sound_buffer_ptr();
292 }
293
294 #ifdef USE_SOUND_VOLUME
295 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
296 {
297         if(ch == 0) {
298                 pcm->set_volume(0, decibel_l, decibel_r);
299         } else if(ch == 1) {
300                 drec->set_volume(0, decibel_l, decibel_r);
301         } else if(ch == 2) {
302                 fdc->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
303                 fdc->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
304                 fdc->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
305         } else if(ch == 3) {
306                 drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
307                 drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
308                 drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
309         }
310 }
311 #endif
312
313 // ----------------------------------------------------------------------------
314 // user interface
315 // ----------------------------------------------------------------------------
316
317 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
318 {
319         fdc->open_disk(drv, file_path, bank);
320 }
321
322 void VM::close_floppy_disk(int drv)
323 {
324         fdc->close_disk(drv);
325 }
326
327 bool VM::is_floppy_disk_inserted(int drv)
328 {
329         return fdc->is_disk_inserted(drv);
330 }
331
332 void VM::is_floppy_disk_protected(int drv, bool value)
333 {
334         fdc->is_disk_protected(drv, value);
335 }
336
337 bool VM::is_floppy_disk_protected(int drv)
338 {
339         return fdc->is_disk_protected(drv);
340 }
341
342 uint32_t VM::is_floppy_disk_accessed()
343 {
344         return fdc->read_signal(0);
345 }
346
347 void VM::play_tape(int drv, const _TCHAR* file_path)
348 {
349         drec->play_tape(file_path);
350 //      drec->set_remote(true);
351 }
352
353 void VM::rec_tape(int drv, const _TCHAR* file_path)
354 {
355         drec->rec_tape(file_path);
356 //      drec->set_remote(true);
357 }
358
359 void VM::close_tape(int drv)
360 {
361         emu->lock_vm();
362         drec->close_tape();
363         emu->unlock_vm();
364 //      drec->set_remote(false);
365 }
366
367 bool VM::is_tape_inserted(int drv)
368 {
369         return drec->is_tape_inserted();
370 }
371
372 bool VM::is_tape_playing(int drv)
373 {
374         return drec->is_tape_playing();
375 }
376
377 bool VM::is_tape_recording(int drv)
378 {
379         return drec->is_tape_recording();
380 }
381
382 int VM::get_tape_position(int drv)
383 {
384         return drec->get_tape_position();
385 }
386
387 const _TCHAR* VM::get_tape_message(int drv)
388 {
389         return drec->get_message();
390 }
391
392 void VM::push_play(int drv)
393 {
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_ff_rew(1);
406         drec->set_remote(true);
407 }
408
409 void VM::push_fast_rewind(int drv)
410 {
411         drec->set_ff_rew(-1);
412         drec->set_remote(true);
413 }
414
415 void VM::load_binary(int drv, const _TCHAR* file_path)
416 {
417         if(drv == 0) {
418                 pac2->open_rampac2(file_path);
419         }
420 }
421
422 bool VM::is_frame_skippable()
423 {
424         return event->is_frame_skippable();
425 }
426
427 void VM::update_config()
428 {
429         if(boot_mode != config.boot_mode) {
430                 // boot mode is changed !!!
431                 boot_mode = config.boot_mode;
432                 memory->load_ipl();
433                 floppy->supported = (boot_mode != MODE_OABASIC_NO_DISK);
434                 // reset virtual machine
435                 reset();
436         } else {
437                 for(DEVICE* device = first_device; device; device = device->next_device) {
438                         device->update_config();
439                 }
440         }
441 }
442
443 #define STATE_VERSION   3
444
445 bool VM::process_state(FILEIO* state_fio, bool loading)
446 {
447         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
448                 return false;
449         }
450         for(DEVICE* device = first_device; device; device = device->next_device) {
451                 // Note: typeid(foo).name is fixed by recent ABI.Not dec 6.
452                 // const char *name = typeid(*device).name();
453                 //       But, using get_device_name() instead of typeid(foo).name() 20181008 K.O
454                 const char *name = device->get_device_name();
455                 int len = strlen(name);
456                 
457                 if(!state_fio->StateCheckInt32(len)) {
458                         if(loading) {
459                                 printf("Class name len Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
460                         }
461                         return false;
462                 }
463                 if(!state_fio->StateCheckBuffer(name, len, 1)) {
464                         if(loading) {
465                                 printf("Class name Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
466                         }
467                         return false;
468                 }
469                 if(!device->process_state(state_fio, loading)) {
470                         if(loading) {
471                                 printf("Data loading Error: DEVID=%d\n", device->this_device_id);
472                         }
473                         return false;
474                 }
475         }
476         // Machine specified.
477         state_fio->StateInt32(boot_mode);
478         return true;
479 }