diff --git a/src/mame/thomson/thomson.cpp b/src/mame/thomson/thomson.cpp index 69215e68d03ed..67d77a2f035fd 100644 --- a/src/mame/thomson/thomson.cpp +++ b/src/mame/thomson/thomson.cpp @@ -460,10 +460,6 @@ static INPUT_PORTS_START ( to7_keyboard ) KEY ( 6, "7 ' \302\264", 7 ) PORT_CHAR('7') PORT_CHAR('\'') KEY ( 7, "6 &", 6 ) PORT_CHAR('6') PORT_CHAR('&') - /* unused */ - PORT_START ( "keyboard.8" ) - PORT_START ( "keyboard.9" ) - INPUT_PORTS_END static INPUT_PORTS_START ( to7 ) @@ -1062,7 +1058,7 @@ void to9_state::to9_map(address_map &map) map(0xe7c8, 0xe7cb).rw("pia_0", FUNC(pia6821_device::read_alt), FUNC(pia6821_device::write_alt)); map(0xe7cc, 0xe7cf).rw("pia_1", FUNC(pia6821_device::read_alt), FUNC(pia6821_device::write_alt)); map(0xe7da, 0xe7dd).rw(FUNC(to9_state::to9_vreg_r), FUNC(to9_state::to9_vreg_w)); - map(0xe7de, 0xe7df).rw(FUNC(to9_state::to9_kbd_r), FUNC(to9_state::to9_kbd_w)); + map(0xe7de, 0xe7df).rw(m_to9_kbd, FUNC(to9_keyboard_device::kbd_acia_r), FUNC(to9_keyboard_device::kbd_acia_w)); map(0xe7e4, 0xe7e7).rw(FUNC(to9_state::to9_gatearray_r), FUNC(to9_state::to9_gatearray_w)); /* map(0xe7f0, 0xe7f7).rw(FUNC(to9_state::to9_ieee_r), FUNC(to9_state::to9_ieee_w )); */ map(0xe800, 0xffff).rom(); /* system bios */ @@ -1127,105 +1123,23 @@ ROM_END /* ------------ inputs ------------ */ -static INPUT_PORTS_START ( to9_keyboard ) - PORT_START ( "keyboard.0" ) - KEY ( 0, "F2 F7", F2 ) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_CHAR(UCHAR_MAMEKEY(F7)) - KEY ( 1, "_ 6", 6 ) PORT_CHAR('_') PORT_CHAR('6') - KEY ( 2, "Y", Y ) PORT_CHAR('Y') - KEY ( 3, "H \302\250", H ) PORT_CHAR('H') - KEY ( 4, UTF8_UP, UP ) PORT_CHAR(UCHAR_MAMEKEY(UP)) - KEY ( 5, UTF8_RIGHT, RIGHT ) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) - KEY ( 6, "Home Clear", HOME ) PORT_CHAR(UCHAR_MAMEKEY(HOME)) PORT_CHAR(UCHAR_MAMEKEY(ESC)) - KEY ( 7, "N", N ) PORT_CHAR('N') - PORT_START ( "keyboard.1" ) - KEY ( 0, "F3 F8", F3 ) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CHAR(UCHAR_MAMEKEY(F8)) - KEY ( 1, "( 5", 5 ) PORT_CHAR('(') PORT_CHAR('5') - KEY ( 2, "T", T ) PORT_CHAR('T') - KEY ( 3, "G", G ) PORT_CHAR('G') - KEY ( 4, "= +", EQUALS ) PORT_CHAR('=') PORT_CHAR('+') - KEY ( 5, UTF8_LEFT, LEFT ) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) - KEY ( 6, "Insert", INSERT ) PORT_CHAR(UCHAR_MAMEKEY(INSERT)) - KEY ( 7, "B \302\264", B ) PORT_CHAR('B') - PORT_START ( "keyboard.2" ) - KEY ( 0, "F4 F9", F4 ) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_CHAR(UCHAR_MAMEKEY(F9)) - KEY ( 1, "' 4", 4 ) PORT_CHAR('\'') PORT_CHAR('4') - KEY ( 2, "R", R ) PORT_CHAR('R') - KEY ( 3, "F", F ) PORT_CHAR('F') - KEY ( 4, "Accent", END ) PORT_CHAR(UCHAR_MAMEKEY(END)) - KEY ( 5, "Keypad 1", 1_PAD ) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) - KEY ( 6, "Delete Backspace", DEL ) PORT_CHAR(8) PORT_CHAR(UCHAR_MAMEKEY(BACKSPACE)) - KEY ( 7, "V", V ) PORT_CHAR('V') - PORT_START ( "keyboard.3" ) - KEY ( 0, "F5 F10", F5 ) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_CHAR(UCHAR_MAMEKEY(F10)) - KEY ( 1, "\" 3", 3 ) PORT_CHAR('"') PORT_CHAR('3') - KEY ( 2, "E", E ) PORT_CHAR('E') - KEY ( 3, "D", D ) PORT_CHAR('D') - KEY ( 4, "Keypad 7", 7_PAD ) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) - KEY ( 5, "Keypad 4", 4_PAD ) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) - KEY ( 6, "Keypad 0", 0_PAD ) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) - KEY ( 7, "C \136", C ) PORT_CHAR('C') - PORT_START ( "keyboard.4" ) - KEY ( 0, "F1 F6", F1 ) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CHAR(UCHAR_MAMEKEY(F6)) - KEY ( 1, "\303\251 2", 2 ) PORT_CHAR( 0xe9 ) PORT_CHAR('2') - KEY ( 2, "Z", Z ) PORT_CHAR('Z') - KEY ( 3, "S", S ) PORT_CHAR('S') - KEY ( 4, "Keypad 8", 8_PAD ) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) - KEY ( 5, "Keypad 2", 2_PAD ) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) - KEY ( 6, "Keypad .", DEL_PAD ) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) - KEY ( 7, "X", X ) PORT_CHAR('X') - PORT_START ( "keyboard.5" ) - KEY ( 0, "# @", TILDE ) PORT_CHAR('#') PORT_CHAR('@') - KEY ( 1, "* 1", 1 ) PORT_CHAR('*') PORT_CHAR('1') - KEY ( 2, "A \140", A ) PORT_CHAR('A') - KEY ( 3, "Q", Q ) PORT_CHAR('Q') - KEY ( 4, "[ {", QUOTE ) PORT_CHAR('[') PORT_CHAR('{') - KEY ( 5, "Keypad 5", 5_PAD ) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) - KEY ( 6, "Keypad 6", 6_PAD ) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) - KEY ( 7, "W", W ) PORT_CHAR('W') - PORT_START ( "keyboard.6" ) - KEY ( 0, "Stop", TAB ) PORT_CHAR(27) - KEY ( 1, "\303\250 7", 7 ) PORT_CHAR( 0xe8 ) PORT_CHAR('7') - KEY ( 2, "U", U ) PORT_CHAR('U') - KEY ( 3, "J", J ) PORT_CHAR('J') - KEY ( 4, "Space", SPACE ) PORT_CHAR(' ') - KEY ( 5, "Keypad 9", 9_PAD ) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) - KEY ( 6, "Keypad Enter", ENTER_PAD ) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) - KEY ( 7, ", ?", COMMA ) PORT_CHAR(',') PORT_CHAR('?') - PORT_START ( "keyboard.7" ) - KEY ( 0, "Control", LCONTROL ) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) - KEY ( 1, "! 8", 8 ) PORT_CHAR('!') PORT_CHAR('8') - KEY ( 2, "I", I ) PORT_CHAR('I') - KEY ( 3, "K", K ) PORT_CHAR('K') - KEY ( 4, "$ &", CLOSEBRACE ) PORT_CHAR('$') PORT_CHAR('&') - KEY ( 5, UTF8_DOWN, DOWN ) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) - KEY ( 6, "] }", BACKSLASH ) PORT_CHAR(']') PORT_CHAR('}') - KEY ( 7, "; .", STOP ) PORT_CHAR(';') PORT_CHAR('.') - PORT_START ( "keyboard.8" ) - KEY ( 0, "Caps-Lock", CAPSLOCK ) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) - KEY ( 1, "\303\247 9", 9 ) PORT_CHAR( 0xe7 ) PORT_CHAR('9') - KEY ( 2, "O", O ) PORT_CHAR('O') - KEY ( 3, "L", L ) PORT_CHAR('L') - KEY ( 4, "- \\", BACKSPACE ) PORT_CHAR('-') PORT_CHAR('\\') - KEY ( 5, "\303\271 %", COLON ) PORT_CHAR( 0xf9 ) PORT_CHAR('%') - KEY ( 6, "Enter", ENTER ) PORT_CHAR(13) - KEY ( 7, ": /", SLASH ) PORT_CHAR(':') PORT_CHAR('/') - PORT_START ( "keyboard.9" ) - KEY ( 0, "Shift", LSHIFT ) PORT_CODE ( KEYCODE_RSHIFT ) PORT_CHAR(UCHAR_SHIFT_1) - KEY ( 1, "\303\240 0", 0 ) PORT_CHAR( 0xe0 ) PORT_CHAR('0') - KEY ( 2, "P", P ) PORT_CHAR('P') - KEY ( 3, "M", M ) PORT_CHAR('M') - KEY ( 4, ") \302\260", MINUS ) PORT_CHAR(')') PORT_CHAR( 0xb0 ) - KEY ( 5, "\342\206\221 \302\250", OPENBRACE ) PORT_CHAR('^') PORT_CHAR( 0xa8 ) - KEY ( 6, "Keypad 3", 3_PAD ) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) - KEY ( 7, "> <", BACKSLASH2 ) PORT_CHAR('>') PORT_CHAR('<') -INPUT_PORTS_END - static INPUT_PORTS_START ( to9 ) PORT_INCLUDE ( thom_lightpen ) PORT_INCLUDE ( thom_game_port ) - PORT_INCLUDE ( to9_keyboard ) - PORT_INCLUDE ( to7_config ) PORT_INCLUDE ( to7_vconfig ) + + PORT_START ( "config" ) + PORT_BIT ( 0x01, 0x00, IPT_UNUSED ) + + PORT_MODIFY ( "mouse_x" ) + PORT_BIT ( 0xffff, 0x00, IPT_UNUSED ) + + PORT_MODIFY ( "mouse_y" ) + PORT_BIT ( 0xffff, 0x00, IPT_UNUSED ) + + PORT_MODIFY ( "mouse_button" ) + PORT_BIT ( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT ( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) INPUT_PORTS_END /* ------------ driver ------------ */ @@ -1238,6 +1152,9 @@ void to9_state::to9(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &to9_state::to9_map); + TO9_KEYBOARD(config, m_to9_kbd); + m_to9_kbd->irq_cb().set(m_mainirq, FUNC(input_merger_device::in_w<4>)); + m_pia_sys->readpa_handler().set(FUNC(to9_state::to9_sys_porta_in)); m_pia_sys->readpb_handler().set_constant(0); m_pia_sys->writepa_handler().set(FUNC(to9_state::to9_sys_porta_out)); @@ -1412,25 +1329,10 @@ ROM_END /* ------------ inputs ------------ */ -static INPUT_PORTS_START ( to8_config ) - PORT_START ( "config" ) - - PORT_CONFNAME ( 0x01, 0x00, "Game Port" ) - PORT_CONFSETTING ( 0x00, DEF_STR( Joystick ) ) - PORT_CONFSETTING ( 0x01, "Mouse" ) - - PORT_CONFNAME ( 0x02, 0x00, "Keyboard" ) - PORT_CONFSETTING ( 0x00, "Enabled" ) - PORT_CONFSETTING ( 0x02, "Disabled" ) - -INPUT_PORTS_END - - static INPUT_PORTS_START ( to8 ) PORT_INCLUDE ( thom_lightpen ) PORT_INCLUDE ( thom_game_port ) - PORT_INCLUDE ( to9_keyboard ) - PORT_INCLUDE ( to8_config ) + PORT_INCLUDE ( to7_config ) PORT_INCLUDE ( to7_vconfig ) INPUT_PORTS_END @@ -1449,7 +1351,8 @@ void to9_state::to8(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &to9_state::to8_map); - //MC6804(config, "kbdmcu", 11_MHz_XTAL); + TO8_KEYBOARD(config, m_to8_kbd); + m_to8_kbd->data_cb().set(m_mc6846, FUNC(mc6846_device::set_input_cp1)); m_pia_sys->readpa_handler().set(FUNC(to9_state::to8_sys_porta_in)); m_pia_sys->readpb_handler().set_constant(0); @@ -1537,7 +1440,7 @@ void to9_state::to9p_map(address_map &map) map(0xe7c8, 0xe7cb).rw("pia_0", FUNC(pia6821_device::read_alt), FUNC(pia6821_device::write_alt)); map(0xe7cc, 0xe7cf).rw("pia_1", FUNC(pia6821_device::read_alt), FUNC(pia6821_device::write_alt)); map(0xe7da, 0xe7dd).rw(FUNC(to9_state::to8_vreg_r), FUNC(to9_state::to8_vreg_w)); - map(0xe7de, 0xe7df).rw(FUNC(to9_state::to9_kbd_r), FUNC(to9_state::to9_kbd_w)); + map(0xe7de, 0xe7df).rw(m_to9_kbd, FUNC(to9_keyboard_device::kbd_acia_r), FUNC(to9_keyboard_device::kbd_acia_w)); map(0xe7e4, 0xe7e7).rw(FUNC(to9_state::to8_gatearray_r), FUNC(to9_state::to8_gatearray_w)); /* map(0xe7f0, 0xe7f7).rw(FUNC(to9_state::to9_ieee_r), FUNC(to9_state::to9_ieee_w )); */ @@ -1588,7 +1491,6 @@ ROM_END static INPUT_PORTS_START ( to9p ) PORT_INCLUDE ( thom_lightpen ) PORT_INCLUDE ( thom_game_port ) - PORT_INCLUDE ( to9_keyboard ) PORT_INCLUDE ( to7_config ) PORT_INCLUDE ( to7_vconfig ) INPUT_PORTS_END @@ -1603,6 +1505,9 @@ void to9_state::to9p(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &to9_state::to9p_map); + TO9P_KEYBOARD(config, m_to9_kbd); + m_to9_kbd->irq_cb().set(m_mainirq, FUNC(input_merger_device::in_w<4>)); + m_pia_sys->readpa_handler().set(FUNC(to9_state::to9_sys_porta_in)); m_pia_sys->readpb_handler().set_constant(0); m_pia_sys->writepa_handler().set(FUNC(to9_state::to9_sys_porta_out)); @@ -1861,9 +1766,6 @@ static INPUT_PORTS_START ( mo6_keyboard ) KEY ( 4, "\303\271 %", COLON ) PORT_CHAR( 0xf9 ) PORT_CHAR('%') PORT_BIT ( 0xe0, IP_ACTIVE_LOW, IPT_UNUSED ) - /* unused */ - PORT_START ( "keyboard.9" ) - INPUT_PORTS_END /* QWERTY version */ @@ -2169,10 +2071,6 @@ static INPUT_PORTS_START ( mo5nr_keyboard ) KEY ( 6, "Stop", TAB ) PORT_CHAR(27) PORT_BIT ( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) - /* unused */ - PORT_START ( "keyboard.8" ) - PORT_START ( "keyboard.9" ) - INPUT_PORTS_END static INPUT_PORTS_START ( mo5nr ) diff --git a/src/mame/thomson/thomson.h b/src/mame/thomson/thomson.h index 0e7991390c0e2..905a71056985f 100644 --- a/src/mame/thomson/thomson.h +++ b/src/mame/thomson/thomson.h @@ -13,6 +13,8 @@ #pragma once +#include "to_kbd.h" + #include "cpu/m6809/m6809.h" #include "imagedev/cassette.h" #include "machine/6821pia.h" @@ -231,7 +233,7 @@ class thomson_state : public driver_device required_ioport m_io_lightpen_button; required_ioport m_io_config; required_ioport m_io_vconfig; - required_ioport_array<10> m_io_keyboard; + optional_ioport_array<9> m_io_keyboard; required_memory_bank m_vrambank; optional_memory_bank m_cartbank; optional_memory_bank m_rambank; @@ -384,6 +386,8 @@ class to9_state : public thomson_state public: to9_state(const machine_config &mconfig, device_type type, const char *tag) : thomson_state(mconfig, type, tag), + m_to8_kbd(*this, "to8_kbd"), + m_to9_kbd(*this, "to9_kbd"), m_centronics(*this, "centronics"), m_cent_data_out(*this, "cent_data_out"), m_syslobank(*this, TO8_SYS_LO), @@ -400,6 +404,8 @@ class to9_state : public thomson_state void to9p(machine_config &config); protected: + optional_device m_to8_kbd; + optional_device m_to9_kbd; optional_device m_centronics; optional_device m_cent_data_out; @@ -411,14 +417,6 @@ class to9_state : public thomson_state int m_centronics_busy = 0; - uint8_t m_to8_kbd_ack = 0; /* 1 = cpu inits / accepts transfers */ - uint16_t m_to8_kbd_data = 0; /* data to transmit */ - uint16_t m_to8_kbd_step = 0; /* transmission automaton state */ - uint8_t m_to8_kbd_last_key = 0; /* last key (for repetition) */ - uint32_t m_to8_kbd_key_count = 0; /* keypress time (for repetition) */ - uint8_t m_to8_kbd_caps = 0; /* caps lock */ - emu_timer* m_to8_kbd_timer = nullptr; /* bit-send */ - emu_timer* m_to8_kbd_signal = nullptr; /* signal from CPU */ uint8_t m_to8_data_vpage = 0; uint8_t m_to8_cart_vpage = 0; uint8_t m_to8_reg_ram = 0; @@ -430,7 +428,6 @@ class to9_state : public thomson_state uint8_t m_to8_soft_bank = 0; uint8_t m_to8_bios_bank = 0; - TIMER_CALLBACK_MEMBER( to8_kbd_timer_cb ); void to8_update_ram_bank_postload(); void to8_update_cart_bank_postload(); void to8_cartridge_w(offs_t offset, uint8_t data); @@ -456,12 +453,6 @@ class to9_state : public thomson_state void to8_data_hi_w(offs_t offset, uint8_t data); void to8_vcart_w(offs_t offset, uint8_t data); - int to8_kbd_ktest(); - int to8_kbd_get_key(); - void to8_kbd_timer_func(); - void to8_kbd_set_ack( int data ); - void to8_kbd_reset(); - void to8_kbd_init(); void to8_update_ram_bank(); void to8_update_cart_bank(); @@ -475,9 +466,6 @@ class to9_state : public thomson_state void to9_cartridge_w(offs_t offset, uint8_t data); uint8_t to9_cartridge_r(offs_t offset); void to9_update_ram_bank_postload(); - uint8_t to9_kbd_r(offs_t offset); - void to9_kbd_w(offs_t offset, uint8_t data); - TIMER_CALLBACK_MEMBER( to9_kbd_timer_cb ); uint8_t to9_sys_porta_in(); void to9_sys_porta_out(uint8_t data); void to9_sys_portb_out(uint8_t data); @@ -496,31 +484,11 @@ class to9_state : public thomson_state uint8_t m_to9_palette_data[32]{}; uint8_t m_to9_palette_idx = 0; uint8_t m_to9_soft_bank = 0; - uint8_t m_to9_kbd_parity = 0; /* 0=even, 1=odd, 2=no parity */ - uint8_t m_to9_kbd_intr = 0; /* interrupt mode */ - uint8_t m_to9_kbd_in = 0; /* data from keyboard */ - uint8_t m_to9_kbd_status = 0; /* status */ - uint8_t m_to9_kbd_overrun = 0; /* character lost */ - uint8_t m_to9_kbd_periph = 0; /* peripheral mode */ - uint8_t m_to9_kbd_byte_count = 0; /* byte-count in peripheral mode */ - uint16_t m_to9_mouse_x = 0; - uint16_t m_to9_mouse_y = 0; - uint8_t m_to9_kbd_last_key = 0; /* for key repetition */ - uint16_t m_to9_kbd_key_count = 0; - uint8_t m_to9_kbd_caps = 0; /* caps-lock */ - uint8_t m_to9_kbd_pad = 0; /* keypad outputs special codes */ - emu_timer* m_to9_kbd_timer = nullptr; void to9_set_video_mode( uint8_t data, int style ); void to9_palette_init(); void to9_update_cart_bank(); void to9_update_ram_bank(); - int to9_kbd_ktest(); - void to9_kbd_update_irq(); - void to9_kbd_send( uint8_t data, int parity ); - int to9_kbd_get_key(); - void to9_kbd_reset(); - void to9_kbd_init(); }; class mo6_state : public to9_state diff --git a/src/mame/thomson/thomson_m.cpp b/src/mame/thomson/thomson_m.cpp index 2bc583f8c6544..b5bc183160df4 100644 --- a/src/mame/thomson/thomson_m.cpp +++ b/src/mame/thomson/thomson_m.cpp @@ -224,19 +224,6 @@ void thomson_state::thom_irq_reset() -/* ------------ 6850 defines ------------ */ - -#define ACIA_6850_RDRF 0x01 /* Receive data register full */ -#define ACIA_6850_TDRE 0x02 /* Transmit data register empty */ -#define ACIA_6850_dcd 0x04 /* Data carrier detect, active low */ -#define ACIA_6850_cts 0x08 /* Clear to send, active low */ -#define ACIA_6850_FE 0x10 /* Framing error */ -#define ACIA_6850_OVRN 0x20 /* Receiver overrun */ -#define ACIA_6850_PE 0x40 /* Parity error */ -#define ACIA_6850_irq 0x80 /* Interrupt request, active low */ - - - /***************************** TO7 / T9000 *************************/ DEVICE_IMAGE_LOAD_MEMBER( thomson_state::to7_cartridge ) @@ -1689,451 +1676,11 @@ void to9_state::to9_update_ram_bank_postload() } - -/* ------------ keyboard (6850 ACIA + 6805 CPU) ------------ */ - -/* The 6805 chip scans the keyboard and sends ASCII codes to the 6909. - Data between the 6809 and 6805 is serialized at 9600 bauds. - On the 6809 side, a 6850 ACIA is used. - We do not emulate the seral line but pass bytes directly between the - keyboard and the 6850 registers. - Note that the keyboard protocol uses the parity bit as an extra data bit. -*/ - - - -/* normal mode: polling interval */ -#define TO9_KBD_POLL_PERIOD attotime::from_msec( 10 ) - -/* peripheral mode: time between two bytes, and after last byte */ -#define TO9_KBD_BYTE_SPACE attotime::from_usec( 300 ) -#define TO9_KBD_END_SPACE attotime::from_usec( 9100 ) - -/* first and subsequent repeat periods, in TO9_KBD_POLL_PERIOD units */ -#define TO9_KBD_REPEAT_DELAY 80 /* 800 ms */ -#define TO9_KBD_REPEAT_PERIOD 7 /* 70 ms */ - - - -/* quick keyboard scan */ -int to9_state::to9_kbd_ktest() -{ - int line, bit; - uint8_t port; - - for ( line = 0; line < 10; line++ ) - { - port = m_io_keyboard[line]->read(); - - if ( line == 7 || line == 9 ) - port |= 1; /* shift & control */ - - for ( bit = 0; bit < 8; bit++ ) - { - if ( ! (port & (1 << bit)) ) - return 1; - } - } - return 0; -} - - - -void to9_state::to9_kbd_update_irq() -{ - if ( (m_to9_kbd_intr & 4) && (m_to9_kbd_status & ACIA_6850_RDRF) ) - m_to9_kbd_status |= ACIA_6850_irq; /* byte received interrupt */ - - if ( (m_to9_kbd_intr & 4) && (m_to9_kbd_status & ACIA_6850_OVRN) ) - m_to9_kbd_status |= ACIA_6850_irq; /* overrun interrupt */ - - if ( (m_to9_kbd_intr & 3) == 1 && (m_to9_kbd_status & ACIA_6850_TDRE) ) - m_to9_kbd_status |= ACIA_6850_irq; /* ready to transmit interrupt */ - - m_mainirq->in_w<3>( m_to9_kbd_status & ACIA_6850_irq ); -} - - - -uint8_t to9_state::to9_kbd_r(offs_t offset) -{ - /* ACIA 6850 registers */ - - switch ( offset ) - { - case 0: /* get status */ - /* bit 0: data received */ - /* bit 1: ready to transmit data (always 1) */ - /* bit 2: data carrier detect (ignored) */ - /* bit 3: clear to send (ignored) */ - /* bit 4: framing error (ignored) */ - /* bit 5: overrun */ - /* bit 6: parity error */ - /* bit 7: interrupt */ - - LOGMASKED(LOG_KBD, "$%04x %f to9_kbd_r: status $%02X (rdrf=%i, tdre=%i, ovrn=%i, pe=%i, irq=%i)\n", - m_maincpu->pc(), machine().time().as_double(), m_to9_kbd_status, - (m_to9_kbd_status & ACIA_6850_RDRF) ? 1 : 0, - (m_to9_kbd_status & ACIA_6850_TDRE) ? 1 : 0, - (m_to9_kbd_status & ACIA_6850_OVRN) ? 1 : 0, - (m_to9_kbd_status & ACIA_6850_PE) ? 1 : 0, - (m_to9_kbd_status & ACIA_6850_irq) ? 1 : 0 ); - return m_to9_kbd_status; - - case 1: /* get input data */ - if ( !machine().side_effects_disabled() ) - { - m_to9_kbd_status &= ~(ACIA_6850_irq | ACIA_6850_PE); - if ( m_to9_kbd_overrun ) - m_to9_kbd_status |= ACIA_6850_OVRN; - else - m_to9_kbd_status &= ~(ACIA_6850_OVRN | ACIA_6850_RDRF); - m_to9_kbd_overrun = 0; - LOGMASKED(LOG_KBD, "$%04x %f to9_kbd_r: read data $%02X\n", m_maincpu->pc(), machine().time().as_double(), m_to9_kbd_in); - to9_kbd_update_irq(); - } - return m_to9_kbd_in; - - default: - LOGMASKED(LOG_ERRORS, "$%04x to9_kbd_r: invalid offset %i\n", m_maincpu->pc(), offset); - return 0; - } -} - - - -void to9_state::to9_kbd_w(offs_t offset, uint8_t data) -{ - /* ACIA 6850 registers */ - - switch ( offset ) - { - case 0: /* set control */ - /* bits 0-1: clock divide (ignored) or reset */ - if ( (data & 3) == 3 ) - { - /* reset */ - m_to9_kbd_overrun = 0; - m_to9_kbd_status = ACIA_6850_TDRE; - m_to9_kbd_intr = 0; - LOGMASKED(LOG_KBD, "$%04x %f to9_kbd_w: reset (data=$%02X)\n", m_maincpu->pc(), machine().time().as_double(), data); - } - else - { - /* bits 2-4: parity */ - if ( (data & 0x18) == 0x10 ) - m_to9_kbd_parity = 2; - else - m_to9_kbd_parity = (data >> 2) & 1; - /* bits 5-6: interrupt on transmit */ - /* bit 7: interrupt on receive */ - m_to9_kbd_intr = data >> 5; - - LOGMASKED(LOG_KBD, "$%04x %f to9_kbd_w: set control to $%02X (parity=%i, intr in=%i out=%i)\n", - m_maincpu->pc(), machine().time().as_double(), - data, m_to9_kbd_parity, m_to9_kbd_intr >> 2, - (m_to9_kbd_intr & 3) ? 1 : 0); - } - to9_kbd_update_irq(); - break; - - case 1: /* output data */ - m_to9_kbd_status &= ~(ACIA_6850_irq | ACIA_6850_TDRE); - to9_kbd_update_irq(); - /* TODO: 1 ms delay here ? */ - m_to9_kbd_status |= ACIA_6850_TDRE; /* data transmit ready again */ - to9_kbd_update_irq(); - - switch ( data ) - { - case 0xF8: - /* reset */ - m_to9_kbd_caps = 1; - m_to9_kbd_periph = 0; - m_to9_kbd_pad = 0; - break; - - case 0xF9: m_to9_kbd_caps = 1; break; - case 0xFA: m_to9_kbd_caps = 0; break; - case 0xFB: m_to9_kbd_pad = 1; break; - case 0xFC: m_to9_kbd_pad = 0; break; - case 0xFD: m_to9_kbd_periph = 1; break; - case 0xFE: m_to9_kbd_periph = 0; break; - - default: - LOGMASKED(LOG_ERRORS, "$%04x %f to9_kbd_w: unknown kbd command %02X\n", m_maincpu->pc(), machine().time().as_double(), data); - } - - m_caps_led = !m_to9_kbd_caps; - - LOG("$%04x %f to9_kbd_w: kbd command %02X (caps=%i, pad=%i, periph=%i)\n", - m_maincpu->pc(), machine().time().as_double(), data, - m_to9_kbd_caps, m_to9_kbd_pad, m_to9_kbd_periph); - - break; - - default: - LOGMASKED(LOG_ERRORS, "$%04x to9_kbd_w: invalid offset %i (data=$%02X) \n", m_maincpu->pc(), offset, data); - } -} - - - -/* send a key to the CPU, 8-bit + parity bit (0=even, 1=odd) - note: parity is not used as a checksum but to actually transmit a 9-th bit - of information! -*/ -void to9_state::to9_kbd_send( uint8_t data, int parity ) -{ - if ( m_to9_kbd_status & ACIA_6850_RDRF ) - { - /* overrun will be set when the current valid byte is read */ - m_to9_kbd_overrun = 1; - LOGMASKED(LOG_KBD, "%f to9_kbd_send: overrun => drop data=$%02X, parity=%i\n", machine().time().as_double(), data, parity); - } - else - { - /* valid byte */ - m_to9_kbd_in = data; - m_to9_kbd_status |= ACIA_6850_RDRF; /* raise data received flag */ - if ( m_to9_kbd_parity == 2 || m_to9_kbd_parity == parity ) - m_to9_kbd_status &= ~ACIA_6850_PE; /* parity OK */ - else - m_to9_kbd_status |= ACIA_6850_PE; /* parity error */ - LOGMASKED(LOG_KBD, "%f to9_kbd_send: data=$%02X, parity=%i, status=$%02X\n", machine().time().as_double(), data, parity, m_to9_kbd_status); - } - to9_kbd_update_irq(); -} - - - -/* keycode => TO9 code (extended ASCII), shifted and un-shifted */ -static const int to9_kbd_code[80][2] = -{ - { 145, 150 }, { '_', '6' }, { 'Y', 'Y' }, { 'H', 'H' }, - { 11, 11 }, { 9, 9 }, { 30, 12 }, { 'N', 'N' }, - - { 146, 151 }, { '(', '5' }, { 'T', 'T' }, { 'G', 'G' }, - { '=', '+' }, { 8, 8 }, { 28, 28 }, { 'B', 'B' }, - - { 147, 152 }, { '\'', '4' }, { 'R', 'R' }, { 'F', 'F' }, - { 22, 22 }, { 155, 155 }, { 29, 127 }, { 'V', 'V' }, - - { 148, 153 }, { '"', '3' }, { 'E', 'E' }, { 'D', 'D' }, - { 161, 161 }, { 158, 158 }, - { 154, 154 }, { 'C', 'C' }, - - { 144, 149 }, { 128, '2' }, { 'Z', 'Z' }, { 'S', 'S' }, - { 162, 162 }, { 156, 156 }, - { 164, 164 }, { 'X', 'X' }, - - { '#', '@' }, { '*', '1' }, { 'A', 'A' }, { 'Q', 'Q' }, - { '[', '{' }, { 159, 159 }, { 160, 160 }, { 'W', 'W' }, - - { 2, 2 }, { 129, '7' }, { 'U', 'U' }, { 'J', 'J' }, - { ' ', ' ' }, { 163, 163 }, { 165, 165 }, - { ',', '?' }, - - { 0, 0 }, { '!', '8' }, { 'I', 'I' }, { 'K', 'K' }, - { '$', '&' }, { 10, 10 }, { ']', '}' }, { ';', '.' }, - - { 0, 0 }, { 130, '9' }, { 'O', 'O' }, { 'L', 'L' }, - { '-', '\\' }, { 132, '%' }, { 13, 13 }, { ':', '/' }, - - { 0, 0 }, { 131, '0' }, { 'P', 'P' }, { 'M', 'M' }, - { ')', 134 }, { '^', 133 }, { 157, 157 }, { '>', '<' } -}; - - - -/* returns the ASCII code for the key, or 0 for no key */ -int to9_state::to9_kbd_get_key() -{ - int control = ! (m_io_keyboard[7]->read() & 1); - int shift = ! (m_io_keyboard[9]->read() & 1); - int key = -1, line, bit; - uint8_t port; - - for ( line = 0; line < 10; line++ ) - { - port = m_io_keyboard[line]->read(); - - if ( line == 7 || line == 9 ) - port |= 1; /* shift & control */ - - /* TODO: correct handling of simultaneous keystokes: - return the new key preferably & disable repeat - */ - for ( bit = 0; bit < 8; bit++ ) - { - if ( ! (port & (1 << bit)) ) - key = line * 8 + bit; - } - } - - if ( key == -1 ) - { - m_to9_kbd_last_key = 0xff; - m_to9_kbd_key_count = 0; - return 0; - } - else if ( key == 64 ) - { - /* caps lock */ - if ( m_to9_kbd_last_key == key ) - return 0; /* no repeat */ - - m_to9_kbd_last_key = key; - m_to9_kbd_caps = !m_to9_kbd_caps; - m_caps_led = !m_to9_kbd_caps; - return 0; - } - else - { - int asc; - asc = to9_kbd_code[key][shift]; - if ( ! asc ) return 0; - - /* keypad */ - if ( ! m_to9_kbd_pad ) { - if ( asc >= 154 && asc <= 163 ) - asc += '0' - 154; - else if ( asc == 164 ) - asc = '.'; - else if ( asc == 165 ) - asc = 13; - } - - /* shifted letter */ - if ( asc >= 'A' && asc <= 'Z' && ( ! m_to9_kbd_caps ) && ( ! shift ) ) - asc += 'a' - 'A'; - - /* control */ - if ( control ) - asc &= ~0x40; - - if ( key == m_to9_kbd_last_key ) - { - /* repeat */ - m_to9_kbd_key_count++; - if ( m_to9_kbd_key_count < TO9_KBD_REPEAT_DELAY || (m_to9_kbd_key_count - TO9_KBD_REPEAT_DELAY) % TO9_KBD_REPEAT_PERIOD ) - return 0; - LOGMASKED(LOG_KBD, "to9_kbd_get_key: repeat key $%02X '%c'\n", asc, asc); - return asc; - } - else - { - m_to9_kbd_last_key = key; - m_to9_kbd_key_count = 0; - LOGMASKED(LOG_KBD, "to9_kbd_get_key: key down $%02X '%c'\n", asc, asc); - return asc; - } - } -} - - - -TIMER_CALLBACK_MEMBER(to9_state::to9_kbd_timer_cb) -{ - if ( m_to9_kbd_periph ) - { - /* peripheral mode: every 10 ms we send 4 bytes */ - - switch ( m_to9_kbd_byte_count ) - { - case 0: /* key */ - to9_kbd_send( to9_kbd_get_key(), 0 ); - break; - - case 1: /* x axis */ - { - int newx = m_io_mouse_x->read(); - uint8_t data = ( (newx - m_to9_mouse_x) & 0xf ) - 8; - to9_kbd_send( data, 1 ); - m_to9_mouse_x = newx; - break; - } - - case 2: /* y axis */ - { - int newy = m_io_mouse_y->read(); - uint8_t data = ( (newy - m_to9_mouse_y) & 0xf ) - 8; - to9_kbd_send( data, 1 ); - m_to9_mouse_y = newy; - break; - } - - case 3: /* axis overflow & buttons */ - { - int b = m_io_mouse_button->read(); - uint8_t data = 0; - if ( b & 1 ) data |= 1; - if ( b & 2 ) data |= 4; - to9_kbd_send( data, 1 ); - break; - } - - } - - m_to9_kbd_byte_count = ( m_to9_kbd_byte_count + 1 ) & 3; - m_to9_kbd_timer->adjust(m_to9_kbd_byte_count ? TO9_KBD_BYTE_SPACE : TO9_KBD_END_SPACE); - } - else - { - int key = to9_kbd_get_key(); - /* keyboard mode: send a byte only if a key is down */ - if ( key ) - to9_kbd_send( key, 0 ); - m_to9_kbd_timer->adjust(TO9_KBD_POLL_PERIOD); - } -} - - - -void to9_state::to9_kbd_reset() -{ - LOG("to9_kbd_reset called\n"); - m_to9_kbd_overrun = 0; /* no byte lost */ - m_to9_kbd_status = ACIA_6850_TDRE; /* clear to transmit */ - m_to9_kbd_intr = 0; /* interrupt disabled */ - m_to9_kbd_caps = 1; - m_to9_kbd_periph = 0; - m_to9_kbd_pad = 0; - m_to9_kbd_byte_count = 0; - m_caps_led = !m_to9_kbd_caps; - m_to9_kbd_key_count = 0; - m_to9_kbd_last_key = 0xff; - to9_kbd_update_irq(); - m_to9_kbd_timer->adjust(TO9_KBD_POLL_PERIOD); -} - - - -void to9_state::to9_kbd_init() -{ - LOG("to9_kbd_init called\n"); - m_to9_kbd_timer = timer_alloc(FUNC(to9_state::to9_kbd_timer_cb), this); - save_item(NAME(m_to9_kbd_parity)); - save_item(NAME(m_to9_kbd_intr)); - save_item(NAME(m_to9_kbd_in)); - save_item(NAME(m_to9_kbd_status)); - save_item(NAME(m_to9_kbd_overrun)); - save_item(NAME(m_to9_kbd_last_key)); - save_item(NAME(m_to9_kbd_key_count)); - save_item(NAME(m_to9_kbd_caps)); - save_item(NAME(m_to9_kbd_periph)); - save_item(NAME(m_to9_kbd_pad)); - save_item(NAME(m_to9_kbd_byte_count)); - save_item(NAME(m_to9_mouse_x)); - save_item(NAME(m_to9_mouse_y)); -} - - /* ------------ system PIA 6821 ------------ */ uint8_t to9_state::to9_sys_porta_in() { - uint8_t ktest = to9_kbd_ktest(); + uint8_t ktest = m_to9_kbd->ktest_r(); LOGMASKED(LOG_KBD, "to9_sys_porta_in: ktest=%i\n", ktest); @@ -2192,7 +1739,6 @@ MACHINE_RESET_MEMBER( to9_state, to9 ) /* subsystems */ thom_irq_reset(); to7_game_reset(); - to9_kbd_reset(); m_extension->rom_map(m_maincpu->space(AS_PROGRAM), 0xe000, 0xe7bf); m_extension->io_map (m_maincpu->space(AS_PROGRAM), 0xe7c0, 0xe7ff); @@ -2229,7 +1775,6 @@ MACHINE_START_MEMBER( to9_state, to9 ) /* subsystems */ to7_game_init(); - to9_kbd_init(); to9_palette_init(); m_extension->rom_map(m_maincpu->space(AS_PROGRAM), 0xe000, 0xe7bf); @@ -2264,318 +1809,6 @@ MACHINE_START_MEMBER( to9_state, to9 ) /***************************** TO8 *************************/ -/* ------------ keyboard (6804) ------------ */ - -/* The 6804 chip scans the keyboard and sends keycodes to the 6809. - Data is serialized using variable pulse length encoding. - Unlike the TO9, there is no decoding chip on the 6809 side, only - 1-bit PIA ports (6821 & 6846). The 6809 does the decoding. - - We do not emulate the 6804 but pass serialized data directly through the - PIA ports. - - Note: if we conform to the (scarce) documentation the CPU tend to lock - waiting for keyboard input. - The protocol documentation is pretty scarce and does not account for these - behaviors! - The emulation code contains many hacks (delays, timeouts, spurious - pulses) to improve the stability. - This works well, but is not very accurate. -*/ - - - -/* polling interval */ -#define TO8_KBD_POLL_PERIOD attotime::from_msec( 1 ) - -/* first and subsequent repeat periods, in TO8_KBD_POLL_PERIOD units */ -#define TO8_KBD_REPEAT_DELAY 800 /* 800 ms */ -#define TO8_KBD_REPEAT_PERIOD 70 /* 70 ms */ - -/* timeout waiting for CPU */ -#define TO8_KBD_TIMEOUT attotime::from_msec( 100 ) - - - -/* quick keyboard scan */ -int to9_state::to8_kbd_ktest() -{ - int line, bit; - uint8_t port; - - if ( m_io_config->read() & 2 ) - return 0; /* disabled */ - - for ( line = 0; line < 10; line++ ) - { - port = m_io_keyboard[line]->read(); - - if ( line == 7 || line == 9 ) - port |= 1; /* shift & control */ - - for ( bit = 0; bit < 8; bit++ ) - { - if ( ! (port & (1 << bit)) ) - return 1; - } - } - - return 0; -} - - - -/* keyboard scan & return keycode (or -1) */ -int to9_state::to8_kbd_get_key() -{ - int control = (m_io_keyboard[7]->read() & 1) ? 0 : 0x100; - int shift = (m_io_keyboard[9]->read() & 1) ? 0 : 0x080; - int key = -1, line, bit; - uint8_t port; - - if ( m_io_config->read() & 2 ) - return -1; /* disabled */ - - for ( line = 0; line < 10; line++ ) - { - port = m_io_keyboard[line]->read(); - - if ( line == 7 || line == 9 ) - port |= 1; /* shift & control */ - - /* TODO: correct handling of simultaneous keystokes: - return the new key preferably & disable repeat - */ - for ( bit = 0; bit < 8; bit++ ) - { - if ( ! (port & (1 << bit)) ) - key = line * 8 + bit; - } - } - - if ( key == -1 ) - { - m_to8_kbd_last_key = 0xff; - m_to8_kbd_key_count = 0; - return -1; - } - else if ( key == 64 ) - { - /* caps lock */ - if ( m_to8_kbd_last_key == key ) - return -1; /* no repeat */ - m_to8_kbd_last_key = key; - m_to8_kbd_caps = !m_to8_kbd_caps; - if ( m_to8_kbd_caps ) - key |= 0x080; /* auto-shift */ - m_caps_led = !m_to8_kbd_caps; - return key; - } - else if ( key == m_to8_kbd_last_key ) - { - /* repeat */ - m_to8_kbd_key_count++; - if ( m_to8_kbd_key_count < TO8_KBD_REPEAT_DELAY || (m_to8_kbd_key_count - TO8_KBD_REPEAT_DELAY) % TO8_KBD_REPEAT_PERIOD ) - return -1; - return key | shift | control; - } - else - { - m_to8_kbd_last_key = key; - m_to8_kbd_key_count = 0; - return key | shift | control; - } -} - - -/* steps: - 0 = idle, key polling - 1 = wait for ack to go down (key to send) - 99-117 = key data transmit - 91-117 = signal - 255 = timeout -*/ - -/* keyboard automaton */ -void to9_state::to8_kbd_timer_func() -{ - attotime d; - - LOGMASKED(LOG_KBD, "%f to8_kbd_timer_cb: step=%i ack=%i data=$%03X\n", machine().time().as_double(), m_to8_kbd_step, m_to8_kbd_ack, m_to8_kbd_data); - - if( ! m_to8_kbd_step ) - { - /* key polling */ - int k = to8_kbd_get_key(); - /* if not in transfer, send pulse from time to time - (helps avoiding CPU lock) - */ - if ( ! m_to8_kbd_ack ) - m_mc6846->set_input_cp1(0); - m_mc6846->set_input_cp1(1); - - if ( k == -1 ) - d = TO8_KBD_POLL_PERIOD; - else - { - /* got key! */ - LOGMASKED(LOG_KBD, "to8_kbd_timer_cb: got key $%03X\n", k); - m_to8_kbd_data = k; - m_to8_kbd_step = 1; - d = attotime::from_usec( 100 ); - } - } - else if ( m_to8_kbd_step == 255 ) - { - /* timeout */ - m_to8_kbd_last_key = 0xff; - m_to8_kbd_key_count = 0; - m_to8_kbd_step = 0; - m_mc6846->set_input_cp1(1); - d = TO8_KBD_POLL_PERIOD; - } - else if ( m_to8_kbd_step == 1 ) - { - /* schedule timeout waiting for ack to go down */ - m_mc6846->set_input_cp1(0); - m_to8_kbd_step = 255; - d = TO8_KBD_TIMEOUT; - } - else if ( m_to8_kbd_step == 117 ) - { - /* schedule timeout waiting for ack to go up */ - m_mc6846->set_input_cp1(0); - m_to8_kbd_step = 255; - d = TO8_KBD_TIMEOUT; - } - else if ( m_to8_kbd_step & 1 ) - { - /* send silence between bits */ - m_mc6846->set_input_cp1(0); - d = attotime::from_usec( 100 ); - m_to8_kbd_step++; - } - else - { - /* send bit */ - int bpos = 8 - ( (m_to8_kbd_step - 100) / 2); - int bit = (m_to8_kbd_data >> bpos) & 1; - m_mc6846->set_input_cp1(1); - d = attotime::from_usec( bit ? 56 : 38 ); - m_to8_kbd_step++; - } - m_to8_kbd_timer->adjust(d); -} - - - -TIMER_CALLBACK_MEMBER(to9_state::to8_kbd_timer_cb) -{ - to8_kbd_timer_func(); -} - - - -/* cpu <-> keyboard hand-check */ -void to9_state::to8_kbd_set_ack( int data ) -{ - if ( data == m_to8_kbd_ack ) - return; - m_to8_kbd_ack = data; - - if ( data ) - { - double len = m_to8_kbd_signal->elapsed( ).as_double() * 1000. - 2.; - LOGMASKED(LOG_KBD, "%f to8_kbd_set_ack: CPU end ack, len=%f\n", machine().time().as_double(), len); - if ( m_to8_kbd_data == 0xfff ) - { - /* end signal from CPU */ - if ( len >= 0.6 && len <= 0.8 ) - { - LOG("%f to8_kbd_set_ack: INIT signal\n", machine().time().as_double()); - m_to8_kbd_last_key = 0xff; - m_to8_kbd_key_count = 0; - m_to8_kbd_caps = 1; - /* send back signal: TODO returned codes ? */ - m_to8_kbd_data = 0; - m_to8_kbd_step = 0; - m_to8_kbd_timer->adjust(attotime::from_msec( 1 )); - } - else - { - m_to8_kbd_step = 0; - m_to8_kbd_timer->adjust(TO8_KBD_POLL_PERIOD); - if ( len >= 1.2 && len <= 1.4 ) - { - LOG("%f to8_kbd_set_ack: CAPS on signal\n", machine().time().as_double()); - m_to8_kbd_caps = 1; - } - else if ( len >= 1.8 && len <= 2.0 ) - { - LOG("%f to8_kbd_set_ack: CAPS off signal\n", machine().time().as_double()); - m_to8_kbd_caps = 0; - } - } - m_caps_led = !m_to8_kbd_caps; - } - else - { - /* end key transmission */ - m_to8_kbd_step = 0; - m_to8_kbd_timer->adjust(TO8_KBD_POLL_PERIOD); - } - } - - else - { - if ( m_to8_kbd_step == 255 ) - { - /* CPU accepts key */ - m_to8_kbd_step = 99; - m_to8_kbd_timer->adjust(attotime::from_usec( 400 )); - } - else - { - /* start signal from CPU */ - m_to8_kbd_data = 0xfff; - m_to8_kbd_step = 91; - m_to8_kbd_timer->adjust(attotime::from_usec( 400 )); - m_to8_kbd_signal->adjust(attotime::never); - } - LOGMASKED(LOG_KBD, "%f to8_kbd_set_ack: CPU ack, data=$%03X\n", machine().time().as_double(), m_to8_kbd_data); - } -} - - - -void to9_state::to8_kbd_reset() -{ - m_to8_kbd_last_key = 0xff; - m_to8_kbd_key_count = 0; - m_to8_kbd_step = 0; - m_to8_kbd_data = 0; - m_to8_kbd_ack = 1; - m_to8_kbd_caps = 1; - m_caps_led = !m_to8_kbd_caps; - to8_kbd_timer_func(); -} - - - -void to9_state::to8_kbd_init() -{ - m_to8_kbd_timer = timer_alloc(FUNC(to9_state::to8_kbd_timer_cb), this); - m_to8_kbd_signal = machine().scheduler().timer_alloc(timer_expired_delegate()); - save_item(NAME(m_to8_kbd_ack)); - save_item(NAME(m_to8_kbd_data)); - save_item(NAME(m_to8_kbd_step)); - save_item(NAME(m_to8_kbd_last_key)); - save_item(NAME(m_to8_kbd_key_count)); - save_item(NAME(m_to8_kbd_caps)); -} - - - /* ------------ RAM / ROM banking ------------ */ void to9_state::to8_update_ram_bank() @@ -3006,7 +2239,7 @@ void to9_state::to8_vreg_w(offs_t offset, uint8_t data) uint8_t to9_state::to8_sys_porta_in() { - int ktest = to8_kbd_ktest(); + int ktest = m_to8_kbd->ktest_r(); LOGMASKED(LOG_KBD, "$%04x %f: to8_sys_porta_in ktest=%i\n", m_maincpu->pc(), machine().time().as_double(), ktest); @@ -3042,7 +2275,7 @@ uint8_t to9_state::to8_timer_port_in() int lightpen = (m_io_lightpen_button->read() & 1) ? 2 : 0; int cass = to7_get_cassette() ? 0x80 : 0; int dtr = m_centronics_busy << 6; - int lock = m_to8_kbd_caps ? 0 : 8; /* undocumented! */ + int lock = m_to8_kbd->caps_r() ? 0 : 8; /* undocumented! */ return lightpen | cass | dtr | lock; } @@ -3056,7 +2289,7 @@ void to9_state::to8_timer_port_out(uint8_t data) m_biosbank->set_entry( m_to8_bios_bank ); m_to8_soft_select = (data & 0x04) ? 1 : 0; /* bit 2: internal ROM select */ to8_update_cart_bank(); - to8_kbd_set_ack(ack); + m_to8_kbd->set_ack(ack); } @@ -3096,7 +2329,6 @@ MACHINE_RESET_MEMBER( to9_state, to8 ) /* subsystems */ thom_irq_reset(); to7_game_reset(); - to8_kbd_reset(); /* gate-array */ m_to7_lightpen = 0; @@ -3141,7 +2373,6 @@ MACHINE_START_MEMBER( to9_state, to8 ) /* subsystems */ to7_game_init(); - to8_kbd_init(); to9_palette_init(); m_extension->rom_map(m_maincpu->space(AS_PROGRAM), 0xe000, 0xe7bf); @@ -3241,7 +2472,6 @@ MACHINE_RESET_MEMBER( to9_state, to9p ) /* subsystems */ thom_irq_reset(); to7_game_reset(); - to9_kbd_reset(); /* gate-array */ m_to7_lightpen = 0; @@ -3285,7 +2515,6 @@ MACHINE_START_MEMBER( to9_state, to9p ) /* subsystems */ to7_game_init(); - to9_kbd_init(); to9_palette_init(); m_extension->rom_map(m_maincpu->space(AS_PROGRAM), 0xe000, 0xe7bf); diff --git a/src/mame/thomson/to_kbd.cpp b/src/mame/thomson/to_kbd.cpp new file mode 100644 index 0000000000000..daf653db12c78 --- /dev/null +++ b/src/mame/thomson/to_kbd.cpp @@ -0,0 +1,999 @@ +// license:BSD-3-Clause +// copyright-holders:Antoine Mine +/********************************************************************** + + Copyright (C) Antoine Mine' 2006 + + Thomson TO8 built-in keyboard & TO9 detached keyboard + +**********************************************************************/ + +#include "emu.h" +#include "to_kbd.h" + +#include "cpu/m6805/m68705.h" + +#define LOG_KBD (1U << 1) +#define LOG_ERRORS (1U << 2) + +#define VERBOSE (LOG_KBD | LOG_ERRORS) +#include "logmacro.h" + + +// device type definitions +DEFINE_DEVICE_TYPE(TO8_KEYBOARD, to8_keyboard_device, "to8_kbd", "Thomson TO8 keyboard") +DEFINE_DEVICE_TYPE(TO9_KEYBOARD, to9_keyboard_device, "to9_kbd", "Thomson TO9 keyboard") +DEFINE_DEVICE_TYPE(TO9P_KEYBOARD, to9p_keyboard_device, "to9p_kbd", "Thomson TO9+ keyboard") + +to8_keyboard_device::to8_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, TO8_KEYBOARD, tag, owner, clock) + , m_data_cb(*this) + , m_io_keyboard(*this, "keyboard.%u", 0) + , m_caps_led(*this, "led0") +{ +} + +to9_keyboard_device::to9_keyboard_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , m_irq_cb(*this) + , m_io_keyboard(*this, "keyboard.%u", 0) + , m_io_mouse_x(*this, "mouse_x") + , m_io_mouse_y(*this, "mouse_y") + , m_io_mouse_button(*this, "mouse_button") + , m_caps_led(*this, "led0") +{ +} + +to9_keyboard_device::to9_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : to9_keyboard_device(mconfig, TO9_KEYBOARD, tag, owner, clock) +{ +} + +to9p_keyboard_device::to9p_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : to9_keyboard_device(mconfig, TO9P_KEYBOARD, tag, owner, clock) +{ +} + +void to8_keyboard_device::device_add_mconfig(machine_config &config) +{ + //MC6804P2(config, "mcu", 11_MHz_XTAL).set_disable(); +} + +void to9_keyboard_device::device_add_mconfig(machine_config &config) +{ + M6805U2(config, "mcu", 4_MHz_XTAL).set_disable(); // 40 pins, actual model unknown +} + +void to9p_keyboard_device::device_add_mconfig(machine_config &config) +{ + M6805P2(config, "mcu", 4_MHz_XTAL).set_disable(); +} + +ROM_START(to8_kbd) + ROM_REGION(0x440, "mcu", 0) + ROM_LOAD("ef6804p2p_clav--to8.bin", 0x000, 0x440, NO_DUMP) +ROM_END + +ROM_START(to9_kbd) + ROM_REGION(0x1000, "mcu", 0) + ROM_LOAD("6805.bin", 0x0000, 0x1000, NO_DUMP) +ROM_END + +ROM_START(to9p_kbd) + ROM_REGION(0x800, "mcu", 0) + ROM_LOAD("6805p2.bin", 0x000, 0x800, NO_DUMP) +ROM_END + +const tiny_rom_entry *to8_keyboard_device::device_rom_region() const +{ + return ROM_NAME(to8_kbd); +} + +const tiny_rom_entry *to9_keyboard_device::device_rom_region() const +{ + return ROM_NAME(to9_kbd); +} + +const tiny_rom_entry *to9p_keyboard_device::device_rom_region() const +{ + return ROM_NAME(to9p_kbd); +} + + +/* ------------ inputs ------------ */ + +#define KEY(pos,name,key) \ + PORT_BIT ( 1<<(pos), IP_ACTIVE_LOW, IPT_KEYBOARD ) \ + PORT_NAME ( name ) \ + PORT_CODE ( KEYCODE_##key ) + +static INPUT_PORTS_START ( to8_keyboard ) + PORT_START ( "keyboard.0" ) + KEY ( 0, "F2 F7", F2 ) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_CHAR(UCHAR_MAMEKEY(F7)) + KEY ( 1, "_ 6", 6 ) PORT_CHAR('_') PORT_CHAR('6') + KEY ( 2, "Y", Y ) PORT_CHAR('Y') + KEY ( 3, "H", H ) PORT_CHAR('H') + KEY ( 4, u8"\u2191", UP ) PORT_CHAR(UCHAR_MAMEKEY(UP)) + KEY ( 5, u8"\u2192", RIGHT ) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) + KEY ( 6, "Home Clear", HOME ) PORT_CHAR(UCHAR_MAMEKEY(HOME)) PORT_CHAR(UCHAR_MAMEKEY(ESC)) + KEY ( 7, "N", N ) PORT_CHAR('N') + PORT_START ( "keyboard.1" ) + KEY ( 0, "F3 F8", F3 ) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CHAR(UCHAR_MAMEKEY(F8)) + KEY ( 1, "( 5", 5 ) PORT_CHAR('(') PORT_CHAR('5') + KEY ( 2, "T", T ) PORT_CHAR('T') + KEY ( 3, "G", G ) PORT_CHAR('G') + KEY ( 4, "= +", EQUALS ) PORT_CHAR('=') PORT_CHAR('+') + KEY ( 5, "\u2190", LEFT ) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) + KEY ( 6, "Insert", INSERT ) PORT_CHAR(UCHAR_MAMEKEY(INSERT)) + KEY ( 7, "B", B ) PORT_CHAR('B') + PORT_START ( "keyboard.2" ) + KEY ( 0, "F4 F9", F4 ) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_CHAR(UCHAR_MAMEKEY(F9)) + KEY ( 1, "' 4", 4 ) PORT_CHAR('\'') PORT_CHAR('4') + KEY ( 2, "R", R ) PORT_CHAR('R') + KEY ( 3, "F", F ) PORT_CHAR('F') + KEY ( 4, "Accent", END ) PORT_CHAR(UCHAR_MAMEKEY(END)) + KEY ( 5, "Keypad 1", 1_PAD ) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) + KEY ( 6, "Delete Backspace", DEL ) PORT_CHAR(8) PORT_CHAR(UCHAR_MAMEKEY(BACKSPACE)) + KEY ( 7, "V", V ) PORT_CHAR('V') + PORT_START ( "keyboard.3" ) + KEY ( 0, "F5 F10", F5 ) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_CHAR(UCHAR_MAMEKEY(F10)) + KEY ( 1, "\" 3", 3 ) PORT_CHAR('"') PORT_CHAR('3') + KEY ( 2, "E", E ) PORT_CHAR('E') + KEY ( 3, "D", D ) PORT_CHAR('D') + KEY ( 4, "Keypad 7", 7_PAD ) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) + KEY ( 5, "Keypad 4", 4_PAD ) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) + KEY ( 6, "Keypad 0", 0_PAD ) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) + KEY ( 7, "C \136", C ) PORT_CHAR('C') + PORT_START ( "keyboard.4" ) + KEY ( 0, "F1 F6", F1 ) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CHAR(UCHAR_MAMEKEY(F6)) + KEY ( 1, u8"é 2", 2 ) PORT_CHAR( 0xe9 ) PORT_CHAR('2') + KEY ( 2, "Z", Z ) PORT_CHAR('Z') + KEY ( 3, "S", S ) PORT_CHAR('S') + KEY ( 4, "Keypad 8", 8_PAD ) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) + KEY ( 5, "Keypad 2", 2_PAD ) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) + KEY ( 6, "Keypad .", DEL_PAD ) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) + KEY ( 7, "X", X ) PORT_CHAR('X') + PORT_START ( "keyboard.5" ) + KEY ( 0, "# @", TILDE ) PORT_CHAR('#') PORT_CHAR('@') + KEY ( 1, "* 1", 1 ) PORT_CHAR('*') PORT_CHAR('1') + KEY ( 2, "A \140", A ) PORT_CHAR('A') + KEY ( 3, "Q", Q ) PORT_CHAR('Q') + KEY ( 4, "[ {", QUOTE ) PORT_CHAR('[') PORT_CHAR('{') + KEY ( 5, "Keypad 5", 5_PAD ) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) + KEY ( 6, "Keypad 6", 6_PAD ) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) + KEY ( 7, "W", W ) PORT_CHAR('W') + PORT_START ( "keyboard.6" ) + KEY ( 0, "Stop", TAB ) PORT_CHAR(27) + KEY ( 1, u8"è 7", 7 ) PORT_CHAR( 0xe8 ) PORT_CHAR('7') + KEY ( 2, "U", U ) PORT_CHAR('U') + KEY ( 3, "J", J ) PORT_CHAR('J') + KEY ( 4, "Space", SPACE ) PORT_CHAR(' ') + KEY ( 5, "Keypad 9", 9_PAD ) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) + KEY ( 6, "Keypad Enter", ENTER_PAD ) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) + KEY ( 7, ", ?", COMMA ) PORT_CHAR(',') PORT_CHAR('?') + PORT_START ( "keyboard.7" ) + KEY ( 0, "Control", LCONTROL ) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) + KEY ( 1, "! 8", 8 ) PORT_CHAR('!') PORT_CHAR('8') + KEY ( 2, "I", I ) PORT_CHAR('I') + KEY ( 3, "K", K ) PORT_CHAR('K') + KEY ( 4, "$ &", CLOSEBRACE ) PORT_CHAR('$') PORT_CHAR('&') + KEY ( 5, u8"\u2193", DOWN ) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) + KEY ( 6, "] }", BACKSLASH ) PORT_CHAR(']') PORT_CHAR('}') + KEY ( 7, "; .", STOP ) PORT_CHAR(';') PORT_CHAR('.') + PORT_START ( "keyboard.8" ) + KEY ( 0, "Caps-Lock", CAPSLOCK ) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) + KEY ( 1, u8"ç 9", 9 ) PORT_CHAR( 0xe7 ) PORT_CHAR('9') + KEY ( 2, "O", O ) PORT_CHAR('O') + KEY ( 3, "L", L ) PORT_CHAR('L') + KEY ( 4, "- \\", BACKSPACE ) PORT_CHAR('-') PORT_CHAR('\\') + KEY ( 5, u8"ù %", COLON ) PORT_CHAR( 0xf9 ) PORT_CHAR('%') + KEY ( 6, "Enter", ENTER ) PORT_CHAR(13) + KEY ( 7, ": /", SLASH ) PORT_CHAR(':') PORT_CHAR('/') + PORT_START ( "keyboard.9" ) + KEY ( 0, "Shift", LSHIFT ) PORT_CODE ( KEYCODE_RSHIFT ) PORT_CHAR(UCHAR_SHIFT_1) + KEY ( 1, u8"à 0", 0 ) PORT_CHAR( 0xe0 ) PORT_CHAR('0') + KEY ( 2, "P", P ) PORT_CHAR('P') + KEY ( 3, "M", M ) PORT_CHAR('M') + KEY ( 4, u8") °", MINUS ) PORT_CHAR(')') PORT_CHAR( 0xb0 ) + KEY ( 5, u8"^ ¨", OPENBRACE ) PORT_CHAR('^') PORT_CHAR( 0xa8 ) + KEY ( 6, "Keypad 3", 3_PAD ) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) + KEY ( 7, "> <", BACKSLASH2 ) PORT_CHAR('>') PORT_CHAR('<') +INPUT_PORTS_END + +static INPUT_PORTS_START ( to9_keyboard ) + PORT_INCLUDE( to8_keyboard ) + + PORT_START ( "mouse_x" ) + PORT_BIT ( 0xffff, 0x00, IPT_MOUSE_X ) + PORT_NAME ( "Mouse X" ) + PORT_SENSITIVITY ( 150 ) + PORT_PLAYER (1) + + PORT_START ( "mouse_y" ) + PORT_BIT ( 0xffff, 0x00, IPT_MOUSE_Y ) + PORT_NAME ( "Mouse Y" ) + PORT_SENSITIVITY ( 150 ) + PORT_PLAYER (1) + + PORT_START ( "mouse_button" ) + PORT_BIT ( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) + PORT_NAME ( "Left Mouse Button" ) + PORT_CODE( MOUSECODE_BUTTON1 ) + PORT_BIT ( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) + PORT_NAME ( "Right Mouse Button" ) +INPUT_PORTS_END + +ioport_constructor to8_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(to8_keyboard); +} + +ioport_constructor to9_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(to9_keyboard); +} + +ioport_constructor to9p_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(to8_keyboard); +} + + +/* ------------ keyboard (6804) ------------ */ + +/* The 6804 chip scans the keyboard and sends keycodes to the 6809. + Data is serialized using variable pulse length encoding. + Unlike the TO9, there is no decoding chip on the 6809 side, only + 1-bit PIA ports (6821 & 6846). The 6809 does the decoding. + + We do not emulate the 6804 but pass serialized data directly through the + PIA ports. + + Note: if we conform to the (scarce) documentation the CPU tend to lock + waiting for keyboard input. + The protocol documentation is pretty scarce and does not account for these + behaviors! + The emulation code contains many hacks (delays, timeouts, spurious + pulses) to improve the stability. + This works well, but is not very accurate. +*/ + + + +/* polling interval */ +#define TO8_KBD_POLL_PERIOD attotime::from_msec( 1 ) + +/* first and subsequent repeat periods, in TO8_KBD_POLL_PERIOD units */ +#define TO8_KBD_REPEAT_DELAY 800 /* 800 ms */ +#define TO8_KBD_REPEAT_PERIOD 70 /* 70 ms */ + +/* timeout waiting for CPU */ +#define TO8_KBD_TIMEOUT attotime::from_msec( 100 ) + + + +/* quick keyboard scan */ +int to8_keyboard_device::ktest_r() +{ + int line, bit; + uint8_t port; + + for ( line = 0; line < 10; line++ ) + { + port = m_io_keyboard[line]->read(); + + if ( line == 7 || line == 9 ) + port |= 1; /* shift & control */ + + for ( bit = 0; bit < 8; bit++ ) + { + if ( ! (port & (1 << bit)) ) + return 1; + } + } + + return 0; +} + + + +/* keyboard scan & return keycode (or -1) */ +int to8_keyboard_device::get_key() +{ + int control = (m_io_keyboard[7]->read() & 1) ? 0 : 0x100; + int shift = (m_io_keyboard[9]->read() & 1) ? 0 : 0x080; + int key = -1, line, bit; + uint8_t port; + + for ( line = 0; line < 10; line++ ) + { + port = m_io_keyboard[line]->read(); + + if ( line == 7 || line == 9 ) + port |= 1; /* shift & control */ + + /* TODO: correct handling of simultaneous keystokes: + return the new key preferably & disable repeat + */ + for ( bit = 0; bit < 8; bit++ ) + { + if ( ! (port & (1 << bit)) ) + key = line * 8 + bit; + } + } + + if ( key == -1 ) + { + m_kbd_last_key = 0xff; + m_kbd_key_count = 0; + return -1; + } + else if ( key == 64 ) + { + /* caps lock */ + if ( m_kbd_last_key == key ) + return -1; /* no repeat */ + m_kbd_last_key = key; + m_kbd_caps = !m_kbd_caps; + if ( m_kbd_caps ) + key |= 0x080; /* auto-shift */ + m_caps_led = !m_kbd_caps; + return key; + } + else if ( key == m_kbd_last_key ) + { + /* repeat */ + m_kbd_key_count++; + if ( m_kbd_key_count < TO8_KBD_REPEAT_DELAY || (m_kbd_key_count - TO8_KBD_REPEAT_DELAY) % TO8_KBD_REPEAT_PERIOD ) + return -1; + return key | shift | control; + } + else + { + m_kbd_last_key = key; + m_kbd_key_count = 0; + return key | shift | control; + } +} + + +/* steps: + 0 = idle, key polling + 1 = wait for ack to go down (key to send) + 99-117 = key data transmit + 91-117 = signal + 255 = timeout +*/ + +/* keyboard automaton */ +void to8_keyboard_device::timer_func() +{ + attotime d; + + LOGMASKED(LOG_KBD, "%f timer_func: step=%i ack=%i data=$%03X\n", machine().time().as_double(), m_kbd_step, m_kbd_ack, m_kbd_data); + + if( ! m_kbd_step ) + { + /* key polling */ + int k = get_key(); + /* if not in transfer, send pulse from time to time + (helps avoiding CPU lock) + */ + if ( ! m_kbd_ack ) + m_data_cb(0); + m_data_cb(1); + + if ( k == -1 ) + d = TO8_KBD_POLL_PERIOD; + else + { + /* got key! */ + LOGMASKED(LOG_KBD, "timer_func: got key $%03X\n", k); + m_kbd_data = k; + m_kbd_step = 1; + d = attotime::from_usec( 100 ); + } + } + else if ( m_kbd_step == 255 ) + { + /* timeout */ + m_kbd_last_key = 0xff; + m_kbd_key_count = 0; + m_kbd_step = 0; + m_data_cb(1); + d = TO8_KBD_POLL_PERIOD; + } + else if ( m_kbd_step == 1 ) + { + /* schedule timeout waiting for ack to go down */ + m_data_cb(0); + m_kbd_step = 255; + d = TO8_KBD_TIMEOUT; + } + else if ( m_kbd_step == 117 ) + { + /* schedule timeout waiting for ack to go up */ + m_data_cb(0); + m_kbd_step = 255; + d = TO8_KBD_TIMEOUT; + } + else if ( m_kbd_step & 1 ) + { + /* send silence between bits */ + m_data_cb(0); + d = attotime::from_usec( 100 ); + m_kbd_step++; + } + else + { + /* send bit */ + int bpos = 8 - ( (m_kbd_step - 100) / 2); + int bit = (m_kbd_data >> bpos) & 1; + m_data_cb(1); + d = attotime::from_usec( bit ? 56 : 38 ); + m_kbd_step++; + } + m_kbd_timer->adjust(d); +} + + + +TIMER_CALLBACK_MEMBER(to8_keyboard_device::timer_cb) +{ + timer_func(); +} + + + +/* cpu <-> keyboard hand-check */ +void to8_keyboard_device::set_ack( int data ) +{ + if ( data == m_kbd_ack ) + return; + m_kbd_ack = data; + + if ( data ) + { + double len = m_kbd_signal->elapsed( ).as_double() * 1000. - 2.; + LOGMASKED(LOG_KBD, "%f set_ack: CPU end ack, len=%f\n", machine().time().as_double(), len); + if ( m_kbd_data == 0xfff ) + { + /* end signal from CPU */ + if ( len >= 0.6 && len <= 0.8 ) + { + LOG("%f set_ack: INIT signal\n", machine().time().as_double()); + m_kbd_last_key = 0xff; + m_kbd_key_count = 0; + m_kbd_caps = 1; + /* send back signal: TODO returned codes ? */ + m_kbd_data = 0; + m_kbd_step = 0; + m_kbd_timer->adjust(attotime::from_msec( 1 )); + } + else + { + m_kbd_step = 0; + m_kbd_timer->adjust(TO8_KBD_POLL_PERIOD); + if ( len >= 1.2 && len <= 1.4 ) + { + LOG("%f set_ack: CAPS on signal\n", machine().time().as_double()); + m_kbd_caps = 1; + } + else if ( len >= 1.8 && len <= 2.0 ) + { + LOG("%f set_ack: CAPS off signal\n", machine().time().as_double()); + m_kbd_caps = 0; + } + } + m_caps_led = !m_kbd_caps; + } + else + { + /* end key transmission */ + m_kbd_step = 0; + m_kbd_timer->adjust(TO8_KBD_POLL_PERIOD); + } + } + + else + { + if ( m_kbd_step == 255 ) + { + /* CPU accepts key */ + m_kbd_step = 99; + m_kbd_timer->adjust(attotime::from_usec( 400 )); + } + else + { + /* start signal from CPU */ + m_kbd_data = 0xfff; + m_kbd_step = 91; + m_kbd_timer->adjust(attotime::from_usec( 400 )); + m_kbd_signal->adjust(attotime::never); + } + LOGMASKED(LOG_KBD, "%f set_ack: CPU ack, data=$%03X\n", machine().time().as_double(), m_kbd_data); + } +} + + + +void to8_keyboard_device::device_reset() +{ + m_kbd_last_key = 0xff; + m_kbd_key_count = 0; + m_kbd_step = 0; + m_kbd_data = 0; + m_kbd_ack = 1; + m_kbd_caps = 1; + m_caps_led = !m_kbd_caps; + timer_func(); +} + + + +void to8_keyboard_device::device_start() +{ + m_caps_led.resolve(); + + m_kbd_timer = timer_alloc(FUNC(to8_keyboard_device::timer_cb), this); + m_kbd_signal = machine().scheduler().timer_alloc(timer_expired_delegate()); + save_item(NAME(m_kbd_ack)); + save_item(NAME(m_kbd_data)); + save_item(NAME(m_kbd_step)); + save_item(NAME(m_kbd_last_key)); + save_item(NAME(m_kbd_key_count)); + save_item(NAME(m_kbd_caps)); +} + + + +/* ------------ 6850 defines ------------ */ + +#define ACIA_6850_RDRF 0x01 /* Receive data register full */ +#define ACIA_6850_TDRE 0x02 /* Transmit data register empty */ +#define ACIA_6850_dcd 0x04 /* Data carrier detect, active low */ +#define ACIA_6850_cts 0x08 /* Clear to send, active low */ +#define ACIA_6850_FE 0x10 /* Framing error */ +#define ACIA_6850_OVRN 0x20 /* Receiver overrun */ +#define ACIA_6850_PE 0x40 /* Parity error */ +#define ACIA_6850_irq 0x80 /* Interrupt request, active low */ + + + +/* ------------ keyboard (6850 ACIA + 6805 CPU) ------------ */ + +/* The 6805 chip scans the keyboard and sends ASCII codes to the 6909. + Data between the 6809 and 6805 is serialized at 9600 bauds. + On the 6809 side, a 6850 ACIA is used. + We do not emulate the seral line but pass bytes directly between the + keyboard and the 6850 registers. + Note that the keyboard protocol uses the parity bit as an extra data bit. +*/ + + + +/* normal mode: polling interval */ +#define TO9_KBD_POLL_PERIOD attotime::from_msec( 10 ) + +/* peripheral mode: time between two bytes, and after last byte */ +#define TO9_KBD_BYTE_SPACE attotime::from_usec( 300 ) +#define TO9_KBD_END_SPACE attotime::from_usec( 9100 ) + +/* first and subsequent repeat periods, in TO9_KBD_POLL_PERIOD units */ +#define TO9_KBD_REPEAT_DELAY 80 /* 800 ms */ +#define TO9_KBD_REPEAT_PERIOD 7 /* 70 ms */ + + + +/* quick keyboard scan */ +int to9_keyboard_device::ktest_r() +{ + int line, bit; + uint8_t port; + + for ( line = 0; line < 10; line++ ) + { + port = m_io_keyboard[line]->read(); + + if ( line == 7 || line == 9 ) + port |= 1; /* shift & control */ + + for ( bit = 0; bit < 8; bit++ ) + { + if ( ! (port & (1 << bit)) ) + return 1; + } + } + return 0; +} + + + +void to9_keyboard_device::update_irq() +{ + if ( (m_kbd_intr & 4) && (m_kbd_status & ACIA_6850_RDRF) ) + m_kbd_status |= ACIA_6850_irq; /* byte received interrupt */ + + if ( (m_kbd_intr & 4) && (m_kbd_status & ACIA_6850_OVRN) ) + m_kbd_status |= ACIA_6850_irq; /* overrun interrupt */ + + if ( (m_kbd_intr & 3) == 1 && (m_kbd_status & ACIA_6850_TDRE) ) + m_kbd_status |= ACIA_6850_irq; /* ready to transmit interrupt */ + + m_irq_cb( (m_kbd_status & ACIA_6850_irq) ? 1 : 0 ); +} + + + +uint8_t to9_keyboard_device::kbd_acia_r(offs_t offset) +{ + /* ACIA 6850 registers */ + + switch ( offset ) + { + case 0: /* get status */ + /* bit 0: data received */ + /* bit 1: ready to transmit data (always 1) */ + /* bit 2: data carrier detect (ignored) */ + /* bit 3: clear to send (ignored) */ + /* bit 4: framing error (ignored) */ + /* bit 5: overrun */ + /* bit 6: parity error */ + /* bit 7: interrupt */ + + LOG("%s %f kbd_acia_r: status $%02X (rdrf=%i, tdre=%i, ovrn=%i, pe=%i, irq=%i)\n", + machine().describe_context(), machine().time().as_double(), m_kbd_status, + (m_kbd_status & ACIA_6850_RDRF) ? 1 : 0, + (m_kbd_status & ACIA_6850_TDRE) ? 1 : 0, + (m_kbd_status & ACIA_6850_OVRN) ? 1 : 0, + (m_kbd_status & ACIA_6850_PE) ? 1 : 0, + (m_kbd_status & ACIA_6850_irq) ? 1 : 0 ); + return m_kbd_status; + + case 1: /* get input data */ + if ( !machine().side_effects_disabled() ) + { + m_kbd_status &= ~(ACIA_6850_irq | ACIA_6850_PE); + if ( m_kbd_overrun ) + m_kbd_status |= ACIA_6850_OVRN; + else + m_kbd_status &= ~(ACIA_6850_OVRN | ACIA_6850_RDRF); + m_kbd_overrun = 0; + LOGMASKED(LOG_KBD, "%s %f kbd_acia_r: read data $%02X\n", machine().describe_context(), machine().time().as_double(), m_kbd_in); + update_irq(); + } + return m_kbd_in; + + default: + LOGMASKED(LOG_ERRORS, "%s kbd_acia_r: invalid offset %i\n", machine().describe_context(), offset); + return 0; + } +} + + + +void to9_keyboard_device::kbd_acia_w(offs_t offset, uint8_t data) +{ + /* ACIA 6850 registers */ + + switch ( offset ) + { + case 0: /* set control */ + /* bits 0-1: clock divide (ignored) or reset */ + if ( (data & 3) == 3 ) + { + /* reset */ + m_kbd_overrun = 0; + m_kbd_status = ACIA_6850_TDRE; + m_kbd_intr = 0; + LOGMASKED(LOG_KBD, "%s %f kbd_acia_w: reset (data=$%02X)\n", machine().describe_context(), machine().time().as_double(), data); + } + else + { + /* bits 2-4: parity */ + if ( (data & 0x18) == 0x10 ) + m_kbd_parity = 2; + else + m_kbd_parity = (data >> 2) & 1; + /* bits 5-6: interrupt on transmit */ + /* bit 7: interrupt on receive */ + m_kbd_intr = data >> 5; + + LOGMASKED(LOG_KBD, "%s %f kbd_acia_w: set control to $%02X (parity=%i, intr in=%i out=%i)\n", + machine().describe_context(), machine().time().as_double(), + data, m_kbd_parity, m_kbd_intr >> 2, + (m_kbd_intr & 3) ? 1 : 0); + } + update_irq(); + break; + + case 1: /* output data */ + m_kbd_status &= ~(ACIA_6850_irq | ACIA_6850_TDRE); + update_irq(); + /* TODO: 1 ms delay here ? */ + m_kbd_status |= ACIA_6850_TDRE; /* data transmit ready again */ + update_irq(); + + switch ( data ) + { + case 0xF8: + /* reset */ + m_kbd_caps = 1; + m_kbd_periph = 0; + m_kbd_pad = 0; + break; + + case 0xF9: m_kbd_caps = 1; break; + case 0xFA: m_kbd_caps = 0; break; + case 0xFB: m_kbd_pad = 1; break; + case 0xFC: m_kbd_pad = 0; break; + case 0xFD: m_kbd_periph = 1; break; + case 0xFE: m_kbd_periph = 0; break; + + default: + LOGMASKED(LOG_ERRORS, "%s %f kbd_acia_w: unknown kbd command %02X\n", machine().describe_context(), machine().time().as_double(), data); + } + + m_caps_led = !m_kbd_caps; + + LOG("%s %f kbd_acia_w: kbd command %02X (caps=%i, pad=%i, periph=%i)\n", + machine().describe_context(), machine().time().as_double(), data, + m_kbd_caps, m_kbd_pad, m_kbd_periph); + + break; + + default: + LOGMASKED(LOG_ERRORS, "%s kbd_acia_w: invalid offset %i (data=$%02X) \n", machine().describe_context(), offset, data); + } +} + + + +/* send a key to the CPU, 8-bit + parity bit (0=even, 1=odd) + note: parity is not used as a checksum but to actually transmit a 9-th bit + of information! +*/ +void to9_keyboard_device::send( uint8_t data, int parity ) +{ + if ( m_kbd_status & ACIA_6850_RDRF ) + { + /* overrun will be set when the current valid byte is read */ + m_kbd_overrun = 1; + LOGMASKED(LOG_KBD, "%f send: overrun => drop data=$%02X, parity=%i\n", machine().time().as_double(), data, parity); + } + else + { + /* valid byte */ + m_kbd_in = data; + m_kbd_status |= ACIA_6850_RDRF; /* raise data received flag */ + if ( m_kbd_parity == 2 || m_kbd_parity == parity ) + m_kbd_status &= ~ACIA_6850_PE; /* parity OK */ + else + m_kbd_status |= ACIA_6850_PE; /* parity error */ + LOGMASKED(LOG_KBD, "%f send: data=$%02X, parity=%i, status=$%02X\n", machine().time().as_double(), data, parity, m_kbd_status); + } + update_irq(); +} + + + +/* keycode => TO9 code (extended ASCII), shifted and un-shifted */ +static const int to9_kbd_code[80][2] = +{ + { 145, 150 }, { '_', '6' }, { 'Y', 'Y' }, { 'H', 'H' }, + { 11, 11 }, { 9, 9 }, { 30, 12 }, { 'N', 'N' }, + + { 146, 151 }, { '(', '5' }, { 'T', 'T' }, { 'G', 'G' }, + { '=', '+' }, { 8, 8 }, { 28, 28 }, { 'B', 'B' }, + + { 147, 152 }, { '\'', '4' }, { 'R', 'R' }, { 'F', 'F' }, + { 22, 22 }, { 155, 155 }, { 29, 127 }, { 'V', 'V' }, + + { 148, 153 }, { '"', '3' }, { 'E', 'E' }, { 'D', 'D' }, + { 161, 161 }, { 158, 158 }, + { 154, 154 }, { 'C', 'C' }, + + { 144, 149 }, { 128, '2' }, { 'Z', 'Z' }, { 'S', 'S' }, + { 162, 162 }, { 156, 156 }, + { 164, 164 }, { 'X', 'X' }, + + { '#', '@' }, { '*', '1' }, { 'A', 'A' }, { 'Q', 'Q' }, + { '[', '{' }, { 159, 159 }, { 160, 160 }, { 'W', 'W' }, + + { 2, 2 }, { 129, '7' }, { 'U', 'U' }, { 'J', 'J' }, + { ' ', ' ' }, { 163, 163 }, { 165, 165 }, + { ',', '?' }, + + { 0, 0 }, { '!', '8' }, { 'I', 'I' }, { 'K', 'K' }, + { '$', '&' }, { 10, 10 }, { ']', '}' }, { ';', '.' }, + + { 0, 0 }, { 130, '9' }, { 'O', 'O' }, { 'L', 'L' }, + { '-', '\\' }, { 132, '%' }, { 13, 13 }, { ':', '/' }, + + { 0, 0 }, { 131, '0' }, { 'P', 'P' }, { 'M', 'M' }, + { ')', 134 }, { '^', 133 }, { 157, 157 }, { '>', '<' } +}; + + + +/* returns the ASCII code for the key, or 0 for no key */ +int to9_keyboard_device::get_key() +{ + int control = ! (m_io_keyboard[7]->read() & 1); + int shift = ! (m_io_keyboard[9]->read() & 1); + int key = -1, line, bit; + uint8_t port; + + for ( line = 0; line < 10; line++ ) + { + port = m_io_keyboard[line]->read(); + + if ( line == 7 || line == 9 ) + port |= 1; /* shift & control */ + + /* TODO: correct handling of simultaneous keystokes: + return the new key preferably & disable repeat + */ + for ( bit = 0; bit < 8; bit++ ) + { + if ( ! (port & (1 << bit)) ) + key = line * 8 + bit; + } + } + + if ( key == -1 ) + { + m_kbd_last_key = 0xff; + m_kbd_key_count = 0; + return 0; + } + else if ( key == 64 ) + { + /* caps lock */ + if ( m_kbd_last_key == key ) + return 0; /* no repeat */ + + m_kbd_last_key = key; + m_kbd_caps = !m_kbd_caps; + m_caps_led = !m_kbd_caps; + return 0; + } + else + { + int asc; + asc = to9_kbd_code[key][shift]; + if ( ! asc ) return 0; + + /* keypad */ + if ( ! m_kbd_pad ) { + if ( asc >= 154 && asc <= 163 ) + asc += '0' - 154; + else if ( asc == 164 ) + asc = '.'; + else if ( asc == 165 ) + asc = 13; + } + + /* shifted letter */ + if ( asc >= 'A' && asc <= 'Z' && ( ! m_kbd_caps ) && ( ! shift ) ) + asc += 'a' - 'A'; + + /* control */ + if ( control ) + asc &= ~0x40; + + if ( key == m_kbd_last_key ) + { + /* repeat */ + m_kbd_key_count++; + if ( m_kbd_key_count < TO9_KBD_REPEAT_DELAY || (m_kbd_key_count - TO9_KBD_REPEAT_DELAY) % TO9_KBD_REPEAT_PERIOD ) + return 0; + LOGMASKED(LOG_KBD, "to9_kbd_get_key: repeat key $%02X '%c'\n", asc, asc); + return asc; + } + else + { + m_kbd_last_key = key; + m_kbd_key_count = 0; + LOGMASKED(LOG_KBD, "to9_kbd_get_key: key down $%02X '%c'\n", asc, asc); + return asc; + } + } +} + + + +TIMER_CALLBACK_MEMBER(to9_keyboard_device::timer_cb) +{ + if ( m_kbd_periph ) + { + /* peripheral mode: every 10 ms we send 4 bytes */ + + switch ( m_kbd_byte_count ) + { + case 0: /* key */ + send( get_key(), 0 ); + break; + + case 1: /* x axis */ + { + int newx = m_io_mouse_x.read_safe(0); + uint8_t data = ( (newx - m_mouse_x) & 0xf ) - 8; + send( data, 1 ); + m_mouse_x = newx; + break; + } + + case 2: /* y axis */ + { + int newy = m_io_mouse_y.read_safe(0); + uint8_t data = ( (newy - m_mouse_y) & 0xf ) - 8; + send( data, 1 ); + m_mouse_y = newy; + break; + } + + case 3: /* axis overflow & buttons */ + { + int b = m_io_mouse_button.read_safe(~0); + uint8_t data = 0; + if ( b & 1 ) data |= 1; + if ( b & 2 ) data |= 4; + send( data, 1 ); + break; + } + + } + + m_kbd_byte_count = ( m_kbd_byte_count + 1 ) & 3; + m_kbd_timer->adjust(m_kbd_byte_count ? TO9_KBD_BYTE_SPACE : TO9_KBD_END_SPACE); + } + else + { + int key = get_key(); + /* keyboard mode: send a byte only if a key is down */ + if ( key ) + send( key, 0 ); + m_kbd_timer->adjust(TO9_KBD_POLL_PERIOD); + } +} + + + +void to9_keyboard_device::device_reset() +{ + m_kbd_overrun = 0; /* no byte lost */ + m_kbd_status = ACIA_6850_TDRE; /* clear to transmit */ + m_kbd_intr = 0; /* interrupt disabled */ + m_kbd_caps = 1; + m_kbd_periph = 0; + m_kbd_pad = 0; + m_kbd_byte_count = 0; + m_caps_led = !m_kbd_caps; + m_kbd_key_count = 0; + m_kbd_last_key = 0xff; + update_irq(); + m_kbd_timer->adjust(TO9_KBD_POLL_PERIOD); +} + + + +void to9_keyboard_device::device_start() +{ + m_caps_led.resolve(); + + m_kbd_timer = timer_alloc(FUNC(to9_keyboard_device::timer_cb), this); + save_item(NAME(m_kbd_parity)); + save_item(NAME(m_kbd_intr)); + save_item(NAME(m_kbd_in)); + save_item(NAME(m_kbd_status)); + save_item(NAME(m_kbd_overrun)); + save_item(NAME(m_kbd_last_key)); + save_item(NAME(m_kbd_key_count)); + save_item(NAME(m_kbd_caps)); + save_item(NAME(m_kbd_periph)); + save_item(NAME(m_kbd_pad)); + save_item(NAME(m_kbd_byte_count)); + save_item(NAME(m_mouse_x)); + save_item(NAME(m_mouse_y)); +} diff --git a/src/mame/thomson/to_kbd.h b/src/mame/thomson/to_kbd.h new file mode 100644 index 0000000000000..96e26d0655dc6 --- /dev/null +++ b/src/mame/thomson/to_kbd.h @@ -0,0 +1,121 @@ +// license:BSD-3-Clause +// copyright-holders:Antoine Mine +/********************************************************************** + + Copyright (C) Antoine Mine' 2006 + + Thomson TO8 built-in keyboard & TO9 detached keyboard + +**********************************************************************/ + +#ifndef MAME_THOMSON_TO_KBD_H +#define MAME_THOMSON_TO_KBD_H + +#pragma once + +class to8_keyboard_device : public device_t +{ +public: + to8_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U); + + auto data_cb() { return m_data_cb.bind(); } + + int ktest_r(); + int caps_r() { return m_kbd_caps; } + void set_ack( int data ); + +protected: + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; + virtual ioport_constructor device_input_ports() const override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + virtual void device_start() override ATTR_COLD; + +private: + devcb_write_line m_data_cb; + + required_ioport_array<10> m_io_keyboard; + output_finder<> m_caps_led; + + uint8_t m_kbd_ack = 0; /* 1 = cpu inits / accepts transfers */ + uint16_t m_kbd_data = 0; /* data to transmit */ + uint16_t m_kbd_step = 0; /* transmission automaton state */ + uint8_t m_kbd_last_key = 0; /* last key (for repetition) */ + uint32_t m_kbd_key_count = 0; /* keypress time (for repetition) */ + uint8_t m_kbd_caps = 0; /* caps lock */ + emu_timer* m_kbd_timer = nullptr; /* bit-send */ + emu_timer* m_kbd_signal = nullptr; /* signal from CPU */ + + TIMER_CALLBACK_MEMBER( timer_cb ); + int get_key(); + void timer_func(); +}; + +class to9_keyboard_device : public device_t +{ +public: + to9_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U); + + auto irq_cb() { return m_irq_cb.bind(); } + + uint8_t kbd_acia_r(offs_t offset); + void kbd_acia_w(offs_t offset, uint8_t data); + + int ktest_r(); + +protected: + to9_keyboard_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock = 0U); + + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; + virtual ioport_constructor device_input_ports() const override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + virtual void device_start() override ATTR_COLD; + +private: + devcb_write_line m_irq_cb; + + required_ioport_array<10> m_io_keyboard; + optional_ioport m_io_mouse_x; + optional_ioport m_io_mouse_y; + optional_ioport m_io_mouse_button; + output_finder<> m_caps_led; + + uint8_t m_kbd_parity = 0; /* 0=even, 1=odd, 2=no parity */ + uint8_t m_kbd_intr = 0; /* interrupt mode */ + uint8_t m_kbd_in = 0; /* data from keyboard */ + uint8_t m_kbd_status = 0; /* status */ + uint8_t m_kbd_overrun = 0; /* character lost */ + uint8_t m_kbd_periph = 0; /* peripheral mode */ + uint8_t m_kbd_byte_count = 0; /* byte-count in peripheral mode */ + uint16_t m_mouse_x = 0; + uint16_t m_mouse_y = 0; + uint8_t m_kbd_last_key = 0; /* for key repetition */ + uint16_t m_kbd_key_count = 0; + uint8_t m_kbd_caps = 0; /* caps-lock */ + uint8_t m_kbd_pad = 0; /* keypad outputs special codes */ + emu_timer* m_kbd_timer = nullptr; + + TIMER_CALLBACK_MEMBER( timer_cb ); + void update_irq(); + void send( uint8_t data, int parity ); + int get_key(); +}; + +class to9p_keyboard_device : public to9_keyboard_device +{ +public: + to9p_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U); + +protected: + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; + virtual ioport_constructor device_input_ports() const override ATTR_COLD; +}; + +// device type declarations +DECLARE_DEVICE_TYPE(TO8_KEYBOARD, to8_keyboard_device) +DECLARE_DEVICE_TYPE(TO9_KEYBOARD, to9_keyboard_device) +DECLARE_DEVICE_TYPE(TO9P_KEYBOARD, to9p_keyboard_device) + +#endif // MAME_THOMSON_TO_KBD_H