summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author AJR <ariedlmayer@gmail.com>2024-10-03 15:17:52 -0400
committer AJR <ariedlmayer@gmail.com>2024-10-03 15:17:52 -0400
commit366d6fea792e28877e7f514aab6307efcb0bb450 (patch)
treec9fc3b20b8fcb08024ee7efeb94b3898a9c64d1b
parentd7211e631dd4599bead5a2785d629b8b0b3e599b (diff)
to8, to9, to9p: Split out serial keyboards as separate devices
-rw-r--r--src/mame/thomson/thomson.cpp150
-rw-r--r--src/mame/thomson/thomson.h46
-rw-r--r--src/mame/thomson/thomson_m.cpp779
-rw-r--r--src/mame/thomson/to_kbd.cpp999
-rw-r--r--src/mame/thomson/to_kbd.h121
5 files changed, 1155 insertions, 940 deletions
diff --git a/src/mame/thomson/thomson.cpp b/src/mame/thomson/thomson.cpp
index 69215e68d03..67d77a2f035 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 0e7991390c0..905a7105698 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 @@ protected:
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 @@ public:
void to9p(machine_config &config);
protected:
+ optional_device<to8_keyboard_device> m_to8_kbd;
+ optional_device<to9_keyboard_device> m_to9_kbd;
optional_device<centronics_device> m_centronics;
optional_device<output_latch_device> m_cent_data_out;
@@ -411,14 +417,6 @@ protected:
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 @@ protected:
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 @@ protected:
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 @@ protected:
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 @@ protected:
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 2bc583f8c65..b5bc183160d 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 00000000000..daf653db12c
--- /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 00000000000..96e26d0655d
--- /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