OSDN Git Service

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