OSDN Git Service

[BUILD] Set SOVERSION and GIT hash automatically.
[csp-qt/common_source_project-fm7.git] / source / src / vm / smc777 / smc777.cpp
1 /*
2         SONY SMC-70 Emulator 'eSMC-70'
3         SONY SMC-777 Emulator 'eSMC-777'
4
5         Author : Takeda.Toshiya
6         Date   : 2015.08.13-
7
8         [ virtual machine ]
9 */
10
11 #include "smc777.h"
12 #include "../../emu.h"
13 #include "../device.h"
14 #include "../event.h"
15
16 #include "../datarec.h"
17 #include "../disk.h"
18 #include "../hd46505.h"
19 #include "../mb8877.h"
20 #if defined(_SMC70)
21 #include "../msm58321.h"
22 #endif
23 #include "../noise.h"
24 #include "../pcm1bit.h"
25 #if defined(_SMC777)
26 #include "../sn76489an.h"
27 #endif
28 #include "../z80.h"
29
30 #ifdef USE_DEBUGGER
31 #include "../debugger.h"
32 #endif
33
34 #include "memory.h"
35
36 // ----------------------------------------------------------------------------
37 // initialize
38 // ----------------------------------------------------------------------------
39
40 VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu)
41 {
42         // create devices
43         first_device = last_device = NULL;
44         dummy = new DEVICE(this, emu);  // must be 1st device
45         event = new EVENT(this, emu);   // must be 2nd device
46         dummy->set_device_name(_T("1st Dummy"));
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         crtc = new HD46505(this, emu);
53         fdc = new MB8877(this, emu);
54         fdc->set_context_noise_seek(new NOISE(this, emu));
55         fdc->set_context_noise_head_down(new NOISE(this, emu));
56         fdc->set_context_noise_head_up(new NOISE(this, emu));
57 #if defined(_SMC70)
58         rtc = new MSM58321(this, emu);
59 #endif
60         pcm = new PCM1BIT(this, emu);
61 #if defined(_SMC777)
62         psg = new SN76489AN(this, emu);
63 #endif
64         cpu = new Z80(this, emu);
65
66         memory = new MEMORY(this, emu);
67         
68         // set contexts
69         event->set_context_cpu(cpu);
70         event->set_context_sound(pcm);
71 #if defined(_SMC777)
72         event->set_context_sound(psg);
73 #endif
74         event->set_context_sound(drec);
75         event->set_context_sound(fdc->get_context_noise_seek());
76         event->set_context_sound(fdc->get_context_noise_head_down());
77         event->set_context_sound(fdc->get_context_noise_head_up());
78         event->set_context_sound(drec->get_context_noise_play());
79         event->set_context_sound(drec->get_context_noise_stop());
80         event->set_context_sound(drec->get_context_noise_fast());
81         
82         // Sound:: Force realtime rendering. This is temporally fix. 20161024 K.O
83         //pcm->set_realtime_render(true);
84
85         drec->set_context_ear(memory, SIG_MEMORY_DATAREC_IN, 1);
86         crtc->set_context_disp(memory, SIG_MEMORY_CRTC_DISP, 1);
87         crtc->set_context_vsync(memory, SIG_MEMORY_CRTC_VSYNC, 1);
88         fdc->set_context_drq(memory, SIG_MEMORY_FDC_DRQ, 1);
89         fdc->set_context_irq(memory, SIG_MEMORY_FDC_IRQ, 1);
90 #if defined(_SMC70)
91         rtc->set_context_data(memory, SIG_MEMORY_RTC_DATA, 0x0f, 0);
92         rtc->set_context_busy(memory, SIG_MEMORY_RTC_BUSY, 1);
93 #endif
94         
95         memory->set_context_cpu(cpu);
96         memory->set_context_crtc(crtc, crtc->get_regs());
97         memory->set_context_drec(drec);
98         memory->set_context_fdc(fdc);
99         memory->set_context_pcm(pcm);
100 #if defined(_SMC70)
101         memory->set_context_rtc(rtc);
102 #elif defined(_SMC777)
103         memory->set_context_psg(psg);
104 #endif
105         
106         // cpu bus
107         cpu->set_context_mem(memory);
108         cpu->set_context_io(memory);
109         cpu->set_context_intr(dummy);
110 #ifdef USE_DEBUGGER
111         cpu->set_context_debugger(new DEBUGGER(this, emu));
112 #endif
113         
114         // initialize all devices
115 #if defined(__GIT_REPO_VERSION)
116         strncpy(_git_revision, __GIT_REPO_VERSION, sizeof(_git_revision) - 1);
117 #endif
118         for(DEVICE* device = first_device; device; device = device->next_device) {
119                 device->initialize();
120         }
121         decl_state();
122         for(int i = 0; i < MAX_DRIVE; i++) {
123                 fdc->set_drive_type(i, DRIVE_TYPE_2DD); // 1DD
124                 fdc->set_drive_rpm(i, 600);
125         }
126         fdc->write_signal(SIG_MB8877_MOTOR, 1, 1);
127 }
128
129 VM::~VM()
130 {
131         // delete all devices
132         for(DEVICE* device = first_device; device;) {
133                 DEVICE *next_device = device->next_device;
134                 device->release();
135                 delete device;
136                 device = next_device;
137         }
138 }
139
140 DEVICE* VM::get_device(int id)
141 {
142         for(DEVICE* device = first_device; device; device = device->next_device) {
143                 if(device->this_device_id == id) {
144                         return device;
145                 }
146         }
147         return NULL;
148 }
149
150 // ----------------------------------------------------------------------------
151 // drive virtual machine
152 // ----------------------------------------------------------------------------
153
154 void VM::reset()
155 {
156         // reset all devices
157         for(DEVICE* device = first_device; device; device = device->next_device) {
158                 device->reset();
159         }
160         memory->warm_start = false;
161 }
162
163 void VM::special_reset()
164 {
165         // reset all devices
166         for(DEVICE* device = first_device; device; device = device->next_device) {
167                 device->reset();
168         }
169         memory->warm_start = true;
170 }
171
172 void VM::run()
173 {
174         event->drive();
175 }
176
177 double VM::get_frame_rate()
178 {
179         return event->get_frame_rate();
180 }
181
182 // ----------------------------------------------------------------------------
183 // debugger
184 // ----------------------------------------------------------------------------
185
186 #ifdef USE_DEBUGGER
187 DEVICE *VM::get_cpu(int index)
188 {
189         if(index == 0) {
190                 return cpu;
191         }
192         return NULL;
193 }
194 #endif
195
196 // ----------------------------------------------------------------------------
197 // draw screen
198 // ----------------------------------------------------------------------------
199
200 void VM::draw_screen()
201 {
202         memory->draw_screen();
203 }
204
205 // ----------------------------------------------------------------------------
206 // soud manager
207 // ----------------------------------------------------------------------------
208
209 void VM::initialize_sound(int rate, int samples)
210 {
211         // init sound manager
212         event->initialize_sound(rate, samples);
213         
214         // init sound gen
215         pcm->initialize_sound(rate, 5000);
216 #if defined(_SMC777)
217         psg->initialize_sound(rate, CPU_CLOCKS, 5000);
218 #endif
219 }
220
221 uint16_t* VM::create_sound(int* extra_frames)
222 {
223         return event->create_sound(extra_frames);
224 }
225
226 int VM::get_sound_buffer_ptr()
227 {
228         return event->get_sound_buffer_ptr();
229 }
230
231 #ifdef USE_SOUND_VOLUME
232 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
233 {
234 #if defined(_SMC777)
235         if(ch-- == 0) {
236                 psg->set_volume(0, decibel_l, decibel_r);
237         } else
238 #endif
239         if(ch-- == 0) {
240                 pcm->set_volume(0, decibel_l, decibel_r);
241         } else if(ch-- == 0) {
242                 drec->set_volume(0, decibel_l, decibel_r);
243         } else if(ch-- == 0) {
244                 fdc->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
245                 fdc->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
246                 fdc->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
247         } else if(ch-- == 0) {
248                 drec->get_context_noise_play()->set_volume(0, decibel_l, decibel_r);
249                 drec->get_context_noise_stop()->set_volume(0, decibel_l, decibel_r);
250                 drec->get_context_noise_fast()->set_volume(0, decibel_l, decibel_r);
251         }
252 }
253 #endif
254
255 // ----------------------------------------------------------------------------
256 // notify key
257 // ----------------------------------------------------------------------------
258
259 void VM::key_down(int code, bool repeat)
260 {
261         if(!repeat) {
262                 memory->key_down_up(code, true);
263         }
264 }
265
266 void VM::key_up(int code)
267 {
268         memory->key_down_up(code, false);
269 }
270
271 bool VM::get_caps_locked()
272 {
273         return memory->get_caps_locked();
274 }
275
276 bool VM::get_kana_locked()
277 {
278         return memory->get_kana_locked();
279 }
280
281 // ----------------------------------------------------------------------------
282 // user interface
283 // ----------------------------------------------------------------------------
284
285 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
286 {
287         fdc->open_disk(drv, file_path, bank);
288 }
289
290 void VM::close_floppy_disk(int drv)
291 {
292         fdc->close_disk(drv);
293 }
294
295 bool VM::is_floppy_disk_inserted(int drv)
296 {
297         return fdc->is_disk_inserted(drv);
298 }
299
300 void VM::is_floppy_disk_protected(int drv, bool value)
301 {
302         fdc->is_disk_protected(drv, value);
303 }
304
305 bool VM::is_floppy_disk_protected(int drv)
306 {
307         return fdc->is_disk_protected(drv);
308 }
309
310 uint32_t VM::is_floppy_disk_accessed()
311 {
312         return fdc->read_signal(0);
313 }
314
315 void VM::play_tape(int drv, const _TCHAR* file_path)
316 {
317         drec->play_tape(file_path);
318 //      drec->set_remote(true);
319 }
320
321 void VM::rec_tape(int drv, const _TCHAR* file_path)
322 {
323         drec->rec_tape(file_path);
324 //      drec->set_remote(true);
325 }
326
327 void VM::close_tape(int drv)
328 {
329         emu->lock_vm();
330         drec->close_tape();
331         emu->unlock_vm();
332 //      drec->set_remote(false);
333 }
334
335 bool VM::is_tape_inserted(int drv)
336 {
337         return drec->is_tape_inserted();
338 }
339
340 bool VM::is_tape_playing(int drv)
341 {
342         return drec->is_tape_playing();
343 }
344
345 bool VM::is_tape_recording(int drv)
346 {
347         return drec->is_tape_recording();
348 }
349
350 int VM::get_tape_position(int drv)
351 {
352         return drec->get_tape_position();
353 }
354
355 const _TCHAR* VM::get_tape_message(int drv)
356 {
357         return drec->get_message();
358 }
359
360 void VM::push_play(int drv)
361 {
362         drec->set_ff_rew(0);
363         drec->set_remote(true);
364 }
365
366 void VM::push_stop(int drv)
367 {
368         drec->set_remote(false);
369 }
370
371 void VM::push_fast_forward(int drv)
372 {
373         drec->set_ff_rew(1);
374         drec->set_remote(true);
375 }
376
377 void VM::push_fast_rewind(int drv)
378 {
379         drec->set_ff_rew(-1);
380         drec->set_remote(true);
381 }
382
383 bool VM::is_frame_skippable()
384 {
385         return event->is_frame_skippable();
386 }
387
388 void VM::update_config()
389 {
390         for(DEVICE* device = first_device; device; device = device->next_device) {
391                 device->update_config();
392         }
393 }
394
395 #define STATE_VERSION   4
396
397 #include "../../statesub.h"
398 #include "../../qt/gui/csp_logger.h"
399 extern CSP_Logger DLL_PREFIX_I *csp_logger;
400
401 void VM::decl_state(void)
402 {
403 #if defined(_SMC70)
404         state_entry = new csp_state_utils(STATE_VERSION, 0, (_TCHAR *)(_T("CSP::SMC_70_HEAD")), csp_logger);
405 #elif defined(_SMC777)
406         state_entry = new csp_state_utils(STATE_VERSION, 0, (_TCHAR *)(_T("CSP::SMC_777_HEAD")), csp_logger);
407 #else
408         state_entry = new csp_state_utils(STATE_VERSION, 0, (_TCHAR *)(_T("CSP::SMC_70_SERIES_HEAD")), csp_logger);
409 #endif  
410         for(DEVICE* device = first_device; device; device = device->next_device) {
411                 device->decl_state();
412         }
413 }
414
415 void VM::save_state(FILEIO* state_fio)
416 {
417         //state_fio->FputUint32(STATE_VERSION);
418         
419         if(state_entry != NULL) {
420                 state_entry->save_state(state_fio);
421         }
422         for(DEVICE* device = first_device; device; device = device->next_device) {
423                 device->save_state(state_fio);
424         }
425 }
426
427 bool VM::load_state(FILEIO* state_fio)
428 {
429         //if(state_fio->FgetUint32() != STATE_VERSION) {
430         //      return false;
431         //}
432         bool mb = false;
433         if(state_entry != NULL) {
434                 mb = state_entry->load_state(state_fio);
435         }
436         if(!mb) {
437                 emu->out_debug_log("INFO: HEADER DATA ERROR");
438                 return false;
439         }
440         for(DEVICE* device = first_device; device; device = device->next_device) {
441                 if(!device->load_state(state_fio)) {
442                         return false;
443                 }
444         }
445         return true;
446 }
447