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 / pc8201 / pc8201.cpp
1 /*
2         NEC PC-8201 Emulator 'ePC-8201'
3
4         Author : Takeda.Toshiya
5         Date   : 2009.03.31-
6
7         [ virtual machine ]
8 */
9
10 #include "pc8201.h"
11 #include "../../emu.h"
12 #include "../device.h"
13 #include "../event.h"
14
15 #include "../datarec.h"
16 #include "../i8080.h"
17 #include "../i8155.h"
18 #include "../io.h"
19 #include "../noise.h"
20 #include "../pcm1bit.h"
21 #include "../upd1990a.h"
22
23 #ifdef USE_DEBUGGER
24 #include "../debugger.h"
25 #endif
26
27 #include "cmt.h"
28 #include "keyboard.h"
29 #include "lcd.h"
30 #include "./memory.h"
31
32 using PC8201::CMT;
33 using PC8201::KEYBOARD;
34 using PC8201::LCD;
35 using PC8201::MEMORY;
36
37 // ----------------------------------------------------------------------------
38 // initialize
39 // ----------------------------------------------------------------------------
40
41 VM::VM(EMU_TEMPLATE* parent_emu) : VM_TEMPLATE(parent_emu)
42 {
43         // create devices
44         first_device = last_device = NULL;
45         dummy = new DEVICE(this, emu);  // must be 1st device
46         event = new EVENT(this, emu);   // must be 2nd device
47
48         drec = new DATAREC(this, emu);
49         drec->set_context_noise_play(new NOISE(this, emu));
50         drec->set_context_noise_stop(new NOISE(this, emu));
51         drec->set_context_noise_fast(new NOISE(this, emu));
52         cpu = new I8080(this, emu);
53         pio = new I8155(this, emu);
54         io = new IO(this, emu);
55         io->space = 0x100;
56         pcm = new PCM1BIT(this, emu);
57         rtc = new UPD1990A(this, emu);
58 #ifdef USE_DEBUGGER
59 //      pcm->set_context_debugger(new DEBUGGER(this, emu));
60 #endif
61
62         cmt = new CMT(this, emu);
63         keyboard = new KEYBOARD(this, emu);
64         lcd = new LCD(this, emu);
65         memory = new MEMORY(this, emu);
66
67         // set contexts
68         event->set_context_cpu(cpu);
69         event->set_context_sound(pcm);
70         event->set_context_sound(drec);
71         event->set_context_sound(drec->get_context_noise_play());
72         event->set_context_sound(drec->get_context_noise_stop());
73         event->set_context_sound(drec->get_context_noise_fast());
74
75         drec->set_context_ear(cpu, SIG_I8085_SID, 1);
76         cpu->set_context_sod(cmt, SIG_CMT_SOD, 1);
77         pio->set_context_port_a(rtc, SIG_UPD1990A_C0, 1, 0);
78         pio->set_context_port_a(rtc, SIG_UPD1990A_C1, 2, 0);
79         pio->set_context_port_a(rtc, SIG_UPD1990A_C2, 4, 0);
80         pio->set_context_port_a(rtc, SIG_UPD1990A_CLK, 8, 0);
81         pio->set_context_port_a(rtc, SIG_UPD1990A_DIN, 0x10, 0);
82         pio->set_context_port_a(keyboard, SIG_KEYBOARD_COLUMN_L, 0xff, 0);
83         pio->set_context_port_a(lcd, SIG_LCD_CHIPSEL_L, 0xff, 0);
84         pio->set_context_port_b(keyboard, SIG_KEYBOARD_COLUMN_H, 1, 0);
85         pio->set_context_port_b(lcd, SIG_LCD_CHIPSEL_H, 3, 0);
86         pio->set_context_port_b(pcm, SIG_PCM1BIT_MUTE, 0x20, 0);
87         pio->set_context_timer(pcm, SIG_PCM1BIT_SIGNAL, 1);
88         pio->set_constant_clock(CPU_CLOCKS);
89         rtc->set_context_dout(pio, SIG_I8155_PORT_C, 1);
90         rtc->set_context_tp(cpu, SIG_I8085_RST7, 1);
91
92         memory->set_context_cmt(cmt);
93         memory->set_context_drec(drec);
94         memory->set_context_rtc(rtc);
95
96         // cpu bus
97         cpu->set_context_mem(memory);
98         cpu->set_context_io(io);
99         cpu->set_context_intr(io);
100 #ifdef USE_DEBUGGER
101         cpu->set_context_debugger(new DEBUGGER(this, emu));
102 #endif
103
104         // i/o bus
105         io->set_iomap_range_w(0x90, 0x9f, memory);
106         io->set_iomap_range_rw(0xa0, 0xaf, memory);
107         io->set_iomap_range_rw(0xb0, 0xbf, pio);
108         io->set_iomap_range_r(0xe0, 0xef, keyboard);
109         io->set_iomap_range_rw(0xf0, 0xff, lcd);
110
111         // initialize all devices
112 #if defined(__GIT_REPO_VERSION)
113         set_git_repo_version(__GIT_REPO_VERSION);
114 #endif
115         initialize_devices();
116
117         rtc->write_signal(SIG_UPD1990A_STB, 0, 0);
118 }
119
120 VM::~VM()
121 {
122         // delete all devices
123         for(DEVICE* device = first_device; device;) {
124                 DEVICE *next_device = device->next_device;
125                 device->release();
126                 delete device;
127                 device = next_device;
128         }
129 }
130
131 DEVICE* VM::get_device(int id)
132 {
133         for(DEVICE* device = first_device; device; device = device->next_device) {
134                 if(device->this_device_id == id) {
135                         return device;
136                 }
137         }
138         return NULL;
139 }
140
141 // ----------------------------------------------------------------------------
142 // drive virtual machine
143 // ----------------------------------------------------------------------------
144
145 void VM::reset()
146 {
147         // reset all devices
148         for(DEVICE* device = first_device; device; device = device->next_device) {
149                 device->reset();
150         }
151 }
152
153 void VM::run()
154 {
155         event->drive();
156 }
157
158 // ----------------------------------------------------------------------------
159 // debugger
160 // ----------------------------------------------------------------------------
161
162 #ifdef USE_DEBUGGER
163 DEVICE *VM::get_cpu(int index)
164 {
165         if(index == 0) {
166                 return cpu;
167         }
168         return NULL;
169 }
170 #endif
171
172 // ----------------------------------------------------------------------------
173 // draw screen
174 // ----------------------------------------------------------------------------
175
176 void VM::draw_screen()
177 {
178         lcd->draw_screen();
179 }
180
181 // ----------------------------------------------------------------------------
182 // soud manager
183 // ----------------------------------------------------------------------------
184
185 void VM::initialize_sound(int rate, int samples)
186 {
187         // init sound manager
188         event->initialize_sound(rate, samples);
189
190         // init sound gen
191         pcm->initialize_sound(rate, 8000);
192 }
193
194 uint16_t* VM::create_sound(int* extra_frames)
195 {
196         return event->create_sound(extra_frames);
197 }
198
199 int VM::get_sound_buffer_ptr()
200 {
201         return event->get_sound_buffer_ptr();
202 }
203
204 #ifdef USE_SOUND_VOLUME
205 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
206 {
207         if(ch == 0) {
208                 pcm->set_volume(0, decibel_l, decibel_r);
209         } else if(ch == 1) {
210                 drec->set_volume(0, decibel_l, decibel_r);
211         } else if(ch == 2) {
212                 drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
213                 drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
214                 drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
215         }
216 }
217 #endif
218
219 // ----------------------------------------------------------------------------
220 // notify key
221 // ----------------------------------------------------------------------------
222
223 void VM::key_down(int code, bool repeat)
224 {
225         keyboard->key_down(code);
226 }
227
228 void VM::key_up(int code)
229 {
230 }
231
232 bool VM::get_caps_locked()
233 {
234         return keyboard->get_caps_locked();
235 }
236
237 bool VM::get_kana_locked()
238 {
239         return keyboard->get_kana_locked();
240 }
241
242 // ----------------------------------------------------------------------------
243 // user interface
244 // ----------------------------------------------------------------------------
245
246 void VM::play_tape(int drv, const _TCHAR* file_path)
247 {
248         cmt->close_tape();
249
250         bool remote = drec->get_remote();
251
252         if(drec->play_tape(file_path) && remote) {
253                 // if machine already sets remote on, start playing now
254                 push_play(drv);
255         }
256 }
257
258 void VM::rec_tape(int drv, const _TCHAR* file_path)
259 {
260         emu->lock_vm();
261         drec->close_tape();
262         emu->unlock_vm();
263         drec->set_remote(false);
264
265         cmt->rec_tape(file_path);
266 }
267
268 void VM::close_tape(int drv)
269 {
270         emu->lock_vm();
271         drec->close_tape();
272         emu->unlock_vm();
273         drec->set_remote(false);
274
275         cmt->close_tape();
276 }
277
278 bool VM::is_tape_inserted(int drv)
279 {
280         return drec->is_tape_inserted() || cmt->is_tape_inserted();
281 }
282
283 bool VM::is_tape_playing(int drv)
284 {
285         if(drec->is_tape_inserted()) {
286                 return drec->is_tape_playing();
287         } else {
288                 return cmt->is_tape_playing();
289         }
290 }
291
292 bool VM::is_tape_recording(int drv)
293 {
294         if(drec->is_tape_inserted()) {
295                 return drec->is_tape_recording();
296         } else {
297                 return cmt->is_tape_recording();
298         }
299 }
300
301 int VM::get_tape_position(int drv)
302 {
303         if(drec->is_tape_inserted()) {
304                 return drec->get_tape_position();
305         } else {
306                 return cmt->get_tape_position();
307         }
308 }
309
310 const _TCHAR* VM::get_tape_message(int drv)
311 {
312         if(drec->is_tape_inserted()) {
313                 return drec->get_message();
314         } else {
315                 return NULL;
316         }
317 }
318
319 void VM::push_play(int drv)
320 {
321         if(drec->is_tape_inserted()) {
322                 drec->set_remote(false);
323                 drec->set_ff_rew(0);
324                 drec->set_remote(true);
325         }
326 }
327
328 void VM::push_stop(int drv)
329 {
330         if(drec->is_tape_inserted()) {
331                 drec->set_remote(false);
332         }
333 }
334
335 void VM::push_fast_forward(int drv)
336 {
337         if(drec->is_tape_inserted()) {
338                 drec->set_remote(false);
339                 drec->set_ff_rew(1);
340                 drec->set_remote(true);
341         }
342 }
343
344 void VM::push_fast_rewind(int drv)
345 {
346         if(drec->is_tape_inserted()) {
347                 drec->set_remote(false);
348                 drec->set_ff_rew(-1);
349                 drec->set_remote(true);
350         }
351 }
352
353 bool VM::is_frame_skippable()
354 {
355         return event->is_frame_skippable();
356 }
357
358 void VM::update_config()
359 {
360         for(DEVICE* device = first_device; device; device = device->next_device) {
361                 device->update_config();
362         }
363 }
364
365 double VM::get_current_usec()
366 {
367         if(event == NULL) return 0.0;
368         return event->get_current_usec();
369 }
370
371 uint64_t VM::get_current_clock_uint64()
372 {
373                 if(event == NULL) return (uint64_t)0;
374                 return event->get_current_clock_uint64();
375 }
376
377 #define STATE_VERSION   3
378
379 bool VM::process_state(FILEIO* state_fio, bool loading)
380 {
381         if(!(VM_TEMPLATE::process_state_core(state_fio, loading, STATE_VERSION))) {
382                 return false;
383         }
384         // Machine specified.
385         return true;
386 }