OSDN Git Service

[BUILD] Set SOVERSION and GIT hash automatically.
[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 #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         decl_state();
193         for(int i = 0; i < 4; i++) {
194                 fdc->set_drive_type(i, DRIVE_TYPE_2D);
195         }
196 }
197
198 VM::~VM()
199 {
200         // delete all devices
201         for(DEVICE* device = first_device; device;) {
202                 DEVICE *next_device = device->next_device;
203                 device->release();
204                 delete device;
205                 device = next_device;
206         }
207 }
208
209 DEVICE* VM::get_device(int id)
210 {
211         for(DEVICE* device = first_device; device; device = device->next_device) {
212                 if(device->this_device_id == id) {
213                         return device;
214                 }
215         }
216         return NULL;
217 }
218
219 // ----------------------------------------------------------------------------
220 // drive virtual machine
221 // ----------------------------------------------------------------------------
222
223 void VM::reset()
224 {
225         // reset all devices
226         for(DEVICE* device = first_device; device; device = device->next_device) {
227                 device->reset();
228         }
229         
230         // set initial port status
231 #ifdef _LCD
232         pio1->write_signal(SIG_I8255_PORT_B, 0, 0x10);
233 #else
234         pio1->write_signal(SIG_I8255_PORT_B, 0xffffffff, 0x10);
235 #endif
236         pcm->write_signal(SIG_PCM1BIT_ON, 0, 1);
237 }
238
239 void VM::run()
240 {
241         event->drive();
242 }
243
244 double VM::get_frame_rate()
245 {
246         return event->get_frame_rate();
247 }
248
249 // ----------------------------------------------------------------------------
250 // debugger
251 // ----------------------------------------------------------------------------
252
253 #ifdef USE_DEBUGGER
254 DEVICE *VM::get_cpu(int index)
255 {
256         if(index == 0) {
257                 return cpu;
258         }
259         return NULL;
260 }
261 #endif
262
263 // ----------------------------------------------------------------------------
264 // draw screen
265 // ----------------------------------------------------------------------------
266
267 void VM::draw_screen()
268 {
269         display->draw_screen();
270 }
271
272 // ----------------------------------------------------------------------------
273 // soud manager
274 // ----------------------------------------------------------------------------
275
276 void VM::initialize_sound(int rate, int samples)
277 {
278         // init sound manager
279         event->initialize_sound(rate, samples);
280         
281         // init sound gen
282         pcm->initialize_sound(rate, 8000);
283 }
284
285 uint16_t* VM::create_sound(int* extra_frames)
286 {
287         return event->create_sound(extra_frames);
288 }
289
290 int VM::get_sound_buffer_ptr()
291 {
292         return event->get_sound_buffer_ptr();
293 }
294
295 #ifdef USE_SOUND_VOLUME
296 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
297 {
298         if(ch == 0) {
299                 pcm->set_volume(0, decibel_l, decibel_r);
300         } else if(ch == 1) {
301                 drec->set_volume(0, decibel_l, decibel_r);
302         } else if(ch == 2) {
303                 fdc->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
304                 fdc->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
305                 fdc->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
306         } else if(ch == 3) {
307                 drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
308                 drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
309                 drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
310         }
311 }
312 #endif
313
314 // ----------------------------------------------------------------------------
315 // user interface
316 // ----------------------------------------------------------------------------
317
318 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
319 {
320         fdc->open_disk(drv, file_path, bank);
321 }
322
323 void VM::close_floppy_disk(int drv)
324 {
325         fdc->close_disk(drv);
326 }
327
328 bool VM::is_floppy_disk_inserted(int drv)
329 {
330         return fdc->is_disk_inserted(drv);
331 }
332
333 void VM::is_floppy_disk_protected(int drv, bool value)
334 {
335         fdc->is_disk_protected(drv, value);
336 }
337
338 bool VM::is_floppy_disk_protected(int drv)
339 {
340         return fdc->is_disk_protected(drv);
341 }
342
343 uint32_t VM::is_floppy_disk_accessed()
344 {
345         return fdc->read_signal(0);
346 }
347
348 void VM::play_tape(int drv, const _TCHAR* file_path)
349 {
350         drec->play_tape(file_path);
351 //      drec->set_remote(true);
352 }
353
354 void VM::rec_tape(int drv, const _TCHAR* file_path)
355 {
356         drec->rec_tape(file_path);
357 //      drec->set_remote(true);
358 }
359
360 void VM::close_tape(int drv)
361 {
362         emu->lock_vm();
363         drec->close_tape();
364         emu->unlock_vm();
365 //      drec->set_remote(false);
366 }
367
368 bool VM::is_tape_inserted(int drv)
369 {
370         return drec->is_tape_inserted();
371 }
372
373 bool VM::is_tape_playing(int drv)
374 {
375         return drec->is_tape_playing();
376 }
377
378 bool VM::is_tape_recording(int drv)
379 {
380         return drec->is_tape_recording();
381 }
382
383 int VM::get_tape_position(int drv)
384 {
385         return drec->get_tape_position();
386 }
387
388 const _TCHAR* VM::get_tape_message(int drv)
389 {
390         return drec->get_message();
391 }
392
393 void VM::push_play(int drv)
394 {
395         drec->set_ff_rew(0);
396         drec->set_remote(true);
397 }
398
399 void VM::push_stop(int drv)
400 {
401         drec->set_remote(false);
402 }
403
404 void VM::push_fast_forward(int drv)
405 {
406         drec->set_ff_rew(1);
407         drec->set_remote(true);
408 }
409
410 void VM::push_fast_rewind(int drv)
411 {
412         drec->set_ff_rew(-1);
413         drec->set_remote(true);
414 }
415
416 void VM::load_binary(int drv, const _TCHAR* file_path)
417 {
418         if(drv == 0) {
419                 pac2->open_rampac2(file_path);
420         }
421 }
422
423 bool VM::is_frame_skippable()
424 {
425         return event->is_frame_skippable();
426 }
427
428 void VM::update_config()
429 {
430         if(boot_mode != config.boot_mode) {
431                 // boot mode is changed !!!
432                 boot_mode = config.boot_mode;
433                 memory->load_ipl();
434                 floppy->supported = (boot_mode != MODE_OABASIC_NO_DISK);
435                 // reset virtual machine
436                 reset();
437         } else {
438                 for(DEVICE* device = first_device; device; device = device->next_device) {
439                         device->update_config();
440                 }
441         }
442 }
443
444 #define STATE_VERSION   3
445
446 #include "../../statesub.h"
447 #include "../../qt/gui/csp_logger.h"
448 extern CSP_Logger DLL_PREFIX_I *csp_logger;
449
450 void VM::decl_state(void)
451 {
452 #if defined(_LCD)
453         state_entry = new csp_state_utils(STATE_VERSION, 0, (_TCHAR *)(_T("CSP::PASOPIA_WITH_LCD_HEAD")), csp_logger);
454 #else
455         state_entry = new csp_state_utils(STATE_VERSION, 0, (_TCHAR *)(_T("CSP::PASOPIA_HEAD")), csp_logger);
456 #endif  
457         DECL_STATE_ENTRY_INT32(boot_mode);
458         for(DEVICE* device = first_device; device; device = device->next_device) {
459                 device->decl_state();
460         }
461 }
462
463 void VM::save_state(FILEIO* state_fio)
464 {
465         //state_fio->FputUint32(STATE_VERSION);
466         
467         if(state_entry != NULL) {
468                 state_entry->save_state(state_fio);
469         }
470         for(DEVICE* device = first_device; device; device = device->next_device) {
471                 device->save_state(state_fio);
472         }
473         //state_fio->FputInt32(boot_mode);
474 }
475
476 bool VM::load_state(FILEIO* state_fio)
477 {
478         //if(state_fio->FgetUint32() != STATE_VERSION) {
479         //      return false;
480         //}
481         bool mb = false;
482         if(state_entry != NULL) {
483                 mb = state_entry->load_state(state_fio);
484         }
485         if(!mb) {
486                 emu->out_debug_log("INFO: HEADER DATA ERROR");
487                 return false;
488         }
489         for(DEVICE* device = first_device; device; device = device->next_device) {
490                 if(!device->load_state(state_fio)) {
491                         //printf("LOAD ERROR at DEVID#%d\n", device->this_device_id);
492                         return false;
493                 }
494         }
495         //boot_mode = state_fio->FgetInt32();
496         //printf("LOAD STATE OK\n");
497         return true;
498 }
499