OSDN Git Service

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