OSDN Git Service

[VM][General] Merge upstream 2016-03-01. (Pahse 1).
[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
4         Author : Takeda.Toshiya
5         Date   : 2008.08.26 -
6
7         [ virtual machine ]
8 */
9
10 #include "tk80bs.h"
11 #include "../../emu.h"
12 #include "../device.h"
13 #include "../event.h"
14
15 #include "../i8080.h"
16 #include "../i8251.h"
17 #include "../i8255.h"
18 #include "../io.h"
19 #include "../memory.h"
20 #include "../pcm1bit.h"
21
22 #ifdef USE_DEBUGGER
23 #include "../debugger.h"
24 #endif
25
26 #include "cmt.h"
27 #include "display.h"
28 #include "keyboard.h"
29
30 // ----------------------------------------------------------------------------
31 // initialize
32 // ----------------------------------------------------------------------------
33
34 VM::VM(EMU* parent_emu) : emu(parent_emu)
35 {
36         // check configs
37 //      boot_mode = config.boot_mode;
38         boot_mode = -1;
39         
40         // create devices
41         first_device = last_device = NULL;
42         dummy = new DEVICE(this, emu);  // must be 1st device
43         event = new EVENT(this, emu);   // must be 2nd device
44         
45         sio_b = new I8251(this, emu);   // on TK-80BS
46         pio_b = new I8255(this, emu);
47         pio_t = new I8255(this, emu);   // on TK-80
48         memio = new IO(this, emu);
49         memory = new MEMORY(this, emu);
50         pcm0 = new PCM1BIT(this, emu);
51         pcm1 = new PCM1BIT(this, emu);
52         cpu = new I8080(this, emu);
53         
54         cmt = new CMT(this, emu);
55         display = new DISPLAY(this, emu);
56         keyboard = new KEYBOARD(this, emu);
57         
58         // set contexts
59         event->set_context_cpu(cpu);
60         event->set_context_sound(pcm0);
61         event->set_context_sound(pcm1);
62         
63 /*      8255 on TK-80
64         
65         PA      key matrix
66         PB0     serial in
67         PC0     serial out
68         PC1     sound #1
69         PC2     sound #2
70         PC4-6   key column
71         PC7     dma disable
72 */
73         sio_b->set_context_out(cmt, SIG_CMT_OUT);
74         pio_b->set_context_port_c(display, SIG_DISPLAY_MODE, 3, 0);
75         pio_t->set_context_port_c(pcm0, SIG_PCM1BIT_SIGNAL, 2, 0);
76         pio_t->set_context_port_c(pcm1, SIG_PCM1BIT_SIGNAL, 4, 0);
77         pio_t->set_context_port_c(keyboard, SIG_KEYBOARD_COLUMN, 0x70, 0);
78         pio_t->set_context_port_c(display, SIG_DISPLAY_DMA, 0x80, 0);
79         
80         cmt->set_context_sio(sio_b);
81         display->set_context_key(keyboard);
82         display->set_vram_ptr(vram);
83         display->set_led_ptr(ram + 0x3f8);
84         keyboard->set_context_pio_b(pio_b);
85         keyboard->set_context_pio_t(pio_t);
86         keyboard->set_context_cpu(cpu);
87         
88         // cpu bus
89         cpu->set_context_mem(memory);
90         cpu->set_context_io(pio_t);
91         cpu->set_context_intr(keyboard);
92 #ifdef USE_DEBUGGER
93         cpu->set_context_debugger(new DEBUGGER(this, emu));
94 #endif
95         
96         // memory bus
97         memset(mon, 0xff, sizeof(mon));
98         memset(bsmon, 0xff, sizeof(bsmon));
99         memset(ext, 0xff, sizeof(ext));
100         
101         static const uint8_t top[3] = {0xc3, 0x00, 0xf0};
102         static const uint8_t rst[3] = {0xc3, 0xdd, 0x83};
103         
104         if(!memory->read_bios(_T("TK80.ROM"), mon, sizeof(mon))) {
105                 // default
106                 memcpy(mon, top, sizeof(top));
107                 memcpy(mon + 0x38, rst, sizeof(rst));
108         }
109         if(memory->read_bios(_T("BSMON.ROM"), bsmon, sizeof(bsmon))) {
110                 // patch
111                 memcpy(mon + 0x38, rst, sizeof(rst));
112         }
113         memory->read_bios(_T("EXT.ROM"), ext, sizeof(ext));
114         
115         memory->set_memory_r(0x0000, 0x07ff, mon);
116         memory->set_memory_r(0x0c00, 0x7bff, ext);
117         memory->set_memory_mapped_io_rw(0x7c00, 0x7dff, memio);
118         memory->set_memory_rw(0x7e00, 0x7fff, vram);
119         memory->set_memory_rw(0x8000, 0xcfff, ram);
120         memory->set_memory_r(0xd000, 0xefff, basic);
121         memory->set_memory_r(0xf000, 0xffff, bsmon);
122         
123         // memory mapped i/o
124         memio->set_iomap_alias_rw(0x7df8, sio_b, 0);
125         memio->set_iomap_alias_rw(0x7df9, sio_b, 1);
126         memio->set_iomap_alias_rw(0x7dfc, pio_b, 0);
127         memio->set_iomap_alias_rw(0x7dfd, pio_b, 1);
128         memio->set_iomap_alias_rw(0x7dfe, pio_b, 2);
129         memio->set_iomap_alias_w(0x7dff, pio_b, 3);
130         
131         // initialize all devices
132         for(DEVICE* device = first_device; device; device = device->next_device) {
133                 device->initialize();
134         }
135 }
136
137 VM::~VM()
138 {
139         // delete all devices
140         for(DEVICE* device = first_device; device;) {
141                 DEVICE *next_device = device->next_device;
142                 device->release();
143                 delete device;
144                 device = next_device;
145         }
146 }
147
148 DEVICE* VM::get_device(int id)
149 {
150         for(DEVICE* device = first_device; device; device = device->next_device) {
151                 if(device->this_device_id == id) {
152                         return device;
153                 }
154         }
155         return NULL;
156 }
157
158 // ----------------------------------------------------------------------------
159 // drive virtual machine
160 // ----------------------------------------------------------------------------
161
162 void VM::reset()
163 {
164         // load basic rom
165         if(boot_mode != config.boot_mode) {
166                 memset(basic, 0xff, sizeof(basic));
167                 if(config.boot_mode == 0) {
168                         memory->read_bios(_T("LV1BASIC.ROM"), basic + 0x1000, 0x1000);
169                 } else {
170                         memory->read_bios(_T("LV2BASIC.ROM"), basic, sizeof(basic));
171                 }
172                 boot_mode = config.boot_mode;
173                 
174                 memset(ram, 0, sizeof(ram));
175         }
176         
177         // initialize screen
178         emu->reload_bitmap();
179         draw_ranges = 8;
180         memset(vram, 0x20, sizeof(vram));
181         
182         // reset all devices
183         for(DEVICE* device = first_device; device; device = device->next_device) {
184                 device->reset();
185         }
186         
187         // init 8255 on TK-80
188         pio_t->write_io8(0xfb, 0x92);
189         pio_t->write_signal(SIG_I8255_PORT_A, 0xff, 0xff);
190 }
191
192 void VM::run()
193 {
194         event->drive();
195 }
196
197 // ----------------------------------------------------------------------------
198 // debugger
199 // ----------------------------------------------------------------------------
200
201 #ifdef USE_DEBUGGER
202 DEVICE *VM::get_cpu(int index)
203 {
204         if(index == 0) {
205                 return cpu;
206         }
207         return NULL;
208 }
209 #endif
210
211 // ----------------------------------------------------------------------------
212 // draw screen
213 // ----------------------------------------------------------------------------
214
215 void VM::draw_screen()
216 {
217         display->draw_screen();
218 }
219
220 int VM::max_draw_ranges()
221 {
222         return draw_ranges;
223 }
224
225 // ----------------------------------------------------------------------------
226 // soud manager
227 // ----------------------------------------------------------------------------
228
229 void VM::initialize_sound(int rate, int samples)
230 {
231         // init sound manager
232         event->initialize_sound(rate, samples);
233         
234         // init sound gen
235         pcm0->initialize_sound(rate, 8000);
236         pcm1->initialize_sound(rate, 8000);
237 }
238
239 uint16_t* VM::create_sound(int* extra_frames)
240 {
241         return event->create_sound(extra_frames);
242 }
243
244 int VM::get_sound_buffer_ptr()
245 {
246         return event->get_sound_buffer_ptr();
247 }
248
249 #ifdef USE_SOUND_VOLUME
250 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
251 {
252         if(ch == 0) {
253                 pcm0->set_volume(0, decibel_l, decibel_r);
254         } else if(ch == 1) {
255                 pcm1->set_volume(0, decibel_l, decibel_r);
256         }
257 }
258 #endif
259
260 // ----------------------------------------------------------------------------
261 // notify key
262 // ----------------------------------------------------------------------------
263
264 void VM::key_down(int code, bool repeat)
265 {
266         keyboard->key_down(code);
267 }
268
269 void VM::key_up(int code)
270 {
271         keyboard->key_up(code);
272 }
273
274 // ----------------------------------------------------------------------------
275 // user interface
276 // ----------------------------------------------------------------------------
277
278 void VM::load_binary(int drv, const _TCHAR* file_path)
279 {
280         if(drv == 0) {
281                 memory->read_image(file_path, ram, sizeof(ram));
282         }
283 }
284
285 void VM::save_binary(int drv, const _TCHAR* file_path)
286 {
287         if(drv == 0) {
288                 memory->write_image(file_path, ram, sizeof(ram));
289         }
290 }
291
292 void VM::play_tape(const _TCHAR* file_path)
293 {
294         cmt->play_tape(file_path);
295 }
296
297 void VM::rec_tape(const _TCHAR* file_path)
298 {
299         cmt->rec_tape(file_path);
300 }
301
302 void VM::close_tape()
303 {
304         cmt->close_tape();
305 }
306
307 bool VM::is_tape_inserted()
308 {
309         return cmt->is_tape_inserted();
310 }
311
312 bool VM::is_frame_skippable()
313 {
314         return event->is_frame_skippable();
315 }
316
317 void VM::update_config()
318 {
319         if(boot_mode != config.boot_mode) {
320                 // boot mode is changed !!!
321 //              boot_mode = config.boot_mode;
322                 reset();
323         } else {
324                 for(DEVICE* device = first_device; device; device = device->next_device) {
325                         device->update_config();
326                 }
327         }
328 }
329
330 #define STATE_VERSION   1
331
332 void VM::save_state(FILEIO* state_fio)
333 {
334         state_fio->FputUint32(STATE_VERSION);
335         
336         for(DEVICE* device = first_device; device; device = device->next_device) {
337                 device->save_state(state_fio);
338         }
339         state_fio->Fwrite(ram, sizeof(ram), 1);
340         state_fio->Fwrite(vram, sizeof(vram), 1);
341         state_fio->FputInt32(boot_mode);
342 //      state_fio->FputInt32(draw_ranges);
343 }
344
345 bool VM::load_state(FILEIO* state_fio)
346 {
347         if(state_fio->FgetUint32() != STATE_VERSION) {
348                 return false;
349         }
350         for(DEVICE* device = first_device; device; device = device->next_device) {
351                 if(!device->load_state(state_fio)) {
352                         return false;
353                 }
354         }
355         state_fio->Fread(ram, sizeof(ram), 1);
356         state_fio->Fread(vram, sizeof(vram), 1);
357         boot_mode = state_fio->FgetInt32();
358 //      draw_ranges = state_fio->FgetInt32();
359         
360         // post process
361         emu->reload_bitmap();
362         draw_ranges = 8;
363         return true;
364 }
365