OSDN Git Service

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