summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Dirk Best <mail@dirk-best.de>2021-01-16 15:09:26 +0100
committer Dirk Best <mail@dirk-best.de>2021-01-16 15:10:10 +0100
commit400ff8ceb53388af80beb27be5c88b7f11f5ba6d (patch)
treecbe61d101a995ce28088ee3ccff480b94704224b
parent4423eb73b542a5a6ab38b40503d1691a792cfdbe (diff)
tabe22: Make it mostly work
- Move to its own driver - Implement keyboard - Implement char/attr RAM switch - Improve video rendering - Hook up RS232 ports - Add gfxdecode
-rw-r--r--scripts/target/mame/mess.lua8
-rw-r--r--src/mame/drivers/cit220.cpp63
-rw-r--r--src/mame/drivers/tabe22.cpp326
-rw-r--r--src/mame/machine/e22_kbd.cpp307
-rw-r--r--src/mame/machine/e22_kbd.h62
-rw-r--r--src/mame/mame.lst4
-rw-r--r--src/mame/mess.flt1
7 files changed, 707 insertions, 64 deletions
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index 51161745726..8df945d71ea 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -1366,6 +1366,7 @@ function linkProjects_mame_mess(_target, _subtarget)
"swtpc",
"synertek",
"ta",
+ "tab",
"tandberg",
"tangerin",
"tasc",
@@ -3799,6 +3800,13 @@ files {
MAME_DIR .. "src/mame/drivers/alphatro.cpp",
}
+createMESSProjects(_target, _subtarget, "tab")
+files {
+ MAME_DIR .. "src/mame/drivers/tabe22.cpp",
+ MAME_DIR .. "src/mame/machine/e22_kbd.cpp",
+ MAME_DIR .. "src/mame/machine/e22_kbd.h",
+}
+
createMESSProjects(_target, _subtarget, "tandberg")
files {
MAME_DIR .. "src/mame/drivers/tdv2324.cpp",
diff --git a/src/mame/drivers/cit220.cpp b/src/mame/drivers/cit220.cpp
index 390c744f391..98db1b8242f 100644
--- a/src/mame/drivers/cit220.cpp
+++ b/src/mame/drivers/cit220.cpp
@@ -51,12 +51,9 @@ private:
void cit220p_io_map(address_map &map);
void vp122_mem_map(address_map &map);
void vp122_io_map(address_map &map);
- void e22_mem_map(address_map &map);
- void e22_io_map(address_map &map);
void char_map(address_map &map);
void attr_map(address_map &map);
- void e22_char_map(address_map &map);
required_device<i8085a_cpu_device> m_maincpu;
required_device<screen_device> m_screen;
@@ -125,22 +122,6 @@ void cit220_state::vp122_io_map(address_map &map)
map(0x70, 0x73).w("pit", FUNC(pit8253_device::write));
}
-void cit220_state::e22_mem_map(address_map &map)
-{
- map(0x0000, 0xbfff).rom().region("maincpu", 0);
- map(0xc000, 0xcfff).ram().share("charram");
- map(0xd000, 0xffff).ram();
-}
-
-void cit220_state::e22_io_map(address_map &map)
-{
- map(0x00, 0x0f).rw("duart", FUNC(scn2681_device::read), FUNC(scn2681_device::write));
- map(0x20, 0x27).rw(m_avdc, FUNC(scn2674_device::read), FUNC(scn2674_device::write));
- map(0x40, 0x41).rw("usart", FUNC(i8251_device::read), FUNC(i8251_device::write));
- map(0x60, 0x60).nopw();
- map(0x61, 0x61).nopw();
-}
-
SCN2674_DRAW_CHARACTER_MEMBER(cit220_state::draw_character)
{
@@ -171,11 +152,6 @@ void cit220_state::attr_map(address_map &map)
map(0x0000, 0x2fff).ram();
}
-void cit220_state::e22_char_map(address_map &map)
-{
- map(0x0000, 0x0fff).ram().share("charram");
-}
-
static INPUT_PORTS_START( cit220p )
INPUT_PORTS_END
@@ -247,36 +223,6 @@ void cit220_state::vp122(machine_config &config)
// Input clocks are video-related and should differ for 80-column and 132-column modes
}
-// TODO: similar devices, but usage seems different enough from others for this to warrant its own driver
-void cit220_state::tabe22(machine_config &config)
-{
- I8085A(config, m_maincpu, 10_MHz_XTAL);
- m_maincpu->set_addrmap(AS_PROGRAM, &cit220_state::e22_mem_map);
- m_maincpu->set_addrmap(AS_IO, &cit220_state::e22_io_map);
-
- //NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0);
-
- SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
- m_screen->set_raw(21.7566_MHz_XTAL, 918, 0, 720, 395, 0, 378);
- //m_screen->set_raw(35.8344_MHz_XTAL, 1512, 0, 1188, 395, 0, 378);
- m_screen->set_screen_update(m_avdc, FUNC(scn2674_device::screen_update));
-
- SCN2674(config, m_avdc, 21.7566_MHz_XTAL / 9);
- m_avdc->intr_callback().set_inputline(m_maincpu, I8085_RST75_LINE);
- m_avdc->set_character_width(9);
- m_avdc->set_display_callback(FUNC(cit220_state::draw_character));
- m_avdc->set_addrmap(0, &cit220_state::e22_char_map);
- m_avdc->set_screen("screen");
-
- scn2681_device &duart(SCN2681(config, "duart", 3.6864_MHz_XTAL));
- duart.irq_cb().set_inputline(m_maincpu, I8085_RST65_LINE);
- duart.outport_cb().set("usart", FUNC(i8251_device::write_txc)).bit(3);
- duart.outport_cb().append("usart", FUNC(i8251_device::write_rxc)).bit(3);
-
- i8251_device &usart(I8251(config, "usart", 10_MHz_XTAL / 4)); // divider guessed
- usart.rxrdy_handler().set_inputline(m_maincpu, I8085_RST55_LINE);
-}
-
ROM_START(cit220p)
ROM_REGION(0x8000, "maincpu", 0)
@@ -308,15 +254,6 @@ ROM_START(vp122)
ROM_LOAD("223-48700.uk4", 0x0000, 0x2000, CRC(4dbab4bd) SHA1(18e9a23ba22e2096fa529541fa329f5a56740e62))
ROM_END
-ROM_START(tabe22)
- ROM_REGION(0xc000, "maincpu", 0)
- ROM_LOAD("e22_u3__2.17.86__v2.00.bin", 0x0000, 0x8000, CRC(fd931bc5) SHA1(013d5a5ed759bb9684bff18a3e848fa6d1167e10))
- ROM_LOAD("e22_u2__2.17.86__v2.00.bin", 0x8000, 0x4000, CRC(45d5e895) SHA1(a2b4e04dbc881230462a38de98ed843d5683c1b9))
-
- ROM_REGION(0x2000, "chargen", 0)
- ROM_LOAD("e22_u43__char_gen.bin", 0x0000, 0x2000, CRC(33880908) SHA1(7f26dede2feaf3591312d67e3dabfc1ad8bb3181))
-ROM_END
COMP(1984, cit220p, 0, 0, cit220p, cit220p, cit220_state, empty_init, "C. Itoh Electronics", "CIT-220+ Video Terminal", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND)
COMP(1985, vp122, 0, 0, vp122, cit220p, cit220_state, empty_init, "ADDS", "Viewpoint 122", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_NO_SOUND)
-COMP(1986, tabe22, 0, 0, tabe22, cit220p, cit220_state, empty_init, "Tab Products", "E-22 Display Terminal", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_NO_SOUND)
diff --git a/src/mame/drivers/tabe22.cpp b/src/mame/drivers/tabe22.cpp
new file mode 100644
index 00000000000..35524d15c9e
--- /dev/null
+++ b/src/mame/drivers/tabe22.cpp
@@ -0,0 +1,326 @@
+// license: BSD-3-Clause
+// copyright-holders: AJR, Dirk Best
+/***************************************************************************
+
+ Tab Products "E22" Terminal
+
+ VT52/VT100/VT220
+
+ Hardware:
+ - P8085AH
+ - SCN2674B with SCB2675T
+ - SCN2681
+ - P8251A
+ - 3x HM6264LP-12 (8k)
+ - 3x HM6116LP-2 (2k)
+ - XTAL: 3.6864 MHz, 10.0000 MHz, 21.7566 MHz, 35.8344 MHz
+
+ TODO:
+ - Dump keyboard controller and emulate it (currently HLE'd)
+ - NVRAM / memory layout
+ - Needs a hack to send out data on the RS232 port:
+ Set $f7a3 = 0 after startup
+
+ Notes:
+ - The hardware has some similarities to cit220.cpp
+ - Everything here is guessed (including the system name), no docs available
+
+***************************************************************************/
+
+#include "emu.h"
+#include "cpu/i8085/i8085.h"
+#include "machine/bankdev.h"
+#include "machine/e22_kbd.h"
+#include "machine/i8251.h"
+#include "machine/mc68681.h"
+#include "machine/nvram.h"
+#include "video/scn2674.h"
+#include "bus/rs232/rs232.h"
+#include "bus/rs232/printer.h"
+#include "emupal.h"
+#include "screen.h"
+
+
+namespace {
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class tabe22_state : public driver_device
+{
+public:
+ tabe22_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag),
+ m_maincpu(*this, "maincpu"),
+ m_screen(*this, "screen"),
+ m_palette(*this, "palette"),
+ m_avdc(*this, "avdc"),
+ m_chargen(*this, "chargen"),
+ m_vram_bank(*this, "vrambank")
+ { }
+
+ void tabe22(machine_config &config);
+
+protected:
+ virtual void machine_start() override;
+
+private:
+ void mem_map(address_map &map);
+ void io_map(address_map &map);
+ void vram_map(address_map &map);
+
+ void char_map(address_map &map);
+ void attr_map(address_map &map);
+
+ required_device<i8085a_cpu_device> m_maincpu;
+ required_device<screen_device> m_screen;
+ required_device<palette_device> m_palette;
+ required_device<scn2674_device> m_avdc;
+ required_region_ptr<uint8_t> m_chargen;
+ optional_device<address_map_bank_device> m_vram_bank;
+
+ void video_ctrl_w(uint8_t data);
+ void crt_brightness_w(uint8_t data);
+ SCN2674_DRAW_CHARACTER_MEMBER(draw_character);
+ void palette(palette_device &palette) const;
+
+ bool m_screen_light;
+};
+
+
+//**************************************************************************
+// ADDRESS MAPS
+//**************************************************************************
+
+void tabe22_state::mem_map(address_map &map)
+{
+ map(0x0000, 0xbfff).rom().region("maincpu", 0);
+ map(0xc000, 0xcfff).rw(m_vram_bank, FUNC(address_map_bank_device::read8), FUNC(address_map_bank_device::write8));
+ map(0xd000, 0xdfff).ram();
+ map(0xe000, 0xffff).ram();
+}
+
+void tabe22_state::vram_map(address_map &map)
+{
+ map(0x0000, 0x0fff).ram().share("charram");
+ map(0x1000, 0x1fff).ram().share("attrram");
+}
+
+void tabe22_state::io_map(address_map &map)
+{
+ map(0x00, 0x0f).rw("duart", FUNC(scn2681_device::read), FUNC(scn2681_device::write));
+ map(0x20, 0x27).rw(m_avdc, FUNC(scn2674_device::read), FUNC(scn2674_device::write));
+ map(0x40, 0x41).rw("usart", FUNC(i8251_device::read), FUNC(i8251_device::write));
+ map(0x60, 0x60).w(FUNC(tabe22_state::video_ctrl_w));
+ map(0x61, 0x61).w(FUNC(tabe22_state::crt_brightness_w));
+}
+
+
+//**************************************************************************
+// VIDEO EMULATION
+//**************************************************************************
+
+void tabe22_state::char_map(address_map &map)
+{
+ map(0x0000, 0x0fff).ram().share("charram");
+}
+
+void tabe22_state::attr_map(address_map &map)
+{
+ map(0x0000, 0x0fff).ram().share("attrram");
+}
+
+void tabe22_state::video_ctrl_w(uint8_t data)
+{
+ // 7------- unknown
+ // -6------ screen light/dark
+ // --5----- char ram/attribute ram switch
+ // ---4---- unknown
+ // ----3--- 80/132 col switch
+ // -----210 unknown
+
+ m_screen_light = bool(BIT(data, 6));
+ m_vram_bank->set_bank(BIT(data, 5));
+ m_avdc->set_unscaled_clock(BIT(data, 3) ? 35.8344_MHz_XTAL / 9 : 21.7566_MHz_XTAL / 9);
+}
+
+void tabe22_state::crt_brightness_w(uint8_t data)
+{
+ // unknown algorithm for the brightness
+ // default value is 7, range is 15 (off) to 0 (brightest)
+ m_screen->set_brightness(0xff - ((data & 0x0f) * 6));
+}
+
+SCN2674_DRAW_CHARACTER_MEMBER( tabe22_state::draw_character )
+{
+ uint16_t data = m_chargen[charcode << 4 | linecount] << 2;
+ const pen_t *const pen = m_palette->pens();
+
+ // 76------ unknown
+ // --5----- shaded
+ // ---4---- unknown
+ // ----3--- bold
+ // -----2-- blink
+ // ------1- underline
+ // -------0 reverse
+
+ if (ul && (BIT(attrcode, 1)))
+ data = 0x1ff;
+
+ if (blink && (BIT(attrcode, 2)))
+ data = 0x000;
+
+ if (BIT(attrcode, 0))
+ data = ~data;
+
+ if (cursor)
+ data = ~data;
+
+ // foreground/background colors
+ rgb_t fg = BIT(attrcode, 5) ? pen[1] : BIT(attrcode, 3) ? pen[3] : pen[2];
+ rgb_t bg = m_screen_light ? pen[1] : pen[0];
+
+ // draw 9 pixels of the character
+ for (int i = 0; i < 9; i++)
+ bitmap.pix(y, x + i) = BIT(data, 8 - i) ? fg : bg;
+}
+
+static const gfx_layout char_layout =
+{
+ 8,16,
+ RGN_FRAC(1,1),
+ 1,
+ { 0 },
+ { STEP8(0,1) },
+ { STEP16(0,8) },
+ 8*16
+};
+
+static GFXDECODE_START(chars)
+ GFXDECODE_ENTRY("chargen", 0, char_layout, 0, 1)
+GFXDECODE_END
+
+void tabe22_state::palette(palette_device &palette) const
+{
+ static constexpr rgb_t pens[4] =
+ {
+ { 0x00, 0x00, 0x00 }, // black
+ { 0x7f, 0x7f, 0x7f }, // gray
+ { 0xcf, 0xcf, 0xcf }, // white
+ { 0xff, 0xff, 0xff }, // highlight
+ };
+
+ palette.set_pen_colors(0, pens);
+}
+
+
+//**************************************************************************
+// MACHINE EMULATION
+//**************************************************************************
+
+void tabe22_state::machine_start()
+{
+ // register for save states
+ save_item(NAME(m_screen_light));
+}
+
+
+//**************************************************************************
+// MACHINE DEFINTIONS
+//**************************************************************************
+
+void printer_devices(device_slot_interface &device)
+{
+ device.option_add("printer", SERIAL_PRINTER);
+}
+
+static DEVICE_INPUT_DEFAULTS_START( printer_defaults )
+ DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_4800 )
+ DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_4800 )
+ DEVICE_INPUT_DEFAULTS( "RS232_STARTBITS", 0xff, RS232_STARTBITS_1 )
+ DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_7 )
+ DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_ODD )
+ DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_1 )
+DEVICE_INPUT_DEFAULTS_END
+
+void tabe22_state::tabe22(machine_config &config)
+{
+ I8085A(config, m_maincpu, 10_MHz_XTAL);
+ m_maincpu->set_addrmap(AS_PROGRAM, &tabe22_state::mem_map);
+ m_maincpu->set_addrmap(AS_IO, &tabe22_state::io_map);
+
+ ADDRESS_MAP_BANK(config, m_vram_bank, 0);
+ m_vram_bank->set_map(&tabe22_state::vram_map);
+ m_vram_bank->set_addr_width(13);
+ m_vram_bank->set_data_width(8);
+ m_vram_bank->set_stride(0x1000);
+
+// NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0);
+
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ m_screen->set_color(rgb_t::amber());
+ m_screen->set_raw(21.7566_MHz_XTAL, 918, 0, 720, 395, 0, 378); // 80 column mode
+// m_screen->set_raw(35.8344_MHz_XTAL, 1494, 0, 1188, 395, 0, 378); // 132 column mode
+ m_screen->set_screen_update(m_avdc, FUNC(scn2674_device::screen_update));
+
+ PALETTE(config, m_palette, FUNC(tabe22_state::palette), 4);
+
+ GFXDECODE(config, "gfxdecode", m_palette, chars);
+
+ SCN2674(config, m_avdc, 21.7566_MHz_XTAL / 9);
+ m_avdc->intr_callback().set_inputline(m_maincpu, I8085_RST75_LINE);
+ m_avdc->set_character_width(9);
+ m_avdc->set_display_callback(FUNC(tabe22_state::draw_character));
+ m_avdc->set_addrmap(0, &tabe22_state::char_map);
+ m_avdc->set_addrmap(1, &tabe22_state::attr_map);
+ m_avdc->set_screen("screen");
+
+ scn2681_device &duart(SCN2681(config, "duart", 3.6864_MHz_XTAL));
+ duart.irq_cb().set_inputline(m_maincpu, I8085_RST65_LINE);
+ duart.a_tx_cb().set("printer", FUNC(rs232_port_device::write_txd));
+ duart.b_tx_cb().set("host", FUNC(rs232_port_device::write_txd));
+ duart.outport_cb().set("usart", FUNC(i8251_device::write_txc)).bit(3);
+ duart.outport_cb().append("usart", FUNC(i8251_device::write_rxc)).bit(3);
+
+ rs232_port_device &rs232_host(RS232_PORT(config, "host", default_rs232_devices, nullptr));
+ rs232_host.rxd_handler().set("duart", FUNC(scn2681_device::rx_b_w));
+ rs232_host.cts_handler().set("duart", FUNC(scn2681_device::ip1_w));
+
+ rs232_port_device &rs232_printer(RS232_PORT(config, "printer", printer_devices, nullptr));
+ rs232_printer.set_option_device_input_defaults("printer", DEVICE_INPUT_DEFAULTS_NAME(printer_defaults));
+
+ i8251_device &usart(I8251(config, "usart", 10_MHz_XTAL / 4)); // divider guessed
+ usart.rxrdy_handler().set_inputline(m_maincpu, I8085_RST55_LINE);
+ usart.txd_handler().set("kbd", FUNC(e22_kbd_hle_device::rx_w));
+
+ e22_kbd_hle_device &kbd(E22_KBD_HLE(config, "kbd"));
+ kbd.tx_handler().set("usart", FUNC(i8251_device::write_rxd));
+ kbd.cts_handler().set("usart", FUNC(i8251_device::write_cts));
+}
+
+
+//**************************************************************************
+// ROM DEFINITIONS
+//**************************************************************************
+
+ROM_START(tabe22)
+ ROM_REGION(0xc000, "maincpu", 0)
+ ROM_LOAD("e22_u3__2.17.86__v2.00.bin", 0x0000, 0x8000, CRC(fd931bc5) SHA1(013d5a5ed759bb9684bff18a3e848fa6d1167e10))
+ ROM_LOAD("e22_u2__2.17.86__v2.00.bin", 0x8000, 0x4000, CRC(45d5e895) SHA1(a2b4e04dbc881230462a38de98ed843d5683c1b9))
+
+ ROM_REGION(0x2000, "chargen", 0)
+ ROM_LOAD("e22_u43__char_gen.bin", 0x0000, 0x2000, CRC(33880908) SHA1(7f26dede2feaf3591312d67e3dabfc1ad8bb3181))
+ROM_END
+
+
+} // anonymous namespace
+
+
+//**************************************************************************
+// SYSTEM DRIVERS
+//**************************************************************************
+
+// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
+COMP( 1986, tabe22, 0, 0, tabe22, 0, tabe22_state, empty_init, "Tab Products", "E-22 Display Terminal", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_NO_SOUND | MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/machine/e22_kbd.cpp b/src/mame/machine/e22_kbd.cpp
new file mode 100644
index 00000000000..61cfafd9b94
--- /dev/null
+++ b/src/mame/machine/e22_kbd.cpp
@@ -0,0 +1,307 @@
+// license: BSD-3-Clause
+// copyright-holders: Dirk Best
+/***************************************************************************
+
+ Tab Products E22 Keyboard (HLE)
+
+ Notes:
+ - Everything here is guessed, no picture of the keyboard available
+
+***************************************************************************/
+
+#include "emu.h"
+#include "e22_kbd.h"
+#include "machine/keyboard.ipp"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(E22_KBD_HLE, e22_kbd_hle_device, "e22_kbd_hle", "Tab E22 Keyboard (HLE)")
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+static INPUT_PORTS_START( keyboard )
+ PORT_START("row_0")
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 00 */ PORT_NAME("00")
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 01 */ PORT_CODE(KEYCODE_SCRLOCK) PORT_NAME("Hold")
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 02 */ PORT_CODE(KEYCODE_PRTSCR) PORT_NAME("Print")
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 03 */ PORT_CODE(KEYCODE_ASTERISK) PORT_NAME("Setup")
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 04 */ PORT_NAME("04")
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 05 */ PORT_NAME("05")
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 06 */ PORT_NAME("06")
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 07 */ PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 08 */ PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7))
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 09 */ PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8))
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 0a */ PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9))
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 0b */ PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10))
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 0c */ PORT_NAME("0c")
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 0d */ PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11))
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 0e */ PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12))
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 0f */ PORT_CODE(KEYCODE_F13) PORT_CHAR(UCHAR_MAMEKEY(F13))
+
+ PORT_START("row_1")
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 10 */ PORT_CODE(KEYCODE_F14) PORT_CHAR(UCHAR_MAMEKEY(F14))
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 11 */ PORT_NAME("11")
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 12 */ PORT_CODE(KEYCODE_F15) PORT_CHAR(UCHAR_MAMEKEY(F15))
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 13 */ PORT_CODE(KEYCODE_F16) PORT_CHAR(UCHAR_MAMEKEY(F16))
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 14 */ PORT_NAME("14")
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 15 */ PORT_NAME("15")
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 16 */ PORT_CODE(KEYCODE_F17) PORT_CHAR(UCHAR_MAMEKEY(F17))
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 17 */ PORT_CODE(KEYCODE_F18) PORT_CHAR(UCHAR_MAMEKEY(F18))
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 18 */ PORT_CODE(KEYCODE_F19) PORT_CHAR(UCHAR_MAMEKEY(F19))
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 19 */ PORT_CODE(KEYCODE_F20) PORT_CHAR(UCHAR_MAMEKEY(F20))
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 1a */ PORT_CODE(KEYCODE_ESC) PORT_CHAR(27)
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 1b */ PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~')
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 1c */ PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 1d */ PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 1e */ PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 1f */ PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+
+ PORT_START("row_2")
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 20 */ PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 21 */ PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 22 */ PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 23 */ PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 24 */ PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 25 */ PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 26 */ PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 27 */ PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 28 */ PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL))
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 29 */ PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 2a */ PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1))
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 2b */ PORT_CODE(KEYCODE_F2) PORT_NAME("F2 (Insert)")
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 2c */ PORT_CODE(KEYCODE_F3) PORT_NAME("F3 (Remove Clear)")
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 2d */ PORT_NAME("PF1")
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 2e */ PORT_NAME("PF2")
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 2f */ PORT_NAME("PF3")
+
+ PORT_START("row_3")
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 30 */ PORT_NAME("PF4")
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 31 */ PORT_NAME("31")
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 32 */ PORT_CODE(KEYCODE_TAB) PORT_CHAR(9)
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 33 */ PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 34 */ PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 35 */ PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 36 */ PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 37 */ PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 38 */ PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 39 */ PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 3a */ PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 3b */ PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 3c */ PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 3d */ PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 3e */ PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 3f */ PORT_NAME("3f")
+
+ PORT_START("row_4")
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 40 */ PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('<') PORT_CHAR('>')
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 41 */ PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4))
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 42 */ PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5))
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 43 */ PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 44 */ PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD))
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 45 */ PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD))
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 46 */ PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD))
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 47 */ PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD))
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 48 */ PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2)
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 49 */ PORT_NAME("49")
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 4a */ PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 4b */ PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 4c */ PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 4d */ PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 4e */ PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 4f */ PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
+
+ PORT_START("row_5")
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 50 */ PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 51 */ PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 52 */ PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 53 */ PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 54 */ PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"')
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 55 */ PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 56 */ PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|')
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 57 */ PORT_NAME("57")
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 58 */ PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 59 */ PORT_NAME("59")
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 5a */ PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD))
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 5b */ PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD))
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 5c */ PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD))
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 5d */ PORT_CODE(KEYCODE_COMMA_PAD) PORT_CHAR(UCHAR_MAMEKEY(COMMA_PAD))
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 5e */ PORT_NAME("5e")
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 5f */ PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+
+ PORT_START("row_6")
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 60 */ PORT_NAME("60")
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 61 */ PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 62 */ PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 63 */ PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 64 */ PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 65 */ PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 66 */ PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 67 */ PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 68 */ PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',')
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 69 */ PORT_CODE(KEYCODE_STOP) PORT_CHAR('.')
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 6a */ PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/')
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 6b */ PORT_NAME("6b")
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 6c */ PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 6d */ PORT_NAME("LF")
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 6e */ PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 6f */ PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+
+ PORT_START("row_7")
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 70 */ PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 71 */ PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD))
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 72 */ PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD))
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 73 */ PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 74 */ PORT_NAME("74")
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 75 */ PORT_NAME("75")
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 76 */ PORT_NAME("76")
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 77 */ PORT_NAME("77")
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 78 */ PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 79 */ PORT_NAME("79")
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 7a */ PORT_NAME("7a")
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 7b */ PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD))
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 7c */ PORT_NAME("7c")
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 7d */ PORT_CODE(KEYCODE_PLUS_PAD) PORT_NAME("Keypad .")
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 7e */ PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD))
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) /* 7f */ PORT_NAME("7f")
+INPUT_PORTS_END
+
+ioport_constructor e22_kbd_hle_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( keyboard );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// e22_kbd_hle_device - constructor
+//-------------------------------------------------
+
+e22_kbd_hle_device::e22_kbd_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, E22_KBD_HLE, tag, owner, clock),
+ device_buffered_serial_interface(mconfig, *this),
+ device_matrix_keyboard_interface(mconfig, *this, "row_0", "row_1", "row_2", "row_3", "row_4", "row_5", "row_6", "row_7"),
+ m_tx_handler(*this),
+ m_cts_handler(*this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void e22_kbd_hle_device::device_start()
+{
+ // resolve callbacks
+ m_tx_handler.resolve_safe();
+ m_cts_handler.resolve_safe();
+
+ // signal ready
+ m_cts_handler(0);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void e22_kbd_hle_device::device_reset()
+{
+ clear_fifo();
+
+ receive_register_reset();
+ transmit_register_reset();
+
+ set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
+ set_rcv_rate(1200);
+ set_tra_rate(1200);
+
+ reset_key_state();
+ start_processing(attotime::from_hz(1200));
+ typematic_stop();
+}
+
+//-------------------------------------------------
+// tra_callback - send bit to host
+//-------------------------------------------------
+
+void e22_kbd_hle_device::tra_callback()
+{
+ m_tx_handler(transmit_register_get_data_bit());
+}
+
+//-------------------------------------------------
+// received_byte - handle received byte
+//-------------------------------------------------
+
+void e22_kbd_hle_device::received_byte(uint8_t byte)
+{
+ logerror("Received from host: %02x\n", byte);
+
+ switch (byte)
+ {
+ case 0x02: break; // keyclick on
+ case 0x06: transmit_byte(0x01); break; // can't be 0x00
+ case 0x07: transmit_byte(0x02); break; // can't be 0x00
+ case 0x09: break; // bell?
+ case 0x12: break; // keyclick off
+ }
+}
+
+//-------------------------------------------------
+// key_make - handle a key being pressed
+//-------------------------------------------------
+
+void e22_kbd_hle_device::key_make(uint8_t row, uint8_t column)
+{
+ // send the code
+ uint8_t code = row * 16 + column;
+
+ transmit_byte(code);
+
+ // no typematic for modifier keys
+ if (code != 0x48 && code != 0x5f && code != 0x6c)
+ typematic_start(row, column, attotime::from_msec(750), attotime::from_msec(50));
+}
+
+//-------------------------------------------------
+// key_break - handle a key being released
+//-------------------------------------------------
+
+void e22_kbd_hle_device::key_break(uint8_t row, uint8_t column)
+{
+ // send the break code (only for modifier keys: ctrl and shift)
+ uint8_t code = row * 16 + column;
+
+ if (code == 0x48 || code == 0x5f || code == 0x6c)
+ transmit_byte(0x80 | code);
+
+ if (typematic_is(row, column))
+ typematic_stop();
+}
+
+//-------------------------------------------------
+// key_repeat - handle a key being repeated
+//-------------------------------------------------
+
+void e22_kbd_hle_device::key_repeat(u8 row, u8 column)
+{
+ uint8_t code = row * 16 + column;
+ transmit_byte(code);
+}
+
+//-------------------------------------------------
+// rx_w - receive bit from host
+//-------------------------------------------------
+
+void e22_kbd_hle_device::rx_w(int state)
+{
+ device_buffered_serial_interface::rx_w(state);
+}
diff --git a/src/mame/machine/e22_kbd.h b/src/mame/machine/e22_kbd.h
new file mode 100644
index 00000000000..a3bac1d98d6
--- /dev/null
+++ b/src/mame/machine/e22_kbd.h
@@ -0,0 +1,62 @@
+// license: BSD-3-Clause
+// copyright-holders: Dirk Best
+/***************************************************************************
+
+ Tab Products E22 Keyboard (HLE)
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_E22_KBD_H
+#define MAME_MACHINE_E22_KBD_H
+
+#pragma once
+
+#include "machine/keyboard.h"
+#include "diserial.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> e22_kbd_hle_device
+
+class e22_kbd_hle_device : public device_t,
+ public device_buffered_serial_interface<16>,
+ protected device_matrix_keyboard_interface<8>
+{
+public:
+ // construction/destruction
+ e22_kbd_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ // callbacks
+ auto tx_handler() { return m_tx_handler.bind(); }
+ auto cts_handler() { return m_cts_handler.bind(); }
+
+ // from host
+ void rx_w(int state);
+
+protected:
+ // device_t overrides
+ virtual ioport_constructor device_input_ports() const override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_buffered_serial_interface overrides
+ virtual void tra_callback() override;
+ virtual void received_byte(uint8_t byte) override;
+
+ // device_matrix_keyboard_interface overrides
+ virtual void key_make(uint8_t row, uint8_t column) override;
+ virtual void key_break(uint8_t row, uint8_t column) override;
+ virtual void key_repeat(uint8_t row, uint8_t column) override;
+
+private:
+ devcb_write_line m_tx_handler;
+ devcb_write_line m_cts_handler;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(E22_KBD_HLE, e22_kbd_hle_device)
+
+#endif // MAME_MACHINE_E22_KBD_H
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 16358e82305..430c0fcecef 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -10407,7 +10407,6 @@ cit101xl //
@source:cit220.cpp
cit220p // (c) 1984 C. Itoh
-tabe22 //
vp122 //
@source:cit1500.cpp
@@ -39465,6 +39464,9 @@ tturfbl // (c) 1989 (Datsu bootleg)
wb3bbl // bootleg
wb3bble // bootleg
+@source:tabe22.cpp
+tabe22 // (c) Tab Products
+
@source:tagteam.cpp
bigprowr // TA-0007 (c) 1983
tagteam // TA-0007 (c) 1983 + Data East license
diff --git a/src/mame/mess.flt b/src/mame/mess.flt
index 022d3008603..3832a298ddf 100644
--- a/src/mame/mess.flt
+++ b/src/mame/mess.flt
@@ -984,6 +984,7 @@ sys2900.cpp
sys9002.cpp
systec.cpp
systel1.cpp
+tabe22.cpp
talkingbb.cpp
talkingfb.cpp
tamag1.cpp