OSDN Git Service

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