OSDN Git Service

[VM] Floppy / CMT : Add Write protection feature, but testing is not enough X-)
[csp-qt/common_source_project-fm7.git] / source / src / emu.cpp
1 /*\r
2         Skelton for retropc emulator\r
3 \r
4         Author : Takeda.Toshiya\r
5         Date   : 2006.08.18 -\r
6 \r
7         [ win32 emulation i/f ]\r
8 */\r
9 \r
10 #include "emu.h"\r
11 #include "vm/vm.h"\r
12 #include "fileio.h"\r
13 #if defined(_USE_AGAR)\r
14 #include <SDL/SDL.h>\r
15 #include "agar_main.h"\r
16 #include "agar_logger.h"\r
17 #include <ctime>\r
18 # elif defined(_USE_QT)\r
19 #include <SDL/SDL.h>\r
20 #include "qt_main.h"\r
21 #include "agar_logger.h"\r
22 #include <ctime>\r
23 # endif\r
24 \r
25 #ifndef FD_BASE_NUMBER\r
26 #define FD_BASE_NUMBER 1\r
27 #endif\r
28 #ifndef QD_BASE_NUMBER\r
29 #define QD_BASE_NUMBER 1\r
30 #endif\r
31 \r
32 // ----------------------------------------------------------------------------\r
33 // initialize\r
34 // ----------------------------------------------------------------------------\r
35 #if defined(_USE_AGAR) || defined(_USE_SDL) || defined(_USE_QT)\r
36 extern void get_long_full_path_name(_TCHAR* src, _TCHAR* dst);\r
37 #include <string>\r
38 #endif\r
39 \r
40 #if defined(_USE_QGAR)\r
41 EMU::EMU(AG_Window *hwnd, AG_Widget *hinst)\r
42 #elif defined(_USE_QT)\r
43 EMU::EMU(Ui_MainWindow *hwnd, GLDrawClass *hinst)\r
44 #else\r
45 EMU::EMU(HWND hwnd, HINSTANCE hinst)\r
46 #endif\r
47 {\r
48 #ifdef _DEBUG_LOG\r
49         // open debug logfile\r
50         initialize_debug_log();\r
51 #endif\r
52         message_count = 0;\r
53         \r
54         // store main window handle\r
55         main_window_handle = hwnd;\r
56         instance_handle = hinst;\r
57         \r
58         // get module path\r
59 \r
60 #if defined(_USE_AGAR) || (_USE_SDL) || defined(_USE_QT)\r
61         std::string tmps;\r
62 #ifndef _USE_QT\r
63         _TCHAR tmp_path[PATH_MAX], *ptr;\r
64         my_procname.copy(tmp_path, PATH_MAX, 0);\r
65         get_long_full_path_name(tmp_path, app_path);\r
66         //AGAR_DebugLog("APPPATH=%s\n", app_path);\r
67         if(AG_UsingGL(AGDRIVER(main_window_handle))) {\r
68            use_opengl = true;\r
69            use_opencl = false;\r
70         } else {\r
71            use_opencl = false;\r
72            use_opengl = false;\r
73         }\r
74 #else\r
75         _TCHAR tmp_path[PATH_MAX], *ptr;\r
76         my_procname.copy(tmp_path, PATH_MAX, 0);\r
77         get_long_full_path_name(tmp_path, app_path);\r
78         //AGAR_DebugLog("APPPATH=%s\n", app_path);\r
79         use_opengl = true;\r
80         use_opencl = false;\r
81 #endif\r
82         pVMSemaphore = SDL_CreateSemaphore(1);\r
83 #else\r
84         _TCHAR tmp_path[_MAX_PATH], *ptr;\r
85         GetModuleFileName(NULL, tmp_path, _MAX_PATH);\r
86         GetFullPathName(tmp_path, _MAX_PATH, app_path, &ptr);\r
87         *ptr = _T('\0');\r
88 #endif  \r
89 #ifdef USE_FD1\r
90         // initialize d88 file info\r
91         memset(d88_file, 0, sizeof(d88_file));\r
92 #endif\r
93         \r
94         // load sound config\r
95         static const int freq_table[8] = {\r
96                 2000, 4000, 8000, 11025, 22050, 44100,\r
97 #ifdef OVERRIDE_SOUND_FREQ_48000HZ\r
98                 OVERRIDE_SOUND_FREQ_48000HZ,\r
99 #else\r
100                 48000,\r
101 #endif\r
102                 96000,\r
103         };\r
104         static const double late_table[5] = {0.05, 0.1, 0.2, 0.3, 0.4};\r
105         \r
106         if(!(0 <= config.sound_frequency && config.sound_frequency < 8)) {\r
107                 config.sound_frequency = 6;     // default: 48KHz\r
108         }\r
109         if(!(0 <= config.sound_latency && config.sound_latency < 5)) {\r
110                 config.sound_latency = 1;       // default: 100msec\r
111         }\r
112         sound_rate = freq_table[config.sound_frequency];\r
113         sound_samples = (int)(sound_rate * late_table[config.sound_latency] + 0.5);\r
114         \r
115 #ifdef USE_CPU_TYPE\r
116         cpu_type = config.cpu_type;\r
117 #endif\r
118 #ifdef USE_SOUND_DEVICE_TYPE\r
119         sound_device_type = config.sound_device_type;\r
120 #endif\r
121         \r
122         // initialize\r
123         vm = new VM(this);\r
124 #ifdef USE_DEBUGGER\r
125         initialize_debugger();\r
126 #endif\r
127         initialize_input();\r
128         initialize_screen();\r
129         initialize_sound();\r
130         initialize_media();\r
131         initialize_printer();\r
132 #ifdef USE_SOCKET\r
133         initialize_socket();\r
134 #endif\r
135 #ifdef USE_DIRECT_SHOW\r
136         CoInitialize(NULL);\r
137         initialize_direct_show();\r
138 #endif\r
139         vm->initialize_sound(sound_rate, sound_samples);\r
140         vm->reset();\r
141         now_suspended = false;\r
142 }\r
143 \r
144 EMU::~EMU()\r
145 {\r
146 #ifdef USE_DEBUGGER\r
147         release_debugger();\r
148 #endif\r
149         release_input();\r
150         release_screen();\r
151         release_sound();\r
152         release_printer();\r
153 #ifdef USE_SOCKET\r
154         release_socket();\r
155 #endif\r
156 #ifdef USE_DIRECT_SHOW\r
157         release_direct_show();\r
158         CoInitialize(NULL);\r
159 #endif\r
160 \r
161 #if defined(_USE_AGAR) || (_USE_SDL) || defined(_USE_QT)\r
162        if(pVMSemaphore) SDL_SemWait(pVMSemaphore);\r
163 #endif\r
164         delete vm;\r
165 #ifdef _DEBUG_LOG\r
166         release_debug_log();\r
167 #endif\r
168 #if defined(_USE_AGAR) || (_USE_SDL) || defined(_USE_QT)\r
169       if(pVMSemaphore) SDL_DestroySemaphore(pVMSemaphore);\r
170 #endif\r
171 }\r
172 \r
173 // ----------------------------------------------------------------------------\r
174 // drive machine\r
175 // ----------------------------------------------------------------------------\r
176 \r
177 int EMU::frame_interval()\r
178 {\r
179 #if 1\r
180 #ifdef SUPPORT_VARIABLE_TIMING\r
181         static int prev_interval = 0;\r
182         static double prev_fps = -1;\r
183         double fps = vm->frame_rate();\r
184         if(prev_fps != fps) {\r
185                 prev_interval = (int)(1024. * 1000. / fps + 0.5);\r
186                 prev_fps = fps;\r
187         }\r
188         return prev_interval;\r
189 #else\r
190         return (int)(1024. * 1000. / FRAMES_PER_SEC + 0.5);\r
191 #endif\r
192 #else\r
193         return (int)(1024. * 1000. / FRAMES_PER_SEC + 0.5);\r
194 #endif\r
195 }\r
196 \r
197 int EMU::run()\r
198 {\r
199         if(now_suspended) {\r
200 #ifdef USE_LASER_DISC\r
201                 if(now_movie_play && !now_movie_pause) {\r
202                         play_movie();\r
203                 }\r
204 #endif\r
205                 now_suspended = false;\r
206         }\r
207 #if defined(_USE_AGAR) || (_USE_SDL) || defined(_USE_QT)\r
208         if(pVMSemaphore) SDL_SemWait(pVMSemaphore);\r
209 #endif\r
210         \r
211         update_input();\r
212         update_media();\r
213         update_printer();\r
214 #ifdef USE_SOCKET\r
215         update_socket();\r
216 #endif\r
217         \r
218         // virtual machine may be driven to fill sound buffer\r
219         int extra_frames = 0;\r
220         update_sound(&extra_frames);\r
221         \r
222         // drive virtual machine\r
223         if(extra_frames == 0) {\r
224                 vm->run();\r
225 //              printf("VM:RUN() %d\n", AG_GetTicks());\r
226                 extra_frames = 1;\r
227         }\r
228         rec_video_run_frames += extra_frames;\r
229 #if defined(_USE_AGAR) || (_USE_SDL) || defined(_USE_QT)\r
230         if(pVMSemaphore) SDL_SemPost(pVMSemaphore);\r
231 #endif\r
232         return extra_frames;\r
233 }\r
234 \r
235 void EMU::reset()\r
236 {\r
237         // check if virtual machine should be reinitialized\r
238         bool reinitialize = false;\r
239 #ifdef USE_CPU_TYPE\r
240         reinitialize |= (cpu_type != config.cpu_type);\r
241         cpu_type = config.cpu_type;\r
242 #endif\r
243 #ifdef USE_SOUND_DEVICE_TYPE\r
244         reinitialize |= (sound_device_type != config.sound_device_type);\r
245         sound_device_type = config.sound_device_type;\r
246 #endif\r
247         if(reinitialize) {\r
248                 // stop sound\r
249                 if(sound_ok && sound_started) {\r
250 #if defined(_USE_SDL) || defined(_USE_AGAR) || defined(_USE_QT)\r
251                         //bSndExit = true;\r
252                         SDL_PauseAudio(1);\r
253 #else\r
254                         lpdsb->Stop();\r
255 #endif\r
256                         sound_started = false;\r
257                 }\r
258                 // reinitialize virtual machine\r
259 #if defined(_USE_AGAR) || (_USE_SDL) || defined(_USE_QT)\r
260         if(pVMSemaphore) SDL_SemWait(pVMSemaphore);\r
261 #endif\r
262                 delete vm;\r
263                 vm = new VM(this);\r
264                 vm->initialize_sound(sound_rate, sound_samples);\r
265                 vm->reset();\r
266 #if defined(_USE_AGAR) || (_USE_SDL) || defined(_USE_QT)\r
267         if(pVMSemaphore) SDL_SemPost(pVMSemaphore);\r
268 #endif\r
269                 // restore inserted medias\r
270                 restore_media();\r
271         } else {\r
272            // reset virtual machine\r
273                 vm->reset();\r
274         }\r
275         \r
276         // reset printer\r
277         reset_printer();\r
278         \r
279         // restart recording\r
280         restart_rec_sound();\r
281         restart_rec_video();\r
282 }\r
283 \r
284 #ifdef USE_SPECIAL_RESET\r
285 void EMU::special_reset()\r
286 {\r
287         // reset virtual machine\r
288         vm->special_reset();\r
289         \r
290         // reset printer\r
291         reset_printer();\r
292         \r
293         // restart recording\r
294         restart_rec_sound();\r
295         restart_rec_video();\r
296 }\r
297 #endif\r
298 \r
299 #ifdef USE_POWER_OFF\r
300 void EMU::notify_power_off()\r
301 {\r
302         vm->notify_power_off();\r
303 }\r
304 #endif\r
305 \r
306 _TCHAR* EMU::bios_path(_TCHAR* file_name)\r
307 {\r
308 #if defined(_USE_AGAR) || defined(_USE_SDL) || defined(_USE_QT)\r
309         static _TCHAR file_path[_MAX_PATH];\r
310         strcpy(file_path, app_path);\r
311         strcat(file_path, file_name);\r
312 #if defined(_USE_AGAR) || defined(_USE_SDL) || defined(_USE_QT)\r
313         AGAR_DebugLog(AGAR_LOG_INFO, "LOAD BIOS: %s\n", file_path);\r
314 #endif\r
315 #else\r
316         static _TCHAR file_path[_MAX_PATH];\r
317         _stprintf(file_path, _T("%s%s"), app_path, file_name);\r
318         printf("LOAD: %s\n", file_path);\r
319 #endif\r
320         return file_path;\r
321 }\r
322 \r
323 void EMU::suspend()\r
324 {\r
325         if(!now_suspended) {\r
326 #ifdef USE_LASER_DISC\r
327                 if(now_movie_play && !now_movie_pause) {\r
328                         pause_movie();\r
329                         now_movie_pause = false;\r
330                 }\r
331 #endif\r
332                 mute_sound();\r
333                 now_suspended = true;\r
334         }\r
335 }\r
336 \r
337 // ----------------------------------------------------------------------------\r
338 // timer\r
339 // ----------------------------------------------------------------------------\r
340 \r
341 void EMU::get_host_time(cur_time_t* t)\r
342 {\r
343 #if defined(_USE_AGAR) || defined(_USE_SDL) || defined(_USE_QT)\r
344         std::tm *tm;\r
345         std::time_t tnow;\r
346         tnow = std::time(NULL);\r
347         tm = std::localtime(&tnow);\r
348 \r
349         t->year = tm->tm_year + 1900;\r
350         t->month = tm->tm_mon + 1;\r
351         t->day = tm->tm_mday;\r
352         t->day_of_week = tm->tm_wday;\r
353         t->hour = tm->tm_hour;\r
354         t->minute = tm->tm_min;\r
355         t->second = tm->tm_sec;\r
356 #else\r
357         SYSTEMTIME sTime;\r
358         GetLocalTime(&sTime);\r
359         \r
360         t->year = sTime.wYear;\r
361         t->month = sTime.wMonth;\r
362         t->day = sTime.wDay;\r
363         t->day_of_week = sTime.wDayOfWeek;\r
364         t->hour = sTime.wHour;\r
365         t->minute = sTime.wMinute;\r
366         t->second = sTime.wSecond;\r
367 #endif\r
368 }\r
369 \r
370 // ----------------------------------------------------------------------------\r
371 // printer\r
372 // ----------------------------------------------------------------------------\r
373 \r
374 void EMU::initialize_printer()\r
375 {\r
376         prn_fio = new FILEIO();\r
377         prn_data = -1;\r
378         prn_strobe = false;\r
379 }\r
380 \r
381 void EMU::release_printer()\r
382 {\r
383         close_printer_file();\r
384         delete prn_fio;\r
385 }\r
386 \r
387 void EMU::reset_printer()\r
388 {\r
389         close_printer_file();\r
390         prn_data = -1;\r
391         prn_strobe = false;\r
392 }\r
393 \r
394 void EMU::update_printer()\r
395 {\r
396         if(prn_fio->IsOpened() && --prn_wait_frames == 0) {\r
397                 close_printer_file();\r
398         }\r
399 }\r
400 \r
401 void EMU::open_printer_file()\r
402 {\r
403         cur_time_t time;\r
404         get_host_time(&time);\r
405         _stprintf(prn_file_name, _T("prn_%d-%0.2d-%0.2d_%0.2d-%0.2d-%0.2d.txt"), time.year, time.month, time.day, time.hour, time.minute, time.second);\r
406         prn_fio->Fopen(bios_path(prn_file_name), FILEIO_WRITE_BINARY);\r
407 }\r
408 \r
409 void EMU::close_printer_file()\r
410 {\r
411         if(prn_fio->IsOpened()) {\r
412                 // remove if the file size is less than 2 bytes\r
413                 bool remove = (prn_fio->Ftell() < 2);\r
414                 prn_fio->Fclose();\r
415                 if(remove) {\r
416                         prn_fio->Remove(bios_path(prn_file_name));\r
417                 }\r
418         }\r
419 }\r
420 \r
421 void EMU::printer_out(uint8 value)\r
422 {\r
423         prn_data = value;\r
424 }\r
425 \r
426 void EMU::printer_strobe(bool value)\r
427 {\r
428         bool falling = (prn_strobe && !value);\r
429         prn_strobe = value;\r
430         \r
431         if(falling) {\r
432                 if(!prn_fio->IsOpened()) {\r
433                         if(prn_data == -1) {\r
434                                 return;\r
435                         }\r
436                         open_printer_file();\r
437                 }\r
438                 prn_fio->Fputc(prn_data);\r
439                 // wait 10sec\r
440 #ifdef SUPPORT_VARIABLE_TIMING\r
441                 prn_wait_frames = (int)(vm->frame_rate() * 10.0 + 0.5);\r
442 #else\r
443                 prn_wait_frames = (int)(FRAMES_PER_SEC * 10.0 + 0.5);\r
444 #endif\r
445         }\r
446 }\r
447 \r
448 // ----------------------------------------------------------------------------\r
449 // debug log\r
450 // ----------------------------------------------------------------------------\r
451 \r
452 #ifdef _DEBUG_LOG\r
453 void EMU::initialize_debug_log()\r
454 {\r
455         debug_log = _tfopen(_T("d:\\debug.log"), _T("w"));\r
456 }\r
457 \r
458 void EMU::release_debug_log()\r
459 {\r
460         if(debug_log) {\r
461                 fclose(debug_log);\r
462         }\r
463 }\r
464 #endif\r
465 \r
466 void EMU::out_debug_log(const _TCHAR* format, ...)\r
467 {\r
468 #ifdef _DEBUG_LOG\r
469         va_list ap;\r
470         _TCHAR buffer[1024];\r
471         static _TCHAR prev_buffer[1024] = {0};\r
472         \r
473         va_start(ap, format);\r
474         _vstprintf(buffer, format, ap);\r
475         va_end(ap);\r
476         \r
477         if(_tcscmp(prev_buffer, buffer) == 0) {\r
478                 return;\r
479         }\r
480         _tcscpy(prev_buffer, buffer);\r
481         \r
482         if(debug_log) {\r
483                 _ftprintf(debug_log, _T("%s"), buffer);\r
484                 static int size = 0;\r
485                 if((size += _tcslen(buffer)) > 0x8000000) { // 128MB\r
486                         static int index = 1;\r
487                         TCHAR path[_MAX_PATH];\r
488                         _stprintf(path, _T("d:\\debug_#%d.log"), ++index);\r
489                         fclose(debug_log);\r
490                         debug_log = _tfopen(path, _T("w"));\r
491                         size = 0;\r
492                 }\r
493         }\r
494 #endif\r
495 }\r
496 \r
497 void EMU::out_message(const _TCHAR* format, ...)\r
498 {\r
499         va_list ap;\r
500         va_start(ap, format);\r
501         _vstprintf(message, format, ap);\r
502         va_end(ap);\r
503         message_count = 4; // 4sec\r
504 }\r
505 \r
506 // ----------------------------------------------------------------------------\r
507 // user interface\r
508 // ----------------------------------------------------------------------------\r
509 \r
510 void EMU::initialize_media()\r
511 {\r
512 #ifdef USE_CART1\r
513         memset(&cart_status, 0, sizeof(cart_status));\r
514 #endif\r
515 #ifdef USE_FD1\r
516         memset(disk_status, 0, sizeof(disk_status));\r
517 #endif\r
518 #ifdef USE_QD1\r
519         memset(&quickdisk_status, 0, sizeof(quickdisk_status));\r
520 #endif\r
521 #ifdef USE_TAPE\r
522         memset(&tape_status, 0, sizeof(tape_status));\r
523 #endif\r
524 #ifdef USE_LASER_DISC\r
525         memset(&laser_disc_status, 0, sizeof(laser_disc_status));\r
526 #endif\r
527 }\r
528 \r
529 #if defined(USE_FD1) || defined(USE_FD2) || defined(USE_FD3) || defined(USE_FD4) || \\r
530     defined(USE_FD5) || defined(USE_FD6) || defined(USE_FD7) || defined(USE_FD8)\r
531 \r
532 \r
533 void EMU::write_protect_fd(int drv, bool flag)\r
534 {\r
535   vm->write_protect_fd(drv, flag);\r
536 }\r
537 bool EMU::is_write_protected_fd(int drv)\r
538 {\r
539   return vm->is_write_protect_fd(drv);\r
540 }\r
541 #endif\r
542 \r
543 void EMU::update_media()\r
544 {\r
545 #ifdef USE_FD1\r
546         for(int drv = 0; drv < MAX_FD; drv++) {\r
547                 if(disk_status[drv].wait_count != 0 && --disk_status[drv].wait_count == 0) {\r
548                         vm->open_disk(drv, disk_status[drv].path, disk_status[drv].offset);\r
549                         out_message(_T("FD%d: %s"), drv + FD_BASE_NUMBER, disk_status[drv].path);\r
550                 }\r
551         }\r
552 #endif\r
553 #ifdef USE_QD1\r
554         for(int drv = 0; drv < MAX_QD; drv++) {\r
555                 if(quickdisk_status[drv].wait_count != 0 && --quickdisk_status[drv].wait_count == 0) {\r
556                         vm->open_quickdisk(drv, quickdisk_status[drv].path);\r
557                         out_message(_T("QD%d: %s"), drv + QD_BASE_NUMBER, quickdisk_status[drv].path);\r
558                 }\r
559         }\r
560 #endif\r
561 #ifdef USE_TAPE\r
562         if(tape_status.wait_count != 0 && --tape_status.wait_count == 0) {\r
563                 if(tape_status.play) {\r
564                         vm->play_tape(tape_status.path);\r
565                 } else {\r
566                         vm->rec_tape(tape_status.path);\r
567                 }\r
568                 out_message(_T("CMT: %s"), tape_status.path);\r
569         }\r
570 #endif\r
571 #ifdef USE_LASER_DISC\r
572         if(laser_disc_status.wait_count != 0 && --laser_disc_status.wait_count == 0) {\r
573                 vm->open_laser_disc(laser_disc_status.path);\r
574                 out_message(_T("LD: %s"), laser_disc_status.path);\r
575         }\r
576 #endif\r
577 }\r
578 \r
579 void EMU::restore_media()\r
580 {\r
581 #ifdef USE_CART1\r
582         for(int drv = 0; drv < MAX_CART; drv++) {\r
583                 if(cart_status[drv].path[0] != _T('\0')) {\r
584                         vm->open_cart(drv, cart_status[drv].path);\r
585                 }\r
586         }\r
587 #endif\r
588 #ifdef USE_FD1\r
589         for(int drv = 0; drv < MAX_FD; drv++) {\r
590                 if(disk_status[drv].path[0] != _T('\0')) {\r
591                         vm->open_disk(drv, disk_status[drv].path, disk_status[drv].offset);\r
592                 }\r
593         }\r
594 #endif\r
595 #ifdef USE_QD1\r
596         for(int drv = 0; drv < MAX_QD; drv++) {\r
597                 if(quickdisk_status[drv].path[0] != _T('\0')) {\r
598                         vm->open_quickdisk(drv, quickdisk_status[drv].path);\r
599                 }\r
600         }\r
601 #endif\r
602 #ifdef USE_TAPE\r
603         if(tape_status.path[0] != _T('\0')) {\r
604                 if(tape_status.play) {\r
605                         vm->play_tape(tape_status.path);\r
606                 } else {\r
607                         tape_status.path[0] = _T('\0');\r
608                 }\r
609         }\r
610 #endif\r
611 #ifdef USE_LASER_DISC\r
612         if(laser_disc_status.path[0] != _T('\0')) {\r
613                 vm->open_laser_disc(laser_disc_status.path);\r
614         }\r
615 #endif\r
616 }\r
617 \r
618 #ifdef USE_CART1\r
619 void EMU::open_cart(int drv, _TCHAR* file_path)\r
620 {\r
621         if(drv < MAX_CART) {\r
622                 vm->open_cart(drv, file_path);\r
623                 _tcscpy(cart_status[drv].path, file_path);\r
624                 out_message(_T("Cart%d: %s"), drv + 1, file_path);\r
625                 \r
626                 // restart recording\r
627                 bool s = now_rec_sound;\r
628                 bool v = now_rec_video;\r
629                 stop_rec_sound();\r
630                 stop_rec_video();\r
631                 if(s) start_rec_sound();\r
632                 if(v) start_rec_video(-1);\r
633         }\r
634 }\r
635 \r
636 void EMU::close_cart(int drv)\r
637 {\r
638         if(drv < MAX_CART) {\r
639                 vm->close_cart(drv);\r
640                 clear_media_status(&cart_status[drv]);\r
641                 out_message(_T("Cart%d: Ejected"), drv + 1);\r
642                 \r
643                 // stop recording\r
644                 stop_rec_video();\r
645                 stop_rec_sound();\r
646         }\r
647 }\r
648 \r
649 bool EMU::cart_inserted(int drv)\r
650 {\r
651         if(drv < MAX_CART) {\r
652                 return vm->cart_inserted(drv);\r
653         } else {\r
654                 return false;\r
655         }\r
656 }\r
657 #endif\r
658 \r
659 #ifdef USE_FD1\r
660 void EMU::open_disk(int drv, _TCHAR* file_path, int offset)\r
661 {\r
662         if(drv < MAX_FD) {\r
663                 if(vm->disk_inserted(drv)) {\r
664                         vm->close_disk(drv);\r
665                         // wait 0.5sec\r
666 #ifdef SUPPORT_VARIABLE_TIMING\r
667                         disk_status[drv].wait_count = (int)(vm->frame_rate() / 2);\r
668 #else\r
669                         disk_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);\r
670 #endif\r
671                         out_message(_T("FD%d: Ejected"), drv + FD_BASE_NUMBER);\r
672                 } else if(disk_status[drv].wait_count == 0) {\r
673                         vm->open_disk(drv, file_path, offset);\r
674                         out_message(_T("FD%d: %s"), drv + FD_BASE_NUMBER, file_path);\r
675                 }\r
676                 _tcscpy(disk_status[drv].path, file_path);\r
677                 disk_status[drv].offset = offset;\r
678         }\r
679 }\r
680 \r
681 void EMU::close_disk(int drv)\r
682 {\r
683         if(drv < MAX_FD) {\r
684                 vm->close_disk(drv);\r
685                 clear_media_status(&disk_status[drv]);\r
686                 out_message(_T("FD%d: Ejected"), drv + FD_BASE_NUMBER);\r
687         }\r
688 }\r
689 \r
690 bool EMU::disk_inserted(int drv)\r
691 {\r
692         if(drv < MAX_FD) {\r
693                 return vm->disk_inserted(drv);\r
694         } else {\r
695                 return false;\r
696         }\r
697 }\r
698 #endif\r
699 \r
700 #ifdef USE_QD1\r
701 void EMU::open_quickdisk(int drv, _TCHAR* file_path)\r
702 {\r
703         if(drv < MAX_QD) {\r
704                 if(vm->quickdisk_inserted(drv)) {\r
705                         vm->close_quickdisk(drv);\r
706                         // wait 0.5sec\r
707 #ifdef SUPPORT_VARIABLE_TIMING\r
708                         quickdisk_status[drv].wait_count = (int)(vm->frame_rate() / 2);\r
709 #else\r
710                         quickdisk_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);\r
711 #endif\r
712                         out_message(_T("QD%d: Ejected"), drv + QD_BASE_NUMBER);\r
713                 } else if(quickdisk_status[drv].wait_count == 0) {\r
714                         vm->open_quickdisk(drv, file_path);\r
715                         out_message(_T("QD%d: %s"), drv + QD_BASE_NUMBER, file_path);\r
716                 }\r
717                 _tcscpy(quickdisk_status[drv].path, file_path);\r
718         }\r
719 }\r
720 \r
721 void EMU::close_quickdisk(int drv)\r
722 {\r
723         if(drv < MAX_QD) {\r
724                 vm->close_quickdisk(drv);\r
725                 clear_media_status(&quickdisk_status[drv]);\r
726                 out_message(_T("QD%d: Ejected"), drv + QD_BASE_NUMBER);\r
727         }\r
728 }\r
729 \r
730 bool EMU::quickdisk_inserted(int drv)\r
731 {\r
732         if(drv < MAX_QD) {\r
733                 return vm->quickdisk_inserted(drv);\r
734         } else {\r
735                 return false;\r
736         }\r
737 }\r
738 #endif\r
739 \r
740 #ifdef USE_TAPE\r
741 void EMU::play_tape(_TCHAR* file_path)\r
742 {\r
743         if(vm->tape_inserted()) {\r
744                 vm->close_tape();\r
745                 // wait 0.5sec\r
746 #ifdef SUPPORT_VARIABLE_TIMING\r
747                 tape_status.wait_count = (int)(vm->frame_rate() / 2);\r
748 #else\r
749                 tape_status.wait_count = (int)(FRAMES_PER_SEC / 2);\r
750 #endif\r
751                 out_message(_T("CMT: Ejected"));\r
752         } else if(tape_status.wait_count == 0) {\r
753                 vm->play_tape(file_path);\r
754                 out_message(_T("CMT: %s"), file_path);\r
755         }\r
756         _tcscpy(tape_status.path, file_path);\r
757         tape_status.play = true;\r
758 }\r
759 \r
760 void EMU::rec_tape(_TCHAR* file_path)\r
761 {\r
762         if(vm->tape_inserted()) {\r
763                 vm->close_tape();\r
764                 // wait 0.5sec\r
765 #ifdef SUPPORT_VARIABLE_TIMING\r
766                 tape_status.wait_count = (int)(vm->frame_rate() / 2);\r
767 #else\r
768                 tape_status.wait_count = (int)(FRAMES_PER_SEC / 2);\r
769 #endif\r
770                 out_message(_T("CMT: Ejected"));\r
771         } else if(tape_status.wait_count == 0) {\r
772                 vm->rec_tape(file_path);\r
773                 out_message(_T("CMT: %s"), file_path);\r
774         }\r
775         _tcscpy(tape_status.path, file_path);\r
776         tape_status.play = false;\r
777 }\r
778 \r
779 void EMU::close_tape()\r
780 {\r
781         vm->close_tape();\r
782         clear_media_status(&tape_status);\r
783         out_message(_T("CMT: Ejected"));\r
784 }\r
785 \r
786 bool EMU::tape_inserted()\r
787 {\r
788         return vm->tape_inserted();\r
789 }\r
790 #endif\r
791 \r
792 #ifdef USE_LASER_DISC\r
793 void EMU::open_laser_disc(_TCHAR* file_path)\r
794 {\r
795         if(vm->laser_disc_inserted()) {\r
796                 vm->close_laser_disc();\r
797                 // wait 0.5sec\r
798 #ifdef SUPPORT_VARIABLE_TIMING\r
799                 laser_disc_status.wait_count = (int)(vm->frame_rate() / 2);\r
800 #else\r
801                 laser_disc_status.wait_count = (int)(FRAMES_PER_SEC / 2);\r
802 #endif\r
803                 out_message(_T("LD: Ejected"));\r
804         } else if(laser_disc_status.wait_count == 0) {\r
805                 vm->open_laser_disc(file_path);\r
806                 out_message(_T("LD: %s"), file_path);\r
807         }\r
808         _tcscpy(laser_disc_status.path, file_path);\r
809 }\r
810 \r
811 void EMU::close_laser_disc()\r
812 {\r
813         vm->close_laser_disc();\r
814         clear_media_status(&laser_disc_status);\r
815         out_message(_T("LD: Ejected"));\r
816 }\r
817 \r
818 bool EMU::laser_disc_inserted()\r
819 {\r
820         return vm->laser_disc_inserted();\r
821 }\r
822 #endif\r
823 \r
824 #ifdef USE_TAPE_BUTTON\r
825 void EMU::push_play()\r
826 {\r
827         vm->push_play();\r
828 }\r
829 \r
830 void EMU::push_stop()\r
831 {\r
832         vm->push_stop();\r
833 }\r
834 #endif\r
835 \r
836 #ifdef USE_BINARY_FILE1\r
837 void EMU::load_binary(int drv, _TCHAR* file_path)\r
838 {\r
839         if(drv < MAX_BINARY) {\r
840                 vm->load_binary(drv, file_path);\r
841                 out_message(_T("Load: %s"), file_path);\r
842         }\r
843 }\r
844 \r
845 void EMU::save_binary(int drv, _TCHAR* file_path)\r
846 {\r
847         if(drv < MAX_BINARY) {\r
848                 vm->save_binary(drv, file_path);\r
849                 out_message(_T("Save: %s"), file_path);\r
850         }\r
851 }\r
852 #endif\r
853 \r
854 bool EMU::now_skip()\r
855 {\r
856         return vm->now_skip();\r
857 }\r
858 \r
859 void EMU::update_config()\r
860 {\r
861         vm->update_config();\r
862 }\r
863 \r
864 #ifdef USE_STATE\r
865 // ----------------------------------------------------------------------------\r
866 // state\r
867 // ----------------------------------------------------------------------------\r
868 \r
869 #define STATE_VERSION   1\r
870 \r
871 void EMU::save_state()\r
872 {\r
873         _TCHAR file_name[_MAX_PATH];\r
874         _stprintf(file_name, _T("%s.sta"), _T(CONFIG_NAME));\r
875         save_state_tmp(bios_path(file_name));\r
876 }\r
877 \r
878 void EMU::load_state()\r
879 {\r
880         _TCHAR file_name[_MAX_PATH];\r
881         _stprintf(file_name, _T("%s.sta"), _T(CONFIG_NAME));\r
882         save_state_tmp(bios_path(_T("$temp$.sta")));\r
883         if(!load_state_tmp(bios_path(file_name))) {\r
884                 load_state_tmp(bios_path(_T("$temp$.sta")));\r
885         }\r
886         DeleteFile(bios_path(_T("$temp$.sta")));\r
887 }\r
888 \r
889 void EMU::save_state_tmp(_TCHAR* file_path)\r
890 {\r
891         FILEIO* fio = new FILEIO();\r
892 #if defined(_USE_AGAR) || (_USE_SDL) || defined(_USE_QT)\r
893         if(pVMSemaphore) SDL_SemWait(pVMSemaphore);\r
894 #endif\r
895         if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {\r
896                 // save state file version\r
897                 fio->FputUint32(STATE_VERSION);\r
898                 // save config\r
899                 save_config_state((void *)fio);\r
900                 // save inserted medias\r
901 #ifdef USE_CART1\r
902                 fio->Fwrite(&cart_status, sizeof(cart_status), 1);\r
903 #endif\r
904 #ifdef USE_FD1\r
905                 fio->Fwrite(disk_status, sizeof(disk_status), 1);\r
906                 fio->Fwrite(d88_file, sizeof(d88_file), 1);\r
907 #endif\r
908 #ifdef USE_QD1\r
909                 fio->Fwrite(&quickdisk_status, sizeof(quickdisk_status), 1);\r
910 #endif\r
911 #ifdef USE_TAPE\r
912                 fio->Fwrite(&tape_status, sizeof(tape_status), 1);\r
913 #endif\r
914 #ifdef USE_LASER_DISC\r
915                 fio->Fwrite(&laser_disc_status, sizeof(laser_disc_status), 1);\r
916 #endif\r
917                 // save vm state\r
918                 vm->save_state(fio);\r
919                 // end of state file\r
920                 fio->FputInt32(-1);\r
921                 fio->Fclose();\r
922         }\r
923 #if defined(_USE_AGAR) || (_USE_SDL) || defined(_USE_QT)\r
924         if(pVMSemaphore) SDL_SemPost(pVMSemaphore);\r
925 #endif\r
926         delete fio;\r
927 }\r
928 \r
929 bool EMU::load_state_tmp(_TCHAR* file_path)\r
930 {\r
931         bool result = false;\r
932         FILEIO* fio = new FILEIO();\r
933         if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {\r
934                 // check state file version\r
935                 if(fio->FgetUint32() == STATE_VERSION) {\r
936                         // load config\r
937                         if(load_config_state((void *)fio)) {\r
938                                 // load inserted medias\r
939 #ifdef USE_CART1\r
940                                 fio->Fread(&cart_status, sizeof(cart_status), 1);\r
941 #endif\r
942 #ifdef USE_FD1\r
943                                 fio->Fread(disk_status, sizeof(disk_status), 1);\r
944                                 fio->Fread(d88_file, sizeof(d88_file), 1);\r
945 #endif\r
946 #ifdef USE_QD1\r
947                                 fio->Fread(&quickdisk_status, sizeof(quickdisk_status), 1);\r
948 #endif\r
949 #ifdef USE_TAPE\r
950                                 fio->Fread(&tape_status, sizeof(tape_status), 1);\r
951 #endif\r
952 #ifdef USE_LASER_DISC\r
953                                 fio->Fread(&laser_disc_status, sizeof(laser_disc_status), 1);\r
954 #endif\r
955                                 // check if virtual machine should be reinitialized\r
956                                 bool reinitialize = false;\r
957 #ifdef USE_CPU_TYPE\r
958                                 reinitialize |= (cpu_type != config.cpu_type);\r
959                                 cpu_type = config.cpu_type;\r
960 #endif\r
961 #ifdef USE_SOUND_DEVICE_TYPE\r
962                                 reinitialize |= (sound_device_type != config.sound_device_type);\r
963                                 sound_device_type = config.sound_device_type;\r
964 #endif\r
965                                 if(reinitialize) {\r
966                                         // stop sound\r
967                                         if(sound_ok && sound_started) {\r
968 #if defined(_USE_SDL) || defined(_USE_AGAR) || defined(_USE_QT)\r
969                                                 //bSndExit = true;\r
970                                                 SDL_PauseAudio(1);\r
971 #else\r
972                                                 lpdsb->Stop();\r
973 #endif\r
974                                                 sound_started = false;\r
975                                         }\r
976 #if defined(_USE_AGAR) || (_USE_SDL) || defined(_USE_QT)\r
977                                         if(pVMSemaphore) SDL_SemWait(pVMSemaphore);\r
978 #endif\r
979                                         // reinitialize virtual machine\r
980                                         delete vm;\r
981                                         vm = new VM(this);\r
982                                         vm->initialize_sound(sound_rate, sound_samples);\r
983                                         vm->reset();\r
984 #if defined(_USE_AGAR) || (_USE_SDL) || defined(_USE_QT)\r
985                                         if(pVMSemaphore) SDL_SemPost(pVMSemaphore);\r
986 #endif\r
987                                 }\r
988                                 // restore inserted medias\r
989                                 restore_media();\r
990                                 // load vm state\r
991                                 if(vm->load_state(fio)) {\r
992                                         // check end of state\r
993                                         result = (fio->FgetInt32() == -1);\r
994                                 }\r
995                         }\r
996                 }\r
997                 fio->Fclose();\r
998         }\r
999         delete fio;\r
1000         return result;\r
1001 }\r
1002 #endif\r
1003 \r