From 57d621860c8b3b53d41471d4fd10e5877bfddad6 Mon Sep 17 00:00:00 2001 From: AJR Date: Mon, 31 May 2021 22:13:44 -0400 Subject: tek410x: Add keyboard [AJR, Bitsavers] * tek440x: Hook up 410X keyboard to pass boot test * mc68681: Wait until transmitter is actually empty to set TxEMT --- scripts/target/mame/mess.lua | 2 + src/devices/machine/mc68681.cpp | 22 +-- src/mame/drivers/tek410x.cpp | 238 +++++++++++++++++++++--- src/mame/drivers/tek440x.cpp | 87 ++++++++- src/mame/machine/tek410x_kbd.cpp | 385 +++++++++++++++++++++++++++++++++++++++ src/mame/machine/tek410x_kbd.h | 69 +++++++ 6 files changed, 751 insertions(+), 52 deletions(-) create mode 100644 src/mame/machine/tek410x_kbd.cpp create mode 100644 src/mame/machine/tek410x_kbd.h diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 84cd754592c..c034b9b403b 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -3908,6 +3908,8 @@ files { MAME_DIR .. "src/mame/drivers/tek440x.cpp", MAME_DIR .. "src/mame/drivers/tekigw.cpp", MAME_DIR .. "src/mame/drivers/tekxp33x.cpp", + MAME_DIR .. "src/mame/machine/tek410x_kbd.cpp", + MAME_DIR .. "src/mame/machine/tek410x_kbd.h", } createMESSProjects(_target, _subtarget, "telenova") diff --git a/src/devices/machine/mc68681.cpp b/src/devices/machine/mc68681.cpp index 6ab7e2f69fe..645b7c9deba 100644 --- a/src/devices/machine/mc68681.cpp +++ b/src/devices/machine/mc68681.cpp @@ -1269,7 +1269,7 @@ void duart_channel::tra_complete() { //printf("%s ch %d Tx complete\n", tag(), m_ch); tx_ready = 1; - SR |= STATUS_TRANSMITTER_READY; + SR |= STATUS_TRANSMITTER_READY | STATUS_TRANSMITTER_EMPTY; if (m_ch == 0) m_uart->set_ISR_bits(INT_TXRDYA); @@ -1319,24 +1319,13 @@ void duart_channel::update_interrupts() switch (MR2 & 0xc0) // what mode are we in? { case 0x00: // normal mode - if (tx_enabled) - SR |= STATUS_TRANSMITTER_EMPTY; - else - SR &= ~STATUS_TRANSMITTER_EMPTY; break; case 0x40: // automatic echo mode - SR &= ~STATUS_TRANSMITTER_EMPTY; SR &= ~STATUS_TRANSMITTER_READY; break; case 0x80: // local loopback mode - if (tx_enabled) - SR |= STATUS_TRANSMITTER_EMPTY; - else - SR &= ~STATUS_TRANSMITTER_EMPTY; break; case 0xc0: // remote loopback mode - // write me, what the txrdy/txemt regs do for remote loopback mode is undocumented afaik, for now just clear both - SR &= ~STATUS_TRANSMITTER_EMPTY; SR &= ~STATUS_TRANSMITTER_READY; break; } @@ -1571,7 +1560,8 @@ void duart_channel::write_CR(uint8_t data) break; case 3: /* Reset channel transmitter */ tx_enabled = 0; - SR &= ~STATUS_TRANSMITTER_READY; + tx_ready = 0; + SR &= ~(STATUS_TRANSMITTER_READY | STATUS_TRANSMITTER_EMPTY); if (m_ch == 0) m_uart->clear_ISR_bits(INT_TXRDYA); else @@ -1636,7 +1626,7 @@ void duart_channel::write_CR(uint8_t data) { tx_enabled = 1; tx_ready = 1; - SR |= STATUS_TRANSMITTER_READY; + SR |= STATUS_TRANSMITTER_READY | STATUS_TRANSMITTER_EMPTY; if (m_ch == 0) m_uart->set_ISR_bits(INT_TXRDYA); else @@ -1646,7 +1636,7 @@ void duart_channel::write_CR(uint8_t data) { tx_enabled = 0; tx_ready = 0; - SR &= ~STATUS_TRANSMITTER_READY; + SR &= ~(STATUS_TRANSMITTER_READY | STATUS_TRANSMITTER_EMPTY); if (m_ch == 0) m_uart->clear_ISR_bits(INT_TXRDYA); else @@ -1668,7 +1658,7 @@ void duart_channel::write_TX(uint8_t data) //printf("%s ch %d Tx %c [%02x]\n", tag(), m_ch, isprint(data) ? data : ' ', data); tx_ready = 0; - SR &= ~STATUS_TRANSMITTER_READY; + SR &= ~(STATUS_TRANSMITTER_READY | STATUS_TRANSMITTER_EMPTY); if (m_ch == 0) m_uart->clear_ISR_bits(INT_TXRDYA); diff --git a/src/mame/drivers/tek410x.cpp b/src/mame/drivers/tek410x.cpp index d32f726d3ee..0008fc7a21e 100644 --- a/src/mame/drivers/tek410x.cpp +++ b/src/mame/drivers/tek410x.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Curt Coder +// copyright-holders:Curt Coder, AJR /*************************************************************************** Tektronix 4107A/4109A @@ -8,19 +8,11 @@ ****************************************************************************/ -/* - - TODO: - - - everything - -*/ - - #include "emu.h" #include "cpu/i86/i186.h" #include "machine/i8255.h" #include "machine/mc68681.h" +#include "machine/tek410x_kbd.h" #include "video/crt9007.h" #include "emupal.h" #include "screen.h" @@ -31,7 +23,19 @@ class tek4107a_state : public driver_device public: tek4107a_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) + , m_duart(*this, "duart%u", 0U) + , m_keyboard(*this, "keyboard") , m_vpac(*this, "vpac") + , m_ppi_pc(0) + , m_kb_rdata(true) + , m_kb_tdata(true) + , m_kb_rclamp(false) + , m_graphics_control(0) + , m_alpha_control(0) + , m_x_position(0) + , m_y_position(0) + , m_x_cursor(0) + , m_y_cursor(0) { } void tek4109a(machine_config &config); @@ -46,10 +50,45 @@ private: u8 vpac_r(offs_t offset); + u16 nmi_enable_r(); + u16 nmi_disable_r(); + u16 system_reset_r(); + + void ppi_pc_w(u8 data); + DECLARE_WRITE_LINE_MEMBER(kb_rdata_w); + DECLARE_WRITE_LINE_MEMBER(kb_tdata_w); + DECLARE_WRITE_LINE_MEMBER(kb_rclamp_w); + + void xpos_w(u16 data); + void ypos_w(u16 data); + void xcur_w(u16 data); + void ycur_w(u16 data); + void tbwin_w(u16 data); + u16 gcntl_r(); + void gcntl_w(u16 data); + u16 acntl_r(); + void acntl_w(u16 data); + u16 test_r(); + u8 font_r(); + void tek4107a_io(address_map &map); void tek4107a_mem(address_map &map); + required_device_array m_duart; + required_device m_keyboard; required_device m_vpac; + + u8 m_ppi_pc; + bool m_kb_rdata; + bool m_kb_tdata; + bool m_kb_rclamp; + + u16 m_graphics_control; + u16 m_alpha_control; + u16 m_x_position; + u16 m_y_position; + u16 m_x_cursor; + u16 m_y_cursor; }; u8 tek4107a_state::vpac_r(offs_t offset) @@ -57,22 +96,150 @@ u8 tek4107a_state::vpac_r(offs_t offset) return m_vpac->read(offset + 0x20); } +u16 tek4107a_state::nmi_enable_r() +{ + // TODO + return 0; +} + +u16 tek4107a_state::nmi_disable_r() +{ + // TODO + return 0; +} + +u16 tek4107a_state::system_reset_r() +{ + // TODO + return 0; +} + +void tek4107a_state::ppi_pc_w(u8 data) +{ + if (!m_kb_rclamp && BIT(m_ppi_pc, 2) != BIT(data, 2)) + m_keyboard->kdo_w(!BIT(data, 2) || m_kb_tdata); + + m_ppi_pc = data; +} + +WRITE_LINE_MEMBER(tek4107a_state::kb_rdata_w) +{ + m_kb_rdata = state; + if (!m_kb_rclamp) + m_duart[0]->rx_a_w(state); +} + +WRITE_LINE_MEMBER(tek4107a_state::kb_rclamp_w) +{ + if (m_kb_rclamp != !state) + { + m_kb_rclamp = !state; + + // Clamp RXDA to 1 and KBRDATA to 0 when DUART asserts RxRDYA + if (m_kb_tdata || !BIT(m_ppi_pc, 2)) + m_keyboard->kdo_w(state); + m_duart[0]->rx_a_w(state ? m_kb_rdata : 1); + } +} + +WRITE_LINE_MEMBER(tek4107a_state::kb_tdata_w) +{ + if (m_kb_tdata != state) + { + m_kb_tdata = state; + + m_duart[0]->ip4_w(!state); + if (BIT(m_ppi_pc, 2) && m_kb_rdata && !m_kb_rclamp) + m_keyboard->kdo_w(state); + } +} + +void tek4107a_state::xpos_w(u16 data) +{ + m_x_position = data & 0x03ff; +} + +void tek4107a_state::ypos_w(u16 data) +{ + m_y_position = data & 0x01ff; +} + +void tek4107a_state::xcur_w(u16 data) +{ + m_x_cursor = data & 0x03ff; +} + +void tek4107a_state::ycur_w(u16 data) +{ + m_y_cursor = data & 0x01ff; +} + +void tek4107a_state::tbwin_w(u16 data) +{ + // TODO +} + +u16 tek4107a_state::gcntl_r() +{ + return m_graphics_control; +} + +void tek4107a_state::gcntl_w(u16 data) +{ + m_graphics_control = data; +} + +u16 tek4107a_state::acntl_r() +{ + return m_alpha_control; +} + +void tek4107a_state::acntl_w(u16 data) +{ + m_alpha_control = data; +} + +u16 tek4107a_state::test_r() +{ + // TODO + return 0; +} + +u8 tek4107a_state::font_r() +{ + // TODO + return 0; +} + + /* Memory Maps */ void tek4107a_state::tek4107a_mem(address_map &map) { - map(0x00000, 0x7ffff).ram(); + map(0x00000, 0x3ffff).ram(); + map(0x40000, 0x7ffff).ram().share("gfxram"); map(0x80000, 0xbffff).rom().region("firmware", 0); map(0xf0000, 0xfffff).rom().region("firmware", 0x30000); } void tek4107a_state::tek4107a_io(address_map &map) { - map(0x0000, 0x001f).rw("duart0", FUNC(scn2681_device::read), FUNC(scn2681_device::write)).umask16(0x00ff); - map(0x0000, 0x001f).rw("duart1", FUNC(scn2681_device::read), FUNC(scn2681_device::write)).umask16(0xff00); + map(0x0000, 0x001f).rw(m_duart[0], FUNC(scn2681_device::read), FUNC(scn2681_device::write)).umask16(0x00ff); + map(0x0000, 0x001f).rw(m_duart[1], FUNC(scn2681_device::read), FUNC(scn2681_device::write)).umask16(0xff00); map(0x0080, 0x00bf).r(FUNC(tek4107a_state::vpac_r)).w(m_vpac, FUNC(crt9007_device::write)).umask16(0x00ff); - map(0x00ce, 0x00cf).ram(); + map(0x00c0, 0x00c1).w(FUNC(tek4107a_state::xpos_w)); + map(0x00c2, 0x00c3).w(FUNC(tek4107a_state::ypos_w)); + map(0x00c4, 0x00c5).w(FUNC(tek4107a_state::xcur_w)); + map(0x00c6, 0x00c7).w(FUNC(tek4107a_state::ycur_w)); + map(0x00c8, 0x00c9).r(FUNC(tek4107a_state::test_r)); + map(0x00ca, 0x00ca).r(FUNC(tek4107a_state::font_r)); + map(0x00ca, 0x00cb).w(FUNC(tek4107a_state::tbwin_w)); + map(0x00cc, 0x00cd).rw(FUNC(tek4107a_state::gcntl_r), FUNC(tek4107a_state::gcntl_w)); + map(0x00ce, 0x00cf).rw(FUNC(tek4107a_state::acntl_r), FUNC(tek4107a_state::acntl_w)); map(0x0100, 0x0107).rw("ppi", FUNC(i8255_device::read), FUNC(i8255_device::write)).umask16(0xff00); + map(0x0200, 0x0201).r(FUNC(tek4107a_state::nmi_enable_r)); + map(0x0280, 0x0281).r(FUNC(tek4107a_state::system_reset_r)); + map(0x0300, 0x0301).r(FUNC(tek4107a_state::nmi_disable_r)); } /* Input Ports */ @@ -84,6 +251,12 @@ INPUT_PORTS_END void tek4107a_state::video_start() { + save_item(NAME(m_graphics_control)); + save_item(NAME(m_alpha_control)); + save_item(NAME(m_x_position)); + save_item(NAME(m_y_position)); + save_item(NAME(m_x_cursor)); + save_item(NAME(m_y_cursor)); } u32 tek4107a_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) @@ -110,6 +283,10 @@ GFXDECODE_END void tek4107a_state::machine_start() { + save_item(NAME(m_ppi_pc)); + save_item(NAME(m_kb_rdata)); + save_item(NAME(m_kb_tdata)); + save_item(NAME(m_kb_rclamp)); } /* Machine Driver */ @@ -117,25 +294,34 @@ void tek4107a_state::machine_start() void tek4107a_state::tek4107a(machine_config &config) { /* basic machine hardware */ - i80186_cpu_device &maincpu(I80186(config, "maincpu", 21000000)); + i80186_cpu_device &maincpu(I80186(config, "maincpu", 14.7456_MHz_XTAL)); maincpu.set_addrmap(AS_PROGRAM, &tek4107a_state::tek4107a_mem); maincpu.set_addrmap(AS_IO, &tek4107a_state::tek4107a_io); - /* video hardware */ - screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); - screen.set_raw(25200000, 800, 0, 640, 525, 0, 480); - screen.set_screen_update(FUNC(tek4107a_state::screen_update)); + SCN2681(config, m_duart[0], 14.7456_MHz_XTAL / 4); + m_duart[0]->irq_cb().set("maincpu", FUNC(i80186_cpu_device::int0_w)); + m_duart[0]->outport_cb().set_inputline("maincpu", INPUT_LINE_NMI).bit(5).invert(); // RxRDYB + m_duart[0]->outport_cb().append(FUNC(tek4107a_state::kb_rclamp_w)).bit(4); + m_duart[0]->outport_cb().append(m_keyboard, FUNC(tek410x_keyboard_device::reset_w)).bit(3); + m_duart[0]->a_tx_cb().set(m_keyboard, FUNC(tek410x_keyboard_device::kdi_w)); - scn2681_device &duart0(SCN2681(config, "duart0", 3686400)); - duart0.irq_cb().set("maincpu", FUNC(i80186_cpu_device::int0_w)); - duart0.outport_cb().set_inputline("maincpu", INPUT_LINE_NMI).bit(5).invert(); // RxRDYB + SCN2681(config, m_duart[1], 14.7456_MHz_XTAL / 4); + m_duart[1]->irq_cb().set("maincpu", FUNC(i80186_cpu_device::int2_w)); - scn2681_device &duart1(SCN2681(config, "duart1", 3686400)); - duart1.irq_cb().set("maincpu", FUNC(i80186_cpu_device::int2_w)); + i8255_device &ppi(I8255(config, "ppi")); + ppi.in_pb_callback().set_constant(0x30); + ppi.out_pc_callback().set(FUNC(tek4107a_state::ppi_pc_w)); - I8255(config, "ppi").in_pb_callback().set_constant(0x30); + TEK410X_KEYBOARD(config, m_keyboard); + m_keyboard->tdata_callback().set(FUNC(tek4107a_state::kb_tdata_w)); + m_keyboard->rdata_callback().set(FUNC(tek4107a_state::kb_rdata_w)); + + /* video hardware */ + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); + screen.set_raw(25.2_MHz_XTAL, 800, 0, 640, 525, 0, 480); + screen.set_screen_update(FUNC(tek4107a_state::screen_update)); - CRT9007(config, m_vpac, 25200000 / 8); + CRT9007(config, m_vpac, 25.2_MHz_XTAL / 8); m_vpac->set_screen("screen"); m_vpac->set_character_width(8); m_vpac->int_callback().set("maincpu", FUNC(i80186_cpu_device::int1_w)); diff --git a/src/mame/drivers/tek440x.cpp b/src/mame/drivers/tek440x.cpp index e04123889ee..a9a744e0963 100644 --- a/src/mame/drivers/tek440x.cpp +++ b/src/mame/drivers/tek440x.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:R. Belmont +// copyright-holders:R. Belmont, AJR /*************************************************************************** Tektronix 440x "AI Workstations" @@ -45,12 +45,12 @@ #include "bus/rs232/rs232.h" #include "cpu/m68000/m68000.h" #include "cpu/m6502/m6502.h" -#include "cpu/mcs48/mcs48.h" #include "machine/am9513.h" #include "machine/bankdev.h" #include "machine/mos6551.h" // debug tty #include "machine/mc146818.h" #include "machine/mc68681.h" +#include "machine/tek410x_kbd.h" #include "sound/sn76496.h" #include "emupal.h" #include "screen.h" @@ -65,10 +65,17 @@ public: m_maincpu(*this, "maincpu"), m_fdccpu(*this, "fdccpu"), m_vm(*this, "vm"), + m_duart(*this, "duart"), + m_keyboard(*this, "keyboard"), m_snsnd(*this, "snsnd"), m_prom(*this, "maincpu"), m_mainram(*this, "mainram"), - m_vram(*this, "vram") + m_vram(*this, "vram"), + m_boot(false), + m_kb_rdata(true), + m_kb_tdata(true), + m_kb_rclamp(false), + m_kb_loop(false) { } void tek4404(machine_config &config); @@ -81,6 +88,11 @@ private: u16 memory_r(offs_t offset, u16 mem_mask); void memory_w(offs_t offset, u16 data, u16 mem_mask); void sound_w(u8 data); + void diag_w(u8 data); + + DECLARE_WRITE_LINE_MEMBER(kb_rdata_w); + DECLARE_WRITE_LINE_MEMBER(kb_tdata_w); + DECLARE_WRITE_LINE_MEMBER(kb_rclamp_w); void logical_map(address_map &map); void physical_map(address_map &map); @@ -89,12 +101,18 @@ private: required_device m_maincpu; required_device m_fdccpu; required_device m_vm; + required_device m_duart; + required_device m_keyboard; required_device m_snsnd; required_region_ptr m_prom; required_shared_ptr m_mainram; required_shared_ptr m_vram; bool m_boot; + bool m_kb_rdata; + bool m_kb_tdata; + bool m_kb_rclamp; + bool m_kb_loop; }; /************************************* @@ -106,6 +124,10 @@ private: void tek440x_state::machine_start() { save_item(NAME(m_boot)); + save_item(NAME(m_kb_rdata)); + save_item(NAME(m_kb_tdata)); + save_item(NAME(m_kb_rclamp)); + save_item(NAME(m_kb_loop)); } @@ -119,6 +141,8 @@ void tek440x_state::machine_start() void tek440x_state::machine_reset() { m_boot = true; + diag_w(0); + m_keyboard->kdo_w(1); } @@ -178,6 +202,46 @@ void tek440x_state::sound_w(u8 data) m_boot = false; } +void tek440x_state::diag_w(u8 data) +{ + if (!m_kb_rclamp && m_kb_loop != BIT(data, 7)) + m_keyboard->kdo_w(!BIT(data, 7) || m_kb_tdata); + + m_kb_loop = BIT(data, 7); +} + +WRITE_LINE_MEMBER(tek440x_state::kb_rdata_w) +{ + m_kb_rdata = state; + if (!m_kb_rclamp) + m_duart->rx_a_w(state); +} + +WRITE_LINE_MEMBER(tek440x_state::kb_rclamp_w) +{ + if (m_kb_rclamp != !state) + { + m_kb_rclamp = !state; + + // Clamp RXDA to 1 and KBRDATA to 0 when DUART asserts RxRDYA + if (m_kb_tdata || !m_kb_loop) + m_keyboard->kdo_w(state); + m_duart->rx_a_w(state ? m_kb_rdata : 1); + } +} + +WRITE_LINE_MEMBER(tek440x_state::kb_tdata_w) +{ + if (m_kb_tdata != state) + { + m_kb_tdata = state; + + m_duart->ip4_w(!state); + if (m_kb_loop && m_kb_rdata && !m_kb_rclamp) + m_keyboard->kdo_w(state); + } +} + void tek440x_state::logical_map(address_map &map) { map(0x000000, 0x7fffff).rw(FUNC(tek440x_state::memory_r), FUNC(tek440x_state::memory_w)); @@ -195,9 +259,10 @@ void tek440x_state::physical_map(address_map &map) map(0x788000, 0x788000).w(FUNC(tek440x_state::sound_w)); // 78a000-78bfff: NS32081 FPU map(0x78c000, 0x78c007).rw("aica", FUNC(mos6551_device::read), FUNC(mos6551_device::write)).umask16(0xff00); + map(0x7b0000, 0x7b0000).w(FUNC(tek440x_state::diag_w)); // 7b1000-7b2fff: diagnostic registers // 7b2000-7b3fff: Centronics printer data - map(0x7b4000, 0x7b401f).rw("duart", FUNC(mc68681_device::read), FUNC(mc68681_device::write)).umask16(0xff00); + map(0x7b4000, 0x7b401f).rw(m_duart, FUNC(mc68681_device::read), FUNC(mc68681_device::write)).umask16(0xff00); // 7b6000-7b7fff: Mouse map(0x7b8000, 0x7b8003).mirror(0x100).rw("timer", FUNC(am9513_device::read16), FUNC(am9513_device::write16)); // 7ba000-7bbfff: MC146818 RTC @@ -254,10 +319,15 @@ void tek440x_state::tek4404(machine_config &config) aica.txd_handler().set("rs232", FUNC(rs232_port_device::write_txd)); aica.irq_handler().set_inputline(m_maincpu, M68K_IRQ_7); - mc68681_device &duart(MC68681(config, "duart", 3.6864_MHz_XTAL)); - duart.irq_cb().set_inputline(m_maincpu, M68K_IRQ_5); + MC68681(config, m_duart, 3.6864_MHz_XTAL); + m_duart->irq_cb().set_inputline(m_maincpu, M68K_IRQ_5); // auto-vectored + m_duart->outport_cb().set(FUNC(tek440x_state::kb_rclamp_w)).bit(4); + m_duart->outport_cb().append(m_keyboard, FUNC(tek410x_keyboard_device::reset_w)).bit(3); + m_duart->a_tx_cb().set(m_keyboard, FUNC(tek410x_keyboard_device::kdi_w)); - I8048(config, "kbdmcu", 4.608_MHz_XTAL).set_disable(); + TEK410X_KEYBOARD(config, m_keyboard); + m_keyboard->tdata_callback().set(FUNC(tek440x_state::kb_tdata_w)); + m_keyboard->rdata_callback().set(FUNC(tek440x_state::kb_rdata_w)); AM9513(config, "timer", 40_MHz_XTAL / 4 / 10); // from CPU E output @@ -293,9 +363,6 @@ ROM_START( tek4404 ) ROM_REGION( 0x2000, "scsimfm", 0 ) ROM_LOAD( "scsi_mfm.bin", 0x000000, 0x002000, CRC(b4293435) SHA1(5e2b96c19c4f5c63a5afa2de504d29fe64a4c908) ) - - ROM_REGION( 0x400, "kbdmcu", 0 ) - ROM_LOAD( "keytronic_8x48.bin", 0x000, 0x400, NO_DUMP ) ROM_END /************************************* diff --git a/src/mame/machine/tek410x_kbd.cpp b/src/mame/machine/tek410x_kbd.cpp new file mode 100644 index 00000000000..4d0d1beea46 --- /dev/null +++ b/src/mame/machine/tek410x_kbd.cpp @@ -0,0 +1,385 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/********************************************************************** + + This emulates the standard serial keyboard used with Tektronix's + 4105, 4106, 4107 and 4109 terminals, including the trademark + octagonal "joy disk". The 4404 keyboard is also compatible. + + The hardware was designed by the Keytronic Corporation, and uses + their 20-pin key strobe driver (22-0950-003) and input receiver + (22-0908-003) ASICs. + + The 8048/8748's DB pins are connected to drivers for up to 5 LEDs, + but only one of these LEDs (CR9, on the Caps Lock key) is actually + populated. + + A different but apparently backward-compatible keyboard was used + with the CX4107 and CX4109, based on a 8051 CPU with space for an + external program ROM and adding an onboard speaker as well as many + extra keys and an IBM 3279-style layout. + + Hexadecimal table of press codes (release codes are the same + 80): + + 00 Caps Lock + 01 Left Shift + 02 Right Shift + 03 Ctrl + 04 DEras/SEras + 05 Break + 06 Back Space + 07 Tab + 08 Line Feed + 09 Return + 0A Esc + 0B Space Bar + 0C " ' + 0D < , + 0E _ - + 0F > . + 10 ? / + 11 ) 0 + 12 ! 1 + 13 @ 2 + 14 # 3 + 15 $ 4 + 16 % 5 + 17 ^ 6 + 18 & 7 + 19 * 8 + 1A ( 9 + 1B : ; + 1C = + 1D A + 1E B + 1F C + 20 D + 21 E + 22 F + 23 G + 24 H + 25 I + 26 J + 27 K + 28 L + 29 M + 2A N + 2B O + 2C P + 2D Q + 2E R + 2F S + 30 T + 31 U + 32 V + 33 W + 34 X + 35 Y + 36 Z + 37 { [ + 38 ` \ + 39 } ] + 3A ~ | + 3B Rub Out + 3C Enter (keypad) + 3D , (keypad) + 3E - (keypad) + 3F . (keypad) + 40 0 (keypad) + 41 1 (keypad) + 42 2 (keypad) + 43 3 (keypad) + 44 4 (keypad) + 45 5 (keypad) + 46 6 (keypad) + 47 7 (keypad) + 48 8 (keypad) + 49 9 (keypad) + 4A F1 + 4B F2 + 4C F3 + 4D F4 + 4E F5 + 4F F6 + 50 F7 + 51 F8 + 52 GEras/Dialog + 53 Cancel/Setup + 54 DCopy/SCopy + 55 Menu + 56 Cursor Right (joystick) + 57 Cursor Up (joystick) + 58 Cursor Left (joystick) + 59 Cursor Down (joystick) + + Additional press codes for CX keyboard only: + + 5A Erase EOF + 5B Dup/PA1 + 5C Reset/Dev Cncl + 5D Field Mark/PA2/_ + 5E Attn Sys Req + 5F Cursr Sel/Clear + 60 < > + 61 Cursr Blink/Alt Cursr + 62 Ident + 63 Down Arrow + 64 Right Arrow/Right Double Arrow + 65 Left Arrow/Left Double Arrow + 66 Up Arrow + 67 Insert/Alpha + 68 Right Alt/Ctrl + + The baud rate is 4800, with 8 data bits and no parity. + +**********************************************************************/ + +#include "emu.h" +#include "tek410x_kbd.h" + +// device type definition +DEFINE_DEVICE_TYPE(TEK410X_KEYBOARD, tek410x_keyboard_device, "tek410x_kbd", "Tektronix 410X Standard Keyboard (119-1592-01)") + +tek410x_keyboard_device::tek410x_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, TEK410X_KEYBOARD, tag, owner, clock) + , m_mcu(*this, "mcu") + , m_key_matrix(*this, "X%u", 0U) + , m_config(*this, "CONFIG") + , m_tdata_callback(*this) + , m_rdata_callback(*this) + , m_select(0) + , m_p2_out(0) + , m_kdi(true) + , m_kdo(false) +{ +} + +void tek410x_keyboard_device::device_resolve_objects() +{ + m_tdata_callback.resolve_safe(); + m_rdata_callback.resolve_safe(); +} + +void tek410x_keyboard_device::device_start() +{ + save_item(NAME(m_select)); + save_item(NAME(m_p2_out)); + save_item(NAME(m_kdi)); + save_item(NAME(m_kdo)); +} + +WRITE_LINE_MEMBER(tek410x_keyboard_device::kdi_w) +{ + m_kdi = state; + if (BIT(m_p2_out, 7)) + { + m_mcu->set_input_line(MCS48_INPUT_IRQ, state ? CLEAR_LINE : ASSERT_LINE); + m_tdata_callback(state); + } +} + +WRITE_LINE_MEMBER(tek410x_keyboard_device::kdo_w) +{ + m_kdo = state; + if (BIT(m_p2_out, 5)) + m_rdata_callback(state); +} + +WRITE_LINE_MEMBER(tek410x_keyboard_device::reset_w) +{ + m_mcu->set_input_line(INPUT_LINE_RESET, state ? CLEAR_LINE : ASSERT_LINE); + if (!state) + p2_w(0xff); +} + +u8 tek410x_keyboard_device::p1_r() +{ + if (m_select < 12) + return m_key_matrix[m_select]->read(); + else + return 0xff; +} + +u8 tek410x_keyboard_device::p2_r() +{ + return 0xb0 | (m_kdo ? (m_p2_out & 0x20) << 1 : 0) | m_config->read(); +} + +void tek410x_keyboard_device::p2_w(u8 data) +{ + if (!BIT(data, 4)) + m_select = m_mcu->p1_r() & 0x0f; + + if (m_kdi && BIT(data, 7) != BIT(m_p2_out, 7)) + { + m_tdata_callback(BIT(data, 7)); + m_mcu->set_input_line(MCS48_INPUT_IRQ, BIT(data, 7) ? CLEAR_LINE : ASSERT_LINE); + } + + if (m_kdo && BIT(data, 5) != BIT(m_p2_out, 5)) + m_rdata_callback(BIT(data, 5)); + + m_p2_out = data; +} + +void tek410x_keyboard_device::ext_map(address_map &map) +{ + map(0x00, 0xff).nopr(); +} + +static INPUT_PORTS_START(tek410x_keyboard) + PORT_START("X0") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) PORT_CODE(KEYCODE_ENTER_PAD) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(COMMA_PAD)) PORT_CODE(KEYCODE_PLUS_PAD) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) PORT_CODE(KEYCODE_3_PAD) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) PORT_CODE(KEYCODE_6_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) PORT_CODE(KEYCODE_MINUS_PAD) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) PORT_CODE(KEYCODE_9_PAD) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) PORT_CODE(KEYCODE_DEL_PAD) + + PORT_START("X1") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) PORT_CODE(KEYCODE_4_PAD) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) PORT_CODE(KEYCODE_2_PAD) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) PORT_CODE(KEYCODE_5_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) PORT_CODE(KEYCODE_7_PAD) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) PORT_CODE(KEYCODE_1_PAD) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) PORT_CODE(KEYCODE_8_PAD) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) PORT_CODE(KEYCODE_0_PAD) + + PORT_START("X2") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Break") //PORT_CODE(KEYCODE_XXX) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Line Feed") PORT_CHAR(0x0a) //PORT_CODE(KEYCODE_XXX) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Rub Out") PORT_CODE(KEYCODE_BACKSPACE) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(']') PORT_CHAR('}') PORT_CODE(KEYCODE_BACKSLASH) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("X3") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Right Shift") PORT_CODE(KEYCODE_RSHIFT) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('\\') PORT_CHAR('`') PORT_CODE(KEYCODE_OPENBRACE) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('\'') PORT_CHAR('"') PORT_CODE(KEYCODE_QUOTE) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Back Space") PORT_CHAR(0x08) PORT_CODE(KEYCODE_CLOSEBRACE) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('-') PORT_CHAR('_') PORT_CODE(KEYCODE_MINUS) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Return") PORT_CHAR(0x0d) PORT_CODE(KEYCODE_ENTER) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('=') PORT_CHAR('+') PORT_CODE(KEYCODE_EQUALS) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Space Bar") PORT_CHAR(' ') PORT_CODE(KEYCODE_SPACE) + + PORT_START("X4") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_CODE(KEYCODE_DOWN) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_CODE(KEYCODE_LEFT) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F7)) PORT_CODE(KEYCODE_F11) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_CODE(KEYCODE_F6) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F6)) PORT_CODE(KEYCODE_F10) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Setup Cancel") PORT_CODE(KEYCODE_F2) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CODE(KEYCODE_F7) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("SCopy DCopy") PORT_CODE(KEYCODE_F3) + + PORT_START("X5") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_CODE(KEYCODE_RIGHT) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_CODE(KEYCODE_UP) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F8)) PORT_CODE(KEYCODE_F12) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CODE(KEYCODE_F5) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_CODE(KEYCODE_F9) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Dialog GEras") PORT_CODE(KEYCODE_F1) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_CODE(KEYCODE_F8) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Menu") PORT_CODE(KEYCODE_F4) + + PORT_START("X6") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("X") PORT_CHAR('x') PORT_CHAR('X') PORT_CODE(KEYCODE_X) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("W") PORT_CHAR('w') PORT_CHAR('W') PORT_CODE(KEYCODE_W) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("S") PORT_CHAR('s') PORT_CHAR('S') PORT_CODE(KEYCODE_S) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Q") PORT_CHAR('q') PORT_CHAR('Q') PORT_CODE(KEYCODE_Q) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('2') PORT_CHAR('@') PORT_CODE(KEYCODE_2) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A") PORT_CHAR('a') PORT_CHAR('A') PORT_CODE(KEYCODE_A) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('1') PORT_CHAR('!') PORT_CODE(KEYCODE_1) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Z") PORT_CHAR('z') PORT_CHAR('Z') PORT_CODE(KEYCODE_Z) + + PORT_START("X7") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Caps Lock") PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) PORT_CODE(KEYCODE_LCONTROL) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CHAR(0x1b) //PORT_CODE(KEYCODE_XXX) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CHAR(0x09) //PORT_CODE(KEYCODE_XXX) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('|') PORT_CHAR('~') PORT_CODE(KEYCODE_TAB) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("SEras DEras") //PORT_CODE(KEYCODE_XXX) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CHAR(UCHAR_SHIFT_2) PORT_CODE(KEYCODE_CAPSLOCK) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('[') PORT_CHAR('{') PORT_CODE(KEYCODE_TILDE) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Left Shift") PORT_CHAR(UCHAR_SHIFT_1) PORT_CODE(KEYCODE_LSHIFT) + + PORT_START("X8") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C") PORT_CHAR('c') PORT_CHAR('C') PORT_CODE(KEYCODE_C) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E") PORT_CHAR('e') PORT_CHAR('E') PORT_CODE(KEYCODE_E) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D") PORT_CHAR('d') PORT_CHAR('D') PORT_CODE(KEYCODE_D) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("R") PORT_CHAR('r') PORT_CHAR('R') PORT_CODE(KEYCODE_R) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('3') PORT_CHAR('#') PORT_CODE(KEYCODE_3) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F") PORT_CHAR('f') PORT_CHAR('F') PORT_CODE(KEYCODE_F) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('4') PORT_CHAR('$') PORT_CODE(KEYCODE_4) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("V") PORT_CHAR('v') PORT_CHAR('V') PORT_CODE(KEYCODE_V) + + PORT_START("X9") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("N") PORT_CHAR('n') PORT_CHAR('N') PORT_CODE(KEYCODE_N) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Y") PORT_CHAR('y') PORT_CHAR('Y') PORT_CODE(KEYCODE_Y) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("H") PORT_CHAR('h') PORT_CHAR('H') PORT_CODE(KEYCODE_H) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("T") PORT_CHAR('t') PORT_CHAR('T') PORT_CODE(KEYCODE_T) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('6') PORT_CHAR('^') PORT_CODE(KEYCODE_6) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G") PORT_CHAR('g') PORT_CHAR('G') PORT_CODE(KEYCODE_G) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('5') PORT_CHAR('%') PORT_CODE(KEYCODE_5) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B") PORT_CHAR('b') PORT_CHAR('B') PORT_CODE(KEYCODE_B) + + PORT_START("X10") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("M") PORT_CHAR('m') PORT_CHAR('M') PORT_CODE(KEYCODE_M) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("U") PORT_CHAR('u') PORT_CHAR('U') PORT_CODE(KEYCODE_U) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("J") PORT_CHAR('j') PORT_CHAR('J') PORT_CODE(KEYCODE_J) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("I") PORT_CHAR('i') PORT_CHAR('I') PORT_CODE(KEYCODE_I) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('7') PORT_CHAR('&') PORT_CODE(KEYCODE_7) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("K") PORT_CHAR('k') PORT_CHAR('K') PORT_CODE(KEYCODE_K) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('8') PORT_CHAR('*') PORT_CODE(KEYCODE_8) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(',') PORT_CHAR('>') PORT_CODE(KEYCODE_COMMA) + + PORT_START("X11") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('/') PORT_CHAR('?') PORT_CODE(KEYCODE_SLASH) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("P") PORT_CHAR('p') PORT_CHAR('P') PORT_CODE(KEYCODE_P) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(';') PORT_CHAR(':') PORT_CODE(KEYCODE_COLON) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("O") PORT_CHAR('o') PORT_CHAR('O') PORT_CODE(KEYCODE_O) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('0') PORT_CHAR('(') PORT_CODE(KEYCODE_0) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("L") PORT_CHAR('l') PORT_CHAR('L') PORT_CODE(KEYCODE_L) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('9') PORT_CHAR(')') PORT_CODE(KEYCODE_9) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('.') PORT_CHAR('>') PORT_CODE(KEYCODE_STOP) + + PORT_START("CONFIG") + PORT_DIPNAME(0x0f, 0x00, "Keyboard Type") PORT_DIPLOCATION("E:1,2,3,4") + PORT_DIPSETTING(0x00, "North America") + PORT_DIPSETTING(0x08, "United Kingdom (4A)") + PORT_DIPSETTING(0x04, "French (4B)") + PORT_DIPSETTING(0x02, "Swedish (4C)") + PORT_DIPSETTING(0x06, "Danish/Norwegian (4F)") + PORT_DIPSETTING(0x07, "German (4G)") + PORT_DIPSETTING(0x0a, "Katakana (4K)") +INPUT_PORTS_END + +ioport_constructor tek410x_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(tek410x_keyboard); +} + +void tek410x_keyboard_device::device_add_mconfig(machine_config &config) +{ + I8748(config, m_mcu, 4.608_MHz_XTAL); + m_mcu->set_addrmap(AS_IO, &tek410x_keyboard_device::ext_map); + m_mcu->bus_out_cb().set_output("led0").bit(0); + m_mcu->p1_in_cb().set(FUNC(tek410x_keyboard_device::p1_r)); + m_mcu->p2_in_cb().set(FUNC(tek410x_keyboard_device::p2_r)); + m_mcu->p2_out_cb().set(FUNC(tek410x_keyboard_device::p2_w)); +} + +ROM_START(tek410x_kbd) + ROM_REGION(0x400, "mcu", 0) + ROM_LOAD("473_8748.bin", 0x000, 0x400, CRC(371553a8) SHA1(165ffc2c0775c1a3c2cc3ec86fb05adc8e8bb3eb)) +ROM_END + +const tiny_rom_entry *tek410x_keyboard_device::device_rom_region() const +{ + return ROM_NAME(tek410x_kbd); +} diff --git a/src/mame/machine/tek410x_kbd.h b/src/mame/machine/tek410x_kbd.h new file mode 100644 index 00000000000..095f7648094 --- /dev/null +++ b/src/mame/machine/tek410x_kbd.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_MACHINE_TEK410X_KEYBOARD_H +#define MAME_MACHINE_TEK410X_KEYBOARD_H + +#pragma once + +#include "cpu/mcs48/mcs48.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> tek410x_keyboard_device + +class tek410x_keyboard_device : public device_t +{ +public: + // device type constructor + tek410x_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); + + // callback configuration + auto tdata_callback() { return m_tdata_callback.bind(); } + auto rdata_callback() { return m_rdata_callback.bind(); } + + // line inputs + DECLARE_WRITE_LINE_MEMBER(kdi_w); + DECLARE_WRITE_LINE_MEMBER(kdo_w); + DECLARE_WRITE_LINE_MEMBER(reset_w); + +protected: + // device-level overrides + virtual void device_resolve_objects() override; + virtual void device_start() override; + virtual ioport_constructor device_input_ports() const override; + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; + +private: + // MCU handlers + u8 p1_r(); + u8 p2_r(); + void p2_w(u8 data); + + // address maps + void ext_map(address_map &map); + + // object finders + required_device m_mcu; + required_ioport_array<12> m_key_matrix; + required_ioport m_config; + + // output callbacks + devcb_write_line m_tdata_callback; + devcb_write_line m_rdata_callback; + + // internal state + u8 m_select; + u8 m_p2_out; + bool m_kdi; + bool m_kdo; +}; + +// device type declaration +DECLARE_DEVICE_TYPE(TEK410X_KEYBOARD, tek410x_keyboard_device) + +#endif // MAME_MACHINE_TEK410X_KEYBOARD_H -- cgit v1.2.3