OSDN Git Service

[VM][STATE] Use namespace {VMNAME} to separate per VMs.
[csp-qt/common_source_project-fm7.git] / source / src / vm / tk80bs / tk80bs.cpp
1 /*
2         NEC TK-80BS (COMPO BS/80) Emulator 'eTK-80BS'
3         NEC TK-80 Emulator 'eTK-80'
4         NEC TK-85 Emulator 'eTK-85'
5
6         Author : Takeda.Toshiya
7         Date   : 2008.08.26 -
8
9         [ virtual machine ]
10 */
11
12 #include "tk80bs.h"
13 #include "../../emu.h"
14 #include "../device.h"
15 #include "../event.h"
16
17 #include "../datarec.h"
18 #include "../i8080.h"
19 #if defined(_TK80BS)
20 #include "../i8251.h"
21 #include "../io.h"
22 #endif
23 #include "../i8255.h"
24 //#include "../memory.h"
25 #include "../noise.h"
26 #include "../pcm1bit.h"
27
28 #ifdef USE_DEBUGGER
29 #include "../debugger.h"
30 #endif
31
32 #if defined(_TK80BS) || defined(_TK80)
33 #include "cmt.h"
34 #endif
35 #include "display.h"
36 #include "keyboard.h"
37 #include "membus.h"
38
39 #if defined(_TK80BS) || defined(_TK80)
40 using TK80::CMT;
41 #endif
42 using TK80::DISPLAY;
43 using TK80::KEYBOARD;
44 using TK80::MEMBUS;
45
46 // ----------------------------------------------------------------------------
47 // initialize
48 // ----------------------------------------------------------------------------
49
50 VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
51 {
52 #if defined(_TK80BS)
53         // check configs
54 //      boot_mode = config.boot_mode;
55         boot_mode = -1;
56 #endif
57 #if defined(_TK80BS) || defined(_TK80)
58         config.wave_shaper[0] = false;
59 #endif
60
61         // create devices
62         first_device = last_device = NULL;
63         dummy = new DEVICE(this, emu);  // must be 1st device
64         dummy->set_device_name(_T("1st Dummy"));
65         event = new EVENT(this, emu);   // must be 2nd device
66         
67         cpu = new I8080(this, emu);
68 #if defined(_TK80BS)
69         sio_b = new I8251(this, emu);   // on TK-80BS
70         sio_b->set_device_name(_T("i8251 SIO (TK-80BS/CMT)"));
71         pio_b = new I8255(this, emu);
72         pio_b->set_device_name(_T("i8255 PIO (TK-80BS/DISPLAY)"));
73         memio = new IO(this, emu);
74         memio->set_device_name(_T("Memory Mapped I/O (TK-80BS)"));
75 #endif
76         drec = new DATAREC(this, emu);
77         drec->set_context_noise_play(new NOISE(this, emu));
78         drec->set_context_noise_stop(new NOISE(this, emu));
79         drec->set_context_noise_fast(new NOISE(this, emu));
80         pio_t = new I8255(this, emu);   // on TK-80
81 //      memory = new MEMORY(this, emu);
82         
83         pcm0 = new PCM1BIT(this, emu);
84         pcm0->set_device_name(_T("1-Bit PCM Sound #1"));
85         pcm1 = new PCM1BIT(this, emu);
86         pcm1->set_device_name(_T("1-Bit PCM Sound #2"));
87         
88 #if defined(_TK80BS) || defined(_TK80)
89         cmt = new CMT(this, emu);
90 #endif
91         display = new DISPLAY(this, emu);
92         keyboard = new KEYBOARD(this, emu);
93         memory = new MEMBUS(this, emu);
94 #if defined(_TK80BS)
95         pio_t->set_device_name(_T("i8255 PIO (TK-80/SOUND/KEYBOARD/DISPLAY)"));
96 #else
97         pio_t->set_device_name(_T("i8255 PIO (TK-80/SOUND/KEYBOARD)"));
98 #endif
99
100         // set contexts
101         event->set_context_cpu(cpu);
102         event->set_context_sound(pcm0);
103         event->set_context_sound(pcm1);
104         event->set_context_sound(drec);
105         event->set_context_sound(drec->get_context_noise_play());
106         event->set_context_sound(drec->get_context_noise_stop());
107         event->set_context_sound(drec->get_context_noise_fast());
108         
109 /*      8255 on TK-80
110         
111         PA      key matrix
112         PB0     serial in
113         PC0     serial out
114         PC1     sound #1
115         PC2     sound #2
116         PC4-6   key column
117         PC7     dma disable
118 */
119 #if defined(_TK80BS)
120         sio_b->set_context_out(cmt, SIG_CMT_OUT);
121         pio_b->set_context_port_c(display, SIG_DISPLAY_MODE, 3, 0);
122 #endif
123 #if defined(_TK80BS) || defined(_TK80)
124         drec->set_context_ear(cmt, SIG_CMT_EAR, 1);
125         pio_t->set_context_port_c(cmt, SIG_CMT_MIC, 1, 0);
126 #elif defined(_TK85)
127         drec->set_context_ear(cpu, SIG_I8085_SID, 1);
128         cpu->set_context_sod(drec, SIG_DATAREC_MIC, 1);
129 #endif
130         pio_t->set_context_port_c(pcm0, SIG_PCM1BIT_SIGNAL, 2, 0);
131         pio_t->set_context_port_c(pcm1, SIG_PCM1BIT_SIGNAL, 4, 0);
132         pio_t->set_context_port_c(keyboard, SIG_KEYBOARD_COLUMN, 0x70, 0);
133 #if defined(_TK80BS) || defined(_TK80)
134         pio_t->set_context_port_c(display, SIG_DISPLAY_DMA, 0x80, 0);
135 #elif defined(_TK85)
136         pio_t->set_context_port_c(memory, SIG_MEMBUS_PC7, 0x80, 0);
137 #endif
138         // Sound:: Force realtime rendering. This is temporally fix. 20161024 K.O
139         //pcm0->set_realtime_render(true);
140         //pcm1->set_realtime_render(true);
141         
142 #if defined(_TK80BS) || defined(_TK80)
143         cmt->set_context_drec(drec);
144         cmt->set_context_pio(pio_t);
145 #endif
146 #if defined(_TK80BS)
147         cmt->set_context_sio(sio_b);
148         display->set_vram_ptr(vram);
149         keyboard->set_context_pio_b(pio_b);
150         keyboard->set_context_cpu(cpu);
151 #endif
152         display->set_led_ptr(ram + 0x3f8);
153         keyboard->set_context_pio_t(pio_t);
154         memory->set_context_cpu(cpu);
155         
156         // cpu bus
157         cpu->set_context_mem(memory);
158         cpu->set_context_io(pio_t);
159         cpu->set_context_intr(keyboard);
160 #ifdef USE_DEBUGGER
161         cpu->set_context_debugger(new DEBUGGER(this, emu));
162 #endif
163         
164         // memory bus
165         memset(mon, 0xff, sizeof(mon));
166 #if defined(_TK80BS)
167         memset(bsmon, 0xff, sizeof(bsmon));
168 #endif
169         memset(ext, 0xff, sizeof(ext));
170         
171 #if defined(_TK80BS)
172         static const uint8_t top[3] = {0xc3, 0x00, 0xf0};
173         static const uint8_t rst[3] = {0xc3, 0xdd, 0x83};
174         
175         if(!memory->read_bios(_T("TK80.ROM"), mon, sizeof(mon))) {
176                 // default
177                 memcpy(mon, top, sizeof(top));
178                 memcpy(mon + 0x38, rst, sizeof(rst));
179         }
180         if(memory->read_bios(_T("BSMON.ROM"), bsmon, sizeof(bsmon))) {
181                 // patch
182                 memcpy(mon + 0x38, rst, sizeof(rst));
183         }
184 #elif defined(_TK80)
185         memory->read_bios(_T("TK80.ROM"), mon, sizeof(mon));
186 #elif defined(_TK85)
187         memory->read_bios(_T("TK85.ROM"), mon, sizeof(mon));
188 #endif
189         memory->read_bios(_T("EXT.ROM"), ext, sizeof(ext));
190         
191         memory->set_memory_r(0x0000, 0x07ff, mon);
192         memory->set_memory_r(0x0c00, 0x7bff, ext);
193 #if defined(_TK80BS)
194         memory->set_memory_mapped_io_rw(0x7c00, 0x7dff, memio);
195         memory->set_memory_rw(0x7e00, 0x7fff, vram);
196 #endif
197         memory->set_memory_rw(0x8000, 0xcfff, ram);
198 #if defined(_TK80BS)
199         memory->set_memory_r(0xd000, 0xefff, basic);
200         memory->set_memory_r(0xf000, 0xffff, bsmon);
201         
202         // memory mapped i/o
203         memio->set_iomap_alias_rw(0x7df8, sio_b, 0);
204         memio->set_iomap_alias_rw(0x7df9, sio_b, 1);
205         memio->set_iomap_alias_rw(0x7dfc, pio_b, 0);
206         memio->set_iomap_alias_rw(0x7dfd, pio_b, 1);
207         memio->set_iomap_alias_rw(0x7dfe, pio_b, 2);
208         memio->set_iomap_alias_w(0x7dff, pio_b, 3);
209 #endif
210         
211         // initialize all devices
212 #if defined(__GIT_REPO_VERSION)
213         strncpy(_git_revision, __GIT_REPO_VERSION, sizeof(_git_revision) - 1);
214 #endif
215         for(DEVICE* device = first_device; device; device = device->next_device) {
216                 device->initialize();
217         }
218 }
219
220 VM::~VM()
221 {
222         // delete all devices
223         for(DEVICE* device = first_device; device;) {
224                 DEVICE *next_device = device->next_device;
225                 device->release();
226                 delete device;
227                 device = next_device;
228         }
229 }
230
231 DEVICE* VM::get_device(int id)
232 {
233         for(DEVICE* device = first_device; device; device = device->next_device) {
234                 if(device->this_device_id == id) {
235                         return device;
236                 }
237         }
238         return NULL;
239 }
240
241 // ----------------------------------------------------------------------------
242 // drive virtual machine
243 // ----------------------------------------------------------------------------
244
245 void VM::reset()
246 {
247 #if defined(_TK80BS)
248         // load basic rom
249         if(boot_mode != config.boot_mode) {
250                 memset(basic, 0xff, sizeof(basic));
251                 if(config.boot_mode == 0) {
252                         memory->read_bios(_T("LV1BASIC.ROM"), basic + 0x1000, 0x1000);
253                 } else {
254                         memory->read_bios(_T("LV2BASIC.ROM"), basic, sizeof(basic));
255                 }
256                 boot_mode = config.boot_mode;
257                 
258                 memset(ram, 0, sizeof(ram));
259         }
260         
261         // initialize screen
262         emu->reload_bitmap();
263         draw_ranges = 8;
264         memset(vram, 0x20, sizeof(vram));
265 #endif
266         
267         // reset all devices
268         for(DEVICE* device = first_device; device; device = device->next_device) {
269                 device->reset();
270         }
271         
272         // init 8255 on TK-80
273         pio_t->write_io8(0xfb, 0x92);
274         pio_t->write_signal(SIG_I8255_PORT_A, 0xff, 0xff);
275 }
276
277 void VM::run()
278 {
279         event->drive();
280 }
281
282 // ----------------------------------------------------------------------------
283 // debugger
284 // ----------------------------------------------------------------------------
285
286 #ifdef USE_DEBUGGER
287 DEVICE *VM::get_cpu(int index)
288 {
289         if(index == 0) {
290                 return cpu;
291         }
292         return NULL;
293 }
294 #endif
295
296 // ----------------------------------------------------------------------------
297 // draw screen
298 // ----------------------------------------------------------------------------
299
300 void VM::draw_screen()
301 {
302         display->draw_screen();
303 }
304
305 #if defined(_TK80BS)
306 int VM::max_draw_ranges()
307 {
308         return draw_ranges;
309 }
310 #endif
311
312 // ----------------------------------------------------------------------------
313 // soud manager
314 // ----------------------------------------------------------------------------
315
316 void VM::initialize_sound(int rate, int samples)
317 {
318         // init sound manager
319         event->initialize_sound(rate, samples);
320         
321         // init sound gen
322         pcm0->initialize_sound(rate, 8000);
323         pcm1->initialize_sound(rate, 8000);
324 }
325
326 uint16_t* VM::create_sound(int* extra_frames)
327 {
328         return event->create_sound(extra_frames);
329 }
330
331 int VM::get_sound_buffer_ptr()
332 {
333         return event->get_sound_buffer_ptr();
334 }
335
336 #ifdef USE_SOUND_VOLUME
337 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
338 {
339         if(ch == 0) {
340                 pcm0->set_volume(0, decibel_l, decibel_r);
341         } else if(ch == 1) {
342                 pcm1->set_volume(0, decibel_l, decibel_r);
343         } else if(ch == 2) {
344                 drec->set_volume(0, decibel_l, decibel_r);
345         } else if(ch == 3) {
346                 drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
347                 drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
348                 drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
349         }
350 }
351 #endif
352
353 // ----------------------------------------------------------------------------
354 // notify key
355 // ----------------------------------------------------------------------------
356
357 void VM::key_down(int code, bool repeat)
358 {
359 #if defined(_TK85)
360         if(code == 0x97) {
361                 cpu->write_signal(SIG_CPU_NMI, 1, 1);
362                 return;
363         }
364 #endif
365         keyboard->key_down(code);
366 }
367
368 void VM::key_up(int code)
369 {
370 #if defined(_TK85)
371         if(code == 0x97) {
372                 return;
373         }
374 #endif
375         keyboard->key_up(code);
376 }
377
378 bool VM::get_caps_locked()
379 {
380         return keyboard->get_caps_locked();
381 }
382
383 bool VM::get_kana_locked()
384 {
385         return keyboard->get_kana_locked();
386 }
387
388 // ----------------------------------------------------------------------------
389 // user interface
390 // ----------------------------------------------------------------------------
391
392 void VM::load_binary(int drv, const _TCHAR* file_path)
393 {
394         if(drv == 0) {
395                 memory->read_image(file_path, ram, sizeof(ram));
396         }
397 }
398
399 void VM::save_binary(int drv, const _TCHAR* file_path)
400 {
401         if(drv == 0) {
402                 memory->write_image(file_path, ram, sizeof(ram));
403         }
404 }
405
406 void VM::play_tape(int drv, const _TCHAR* file_path)
407 {
408         if(drv == 0) {
409                 drec->play_tape(file_path);
410 //              drec->set_remote(true);
411 #if defined(_TK80BS)
412         } else if(drv == 1) {
413                 cmt->play_tape(file_path);
414 #endif
415         }
416 }
417
418 void VM::rec_tape(int drv, const _TCHAR* file_path)
419 {
420         if(drv == 0) {
421                 drec->rec_tape(file_path);
422 //              drec->set_remote(true);
423 #if defined(_TK80BS)
424         } else if(drv == 1) {
425                 cmt->rec_tape(file_path);
426 #endif
427         }
428 }
429
430 void VM::close_tape(int drv)
431 {
432         if(drv == 0) {
433                 emu->lock_vm();
434                 drec->close_tape();
435                 emu->unlock_vm();
436 //              drec->set_remote(false);
437 #if defined(_TK80BS)
438         } else if(drv == 1) {
439                 cmt->close_tape();
440 #endif
441         }
442 }
443
444 bool VM::is_tape_inserted(int drv)
445 {
446         if(drv == 0) {
447                 return drec->is_tape_inserted();
448 #if defined(_TK80BS)
449         } else if(drv == 1) {
450                 return cmt->is_tape_inserted();
451 #endif
452         }
453         return false;
454 }
455
456 bool VM::is_tape_playing(int drv)
457 {
458         if(drv == 0) {
459                 return drec->is_tape_playing();
460 #if defined(_TK80BS)
461         } else if(drv == 1) {
462                 return cmt->is_tape_playing();
463 #endif
464         }
465         return false;
466 }
467
468 bool VM::is_tape_recording(int drv)
469 {
470         if(drv == 0) {
471                 return drec->is_tape_recording();
472 #if defined(_TK80BS)
473         } else if(drv == 1) {
474                 return cmt->is_tape_recording();
475 #endif
476         }
477         return false;
478 }
479
480 int VM::get_tape_position(int drv)
481 {
482         if(drv == 0) {
483                 return drec->get_tape_position();
484 #if defined(_TK80BS)
485         } else if(drv == 1) {
486                 return cmt->get_tape_position();
487 #endif
488         }
489         return 0;
490 }
491
492 const _TCHAR* VM::get_tape_message(int drv)
493 {
494         if(drv == 0) {
495                 return drec->get_message();
496         }
497         return NULL;
498 }
499
500 void VM::push_play(int drv)
501 {
502         if(drv == 0) {
503                 drec->set_ff_rew(0);
504                 drec->set_remote(true);
505         }
506 }
507
508 void VM::push_stop(int drv)
509 {
510         if(drv == 0) {
511                 drec->set_remote(false);
512         }
513 }
514
515 void VM::push_fast_forward(int drv)
516 {
517         if(drv == 0) {
518                 drec->set_ff_rew(1);
519                 drec->set_remote(true);
520         }
521 }
522
523 void VM::push_fast_rewind(int drv)
524 {
525         if(drv == 0) {
526                 drec->set_ff_rew(-1);
527                 drec->set_remote(true);
528         }
529 }
530
531 bool VM::is_frame_skippable()
532 {
533 //      return event->is_frame_skippable();
534         return false;
535 }
536
537 void VM::update_config()
538 {
539 #if defined(_TK80BS)
540         if(boot_mode != config.boot_mode) {
541                 // boot mode is changed !!!
542 //              boot_mode = config.boot_mode;
543                 reset();
544         } else {
545 #endif
546                 for(DEVICE* device = first_device; device; device = device->next_device) {
547                         device->update_config();
548                 }
549 #if defined(_TK80BS)
550         }
551 #endif
552 }
553
554 #define STATE_VERSION   6
555
556 bool VM::process_state(FILEIO* state_fio, bool loading)
557 {
558         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
559                 return false;
560         }
561         for(DEVICE* device = first_device; device; device = device->next_device) {
562                 // Note: typeid(foo).name is fixed by recent ABI.Not dec 6.
563                 // const char *name = typeid(*device).name();
564                 //       But, using get_device_name() instead of typeid(foo).name() 20181008 K.O
565                 const char *name = device->get_device_name();
566                 int len = strlen(name);
567                 
568                 if(!state_fio->StateCheckInt32(len)) {
569                         if(loading) {
570                                 printf("Class name len Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
571                         }
572                         return false;
573                 }
574                 if(!state_fio->StateCheckBuffer(name, len, 1)) {
575                         if(loading) {
576                                 printf("Class name Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
577                         }
578                         return false;
579                 }
580                 if(!device->process_state(state_fio, loading)) {
581                         if(loading) {
582                                 printf("Data loading Error: DEVID=%d\n", device->this_device_id);
583                         }
584                         return false;
585                 }
586         }
587         // Machine specified.
588         state_fio->StateBuffer(ram, sizeof(ram), 1);
589 #if defined(_TK80BS)
590         state_fio->StateBuffer(vram, sizeof(vram), 1);
591         state_fio->StateInt32(boot_mode);
592 //      state_fio->StateInt32(draw_ranges);
593         
594         // post process
595         if(loading) {
596                 emu->reload_bitmap();
597                 draw_ranges = 8;
598         }
599 #endif
600         return true;
601 }