OSDN Git Service

[VM][Qt][UI][EMU][WIP] Use EMU_TEMPLATE:: instead of EMU:: . Some VMs are not apply...
[csp-qt/common_source_project-fm7.git] / source / src / vm / fp200 / fp200.cpp
1 /*
2         CASIO FP-200 Emulator 'eFP-200'
3
4         Author : Takeda.Toshiya
5         Date   : 2013.03.21-
6
7         [ virtual machine ]
8 */
9
10 #include "fp200.h"
11 #include "../../emu.h"
12 #include "../device.h"
13 #include "../event.h"
14
15 #include "../datarec.h"
16 #include "../i8080.h"
17 #include "../memory.h"
18 #include "../noise.h"
19 #include "../rp5c01.h"
20
21 #ifdef USE_DEBUGGER
22 #include "../debugger.h"
23 #endif
24
25 #include "./io.h"
26
27 // ----------------------------------------------------------------------------
28 // initialize
29 // ----------------------------------------------------------------------------
30 using FP200::IO;
31
32 VM::VM(EMU_TEMPLATE* parent_emu) : VM_TEMPLATE(parent_emu)
33 {
34         // create devices
35         first_device = last_device = NULL;
36         dummy = new DEVICE(this, emu);  // must be 1st device
37         event = new EVENT(this, emu);   // must be 2nd device
38         dummy->set_device_name(_T("1st Dummy"));
39
40         drec = new DATAREC(this, emu);
41         drec->set_context_noise_play(new NOISE(this, emu));
42         drec->set_context_noise_stop(new NOISE(this, emu));
43         drec->set_context_noise_fast(new NOISE(this, emu));
44         cpu = new I8080(this, emu);     // i8085
45         memory = new MEMORY(this, emu);
46         
47         rtc = new RP5C01(this, emu);
48         
49         io = new IO(this, emu);
50         // set contexts
51         event->set_context_cpu(cpu);
52         event->set_context_sound(drec);
53         event->set_context_sound(drec->get_context_noise_play());
54         event->set_context_sound(drec->get_context_noise_stop());
55         event->set_context_sound(drec->get_context_noise_fast());
56         
57         drec->set_context_ear(io, SIG_IO_CMT, 1);
58         cpu->set_context_sod(io, SIG_IO_SOD, 1);
59         
60         io->set_context_cpu(cpu);
61         io->set_context_drec(drec);
62         io->set_context_rtc(rtc);
63         
64         // cpu bus
65         cpu->set_context_mem(memory);
66         cpu->set_context_io(io);
67         cpu->set_context_intr(io);
68 #ifdef USE_DEBUGGER
69         cpu->set_context_debugger(new DEBUGGER(this, emu));
70 #endif
71         
72         // memory bus
73         memset(rom, 0xff, sizeof(rom));
74         memset(ram, 0, sizeof(ram));
75         
76         memory->read_bios(_T("BIOS.ROM"), rom, sizeof(rom));
77         
78         FILEIO* fio = new FILEIO();
79         if(fio->Fopen(create_local_path(_T("RAM.BIN")), FILEIO_READ_BINARY)) {
80                 fio->Fread(ram, sizeof(ram), 1);
81                 fio->Fclose();
82         }
83         delete fio;
84         
85         memory->set_memory_r(0x0000, 0x7fff, rom);
86         memory->set_memory_rw(0x8000, 0xffff, ram);
87         memory->set_wait_rw(0x0000, 0xffff, 1);
88         
89         // initialize all devices
90 #if defined(__GIT_REPO_VERSION)
91         strncpy(_git_revision, __GIT_REPO_VERSION, sizeof(_git_revision) - 1);
92 #endif
93         for(DEVICE* device = first_device; device; device = device->next_device) {
94                 device->initialize();
95         }
96 }
97
98 VM::~VM()
99 {
100         FILEIO* fio = new FILEIO();
101         if(fio->Fopen(create_local_path(_T("RAM.BIN")), FILEIO_WRITE_BINARY)) {
102                 fio->Fwrite(ram, sizeof(ram), 1);
103                 fio->Fclose();
104         }
105         delete fio;
106         
107         // delete all devices
108         for(DEVICE* device = first_device; device;) {
109                 DEVICE *next_device = device->next_device;
110                 device->release();
111                 delete device;
112                 device = next_device;
113         }
114 }
115
116 DEVICE* VM::get_device(int id)
117 {
118         for(DEVICE* device = first_device; device; device = device->next_device) {
119                 if(device->this_device_id == id) {
120                         return device;
121                 }
122         }
123         return NULL;
124 }
125
126 // ----------------------------------------------------------------------------
127 // drive virtual machine
128 // ----------------------------------------------------------------------------
129
130 void VM::reset()
131 {
132         // reset all devices
133         for(DEVICE* device = first_device; device; device = device->next_device) {
134                 device->reset();
135         }
136 }
137
138 void VM::run()
139 {
140         event->drive();
141 }
142
143 // ----------------------------------------------------------------------------
144 // debugger
145 // ----------------------------------------------------------------------------
146
147 #ifdef USE_DEBUGGER
148 DEVICE *VM::get_cpu(int index)
149 {
150         if(index == 0) {
151                 return cpu;
152         }
153         return NULL;
154 }
155 #endif
156
157 // ----------------------------------------------------------------------------
158 // draw screen
159 // ----------------------------------------------------------------------------
160
161 void VM::draw_screen()
162 {
163         io->draw_screen();
164 }
165
166 // ----------------------------------------------------------------------------
167 // soud manager
168 // ----------------------------------------------------------------------------
169
170 void VM::initialize_sound(int rate, int samples)
171 {
172         // init sound manager
173         event->initialize_sound(rate, samples);
174 }
175
176 uint16_t* VM::create_sound(int* extra_frames)
177 {
178         return event->create_sound(extra_frames);
179 }
180
181 int VM::get_sound_buffer_ptr()
182 {
183         return event->get_sound_buffer_ptr();
184 }
185
186 #ifdef USE_SOUND_VOLUME
187 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
188 {
189         if(ch == 0) {
190                 drec->set_volume(0, decibel_l, decibel_r);
191         } else if(ch == 1) {
192                 drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
193                 drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
194                 drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
195         }
196 }
197 #endif
198
199 // ----------------------------------------------------------------------------
200 // notify key
201 // ----------------------------------------------------------------------------
202
203 void VM::key_down(int code, bool repeat)
204 {
205         if(!repeat) {
206                 io->key_down(code);
207         }
208 }
209
210 void VM::key_up(int code)
211 {
212         io->key_up();
213 }
214
215 // ----------------------------------------------------------------------------
216 // user interface
217 // ----------------------------------------------------------------------------
218
219 void VM::play_tape(int drv, const _TCHAR* file_path)
220 {
221         io->close_tape();
222         
223         bool remote = drec->get_remote();
224         
225         if(drec->play_tape(file_path) && remote) {
226                 // if machine already sets remote on, start playing now
227                 push_play(drv);
228         }
229 }
230
231 void VM::rec_tape(int drv, const _TCHAR* file_path)
232 {
233         emu->lock_vm();
234         drec->close_tape();
235         emu->unlock_vm();
236         drec->set_remote(false);
237         io->rec_tape(file_path);
238 }
239
240 void VM::close_tape(int drv)
241 {
242         emu->lock_vm();
243         drec->close_tape();
244         emu->unlock_vm();
245         drec->set_remote(false);
246         
247         io->close_tape();
248 }
249
250 bool VM::is_tape_inserted(int drv)
251 {
252         return drec->is_tape_inserted() || io->is_tape_inserted();
253 }
254
255 bool VM::is_tape_playing(int drv)
256 {
257         if(drec->is_tape_inserted()) {
258                 return drec->is_tape_playing();
259         } else {
260                 return io->is_tape_playing();
261         }
262 }
263
264 bool VM::is_tape_recording(int drv)
265 {
266         if(drec->is_tape_inserted()) {
267                 return drec->is_tape_recording();
268         } else {
269                 return io->is_tape_recording();
270         }
271 }
272
273 int VM::get_tape_position(int drv)
274 {
275         if(drec->is_tape_inserted()) {
276                 return drec->get_tape_position();
277         } else {
278                 return io->get_tape_position();
279         }
280 }
281
282 const _TCHAR* VM::get_tape_message(int drv)
283 {
284         if(drec->is_tape_inserted()) {
285                 return drec->get_message();
286         } else {
287                 return NULL;
288         }
289 }
290
291 void VM::push_play(int drv)
292 {
293         if(drec->is_tape_inserted()) {
294                 drec->set_remote(false);
295                 drec->set_ff_rew(0);
296                 drec->set_remote(true);
297         }
298 }
299
300 void VM::push_stop(int drv)
301 {
302         if(drec->is_tape_inserted()) {
303                 drec->set_remote(false);
304         }
305 }
306
307 void VM::push_fast_forward(int drv)
308 {
309         if(drec->is_tape_inserted()) {
310                 drec->set_remote(false);
311                 drec->set_ff_rew(1);
312                 drec->set_remote(true);
313         }
314 }
315
316 void VM::push_fast_rewind(int drv)
317 {
318         if(drec->is_tape_inserted()) {
319                 drec->set_remote(false);
320                 drec->set_ff_rew(-1);
321                 drec->set_remote(true);
322         }
323 }
324
325 bool VM::is_frame_skippable()
326 {
327         return event->is_frame_skippable();
328 }
329
330 void VM::update_config()
331 {
332         for(DEVICE* device = first_device; device; device = device->next_device) {
333                 device->update_config();
334         }
335 }
336
337 double VM::get_current_usec()
338 {
339         if(event == NULL) return 0.0;
340         return event->get_current_usec();
341 }
342
343 uint64_t VM::get_current_clock_uint64()
344 {
345                 if(event == NULL) return (uint64_t)0;
346                 return event->get_current_clock_uint64();
347 }
348
349 #define STATE_VERSION   3
350
351 bool VM::process_state(FILEIO* state_fio, bool loading)
352 {
353         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
354                 return false;
355         }
356         for(DEVICE* device = first_device; device; device = device->next_device) {
357                 // Note: typeid(foo).name is fixed by recent ABI.Not dec 6.
358                 // const char *name = typeid(*device).name();
359                 //       But, using get_device_name() instead of typeid(foo).name() 20181008 K.O
360                 const char *name = device->get_device_name();
361                 int len = strlen(name);
362                 
363                 if(!state_fio->StateCheckInt32(len)) {
364                         if(loading) {
365                                 printf("Class name len Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
366                         }
367                         return false;
368                 }
369                 if(!state_fio->StateCheckBuffer(name, len, 1)) {
370                         if(loading) {
371                                 printf("Class name Error: DEVID=%d EXPECT=%s\n", device->this_device_id, name);
372                         }
373                         return false;
374                 }
375                 if(!device->process_state(state_fio, loading)) {
376                         if(loading) {
377                                 printf("Data loading Error: DEVID=%d\n", device->this_device_id);
378                         }
379                         return false;
380                 }
381         }
382         state_fio->StateArray(ram, sizeof(ram), 1);
383         return true;
384 }