2 * FM-7 Main I/O [fm7_mainio.h]
4 * Author: K.Ohta <whatisthis.sowhat _at_ gmail.com>
7 * Jan 03, 2015 : Initial
12 #include "fm7_mainio.h"
14 #define EVENT_UPDATE_T77 3
16 int FM7_CMT::load_t77_image(void)
23 memset(tmpbuf, 0x00, 17);
24 play_fio->Fseek(0, FILEIO_SEEK_END);
25 buffer_length = drec->play_fio->Ftell();
26 if(buffer_length < 18) goto _error_2;
28 play_fio->Fseek(0, FILEIO_SEEK_SET);
29 play_fio->Fread(tmpbuf, 16, 1);
31 if(strcmp(tmpbuf, "XM7 TAPE IMAGE 0") != 0) goto _error_2;
33 buffer_length = buffer_length - 16;
36 buffer = (uint8 *)malloc(buffer_length);
37 if(buffer == NULL) goto _error_2;
39 play_fio->Fread(buffer, buffer_length, 1);
46 for(tptr = 0; tptr < buffer_length; tptr += 2) {
48 lo = buffer[tptr + 1];
49 val = (hi * 256 + lo) & 0x7fff;
57 int FM7_CMT::get_tape_ptr(void)
60 if((buffer_length == 0) || (buffer == NULL)) return -1;
61 return (100 * buffer_ptr) / buffer_length;
63 if(total_count == 0) return -1;
64 return ((total_count * 100) / total_length);
68 void FM7_CMT::event_callback(int event_id, int err)
70 if(event_id == EVENT_UPDATE_T77) {
74 drec->event_callback(event_id, err);
78 void FM7_CMT::parse_t77(void)
88 if(buffer_length <= buffer_ptr) {
91 hi = buffer[buffer_ptr++];
92 lo = buffer[buffer_ptr++];
93 rawdata = hi * 256 + lo;
94 total_count += (rawdata & 0x7fff);
95 } while((rawdata & 0x7fff) != 0x0000);
97 if((rawdata & 0x8000) == 0) {
99 this->write_signal(SIG_DATAREC_OUT, 0x00, 0x01);
102 this->write_signal(SIG_DATAREC_OUT, 0x01, 0x01);
104 usec = (double)(rawdata & 0x7fff);
106 register_event(this, EVENT_UPDATE_T77, usec, false, NULL); // NEXT CYCLE
111 void FM7_MAINIO::set_port_fd00(uint8 data)
113 cmt->write_data8(0x00, data);
116 FM7_MAINIO::FM7_MAINIO(VM *parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
120 keyboard = new FM7_KEYBOARD;
123 void FM7_MAINIO::set_clockmode(uint8 flags)
125 if(flags == FM7_MAINCLOCK_SLOW) {
132 uint8 FM7_MAINIO::get_clockmode(void)
134 if(clock_fast) return FM7_MAINCLOCK_SLOW;
135 return FM7_MAINCLOCK_HIGH;
139 uint8 FM7_MAINIO::get_port_fd00(void)
142 if(kbd_bit8) ret |= 0x80;
143 if(clock_fast) ret |= 0x01;
147 void FM7_MAINIO::set_port_fd00(uint8 data)
149 if(cmt != NULL) cmt->write_data8(0x00, data);
152 uint8 FM7_MAINIO::get_port_fd02(void)
155 // Still unimplemented printer.
156 ret |= cmt->read_data8(0x02); // CMT
160 void FM7_MAINIO::set_port_fd02(uint8 val)
163 if((val & 0b00010000) != 0) {
168 if((val & 0b00000100) != 0) {
169 irqmask_timer = false;
171 irqmask_timer = true;
173 if((val & 0b00000010) != 0) {
174 irqmask_printer = false;
176 irqmask_printer = true;
178 if((val & 0b00000001) != 0) {
179 irqmask_keyboard = false;
181 irqmask_keyboard = true;
187 uint32 FM7_MAINIO::get_keyboard(void)
189 uint32 kbd_data = (uint32) kbd_bit7_0;
191 if(kbd_bit8) kbd_data |= 0x0100;
195 void FM7_MAINIO::do_irq(bool flag)
198 maincpu->write_signal(SIG_CPU_IRQ, 1, 1);
200 maincpu->write_signal(SIG_CPU_IRQ, 0, 1);
205 void FM7_MAINIO::set_beep(uint32 data) // fd03
207 beep->write_signal(SIG_BEEP_ON, data, 0b11000000);
208 beep->write_signal(SIG_BEEP_MUTE, data , 0b00000001);
209 if((data & 0x40) != 0) {
210 // beep->write_signal(SIG_BEEP_ON, 0b01000000, 0b01000000);
211 // BEEP ON, after 200ms, BEEP OFF.
212 register_event(this, EVENT_BEEP_OFF, 200.0 * 1000.0, false, NULL); // NEXT CYCLE
216 void FM7_MAINIO::set_irq_timer(bool flag)
218 if(flag && !irqmask_timer) {
219 irqstat_reg0 &= 0b11111011;
225 irqstat_reg0 |= 0b00000100;
230 void FM7_MAINIO::set_irq_printer(bool flag)
232 if(flag && !irqmask_printer) {
233 irqstat_reg0 &= 0b11111101;
238 irqstat_reg0 |= 0b00000010;
243 void FM7_MAINIO::set_irq_keyboard(bool flag)
245 if(flag && !irqmask_keyboard) {
246 irqstat_reg0 &= 0b11111110;
251 irqstat_reg0 |= 0b00000001;
256 void FM7_MAINIO::set_irq_mfd(bool flag)
259 if(flag && !irqmask_mfd && fdc_connected) {
260 irqstat_fdc |= 0b01000000;
264 if((flag == false) && fdc_connected){
265 irqstat_fdc &= 0b10111111;
271 void FM7_MAINIO::set_keyboard(uint32 data)
273 if((data & 0x100) != 0){
278 kbd_bit7_0 = (data & 0xff);
281 void FM7_MAINIO::do_firq(bool flag)
284 maincpu->write_signal(SIG_CPU_FIRQ, 1, 1);
286 maincpu->write_signal(SIG_CPU_FIRQ, 0, 1);
290 void FM7_MAINIO::set_break_key(bool pressed)
292 firq_break_key = pressed;
295 void FM7_MAINIO::set_sub_attention(bool flag)
297 firq_sub_attention = flag;
302 uint8 FM7_MAINIO::get_fd04(void)
304 uint8 val = 0b11111100;
305 if(!firq_break_key) val |= 0b00000010;
306 if(!firq_sub_attention) val |= 0b00000001;
310 void FM7_MAINIO::set_fd04(uint8 val)
316 uint8 FM7_MAINIO::get_fd05(void)
318 uint8 val = 0b01111110;
319 if(sub_busy) val |= 0b10000000;
320 if(!extdet_neg) val |= 0b00000001;
323 void FM7_MAINIO::set_fd05(uint8 val)
325 subio->write_signal(SIG_SUBIO_HALT, val, 0b10000000);
326 subio->write_signal(SIG_SUBIO_IRQ, val, 0b01000000);
327 if((val & 0b10000000) == 0) {
332 if((val & 0b00000001) != 0) {
333 maincpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
334 //z80->write_signal(SIG_CPU_BUSREQ, 0, 1);
336 maincpu->write_signal(SIG_CPU_BUSREQ, 0, 1);
337 //z80->write_signal(SIG_CPU_BUSREQ, 1, 1);
341 void FM7_MAINIO::set_extdet(bool flag)
346 void FM7_MAINIO::set_psg(uint8 val)
348 switch(psg_cmdreg & 0x03){
349 case 0: // High inpedance
353 //psg_data = psg->read_io8(1);
355 case 2: // Write Data
356 psg->write_io(1, val & 0x00ff);
357 psg->write_signal(SIG_YM2203_MUTE, 0x01, 0x01); // Okay?
359 case 3: // Register address
360 psg_address = val & 0x0f;
361 psg->write_io8(0, psg_address);
366 uint8 FM7_MAINIO::get_psg(void)
369 switch(psg_cmdreg & 0x03) {
374 val = psg->read_io8(1);
375 psg_data = val & 0x00ff;
378 val = 0xff; // Write conflict
381 val = psg->read_io8(1);
389 * $fd0d : After 77AV, this is OPN.
391 void FM7_MAINIO::set_psg_cmd(uint32 cmd)
397 psg_cmdreg = (uint8)(cmd & 0b00000011);
401 uint8 FM7_MAINIO::get_psg_cmd(void)
403 if(opn_psg_77av) return get_opn_cmd();
404 return ((psg_cmdreg & 0b00000011) | 0b11111100);
409 // Kanji ROM, FD20 AND FD21 (or SUBSYSTEM)
410 void FM7_MAINIO::write_kanjiaddr_hi(uint8 addr)
412 if(!connect_kanjirom1) return;
417 void FM7_MAINIO::write_kanjiaddr_lo(uint8 addr)
419 if(!connect_kanjirom1) return;
424 uint8 FM7_MAINIO::read_kanjidata_left(void)
428 if(!connect_kanjirom1) return;
429 addr = ((kaddress_hi & 0xff) * 256) + (kaddress_lo * 0xff);
432 return kanjiclass1->read_data8(addr);
438 uint8 FM7_MAINIO::read_kanjidata_right(void)
442 if(!connect_kanjirom1) return;
443 addr = ((kaddress_hi & 0xff) * 256) + (kaddress_lo * 0xff);
446 return kanjiclass1->read_data8(addr);
453 // Write to FD16, same as
454 void FM7_MAINIO::set_opn(uint8 val, int index)
458 if(!opn_connected) return;
461 if(!whg_connected) return;
464 if(!thg_connected) return;
470 if((opn_cmdreg[index] & 0b00001000) != 0) {
474 if((opn_cmdreg[index] & 0b00000100) != 0) {
478 switch(opn_cmdreg[index] & 0x03){
479 case 0: // High inpedance
483 //psg_data = psg->read_io8(1);
485 case 2: // Write Data
486 opn_data[index] = val & 0x00ff;
487 opn[index]->write_io(1, val & 0x00ff);
488 opn[index]->write_signal(SIG_YM2203_MUTE, 0x01, 0x01); // Okay?
490 case 3: // Register address
491 opn_address[index] = val & 0x0f;
492 opn[index]->write_io8(0, psg_address);
497 uint8 FM7_MAINIO::get_opn(int index)
502 if(!opn_connected) return val;
505 if(!whg_connected) return val;
508 if(!thg_connected) return val;
514 if((opn_cmdreg[index] & 0b00001000) != 0) {
516 val = opn[index]->read_io8(1); // opn->joystick?
517 opn_data[index] = val & 0x00ff;
520 if((opn_cmdreg[index] & 0b00000100) != 0) {
522 val = opn[index]->read_io8(0);
523 opn_stat[index] = val & 0b00ff;
526 switch(opn_cmdreg[index] & 0x03) {
531 val = opn[index]->read_io8(1);
532 opn_data[index] = val & 0x00ff;
535 val = 0xff; // Write conflict
538 val = opn[index]->read_io8(1);
539 opn_address[index] = val;
547 void FM7_MAINIO::set_opn_cmd(uint32 cmd)
549 if(!connect_opn) return;
550 opn_cmdreg[0] = (uint8)(cmd & 0b00001111);
554 uint8 FM7_MAINIO::get_opn_cmd(void)
556 if(!connect_opn) return 0xff;
557 return ((opn_cmdreg[0] & 0b00001111) | 0b11110000);
560 void FM7_MAINIO::wait()
562 int waitfactor; // If MMR of TWR enabled, factor = 3.
563 // If memory, factor = 2?
566 ioaccess_wait = true;
567 } else { // Not MMR, TWR or enabled FAST MMR mode
568 waitfactor = 2; // If(MMR or TWR) and NOT FAST MMR factor = 3, else factor = 2
569 ioaccess_wait =false;
572 if(waitfactor <= 0) return;
573 if(!clock_fast) return;
575 if(waitcount >= waitfactor) {
576 maincpu->set_extra_icount(1);
581 void FM7_MAINIO::write_signals(int id, uint32 data, uint32 mask)
584 val_b = ((data & mask) != 0);
587 case FM7_MAINIO_CLOCKMODE: // fd00
594 case FM7_MAINIO_CMTIN: // fd02
597 case FM7_MAINIO_TIMERIRQ: //
598 set_irq_timer(val_b);
600 case FM7_MAINIO_LPTIRQ: //
601 set_irq_printer(val_b);
603 case FM7_MAINIO_KEYBOARDIRQ: //
604 set_irq_keyboard(val_b);
606 case FM7_MAINIO_PUSH_KEYBOARD:
607 set_keyboard(data & 0x1ff);
610 case FM7_MAINIO_PUSH_BREAK:
611 set_break_key(val_b);
613 case FM7_MAINIO_SUB_ATTENTION:
614 set_sub_attention(val_b);
620 case FM7_MAINIO_EXTDET:
623 case FM7_MAINIO_BEEP:
624 beep->write_signal(SIG_BEEP_ON, data, mask);
626 case FM7_MAINIO_OPNPORTA_CHANGED:
627 opnport_a = data & mask;
629 case FM7_MAINIO_OPNPORTB_CHANGED:
630 opnport_a = data & mask;
632 case FM7_MAINIO_PSG_IRQ:
634 case FM7_MAINIO_OPN_IRQ:
638 case FM7_MAINIO_WHG_IRQ:
642 case FM7_MAINIO_THG_IRQ:
646 case FM7_MAINIO_FDC_DRQ:
649 irqstat_fdc |= 0b10000000;
651 irqstat_fdc &= 0b01111111;
654 case FM7_MAINIO_FDC_IRQ:
656 irqstat_fdc |= 0b01000000;
658 irqstat_fdc &= 0b10111111;
662 case FM7_MAINIO_MPUCLOCK:
664 maincpu->set_context_cpu(maincpu, 2000000); // 2MHz
666 maincpu->set_context_cpu(maincpu, 1200000); // 1.2MHz
673 uint8 FM7_MAINIO::fdc_getdrqirq(void)
678 uint8 FM7_MAINIO::get_irqstat_fd03(void)
680 uint8 val = 0b11111000;
683 extirq = instat_opn | intstat_mouse | fdc_irq;
684 extirq = extirq | intstat_thg | intstat_whg;
685 //extirq = extirq | intstat_syndet | intstat_rxrdy | intstat_txrdy;
686 if(extirq) val &= 0b11110111;
691 uint8 FM7_MAINIO::get_extirq_fd17(void)
694 if(intstat_opn) val &= 0b11110111;
695 if(intstat_mouse) val &= 0b11111011;
699 void FM7_MAINIO::set_ext_fd17(uint8 data)
701 if((data & 0b00000100) != 0) {
704 mouse_enable = false;
711 void FM7_MAINIO::set_fdc_stat(uint8 val)
713 if(!connect_fdc) return;
715 fdc->write_io8(0, val & 0x00ff);
718 uint8 FM7_MAINIO::get_fdc_stat(void)
720 if(!connect_fdc) return 0xff;
721 this->write_signals(FM7_MAINIO_FDC_IRQ, 0, 1);
722 fdc_statreg = fdc->read_io8(0);
726 void FM7_MAINIO::set_fdc_track(uint8 val)
728 if(!connect_fdc) return;
729 // if mode is 2DD and type-of-image = 2D then val >>= 1;
731 fdc->write_io8(1, val & 0x00ff);
734 uint8 FM7_MAINIO::get_fdc_track(void)
736 if(!connect_fdc) return 0xff;
737 fdc_trackreg = fdc->read_io8(1);
741 void FM7_MAINIO::set_fdc_sector(uint8 val)
743 if(!connect_fdc) return;
745 fdc->write_io8(2, val & 0x00ff);
748 uint8 FM7_MAINIO::get_fdc_sector(void)
750 if(!connect_fdc) return 0xff;
751 fdc_sectreg = fdc->read_io8(2);
755 void FM7_MAINIO::set_fdc_data(uint8 val)
757 if(!connect_fdc) return;
759 fdc->write_io8(3, val & 0x00ff);
762 uint8 FM7_MAINIO::get_fdc_data(void)
764 if(!connect_fdc) return 0xff;
765 fdc_datareg = fdc->read_io(3);
769 uint8 FM7_MAINIO::get_fdc_motor(void)
772 if(fdc_motor) val = 0x80;
773 val = val | (fdc_drvsel & 0x03);
777 void FM7_MAINIO::set_fdc_fd1c(uint8 val)
779 fdc_headreg = (val & 0x01) | 0xfe;
780 fdc->write_signal(SIG_MB8877_SIDEREG, val, 0x01);
783 uint8 FM7_MAINIO::get_fdc_fd1c(void)
788 void FM7_MAINIO::set_fdc_fd1d(uint8 val)
790 if((val & 0x80) != 0) {
795 fdc->write_signal(SIG_MB8877_DRIVEREG, val, 0x07);
796 fdc->write_signal(SIG_MB8877_MOTOR, val, 0x80);
801 uint32 FM7_MAINIO::read_data8(uint32 addr)
804 addr = addr & 0xff; //
808 return (uint32) get_port_fd00();
811 return (uint32) kbd_bit7_0;
814 return (uint32) get_port_fd02();
817 return (uint32) get_irqstat_fd03();
820 return (uint32) get_fd04();
823 return (uint32) get_fd05();
825 case 0x06: // RS-232C
829 case 0x08: // Light pen
835 return (uint32) get_psg_cmd();
838 return (uint32) get_psg();
844 case 0x15: // OPN CMD
845 return (uint32) get_opn_cmd();
847 case 0x16: // OPN DATA
848 return (uint32) get_opn();
851 return (uint32) get_extirq_fd17();
853 case 0x18: // FDC: STATUS
854 return (uint32) get_fdc_stat();
856 case 0x19: // FDC: Track
857 return (uint32) get_fdc_track();
859 case 0x1a: // FDC: Sector
860 return (uint32) get_fdc_sector();
862 case 0x1b: // FDC: Data
863 return (uint32) get_fdc_data();
866 return (uint32) get_fdc_fd1c();
869 return (uint32) get_fdc_motor();
872 return (uint32) irqstat_fdc;
874 case 0x20: // Kanji ROM
875 return (uint32) read_kanjidata_left();
877 case 0x21: // Kanji ROM
878 return (uint32) read_kanjidata_right();
880 case 0x37: // Multi page
881 return (uint32)display->read_data8(DISPLAY_ADDR_MULTIPAGE);
886 if((addr < 0x40) && (addr >= 0x38)) {
887 addr = (addr - 0x38) + DISPLAY_ADDR_DPALETTE;
888 return (uint32) display->read_data8(addr);
894 void FM7_MAINIO::write_data8(uint32 addr, uint32 data)
898 addr = addr & 0xff; //
903 set_port_fd00((uint8)data);
907 // set_lptdata_fd01((uint8)data);
911 set_port_fd02((uint8)data);
919 // set_flags_fd04(data);
923 set_fd05((uint8)data);
926 case 0x06: // RS-232C
930 case 0x08: // Light pen
936 set_psg_cmd((uint8)data);
940 set_psg((uint8)data);
947 case 0x15: // OPN CMD
948 return set_opn_cmd((uint8)data);
950 case 0x16: // OPN DATA
951 return set_opn((uint8)data);
954 set_ext_fd17((uint8)data);
957 case 0x18: // FDC: STATUS
958 return set_fdc_stat((uint8)data);
960 case 0x19: // FDC: Track
961 return set_fdc_track((uint8)data);
963 case 0x1a: // FDC: Sector
964 return set_fdc_sector((uint8)data);
966 case 0x1b: // FDC: Data
967 return set_fdc_data((uint8)data);
970 return set_fdc_fd1c((uint8)data);
973 return set_fdc_motor((uint8)data);
978 case 0x20: // Kanji ROM
979 return write_kanjiaddr_hi((uint8)data);
981 case 0x21: // Kanji ROM
982 return write_kanjiaddr_lo((uint8)data);
984 case 0x37: // Multi page
985 return display->write_data8(DISPLAY_ADDR_MULTIPAGE, (uint8)data);
990 if((addr < 0x40) && (addr >= 0x38)) {
991 addr = (addr - 0x38) + DISPLAY_ADDR_DPALETTE;
992 display->write_data8(addr, (uint8)data);
999 void VM::connect_bus(void)
1004 * CLASS CONSTRUCTION
1007 * |-> MAINCPU -> MAINMEM -> MAINIO -> MAIN DEVICES
1009 * | -> SUBCPU -> SUBMEM -> SUBIO -> SUB DEVICES
1013 * MAINMEM can access SUBMEM/IO, when SUBCPU is halted.
1014 * MAINMEM and SUBMEM can access DISPLAY and KEYBOARD with exclusive.
1015 * MAINCPU can access MAINMEM.
1016 * SUBCPU can access SUBMEM.
1017 * DISPLAY : R/W from MAINCPU and SUBCPU.
1021 event->set_context_cpu(maincpu);
1022 event->set_context_cpu(subcpu);
1024 if((!opn_psg_77av) || (!opn_connected)) {
1025 event->set_context_sound(psg);
1028 event->set_context_sound(opn[0]);
1031 event->set_context_sound(opn[1]);
1034 event->set_context_sound(opn[2]);
1037 cmt->set_context_out(mainio, FM7_MAINIO_CMTIN, 0x0001);
1039 keyboard->set_context_mainio(mainio);
1040 keyboard->set_context_subio(subio);
1042 mainmem->set_context_submem(submem);
1043 // mainmem->set_context_cpu(maincpu);
1045 mainio->set_context_maincpu(maincpu);
1046 mainio->set_context_subio(subio);
1048 subio->set_context_mainio(mainio);
1049 subio->set_context_subcpu(subcpu);
1051 // Palette, VSYNC, HSYNC, Multi-page, display mode.
1052 mainio->set_context_display(display);
1053 subio->set_context_display(display);
1054 display->set_context_submem(submem); // For VRAM?
1055 display->set_context_subcpu(subcpu); // For VRAM?
1058 fdc->set_context_irq(mainio, FM7_MAINIO_FDC_IRQ, 0xffffffff);
1059 fdc->set_context_drq(mainio, FM7_MAINIO_FDC_DRQ, 0xffffffff);
1061 psg->set_context_irq(mainio, FM7_MAINIO_PSG_IRQ, 0xffffffff);
1062 opn[0]->set_context_irq(mainio, FM7_MAINIO_OPN_IRQ, 0xffffffff);
1063 opn[1]->set_context_irq(mainio, FM7_MAINIO_WHG_IRQ, 0xffffffff);
1064 opn[2]->set_context_irq(mainio, FM7_MAINIO_THG_IRQ, 0xffffffff);
1066 opn[0]->set_context_port_a(mainio, SIG_FM7_OPN_JOY_A, 0xff);
1067 opn[0]->set_context_port_b(mainio, SIG_FM7_OPN_JOY_B, 0xff);
1069 maincpu->set_context_mem(mainmem);
1070 subcpu->set_context_mem(submem);