OSDN Git Service

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