OSDN Git Service

[VM][General][Qt] Merge upstream 2015-12-31.
[csp-qt/common_source_project-fm7.git] / source / src / emu.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2006.08.18 -
6
7         [ win32 emulation i/f ]
8 */
9
10 #include "emu.h"
11 #include "vm/vm.h"
12 #include "fileio.h"
13
14 #ifndef FD_BASE_NUMBER
15 #define FD_BASE_NUMBER 1
16 #endif
17 #ifndef QD_BASE_NUMBER
18 #define QD_BASE_NUMBER 1
19 #endif
20
21 // ----------------------------------------------------------------------------
22 // initialize
23 // ----------------------------------------------------------------------------
24 #if defined(_USE_QT)
25 // Please permit at least them m(.. )m
26 extern void get_long_full_path_name(_TCHAR* src, _TCHAR* dst);
27 #include <string>
28 #endif
29
30 #if defined(_USE_QT)
31 EMU::EMU(class Ui_MainWindow *hwnd, GLDrawClass *hinst)
32 #elif defined(OSD_WIN32)
33 EMU::EMU(HWND hwnd, HINSTANCE hinst)
34 #else
35 EMU::EMU()
36 #endif
37 {
38         message_count = 0;
39         // store main window handle
40 #ifdef USE_FD1
41         // initialize d88 file info
42         memset(d88_file, 0, sizeof(d88_file));
43 #endif
44         // load sound config
45         static const int freq_table[8] = {
46                 2000, 4000, 8000, 11025, 22050, 44100,
47 #ifdef OVERRIDE_SOUND_FREQ_48000HZ
48                 OVERRIDE_SOUND_FREQ_48000HZ,
49 #else
50                 48000,
51 #endif
52                 96000,
53         };
54         static const double late_table[5] = {0.05, 0.1, 0.2, 0.3, 0.4};
55         
56         if(!(0 <= config.sound_frequency && config.sound_frequency < 8)) {
57                 config.sound_frequency = 6;     // default: 48KHz
58         }
59         if(!(0 <= config.sound_latency && config.sound_latency < 5)) {
60                 config.sound_latency = 1;       // default: 100msec
61         }
62         sound_rate = freq_table[config.sound_frequency];
63         sound_samples = (int)(sound_rate * late_table[config.sound_latency] + 0.5);
64
65 #ifdef USE_CPU_TYPE
66         cpu_type = config.cpu_type;
67 #endif
68 #ifdef USE_SOUND_DEVICE_TYPE
69         sound_device_type = config.sound_device_type;
70 #endif
71 #ifdef USE_PRINTER
72         printer_device_type = config.printer_device_type;
73 #endif
74         
75         // initialize
76         osd = new OSD();
77 #if defined(OSD_QT)
78         osd->main_window_handle = hwnd;
79         osd->glv = hinst;
80         osd->host_cpus = 4;
81 #elif defined(OSD_WIN32)
82         osd->main_window_handle = hwnd;
83         osd->instance_handle = hinst;
84 #endif
85         osd->initialize(sound_rate, sound_samples);
86         osd->vm = vm = new VM(this);
87 #ifdef USE_DEBUGGER
88         initialize_debugger();
89 #endif
90         initialize_media();
91         vm->initialize_sound(sound_rate, sound_samples);
92         vm->reset();
93         
94         now_suspended = false;
95 }
96
97 EMU::~EMU()
98 {
99 #ifdef USE_DEBUGGER
100         release_debugger();
101 #endif
102         delete vm;
103         osd->release();
104         delete osd;
105 #ifdef _DEBUG_LOG
106         release_debug_log();
107 #endif
108 }
109
110 #ifdef OSD_QT
111 EmuThreadClass *EMU::get_parent_handler()
112 {
113         return osd->get_parent_handler();
114 }
115
116 void EMU::set_parent_handler(EmuThreadClass *p, DrawThreadClass *q)
117 {
118         osd->set_parent_thread(p);
119         osd->set_draw_thread(q);
120 }
121
122 void EMU::set_host_cpus(int v)
123 {
124         osd->host_cpus = (v <= 0) ? 1 : v;
125 }
126
127 int EMU::get_host_cpus()
128 {
129         return osd->host_cpus;
130 }
131 #endif
132
133 // ----------------------------------------------------------------------------
134 // drive machine
135 // ----------------------------------------------------------------------------
136
137 int EMU::frame_interval()
138 {
139 #ifdef SUPPORT_VARIABLE_TIMING
140         static int prev_interval = 0;
141         static double prev_fps = -1;
142         double fps = vm->frame_rate();
143         if(prev_fps != fps) {
144                 prev_interval = (int)(1024. * 1000. / fps + 0.5);
145                 prev_fps = fps;
146         }
147         return prev_interval;
148 #else
149         return (int)(1024. * 1000. / FRAMES_PER_SEC + 0.5);
150 #endif
151 }
152
153 bool EMU::now_skip()
154 {
155         return vm->now_skip();
156 }
157
158 int EMU::run()
159 {
160         if(now_suspended) {
161                 osd->restore();
162                 now_suspended = false;
163         }
164         osd->update_input();
165 #ifdef USE_SOCKET
166         //osd->update_socket();
167 #endif
168         update_media();
169         
170         // virtual machine may be driven to fill sound buffer
171         int extra_frames = 0;
172         osd->update_sound(&extra_frames);
173         
174         // drive virtual machine
175         if(extra_frames == 0) {
176                 osd->lock_vm();
177                 vm->run();
178                 extra_frames = 1;
179                 osd->unlock_vm();
180         }
181         osd->add_extra_frames(extra_frames);
182         return extra_frames;
183 }
184
185 void EMU::reset()
186 {
187         // check if virtual machine should be reinitialized
188         bool reinitialize = false;
189 #ifdef USE_CPU_TYPE
190         reinitialize |= (cpu_type != config.cpu_type);
191         cpu_type = config.cpu_type;
192 #endif
193 #ifdef USE_SOUND_DEVICE_TYPE
194         reinitialize |= (sound_device_type != config.sound_device_type);
195         sound_device_type = config.sound_device_type;
196 #endif
197 #ifdef USE_PRINTER
198         reinitialize |= (printer_device_type != config.printer_device_type);
199         printer_device_type = config.printer_device_type;
200 #endif
201         if(reinitialize) {
202                 // stop sound
203                 osd->stop_sound();
204                 // reinitialize virtual machine
205                 osd->lock_vm();         
206                 delete vm;
207                 osd->vm = vm = new VM(this);
208                 vm->initialize_sound(sound_rate, sound_samples);
209                 vm->reset();
210                 osd->unlock_vm();
211                 // restore inserted medias
212                 restore_media();
213         } else {
214                 // reset virtual machine
215                 osd->lock_vm();         
216                 vm->reset();
217                 osd->unlock_vm();               
218         }
219         
220 #if !defined(_USE_QT) // Temporally
221         // restart recording
222         osd->restart_rec_sound();
223         osd->restart_rec_video();
224 #endif  
225 }
226
227 #ifdef USE_SPECIAL_RESET
228 void EMU::special_reset()
229 {
230         // reset virtual machine
231         osd->lock_vm();         
232         vm->special_reset();
233         osd->unlock_vm();
234         // restart recording
235 #if !defined(_USE_QT) // Temporally
236         restart_rec_sound();
237         restart_rec_video();
238 #endif  
239 }
240 #endif
241
242 #ifdef USE_NOTIFY_POWER_OFF
243 void EMU::notify_power_off()
244 {
245         vm->notify_power_off();
246 }
247 #endif
248
249 void EMU::power_off()
250 {
251         osd->power_off();
252 }
253
254 void EMU::suspend()
255 {
256         if(!now_suspended) {
257                 osd->suspend();
258                 now_suspended = true;
259         }
260 }
261
262 void EMU::lock_vm()
263 {
264         osd->lock_vm();
265 }
266
267 void EMU::unlock_vm()
268 {
269         osd->unlock_vm();
270 }
271
272 void EMU::force_unlock_vm()
273 {
274         osd->force_unlock_vm();
275 }
276
277
278 // ----------------------------------------------------------------------------
279 // input
280 // ----------------------------------------------------------------------------
281
282 #ifdef OSD_QT
283 void EMU::key_modifiers(uint32 mod)
284 {
285         osd->key_modifiers(mod);
286 }
287
288 void EMU::set_mouse_pointer(int x, int y)
289 {
290         osd->set_mouse_pointer(x, y);
291 }
292
293 void EMU::set_mouse_button(int button)
294 {
295         osd->set_mouse_button(button);
296 }
297
298 int EMU::get_mouse_button()
299 {
300         return osd->get_mouse_button();
301 }
302
303 #endif
304
305 void EMU::key_down(int code, bool repeat)
306 {
307         osd->key_down(code, repeat);
308 }
309
310 void EMU::key_up(int code)
311 {
312         osd->key_up(code);
313 }
314
315 void EMU::key_lost_focus()
316 {
317         osd->key_lost_focus();
318 }
319
320 #ifdef ONE_BOARD_MICRO_COMPUTER
321 void EMU::press_button(int num)
322 {
323         osd->press_button(num);
324 }
325 #endif
326
327 void EMU::enable_mouse()
328 {
329         osd->enable_mouse();
330 }
331
332 void EMU::disenable_mouse()
333 {
334         osd->disenable_mouse();
335 }
336
337 void EMU::toggle_mouse()
338 {
339         osd->toggle_mouse();
340 }
341
342 bool EMU::get_mouse_enabled()
343 {
344         return osd->get_mouse_enabled();
345 }
346
347 #ifdef USE_AUTO_KEY
348 void EMU::start_auto_key()
349 {
350         osd->start_auto_key();
351 }
352
353 void EMU::stop_auto_key()
354 {
355         osd->stop_auto_key();
356 }
357
358 bool EMU::now_auto_key()
359 {
360         return osd->now_auto_key();
361 }
362 #endif
363
364 uint8* EMU::key_buffer()
365 {
366         return osd->key_buffer();
367 }
368
369 uint32* EMU::joy_buffer()
370 {
371         return osd->joy_buffer();
372 }
373 int* EMU::mouse_buffer()
374 {
375         return osd->mouse_buffer();
376 }
377
378 // ----------------------------------------------------------------------------
379 // screen
380 // ----------------------------------------------------------------------------
381
382 int EMU::get_window_width(int mode)
383 {
384         return osd->get_window_width(mode);
385 }
386
387 int EMU::get_window_height(int mode)
388 {
389         return osd->get_window_height(mode);
390 }
391
392 void EMU::set_window_size(int width, int height, bool window_mode)
393 {
394         osd->set_window_size(width, height, window_mode);
395 }
396
397 void EMU::set_vm_screen_size(int sw, int sh, int swa, int sha, int ww, int wh)
398 {
399         osd->set_vm_screen_size(sw, sh, swa, sha, ww, wh);
400 }
401
402 #if defined(USE_MINIMUM_RENDERING)
403 bool EMU::screen_changed()
404 {
405         return vm->screen_changed();
406 }
407 #endif
408
409 int EMU::draw_screen()
410 {
411         return osd->draw_screen();
412 }
413
414 scrntype* EMU::screen_buffer(int y)
415 {
416         return osd->get_vm_screen_buffer(y);
417 }
418
419 #ifdef USE_CRT_FILTER
420 void EMU::screen_skip_line(bool skip_line)
421 {
422         osd->screen_skip_line = skip_line;
423 }
424 #endif
425
426 #ifdef ONE_BOARD_MICRO_COMPUTER
427 void EMU::reload_bitmap()
428 {
429         osd->reload_bitmap();
430 }
431 #endif
432
433 #ifdef OSD_WIN32
434 void EMU::update_screen(HDC hdc)
435 {
436         osd->update_screen(hdc);
437 }
438 #endif
439
440 void EMU::capture_screen()
441 {
442         osd->capture_screen();
443 }
444
445 bool EMU::start_rec_video(int fps)
446 {
447         return osd->start_rec_video(fps);
448 }
449
450 void EMU::stop_rec_video()
451 {
452         osd->stop_rec_video();
453 }
454
455 bool EMU::now_rec_video()
456 {
457         return osd->now_rec_video;
458 }
459
460 // ----------------------------------------------------------------------------
461 // sound
462 // ----------------------------------------------------------------------------
463
464 void EMU::mute_sound()
465 {
466         osd->mute_sound();
467 }
468
469 void EMU::start_rec_sound()
470 {
471         osd->start_rec_sound();
472 }
473
474 void EMU::stop_rec_sound()
475 {
476         osd->stop_rec_sound();
477 }
478
479 bool EMU::now_rec_sound()
480 {
481         return osd->now_rec_sound;
482 }
483
484 // ----------------------------------------------------------------------------
485 // video
486 // ----------------------------------------------------------------------------
487
488 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
489 void EMU::get_video_buffer()
490 {
491         osd->get_video_buffer();
492 }
493
494 void EMU::mute_video_dev(bool l, bool r)
495 {
496         osd->mute_video_dev(l, r);
497 }
498 #endif
499
500 #ifdef USE_MOVIE_PLAYER
501 bool EMU::open_movie_file(const _TCHAR* file_path)
502 {
503         return osd->open_movie_file(file_path);
504 }
505
506 void EMU::close_movie_file()
507 {
508         osd->close_movie_file();
509 }
510
511 void EMU::play_movie()
512 {
513         osd->play_movie();
514 }
515
516 void EMU::stop_movie()
517 {
518         osd->stop_movie();
519 }
520
521 void EMU::pause_movie()
522 {
523         osd->pause_movie();
524 }
525
526 double EMU::get_movie_frame_rate()
527 {
528         return osd->get_movie_frame_rate();
529 }
530
531 int EMU::get_movie_sound_rate()
532 {
533         return osd->get_movie_sound_rate();
534 }
535
536 void EMU::set_cur_movie_frame(int frame, bool relative)
537 {
538         osd->set_cur_movie_frame(frame, relative);
539 }
540
541 uint32 EMU::get_cur_movie_frame()
542 {
543         return osd->get_cur_movie_frame();
544 }
545 #endif
546
547 #ifdef USE_VIDEO_CAPTURE
548 int EMU::get_cur_capture_dev_index()
549 {
550         return osd->get_cur_capture_dev_index();
551 }
552
553 int EMU::get_num_capture_devs()
554 {
555         return osd->get_num_capture_devs();
556 }
557
558 _TCHAR* EMU::get_capture_dev_name(int index)
559 {
560         return osd->get_capture_dev_name(index);
561 }
562
563 void EMU::open_capture_dev(int index, bool pin)
564 {
565         osd->open_capture_dev(index, pin);
566 }
567
568 void EMU::close_capture_dev()
569 {
570         osd->close_capture_dev();
571 }
572
573 void EMU::show_capture_dev_filter()
574 {
575         osd->show_capture_dev_filter();
576 }
577
578 void EMU::show_capture_dev_pin()
579 {
580         osd->show_capture_dev_pin();
581 }
582
583 void EMU::show_capture_dev_source()
584 {
585         osd->show_capture_dev_source();
586 }
587
588 void EMU::set_capture_dev_channel(int ch)
589 {
590         osd->set_capture_dev_channel(ch);
591 }
592 #endif
593
594 // ----------------------------------------------------------------------------
595 // printer
596 // ----------------------------------------------------------------------------
597
598 #ifdef USE_PRINTER
599 void EMU::create_bitmap(bitmap_t *bitmap, int width, int height)
600 {
601         osd->create_bitmap(bitmap, width, height);
602 }
603
604 void EMU::release_bitmap(bitmap_t *bitmap)
605 {
606         osd->release_bitmap(bitmap);
607 }
608
609 void EMU::create_font(font_t *font, const _TCHAR *family, int width, int height, int rotate, bool bold, bool italic)
610 {
611         osd->create_font(font, family, width, height, rotate, bold, italic);
612 }
613
614 void EMU::release_font(font_t *font)
615 {
616         osd->release_font(font);
617 }
618
619 void EMU::create_pen(pen_t *pen, int width, uint8 r, uint8 g, uint8 b)
620 {
621         osd->create_pen(pen, width, r, g, b);
622 }
623
624 void EMU::release_pen(pen_t *pen)
625 {
626         osd->release_pen(pen);
627 }
628
629 void EMU::clear_bitmap(bitmap_t *bitmap, uint8 r, uint8 g, uint8 b)
630 {
631         osd->clear_bitmap(bitmap, r, g, b);
632 }
633
634 int EMU::get_text_width(bitmap_t *bitmap, font_t *font, const char *text)
635 {
636         return osd->get_text_width(bitmap, font, text);
637 }
638
639 void EMU::draw_text_to_bitmap(bitmap_t *bitmap, font_t *font, int x, int y, const char *text, uint8 r, uint8 g, uint8 b)
640 {
641         osd->draw_text_to_bitmap(bitmap, font, x, y, text, r, g, b);
642 }
643
644 void EMU::draw_line_to_bitmap(bitmap_t *bitmap, pen_t *pen, int sx, int sy, int ex, int ey)
645 {
646         osd->draw_line_to_bitmap(bitmap, pen, sx, sy, ex, ey);
647 }
648
649 void EMU::draw_rectangle_to_bitmap(bitmap_t *bitmap, int x, int y, int width, int height, uint8 r, uint8 g, uint8 b)
650 {
651         osd->draw_rectangle_to_bitmap(bitmap, x, y, width, height, r, g, b);
652 }
653
654 void EMU::draw_point_to_bitmap(bitmap_t *bitmap, int x, int y, uint8 r, uint8 g, uint8 b)
655 {
656         osd->draw_point_to_bitmap(bitmap, x, y, r, g, b);
657 }
658
659 void EMU::stretch_bitmap(bitmap_t *dest, int dest_x, int dest_y, int dest_width, int dest_height, bitmap_t *source, int source_x, int source_y, int source_width, int source_height)
660 {
661         osd->stretch_bitmap(dest, dest_x, dest_y, dest_width, dest_height, source, source_x, source_y, source_width, source_height);
662 }
663
664 void EMU::write_bitmap_to_file(bitmap_t *bitmap, const _TCHAR *file_path)
665 {
666         osd->write_bitmap_to_file(bitmap, file_path);
667 }
668 #endif
669
670 // ----------------------------------------------------------------------------
671 // socket
672 // ----------------------------------------------------------------------------
673
674 #ifdef USE_SOCKET
675 int EMU::get_socket(int ch)
676 {
677         return osd->get_socket(ch);
678 }
679
680 void EMU::socket_connected(int ch)
681 {
682         osd->socket_connected(ch);
683 }
684
685 void EMU::socket_disconnected(int ch)
686 {
687         osd->socket_disconnected(ch);
688 }
689
690 bool EMU::init_socket_tcp(int ch)
691 {
692         return osd->init_socket_tcp(ch);
693 }
694
695 bool EMU::init_socket_udp(int ch)
696 {
697         return osd->init_socket_udp(ch);
698 }
699
700 bool EMU::connect_socket(int ch, uint32 ipaddr, int port)
701 {
702         return osd->connect_socket(ch, ipaddr, port);
703 }
704
705 void EMU::disconnect_socket(int ch)
706 {
707         osd->disconnect_socket(ch);
708 }
709  
710 bool EMU::listen_socket(int ch)
711 {
712         return osd->listen_socket(ch);
713 }
714
715 void EMU::send_data_tcp(int ch)
716 {
717         osd->send_data_tcp(ch);
718 }
719
720 void EMU::send_data_udp(int ch, uint32 ipaddr, int port)
721 {
722         osd->send_data_udp(ch, ipaddr, port);
723 }
724
725 void EMU::send_data(int ch)
726 {
727         osd->send_data(ch);
728 }
729
730 void EMU::recv_data(int ch)
731 {
732         osd->recv_data(ch);
733 }
734 #endif
735
736 // ----------------------------------------------------------------------------
737 // debug log
738 // ----------------------------------------------------------------------------
739
740 #ifdef _DEBUG_LOG
741 void EMU::initialize_debug_log()
742 {
743         _TCHAR path[_MAX_PATH];
744         debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
745 }
746
747 void EMU::release_debug_log()
748 {
749         if(debug_log) {
750                 fclose(debug_log);
751                 debug_log = NULL;
752         }
753 }
754 #endif
755
756 void EMU::out_debug_log(const _TCHAR* format, ...)
757 {
758 #ifdef _DEBUG_LOG
759         va_list ap;
760         _TCHAR buffer[1024];
761         static _TCHAR prev_buffer[1024] = {0};
762         
763         va_start(ap, format);
764         my_vstprintf_s(buffer, 1024, format, ap);
765         va_end(ap);
766
767 #if defined(_USE_QT) || defined(_USE_AGAR) || defined(_USE_SDL)
768         AGAR_DebugLog(AGAR_LOG_DEBUG, "%s", buffer);
769 #else
770         if(my_tcscmp(prev_buffer, buffer) == 0) {
771                 return;
772         }
773         my_tcscpy_s(prev_buffer, 1024, buffer);
774         if(debug_log) {
775                 _ftprintf(debug_log, _T("%s"), buffer);
776                 static int size = 0;
777                 if((size += _tcslen(buffer)) > 0x8000000) { // 128MB
778                         fclose(debug_log);
779                         debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
780                         size = 0;
781                 }
782         }
783 #endif
784 #endif
785 }
786
787 void EMU::out_message(const _TCHAR* format, ...)
788 {
789         va_list ap;
790         va_start(ap, format);
791         my_vstprintf_s(message, 1024, format, ap); // Security for MSVC:C6386.
792         va_end(ap);
793         message_count = 4; // 4sec
794 }
795
796 // ----------------------------------------------------------------------------
797 // misc
798 // ----------------------------------------------------------------------------
799
800
801 void EMU::sleep(uint32 ms)
802 {
803         osd->sleep(ms);
804 }
805
806
807 // ----------------------------------------------------------------------------
808 // user interface
809 // ----------------------------------------------------------------------------
810
811 static uint8 hex2uint8(char *value)
812 {
813         char tmp[3];
814         memset(tmp, 0, sizeof(tmp));
815         memcpy(tmp, value, 2);
816         return (uint8)strtoul(tmp, NULL, 16);
817 }
818
819 static uint16 hex2uint16(char *value)
820 {
821         char tmp[5];
822         memset(tmp, 0, sizeof(tmp));
823         memcpy(tmp, value, 4);
824         return (uint16)strtoul(tmp, NULL, 16);
825 }
826
827 static bool hex2bin(const _TCHAR* file_path, const _TCHAR* dest_path)
828 {
829         bool result = false;
830         FILEIO *fio_s = new FILEIO();
831         if(fio_s->Fopen(file_path, FILEIO_READ_BINARY)) {
832                 int length = 0;
833                 char line[1024];
834                 uint8 buffer[0x10000];
835                 memset(buffer, 0xff, sizeof(buffer));
836                 while(fio_s->Fgets(line, sizeof(line)) != NULL) {
837                         if(line[0] != ':') continue;
838                         int bytes = hex2uint8(line + 1);
839                         int offset = hex2uint16(line + 3);
840                         uint8 record_type = hex2uint8(line + 7);
841                         if(record_type == 0x01) break;
842                         if(record_type != 0x00) continue;
843                         for(int i = 0; i < bytes; i++) {
844                                 if(offset + i < sizeof(buffer)) {
845                                         if(length < offset + i) {
846                                                 length = offset + i;
847                                         }
848                                         buffer[offset + i] = hex2uint8(line + 9 + 2 * i);
849                                 }
850                         }
851                 }
852                 if(length > 0) {
853                         FILEIO *fio_d = new FILEIO();
854                         if(fio_d->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
855                                 fio_d->Fwrite(buffer, length, 1);
856                                 fio_d->Fclose();
857                                 result = true;
858                         }
859                         delete fio_d;
860                 }
861                 fio_s->Fclose();
862         }
863         delete fio_s;
864         return result;
865 }
866
867 void EMU::initialize_media()
868 {
869 #ifdef USE_CART1
870         memset(&cart_status, 0, sizeof(cart_status));
871 #endif
872 #ifdef USE_FD1
873         memset(disk_status, 0, sizeof(disk_status));
874 #endif
875 #ifdef USE_QD1
876         memset(&quickdisk_status, 0, sizeof(quickdisk_status));
877 #endif
878 #ifdef USE_TAPE
879         memset(&tape_status, 0, sizeof(tape_status));
880 #endif
881 #ifdef USE_LASER_DISC
882         memset(&laser_disc_status, 0, sizeof(laser_disc_status));
883 #endif
884 }
885
886
887 void EMU::update_media()
888 {
889 #ifdef USE_FD1
890         for(int drv = 0; drv < MAX_FD; drv++) {
891                 if(disk_status[drv].wait_count != 0 && --disk_status[drv].wait_count == 0) {
892                         vm->open_disk(drv, disk_status[drv].path, disk_status[drv].bank);
893                         out_message(_T("FD%d: %s"), drv + FD_BASE_NUMBER, disk_status[drv].path);
894                 }
895         }
896 #endif
897 #ifdef USE_QD1
898         for(int drv = 0; drv < MAX_QD; drv++) {
899                 if(quickdisk_status[drv].wait_count != 0 && --quickdisk_status[drv].wait_count == 0) {
900                         vm->open_quickdisk(drv, quickdisk_status[drv].path);
901                         out_message(_T("QD%d: %s"), drv + QD_BASE_NUMBER, quickdisk_status[drv].path);
902                 }
903         }
904 #endif
905 #ifdef USE_TAPE
906         if(tape_status.wait_count != 0 && --tape_status.wait_count == 0) {
907                 if(tape_status.play) {
908                         vm->play_tape(tape_status.path);
909                 } else {
910                         vm->rec_tape(tape_status.path);
911                 }
912                 out_message(_T("CMT: %s"), tape_status.path);
913         }
914 #endif
915 #ifdef USE_LASER_DISC
916         if(laser_disc_status.wait_count != 0 && --laser_disc_status.wait_count == 0) {
917                 vm->open_laser_disc(laser_disc_status.path);
918                 out_message(_T("LD: %s"), laser_disc_status.path);
919         }
920 #endif
921 }
922
923 void EMU::restore_media()
924 {
925 #ifdef USE_CART1
926         for(int drv = 0; drv < MAX_CART; drv++) {
927                 if(cart_status[drv].path[0] != _T('\0')) {
928                         if(check_file_extension(cart_status[drv].path, _T(".hex")) && hex2bin(cart_status[drv].path, create_local_path(_T("hex2bin.$$$")))) {
929                                 vm->open_cart(drv, create_local_path(_T("hex2bin.$$$")));
930                                 FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
931                         } else {
932                                 vm->open_cart(drv, cart_status[drv].path);
933                         }
934                 }
935         }
936 #endif
937 #ifdef USE_FD1
938         for(int drv = 0; drv < MAX_FD; drv++) {
939                 if(disk_status[drv].path[0] != _T('\0')) {
940                         vm->open_disk(drv, disk_status[drv].path, disk_status[drv].bank);
941                 }
942         }
943 #endif
944 #ifdef USE_QD1
945         for(int drv = 0; drv < MAX_QD; drv++) {
946                 if(quickdisk_status[drv].path[0] != _T('\0')) {
947                         vm->open_quickdisk(drv, quickdisk_status[drv].path);
948                 }
949         }
950 #endif
951 #ifdef USE_TAPE
952         if(tape_status.path[0] != _T('\0')) {
953                 if(tape_status.play) {
954                         vm->play_tape(tape_status.path);
955                 } else {
956                         tape_status.path[0] = _T('\0');
957                 }
958         }
959 #endif
960 #ifdef USE_LASER_DISC
961         if(laser_disc_status.path[0] != _T('\0')) {
962                 vm->open_laser_disc(laser_disc_status.path);
963         }
964 #endif
965 }
966
967 #ifdef USE_CART1
968 void EMU::open_cart(int drv, const _TCHAR* file_path)
969 {
970         if(drv < MAX_CART) {
971                 if(check_file_extension(file_path, _T(".hex")) && hex2bin(file_path, create_local_path(_T("hex2bin.$$$")))) {
972                         vm->open_cart(drv, create_local_path(_T("hex2bin.$$$")));
973                         FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
974                 } else {
975                         vm->open_cart(drv, file_path);
976                 }
977                 my_tcscpy_s(cart_status[drv].path, _MAX_PATH, file_path);
978                 out_message(_T("Cart%d: %s"), drv + 1, file_path);
979                 
980                 // restart recording
981                 bool s = osd->now_rec_sound;
982                 bool v = osd->now_rec_video;
983                 stop_rec_sound();
984                 stop_rec_video();
985                 if(s) osd->start_rec_sound();
986                 if(v) osd->start_rec_video(-1);
987         }
988 }
989
990 void EMU::close_cart(int drv)
991 {
992         if(drv < MAX_CART) {
993                 vm->close_cart(drv);
994                 clear_media_status(&cart_status[drv]);
995                 out_message(_T("Cart%d: Ejected"), drv + 1);
996                 
997                 // stop recording
998                 stop_rec_video();
999                 stop_rec_sound();
1000         }
1001 }
1002
1003 bool EMU::cart_inserted(int drv)
1004 {
1005         if(drv < MAX_CART) {
1006                 return vm->cart_inserted(drv);
1007         } else {
1008                 return false;
1009         }
1010 }
1011 #endif
1012
1013 #ifdef USE_FD1
1014 void EMU::open_disk(int drv, const _TCHAR* file_path, int bank)
1015 {
1016         if(drv < MAX_FD) {
1017                 if(vm->disk_inserted(drv)) {
1018                         vm->close_disk(drv);
1019                         // wait 0.5sec
1020 #ifdef SUPPORT_VARIABLE_TIMING
1021                         disk_status[drv].wait_count = (int)(vm->frame_rate() / 2);
1022 #else
1023                         disk_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);
1024 #endif
1025                         out_message(_T("FD%d: Ejected"), drv + FD_BASE_NUMBER);
1026                 } else if(disk_status[drv].wait_count == 0) {
1027                         vm->open_disk(drv, file_path, bank);
1028                         out_message(_T("FD%d: %s"), drv + FD_BASE_NUMBER, file_path);
1029                 }
1030                 my_tcscpy_s(disk_status[drv].path, _MAX_PATH, file_path);
1031                 disk_status[drv].bank = bank;
1032         }
1033 }
1034
1035 void EMU::close_disk(int drv)
1036 {
1037         if(drv < MAX_FD) {
1038                 vm->close_disk(drv);
1039                 clear_media_status(&disk_status[drv]);
1040                 out_message(_T("FD%d: Ejected"), drv + FD_BASE_NUMBER);
1041         }
1042 }
1043
1044 bool EMU::disk_inserted(int drv)
1045 {
1046         if(drv < MAX_FD) {
1047                 return vm->disk_inserted(drv);
1048         } else {
1049                 return false;
1050         }
1051 }
1052
1053 void EMU::set_disk_protected(int drv, bool value)
1054 {
1055         if(drv < MAX_FD) {
1056                 vm->set_disk_protected(drv, value);
1057         }
1058 }
1059
1060 bool EMU::get_disk_protected(int drv)
1061 {
1062         if(drv < MAX_FD) {
1063                 return vm->get_disk_protected(drv);
1064         } else {
1065                 return false;
1066         }
1067 }
1068 #endif
1069
1070 int EMU::get_access_lamp(void)
1071 {
1072         return 0;
1073 }
1074
1075 #ifdef USE_QD1
1076 void EMU::open_quickdisk(int drv, const _TCHAR* file_path)
1077 {
1078         if(drv < MAX_QD) {
1079                 if(vm->quickdisk_inserted(drv)) {
1080                         vm->close_quickdisk(drv);
1081                         // wait 0.5sec
1082 #ifdef SUPPORT_VARIABLE_TIMING
1083                         quickdisk_status[drv].wait_count = (int)(vm->frame_rate() / 2);
1084 #else
1085                         quickdisk_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);
1086 #endif
1087                         out_message(_T("QD%d: Ejected"), drv + QD_BASE_NUMBER);
1088                 } else if(quickdisk_status[drv].wait_count == 0) {
1089                         vm->open_quickdisk(drv, file_path);
1090                         out_message(_T("QD%d: %s"), drv + QD_BASE_NUMBER, file_path);
1091                 }
1092                 my_tcscpy_s(quickdisk_status[drv].path, _MAX_PATH, file_path);
1093         }
1094 }
1095
1096 void EMU::close_quickdisk(int drv)
1097 {
1098         if(drv < MAX_QD) {
1099                 vm->close_quickdisk(drv);
1100                 clear_media_status(&quickdisk_status[drv]);
1101                 out_message(_T("QD%d: Ejected"), drv + QD_BASE_NUMBER);
1102         }
1103 }
1104
1105 bool EMU::quickdisk_inserted(int drv)
1106 {
1107         if(drv < MAX_QD) {
1108                 return vm->quickdisk_inserted(drv);
1109         } else {
1110                 return false;
1111         }
1112 }
1113 #endif
1114
1115 #ifdef USE_TAPE
1116 void EMU::play_tape(const _TCHAR* file_path)
1117 {
1118         if(vm->tape_inserted()) {
1119                 vm->close_tape();
1120                 // wait 0.5sec
1121 #ifdef SUPPORT_VARIABLE_TIMING
1122                 tape_status.wait_count = (int)(vm->frame_rate() / 2);
1123 #else
1124                 tape_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1125 #endif
1126                 out_message(_T("CMT: Ejected"));
1127         } else if(tape_status.wait_count == 0) {
1128                 vm->play_tape(file_path);
1129                 out_message(_T("CMT: %s"), file_path);
1130         }
1131         my_tcscpy_s(tape_status.path, _MAX_PATH, file_path);
1132         tape_status.play = true;
1133 }
1134
1135 void EMU::rec_tape(const _TCHAR* file_path)
1136 {
1137         if(vm->tape_inserted()) {
1138                 vm->close_tape();
1139                 // wait 0.5sec
1140 #ifdef SUPPORT_VARIABLE_TIMING
1141                 tape_status.wait_count = (int)(vm->frame_rate() / 2);
1142 #else
1143                 tape_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1144 #endif
1145                 out_message(_T("CMT: Ejected"));
1146         } else if(tape_status.wait_count == 0) {
1147                 vm->rec_tape(file_path);
1148                 out_message(_T("CMT: %s"), file_path);
1149         }
1150         my_tcscpy_s(tape_status.path, _MAX_PATH, file_path);
1151         tape_status.play = false;
1152 }
1153
1154 void EMU::close_tape()
1155 {
1156         vm->close_tape();
1157         clear_media_status(&tape_status);
1158         out_message(_T("CMT: Ejected"));
1159 }
1160
1161 bool EMU::tape_inserted()
1162 {
1163         return vm->tape_inserted();
1164 }
1165
1166 #ifndef TAPE_BINARY_ONLY
1167 bool EMU::tape_playing()
1168 {
1169         return vm->tape_playing();
1170 }
1171
1172 bool EMU::tape_recording()
1173 {
1174         return vm->tape_recording();
1175 }
1176
1177 int EMU::tape_position()
1178 {
1179         return vm->tape_position();
1180 }
1181 #endif
1182
1183 #ifdef USE_TAPE_BUTTON
1184 void EMU::push_play()
1185 {
1186         vm->push_play();
1187 }
1188
1189 void EMU::push_stop()
1190 {
1191         vm->push_stop();
1192 }
1193
1194 void EMU::push_fast_forward()
1195 {
1196         vm->push_fast_forward();
1197 }
1198
1199 void EMU::push_fast_rewind()
1200 {
1201         vm->push_fast_rewind();
1202 }
1203
1204 void EMU::push_apss_forward()
1205 {
1206         vm->push_apss_forward();
1207 }
1208
1209 void EMU::push_apss_rewind()
1210 {
1211         vm->push_apss_rewind();
1212 }
1213 #endif
1214 #endif
1215
1216 #ifdef USE_LASER_DISC
1217 void EMU::open_laser_disc(const _TCHAR* file_path)
1218 {
1219         if(vm->laser_disc_inserted()) {
1220                 vm->close_laser_disc();
1221                 // wait 0.5sec
1222 #ifdef SUPPORT_VARIABLE_TIMING
1223                 laser_disc_status.wait_count = (int)(vm->frame_rate() / 2);
1224 #else
1225                 laser_disc_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1226 #endif
1227                 out_message(_T("LD: Ejected"));
1228         } else if(laser_disc_status.wait_count == 0) {
1229                 vm->open_laser_disc(file_path);
1230                 out_message(_T("LD: %s"), file_path);
1231         }
1232         my_tcscpy_s(laser_disc_status.path, _MAX_PATH, file_path);
1233 }
1234
1235 void EMU::close_laser_disc()
1236 {
1237         vm->close_laser_disc();
1238         clear_media_status(&laser_disc_status);
1239         out_message(_T("LD: Ejected"));
1240 }
1241
1242 bool EMU::laser_disc_inserted()
1243 {
1244         return vm->laser_disc_inserted();
1245 }
1246 #endif
1247
1248 #ifdef USE_BINARY_FILE1
1249 void EMU::load_binary(int drv, const _TCHAR* file_path)
1250 {
1251         if(drv < MAX_BINARY) {
1252                 if(check_file_extension(file_path, _T(".hex")) && hex2bin(file_path, create_local_path(_T("hex2bin.$$$")))) {
1253                         vm->load_binary(drv, create_local_path(_T("hex2bin.$$$")));
1254                         FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
1255                 } else {
1256                         vm->load_binary(drv, file_path);
1257                 }
1258                 out_message(_T("Load: %s"), file_path);
1259         }
1260 }
1261
1262 void EMU::save_binary(int drv, const _TCHAR* file_path)
1263 {
1264         if(drv < MAX_BINARY) {
1265                 vm->save_binary(drv, file_path);
1266                 out_message(_T("Save: %s"), file_path);
1267         }
1268 }
1269 #endif
1270
1271 // I will decide to move this to osd?
1272 #ifdef SUPPORT_DUMMY_DEVICE_LED
1273 uint32 EMU::get_led_status(void)
1274 {
1275         return vm->get_led_status();
1276 }
1277 #endif
1278
1279 void EMU::update_config()
1280 {
1281         vm->update_config();
1282 }
1283
1284
1285
1286 // ----------------------------------------------------------------------------
1287 // state
1288 // ----------------------------------------------------------------------------
1289
1290 #ifdef USE_STATE
1291 #define STATE_VERSION   2
1292
1293 void EMU::save_state()
1294 {
1295         save_state_tmp(create_local_path(_T("%s.sta"), _T(CONFIG_NAME)));
1296 }
1297
1298 void EMU::load_state()
1299 {
1300         if(FILEIO::IsFileExists(create_local_path(_T("%s.sta"), _T(CONFIG_NAME)))) {
1301                 save_state_tmp(create_local_path(_T("$temp$.sta")));
1302                 if(!load_state_tmp(create_local_path(_T("%s.sta"), _T(CONFIG_NAME)))) {
1303                         out_debug_log(_T("failed to load state file\n"));
1304                         load_state_tmp(create_local_path(_T("$temp$.sta")));
1305                 }
1306                 FILEIO::RemoveFile(create_local_path(_T("$temp$.sta")));
1307         }
1308 }
1309
1310 void EMU::save_state_tmp(const _TCHAR* file_path)
1311 {
1312         FILEIO* fio = new FILEIO();
1313         osd->lock_vm();
1314         if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
1315                 // save state file version
1316                 fio->FputUint32(STATE_VERSION);
1317                 // save config
1318                 save_config_state((void *)fio);
1319                 // save inserted medias
1320 #ifdef USE_CART1
1321                 fio->Fwrite(&cart_status, sizeof(cart_status), 1);
1322 #endif
1323 #ifdef USE_FD1
1324                 fio->Fwrite(disk_status, sizeof(disk_status), 1);
1325                 fio->Fwrite(d88_file, sizeof(d88_file), 1);
1326 #endif
1327 #ifdef USE_QD1
1328                 fio->Fwrite(&quickdisk_status, sizeof(quickdisk_status), 1);
1329 #endif
1330 #ifdef USE_TAPE
1331                 fio->Fwrite(&tape_status, sizeof(tape_status), 1);
1332 #endif
1333 #ifdef USE_LASER_DISC
1334                 fio->Fwrite(&laser_disc_status, sizeof(laser_disc_status), 1);
1335 #endif
1336                 // save vm state
1337                 vm->save_state(fio);
1338                 // end of state file
1339                 fio->FputInt32(-1);
1340                 fio->Fclose();
1341         }
1342         osd->unlock_vm();
1343         delete fio;
1344 }
1345
1346 bool EMU::load_state_tmp(const _TCHAR* file_path)
1347 {
1348         bool result = false;
1349         FILEIO* fio = new FILEIO();
1350         osd->lock_vm();
1351         if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
1352                 // check state file version
1353                 if(fio->FgetUint32() == STATE_VERSION) {
1354                         // load config
1355                         if(load_config_state((void *)fio)) {
1356                                 // load inserted medias
1357 #ifdef USE_CART1
1358                                 fio->Fread(&cart_status, sizeof(cart_status), 1);
1359 #endif
1360 #ifdef USE_FD1
1361                                 fio->Fread(disk_status, sizeof(disk_status), 1);
1362                                 fio->Fread(d88_file, sizeof(d88_file), 1);
1363 #endif
1364 #ifdef USE_QD1
1365                                 fio->Fread(&quickdisk_status, sizeof(quickdisk_status), 1);
1366 #endif
1367 #ifdef USE_TAPE
1368                                 fio->Fread(&tape_status, sizeof(tape_status), 1);
1369 #endif
1370 #ifdef USE_LASER_DISC
1371                                 fio->Fread(&laser_disc_status, sizeof(laser_disc_status), 1);
1372 #endif
1373                                 // check if virtual machine should be reinitialized
1374                                 bool reinitialize = false;
1375 #ifdef USE_CPU_TYPE
1376                                 reinitialize |= (cpu_type != config.cpu_type);
1377                                 cpu_type = config.cpu_type;
1378 #endif
1379 #ifdef USE_SOUND_DEVICE_TYPE
1380                                 reinitialize |= (sound_device_type != config.sound_device_type);
1381                                 sound_device_type = config.sound_device_type;
1382 #endif
1383 #ifdef USE_PRINTER
1384                                 reinitialize |= (printer_device_type != config.printer_device_type);
1385                                 printer_device_type = config.printer_device_type;
1386 #endif
1387                                 if(reinitialize) {
1388                                         // stop sound
1389                                         //osd->lock_vm();
1390                                         // reinitialize virtual machine
1391                                         osd->stop_sound();
1392                                         delete vm;
1393                                         osd->vm = vm = new VM(this);
1394                                         vm->initialize_sound(sound_rate, sound_samples);
1395                                         vm->reset();
1396                                         //osd->unlock_vm();
1397                                 }
1398                                 // restore inserted medias
1399                                 restore_media();
1400                                 // load vm state
1401                                 if(vm->load_state(fio)) {
1402                                         // check end of state
1403                                         result = (fio->FgetInt32() == -1);
1404                                 }
1405                         }
1406                 }
1407                 fio->Fclose();
1408         }
1409         osd->unlock_vm();
1410         delete fio;
1411         return result;
1412 }
1413 #endif