• R/O
  • HTTP
  • SSH
  • HTTPS

common_source_project-fm7: Commit

Common Source Code Project for Qt (a.k.a for FM-7).


Commit MetaInfo

Revision744ff4c4e59fb11720a1446699fb8536a0b6626e (tree)
Time2018-05-27 15:12:24
AuthorK.Ohta <whatisthis.sowhat@gmai...>
CommiterK.Ohta

Log Message

[UI][Qt] Apply to upstream's updating definitions.Still not implement around HDDs.

Change Summary

Incremental Difference

Binary files /dev/null and b/source/src/000_rejs.lst differ
--- a/source/src/config.cpp
+++ b/source/src/config.cpp
@@ -607,8 +607,8 @@ void save_config(const _TCHAR *config_path)
607607 #ifdef USE_PRINTER
608608 MyWritePrivateProfileInt(_T("Control"), _T("PrinterType"), config.printer_type, config_path);
609609 #endif
610- #ifdef USE_FD1
611- for(int drv = 0; drv < MAX_FD; drv++) {
610+ #ifdef USE_FLOPPY_DISK
611+ for(int drv = 0; drv < USE_FLOPPY_DISK; drv++) {
612612 MyWritePrivateProfileBool(_T("Control"), create_string(_T("CorrectDiskTiming%d"), drv + 1), config.correct_disk_timing[drv], config_path);
613613 MyWritePrivateProfileBool(_T("Control"), create_string(_T("IgnoreDiskCRC%d"), drv + 1), config.ignore_disk_crc[drv], config_path);
614614 #ifdef _USE_QT
@@ -889,7 +889,7 @@ void save_config_state(void *f)
889889 state_fio->FputInt32(config.printer_type);
890890 #endif
891891 #ifdef USE_FLOPPY_DISK
892- for(int drv = 0; drv < MAX_FD; drv++) {
892+ for(int drv = 0; drv < USE_FLOPPY_DISK; drv++) {
893893 state_fio->FputBool(config.correct_disk_timing[drv]);
894894 state_fio->FputBool(config.ignore_disk_crc[drv]);
895895 }
@@ -938,8 +938,8 @@ bool load_config_state(void *f)
938938 #ifdef USE_PRINTER_TYPE
939939 config.printer_type = state_fio->FgetInt32();
940940 #endif
941- #ifdef USE_FD1
942- for(int drv = 0; drv < MAX_FD; drv++) {
941+ #ifdef USE_FLOPPY_DISK
942+ for(int drv = 0; drv < USE_FLOPPY_DISK; drv++) {
943943 config.correct_disk_timing[drv] = state_fio->FgetBool();
944944 config.ignore_disk_crc[drv] = state_fio->FgetBool();
945945 }
--- a/source/src/config.h
+++ b/source/src/config.h
@@ -188,9 +188,9 @@ typedef struct {
188188 #endif
189189 #if defined(USE_SHARED_DLL) || defined(USE_LASER_DISC)
190190 _TCHAR initial_laser_disc_dir[_MAX_PATH];
191- _TCHAR recent_compact_disc_path[USE_LASER_DISC_TMP][MAX_HISTORY][_MAX_PATH];
191+ _TCHAR recent_laser_disc_path[USE_LASER_DISC_TMP][MAX_HISTORY][_MAX_PATH];
192192 #endif
193- #if defined(USE_SHARED_DLL) || defined(USE_BINARY_FILE1)
193+ #if defined(USE_SHARED_DLL) || defined(USE_BINARY_FILE)
194194 _TCHAR initial_binary_dir[_MAX_PATH];
195195 _TCHAR recent_binary_path[USE_BINARY_FILE_TMP][MAX_HISTORY][_MAX_PATH];
196196 #endif
--- a/source/src/emu.cpp
+++ b/source/src/emu.cpp
@@ -2162,13 +2162,6 @@ void EMU::restore_media()
21622162 }
21632163 }
21642164 #endif
2165-#ifdef USE_BUBBLE1
2166- for(int drv = 0; drv < MAX_BUBBLE; drv++) {
2167- if(bubble_casette_status[drv].path[0] != _T('\0')) {
2168- vm->open_bubble_casette(drv, bubble_casette_status[drv].path, bubble_casette_status[drv].bank);
2169- }
2170- }
2171-#endif
21722165 }
21732166
21742167 #ifdef USE_CART
--- a/source/src/emu.h
+++ b/source/src/emu.h
@@ -407,22 +407,22 @@ public:
407407 #endif
408408
409409 // media
410-#ifdef USE_FD1
410+#ifdef USE_FLOPPY_DISK
411411 struct {
412412 _TCHAR path[_MAX_PATH];
413413 _TCHAR disk_name[MAX_D88_BANKS][128]; // Convert to UTF8
414414 int bank_num;
415415 int cur_bank;
416- } d88_file[MAX_FD];
416+ } d88_file[USE_FLOPPY_DISK];
417417 #endif
418418
419419 // user interface
420-#ifdef USE_CART1
420+#ifdef USE_CART
421421 void open_cart(int drv, const _TCHAR* file_path);
422422 void close_cart(int drv);
423423 bool is_cart_inserted(int drv);
424424 #endif
425-#ifdef USE_FD1
425+#ifdef USE_FLOPPY_DISK
426426 void open_floppy_disk(int drv, const _TCHAR* file_path, int bank);
427427 void close_floppy_disk(int drv);
428428 bool is_floppy_disk_inserted(int drv);
@@ -430,13 +430,13 @@ public:
430430 bool is_floppy_disk_protected(int drv);
431431 uint32_t is_floppy_disk_accessed();
432432 #endif
433-#ifdef USE_QD1
433+#ifdef USE_QUICK_DISK
434434 void open_quick_disk(int drv, const _TCHAR* file_path);
435435 void close_quick_disk(int drv);
436436 bool is_quick_disk_inserted(int drv);
437437 uint32_t is_quick_disk_accessed();
438438 #endif
439-#ifdef USE_TAPE1
439+#ifdef USE_TAPE
440440 void play_tape(int drv, const _TCHAR* file_path);
441441 void rec_tape(int drv, const _TCHAR* file_path);
442442 void close_tape(int drv);
@@ -468,17 +468,17 @@ public:
468468 bool is_laser_disc_inserted();
469469 uint32_t is_laser_disc_accessed();
470470 #endif
471-#ifdef USE_BINARY_FILE1
471+#ifdef USE_BINARY_FILE
472472 void load_binary(int drv, const _TCHAR* file_path);
473473 void save_binary(int drv, const _TCHAR* file_path);
474474 #endif
475-#ifdef USE_BUBBLE1
475+#ifdef USE_BUBBLE
476476 struct {
477477 _TCHAR path[_MAX_PATH];
478478 _TCHAR bubble_name[MAX_B77_BANKS][128]; // Convert to UTF8
479479 int bank_num;
480480 int cur_bank;
481- } b77_file[MAX_BUBBLE];
481+ } b77_file[USE_BUBBLE];
482482 void open_bubble_casette(int drv, const _TCHAR* file_path, int bank);
483483 void close_bubble_casette(int drv);
484484 bool is_bubble_casette_inserted(int drv);
--- a/source/src/qt/common/emu_thread.cpp
+++ b/source/src/qt/common/emu_thread.cpp
@@ -51,6 +51,8 @@ EmuThreadClass::EmuThreadClass(META_MainWindow *rootWindow, USING_FLAGS *p, QObj
5151 connect(this, SIGNAL(sig_open_cdrom(int, QString)), MainWindow, SLOT(do_open_cdrom(int, QString)));
5252 connect(this, SIGNAL(sig_open_laser_disc(int, QString)), MainWindow, SLOT(do_open_laserdisc(int, QString)));
5353
54+ connect(this, SIGNAL(sig_open_hdd(int, QString)), MainWindow, SLOT(_open_hard_disk(int, QString)));
55+
5456 connect(this, SIGNAL(sig_set_d88_num(int, int)), MainWindow, SLOT(set_d88_slot(int, int)));
5557 connect(this, SIGNAL(sig_set_b77_num(int, int)), MainWindow, SLOT(set_b77_slot(int, int)));
5658 }
@@ -136,7 +138,7 @@ void EmuThreadClass::button_released_mouse_sub(Qt::MouseButton button)
136138
137139 void EmuThreadClass::get_fd_string(void)
138140 {
139-#if defined(USE_FD1)
141+#if defined(USE_FLOPPY_DISK)
140142 int i;
141143 QString tmpstr;
142144 QString iname;
@@ -187,7 +189,7 @@ void EmuThreadClass::get_fd_string(void)
187189
188190 void EmuThreadClass::get_qd_string(void)
189191 {
190-#if defined(USE_QD1)
192+#if defined(USE_QUICK_DISK)
191193 int i;
192194 QString iname;
193195 QString alamp;
@@ -227,8 +229,8 @@ void EmuThreadClass::get_tape_string()
227229 QString tmpstr;
228230 bool readwrite;
229231 bool inserted;
230-#if defined(USE_TAPE1) && !defined(TAPE_BINARY_ONLY)
231- for(int i = 0; i < MAX_TAPE; i++) {
232+#if defined(USE_TAPE) && !defined(TAPE_BINARY_ONLY)
233+ for(int i = 0; i < USE_TAPE; i++) {
232234 inserted = p_emu->is_tape_inserted(i);
233235 readwrite = false;
234236 if(inserted) {
@@ -273,7 +275,7 @@ void EmuThreadClass::get_cd_string(void)
273275
274276 void EmuThreadClass::get_bubble_string(void)
275277 {
276-#if defined(USE_BUBBLE1)
278+#if defined(USE_BUBBLE)
277279 uint32_t access_drv;
278280 int i;
279281 QString alamp;
--- a/source/src/qt/common/emu_thread.h
+++ b/source/src/qt/common/emu_thread.h
@@ -102,6 +102,10 @@ public slots:
102102 void do_stop_auto_key(void);
103103 void set_romakana(bool flag);
104104 void do_close_debugger(void);
105+
106+ void do_close_hard_disk(int);
107+ void do_open_hard_disk(int, QString);
108+
105109 signals:
106110 int sig_set_draw_fps(double);
107111 int sig_draw_one_turn(bool);
--- a/source/src/qt/common/emu_thread_slots.cpp
+++ b/source/src/qt/common/emu_thread_slots.cpp
@@ -489,16 +489,14 @@ void EmuThreadClass::do_stop_auto_key(void)
489489
490490 void EmuThreadClass::do_write_protect_disk(int drv, bool flag)
491491 {
492-#if defined(USE_FD1) || defined(USE_FD2) || defined(USE_FD3) || defined(USE_FD4) || \
493- defined(USE_FD5) || defined(USE_FD6) || defined(USE_FD7) || defined(USE_FD8)
492+#ifdef USE_FLOPPY_DISK
494493 p_emu->is_floppy_disk_protected(drv, flag);
495494 #endif
496495 }
497496
498497 void EmuThreadClass::do_close_disk(int drv)
499498 {
500-#if defined(USE_FD1) || defined(USE_FD2) || defined(USE_FD3) || defined(USE_FD4) || \
501- defined(USE_FD5) || defined(USE_FD6) || defined(USE_FD7) || defined(USE_FD8)
499+#ifdef USE_FLOPPY_DISK
502500 p_emu->close_floppy_disk(drv);
503501 p_emu->d88_file[drv].bank_num = 0;
504502 p_emu->d88_file[drv].cur_bank = -1;
@@ -507,8 +505,7 @@ void EmuThreadClass::do_close_disk(int drv)
507505
508506 void EmuThreadClass::do_open_disk(int drv, QString path, int bank)
509507 {
510-#if defined(USE_FD1) || defined(USE_FD2) || defined(USE_FD3) || defined(USE_FD4) || \
511- defined(USE_FD5) || defined(USE_FD6) || defined(USE_FD7) || defined(USE_FD8)
508+#ifdef USE_FLOPPY_DISK
512509 QByteArray localPath = path.toLocal8Bit();
513510
514511 //p_emu->d88_file[drv].bank_num = 0;
@@ -554,21 +551,21 @@ void EmuThreadClass::do_open_disk(int drv, QString path, int bank)
554551 }
555552 void EmuThreadClass::do_play_tape(int drv, QString name)
556553 {
557-#if defined(USE_TAPE1)
554+#if defined(USE_TAPE)
558555 p_emu->play_tape(drv, name.toLocal8Bit().constData());
559556 #endif
560557 }
561558
562559 void EmuThreadClass::do_rec_tape(int drv, QString name)
563560 {
564-#if defined(USE_TAPE1)
561+#if defined(USE_TAPE)
565562 p_emu->rec_tape(drv, name.toLocal8Bit().constData());
566563 #endif
567564 }
568565
569566 void EmuThreadClass::do_close_tape(int drv)
570567 {
571-#if defined(USE_TAPE1)
568+#if defined(USE_TAPE)
572569 p_emu->close_tape(drv);
573570 #endif
574571 }
@@ -618,21 +615,21 @@ void EmuThreadClass::do_cmt_push_apss_rewind(int drv)
618615
619616 void EmuThreadClass::do_write_protect_quickdisk(int drv, bool flag)
620617 {
621-#if defined(USE_QD1)
618+#ifdef USE_QUICK_DISK
622619 //p_emu->write_protect_Qd(drv, flag);
623620 #endif
624621 }
625622
626623 void EmuThreadClass::do_close_quickdisk(int drv)
627624 {
628-#if defined(USE_QD1)
625+#ifdef USE_QUICK_DISK
629626 p_emu->close_quick_disk(drv);
630627 #endif
631628 }
632629
633630 void EmuThreadClass::do_open_quickdisk(int drv, QString path)
634631 {
635-#if defined(USE_QD1)
632+#ifdef USE_QUICK_DISK
636633 p_emu->open_quick_disk(drv, path.toLocal8Bit().constData());
637634 #endif
638635 }
@@ -652,14 +649,14 @@ void EmuThreadClass::do_eject_cdrom(void)
652649
653650 void EmuThreadClass::do_close_cart(int drv)
654651 {
655-#ifdef USE_CART1
652+#ifdef USE_CART
656653 p_emu->close_cart(drv);
657654 #endif
658655 }
659656
660657 void EmuThreadClass::do_open_cart(int drv, QString path)
661658 {
662-#ifdef USE_CART1
659+#ifdef USE_CART
663660 p_emu->open_cart(drv, path.toLocal8Bit().constData());
664661 #endif
665662 }
@@ -681,14 +678,14 @@ void EmuThreadClass::do_open_laser_disc(QString path)
681678
682679 void EmuThreadClass::do_load_binary(int drv, QString path)
683680 {
684-#ifdef USE_BINARY_FILE1
681+#ifdef USE_BINARY_FILE
685682 p_emu->load_binary(drv, path.toLocal8Bit().constData());
686683 #endif
687684 }
688685
689686 void EmuThreadClass::do_save_binary(int drv, QString path)
690687 {
691-#ifdef USE_BINARY_FILE1
688+#ifdef USE_BINARY_FILE
692689 p_emu->save_binary(drv, path.toLocal8Bit().constData());
693690 #endif
694691 }
@@ -696,14 +693,14 @@ void EmuThreadClass::do_save_binary(int drv, QString path)
696693
697694 void EmuThreadClass::do_write_protect_bubble_casette(int drv, bool flag)
698695 {
699-#ifdef USE_BUBBLE1
696+#ifdef USE_BUBBLE
700697 p_emu->is_bubble_casette_protected(drv, flag);
701698 #endif
702699 }
703700
704701 void EmuThreadClass::do_close_bubble_casette(int drv)
705702 {
706-#ifdef USE_BUBBLE1
703+#ifdef USE_BUBBLE
707704 p_emu->close_bubble_casette(drv);
708705 p_emu->b77_file[drv].bank_num = 0;
709706 p_emu->b77_file[drv].cur_bank = -1;
@@ -712,7 +709,7 @@ void EmuThreadClass::do_close_bubble_casette(int drv)
712709
713710 void EmuThreadClass::do_open_bubble_casette(int drv, QString path, int bank)
714711 {
715-#ifdef USE_BUBBLE1
712+#ifdef USE_BUBBLE
716713 QByteArray localPath = path.toLocal8Bit();
717714
718715 p_emu->b77_file[drv].bank_num = 0;
@@ -773,3 +770,19 @@ bool EmuThreadClass::now_debugging() {
773770 return false;
774771 #endif
775772 }
773+
774+void EmuThreadClass::do_close_hard_disk(int drv)
775+{
776+#ifdef USE_HARD_DISK
777+ p_emu->close_hard_disk(drv);
778+#endif
779+}
780+
781+void EmuThreadClass::do_open_hard_disk(int drv, QString path)
782+{
783+#ifdef USE_HARD_DISK
784+ QByteArray localPath = path.toLocal8Bit();
785+ p_emu->open_hard_disk(drv, localPath.constData(), bank);
786+ emit sig_update_recent_hard_disk(drv);
787+#endif
788+}
--- a/source/src/qt/common/mainwidget.h
+++ b/source/src/qt/common/mainwidget.h
@@ -52,12 +52,17 @@ public:
5252 QString GetBubbleB77BubbleName(int drv, int num);
5353
5454 public slots:
55-#if defined(USE_FD1)
55+#if defined(USE_FLOPPY_DISK)
5656 void _open_disk(int drv, const QString fname);
5757 void do_update_recent_disk(int);
5858 int set_d88_slot(int drive, int num);
5959 int set_recent_disk(int, int);
6060 #endif
61+#if defined(USE_HARD_DISK)
62+ void _open_hard_disk(int drv, const QString fname);
63+ void do_update_recent_hard_disk(int);
64+ int set_recent_hard_disk(int, int);
65+#endif
6166 #if defined(USE_DEBUGGER)
6267 void OnOpenDebugger(int n);
6368 void OnCloseDebugger(void);
--- a/source/src/qt/common/qt_utils.cpp
+++ b/source/src/qt/common/qt_utils.cpp
@@ -142,45 +142,32 @@ void Ui_MainWindow::LaunchEmuThread(void)
142142 connect(actionSave_State[i], SIGNAL(sig_save_state(QString)), hRunEmu, SLOT(do_save_state(QString))); // OK?
143143 }
144144 }
145-#if defined(USE_FD1) || defined(USE_FD2) || defined(USE_FD3) || defined(USE_FD4) || \
146- defined(USE_FD5) || defined(USE_FD6) || defined(USE_FD7) || defined(USE_FD8)
145+#if defined(USE_FLOPPY_DISK)
147146 connect(this, SIGNAL(sig_write_protect_disk(int, bool)), hRunEmu, SLOT(do_write_protect_disk(int, bool)));
148147 connect(this, SIGNAL(sig_open_disk(int, QString, int)), hRunEmu, SLOT(do_open_disk(int, QString, int)));
149148 connect(this, SIGNAL(sig_close_disk(int)), hRunEmu, SLOT(do_close_disk(int)));
150149 connect(hRunEmu, SIGNAL(sig_update_recent_disk(int)), this, SLOT(do_update_recent_disk(int)));
151150 //connect(hRunEmu, SIGNAL(sig_change_osd_fd(int, QString)), this, SLOT(do_change_osd_fd(int, QString)));
152- drvs = 0;
153-# if defined(USE_FD1)
154- drvs = 1;
155-# endif
156-# if defined(USE_FD2)
157- drvs = 2;
158-# endif
159-# if defined(USE_FD3)
160- drvs = 3;
161-# endif
162-# if defined(USE_FD4)
163- drvs = 4;
164-# endif
165-# if defined(USE_FD5)
166- drvs = 5;
167-# endif
168-# if defined(USE_FD6)
169- drvs = 6;
170-# endif
171-# if defined(USE_FD7)
172- drvs = 7;
173-# endif
174-# if defined(USE_FD8)
175- drvs = 8;
176-# endif
151+ drvs = USE_FLOPPY_DISK;
177152 for(int ii = 0; ii < drvs; ii++) {
178153 menu_fds[ii]->setEmu(emu);
179154 connect(menu_fds[ii], SIGNAL(sig_update_inner_fd(int ,QStringList , class Action_Control **, QStringList , int, bool)),
180155 this, SLOT(do_update_inner_fd(int ,QStringList , class Action_Control **, QStringList , int, bool)));
181156 }
182157 #endif
183-#if defined(USE_TAPE1)
158+#if defined(USE_HARD_DISK)
159+ connect(this, SIGNAL(sig_open_disk(int, QString, int)), hRunEmu, SLOT(do_open_disk(int, QString, int)));
160+ connect(this, SIGNAL(sig_close_disk(int)), hRunEmu, SLOT(do_close_disk(int)));
161+ connect(hRunEmu, SIGNAL(sig_update_recent_disk(int)), this, SLOT(do_update_recent_disk(int)));
162+ //connect(hRunEmu, SIGNAL(sig_change_osd_fd(int, QString)), this, SLOT(do_change_osd_fd(int, QString)));
163+ drvs = USE_FHARD_DISK;
164+ for(int ii = 0; ii < drvs; ii++) {
165+ menu_fds[ii]->setEmu(emu);
166+ connect(menu_hdds[ii], SIGNAL(sig_update_inner_hdd(int ,QStringList , class Action_Control **, QStringList , int, bool)),
167+ this, SLOT(do_update_inner_hdd(int ,QStringList , class Action_Control **, QStringList , int, bool)));
168+ }
169+#endif
170+#if defined(USE_TAPE)
184171 connect(this, SIGNAL(sig_play_tape(int, QString)), hRunEmu, SLOT(do_play_tape(int, QString)));
185172 connect(this, SIGNAL(sig_rec_tape(int, QString)), hRunEmu, SLOT(do_rec_tape(int, QString)));
186173 connect(this, SIGNAL(sig_close_tape(int)), hRunEmu, SLOT(do_close_tape(int)));
@@ -194,13 +181,13 @@ void Ui_MainWindow::LaunchEmuThread(void)
194181 connect(this, SIGNAL(sig_cmt_push_apss_rewind(int)), hRunEmu, SLOT(do_cmt_push_apss_rewind(int)));
195182 # endif
196183 #endif
197-#if defined(USE_QD1)
184+#if defined(USE_QUICK_DISK)
198185 connect(this, SIGNAL(sig_write_protect_quickdisk(int, bool)), hRunEmu, SLOT(do_write_protect_quickdisk(int, bool)));
199186 connect(this, SIGNAL(sig_open_quickdisk(int, QString)), hRunEmu, SLOT(do_open_quickdisk(int, QString)));
200187 connect(this, SIGNAL(sig_close_quickdisk(int)), hRunEmu, SLOT(do_close_quickdisk(int)));
201188 //connect(hRunEmu, SIGNAL(sig_change_osd_qd(int, QString)), this, SLOT(do_change_osd_qd(int, QString)));
202189 #endif
203-#if defined(USE_CART1)
190+#if defined(USE_CART)
204191 connect(this, SIGNAL(sig_open_cart(int, QString)), hRunEmu, SLOT(do_open_cart(int, QString)));
205192 connect(this, SIGNAL(sig_close_cart(int)), hRunEmu, SLOT(do_close_cart(int)));
206193 #endif
@@ -208,28 +195,24 @@ void Ui_MainWindow::LaunchEmuThread(void)
208195 connect(this, SIGNAL(sig_open_cdrom(QString)), hRunEmu, SLOT(do_open_cdrom(QString)));
209196 connect(this, SIGNAL(sig_close_cdrom()), hRunEmu, SLOT(do_eject_cdrom()));
210197 //connect(hRunEmu, SIGNAL(sig_change_osd_cdrom(QString)), this, SLOT(do_change_osd_cdrom(QString)));
198+ // ToDo: multiple CDs
211199 #endif
212200 #if defined(USE_LASER_DISC)
213201 connect(this, SIGNAL(sig_open_laserdisc(QString)), hRunEmu, SLOT(do_open_laser_disc(QString)));
214202 connect(this, SIGNAL(sig_close_laserdisc(void)), hRunEmu, SLOT(do_close_laser_disc(void)));
203+ // ToDo: multiple LDs
215204 #endif
216-#if defined(USE_BINARY_FILE1)
205+#if defined(USE_BINARY_FILE)
217206 connect(this, SIGNAL(sig_load_binary(int, QString)), hRunEmu, SLOT(do_load_binary(int, QString)));
218207 connect(this, SIGNAL(sig_save_binary(int, QString)), hRunEmu, SLOT(do_save_binary(int, QString)));
219208 #endif
220-#if defined(USE_BUBBLE1)
209+#if defined(USE_BUBBLE)
221210 connect(this, SIGNAL(sig_write_protect_bubble(int, bool)), hRunEmu, SLOT(do_write_protect_bubble_casette(int, bool)));
222211 connect(this, SIGNAL(sig_open_bubble(int, QString, int)), hRunEmu, SLOT(do_open_bubble_casette(int, QString, int)));
223212 connect(this, SIGNAL(sig_close_bubble(int)), hRunEmu, SLOT(do_close_bubble_casette(int)));
224213 connect(hRunEmu, SIGNAL(sig_update_recent_bubble(int)), this, SLOT(do_update_recent_bubble(int)));
225214 //connect(hRunEmu, SIGNAL(sig_change_osd_bubble(int, QString)), this, SLOT(do_change_osd_bubble(int, QString)));
226- drvs = 0;
227-# if defined(USE_BUBBLE1)
228- drvs = 1;
229-# endif
230-# if defined(USE_BUBBLE2)
231- drvs = 2;
232-# endif
215+ drvs = USE_BUBBLE;
233216 for(int ii = 0; ii < drvs; ii++) {
234217 menu_bubbles[ii]->setEmu(emu);
235218 connect(menu_bubbles[ii],
@@ -598,6 +581,7 @@ static void setup_logs(void)
598581 CSP_Logger *csp_logger;
599582 QStringList virtualMediaList; // {TYPE, POSITION}
600583 QCommandLineOption *_opt_fds[8];
584+QCommandLineOption *_opt_hdds[8];
601585 QCommandLineOption *_opt_cmts[2];
602586 QCommandLineOption *_opt_lds[2];
603587 QCommandLineOption *_opt_cds[2];
@@ -620,8 +604,8 @@ std::string config_fullpath;
620604
621605 void SetFDOptions(QCommandLineParser *cmdparser)
622606 {
623-#if defined(USE_FD1)
624- for(int i = 0; i < MAX_FD; i++) {
607+#if defined(USE_FLOPPY_DISK)
608+ for(int i = 0; i < USE_FLOPPY_DISK; i++) {
625609 QString sfdType1 = QString::fromUtf8("fd%1").arg(i);
626610 QString sfdType2 = QString::fromUtf8("vFd%1").arg(i);
627611 QString sfdType3 = QString::fromUtf8("vFloppyDisk%1").arg(i);
@@ -636,10 +620,30 @@ void SetFDOptions(QCommandLineParser *cmdparser)
636620 #endif
637621 }
638622
623+void SetHDDOptions(QCommandLineParser *cmdparser)
624+{
625+#if defined(USE_HARD_DISK)
626+ for(int i = 0; i < USE_HARD_DISK; i++) {
627+ QString sfdType1 = QString::fromUtf8("hd%1").arg(i);
628+ QString sfdType2 = QString::fromUtf8("vHd%1").arg(i);
629+ QString sfdType3 = QString::fromUtf8("vHardDisk%1").arg(i);
630+ QString sfdType4 = QString::fromUtf8("vHardDrive%1").arg(i);
631+ QStringList _cl;
632+ _cl.append(sfdType1);
633+ _cl.append(sfdType2);
634+ _cl.append(sfdType3);
635+ _cl.append(sfdType4);
636+ _opt_hdds[i] = new QCommandLineOption(_cl,QCoreApplication::translate("main", "Set virtual hard drive %1.").arg(i) , "[D88_SLOT@]fullpath");
637+ cmdparser->addOption(*_opt_hdds[i]);
638+ _cl.clear();
639+ }
640+#endif
641+}
642+
639643 void SetBinaryOptions(QCommandLineParser *cmdparser)
640644 {
641-#if defined(USE_BINARY_FILE1)
642- for(int i = 0; i < MAX_BINARY; i++) {
645+#if defined(USE_BINARY_FILE)
646+ for(int i = 0; i < USE_BINARY_FILE; i++) {
643647 QString sfdType1 = QString::fromUtf8("bin%1").arg(i);
644648 QString sfdType2 = QString::fromUtf8("vBinary%1").arg(i);
645649 QStringList _cl;
@@ -654,8 +658,8 @@ void SetBinaryOptions(QCommandLineParser *cmdparser)
654658
655659 void SetCartOptions(QCommandLineParser *cmdparser)
656660 {
657-#if defined(USE_CART1)
658- for(int i = 0; i < MAX_CART; i++) {
661+#if defined(USE_CART)
662+ for(int i = 0; i < USE_CART; i++) {
659663 QString sfdType1 = QString::fromUtf8("cart%1").arg(i);
660664 QString sfdType2 = QString::fromUtf8("vCart%1").arg(i);
661665 QString sfdType3 = QString::fromUtf8("vCartridge%1").arg(i);
@@ -671,8 +675,8 @@ void SetCartOptions(QCommandLineParser *cmdparser)
671675 }
672676 void SetBubbleOptions(QCommandLineParser *cmdparser)
673677 {
674-#if defined(USE_BUBBLE1)
675- for(int i = 0; i < MAX_BUBBLE; i++) {
678+#if defined(USE_BUBBLE)
679+ for(int i = 0; i < USE_BUBBLE; i++) {
676680 QString sfdType1 = QString::fromUtf8("bub%1").arg(i);
677681 QString sfdType2 = QString::fromUtf8("vBubble%1").arg(i);
678682 QStringList _cl;
@@ -687,7 +691,7 @@ void SetBubbleOptions(QCommandLineParser *cmdparser)
687691 void SetLDOptions(QCommandLineParser *cmdparser)
688692 {
689693 #if defined(USE_LASER_DISC)
690- for(int i = 0; i < 1; i++) {
694+ for(int i = 0; i < USE_LASER_DISC; i++) {
691695 QString sfdType1 = QString::fromUtf8("ld%1").arg(i);
692696 QString sfdType2 = QString::fromUtf8("vLaserDisc%1").arg(i);
693697 QStringList _cl;
@@ -702,7 +706,7 @@ void SetLDOptions(QCommandLineParser *cmdparser)
702706 void SetCDOptions(QCommandLineParser *cmdparser)
703707 {
704708 #if defined(USE_COMPACT_DISC)
705- for(int i = 0; i < 1; i++) {
709+ for(int i = 0; i < USE_COMPACT_DISC; i++) {
706710 QString sfdType1 = QString::fromUtf8("cd%1").arg(i);
707711 QString sfdType2 = QString::fromUtf8("vCompactDisc%1").arg(i);
708712 QStringList _cl;
@@ -717,8 +721,8 @@ void SetCDOptions(QCommandLineParser *cmdparser)
717721
718722 void SetCmtOptions(QCommandLineParser *cmdparser)
719723 {
720-#if defined(USE_TAPE1)
721- for(int i = 0; i < MAX_TAPE; i++) {
724+#if defined(USE_TAPE)
725+ for(int i = 0; i < USE_TAPE; i++) {
722726 QString sfdType1 = QString::fromUtf8("cmt%1").arg(i);
723727 QString sfdType2 = QString::fromUtf8("tape%1").arg(i);
724728 QString sfdType3 = QString::fromUtf8("vCmt%1").arg(i);
@@ -737,8 +741,8 @@ void SetCmtOptions(QCommandLineParser *cmdparser)
737741
738742 void SetQuickDiskOptions(QCommandLineParser *cmdparser)
739743 {
740-#if defined(USE_QD1)
741- for(int i = 0; i < MAX_QD; i++) {
744+#if defined(USE_QUICK_DISK)
745+ for(int i = 0; i < USE_QUICK_DISK; i++) {
742746 QString sfdType1 = QString::fromUtf8("qd%1").arg(i);
743747 QString sfdType2 = QString::fromUtf8("vQuickDisk%1").arg(i);
744748
@@ -755,8 +759,8 @@ void SetQuickDiskOptions(QCommandLineParser *cmdparser)
755759
756760 void SetProcCmdFD(QCommandLineParser *cmdparser, QStringList *_l)
757761 {
758-#if defined(USE_FD1)
759- for(int i = 0; i < MAX_FD; i++) {
762+#if defined(USE_FLOPPY_DISK)
763+ for(int i = 0; i < USE_FLOPPY_DISK; i++) {
760764 if(_opt_fds[i] != NULL) {
761765 if(cmdparser->isSet(*_opt_fds[i])) {
762766 QString sfdType = QString::fromUtf8("vFloppyDisk%1").arg(i);
@@ -769,10 +773,26 @@ void SetProcCmdFD(QCommandLineParser *cmdparser, QStringList *_l)
769773 #endif
770774 }
771775
776+void SetProcCmdHDD(QCommandLineParser *cmdparser, QStringList *_l)
777+{
778+#if defined(USE_HARD_DISK)
779+ for(int i = 0; i < USE_HARD_DISK; i++) {
780+ if(_opt_hdds[i] != NULL) {
781+ if(cmdparser->isSet(*_opt_hdds[i])) {
782+ QString sfdType = QString::fromUtf8("vHardDisk%1").arg(i);
783+ QString medianame = cmdparser->value(*_opt_hdds[i]);
784+ _l->append(sfdType);
785+ _l->append(medianame);
786+ }
787+ }
788+ }
789+#endif
790+}
791+
772792 void SetProcCmdQuickDisk(QCommandLineParser *cmdparser, QStringList *_l)
773793 {
774-#if defined(USE_QD1)
775- for(int i = 0; i < MAX_QD; i++) {
794+#if defined(USE_QUICK_DISK)
795+ for(int i = 0; i < USE_QUICK_DISK; i++) {
776796 if(_opt_qds[i] != NULL) {
777797 if(cmdparser->isSet(*_opt_qds[i])) {
778798 QString sfdType = QString::fromUtf8("vQuickDisk%1").arg(i);
@@ -787,8 +807,8 @@ void SetProcCmdQuickDisk(QCommandLineParser *cmdparser, QStringList *_l)
787807
788808 void SetProcCmdCmt(QCommandLineParser *cmdparser, QStringList *_l)
789809 {
790-#if defined(USE_TAPE1)
791- for(int i = 0; i < MAX_TAPE; i++) {
810+#if defined(USE_TAPE)
811+ for(int i = 0; i < USE_TAPE; i++) {
792812 if(_opt_cmts[i] != NULL) {
793813 if(cmdparser->isSet(*_opt_cmts[i])) {
794814 QString sfdType = QString::fromUtf8("vCmt%1").arg(i);
@@ -803,8 +823,8 @@ void SetProcCmdCmt(QCommandLineParser *cmdparser, QStringList *_l)
803823
804824 void SetProcCmdBinary(QCommandLineParser *cmdparser, QStringList *_l)
805825 {
806-#if defined(USE_BINARY_FILE1)
807- for(int i = 0; i < MAX_BINARY; i++) {
826+#if defined(USE_BINARY_FILE)
827+ for(int i = 0; i < USE_BINARY_FILE; i++) {
808828 if(_opt_binaries[i] != NULL) {
809829 if(cmdparser->isSet(*_opt_binaries[i])) {
810830 QString sfdType = QString::fromUtf8("vBinary%1").arg(i);
@@ -819,8 +839,8 @@ void SetProcCmdBinary(QCommandLineParser *cmdparser, QStringList *_l)
819839
820840 void SetProcCmdBubble(QCommandLineParser *cmdparser, QStringList *_l)
821841 {
822-#if defined(USE_BUBBLE1)
823- for(int i = 0; i < MAX_BUBBLE; i++) {
842+#if defined(USE_BUBBLE)
843+ for(int i = 0; i < USE_BUBBLE; i++) {
824844 if(_opt_bubbles[i] != NULL) {
825845 if(cmdparser->isSet(*_opt_bubbles[i])) {
826846 QString sfdType = QString::fromUtf8("vBubble%1").arg(i);
@@ -835,8 +855,8 @@ void SetProcCmdBubble(QCommandLineParser *cmdparser, QStringList *_l)
835855
836856 void SetProcCmdCart(QCommandLineParser *cmdparser, QStringList *_l)
837857 {
838-#if defined(USE_CART1)
839- for(int i = 0; i < MAX_CART; i++) {
858+#if defined(USE_CART)
859+ for(int i = 0; i < USE_CART; i++) {
840860 if(_opt_carts[i] != NULL) {
841861 if(cmdparser->isSet(*_opt_carts[i])) {
842862 QString sfdType = QString::fromUtf8("vCart%1").arg(i);
@@ -852,7 +872,7 @@ void SetProcCmdCart(QCommandLineParser *cmdparser, QStringList *_l)
852872 void SetProcCmdLD(QCommandLineParser *cmdparser, QStringList *_l)
853873 {
854874 #if defined(USE_LASER_DISC)
855- for(int i = 0; i < 1; i++) {
875+ for(int i = 0; i < USE_LASER_DISC; i++) {
856876 if(_opt_lds[i] != NULL) {
857877 if(cmdparser->isSet(*_opt_lds[i])) {
858878 QString sfdType = QString::fromUtf8("vLD%1").arg(i);
@@ -868,7 +888,7 @@ void SetProcCmdLD(QCommandLineParser *cmdparser, QStringList *_l)
868888 void SetProcCmdCD(QCommandLineParser *cmdparser, QStringList *_l)
869889 {
870890 #if defined(USE_COMPACT_DISC)
871- for(int i = 0; i < 1; i++) {
891+ for(int i = 0; i < USE_COMPACT_DISC; i++) {
872892 if(_opt_cds[i] != NULL) {
873893 if(cmdparser->isSet(*_opt_cds[i])) {
874894 QString sfdType = QString::fromUtf8("vCD%1").arg(i);
@@ -937,6 +957,7 @@ void SetOptions(QCommandLineParser *cmdparser)
937957
938958 for(int i = 0; i < 8; i++) {
939959 _opt_fds[i] = NULL;
960+ _opt_hdds[i] = NULL;
940961 _opt_qds[i] = NULL;
941962 _opt_bubbles[i] = NULL;
942963 _opt_binaries[i] = NULL;
@@ -957,6 +978,7 @@ void SetOptions(QCommandLineParser *cmdparser)
957978 cmdparser->addOption(*_opt_dipsw_off);
958979
959980 SetFDOptions(cmdparser);
981+ SetHDDOptions(cmdparser);
960982 //SetBinaryOptions(cmdparser); // Temporally disabled.
961983 SetCmtOptions(cmdparser);
962984 SetCartOptions(cmdparser);
@@ -980,6 +1002,7 @@ void ProcessCmdLine(QCommandLineParser *cmdparser, QStringList *_l)
9801002 #endif
9811003
9821004 SetProcCmdFD(cmdparser, _l);
1005+ SetProcCmdHDD(cmdparser, _l);
9831006 SetProcCmdQuickDisk(cmdparser, _l);
9841007 SetProcCmdCmt(cmdparser, _l);
9851008 SetProcCmdCart(cmdparser, _l);
@@ -1345,7 +1368,7 @@ int MainLoop(int argc, char *argv[])
13451368 void Ui_MainWindow::do_update_inner_fd(int drv, QStringList base, class Action_Control **action_select_media_list,
13461369 QStringList lst, int num, bool use_d88_menus)
13471370 {
1348-#if defined(USE_FD1)
1371+#if defined(USE_FLOPPY_DISK)
13491372 if(use_d88_menus) {
13501373 for(int ii = 0; ii < using_flags->get_max_d88_banks(); ii++) {
13511374 if(ii < emu->d88_file[drv].bank_num) {
@@ -1367,7 +1390,7 @@ void Ui_MainWindow::do_update_inner_fd(int drv, QStringList base, class Action_C
13671390 void Ui_MainWindow::do_update_inner_bubble(int drv, QStringList base, class Action_Control **action_select_media_list,
13681391 QStringList lst, int num, bool use_d88_menus)
13691392 {
1370-#if defined(USE_BUBBLE1)
1393+#if defined(USE_BUBBLE)
13711394 if(use_d88_menus) {
13721395 for(int ii = 0; ii < using_flags->get_max_b77_banks(); ii++) {
13731396 if(ii < emu->b77_file[drv].bank_num) {
--- a/source/src/qt/common/util_fd2.cpp
+++ b/source/src/qt/common/util_fd2.cpp
@@ -11,7 +11,7 @@
1111 //extern USING_FLAGS *using_flags;
1212 extern class EMU *emu;
1313
14-#if defined(USE_FD1)
14+#if defined(USE_FLOPPY_DISK)
1515
1616 #ifndef UPDATE_D88_LIST
1717 #define UPDATE_D88_LIST(__d, lst) { \
@@ -57,6 +57,7 @@ void Ui_MainWindow::do_update_recent_disk(int drv)
5757 }
5858 }
5959
60+
6061 extern const _TCHAR* DLL_PREFIX_I get_parent_dir(const _TCHAR* file);
6162 int Ui_MainWindow::set_recent_disk(int drv, int num)
6263 {
@@ -142,3 +143,56 @@ void Ui_MainWindow::_open_disk(int drv, const QString fname)
142143 }
143144
144145 #endif
146+
147+#if defined(USE_HARD_DISK)
148+void Ui_MainWindow::do_update_recent_hard_disk(int drv)
149+{
150+ if(emu == NULL) return;
151+ menu_hdds[drv]->do_update_histories(listHDDs[drv]);
152+ menu_hdds[drv]->do_set_initialize_directory(p_config->initial_hard_disk_dir);
153+}
154+
155+int Ui_MainWindow::set_recent_hard_disk(int drv, int num)
156+{
157+ QString s_path;
158+ char path_shadow[PATH_MAX];
159+ if((num < 0) || (num >= MAX_HISTORY)) return -1;
160+ s_path = QString::fromLocal8Bit(p_config->recent_hard_disk_path[drv][num]);
161+ strncpy(path_shadow, s_path.toLocal8Bit().constData(), PATH_MAX);
162+ UPDATE_HISTORY(path_shadow, p_config->recent_hard_disk_path[drv], listHDDs[drv]);
163+
164+ strncpy(p_config->initial_hard_disk_dir, get_parent_dir((const _TCHAR *)path_shadow), _MAX_PATH);
165+ strncpy(path_shadow, s_path.toLocal8Bit().constData(), PATH_MAX);
166+
167+ if(emu) {
168+ emit sig_close_hard_disk(drv);
169+ emit sig_open_hard_disk(drv, s_path, 0);
170+ menu_hdds[drv]->do_update_histories(listHDDs[drv]);
171+ menu_hdds[drv]->do_set_initialize_directory(p_config->initial_hard_disk_dir);
172+ menu_hdds[drv]->do_clear_inner_media();
173+ }
174+ return 0;
175+}
176+
177+void Ui_MainWindow::_open_hard_disk(int drv, const QString fname)
178+{
179+ char path_shadow[PATH_MAX];
180+
181+ if(fname.length() <= 0) return;
182+ drv = drv & 7;
183+ strncpy(path_shadow, fname.toLocal8Bit().constData(), PATH_MAX);
184+ UPDATE_HISTORY(path_shadow, p_config->recent_hard_disk_path[drv], listHDDs[drv]);
185+ strcpy(p_config->initial_floppy_disk_dir, get_parent_dir((const _TCHAR *)path_shadow));
186+ // Update List
187+ strncpy(path_shadow, fname.toLocal8Bit().constData(), PATH_MAX);
188+ if(emu) {
189+ emit sig_close_hard_disk(drv);
190+ //emu->LockVM();
191+ emit sig_open_hard_disk(drv, fname, 0);
192+ menu_hdds[drv]->do_update_histories(listHDDs[drv]);
193+ menu_hdds[drv]->do_set_initialize_directory(p_config->initial_hard_disk_dir);
194+ menu_hdds[drv]->do_clear_inner_media();
195+ }
196+}
197+
198+#endif
--- a/source/src/qt/gui/emu_thread_tmpl.h
+++ b/source/src/qt/gui/emu_thread_tmpl.h
@@ -218,6 +218,7 @@ signals:
218218 int sig_check_grab_mouse(bool);
219219 int sig_mouse_enable(bool);
220220 int sig_update_recent_disk(int);
221+ int sig_update_recent_hard_disk(int);
221222
222223 int sig_change_osd(int, int, QString);
223224 int sig_change_access_lamp(int, int, QString);
--- a/source/src/qt/gui/mainwidget_base.h
+++ b/source/src/qt/gui/mainwidget_base.h
@@ -595,6 +595,7 @@ public slots:
595595 virtual int set_d88_slot(int drive, int num);
596596 virtual int set_recent_disk(int, int);
597597
598+ virtual void do_update_recent_hard_disk(int);
598599 // Bubble Casette
599600 int write_protect_bubble(int drv, bool flag);
600601
@@ -673,6 +674,7 @@ signals:
673674 int on_insert_fd(int);
674675 int on_eject_fd(int);
675676 int do_open_disk(int, QString);
677+
676678 int closed(void);
677679 int sig_quit_all(void);
678680 int sig_vm_reset(void);
--- a/source/src/qt/machines/fm7/MainWindow.cpp
+++ b/source/src/qt/machines/fm7/MainWindow.cpp
@@ -290,12 +290,11 @@ void META_MainWindow::retranslateUi(void)
290290 retranslateFloppyMenu(3, 3, fdname1M);
291291 #endif
292292 retranslateCMTMenu(0);
293-#if defined(USE_BUBBLE1)
294- retranslateBubbleMenu(0, 0);
293+#if defined(USE_BUBBLE)
294+ for(int _drv = 0; _drv < USE_BUBBLE; _drv++) {
295+ retranslateBubbleMenu(_drv, _drv + 1);
296+ }
295297 #endif
296-#if defined(USE_BUBBLE2)
297- retranslateBubbleMenu(1, 1);
298-#endif
299298 retranslateSoundMenu();
300299 retranslateScreenMenu();
301300
--- a/source/src/qt/machines/mz2500/MainWindow.cpp
+++ b/source/src/qt/machines/mz2500/MainWindow.cpp
@@ -27,7 +27,7 @@ void META_MainWindow::retranslateUi(void)
2727 retranslateFloppyMenu(1, 2);
2828 retranslateFloppyMenu(2, 3);
2929 retranslateFloppyMenu(3, 4);
30-#if defined(USE_QD1)
30+#if defined(USE_QUICK_DISK)
3131 retranslateQuickDiskMenu(0,0);
3232 #endif
3333 retranslateCMTMenu(0);
--- a/source/src/qt/machines/pc6001/MainWindow.cpp
+++ b/source/src/qt/machines/pc6001/MainWindow.cpp
@@ -59,13 +59,12 @@ void META_MainWindow::retranslateUi(void)
5959 retranslateControlMenu(title, false);
6060 retranslateFloppyMenu(0, 1);
6161 retranslateFloppyMenu(1, 2);
62-#if defined(USE_FD3)
63- retranslateFloppyMenu(2, 3);
62+#if USE_FLOPPY_DISK > 2
63+ for(int _drv = 2; _drv < USE_FLOPPY_DISK; _drv++) {
64+ retranslateFloppyMenu(_drv, _drv + 1);
65+ }
6466 #endif
65-#if defined(USE_FD4)
66- retranslateFloppyMenu(3, 4);
67-#endif
68-#if defined(USE_CART1)
67+#if defined(USE_CART)
6968 retranslateCartMenu(0, 1);
7069 #endif
7170 retranslateCMTMenu(0);
--- a/source/src/qt/machines/pc9801/MainWindow.cpp
+++ b/source/src/qt/machines/pc9801/MainWindow.cpp
@@ -54,24 +54,9 @@ void META_MainWindow::retranslateUi(void)
5454 const char *title="";
5555 retranslateControlMenu(title, false);
5656 retranslateMachineMenu();
57-#if defined(USE_FD1)
58- retranslateFloppyMenu(0, 1);
59-#endif
60-#if defined(USE_FD2)
61- retranslateFloppyMenu(1, 2);
62-#endif
63-#if defined(USE_FD3)
64- retranslateFloppyMenu(2, 3);
65-#endif
66-#if defined(USE_FD4)
67- retranslateFloppyMenu(3, 4);
68-#endif
69-#if defined(USE_FD5)
70- retranslateFloppyMenu(4, 5);
71-#endif
72-#if defined(USE_FD6)
73- retranslateFloppyMenu(5, 6);
74-#endif
57+ for(int _drv = 0; _drv < USE_FLOPPY_DISK; _drv++) {
58+ retranslateFloppyMenu(_drv, _drv + 1);
59+ }
7560 #if defined(_PC9801) || defined(_PC9801E)
7661 // Drive 3,4
7762 menu_fds[2]->setTitle(QApplication::translate("MainWindow", "2DD-1", 0));
--- a/source/src/qt/machines/pc98ha/MainWindow.cpp
+++ b/source/src/qt/machines/pc98ha/MainWindow.cpp
@@ -25,13 +25,9 @@ void META_MainWindow::retranslateUi(void)
2525 {
2626 const char *title="";
2727 retranslateControlMenu(title, false);
28-#if defined(USE_FD1)
29- retranslateFloppyMenu(0, 1);
30-#endif
31-#if defined(USE_FD2)
32- retranslateFloppyMenu(1, 2);
33-#endif
34-
28+ if(int _drv = 0; _drv < USE_FLOPPY_DISK; _drv++) {
29+ retranslateFloppyMenu(_drv, _drv + 1);
30+ }
3531 retranslateSoundMenu();
3632 retranslateScreenMenu();
3733 retranslateMachineMenu();
--- a/source/src/qt/machines/qc10/MainWindow.cpp
+++ b/source/src/qt/machines/qc10/MainWindow.cpp
@@ -43,11 +43,11 @@ void META_MainWindow::retranslateUi(void)
4343 retranslateControlMenu(" ", false);
4444 retranslateFloppyMenu(0, 1);
4545 retranslateFloppyMenu(1, 2);
46-#if defined(USE_FD3)
47- retranslateFloppyMenu(2, 3);
48-#endif
49-#if defined(USE_FD4)
50- retranslateFloppyMenu(3, 4);
46+
47+#if USE_FLOPPY_DISK > 2
48+ for(int _drv = 0; _drv < USE_FLOPPY_DISK; _drv++) {
49+ retranslateFloppyMenu(_drv, _drv + 1);
50+ }
5151 #endif
5252 retranslateSoundMenu();
5353 retranslateScreenMenu();
--- a/source/src/qt/osd.cpp
+++ b/source/src/qt/osd.cpp
@@ -662,46 +662,74 @@ void OSD::set_features_vm(void)
662662 // Begin vm.h
663663 #ifdef USE_CART
664664 add_feature(_T("MAX_CART"), (int)USE_CART);
665+ add_feature(_T("USE_CART"), (int)USE_CART);
665666 #endif
666667 #ifdef BASE_CART_NUM
667668 add_feature(_T("BASE_CART_NUM"), (int)BASE_CART_NUM);
668669 #endif
669670
670-#ifdef MAX_FD
671- add_feature(_T("MAX_FD"), (int)MAX_FD);
672-#elif defined(USE_FLOPPY_DISK)
671+#if defined(USE_FLOPPY_DISK)
673672 add_feature(_T("MAX_FD"), (int)USE_FLOPPY_DISK);
673+ add_feature(_T("USE_FLOPPY_DISK"), (int)USE_FLOPPY_DISK);
674674 #endif
675-#ifdef FD_BASE_NUMBER
676- add_feature(_T("FD_BASE_NUMBER"), (int)FD_BASE_NUMBER);
675+#ifdef BASE_FLOPPY_DISK_NUM
676+ add_feature(_T("BASE_FLOPPY_DISK_NUM"), (int)BASE_FLOPPY_DISK_NUM);
677677 #endif
678678
679-#ifdef MAX_QD
680- add_feature(_T("MAX_QD"), (int)MAX_QD);
679+#ifdef USE_QUICK_DISK
680+ add_feature(_T("USE_QUICK_DISK"), (int)USE_QUICK_DISK);
681+ add_feature(_T("MAX_QD"), (int)USE_QUICK_DISK);
681682 #endif
682-#ifdef QD_BASE_NUMBER
683- add_feature(_T("QD_BASE_NUMBER"), (int)QD_BASE_NUMBER);
683+#ifdef BASE_QUICK_DISK_NUM
684+ add_feature(_T("BASE_QUICK_DISK_NUM"), (int)BASE_QUICK_DISK_NUM);
684685 #endif
685686
686-#ifdef MAX_TAPE
687- add_feature(_T("MAX_TAPE"), (int)MAX_TAPE);
687+#ifdef USE_HARD_DISK
688+ add_feature(_T("USE_HARD_DISK"), (int)USE_HARD_DISK);
689+ add_feature(_T("MAX_HDD"), (int)USE_HARD_DISK);
688690 #endif
689-#ifdef TAPE_BASE_NUMBER
690- add_feature(_T("TAPE_BASE_NUMBER"), (int)TAPE_BASE_NUMBER);
691+#ifdef BASE_HARD_DISK_NUM
692+ add_feature(_T("BASE_HARD_DISK_NUM"), (int)BASE_HARD_DISK_NUM);
691693 #endif
692694
693-#ifdef MAX_BINARY
694- add_feature(_T("MAX_BINARY"), (int)MAX_BINARY);
695+#ifdef USE_COMPACT_DISC
696+ add_feature(_T("USE_COMPACT_DISC"), (int)USE_COMPACT_DISC);
697+ add_feature(_T("MAX_CD"), (int)USE_COMPACT_DISC);
695698 #endif
696-#ifdef BINARY_BASE_NUMBER
697- add_feature(_T("BINARY_BASE_NUMBER"), (int)BINARY_BASE_NUMBER);
699+#ifdef BASE_COMPACT_DISC_NUM
700+ add_feature(_T("BASE_COMPACT_DISC_NUM"), (int)BASE_COMPACT_DISC_NUM);
698701 #endif
699702
700-#ifdef MAX_BUBBLE
701- add_feature(_T("MAX_BUBBLE"), (int)MAX_BUBBLE);
703+#ifdef USE_LASER_DISC
704+ add_feature(_T("USE_LASER_DISC"), (int)USE_LASER_DISC);
705+ add_feature(_T("MAX_LD"), (int)USE_LASER_DISC);
702706 #endif
703-#ifdef BUBBLE_BASE_NUMBER
704- add_feature(_T("BUBBLE_BASE_NUMBER"), (int)BUBBLE_BASE_NUMBER);
707+#ifdef BASE_LASER_DISC_NUM
708+ add_feature(_T("BASE_LASER_DISC_NUM"), (int)BASE_LASER_DISC_NUM);
709+#endif
710+
711+#ifdef USE_TAPE
712+ add_feature(_T("USE_TAPE"), (int)USE_TAPE);
713+ add_feature(_T("MAX_TAPE"), (int)USE_TAPE);
714+#endif
715+#ifdef BASE_TAPE_NUM
716+ add_feature(_T("BASE_TAPE_NUM"), (int)BASE_TAPE_NUM);
717+#endif
718+
719+#ifdef USE_BINARY_FILE
720+ add_feature(_T("USE_BINARY_FILE"), (int)USE_BINARY_FILE);
721+ add_feature(_T("MAX_BINARY"), (int)USE_BINARY_FILE);
722+#endif
723+#ifdef BASE_BINARY_FILE_NUM
724+ add_feature(_T("BASE_BINARY_FILE_NUM"), (int)BASE_BINARY_FILE_NUM);
725+#endif
726+
727+#ifdef USE_BUBBLE
728+ add_feature(_T("USE_BUBBLE"), (int)USE_BUBBLE);
729+ add_feature(_T("MAX_BUBBLE"), (int)USE_BUBBLE);
730+#endif
731+#ifdef BASE_BUBBLE_NUM
732+ add_feature(_T("BASE_BUBBLE_NUM"), (int)BASE_BUBBLE_NUM);
705733 #endif
706734
707735 #ifndef KEY_KEEP_FRAMES
--- /dev/null
+++ b/source/src/vm/bubcom80/bubblecasette.cpp
@@ -0,0 +1,820 @@
1+/*
2+ * BUBBLE CASETTE for FM-8/7? [bubblecasette.h]
3+ *
4+ * Author: K.Ohta <whatisthis.sowhat _at_ gmail.com>
5+ * License: GPLv2
6+ * History:
7+ * Mar 22, 2016 : Initial
8+ *
9+ */
10+
11+#include "bubblecasette.h"
12+
13+void BUBBLECASETTE::initialize()
14+{
15+ is_wrote = false;
16+ header_changed = false;
17+ is_b77 = false;
18+ write_protect = false;
19+ not_ready = true;
20+ stat_error = false;
21+ cmd_error = true;
22+ cmd_reg = 0;
23+ media_offset = 0;
24+ media_offset_new = 0;
25+ media_size = 0;
26+ file_length = 0;
27+}
28+
29+void BUBBLECASETTE::reset()
30+{
31+ data_reg = 0;
32+ offset_reg = 0;
33+ if(is_wrote) {
34+ write_one_page();
35+ if(is_b77) {
36+ if(header_changed) write_header();
37+ header_changed = false;
38+ }
39+ is_wrote = false;
40+ }
41+ cmd_reg = 0;
42+ page_address.d = 0;
43+ page_count.d = 0;
44+ write_access = read_access = false;
45+
46+ stat_busy = false;
47+ stat_tdra = false;
48+ stat_rda = false;
49+ cmd_error = false;
50+ stat_error = false;
51+
52+ eject_error = false;
53+ povr_error = false;
54+ crc_error = false;
55+ transfer_error = false;
56+ bad_loop_over_error = false;
57+ no_marker_error = false;
58+ undefined_cmd_error = false;
59+}
60+
61+uint32_t BUBBLECASETTE::read_io8(uint32_t address)
62+{
63+ uint32_t val = 0xff;
64+ uint32_t offset;
65+ uint16_t mask;
66+ uint16_t page_size_tmp;
67+ uint32_t media_size_tmp;
68+ if(bubble_type == BUBBLE_TYPE_32KB) {
69+ page_size_tmp = 0x20;
70+ mask = 0x3ff;
71+ media_size_tmp = 0x8000;
72+ } else if(bubble_type == BUBBLE_TYPE_64KB) {
73+ page_size_tmp = 0x20;
74+ mask = 0x7ff;
75+ media_size_tmp = 0x10000;
76+ } else if(bubble_type == BUBBLE_TYPE_128KB) {
77+ page_size_tmp = 0x40;
78+ mask = 0x7ff;
79+ media_size_tmp = 0x20000;
80+ } else {
81+ //return val; // Not inserted.
82+ mask = 0;
83+ }
84+ switch(address & 15) {
85+ case 0: // Data Resistor
86+ val = (uint32_t)data_reg;
87+ offset = (page_address.w.l & mask) * page_size_tmp + offset_reg;
88+ if(stat_rda) {
89+ if(offset >= media_size_tmp) {
90+ povr_error = true;
91+ stat_error = true;
92+ cmd_error = true;
93+ read_access = false;
94+ return val;
95+ }
96+ write_access = false;
97+ read_access = true;
98+ offset_reg++;
99+ if(offset_reg == page_size_tmp) {
100+ stat_busy = false;
101+ stat_rda = false;
102+ cmd_error = true;
103+ offset_reg = 0;
104+ //if(!read_one_page()) {
105+ // stat_error = true;
106+ // cmd_error = true;
107+ // transfer_error = true; // Okay?
108+ // // Error handling: End?
109+ // page_count.w.l = 0;
110+ //}
111+ if(page_count.w.l > 0) page_count.w.l--;
112+ if((page_count.w.l > 0) && (offset < media_size_tmp)) {
113+ // Multi read
114+ stat_busy = true;
115+ cmd_error = false;
116+ page_address.w.l = (page_address.w.l + 1) & mask;
117+ data_reg = bubble_data[page_address.w.l * page_size_tmp];
118+ //stat_rda = true;
119+ } else { // End multi read
120+ offset_reg = 0;
121+ read_access = false;
122+ //page_count.w.l = 0; // ??
123+ }
124+ } else {
125+ // Normal read
126+ data_reg = bubble_data[(page_address.w.l & mask) * page_size_tmp + offset_reg];
127+ //stat_rda = true;
128+ cmd_error = false;
129+ stat_busy = true;
130+ }
131+ }
132+ break;
133+ case 2: // Read status register
134+ val = 0x00;
135+ if(!bubble_inserted) {
136+ cmd_error = true;
137+ not_ready = true;
138+ stat_error = true;
139+ eject_error = true;
140+ }
141+ val |= (cmd_error) ? 0x80 : 0;
142+ val |= (stat_tdra) ? 0x40 : 0;
143+ val |= (stat_rda) ? 0x20 : 0;
144+ val |= (not_ready) ? 0x10 : 0;
145+ val |= (write_protect) ? 0x04 : 0;
146+ val |= (stat_error) ? 0x02 : 0;
147+ val |= (stat_busy) ? 0x01 : 0;
148+ if(!(bubble_inserted) && (stat_busy)) {
149+ stat_busy = false;
150+ }
151+ if((cmd_reg == 1) && (bubble_inserted) && (read_access)){
152+ if(!stat_rda) stat_rda = true;
153+ } else if((cmd_reg == 2) && (bubble_inserted) && (write_access)){
154+ if(!stat_tdra) stat_tdra = true;
155+ }
156+ break;
157+ case 3: // Read Error register
158+ val = 0x00;
159+ val |= (eject_error) ? 0x80 : 0;
160+ val |= (povr_error) ? 0x20 : 0;
161+ val |= (crc_error) ? 0x10 : 0;
162+ val |= (transfer_error) ? 0x08 : 0;
163+ val |= (bad_loop_over_error) ? 0x04 : 0;
164+ val |= (no_marker_error) ? 0x02 : 0;
165+ val |= (undefined_cmd_error) ? 0x01 : 0;
166+ break;
167+ case 4:
168+ val = page_address.b.h;
169+ break;
170+ case 5:
171+ val = page_address.b.l;
172+ break;
173+ case 6:
174+ val = page_count.b.h;
175+ break;
176+ case 7:
177+ val = page_count.b.l;
178+ break;
179+ case 8:
180+ val = 0xff;
181+ if(bubble_inserted) {
182+ val &= ~0x80; // page_address = 0000h
183+// val &= ~0x40; // page_address = 0400h
184+ }
185+ break;
186+ }
187+ return val;
188+}
189+
190+void BUBBLECASETTE::bubble_command(uint8_t cmd)
191+{
192+ uint16_t mask = 0;
193+ uint16_t page_size_tmp;
194+ uint32_t media_size_tmp;
195+ if(bubble_type == BUBBLE_TYPE_32KB) {
196+ page_size_tmp = 0x20;
197+ mask = 0x3ff;
198+ media_size_tmp = 0x8000;
199+ } else if(bubble_type == BUBBLE_TYPE_64KB) {
200+ page_size_tmp = 0x20;
201+ mask = 0x7ff;
202+ media_size_tmp = 0x10000;
203+ } else if(bubble_type == BUBBLE_TYPE_128KB) {
204+ page_size_tmp = 0x40;
205+ mask = 0x7ff;
206+ media_size_tmp = 0x20000;
207+ }
208+ switch(cmd) {
209+ case 1: // Read
210+ offset_reg = 0;
211+ read_access = false;
212+ write_access = false;
213+ if(!bubble_inserted) {
214+ stat_error = true;
215+ cmd_error = true;
216+ no_marker_error = true;
217+ eject_error = true;
218+ } else {
219+ data_reg = bubble_data[(page_address.w.l & mask) * page_size_tmp];
220+ stat_rda = true;
221+ read_access = true;
222+ }
223+ break;
224+ case 2: // Write :: Will not check insert?
225+ stat_busy = true;
226+ write_access = false;
227+ read_access = false;
228+ if(!bubble_inserted) {
229+ stat_error = true;
230+ cmd_error = true;
231+ no_marker_error = true;
232+ eject_error = true;
233+ } else {
234+ if(write_protect) {
235+ stat_busy = false;
236+ cmd_error = true;
237+ stat_tdra = false;
238+ } else {
239+ offset_reg = 0;
240+ write_access = true;
241+ stat_tdra = true;
242+ cmd_error = false;
243+ }
244+ }
245+ break;
246+ case 4:
247+ case 15: // Reset
248+ data_reg = 0;
249+ if(is_wrote) {
250+ write_one_page();
251+ is_wrote = false;
252+ }
253+ page_address.d = 0;
254+ page_count.d = 0;
255+ write_access = read_access = false;
256+ break;
257+ default:
258+ stat_error = true;
259+ cmd_error = true;
260+ undefined_cmd_error = true;
261+ break;
262+ }
263+}
264+void BUBBLECASETTE::write_io8(uint32_t address, uint32_t data)
265+{
266+ uint8_t val;
267+ uint32_t offset;
268+ uint16_t mask = 0;
269+ uint16_t page_size_tmp;
270+ uint32_t media_size_tmp;
271+ if(bubble_type == BUBBLE_TYPE_32KB) {
272+ page_size_tmp = 0x20;
273+ mask = 0x3ff;
274+ media_size_tmp = 0x8000;
275+ } else if(bubble_type == BUBBLE_TYPE_64KB) {
276+ page_size_tmp = 0x20;
277+ mask = 0x7ff;
278+ media_size_tmp = 0x10000;
279+ } else if(bubble_type == BUBBLE_TYPE_128KB) {
280+ page_size_tmp = 0x40;
281+ mask = 0x7ff;
282+ media_size_tmp = 0x20000;
283+ } else {
284+ //return; // Not inserted.
285+ }
286+ val = (uint8_t)data;
287+
288+ switch(address & 15) {
289+ case 0: // Write Data
290+ data_reg = val;
291+ if(stat_tdra) {
292+ if((offset = page_address.w.l * page_size_tmp + offset_reg) >= media_size_tmp) {
293+ povr_error = true;
294+ stat_error = true;
295+ cmd_error = true;
296+ return;
297+ }
298+ is_wrote = true;
299+ bubble_data[(page_address.w.l & mask) * page_size_tmp + offset_reg] = data_reg;
300+ write_access = true;
301+ read_access = false;
302+ offset_reg++;
303+ if(offset_reg == page_size_tmp) {
304+ stat_busy = false;
305+ stat_tdra = false;
306+ cmd_error = true;
307+ stat_error = false;
308+ if(!write_one_page()) {
309+ stat_error = true;
310+ cmd_error = true;
311+ transfer_error = true; // Okay?
312+ // Error handling: End?
313+ page_count.w.l = 0;
314+ return;
315+ }
316+ offset_reg = 0;
317+ if(page_count.w.l > 0) {
318+ page_count.w.l--;
319+ //page_address.w.l = (page_address.w.l + 1) & mask;
320+ }
321+ if((page_count.w.l > 0) && (offset < media_size_tmp)) {
322+ stat_busy = true;
323+ cmd_error = false;
324+ page_address.w.l = (page_address.w.l + 1) & mask;
325+ } else {
326+ // Completed
327+ write_access = false;
328+ }
329+ } else {
330+ //stat_busy = true;
331+ //stat_tdra = false; // Move to event_callback()?
332+ }
333+ }
334+ break;
335+ case 1: // CMD register
336+ stat_busy = false;
337+ stat_tdra = false;
338+ stat_rda = false;
339+ cmd_error = false;
340+ stat_error = false;
341+
342+ eject_error = false;
343+ povr_error = false;
344+ crc_error = false;
345+ transfer_error = false;
346+ bad_loop_over_error = false;
347+ no_marker_error = false;
348+ undefined_cmd_error = false;
349+ cmd_reg = val;
350+ bubble_command(val);
351+
352+ break;
353+ case 2: // Read only
354+ case 3: // Read only
355+ break;
356+ case 4:
357+ page_address.b.h = val;
358+ break;
359+ case 5:
360+ page_address.b.l = val;
361+ break;
362+ case 6:
363+ page_count.b.h = val;
364+ break;
365+ case 7:
366+ page_count.b.l = val;
367+ break;
368+ }
369+}
370+
371+uint32_t BUBBLECASETTE::read_signal(int address)
372+{
373+ return 0;
374+}
375+
376+void BUBBLECASETTE::write_signal(int id, uint32_t data, uint32_t mask)
377+{
378+}
379+
380+void BUBBLECASETTE::open(_TCHAR* file_path, int bank)
381+{
382+// int i;
383+ int contain_medias = 0;
384+ is_wrote = false;
385+ header_changed = false;
386+ is_b77 = false;
387+ fio = NULL;
388+
389+ media_offset = 0;
390+ media_offset_new = 0;
391+ file_length = 0;
392+ bubble_inserted = false;
393+ not_ready = true;
394+ cmd_error = true;
395+ stat_tdra = false;
396+ stat_rda = false;
397+ stat_error = false; // OK?
398+ stat_busy = false;
399+
400+ memset(bubble_data, 0, 0x20000);
401+ memset(&bbl_header, 0, sizeof(bbl_header_t));
402+ bubble_type = -1;
403+
404+ if(fio != NULL) {
405+ close();
406+ } else {
407+ fio = new FILEIO;
408+ if(fio == NULL) return;
409+ }
410+ memset(image_path, 0x00, _MAX_PATH * sizeof(_TCHAR));
411+ _tcsncpy(image_path, file_path, _MAX_PATH);
412+
413+ if(fio->IsFileExisting(file_path)) {
414+ fio->Fopen(file_path, FILEIO_READ_WRITE_BINARY);
415+ file_length = fio->FileLength();
416+ if(file_length == 0) return;
417+ //printf("Size=%d\n", file_length);
418+ if(file_length == 0x8000) { // 32KB
419+ bubble_type = BUBBLE_TYPE_32KB;
420+ media_size = 0x8000;
421+ } else if(file_length == 0x10000) {
422+ bubble_type = BUBBLE_TYPE_64KB;
423+ media_size = 0x10000;
424+ } else if(file_length == 0x20000) {
425+ bubble_type = BUBBLE_TYPE_128KB;
426+ media_size = 0x20000;
427+ } else {
428+ bubble_type = BUBBLE_TYPE_B77;
429+ }
430+
431+ if(bubble_type != BUBBLE_TYPE_B77) {
432+ if(bubble_type < 0) return;
433+ write_protect = false;
434+ not_ready = false;
435+ switch(bubble_type) {
436+ case BUBBLE_TYPE_32KB:
437+ fio->Fread(bubble_data, 0x8000, 1);
438+ break;
439+ case BUBBLE_TYPE_64KB:
440+ fio->Fread(bubble_data, 0x10000, 1);
441+ break;
442+ case BUBBLE_TYPE_128KB:
443+ fio->Fread(bubble_data, 0x20000, 1);
444+ break;
445+ }
446+ media_num = 0;
447+ bubble_inserted = true;
448+ } else { // b77
449+ int remain;
450+ do {
451+ write_protect = false;
452+ not_ready = false;
453+ if(!this->read_header()) break;
454+ if(contain_medias != bank) {
455+ fio->Fseek(media_offset_new , FILEIO_SEEK_SET); // Skip
456+ if((uint32_t)fio->Ftell() >= file_length) return; // Error
457+ } else { // Image found
458+ if(bubble_type == BUBBLE_TYPE_32KB) {
459+ if(bbl_header.offset.d > 0x20) fio->Fseek(media_offset, FILEIO_SEEK_SET);
460+ remain = file_length - bbl_header.offset.d;
461+ media_size = 0x8000;
462+ if(remain >= 0x8000) {
463+ remain = 0x8000;
464+ }
465+ fio->Fread(bubble_data, remain, 1);
466+ is_b77 = true;
467+ } else if(bubble_type == BUBBLE_TYPE_128KB) {
468+ if(bbl_header.offset.d > 0x20) fio->Fseek(media_offset, FILEIO_SEEK_SET);
469+ remain = file_length - bbl_header.offset.d;
470+ media_size = 0x20000;
471+
472+ if(remain >= 0x20000) {
473+ remain = 0x20000;
474+ }
475+ fio->Fread(bubble_data, remain, 1);
476+ is_b77 = true;
477+ }
478+ bubble_inserted = true;
479+ media_num = (uint32_t)bank;
480+ contain_medias++;
481+ return;
482+ }
483+ contain_medias++;
484+ } while(contain_medias <= 16);
485+ }
486+ } else {
487+ not_ready = true;
488+ }
489+}
490+
491+bool BUBBLECASETTE::read_header()
492+{
493+// uint32_t f_pos;
494+ uint8_t tmpval[16];
495+ if(fio == NULL) return false;
496+ if ((uint32_t)fio->Ftell() >= file_length) return false;
497+ // You need convert to [UTF8|Local8Bit] when using UI.
498+ fio->Fread(bbl_header.filename, 0x10, 1);
499+ if(fio->Fread(&tmpval, 0x10, 1) != 0x10) return false;
500+ // Offset(little endian)
501+ bbl_header.offset.b.l = tmpval[4];
502+ bbl_header.offset.b.h = tmpval[5];
503+ bbl_header.offset.b.h2 = tmpval[6];
504+ bbl_header.offset.b.h3 = tmpval[7];
505+ // Casette size(little endian)
506+ bbl_header.size.b.l = tmpval[12];
507+ bbl_header.size.b.h = tmpval[13];
508+ bbl_header.size.b.h2 = tmpval[14];
509+ bbl_header.size.b.h3 = tmpval[15];
510+ // Misc
511+ bbl_header.misc[0] = tmpval[0];
512+ bbl_header.misc[1] = tmpval[1];
513+ bbl_header.misc[2] = tmpval[2];
514+ bbl_header.misc[3] = tmpval[3];
515+
516+ bbl_header.misc[4] = tmpval[8];
517+ bbl_header.misc[5] = tmpval[9];
518+ bbl_header.misc[6] = tmpval[10];
519+ bbl_header.misc[7] = tmpval[11];
520+
521+ if((tmpval[10] & 0x10) != 0) {
522+ write_protect = true; // ToDo : Relate to permission of image file.
523+ } else {
524+ write_protect = false; // ToDo : Relate to permission of image file.
525+ }
526+ switch(tmpval[11]) {
527+ case 0x80:
528+ bubble_type = BUBBLE_TYPE_32KB;
529+ break;
530+ case 0x90:
531+ bubble_type = BUBBLE_TYPE_128KB;
532+ break;
533+ default:
534+ return false;
535+ break;
536+ }
537+ media_size = bbl_header.size.d;
538+ media_offset = media_offset_new + bbl_header.offset.d;
539+ media_offset_new = media_offset_new + media_size;
540+ return true;
541+}
542+
543+void BUBBLECASETTE::write_header()
544+{
545+// uint32_t f_pos;
546+ uint8_t tmpval[16];
547+ if(fio == NULL) return;
548+ if((uint32_t)fio->Ftell() >= file_length) return;
549+ // You need convert to [UTF8|Local8Bit] when using UI.
550+ // Offset(little endian)
551+ tmpval[4] = bbl_header.offset.b.l;
552+ tmpval[5] = bbl_header.offset.b.h;
553+ tmpval[6] = bbl_header.offset.b.h2;
554+ tmpval[7] = bbl_header.offset.b.h3;
555+ // Casette size(little endian)
556+ tmpval[12] = bbl_header.size.b.l;
557+ tmpval[13] = bbl_header.size.b.h;
558+ tmpval[14] = bbl_header.size.b.h2;
559+ tmpval[15] = bbl_header.size.b.h3;
560+ // Misc
561+ tmpval[0] = bbl_header.misc[0];
562+ tmpval[1] = bbl_header.misc[1];
563+ tmpval[2] = bbl_header.misc[2];
564+ tmpval[3] = bbl_header.misc[3];
565+
566+ tmpval[8] = bbl_header.misc[4];
567+ tmpval[9] = bbl_header.misc[5];
568+ tmpval[10] = bbl_header.misc[6];
569+ tmpval[11] = bbl_header.misc[7];
570+
571+ if(write_protect) {
572+ tmpval[10] |= 0x10;
573+ } else {
574+ tmpval[10] &= (uint8_t)(~0x10);
575+ }
576+ switch(bubble_type) {
577+ case BUBBLE_TYPE_32KB:
578+ tmpval[11] = 0x80;
579+ break;
580+ case BUBBLE_TYPE_128KB:
581+ tmpval[11] = 0x90;
582+ break;
583+ default:
584+ return;
585+ break;
586+ }
587+ fio->Fwrite(bbl_header.filename, 0x10, 1);
588+ fio->Fwrite(&tmpval, 0x10, 1);
589+ return;
590+}
591+
592+bool BUBBLECASETTE::read_one_page()
593+{
594+ uint32_t f_pos;
595+ if(fio == NULL) return false;
596+ if(!fio->IsOpened()) return false;
597+ if(!bubble_inserted) {
598+ // Error Handling
599+ return false;
600+ }
601+ f_pos = media_offset;
602+ {
603+ uint32_t offset = 0;
604+ uint32_t page_size = 0;
605+ int remain = (int)media_size - (int)bbl_header.offset.d;
606+ if(remain <= 0) return false;
607+ switch(bubble_type) {
608+ case BUBBLE_TYPE_32KB:
609+ offset = (page_address.w.l & 0x03ff) * 0x20;
610+ page_size = 0x20;
611+ break;
612+ case BUBBLE_TYPE_64KB:
613+ offset = (page_address.w.l & 0x07ff) * 0x20;
614+ page_size = 0x20;
615+ break;
616+ case BUBBLE_TYPE_128KB:
617+ offset = bbl_header.offset.d + (page_address.w.l & 0x07ff) * 0x40;
618+ page_size = 0x40;
619+ break;
620+ default:
621+ return false;
622+ break;
623+ }
624+ if(remain < (int)(offset + page_size)) return false;
625+ fio->Fseek(f_pos + offset, FILEIO_SEEK_SET);
626+ fio->Fread(&bubble_data[offset], page_size, 1);
627+ }
628+ return true;
629+}
630+
631+bool BUBBLECASETTE::write_one_page()
632+{
633+ uint32_t f_pos;
634+ if(fio == NULL) return false;
635+ if(!fio->IsOpened()) return false;
636+ if(!bubble_inserted) {
637+ // Error Handling
638+ return false;
639+ }
640+ f_pos = media_offset;
641+ if(is_wrote) {
642+ uint32_t offset = 0;
643+ uint32_t page_size = 0;
644+ int remain = (int)media_size - (int)bbl_header.offset.d;
645+ if(remain <= 0) return false;
646+ switch(bubble_type) {
647+ case BUBBLE_TYPE_32KB:
648+ offset = (page_address.w.l & 0x03ff) * 0x20;
649+ page_size = 0x20;
650+ break;
651+ case BUBBLE_TYPE_64KB:
652+ offset = (page_address.w.l & 0x07ff) * 0x20;
653+ page_size = 0x20;
654+ break;
655+ case BUBBLE_TYPE_128KB:
656+ offset = bbl_header.offset.d + (page_address.w.l & 0x07ff) * 0x40;
657+ page_size = 0x40;
658+ break;
659+ default:
660+ return false;
661+ break;
662+ }
663+ //printf("Write One Page: PAGE=%04x COUNT=%04x:\n ",page_address.w.l, page_count.w.l);
664+ if(remain < (int)(offset + page_size)) return false;
665+ fio->Fseek(f_pos + offset, FILEIO_SEEK_SET);
666+ fio->Fwrite(&bubble_data[offset], page_size, 1);
667+ is_wrote = false;
668+ }
669+ return true;
670+}
671+
672+void BUBBLECASETTE::close()
673+{
674+// int i;
675+ if(fio != NULL) {
676+ if(fio->IsOpened()) {
677+ if(is_wrote) write_one_page();
678+ if(is_b77) {
679+ if(header_changed) write_header();
680+ header_changed = false;
681+ is_b77 = false;
682+ }
683+ fio->Fclose();
684+ }
685+ delete fio;
686+ }
687+ fio = NULL;
688+ memset(image_path, 0x00, _MAX_PATH * sizeof(_TCHAR));
689+ bubble_type = -1;
690+ memset(&bbl_header, 0x00, sizeof(bbl_header_t));
691+ memset(bubble_data, 0x00, 0x20000);
692+ media_offset = 0;
693+ media_offset_new = 0;
694+ is_wrote = false;
695+ is_b77 = false;
696+ header_changed = false;
697+ bubble_inserted = false;
698+ read_access = write_access = false;
699+}
700+
701+void BUBBLECASETTE::event_callback(int event_id, int err)
702+{
703+}
704+
705+#define STATE_VERSION 2
706+
707+void BUBBLECASETTE::save_state(FILEIO *state_fio)
708+{
709+// int i, j;
710+ state_fio->FputUint32_BE(STATE_VERSION);
711+ state_fio->FputInt32_BE(this_device_id);
712+// this->out_debug_log(_T("Save State: BUBBLE: id=%d ver=%d\n"), this_device_id, STATE_VERSION);
713+
714+ // Attributes
715+ state_fio->FputUint32_BE(file_length);
716+ state_fio->FputBool(bubble_inserted);
717+ state_fio->FputInt32_BE(bubble_type);
718+ state_fio->FputInt32_BE(media_num);
719+ state_fio->FputUint32_BE(media_offset);
720+ state_fio->FputUint32_BE(media_offset_new);
721+ state_fio->FputUint32_BE(media_size);
722+ // Data reg
723+ state_fio->FputUint8(data_reg);
724+ // Command reg
725+ state_fio->FputUint8(cmd_reg);
726+ // Status reg
727+ state_fio->FputBool(stat_busy);
728+ state_fio->FputBool(stat_tdra);
729+ state_fio->FputBool(stat_rda);
730+ state_fio->FputBool(cmd_error);
731+ state_fio->FputBool(stat_error);
732+ state_fio->FputBool(not_ready);
733+ // Error reg
734+ state_fio->FputBool(eject_error);
735+ state_fio->FputBool(povr_error);
736+ state_fio->FputBool(crc_error);
737+ state_fio->FputBool(transfer_error);
738+ state_fio->FputBool(bad_loop_over_error);
739+ state_fio->FputBool(no_marker_error);
740+ state_fio->FputBool(undefined_cmd_error);
741+ // Page address
742+ state_fio->FputUint32_BE(page_address.d);
743+ //Page Count
744+ state_fio->FputUint32_BE(page_count.d);
745+ // Misc flags
746+ state_fio->FputBool(is_b77);
747+ state_fio->FputBool(read_access);
748+ state_fio->FputBool(write_access);
749+ state_fio->FputBool(write_protect);
750+ state_fio->FputUint8(offset_reg);
751+
752+
753+ state_fio->Fwrite(image_path, _MAX_PATH * sizeof(_TCHAR), 1);
754+ if(fio != NULL) {
755+ if(fio->IsOpened()) {
756+ if(is_wrote) write_one_page();
757+ if(is_b77) {
758+ if(header_changed) {
759+ write_header();
760+ header_changed = false;
761+ }
762+ }
763+ }
764+ }
765+}
766+
767+bool BUBBLECASETTE::load_state(FILEIO *state_fio)
768+{
769+// int i, j;
770+ if(state_fio->FgetUint32_BE() != STATE_VERSION) return false;
771+ if(state_fio->FgetInt32_BE() != this_device_id) return false;
772+// this->out_debug_log(_T("Load State: BUBBLE: id=%d ver=%d\n"), this_device_id, STATE_VERSION);
773+
774+ // Attributes
775+ file_length = state_fio->FgetUint32_BE();
776+ bubble_inserted = state_fio->FgetBool();
777+ bubble_type = state_fio->FgetInt32_BE();
778+ media_num = state_fio->FgetInt32_BE();
779+ media_offset = state_fio->FgetInt32_BE();
780+ media_offset_new = state_fio->FgetInt32_BE();
781+ media_size = state_fio->FgetInt32_BE();
782+ // Data reg
783+ data_reg = state_fio->FgetUint8();
784+ // Command reg
785+ cmd_reg = state_fio->FgetUint8();
786+ // Status reg
787+ stat_busy = state_fio->FgetBool();
788+ stat_tdra = state_fio->FgetBool();
789+ stat_rda = state_fio->FgetBool();
790+ cmd_error = state_fio->FgetBool();
791+ stat_error = state_fio->FgetBool();
792+ not_ready = state_fio->FgetBool();
793+ // Error reg
794+ eject_error = state_fio->FgetBool();
795+ povr_error = state_fio->FgetBool();
796+ crc_error = state_fio->FgetBool();
797+ transfer_error = state_fio->FgetBool();
798+ bad_loop_over_error = state_fio->FgetBool();
799+ no_marker_error = state_fio->FgetBool();
800+ undefined_cmd_error = state_fio->FgetBool();
801+ // Page address
802+ page_address.d = state_fio->FgetUint32_BE();
803+ //Page Count
804+ page_count.d = state_fio->FgetUint32_BE();
805+ // Misc flags
806+ is_b77 = state_fio->FgetBool();
807+ read_access = state_fio->FgetBool();
808+ write_access = state_fio->FgetBool();
809+ write_protect = state_fio->FgetBool();
810+ offset_reg = state_fio->FgetUint8();
811+ is_wrote = false;
812+ header_changed = false;
813+
814+ if(state_fio->Fread(image_path, _MAX_PATH * sizeof(_TCHAR), 1) != (_MAX_PATH * sizeof(_TCHAR))) return false;
815+ if(_tcslen(image_path) > 0) {
816+ this->open(image_path, (int)media_num);
817+ }
818+ return true;
819+}
820+
--- /dev/null
+++ b/source/src/vm/bubcom80/bubblecasette.h
@@ -0,0 +1,156 @@
1+/*
2+ * BUBBLE CASETTE for FM-8/7? [bubblecasette.h]
3+ *
4+ * Author: K.Ohta <whatisthis.sowhat _at_ gmail.com>
5+ * License: GPLv2
6+ * History:
7+ * Mar 22, 2016 : Initial
8+ *
9+ */
10+
11+#ifndef _VM_FM_BUBBLECASETTE_H_
12+#define _VM_FM_BUBBLECASETTE_H_
13+
14+#include "../vm.h"
15+#include "../device.h"
16+#include "../../common.h"
17+
18+class FILEIO;
19+
20+enum {
21+ BUBBLE_DATA_REG = 0,
22+ BUBBLE_CMD_REG,
23+ BUBBLE_STATUS_REG,
24+ BUBBLE_ERROR_REG,
25+ BUBBLE_PAGE_ADDR_HI,
26+ BUBBLE_PAGE_ADDR_LO,
27+ BUBBLE_PAGE_COUNT_HI,
28+ BUBBLE_PAGE_COUNT_LO,
29+};
30+
31+enum {
32+ BUBBLE_TYPE_32KB = 0,
33+ BUBBLE_TYPE_128KB = 1,
34+ BUBBLE_TYPE_B77,
35+ BUBBLE_TYPE_64KB,
36+};
37+
38+typedef struct {
39+ _TCHAR filename[16];
40+ pair_t size;
41+ pair_t offset;
42+ uint8_t misc[8];
43+} bbl_header_t;
44+
45+class BUBBLECASETTE: public DEVICE
46+{
47+protected:
48+ FILEIO* fio;
49+
50+ bool is_wrote;
51+ bool is_b77;
52+ bool header_changed; // if change header: e.g:change write protection flag.
53+ bool read_access;
54+ bool write_access;
55+
56+ uint8_t offset_reg;
57+ // FD10(RW)
58+ uint8_t data_reg;
59+ // FD11(RW)
60+ uint8_t cmd_reg;
61+
62+ // FD12(RO) : Positive logic
63+ bool cmd_error; // bit7 : Command error
64+ bool stat_tdra; // bit6: Ready to write.
65+ bool stat_rda; // bit5: Ready to read.
66+ bool not_ready; // bit4: Not Ready(Slot empty).
67+ // bit3 : NOOP
68+ bool write_protect; // bit2
69+ bool stat_error; // bit 1
70+ bool stat_busy; // bit 0
71+
72+ // FD13(RO): Maybe positive
73+ bool eject_error; // bit7
74+ bool povr_error; // bit5 : Page over
75+ bool crc_error; // bit4
76+ bool transfer_error; // bit3
77+ bool bad_loop_over_error; // bit2
78+ bool no_marker_error; // bit1
79+ bool undefined_cmd_error; // bit0
80+
81+ //FD14-FD15: Page address register
82+ pair_t page_address; // 16bit, Big ENDIAN
83+ // FD16-FD17: Page Count Resister
84+ pair_t page_count; // 16bit, Big ENDIAN
85+
86+private:
87+ bool bubble_inserted;
88+ int bubble_type;
89+ int media_num;
90+ bbl_header_t bbl_header;
91+ uint32_t media_offset;
92+ uint32_t media_offset_new;
93+ uint32_t media_size;
94+ uint32_t file_length;
95+
96+ uint8_t bubble_data[0x20000]; // MAX 128KB, normally 32KB at FM-8.
97+ _TCHAR image_path[_MAX_PATH];
98+
99+ void bubble_command(uint8_t cmd);
100+ bool read_header(void);
101+ void write_header(void);
102+ bool read_one_page(void);
103+ bool write_one_page(void);
104+
105+public:
106+ BUBBLECASETTE(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
107+ {
108+ fio = NULL;
109+ memset(image_path, 0x00, _MAX_PATH * sizeof(_TCHAR));
110+ bubble_type = -1;
111+ memset(&bbl_header, 0x00, sizeof(bbl_header_t));
112+ memset(bubble_data, 0x00, 0x20000);
113+ bubble_inserted = false;
114+ read_access = write_access = false;
115+ set_device_name(_T("Bubble Cassette"));
116+ }
117+ ~BUBBLECASETTE() {}
118+
119+ // common functions
120+ void initialize();
121+ void reset();
122+
123+ uint32_t read_io8(uint32_t addr);
124+ void write_io8(uint32_t addr, uint32_t data);
125+
126+ uint32_t read_signal(int id);
127+ void write_signal(int id, uint32_t data, uint32_t mask);
128+ void event_callback(int event_id, int err);
129+ void save_state(FILEIO* state_fio);
130+ bool load_state(FILEIO* state_fio);
131+
132+ // unique functions
133+ void open(_TCHAR* file_path, int bank);
134+ void close();
135+ bool is_bubble_inserted()
136+ {
137+ return bubble_inserted;
138+ }
139+ bool is_bubble_protected()
140+ {
141+ return write_protect;
142+ }
143+ void set_bubble_protect(bool flag)
144+ {
145+ if(write_protect != flag) {
146+ write_protect = flag;
147+ header_changed = true;
148+ }
149+ }
150+ bool get_access_lamp()
151+ {
152+ return (read_access | write_access);
153+ }
154+};
155+
156+#endif
--- /dev/null
+++ b/source/src/vm/bubcom80/bubcom80.cpp
@@ -0,0 +1,382 @@
1+/*
2+ Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3+
4+ Author : Takeda.Toshiya
5+ Date : 2018.05.08-
6+
7+ [ virtual machine ]
8+*/
9+
10+#include "bubcom80.h"
11+#include "../../emu.h"
12+#include "../device.h"
13+#include "../event.h"
14+
15+#include "../disk.h"
16+#include "../io.h"
17+#include "../ls393.h"
18+#include "../mb8877.h"
19+#include "../mc6850.h"
20+#include "../noise.h"
21+#include "../pcm1bit.h"
22+#include "../prnfile.h"
23+#include "../z80.h"
24+#include "../z80ctc.h"
25+
26+#ifdef USE_DEBUGGER
27+#include "../debugger.h"
28+#endif
29+
30+#include "bubblecasette.h"
31+#include "cmt.h"
32+#include "display.h"
33+#include "floppy.h"
34+#include "keyboard.h"
35+#include "membus.h"
36+#include "rtc.h"
37+
38+// ----------------------------------------------------------------------------
39+// initialize
40+// ----------------------------------------------------------------------------
41+
42+VM::VM(EMU* parent_emu) : emu(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+
49+ io = new IO(this, emu);
50+ flipflop = new LS393(this, emu);
51+ fdc = new MB8877(this, emu);
52+ fdc->set_context_noise_seek(new NOISE(this, emu));
53+ fdc->set_context_noise_head_down(new NOISE(this, emu));
54+ fdc->set_context_noise_head_up(new NOISE(this, emu));
55+// sio_rs = new MC6850(this, emu);
56+ sio_cmt = new MC6850(this, emu);
57+// sio_key = new MC6850(this, emu);
58+ pcm = new PCM1BIT(this, emu);
59+ cpu = new Z80(this, emu);
60+ ctc = new Z80CTC(this, emu);
61+
62+ bubblecasette[0] = new BUBBLECASETTE(this, emu);
63+ bubblecasette[1] = new BUBBLECASETTE(this, emu);
64+ cmt = new CMT(this, emu);
65+ if(config.printer_type == 0) {
66+ printer = new PRNFILE(this, emu);
67+// } else if(config.printer_type == 1) {
68+// printer = new BC861(this, emu);
69+ } else {
70+ printer = dummy;
71+ }
72+ display = new DISPLAY(this, emu);
73+ floppy = new FLOPPY(this, emu);
74+ keyboard = new KEYBOARD(this, emu);
75+ membus = new MEMBUS(this, emu);
76+ rtc = new RTC(this, emu);
77+
78+ // set contexts
79+ event->set_context_cpu(cpu);
80+ event->set_context_sound(pcm);
81+ event->set_context_sound(fdc->get_context_noise_seek());
82+ event->set_context_sound(fdc->get_context_noise_head_down());
83+ event->set_context_sound(fdc->get_context_noise_head_up());
84+
85+ flipflop->set_context_1qa(pcm, SIG_PCM1BIT_SIGNAL, 1);
86+ fdc->set_context_drq(display, SIG_DISPLAY_DMAC_CH0, 1);
87+ sio_cmt->set_context_out(cmt, SIG_CMT_OUT);
88+ ctc->set_context_zc0(flipflop, SIG_LS393_CLK, 1);
89+ ctc->set_constant_clock(0, CPU_CLOCKS);
90+ ctc->set_constant_clock(1, CPU_CLOCKS);
91+ ctc->set_constant_clock(2, CPU_CLOCKS);
92+
93+ cmt->set_context_sio(sio_cmt);
94+ display->set_context_cpu(cpu);
95+ display->set_context_cmt(cmt);
96+ display->set_context_pcm(pcm);
97+ display->set_context_prn(printer);
98+ display->set_context_dmac_mem(membus);
99+ display->set_context_dmac_ch0(fdc);
100+ display->set_context_dmac_ch2(display); // crtc
101+ floppy->set_context_fdc(floppy);
102+
103+ // cpu bus
104+ cpu->set_context_mem(membus);
105+ cpu->set_context_io(io);
106+ cpu->set_context_intr(ctc);
107+#ifdef USE_DEBUGGER
108+ cpu->set_context_debugger(new DEBUGGER(this, emu));
109+#endif
110+
111+ // z80 family daisy chain
112+ ctc->set_context_intr(cpu, 0);
113+
114+ // i/o bus
115+ io->set_iomap_range_rw(0x0000, 0x0008, bubblecasette[0]);
116+ io->set_iomap_range_rw(0x000c, 0x000d, membus);
117+ io->set_iomap_range_rw(0x0010, 0x0011, display);
118+ io->set_iomap_single_rw(0x0020, display);
119+ io->set_iomap_range_rw(0x0030, 0x0031, sio_cmt);
120+ io->set_iomap_range_rw(0x0040, 0x0043, ctc);
121+ io->set_iomap_single_rw(0x0050, display);
122+ io->set_iomap_range_rw(0x0060, 0x0068, display);
123+ io->set_iomap_single_w(0x0080, membus);
124+ io->set_iomap_range_r(0x0400, 0x047f, keyboard);
125+ io->set_iomap_range_rw(0x0800, 0x0fff, display);
126+ io->set_iomap_range_rw(0x3fd0, 0x3fd3, fdc);
127+ io->set_iomap_single_w(0x3fd8, floppy);
128+ io->set_iomap_range_rw(0x3fe0, 0x3fed, rtc);
129+ io->set_iomap_single_rw(0x3ff0, display);
130+ io->set_iomap_range_rw(0x4000, 0xffff, display);
131+
132+ // initialize all devices
133+ for(DEVICE* device = first_device; device; device = device->next_device) {
134+ device->initialize();
135+ }
136+ for(int i = 0; i < MAX_DRIVE; i++) {
137+ fdc->set_drive_type(i, DRIVE_TYPE_2HD); // 8inch 2D
138+ }
139+ fdc->write_signal(SIG_MB8877_MOTOR, 1, 1);
140+}
141+
142+VM::~VM()
143+{
144+ // delete all devices
145+ for(DEVICE* device = first_device; device;) {
146+ DEVICE *next_device = device->next_device;
147+ device->release();
148+ delete device;
149+ device = next_device;
150+ }
151+}
152+
153+DEVICE* VM::get_device(int id)
154+{
155+ for(DEVICE* device = first_device; device; device = device->next_device) {
156+ if(device->this_device_id == id) {
157+ return device;
158+ }
159+ }
160+ return NULL;
161+}
162+
163+// ----------------------------------------------------------------------------
164+// drive virtual machine
165+// ----------------------------------------------------------------------------
166+
167+void VM::reset()
168+{
169+ // reset all devices
170+ for(DEVICE* device = first_device; device; device = device->next_device) {
171+ device->reset();
172+ }
173+ ctc->write_io8(0, 0x07); // default frequency for beep
174+ ctc->write_io8(0, 0xef);
175+ pcm->write_signal(SIG_PCM1BIT_ON, 0, 0); // beep off
176+}
177+
178+void VM::run()
179+{
180+ event->drive();
181+}
182+
183+double VM::get_frame_rate()
184+{
185+ return event->get_frame_rate();
186+}
187+
188+// ----------------------------------------------------------------------------
189+// debugger
190+// ----------------------------------------------------------------------------
191+
192+#ifdef USE_DEBUGGER
193+DEVICE *VM::get_cpu(int index)
194+{
195+ if(index == 0) {
196+ return cpu;
197+ }
198+ return NULL;
199+}
200+#endif
201+
202+// ----------------------------------------------------------------------------
203+// draw screen
204+// ----------------------------------------------------------------------------
205+
206+void VM::draw_screen()
207+{
208+ display->draw_screen();
209+}
210+
211+// ----------------------------------------------------------------------------
212+// soud manager
213+// ----------------------------------------------------------------------------
214+
215+void VM::initialize_sound(int rate, int samples)
216+{
217+ // init sound manager
218+ event->initialize_sound(rate, samples);
219+
220+ // init sound gen
221+ pcm->initialize_sound(rate, 8000);
222+}
223+
224+uint16_t* VM::create_sound(int* extra_frames)
225+{
226+ return event->create_sound(extra_frames);
227+}
228+
229+int VM::get_sound_buffer_ptr()
230+{
231+ return event->get_sound_buffer_ptr();
232+}
233+
234+#ifdef USE_SOUND_VOLUME
235+void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
236+{
237+ if(ch == 0) {
238+ pcm->set_volume(0, decibel_l, decibel_r);
239+ } else if(ch == 1) {
240+ fdc->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
241+ fdc->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
242+ fdc->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
243+ }
244+}
245+#endif
246+
247+// ----------------------------------------------------------------------------
248+// user interface
249+// ----------------------------------------------------------------------------
250+
251+void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
252+{
253+ fdc->open_disk(drv, file_path, bank);
254+}
255+
256+void VM::close_floppy_disk(int drv)
257+{
258+ fdc->close_disk(drv);
259+}
260+
261+bool VM::is_floppy_disk_inserted(int drv)
262+{
263+ return fdc->is_disk_inserted(drv);
264+}
265+
266+void VM::is_floppy_disk_protected(int drv, bool value)
267+{
268+ fdc->is_disk_protected(drv, value);
269+}
270+
271+bool VM::is_floppy_disk_protected(int drv)
272+{
273+ return fdc->is_disk_protected(drv);
274+}
275+
276+uint32_t VM::is_floppy_disk_accessed()
277+{
278+ return fdc->read_signal(0);
279+}
280+
281+void VM::play_tape(int drv, const _TCHAR* file_path)
282+{
283+ cmt->play_tape(file_path);
284+}
285+
286+void VM::rec_tape(int drv, const _TCHAR* file_path)
287+{
288+ cmt->rec_tape(file_path);
289+}
290+
291+void VM::close_tape(int drv)
292+{
293+ cmt->close_tape();
294+}
295+
296+bool VM::is_tape_inserted(int drv)
297+{
298+ return cmt->is_tape_inserted();
299+}
300+
301+void VM::open_bubble_casette(int drv, const _TCHAR *path, int bank)
302+{
303+ if(drv < 2 && bubblecasette[drv] != NULL) {
304+ bubblecasette[drv]->open((_TCHAR *)path, bank);
305+ }
306+}
307+
308+void VM::close_bubble_casette(int drv)
309+{
310+ if(drv < 2 && bubblecasette[drv] != NULL) {
311+ bubblecasette[drv]->close();
312+ }
313+}
314+
315+bool VM::is_bubble_casette_inserted(int drv)
316+{
317+ if(drv < 2 && bubblecasette[drv] != NULL) {
318+ return bubblecasette[drv]->is_bubble_inserted();
319+ }
320+ return false;
321+}
322+
323+bool VM::is_bubble_casette_protected(int drv)
324+{
325+ if(drv < 2 && bubblecasette[drv] != NULL) {
326+ return bubblecasette[drv]->is_bubble_protected();
327+ }
328+ return false;
329+}
330+
331+void VM::is_bubble_casette_protected(int drv, bool flag)
332+{
333+ if(drv < 2 && bubblecasette[drv] != NULL) {
334+ bubblecasette[drv]->set_bubble_protect(flag);
335+ }
336+}
337+
338+bool VM::is_frame_skippable()
339+{
340+ return event->is_frame_skippable();
341+}
342+
343+void VM::update_config()
344+{
345+ for(DEVICE* device = first_device; device; device = device->next_device) {
346+ device->update_config();
347+ }
348+}
349+
350+#define STATE_VERSION 1
351+
352+void VM::save_state(FILEIO* state_fio)
353+{
354+ state_fio->FputUint32(STATE_VERSION);
355+
356+ for(DEVICE* device = first_device; device; device = device->next_device) {
357+ const char *name = typeid(*device).name() + 6; // skip "class "
358+
359+ state_fio->FputInt32(strlen(name));
360+ state_fio->Fwrite(name, strlen(name), 1);
361+ device->save_state(state_fio);
362+ }
363+}
364+
365+bool VM::load_state(FILEIO* state_fio)
366+{
367+ if(state_fio->FgetUint32() != STATE_VERSION) {
368+ return false;
369+ }
370+ for(DEVICE* device = first_device; device; device = device->next_device) {
371+ const char *name = typeid(*device).name() + 6; // skip "class "
372+
373+ if(!(state_fio->FgetInt32() == strlen(name) && state_fio->Fcompare(name, strlen(name)))) {
374+ return false;
375+ }
376+ if(!device->load_state(state_fio)) {
377+ return false;
378+ }
379+ }
380+ return true;
381+}
382+
--- /dev/null
+++ b/source/src/vm/bubcom80/bubcom80.h
@@ -0,0 +1,172 @@
1+/*
2+ Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3+
4+ Author : Takeda.Toshiya
5+ Date : 2018.05.08-
6+
7+ [ virtual machine ]
8+*/
9+
10+#ifndef _BUBCOM80_H_
11+#define _BUBCOM80_H_
12+
13+#define DEVICE_NAME "Systems Formulate BUBCOM80"
14+#define CONFIG_NAME "bubcom80"
15+
16+// device informations for virtual machine
17+#define FRAMES_PER_SEC 62.422
18+#define LINES_PER_FRAME 260
19+//#define CPU_CLOCKS 3993624
20+#define CPU_CLOCKS 4000000
21+#define SCREEN_WIDTH 640
22+#define SCREEN_HEIGHT 400
23+#define WINDOW_HEIGHT_ASPECT 480
24+#define MAX_DRIVE 4
25+#define MEMORY_ADDR_MAX 0x10000
26+#define MEMORY_BANK_SIZE 0x800
27+#define IO_ADDR_MAX 0x10000
28+#define SUPPORT_VARIABLE_TIMING
29+
30+// device informations for win32
31+#define USE_FLOPPY_DISK 4
32+#define USE_TAPE 1
33+#define TAPE_BINARY_ONLY
34+#define USE_BUBBLE 2
35+#define USE_SHIFT_NUMPAD_KEY
36+#define USE_ALT_F10_KEY
37+#define USE_AUTO_KEY 5
38+#define USE_AUTO_KEY_RELEASE 6
39+#define USE_AUTO_KEY_NUMPAD
40+#define USE_SCREEN_FILTER
41+#define USE_SCANLINE
42+#define USE_SOUND_VOLUME 2
43+#define USE_JOYSTICK
44+#define USE_PRINTER
45+#define USE_PRINTER_TYPE 3
46+#define USE_DEBUGGER
47+#define USE_STATE
48+
49+#include "../../common.h"
50+#include "../../fileio.h"
51+
52+#ifdef USE_SOUND_VOLUME
53+static const _TCHAR *sound_device_caption[] = {
54+ _T("Beep"), _T("Noise (FDD)"),
55+};
56+#endif
57+
58+class EMU;
59+class DEVICE;
60+class EVENT;
61+
62+class IO;
63+class LS393;
64+class MB8877;
65+class MC6850;
66+class MEMORY;
67+class PCM1BIT;
68+class Z80;
69+class Z80CTC;
70+
71+class BUBBLECASETTE;
72+class CMT;
73+class DISPLAY;
74+class FLOPPY;
75+class KEYBOARD;
76+class MEMBUS;
77+class RTC;
78+
79+class VM
80+{
81+protected:
82+ EMU* emu;
83+
84+ // devices
85+ EVENT* event;
86+
87+ IO* io;
88+ LS393* flipflop;
89+ MB8877* fdc;
90+// MC6850* sio_rs;
91+ MC6850* sio_cmt;
92+// MC6850* sio_key;
93+ PCM1BIT* pcm;
94+ Z80* cpu;
95+ Z80CTC* ctc;
96+
97+ BUBBLECASETTE* bubblecasette[2];
98+ CMT* cmt;
99+ DEVICE* printer;
100+ DISPLAY* display;
101+ FLOPPY* floppy;
102+ KEYBOARD* keyboard;
103+ MEMBUS* membus;
104+ RTC* rtc;
105+
106+public:
107+ // ----------------------------------------
108+ // initialize
109+ // ----------------------------------------
110+
111+ VM(EMU* parent_emu);
112+ ~VM();
113+
114+ // ----------------------------------------
115+ // for emulation class
116+ // ----------------------------------------
117+
118+ // drive virtual machine
119+ void reset();
120+ void run();
121+ double get_frame_rate();
122+
123+#ifdef USE_DEBUGGER
124+ // debugger
125+ DEVICE *get_cpu(int index);
126+#endif
127+
128+ // draw screen
129+ void draw_screen();
130+
131+ // sound generation
132+ void initialize_sound(int rate, int samples);
133+ uint16_t* create_sound(int* extra_frames);
134+ int get_sound_buffer_ptr();
135+#ifdef USE_SOUND_VOLUME
136+ void set_sound_device_volume(int ch, int decibel_l, int decibel_r);
137+#endif
138+
139+ // user interface
140+ void open_floppy_disk(int drv, const _TCHAR* file_path, int bank);
141+ void close_floppy_disk(int drv);
142+ bool is_floppy_disk_inserted(int drv);
143+ void is_floppy_disk_protected(int drv, bool value);
144+ bool is_floppy_disk_protected(int drv);
145+ uint32_t is_floppy_disk_accessed();
146+ void play_tape(int drv, const _TCHAR* file_path);
147+ void rec_tape(int drv, const _TCHAR* file_path);
148+ void close_tape(int drv);
149+ bool is_tape_inserted(int drv);
150+ void open_bubble_casette(int drv, const _TCHAR *path, int bank);
151+ void close_bubble_casette(int drv);
152+ bool is_bubble_casette_inserted(int drv);
153+ bool is_bubble_casette_protected(int drv);
154+ void is_bubble_casette_protected(int drv, bool flag);
155+ bool is_frame_skippable();
156+
157+ void update_config();
158+ void save_state(FILEIO* state_fio);
159+ bool load_state(FILEIO* state_fio);
160+
161+ // ----------------------------------------
162+ // for each device
163+ // ----------------------------------------
164+
165+ // devices
166+ DEVICE* get_device(int id);
167+ DEVICE* dummy;
168+ DEVICE* first_device;
169+ DEVICE* last_device;
170+};
171+
172+#endif
--- /dev/null
+++ b/source/src/vm/bubcom80/cmt.cpp
@@ -0,0 +1,160 @@
1+/*
2+ Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3+
4+ Author : Takeda.Toshiya
5+ Date : 2018.05.09-
6+
7+ [ cmt ]
8+*/
9+
10+#include "cmt.h"
11+#include "../mc6850.h"
12+
13+void CMT::initialize()
14+{
15+ fio = new FILEIO();
16+ play = rec = remote = false;
17+}
18+
19+void CMT::release()
20+{
21+ release_tape();
22+ delete fio;
23+}
24+
25+void CMT::reset()
26+{
27+ close_tape();
28+ play = rec = remote = false;
29+}
30+
31+void CMT::write_signal(int id, uint32_t data, uint32_t mask)
32+{
33+ if(id == SIG_CMT_REMOTE) {
34+ remote = ((data & mask) != 0);
35+ } else if(id == SIG_CMT_OUT) {
36+ if(rec && remote) {
37+ // recv from sio
38+ buffer[bufcnt++] = data & mask;
39+ if(bufcnt >= BUFFER_SIZE) {
40+ fio->Fwrite(buffer, bufcnt, 1);
41+ bufcnt = 0;
42+ }
43+ }
44+ }
45+}
46+
47+void CMT::play_tape(const _TCHAR* file_path)
48+{
49+ close_tape();
50+
51+ if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
52+ fio->Fseek(0, FILEIO_SEEK_END);
53+ int size = (fio->Ftell() + 9) & (BUFFER_SIZE - 1);
54+ fio->Fseek(0, FILEIO_SEEK_SET);
55+ memset(buffer, 0, sizeof(buffer));
56+ fio->Fread(buffer, sizeof(buffer), 1);
57+ fio->Fclose();
58+
59+ // send data to sio
60+ // this implement does not care the sio buffer size... :-(
61+ for(int i = 0; i < size; i++) {
62+ d_sio->write_signal(SIG_MC6850_RECV, buffer[i], 0xff);
63+ }
64+ play = true;
65+ }
66+}
67+
68+void CMT::rec_tape(const _TCHAR* file_path)
69+{
70+ close_tape();
71+
72+ if(fio->Fopen(file_path, FILEIO_READ_WRITE_NEW_BINARY)) {
73+ my_tcscpy_s(rec_file_path, _MAX_PATH, file_path);
74+ bufcnt = 0;
75+ rec = true;
76+ }
77+}
78+
79+void CMT::close_tape()
80+{
81+ // close file
82+ release_tape();
83+
84+ // clear sio buffer
85+ d_sio->write_signal(SIG_MC6850_CLEAR, 0, 0);
86+}
87+
88+void CMT::release_tape()
89+{
90+ // close file
91+ if(fio->IsOpened()) {
92+ if(rec && bufcnt) {
93+ fio->Fwrite(buffer, bufcnt, 1);
94+ }
95+ fio->Fclose();
96+ }
97+ play = rec = false;
98+}
99+
100+#define STATE_VERSION 2
101+
102+void CMT::save_state(FILEIO* state_fio)
103+{
104+ state_fio->FputUint32(STATE_VERSION);
105+ state_fio->FputInt32(this_device_id);
106+
107+ state_fio->FputBool(play);
108+ state_fio->FputBool(rec);
109+ state_fio->FputBool(remote);
110+ state_fio->Fwrite(rec_file_path, sizeof(rec_file_path), 1);
111+ if(rec && fio->IsOpened()) {
112+ int length_tmp = (int)fio->Ftell();
113+ fio->Fseek(0, FILEIO_SEEK_SET);
114+ state_fio->FputInt32(length_tmp);
115+ while(length_tmp != 0) {
116+ uint8_t buffer_tmp[1024];
117+ int length_rw = min(length_tmp, (int)sizeof(buffer_tmp));
118+ fio->Fread(buffer_tmp, length_rw, 1);
119+ state_fio->Fwrite(buffer_tmp, length_rw, 1);
120+ length_tmp -= length_rw;
121+ }
122+ } else {
123+ state_fio->FputInt32(0);
124+ }
125+ state_fio->FputInt32(bufcnt);
126+ state_fio->Fwrite(buffer, sizeof(buffer), 1);
127+}
128+
129+bool CMT::load_state(FILEIO* state_fio)
130+{
131+ release_tape();
132+
133+ if(state_fio->FgetUint32() != STATE_VERSION) {
134+ return false;
135+ }
136+ if(state_fio->FgetInt32() != this_device_id) {
137+ return false;
138+ }
139+ play = state_fio->FgetBool();
140+ rec = state_fio->FgetBool();
141+ remote = state_fio->FgetBool();
142+ state_fio->Fread(rec_file_path, sizeof(rec_file_path), 1);
143+ int length_tmp = state_fio->FgetInt32();
144+ if(rec) {
145+ fio->Fopen(rec_file_path, FILEIO_READ_WRITE_NEW_BINARY);
146+ while(length_tmp != 0) {
147+ uint8_t buffer_tmp[1024];
148+ int length_rw = min(length_tmp, (int)sizeof(buffer_tmp));
149+ state_fio->Fread(buffer_tmp, length_rw, 1);
150+ if(fio->IsOpened()) {
151+ fio->Fwrite(buffer_tmp, length_rw, 1);
152+ }
153+ length_tmp -= length_rw;
154+ }
155+ }
156+ bufcnt = state_fio->FgetInt32();
157+ state_fio->Fread(buffer, sizeof(buffer), 1);
158+ return true;
159+}
160+
--- /dev/null
+++ b/source/src/vm/bubcom80/cmt.h
@@ -0,0 +1,66 @@
1+/*
2+ Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3+
4+ Author : Takeda.Toshiya
5+ Date : 2018.05.09-
6+
7+ [ cmt ]
8+*/
9+
10+#ifndef _CMT_H_
11+#define _CMT_H_
12+
13+#include "../vm.h"
14+#include "../../emu.h"
15+#include "../device.h"
16+
17+#define SIG_CMT_REMOTE 0
18+#define SIG_CMT_OUT 1
19+
20+// max 256kbytes
21+#define BUFFER_SIZE 0x40000
22+
23+class CMT : public DEVICE
24+{
25+private:
26+ DEVICE* d_sio;
27+
28+ FILEIO* fio;
29+ bool play, rec, remote;
30+ _TCHAR rec_file_path[_MAX_PATH];
31+ int bufcnt;
32+ uint8_t buffer[BUFFER_SIZE];
33+
34+ void release_tape();
35+
36+public:
37+ CMT(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
38+ {
39+ set_device_name(_T("CMT I/F"));
40+ }
41+ ~CMT() {}
42+
43+ // common functions
44+ void initialize();
45+ void release();
46+ void reset();
47+ void write_signal(int id, uint32_t data, uint32_t mask);
48+ void save_state(FILEIO* state_fio);
49+ bool load_state(FILEIO* state_fio);
50+
51+ // unique functions
52+ void play_tape(const _TCHAR* file_path);
53+ void rec_tape(const _TCHAR* file_path);
54+ void close_tape();
55+ bool is_tape_inserted()
56+ {
57+ return (play || rec);
58+ }
59+ void set_context_sio(DEVICE* device)
60+ {
61+ d_sio = device;
62+ }
63+};
64+
65+#endif
66+
--- /dev/null
+++ b/source/src/vm/bubcom80/display.cpp
@@ -0,0 +1,849 @@
1+/*
2+ Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3+
4+ Author : Takeda.Toshiya
5+ Date : 2018.05.08-
6+
7+ [ display ]
8+*/
9+
10+#include "display.h"
11+#include "cmt.h"
12+#include "../pcm1bit.h"
13+#include "../z80.h"
14+
15+#define EVENT_BUSREQ 0
16+
17+void DISPLAY::initialize()
18+{
19+ for(int i = 0; i < 256; i++) {
20+ uint8_t *dest = sg_pattern + 8 * i;
21+ dest[0] = dest[1] = ((i & 0x01) ? 0xf0 : 0) | ((i & 0x02) ? 0x0f : 0);
22+ dest[2] = dest[3] = ((i & 0x04) ? 0xf0 : 0) | ((i & 0x08) ? 0x0f : 0);
23+ dest[4] = dest[5] = ((i & 0x10) ? 0xf0 : 0) | ((i & 0x20) ? 0x0f : 0);
24+ dest[6] = dest[7] = ((i & 0x40) ? 0xf0 : 0) | ((i & 0x80) ? 0x0f : 0);
25+ }
26+ memset(font, 0x00, sizeof(font));
27+ memset(vram, 0x00, sizeof(vram));
28+
29+ for(int i = 0; i < 8; i++) {
30+ palette_text_pc [i] = RGBA_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0, 255); // A is a flag for crt filter
31+ palette_graph_pc[i] = RGBA_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0, 0);
32+ }
33+ color = true;
34+ width40 = false;
35+ mode = 0x80;
36+
37+ register_frame_event(this);
38+ register_vline_event(this);
39+}
40+
41+#define STORE_DMAC_CONTEXTS() \
42+ DEVICE *d_mem = dmac.mem; \
43+ DEVICE *d_ch0 = dmac.ch[0].io; \
44+ DEVICE *d_ch1 = dmac.ch[1].io; \
45+ DEVICE *d_ch2 = dmac.ch[2].io; \
46+ DEVICE *d_ch3 = dmac.ch[3].io
47+
48+#define RESTORE_DMAC_CONTEXTS() \
49+ dmac.mem = d_mem; \
50+ dmac.ch[0].io = d_ch0; \
51+ dmac.ch[1].io = d_ch1; \
52+ dmac.ch[2].io = d_ch2; \
53+ dmac.ch[3].io = d_ch3;
54+
55+void DISPLAY::reset()
56+{
57+ memset(&crtc, 0, sizeof(crtc));
58+ crtc.reset();
59+ update_timing();
60+
61+ STORE_DMAC_CONTEXTS();
62+ memset(&dmac, 0, sizeof(dmac));
63+ RESTORE_DMAC_CONTEXTS();
64+}
65+
66+void DISPLAY::write_io8(uint32_t addr, uint32_t data)
67+{
68+ switch(addr) {
69+ case 0x10:
70+ crtc.write_param(data);
71+ if(crtc.timing_changed) {
72+ update_timing();
73+ crtc.timing_changed = false;
74+ }
75+ break;
76+ case 0x11:
77+ crtc.write_cmd(data);
78+ break;
79+ case 0x20:
80+ d_prn->write_signal(SIG_PRINTER_DATA, data, 0xff);
81+ break;
82+ case 0x50:
83+ d_cmt->write_signal(SIG_CMT_REMOTE, data, 0x01);
84+ color = ((data & 0x04) != 0);
85+ width40 = ((data & 0x08) != 0);
86+ d_pcm->write_signal(SIG_PCM1BIT_ON, data, 0x10);
87+ d_prn->write_signal(SIG_PRINTER_STROBE, data, 0x20);
88+ break;
89+ case 0x60:
90+ case 0x61:
91+ case 0x62:
92+ case 0x63:
93+ case 0x64:
94+ case 0x65:
95+ case 0x66:
96+ case 0x67:
97+ case 0x68:
98+ dmac.write_io8(addr, data);
99+ break;
100+ case 0x3ff0:
101+ mode = data;
102+ break;
103+ default:
104+ if(addr >= 0x800 && addr < 0x1000) {
105+ font[addr & 0x7ff] = data;
106+ } else if(addr >= 0x4000 && addr < 0x10000) {
107+ vram[addr] = data;
108+ }
109+ break;
110+ }
111+}
112+
113+uint32_t DISPLAY::read_io8(uint32_t addr)
114+{
115+ switch(addr) {
116+ case 0x10:
117+ return crtc.read_param();
118+ case 0x11:
119+ return crtc.read_status();
120+ case 0x20:
121+ return d_prn->read_signal(SIG_PRINTER_BUSY) & 0x40;
122+ case 0x50:
123+ // bit1: 1=WIDTH80, 0=WIDTH40
124+ return 0xff; // dipswitch???
125+ case 0x60:
126+ case 0x61:
127+ case 0x62:
128+ case 0x63:
129+ case 0x64:
130+ case 0x65:
131+ case 0x66:
132+ case 0x67:
133+ case 0x68:
134+ return dmac.read_io8(addr);
135+ case 0x3ff0:
136+ return (crtc.vblank ? 0x40 : 0);
137+ default:
138+ if(addr >= 0x800 && addr < 0x1000) {
139+ return font[addr & 0x7ff];
140+ } else if(addr >= 0x4000 && addr < 0x10000) {
141+ return vram[addr];
142+ }
143+ break;
144+ }
145+ return 0x0f;
146+}
147+
148+void DISPLAY::write_dma_io8(uint32_t addr, uint32_t data)
149+{
150+ // to crtc
151+ crtc.write_buffer(data);
152+}
153+
154+void DISPLAY::write_signal(int id, uint32_t data, uint32_t mask)
155+{
156+ switch(id) {
157+ case SIG_DISPLAY_DMAC_CH0:
158+ case SIG_DISPLAY_DMAC_CH1:
159+ case SIG_DISPLAY_DMAC_CH2:
160+ case SIG_DISPLAY_DMAC_CH3:
161+ if(data & mask) {
162+ if(!dmac.ch[id].running) {
163+ dmac.start(id);
164+ }
165+ dmac.run(id);
166+ }
167+ break;
168+ }
169+}
170+
171+void DISPLAY::event_callback(int event_id, int err)
172+{
173+ switch(event_id) {
174+ case EVENT_BUSREQ:
175+ d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 0);
176+ break;
177+ }
178+}
179+
180+void DISPLAY::event_frame()
181+{
182+ crtc.update_blink();
183+}
184+
185+void DISPLAY::event_vline(int v, int clock)
186+{
187+ int disp_line = crtc.height * crtc.char_height;
188+
189+ if(v == 0) {
190+ if(crtc.status & 0x10) {
191+ // start dma transfer to crtc
192+ dmac.start(2);
193+ if(!dmac.ch[2].running) {
194+ // dma underrun occurs !!!
195+ crtc.status |= 8;
196+// crtc.status &= ~0x10;
197+ } else {
198+ crtc.status &= ~8;
199+ }
200+ // dma wait cycles
201+ // from memory access test on PC-8801MA2 (XM8 version 1.20)
202+ busreq_clocks = (int)((double)(dmac.ch[2].count.sd + 1) * 5.95 / (double)disp_line + 0.5);
203+ }
204+ crtc.start();
205+ }
206+ if(v < disp_line) {
207+ if(/*(crtc.status & 0x10) && */dmac.ch[2].running) {
208+ // bus request
209+ d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
210+ register_event_by_clock(this, EVENT_BUSREQ, busreq_clocks, false, NULL);
211+ // run dma transfer to crtc
212+ if((v % crtc.char_height) == 0) {
213+ for(int i = 0; i < 80 + crtc.attrib.num * 2; i++) {
214+ dmac.run(2);
215+ }
216+ }
217+ }
218+ } else if(v == disp_line) {
219+ if(/*(crtc.status & 0x10) && */dmac.ch[2].running) {
220+ dmac.finish(2);
221+ }
222+ crtc.expand_buffer();
223+ crtc.finish();
224+ }
225+}
226+
227+void DISPLAY::update_timing()
228+{
229+ int lines_per_frame = (crtc.height + crtc.vretrace) * crtc.char_height;
230+ double frames_per_sec = 15980.0 / (double)lines_per_frame;
231+
232+ set_frames_per_sec(frames_per_sec);
233+ set_lines_per_frame(lines_per_frame);
234+}
235+
236+void DISPLAY::draw_screen()
237+{
238+ draw_text();
239+ draw_graph();
240+
241+ for(int y = 0; y < 200; y++) {
242+ scrntype_t* dest0 = emu->get_screen_buffer(y * 2);
243+ scrntype_t* dest1 = emu->get_screen_buffer(y * 2 + 1);
244+ uint8_t* src_t = text[y];
245+ uint8_t* src_g = graph[y];
246+
247+ for(int x = 0; x < 640; x++) {
248+ uint32_t t = src_t[x];
249+ uint32_t g = src_g[x];
250+ dest0[x] = t ? palette_text_pc[t & 7] : palette_graph_pc[g ? g : (mode & 7)];
251+ }
252+ if(config.scan_line) {
253+ memset(dest1, 0, 640 * sizeof(scrntype_t));
254+ } else {
255+ for(int x = 0; x < 640; x++) {
256+ dest1[x] = dest0[x];
257+ }
258+ }
259+ }
260+ emu->screen_skip_line(true);
261+}
262+
263+/*
264+ attributes:
265+
266+ bit7: graph=1/character=0
267+ bit6: green
268+ bit5: red
269+ bit4: blue
270+ bit3: under line
271+ bit2: upper line
272+ bit1: secret
273+ bit0: reverse
274+*/
275+
276+void DISPLAY::draw_text()
277+{
278+ if(crtc.status & 0x88) {
279+ // dma underrun
280+ crtc.status &= ~0x80;
281+ memset(crtc.text.expand, 0, 200 * 80);
282+ memset(crtc.attrib.expand, crtc.reverse ? 3 : 2, 200 * 80);
283+ }
284+ // for Advanced Fantasian Opening (20line) (XM8 version 1.00)
285+ if(!(crtc.status & 0x10)) {
286+// if(!(crtc.status & 0x10) || (crtc.status & 8)) {
287+ memset(crtc.text.expand, 0, 200 * 80);
288+ for(int y = 0; y < 200; y++) {
289+ for(int x = 0; x < 80; x++) {
290+ crtc.attrib.expand[y][x] &= 0x70;
291+ crtc.attrib.expand[y][x] |= 0x02;
292+ }
293+ }
294+// memset(crtc.attrib.expand, 2, 200 * 80);
295+ }
296+
297+ // for Xak2 opening
298+ memset(text, 8, sizeof(text));
299+
300+ int char_height = crtc.char_height;
301+
302+ if(crtc.skip_line) {
303+ char_height <<= 1;
304+ }
305+ for(int cy = 0, ytop = 0; cy < crtc.height && ytop < 200; cy++, ytop += char_height) {
306+ for(int x = 0, cx = 0; cx < crtc.width; x += 8, cx++) {
307+ if(width40 && (cx & 1)) {
308+ continue;
309+ }
310+ uint8_t attrib = crtc.attrib.expand[cy][cx];
311+ uint8_t color = (attrib & 0x70) ? (attrib >> 4) : 8;
312+ bool under_line = ((attrib & 8) != 0);
313+ bool upper_line = ((attrib & 4) != 0);
314+ bool secret = ((attrib & 2) != 0);
315+ bool reverse = ((attrib & 1) != 0);
316+
317+ uint8_t code = secret ? 0 : crtc.text.expand[cy][cx];
318+ uint8_t *pattern = ((attrib & 0x80) ? sg_pattern : font) + code * 8;
319+
320+ for(int l = 0, y = ytop; l < char_height && y < 200; l++, y++) {
321+ uint8_t pat = (l < 8) ? pattern[l] : 0;
322+ if((upper_line && l == 0) || (under_line && l >= 7)) {
323+ pat = 0xff;
324+ }
325+ if(reverse) {
326+ pat ^= 0xff;
327+ }
328+
329+ uint8_t *dest = &text[y][x];
330+ if(width40) {
331+ dest[ 0] = dest[ 1] = (pat & 0x80) ? color : 0;
332+ dest[ 2] = dest[ 3] = (pat & 0x40) ? color : 0;
333+ dest[ 4] = dest[ 5] = (pat & 0x20) ? color : 0;
334+ dest[ 6] = dest[ 7] = (pat & 0x10) ? color : 0;
335+ dest[ 8] = dest[ 9] = (pat & 0x08) ? color : 0;
336+ dest[10] = dest[11] = (pat & 0x04) ? color : 0;
337+ dest[12] = dest[13] = (pat & 0x02) ? color : 0;
338+ dest[14] = dest[15] = (pat & 0x01) ? color : 0;
339+ } else {
340+ dest[0] = (pat & 0x80) ? color : 0;
341+ dest[1] = (pat & 0x40) ? color : 0;
342+ dest[2] = (pat & 0x20) ? color : 0;
343+ dest[3] = (pat & 0x10) ? color : 0;
344+ dest[4] = (pat & 0x08) ? color : 0;
345+ dest[5] = (pat & 0x04) ? color : 0;
346+ dest[6] = (pat & 0x02) ? color : 0;
347+ dest[7] = (pat & 0x01) ? color : 0;
348+ }
349+ }
350+ }
351+ }
352+}
353+
354+void DISPLAY::draw_graph()
355+{
356+ uint8_t *vram_b, *vram_r, *vram_g;
357+
358+ switch(mode & 0xe0) {
359+ case 0x00:
360+ vram_b = vram_r = vram_g = vram + 0x0000; // null
361+ break;
362+ case 0xc0:
363+ vram_b = vram_r = vram_g = vram + 0x8000; // blue
364+ break;
365+ case 0xe0:
366+ vram_b = vram_r = vram_g = vram + 0xc000; // red
367+ break;
368+ case 0xa0:
369+ vram_b = vram_r = vram_g = vram + 0x4000; // green
370+ break;
371+ default:
372+ vram_b = vram + 0x8000; // blue
373+ vram_r = vram + 0xc000; // red
374+ vram_g = vram + 0x4000; // green
375+ break;
376+ }
377+ for(int y = 0, src = 0; y < 200; y ++) {
378+ for(int x = 0; x < 80; x++) {
379+ uint8_t b = vram_b[src];
380+ uint8_t r = vram_r[src];
381+ uint8_t g = vram_g[src];
382+ uint8_t* d = &graph[y][x << 3];
383+
384+ d[0] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
385+ d[1] = ((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4);
386+ d[2] = ((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3);
387+ d[3] = ((b & 0x10) >> 4) | ((r & 0x10) >> 3) | ((g & 0x10) >> 2);
388+ d[4] = ((b & 0x08) >> 3) | ((r & 0x08) >> 2) | ((g & 0x08) >> 1);
389+ d[5] = ((b & 0x04) >> 2) | ((r & 0x04) >> 1) | ((g & 0x04) >> 0);
390+ d[6] = ((b & 0x02) >> 1) | ((r & 0x02) >> 0) | ((g & 0x02) << 1);
391+ d[7] = ((b & 0x01) >> 0) | ((r & 0x01) << 1) | ((g & 0x01) << 2);
392+
393+ src = (src + 1) & 0x3fff;
394+ }
395+ }
396+}
397+
398+/* ----------------------------------------------------------------------------
399+ CRTC (uPD3301)
400+---------------------------------------------------------------------------- */
401+
402+void crtc_t::reset()
403+{
404+ blink.rate = 24;
405+ cursor.type = cursor.mode = -1;
406+ cursor.x = cursor.y = -1;
407+ attrib.data = 0x70;
408+ attrib.num = 20;
409+ width = 80;
410+ height = 25;
411+ char_height = 8;
412+ skip_line = false;
413+ vretrace = 7;
414+ timing_changed = false;
415+ reverse = 0;
416+ intr_mask = 3;
417+}
418+
419+void crtc_t::write_cmd(uint8_t data)
420+{
421+ cmd = (data >> 5) & 7;
422+ cmd_ptr = 0;
423+ switch(cmd) {
424+ case 0: // reset
425+ status &= ~0x16;
426+ status |= 0x80; // fix
427+ cursor.x = cursor.y = -1;
428+ break;
429+ case 1: // start display
430+ reverse = data & 1;
431+// status |= 0x10;
432+ status |= 0x90; // fix
433+ status &= ~8;
434+ break;
435+ case 2: // set interrupt mask
436+ if(!(data & 1)) {
437+// status = 0; // from M88
438+ status = 0x80; // fix
439+ }
440+ intr_mask = data & 3;
441+ break;
442+ case 3: // read light pen
443+ status &= ~1;
444+ break;
445+ case 4: // load cursor position ON/OFF
446+ cursor.type = (data & 1) ? cursor.mode : -1;
447+ break;
448+ case 5: // reset interrupt
449+ status &= ~6;
450+ break;
451+ case 6: // reset counters
452+ status &= ~6;
453+ break;
454+ }
455+}
456+
457+void crtc_t::write_param(uint8_t data)
458+{
459+ switch(cmd) {
460+ case 0:
461+ switch(cmd_ptr) {
462+ case 0:
463+ width = min((data & 0x7f) + 2, 80);
464+ break;
465+ case 1:
466+ if(height != (data & 0x3f) + 1) {
467+ height = (data & 0x3f) + 1;
468+ timing_changed = true;
469+ }
470+ blink.rate = 32 * ((data >> 6) + 1);
471+ break;
472+ case 2:
473+ if(char_height != (data & 0x1f) + 1) {
474+ char_height = (data & 0x1f) + 1;
475+ timing_changed = true;
476+ }
477+ cursor.mode = (data >> 5) & 3;
478+ skip_line = ((data & 0x80) != 0);
479+ break;
480+ case 3:
481+ if(vretrace != ((data >> 5) & 7) + 1) {
482+ vretrace = ((data >> 5) & 7) + 1;
483+ timing_changed = true;
484+ }
485+ break;
486+ case 4:
487+ mode = (data >> 5) & 7;
488+ attrib.num = (mode & 1) ? 0 : min((data & 0x1f) + 1, 20);
489+ break;
490+ }
491+ break;
492+ case 4:
493+ switch(cmd_ptr) {
494+ case 0:
495+ cursor.x = data;
496+ break;
497+ case 1:
498+ cursor.y = data;
499+ break;
500+ }
501+ break;
502+ case 6:
503+ status = 0;
504+ break;
505+ }
506+ cmd_ptr++;
507+}
508+
509+uint32_t crtc_t::read_param()
510+{
511+ uint32_t val = 0xff;
512+
513+ switch(cmd) {
514+ case 3: // read light pen
515+ switch(cmd_ptr) {
516+ case 0:
517+ val = 0; // fix me
518+ break;
519+ case 1:
520+ val = 0; // fix me
521+ break;
522+ }
523+ break;
524+ default:
525+ // XM8 version 1.10
526+ val = read_status();
527+ break;
528+ }
529+ cmd_ptr++;
530+ return val;
531+}
532+
533+uint32_t crtc_t::read_status()
534+{
535+ if(status & 8) {
536+ return status & ~0x10;
537+ } else {
538+ return status;
539+ }
540+}
541+
542+void crtc_t::start()
543+{
544+ memset(buffer, 0, sizeof(buffer));
545+ buffer_ptr = 0;
546+ vblank = false;
547+}
548+
549+void crtc_t::finish()
550+{
551+ if((status & 0x10) && !(intr_mask & 1)) {
552+ status |= 2;
553+ }
554+ vblank = true;
555+}
556+
557+void crtc_t::write_buffer(uint8_t data)
558+{
559+ buffer[(buffer_ptr++) & 0x3fff] = data;
560+}
561+
562+uint8_t crtc_t::read_buffer(int ofs)
563+{
564+ if(ofs < buffer_ptr) {
565+ return buffer[ofs];
566+ }
567+ // dma underrun occurs !!!
568+ status |= 8;
569+// status &= ~0x10;
570+ return 0;
571+}
572+
573+void crtc_t::update_blink()
574+{
575+ // from m88
576+ if(++blink.counter > blink.rate) {
577+ blink.counter = 0;
578+ }
579+ blink.attrib = (blink.counter < blink.rate / 4) ? 2 : 0;
580+ blink.cursor = (blink.counter <= blink.rate / 4) || (blink.rate / 2 <= blink.counter && blink.counter <= 3 * blink.rate / 4);
581+}
582+
583+void crtc_t::expand_buffer()
584+{
585+ int char_height_tmp = char_height;
586+ int exitline = -1;
587+
588+ if(skip_line) {
589+ char_height_tmp <<= 1;
590+ }
591+ if(!(status & 0x10)) {
592+ exitline = 0;
593+ goto underrun;
594+ }
595+ for(int cy = 0, ytop = 0, ofs = 0; cy < height && ytop < 200; cy++, ytop += char_height_tmp, ofs += 80 + attrib.num * 2) {
596+ for(int cx = 0; cx < width; cx++) {
597+ text.expand[cy][cx] = read_buffer(ofs + cx);
598+ }
599+ if((status & 8) && exitline == -1) {
600+ exitline = cy;
601+// goto underrun;
602+ }
603+ }
604+ if(mode & 4) {
605+ // non transparent
606+ for(int cy = 0, ytop = 0, ofs = 0; cy < height && ytop < 200; cy++, ytop += char_height_tmp, ofs += 80 + attrib.num * 2) {
607+ for(int cx = 0; cx < width; cx += 2) {
608+ set_attrib(read_buffer(ofs + cx + 1));
609+ attrib.expand[cy][cx] = attrib.expand[cy][cx + 1] = attrib.data;
610+ }
611+ if((status & 8) && exitline == -1) {
612+ exitline = cy;
613+// goto underrun;
614+ }
615+ }
616+ } else {
617+ // transparent
618+ if(mode & 1) {
619+ memset(attrib.expand, 0x70, sizeof(attrib.expand));
620+ } else {
621+ for(int cy = 0, ytop = 0, ofs = 0; cy < height && ytop < 200; cy++, ytop += char_height_tmp, ofs += 80 + attrib.num * 2) {
622+ uint8_t flags[128];
623+ memset(flags, 0, sizeof(flags));
624+ for(int i = 2 * (attrib.num - 1); i >= 0; i -= 2) {
625+ flags[read_buffer(ofs + i + 80) & 0x7f] = 1;
626+ }
627+ attrib.data &= 0xf3; // for PC-8801mkIIFR 付属デモ
628+
629+ for(int cx = 0, pos = 0; cx < width; cx++) {
630+ if(flags[cx]) {
631+ set_attrib(read_buffer(ofs + pos + 81));
632+ pos += 2;
633+ }
634+ attrib.expand[cy][cx] = attrib.data;
635+ }
636+ if((status & 8) && exitline == -1) {
637+ exitline = cy;
638+// goto underrun;
639+ }
640+ }
641+ }
642+ }
643+ if(cursor.x < 80 && cursor.y < 200) {
644+ if((cursor.type & 1) && blink.cursor) {
645+ // no cursor
646+ } else {
647+ static const uint8_t ctype[5] = {0, 8, 8, 1, 1};
648+ attrib.expand[cursor.y][cursor.x] ^= ctype[cursor.type + 1];
649+ }
650+ }
651+ // only burst mode
652+underrun:
653+ if(exitline != -1) {
654+ for(int cy = exitline; cy < 200; cy++) {
655+ memset(&text.expand[cy][0], 0, width);
656+ memset(&attrib.expand[cy][0], 0x70, width); // color=7
657+ }
658+ }
659+}
660+
661+void crtc_t::set_attrib(uint8_t code)
662+{
663+ if(mode & 2) {
664+ // color
665+ if(code & 8) {
666+ attrib.data = (attrib.data & 0x0f) | (code & 0xf0);
667+ } else {
668+ attrib.data = (attrib.data & 0xf0) | ((code >> 2) & 0x0d) | ((code << 1) & 2);
669+ attrib.data ^= reverse;
670+ attrib.data ^= ((code & 2) && !(code & 1)) ? blink.attrib : 0;
671+ }
672+ } else {
673+ attrib.data = 0x70 | (code & 0x80) | ((code >> 2) & 0x0d) | ((code << 1) & 2);
674+ attrib.data ^= reverse;
675+ attrib.data ^= ((code & 2) && !(code & 1)) ? blink.attrib : 0;
676+ }
677+}
678+
679+/* ----------------------------------------------------------------------------
680+ DMAC (uPD8257)
681+---------------------------------------------------------------------------- */
682+
683+void dmac_t::write_io8(uint32_t addr, uint32_t data)
684+{
685+ int c = (addr >> 1) & 3;
686+
687+ switch(addr & 0x0f) {
688+ case 0:
689+ case 2:
690+ case 4:
691+ case 6:
692+ if(!high_low) {
693+ if((mode & 0x80) && c == 2) {
694+ ch[3].addr.b.l = data;
695+ }
696+ ch[c].addr.b.l = data;
697+ } else {
698+ if((mode & 0x80) && c == 2) {
699+ ch[3].addr.b.h = data;
700+ }
701+ ch[c].addr.b.h = data;
702+ }
703+ high_low = !high_low;
704+ break;
705+ case 1:
706+ case 3:
707+ case 5:
708+ case 7:
709+ if(!high_low) {
710+ if((mode & 0x80) && c == 2) {
711+ ch[3].count.b.l = data;
712+ }
713+ ch[c].count.b.l = data;
714+ } else {
715+ if((mode & 0x80) && c == 2) {
716+ ch[3].count.b.h = data & 0x3f;
717+ ch[3].mode = data & 0xc0;
718+ }
719+ ch[c].count.b.h = data & 0x3f;
720+ ch[c].mode = data & 0xc0;
721+ }
722+ high_low = !high_low;
723+ break;
724+ case 8:
725+ mode = data;
726+ high_low = false;
727+ break;
728+ }
729+}
730+
731+uint32_t dmac_t::read_io8(uint32_t addr)
732+{
733+ uint32_t val = 0xff;
734+ int c = (addr >> 1) & 3;
735+
736+ switch(addr & 0x0f) {
737+ case 0:
738+ case 2:
739+ case 4:
740+ case 6:
741+ if(!high_low) {
742+ val = ch[c].addr.b.l;
743+ } else {
744+ val = ch[c].addr.b.h;
745+ }
746+ high_low = !high_low;
747+ break;
748+ case 1:
749+ case 3:
750+ case 5:
751+ case 7:
752+ if(!high_low) {
753+ val = ch[c].count.b.l;
754+ } else {
755+ val = (ch[c].count.b.h & 0x3f) | ch[c].mode;
756+ }
757+ high_low = !high_low;
758+ break;
759+ case 8:
760+ val = status;
761+ status &= 0xf0;
762+// high_low = false;
763+ break;
764+ }
765+ return val;
766+}
767+
768+void dmac_t::start(int c)
769+{
770+ if(mode & (1 << c)) {
771+ status &= ~(1 << c);
772+ ch[c].running = true;
773+ } else {
774+ ch[c].running = false;
775+ }
776+}
777+
778+void dmac_t::finish(int c)
779+{
780+ if(ch[c].running) {
781+ while(ch[c].count.sd >= 0) {
782+ run(c);
783+ }
784+ }
785+}
786+
787+void dmac_t::run(int c)
788+{
789+ if(ch[c].running) {
790+ if(ch[c].count.sd >= 0) {
791+ if(ch[c].mode == 0x80) {
792+ ch[c].io->write_dma_io8(0, mem->read_dma_data8(ch[c].addr.w.l));
793+ } else if(ch[c].mode == 0x40) {
794+ mem->write_dma_data8(ch[c].addr.w.l, ch[c].io->read_dma_io8(0));
795+ }
796+ ch[c].addr.sd++;
797+ ch[c].count.sd--;
798+ }
799+ if(ch[c].count.sd < 0) {
800+ if((mode & 0x80) && c == 2) {
801+ ch[2].addr.sd = ch[3].addr.sd;
802+ ch[2].count.sd = ch[3].count.sd;
803+ ch[2].mode = ch[3].mode;
804+ } else if(mode & 0x40) {
805+ mode &= ~(1 << c);
806+ }
807+ status |= (1 << c);
808+ ch[c].running = false;
809+ }
810+ }
811+}
812+
813+#define STATE_VERSION 1
814+
815+void DISPLAY::save_state(FILEIO* state_fio)
816+{
817+ state_fio->FputUint32(STATE_VERSION);
818+ state_fio->FputInt32(this_device_id);
819+
820+ state_fio->Fwrite(font, sizeof(font), 1);
821+ state_fio->Fwrite(vram, sizeof(vram), 1);
822+ state_fio->FputInt32(busreq_clocks);
823+ state_fio->FputBool(color);
824+ state_fio->FputBool(width40);
825+ state_fio->FputUint8(mode);
826+ state_fio->Fwrite(&crtc, sizeof(crtc), 1);
827+ state_fio->Fwrite(&dmac, sizeof(dmac), 1);
828+}
829+
830+bool DISPLAY::load_state(FILEIO* state_fio)
831+{
832+ if(state_fio->FgetUint32() != STATE_VERSION) {
833+ return false;
834+ }
835+ if(state_fio->FgetInt32() != this_device_id) {
836+ return false;
837+ }
838+ state_fio->Fread(font, sizeof(font), 1);
839+ state_fio->Fread(vram, sizeof(vram), 1);
840+ busreq_clocks = state_fio->FgetInt32();
841+ color = state_fio->FgetBool();
842+ width40 = state_fio->FgetBool();
843+ mode = state_fio->FgetUint8();
844+ state_fio->Fread(&crtc, sizeof(crtc), 1);
845+ STORE_DMAC_CONTEXTS();
846+ state_fio->Fread(&dmac, sizeof(dmac), 1);
847+ RESTORE_DMAC_CONTEXTS();
848+ return true;
849+}
--- /dev/null
+++ b/source/src/vm/bubcom80/display.h
@@ -0,0 +1,170 @@
1+/*
2+ Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3+
4+ Author : Takeda.Toshiya
5+ Date : 2018.05.08-
6+
7+ [ display ]
8+*/
9+
10+#ifndef _DISPLAY_H_
11+#define _DISPLAY_H_
12+
13+#include "../vm.h"
14+#include "../../emu.h"
15+#include "../device.h"
16+
17+#define SIG_DISPLAY_DMAC_CH0 0
18+#define SIG_DISPLAY_DMAC_CH1 1
19+#define SIG_DISPLAY_DMAC_CH2 2
20+#define SIG_DISPLAY_DMAC_CH3 3
21+
22+class Z80;
23+
24+typedef struct {
25+ struct {
26+ int rate, counter;
27+ uint8_t cursor, attrib;
28+ } blink;
29+ struct {
30+ int type, mode;
31+ int x, y;
32+ } cursor;
33+ struct {
34+ uint8_t data;
35+ int num;
36+ uint8_t expand[200][80];
37+ } attrib;
38+ struct {
39+ uint8_t expand[200][80];
40+ } text;
41+ int width, height;
42+ int char_height;
43+ bool skip_line;
44+ int vretrace;
45+ bool timing_changed;
46+ uint8_t buffer[120 * 200];
47+ int buffer_ptr;
48+ uint8_t cmd;
49+ int cmd_ptr;
50+ uint8_t mode, reverse, intr_mask, status;
51+ bool vblank;
52+
53+ void reset();
54+ void write_cmd(uint8_t data);
55+ void write_param(uint8_t data);
56+ uint32_t read_param();
57+ uint32_t read_status();
58+ void start();
59+ void finish();
60+ void write_buffer(uint8_t data);
61+ uint8_t read_buffer(int ofs);
62+ void update_blink();
63+ void expand_buffer();
64+ void set_attrib(uint8_t code);
65+} crtc_t;
66+
67+typedef struct {
68+ struct {
69+ pair_t addr, count;
70+ uint8_t mode;
71+ int nbytes;
72+ DEVICE *io;
73+ bool running;
74+ } ch[4];
75+ uint8_t mode, status;
76+ bool high_low;
77+ DEVICE *mem;
78+
79+ void write_io8(uint32_t addr, uint32_t data);
80+ uint32_t read_io8(uint32_t addr);
81+ void start(int c);
82+ void finish(int c);
83+ void run(int c);
84+} dmac_t;
85+
86+class DISPLAY : public DEVICE
87+{
88+private:
89+ Z80 *d_cpu;
90+ DEVICE *d_cmt, *d_pcm, *d_prn;
91+
92+ uint8_t sg_pattern[0x800];
93+ uint8_t font[0x800];
94+ uint8_t vram[0x10000];
95+
96+ int busreq_clocks;
97+ bool color;
98+ bool width40;
99+ uint8_t mode;
100+
101+ crtc_t crtc;
102+ dmac_t dmac;
103+
104+ scrntype_t palette_text_pc[8];
105+ scrntype_t palette_graph_pc[8];
106+ uint8_t text[200][640];
107+ uint8_t graph[200][640];
108+
109+ void update_timing();
110+ void draw_text();
111+ void draw_graph();
112+
113+public:
114+ DISPLAY(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
115+ {
116+ for(int i = 0; i < 4; i++) {
117+ dmac.ch[i].io = parent_vm->dummy;
118+ }
119+ dmac.mem = parent_vm->dummy;
120+
121+ set_device_name(_T("Display"));
122+ }
123+ ~DISPLAY() {}
124+
125+ // common functions
126+ void initialize();
127+ void reset();
128+ void write_io8(uint32_t addr, uint32_t data);
129+ uint32_t read_io8(uint32_t addr);
130+ void write_dma_io8(uint32_t addr, uint32_t data);
131+ void write_signal(int id, uint32_t data, uint32_t mask);
132+ void event_callback(int event_id, int err);
133+ void event_frame();
134+ void event_vline(int v, int clock);
135+ void save_state(FILEIO* state_fio);
136+ bool load_state(FILEIO* state_fio);
137+
138+ // unique functions
139+ void set_context_cpu(Z80* device)
140+ {
141+ d_cpu = device;
142+ }
143+ void set_context_cmt(DEVICE* device)
144+ {
145+ d_cmt = device;
146+ }
147+ void set_context_pcm(DEVICE* device)
148+ {
149+ d_pcm = device;
150+ }
151+ void set_context_prn(DEVICE* device)
152+ {
153+ d_prn = device;
154+ }
155+ void set_context_dmac_mem(DEVICE* device)
156+ {
157+ dmac.mem = device;
158+ }
159+ void set_context_dmac_ch0(DEVICE* device)
160+ {
161+ dmac.ch[0].io = device;
162+ }
163+ void set_context_dmac_ch2(DEVICE* device)
164+ {
165+ dmac.ch[2].io = device;
166+ }
167+ void draw_screen();
168+};
169+
170+#endif
--- /dev/null
+++ b/source/src/vm/bubcom80/floppy.cpp
@@ -0,0 +1,25 @@
1+/*
2+ Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3+
4+ Author : Takeda.Toshiya
5+ Date : 2018.05.09-
6+
7+ [ floppy ]
8+*/
9+
10+#include "floppy.h"
11+#include "../mb8877.h"
12+
13+void FLOPPY::write_io8(uint32_t addr, uint32_t data)
14+{
15+ switch(addr) {
16+ case 0x3fd8:
17+// if((data & 0x0c) == 0x0c) {
18+ d_fdc->write_signal(SIG_MB8877_DRIVEREG, data, 0x03);
19+ d_fdc->write_signal(SIG_MB8877_SIDEREG, data, 0x40);
20+ // bit7: set when track > 59
21+// }
22+ break;
23+ }
24+}
25+
--- /dev/null
+++ b/source/src/vm/bubcom80/floppy.h
@@ -0,0 +1,40 @@
1+/*
2+ Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3+
4+ Author : Takeda.Toshiya
5+ Date : 2018.05.09-
6+
7+ [ floppy ]
8+*/
9+
10+#ifndef _FLOPPY_H_
11+#define _FLOPPY_H_
12+
13+#include "../vm.h"
14+#include "../../emu.h"
15+#include "../device.h"
16+
17+class FLOPPY : public DEVICE
18+{
19+private:
20+ DEVICE* d_fdc;
21+
22+public:
23+ FLOPPY(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
24+ {
25+ set_device_name(_T("Floppy I/F"));
26+ }
27+ ~FLOPPY() {}
28+
29+ // common function
30+ void write_io8(uint32_t addr, uint32_t data);
31+
32+ // unique function
33+ void set_context_fdc(DEVICE* device)
34+ {
35+ d_fdc = device;
36+ }
37+};
38+
39+#endif
40+
--- /dev/null
+++ b/source/src/vm/bubcom80/keyboard.cpp
@@ -0,0 +1,84 @@
1+/*
2+ Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3+
4+ Author : Takeda.Toshiya
5+ Date : 2018.05.08-
6+
7+ [ keyboard ]
8+*/
9+
10+#include "keyboard.h"
11+
12+static const uint8_t key_matrix[128] = {
13+/*
14+// keyboard
15+00: 2 3 4 5 6 7 8 9 0 - ^ \ NUM * NUM / NUM + NUM -
16+10: W E R T Y U I O P @ [ RETURN NUM 7 NUM 8 NUM 9 NUM ,
17+20: S D F G H J K L ; : ] A NUM 4 NUM 5 NUM 6 NUM .
18+30: X C V B N M , . / _ Z NUM 1 NUM 2 NUM 3
19+40: 1 Q TAB ESC SPACE GRAPH CTRL KANA SHIFT BACK CAP NUM 0 NUM 000 NUM RETURN
20+50: F1 F2 F3 F4 CLS EDIT LIST RUN LEFT DOWN RIGHT
21+60: F5 F6 F7 F8 LABEL FILES INIT STOP INS UP DEL
22+// joystick #1/#2
23+70: TRIG UP DOWN LEFT RIGHT TRIG UP DOWN LEFT RIGHT
24+
25+GRAPH Alt
26+CLS Home
27+EDIT End
28+LIST PgUp
29+RUN PgDn
30+LABEL F9
31+FILES F10
32+INIT F11
33+STOP F12
34+*/
35+ 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0xBD, 0xDE, 0xDC, 0x6A, 0x6F, 0x6B, 0x6D,
36+ 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4F, 0x50, 0xC0, 0xDB, 0x0D, 0x67, 0x68, 0x69, 0x6C,
37+ 0x53, 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0xBB, 0xBA, 0xDD, 0x41, 0x64, 0x65, 0x66, 0x6E,
38+ 0x58, 0x43, 0x56, 0x42, 0x4E, 0x4D, 0xBC, 0xBE, 0xBF, 0xE2, 0x00, 0x5A, 0x61, 0x62, 0x63, 0x00,
39+ 0x31, 0x51, 0x09, 0x1B, 0x00, 0x00, 0x20, 0x12, 0x11, 0x15, 0x10, 0x08, 0x14, 0x60, 0x00, 0x00,
40+ 0x70, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00, 0x24, 0x23, 0x21, 0x22, 0x00, 0x00, 0x25, 0x28, 0x27,
41+ 0x74, 0x75, 0x76, 0x77, 0x00, 0x00, 0x00, 0x78, 0x79, 0x7A, 0x7B, 0x00, 0x00, 0x2D, 0x26, 0x2E,
42+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43+};
44+
45+static const uint32_t joy_bits[5] = {
46+ 0xf0, 0x01, 0x02, 0x04, 0x08, // TRIG, UP, DOWN, LEFT, RIGHT
47+};
48+
49+void KEYBOARD::initialize()
50+{
51+ key_stat = emu->get_key_buffer();
52+ joy_stat = emu->get_joy_buffer();
53+}
54+
55+uint32_t KEYBOARD::read_io8(uint32_t addr)
56+{
57+ switch(addr & 0x7f) {
58+ case 0x70:
59+ case 0x71:
60+ case 0x72:
61+ case 0x73:
62+ case 0x74:
63+ if(joy_stat[0] & joy_bits[addr - 0x70]) {
64+ return 0xff;
65+ }
66+ break;
67+ case 0x75:
68+ case 0x76:
69+ case 0x77:
70+ case 0x78:
71+ case 0x79:
72+ if(joy_stat[1] & joy_bits[addr - 0x75]) {
73+ return 0xff;
74+ }
75+ break;
76+ default:
77+ if(key_stat[key_matrix[addr & 0x7f]]) {
78+ return 0xff;
79+ }
80+ break;
81+ }
82+ return 0x0f;
83+}
84+
--- /dev/null
+++ b/source/src/vm/bubcom80/keyboard.h
@@ -0,0 +1,35 @@
1+/*
2+ Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3+
4+ Author : Takeda.Toshiya
5+ Date : 2018.05.08-
6+
7+ [ keyboard ]
8+*/
9+
10+#ifndef _KEYBOARD_H_
11+#define _KEYBOARD_H_
12+
13+#include "../vm.h"
14+#include "../../emu.h"
15+#include "../device.h"
16+
17+class KEYBOARD : public DEVICE
18+{
19+private:
20+ const uint8_t* key_stat;
21+ const uint32_t* joy_stat;
22+
23+public:
24+ KEYBOARD(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
25+ {
26+ set_device_name(_T("Keyboard"));
27+ }
28+ ~KEYBOARD() {}
29+
30+ // common functions
31+ void initialize();
32+ uint32_t read_io8(uint32_t addr);
33+};
34+
35+#endif
--- /dev/null
+++ b/source/src/vm/bubcom80/membus.cpp
@@ -0,0 +1,111 @@
1+/*
2+ Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3+
4+ Author : Takeda.Toshiya
5+ Date : 2018.05.08-
6+
7+ [ memory bus ]
8+*/
9+
10+#include "membus.h"
11+
12+void MEMBUS::initialize()
13+{
14+ MEMORY::initialize();
15+
16+ memset(ram, 0x00, sizeof(ram));
17+ memset(boot, 0xff, sizeof(boot));
18+ memset(basic, 0xff, sizeof(basic));
19+
20+ if(!read_bios(_T("IPL.ROM"), boot, sizeof(boot))) {
21+ read_bios(_T("BOOT.ROM"), boot, sizeof(boot));
22+ }
23+ read_bios(_T("BASIC.ROM"), basic, sizeof(basic));
24+
25+ set_memory_rw(0x0000, 0xffff, ram);
26+}
27+
28+void MEMBUS::reset()
29+{
30+ MEMORY::reset();
31+
32+ basic_addr.d = 0;
33+ ram_selected = false;
34+ update_bank();
35+}
36+
37+void MEMBUS::write_io8(uint32_t addr, uint32_t data)
38+{
39+ switch(addr) {
40+ case 0x0c:
41+ basic_addr.b.l = data;
42+ break;
43+ case 0x0d:
44+ basic_addr.b.h = data;
45+ break;
46+ case 0x0e:
47+ // error code ???
48+ break;
49+ case 0x80:
50+ ram_selected = ((data & 0x80) != 0);
51+ update_bank();
52+ break;
53+ }
54+}
55+
56+uint32_t MEMBUS::read_io8(uint32_t addr)
57+{
58+ switch(addr) {
59+ case 0x0c:
60+ return basic[basic_addr.w.l];
61+ }
62+ return 0xff;
63+}
64+
65+void MEMBUS::write_dma_data8(uint32_t addr, uint32_t data)
66+{
67+ ram[addr & 0xffff] = data;
68+}
69+
70+uint32_t MEMBUS::read_dma_data8(uint32_t addr)
71+{
72+ return ram[addr & 0xffff];
73+}
74+
75+void MEMBUS::update_bank()
76+{
77+ set_memory_r(0x0000, 0x07ff, ram_selected ? ram : boot);
78+}
79+
80+#define STATE_VERSION 1
81+
82+void MEMBUS::save_state(FILEIO* state_fio)
83+{
84+ state_fio->FputUint32(STATE_VERSION);
85+ state_fio->FputInt32(this_device_id);
86+
87+ MEMORY::save_state(state_fio);
88+ state_fio->Fwrite(ram, sizeof(ram), 1);
89+ state_fio->FputUint32(basic_addr.d);
90+ state_fio->FputBool(ram_selected);
91+}
92+
93+bool MEMBUS::load_state(FILEIO* state_fio)
94+{
95+ if(state_fio->FgetUint32() != STATE_VERSION) {
96+ return false;
97+ }
98+ if(state_fio->FgetInt32() != this_device_id) {
99+ return false;
100+ }
101+ if(!MEMORY::load_state(state_fio)) {
102+ return false;
103+ }
104+ state_fio->Fread(ram, sizeof(ram), 1);
105+ basic_addr.d = state_fio->FgetUint32();
106+ ram_selected = state_fio->FgetBool();
107+
108+ // post process
109+ update_bank();
110+ return true;
111+}
--- /dev/null
+++ b/source/src/vm/bubcom80/membus.h
@@ -0,0 +1,46 @@
1+/*
2+ Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3+
4+ Author : Takeda.Toshiya
5+ Date : 2018.05.08-
6+
7+ [ memory bus ]
8+*/
9+
10+#ifndef _MEMBUS_H_
11+#define _MEMBUS_H_
12+
13+#include "../memory.h"
14+
15+class MEMBUS : public MEMORY
16+{
17+private:
18+
19+ uint8_t boot[0x800];
20+ uint8_t basic[0x10000];
21+ uint8_t ram[0x10000];
22+
23+ pair_t basic_addr;
24+ bool ram_selected;
25+
26+ void update_bank();
27+
28+public:
29+ MEMBUS(VM* parent_vm, EMU* parent_emu) : MEMORY(parent_vm, parent_emu)
30+ {
31+ set_device_name(_T("Memory Bus"));
32+ }
33+ ~MEMBUS() {}
34+
35+ // common functions
36+ void initialize();
37+ void reset();
38+ void write_io8(uint32_t addr, uint32_t data);
39+ uint32_t read_io8(uint32_t addr);
40+ void write_dma_data8(uint32_t addr, uint32_t data);
41+ uint32_t read_dma_data8(uint32_t addr);
42+ void save_state(FILEIO* state_fio);
43+ bool load_state(FILEIO* state_fio);
44+};
45+
46+#endif
--- /dev/null
+++ b/source/src/vm/bubcom80/rtc.cpp
@@ -0,0 +1,176 @@
1+/*
2+ Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3+
4+ Author : Takeda.Toshiya
5+ Date : 2018.05.11-
6+
7+ [ rtc ]
8+*/
9+
10+#include "rtc.h"
11+
12+#define EVENT_1HZ 0
13+
14+void RTC::initialize()
15+{
16+ get_host_time(&cur_time);
17+
18+ register_event_by_clock(this, EVENT_1HZ, CPU_CLOCKS, true, NULL);
19+}
20+
21+void RTC::reset()
22+{
23+ tmp_time = cur_time; // ???
24+ ctrl = 0;
25+}
26+
27+#define SET_DECIMAL_HI(t, v) \
28+ t %= 10; \
29+ t += (v) * 10
30+#define SET_DECIMAL_LO(t, v) \
31+ t /= 10; \
32+ t *= 10; \
33+ t += (v)
34+#define GET_DECIMAL_HI(t) TO_BCD_HI(t)
35+#define GET_DECIMAL_LO(t) TO_BCD_LO(t)
36+
37+void RTC::write_io8(uint32_t addr, uint32_t data)
38+{
39+ switch(addr) {
40+ case 0x3fed:
41+ if(ctrl == 0x80 && data != 0x80) {
42+ cur_time = tmp_time;
43+ cur_time.initialized = true;
44+ }
45+ if(data == 0xc0) {
46+ tmp_time = cur_time;
47+ }
48+ ctrl = data;
49+ break;
50+ case 0x3fec:
51+ SET_DECIMAL_HI(tmp_time.year, data & 0x0f);
52+ tmp_time.update_year();
53+ tmp_time.update_day_of_week();
54+ break;
55+ case 0x3feb:
56+ SET_DECIMAL_LO(tmp_time.year, data & 0x0f);
57+ tmp_time.update_day_of_week();
58+ break;
59+ case 0x3fea:
60+ SET_DECIMAL_HI(tmp_time.month, data & 0x01);
61+ tmp_time.update_day_of_week();
62+ break;
63+ case 0x3fe9:
64+ SET_DECIMAL_LO(tmp_time.month, data & 0x0f);
65+ tmp_time.update_day_of_week();
66+ break;
67+ case 0x3fe8:
68+ SET_DECIMAL_HI(tmp_time.day, data & 0x03);
69+ tmp_time.update_day_of_week();
70+ break;
71+ case 0x3fe7:
72+ SET_DECIMAL_LO(tmp_time.day, data & 0x0f);
73+ tmp_time.update_day_of_week();
74+ break;
75+ case 0x3fe6:
76+// tmp_time.day_of_week = data & 0x07;
77+ break;
78+ case 0x3fe5:
79+ SET_DECIMAL_HI(tmp_time.hour, data & 0x03);
80+ break;
81+ case 0x3fe4:
82+ SET_DECIMAL_LO(tmp_time.hour, data & 0x0f);
83+ break;
84+ case 0x3fe3:
85+ SET_DECIMAL_HI(tmp_time.minute, data & 0x07);
86+ break;
87+ case 0x3fe2:
88+ SET_DECIMAL_LO(tmp_time.minute, data & 0x0f);
89+ break;
90+ case 0x3fe1:
91+ SET_DECIMAL_HI(tmp_time.second, data & 0x07);
92+ break;
93+ case 0x3fe0:
94+ SET_DECIMAL_LO(tmp_time.second, data & 0x0f);
95+ break;
96+ }
97+}
98+
99+uint32_t RTC::read_io8(uint32_t addr)
100+{
101+ switch(addr) {
102+ case 0x3fed:
103+ return ctrl;
104+ case 0x3fec:
105+ return GET_DECIMAL_HI(tmp_time.year);
106+ case 0x3feb:
107+ return GET_DECIMAL_LO(tmp_time.year);
108+ case 0x3fea:
109+ return GET_DECIMAL_HI(tmp_time.month);
110+ case 0x3fe9:
111+ return GET_DECIMAL_LO(tmp_time.month);
112+ case 0x3fe8:
113+ return GET_DECIMAL_HI(tmp_time.day);
114+ case 0x3fe7:
115+ return GET_DECIMAL_LO(tmp_time.day);
116+ case 0x3fe6:
117+ return tmp_time.day_of_week;
118+ case 0x3fe5:
119+ return GET_DECIMAL_HI(tmp_time.hour);
120+ case 0x3fe4:
121+ return GET_DECIMAL_LO(tmp_time.hour);
122+ case 0x3fe3:
123+ return GET_DECIMAL_HI(tmp_time.minute);
124+ case 0x3fe2:
125+ return GET_DECIMAL_LO(tmp_time.minute);
126+ case 0x3fe1:
127+ return GET_DECIMAL_HI(tmp_time.second);
128+ case 0x3fe0:
129+ return GET_DECIMAL_LO(tmp_time.second);
130+ }
131+ return 0xff;
132+}
133+
134+void RTC::event_callback(int event_id, int err)
135+{
136+ if(event_id == EVENT_1HZ) {
137+ // update calendar
138+ if(cur_time.initialized) {
139+ cur_time.increment();
140+ } else {
141+ get_host_time(&cur_time); // resync
142+ cur_time.initialized = true;
143+ }
144+ }
145+}
146+
147+#define STATE_VERSION 1
148+
149+void RTC::save_state(FILEIO* state_fio)
150+{
151+ state_fio->FputUint32(STATE_VERSION);
152+ state_fio->FputInt32(this_device_id);
153+
154+ cur_time.save_state((void *)state_fio);
155+ tmp_time.save_state((void *)state_fio);
156+ state_fio->FputUint8(ctrl);
157+}
158+
159+bool RTC::load_state(FILEIO* state_fio)
160+{
161+ if(state_fio->FgetUint32() != STATE_VERSION) {
162+ return false;
163+ }
164+ if(state_fio->FgetInt32() != this_device_id) {
165+ return false;
166+ }
167+ if(!cur_time.load_state((void *)state_fio)) {
168+ return false;
169+ }
170+ if(!tmp_time.load_state((void *)state_fio)) {
171+ return false;
172+ }
173+ ctrl = state_fio->FgetUint8();
174+ return true;
175+}
176+
--- /dev/null
+++ b/source/src/vm/bubcom80/rtc.h
@@ -0,0 +1,42 @@
1+/*
2+ Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3+
4+ Author : Takeda.Toshiya
5+ Date : 2018.05.11-
6+
7+ [ rtc ]
8+*/
9+
10+#ifndef _RTC_H_
11+#define _RTC_H_
12+
13+#include "../vm.h"
14+#include "../../emu.h"
15+#include "../device.h"
16+
17+class RTC : public DEVICE
18+{
19+private:
20+ dll_cur_time_t cur_time;
21+ dll_cur_time_t tmp_time;
22+ uint8_t ctrl;
23+
24+public:
25+ RTC(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
26+ {
27+ set_device_name(_T("RTC"));
28+ }
29+ ~RTC() {}
30+
31+ // common functions
32+ void initialize();
33+ void reset();
34+ void write_io8(uint32_t addr, uint32_t data);
35+ uint32_t read_io8(uint32_t addr);
36+ void event_callback(int event_id, int err);
37+ void save_state(FILEIO* state_fio);
38+ bool load_state(FILEIO* state_fio);
39+};
40+
41+#endif
42+
--- /dev/null
+++ b/source/src/vm/common_vm/shared_headers.cmake
@@ -0,0 +1,32 @@
1+## From:
2+##https://qiita.com/mrk_21/items/264f6135679239ff018a#cotire-で生成したプリコンパイル済みヘッダーを複数のバイナリターゲットで使いまわす
3+# HACK: shared precompiled header
4+# use_shared_pch(target origin [origin_source_dir])
5+function(use_shared_pch target origin)
6+ # origin source directory
7+ set(origin_source_dir ${ARGV2})
8+ if(NOT DEFINED origin_source_dir)
9+ set(origin_source_dir ${CMAKE_CURRENT_SOURCE_DIR})
10+ endif()
11+
12+ # origin prefix header
13+ get_target_property(origin_prefix_header ${origin} COTIRE_CXX_PREFIX_HEADER)
14+ if(NOT origin_prefix_header)
15+ return()
16+ endif()
17+
18+ # make target pch flags
19+ cotire_make_pch_file_path(CXX ${origin_source_dir} ${origin} origin_pch_file)
20+ cotire_add_prefix_pch_inclusion_flags(
21+ CXX ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}
22+ ${origin_prefix_header} ${origin_pch_file}
23+ target_pch_flags
24+ )
25+ set_property(TARGET ${target} APPEND_STRING PROPERTY COMPILE_FLAGS ${target_pch_flags})
26+endfunction()
27+
28+foreach(i RANGE 9)
29+ add_executable(bin_alias${i} main.cpp)
30+ target_link_libraries(bin_alias${i} ${Boost_LIBRARIES})
31+ use_shared_pch(bin_alias${i})
32+endforeach()
--- a/source/src/vm/fmtowns/fmtowns.h
+++ b/source/src/vm/fmtowns/fmtowns.h
@@ -77,10 +77,7 @@
7777
7878 // device informations for win32
7979 #define USE_CPU_TYPE 2
80-#define USE_FD1
81-#define USE_FD2
82-#define USE_FD3
83-#define USE_FD4
80+#define USE_FLOPPY_DISK 4 // ??
8481 #define NOTIFY_KEY_DOWN
8582 #define USE_SHIFT_NUMPAD_KEY
8683 #define USE_ALT_F10_KEY
Show on old repository browser