OSDN Git Service

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