From c398cf3073a50a0f063b267aab8b9ea53012b610 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Fri, 22 Sep 2023 14:31:27 +0700 Subject: dec: reorganize and rename some device files --- scripts/src/machine.lua | 12 - scripts/src/video.lua | 11 - src/devices/machine/dc7085.cpp | 361 ---------------- src/devices/machine/dc7085.h | 113 ----- src/devices/video/decsfb.cpp | 172 -------- src/devices/video/decsfb.h | 38 -- src/mame/dec/dc7085.cpp | 361 ++++++++++++++++ src/mame/dec/dc7085.h | 113 +++++ src/mame/dec/dec_lk201.cpp | 916 ----------------------------------------- src/mame/dec/dec_lk201.h | 132 ------ src/mame/dec/decmate2.cpp | 2 +- src/mame/dec/decstation.cpp | 9 +- src/mame/dec/lk201.cpp | 916 +++++++++++++++++++++++++++++++++++++++++ src/mame/dec/lk201.h | 132 ++++++ src/mame/dec/rainbow.cpp | 4 +- src/mame/dec/sfb.cpp | 172 ++++++++ src/mame/dec/sfb.h | 38 ++ src/mame/dec/vt240.cpp | 2 +- 18 files changed, 1741 insertions(+), 1763 deletions(-) delete mode 100644 src/devices/machine/dc7085.cpp delete mode 100644 src/devices/machine/dc7085.h delete mode 100644 src/devices/video/decsfb.cpp delete mode 100644 src/devices/video/decsfb.h create mode 100644 src/mame/dec/dc7085.cpp create mode 100644 src/mame/dec/dc7085.h delete mode 100644 src/mame/dec/dec_lk201.cpp delete mode 100644 src/mame/dec/dec_lk201.h create mode 100644 src/mame/dec/lk201.cpp create mode 100644 src/mame/dec/lk201.h create mode 100644 src/mame/dec/sfb.cpp create mode 100644 src/mame/dec/sfb.h diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index 5138a692fee..93946cfb50b 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -4839,18 +4839,6 @@ if (MACHINES["AIC6250"]~=null) then } end ---------------------------------------------------- --- ---@src/devices/machine/dc7085.h,MACHINES["DC7085"] = true ---------------------------------------------------- - -if (MACHINES["DC7085"]~=null) then - files { - MAME_DIR .. "src/devices/machine/dc7085.cpp", - MAME_DIR .. "src/devices/machine/dc7085.h", - } -end - --------------------------------------------------- -- --@src/devices/machine/i82357.h,MACHINES["I82357"] = true diff --git a/scripts/src/video.lua b/scripts/src/video.lua index e23e563cdea..69277f16e61 100644 --- a/scripts/src/video.lua +++ b/scripts/src/video.lua @@ -1661,17 +1661,6 @@ if (VIDEOS["PS2GS"]~=null) then } end --------------------------------------------------- --- ---@src/devices/video/decsfb.h,VIDEOS["DECSFB"] = true --------------------------------------------------- -if (VIDEOS["DECSFB"]~=null) then - files { - MAME_DIR .. "src/devices/video/decsfb.cpp", - MAME_DIR .. "src/devices/video/decsfb.h", - } -end - -------------------------------------------------- -- --@src/devices/video/bt47x.h,VIDEOS["BT47X"] = true diff --git a/src/devices/machine/dc7085.cpp b/src/devices/machine/dc7085.cpp deleted file mode 100644 index 37156a08494..00000000000 --- a/src/devices/machine/dc7085.cpp +++ /dev/null @@ -1,361 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:R. Belmont - -/* - * An emulation of the Digital Equipment Corporation DC7085 (also called "DZ") quad-UART - * - * Used in: - * - * Several models of MIPS DECstation - * Some VAXstations - * - * Sources: - * - * http://www.vanade.com/~blc/DS3100/pmax/DS3100.func.spec.pdf - * - */ - -#include "emu.h" -#include "dc7085.h" - -#define LOG_REG (1U << 1) -#define LOG_RX (1U << 2) -#define LOG_TX (1U << 3) -#define LOG_IRQ (1U << 4) - -//#define VERBOSE (LOG_GENERAL|LOG_REG|LOG_RX|LOG_TX|LOG_IRQ) - -#include "logmacro.h" - -DEFINE_DEVICE_TYPE(DC7085, dc7085_device, "dc7085", "Digital Equipment Corporation DC7085 Quad UART") -DEFINE_DEVICE_TYPE(DC7085_CHANNEL, dc7085_channel, "dc7085_channel", "DC7085 UART channel") - -enum csr_mask : u16 -{ - CSR_TRDY = 0x8000, // transmitter ready - CSR_TIE = 0x4000, // transmitter interrupt enable - CSR_TLINE = 0x0300, // transmitter line number - CSR_RDONE = 0x0080, // receiver done - CSR_RIE = 0x0040, // receiver interrupt enable - CSR_MSE = 0x0020, // master scan enable - CSR_CLR = 0x0010, // master clear - CSR_MAINT = 0x0008, // maintenance (loopback) -}; - -enum rbuf_mask : u16 -{ - RBUF_DVAL = 0x8000, // data valid - RBUF_OERR = 0x4000, // overrun error - RBUF_FERR = 0x2000, // framing error - RBUF_PERR = 0x1000, // parity error - RBUF_RLINE = 0x0300, // received line number - RBUF_RLINE3 = 0x0300, - RBUF_RLINE2 = 0x0200, - RBUF_RLINE1 = 0x0100, - RBUF_RLINE0 = 0x0000, - RBUF_DATA = 0x00ff, // received character -}; - -enum lpr_mask : u16 -{ - LPR_RXENAB = 0x1000, // receiver enable - LPR_SC = 0x0f00, // speed code - LPR_ODDPAR = 0x0080, // odd parity - LPR_PARENB = 0x0040, // parity enable - LPR_STOP = 0x0020, // stop code - LPR_CHAR = 0x0018, // character length - LPR_LINE = 0x0003, // parameter line number -}; - -enum tcr_mask : u16 -{ - TCR_DTR3 = 0x0800, // modem control - TCR_DTR2 = 0x0400, - TCR_DTR1 = 0x0200, - TCR_DTR0 = 0x0100, - TCR_LNENB3 = 0x0008, // transmitter line enable - TCR_LNENB2 = 0x0004, - TCR_LNENB1 = 0x0002, - TCR_LNENB0 = 0x0001, -}; - -enum tdr_mask : u16 -{ - TDR_BRK3 = 0x0800, // break control - TDR_BRK2 = 0x0400, - TDR_BRK1 = 0x0200, - TDR_BRK0 = 0x0100, - TDR_TBUF = 0x00ff, // transmitter buffer -}; - -dc7085_device::dc7085_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) - : device_t(mconfig, DC7085, tag, owner, clock) - , m_chan(*this, "ch%u", 0U) - , m_int_cb(*this) - , m_tx_cb(*this) - , m_dtr_cb(*this) - , m_int_state(false) -{ -} - -void dc7085_device::device_add_mconfig(machine_config &config) -{ - /* - * Configure all four channels such that: - * - line numbers are inesrted into received data words - * - transmitter output is looped back to receiver when enabled - * - transmitter completion is signalled - */ - for (unsigned i = 0; i < std::size(m_chan); i++) - { - DC7085_CHANNEL(config, m_chan[i], 0); - - m_chan[i]->rx_done().set([this, i](u16 data) { rx_done((i << 8) | data); }); - m_chan[i]->tx_cb().set([this, i](int state) { m_tx_cb[i](state); if (m_csr & CSR_MAINT) m_chan[i]->rx_w(state); }); - m_chan[i]->tx_done().set(*this, FUNC(dc7085_device::tx_done)); - } -} - -void dc7085_device::map(address_map &map) -{ - map(0x00, 0x01).rw(FUNC(dc7085_device::csr_r), FUNC(dc7085_device::csr_w)); - map(0x04, 0x05).rw(FUNC(dc7085_device::rbuf_r), FUNC(dc7085_device::lpr_w)); - map(0x08, 0x09).rw(FUNC(dc7085_device::tcr_r), FUNC(dc7085_device::tcr_w)); - map(0x0c, 0x0d).rw(FUNC(dc7085_device::msr_r), FUNC(dc7085_device::tdr_w)); -} - -void dc7085_device::device_start() -{ - save_item(NAME(m_csr)); - save_item(NAME(m_tcr)); - save_item(NAME(m_msr)); - //save_item(NAME(m_fifo)); - save_item(NAME(m_rx_buf)); - save_item(NAME(m_int_state)); -} - -void dc7085_device::device_reset() -{ - m_csr = 0; - m_tcr = 0; - m_msr = 0; - - m_fifo.clear(); - m_rx_buf = 0; - - set_int(false); -} - -u16 dc7085_device::rbuf_r() -{ - if (m_fifo.empty()) - return 0; - - u16 const data = m_fifo.dequeue(); - - LOGMASKED(LOG_RX, "rbuf_r 0x%04x fifo_length %d\n", data, m_fifo.queue_length()); - - if (m_fifo.empty()) - m_csr &= ~CSR_RDONE; - - // FIXME: insert pending data into fifo - if (m_rx_buf & RBUF_DVAL) - { - rx_fifo_push(m_rx_buf); - m_rx_buf = 0; - } - - recalc_irqs(); - - return data; -} - -void dc7085_device::csr_w(u16 data) -{ - LOGMASKED(LOG_REG, "csr_w %04x tie %d rie %d scan %d clear %d loopback %d\n", data, - bool(data & CSR_TIE), bool(data & CSR_RIE), bool(data & CSR_MSE), bool(data & CSR_CLR), bool(data & CSR_MAINT)); - - if (!(data & CSR_CLR)) - { - data &= (CSR_TIE | CSR_RIE | CSR_MSE | CSR_MAINT); - m_csr &= ~(CSR_TIE | CSR_RIE | CSR_MSE | CSR_MAINT); - m_csr |= data; - } - else - reset(); -} - -void dc7085_device::lpr_w(u16 data) -{ - static const int bauds[] = { 50, 75, 110, 134, 150, 300, 600, 1200, 1800, 2000, 2400, 3600, 4800, 7200, 9600, 19800 }; - - unsigned const baud = (data & LPR_SC) >> 8; - unsigned const data_bits = ((data & LPR_CHAR) >> 3) + 5; - unsigned const parity = (data & LPR_PARENB) ? ((data & LPR_ODDPAR) ? 1 : 2) : 0; - unsigned const stop_bits = (data & LPR_STOP) ? 2 : 1; - - m_chan[data & LPR_LINE]->set_format(bauds[baud], data_bits, parity, stop_bits); - m_chan[data & LPR_LINE]->set_enable(data & LPR_RXENAB); -} - -void dc7085_device::tcr_w(u16 data) -{ - LOGMASKED(LOG_REG, "tcr_w %04x\n", data); - - if ((data ^ m_tcr) & TCR_DTR0) - m_dtr_cb[0](bool(data & TCR_DTR0)); - if ((data ^ m_tcr) & TCR_DTR1) - m_dtr_cb[1](bool(data & TCR_DTR1)); - if ((data ^ m_tcr) & TCR_DTR2) - m_dtr_cb[2](bool(data & TCR_DTR2)); - if ((data ^ m_tcr) & TCR_DTR3) - m_dtr_cb[3](bool(data & TCR_DTR3)); - - m_tcr = data; - - recalc_irqs(); -} - -void dc7085_device::tdr_w(u16 data) -{ - LOGMASKED(LOG_REG, "tdr_w %04x (%s)\n", data, machine().describe_context()); - - unsigned const ch = (m_csr & CSR_TLINE) >> 8; - - if (BIT(m_tcr, ch)) - m_chan[ch]->tx_w(data & TDR_TBUF); - - m_csr &= ~CSR_TRDY; - recalc_irqs(); -} - -void dc7085_device::recalc_irqs() -{ - LOGMASKED(LOG_IRQ, "recalc_irqs enter\n"); - m_csr &= ~(CSR_TRDY | CSR_TLINE); - for (unsigned i = 0; i < 4; i++) - { - if (BIT(m_tcr, i) && m_chan[i]->tx_ready()) - { - m_csr |= CSR_TRDY; - m_csr |= (i << 8); - LOGMASKED(LOG_IRQ, "ch %u: set TRDY\n", i); - - break; - } - } - - set_int(((m_csr & CSR_TIE) && (m_csr & CSR_TRDY)) || ((m_csr & CSR_RIE) && (m_csr & CSR_RDONE))); -} - -void dc7085_device::rx_fifo_push(u16 data) -{ - if (!m_fifo.full()) - { - LOGMASKED(LOG_RX, "rx_fifo_push 0x%04x fifo_length %d\n", data, m_fifo.queue_length()); - - m_fifo.enqueue(data); - - m_csr |= CSR_RDONE; - } - else - throw emu_fatalerror("fifo overflow\n"); -} - -void dc7085_device::rx_done(u16 data) -{ - // check if receive buffer is full - if (m_rx_buf & RBUF_DVAL) - { - // push buffer into fifo if not full - if (!m_fifo.full()) - { - rx_fifo_push(m_rx_buf); - m_rx_buf = 0; - } - else - // flag buffer overrun - data |= RBUF_OERR; - } - - // store received data in fifo or buffer - if (!m_fifo.full()) - rx_fifo_push(data); - else - m_rx_buf = data; - - recalc_irqs(); -} - -void dc7085_device::tx_done(int state) -{ - recalc_irqs(); -} - -dc7085_channel::dc7085_channel(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) - : device_t(mconfig, DC7085_CHANNEL, tag, owner, clock) - , device_serial_interface(mconfig, *this) - , m_tx_cb(*this) - , m_tx_done(*this) - , m_rx_done(*this) - , m_rx_enabled(false) -{ -} - -void dc7085_channel::device_start() -{ - save_item(NAME(m_rx_enabled)); -} - -void dc7085_channel::device_reset() -{ - transmit_register_reset(); - - set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); - set_tra_rate(0); - set_rcv_rate(0); - - m_rx_enabled = false; -} - -void dc7085_channel::rcv_complete() -{ - receive_register_extract(); - - if (m_rx_enabled) - { - u16 data = RBUF_DVAL | get_received_char(); - - if (is_receive_framing_error()) - data |= RBUF_FERR; - if (is_receive_parity_error()) - data |= RBUF_PERR; - - m_rx_done(data); - } -} - -void dc7085_channel::tra_complete() -{ - m_tx_done(1); -} - -void dc7085_channel::tra_callback() -{ - m_tx_cb(transmit_register_get_data_bit()); -} - -void dc7085_channel::set_format(unsigned baud, unsigned data_bits, unsigned parity, unsigned stop_bits) -{ - set_data_frame(1, data_bits, parity ? (parity == 1 ? PARITY_ODD : PARITY_EVEN) : PARITY_NONE, - stop_bits == 1 ? STOP_BITS_1 : (data_bits == 5 ? STOP_BITS_1_5 : STOP_BITS_2)); - - set_tra_rate(baud); - set_rcv_rate(baud); -} - -void dc7085_channel::tx_w(u8 data) -{ - if (is_transmit_register_empty()) - transmit_register_setup(data); -} diff --git a/src/devices/machine/dc7085.h b/src/devices/machine/dc7085.h deleted file mode 100644 index dccb2bbefce..00000000000 --- a/src/devices/machine/dc7085.h +++ /dev/null @@ -1,113 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:R. Belmont - -#ifndef MAME_MACHINE_DC7085_H -#define MAME_MACHINE_DC7085_H - -#pragma once - -#include "diserial.h" - -class dc7085_channel - : public device_t - , public device_serial_interface -{ - friend class dc7085_device; - -public: - auto tx_cb() { return m_tx_cb.bind(); } - - dc7085_channel(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); - -protected: - // device_t overrides - virtual void device_start() override; - virtual void device_reset() override; - - // device_serial overrides - virtual void rcv_complete() override; - virtual void tra_complete() override; - virtual void tra_callback() override; - - // parent interface - auto rx_done() { return m_rx_done.bind(); } - auto tx_done() { return m_tx_done.bind(); } - - void set_format(unsigned baud, unsigned data_bits, unsigned parity, unsigned stop_bits); - void set_enable(bool enable) { m_rx_enabled = enable; } - bool tx_ready() const { return is_transmit_register_empty(); } - void tx_w(u8 data); - -private: - devcb_write_line m_tx_cb; - devcb_write_line m_tx_done; - devcb_write16 m_rx_done; - - bool m_rx_enabled; -}; - -class dc7085_device : public device_t -{ -public: - dc7085_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); - - void map(address_map &map); - - auto int_cb() { return m_int_cb.bind(); } - - template void rx_w(int state) { m_chan[Ch]->rx_w(state); } - template auto tx_cb() { return m_tx_cb[Ch].bind(); } - template auto dtr_cb() { return m_dtr_cb[Ch].bind(); } - -protected: - // device_t overrides - virtual void device_start() override; - virtual void device_reset() override; - virtual void device_add_mconfig(machine_config &config) override; - - // register accessors - u16 csr_r() { return m_csr; } - u16 rbuf_r(); - u16 tcr_r() { return m_tcr; } - u16 msr_r() { return m_msr; } - void csr_w(u16 data); - void lpr_w(u16 data); - void tcr_w(u16 data); - void tdr_w(u16 data); - - // helpers - void rx_fifo_push(u16 data); - void rx_done(u16 data); - void tx_done(int state); - void recalc_irqs(); - - void set_int(bool state) - { - if (state != m_int_state) - { - m_int_state = state; - m_int_cb(state); - } - } - -private: - required_device_array m_chan; - - devcb_write_line m_int_cb; - devcb_write_line::array<4> m_tx_cb; - devcb_write_line::array<4> m_dtr_cb; - - u16 m_csr; - u16 m_tcr; - u16 m_msr; - - util::fifo m_fifo; - u16 m_rx_buf; - - bool m_int_state; -}; - -DECLARE_DEVICE_TYPE(DC7085, dc7085_device) -DECLARE_DEVICE_TYPE(DC7085_CHANNEL, dc7085_channel) - -#endif // MAME_MACHINE_DC7085_H diff --git a/src/devices/video/decsfb.cpp b/src/devices/video/decsfb.cpp deleted file mode 100644 index df302d076f4..00000000000 --- a/src/devices/video/decsfb.cpp +++ /dev/null @@ -1,172 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:R. Belmont - -/* - * An emulation of the Digital Equipment Corporation SFB "Smart Frame Buffer" chip - * - * Used in: - * - * Accelerated TURBOChannel video cards for DECstations and AlphaStations - * On-board on some DECstations - * On-board on many AlphaStations - * - * Sources: - * - * http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-93-1.pdf - * - */ - -#include "emu.h" -#include "decsfb.h" - -#define MODE_SIMPLE 0 -#define MODE_OPAQUESTIPPLE 1 -#define MODE_OPAQUELINE 2 -#define MODE_TRANSPARENTSTIPPLE 5 -#define MODE_TRANSPARENTLINE 6 -#define MODE_COPY 7 - -#define LOG_REG (1U << 1) -#define LOG_IRQ (1U << 2) - -//#define VERBOSE (LOG_GENERAL|LOG_REG||LOG_IRQ) - -#include "logmacro.h" - -DEFINE_DEVICE_TYPE(DECSFB, decsfb_device, "decsfb", "Digital Equipment Corporation Smart Frame Buffer") - -decsfb_device::decsfb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, DECSFB, tag, owner, clock), - m_int_cb(*this) -{ -} - -void decsfb_device::device_start() -{ - save_item(NAME(m_vram)); - save_item(NAME(m_regs)); - save_item(NAME(m_copy_src)); -} - -void decsfb_device::device_reset() -{ - m_copy_src = 1; -} - -/* - 0x100000 copy register 0 - 0x100004 copy register 1 - 0x100008 copy register 2 - 0x10000C copy register 3 - 0x100010 copy register 4 - 0x100014 copy register 5 - 0x100018 copy register 6 - 0x10001C copy register 7 - 0x100020 foreground register - 0x100024 background register - 0x100028 plane mask - 0x10002C pixel mask - 0x100030 cxt mode - 0x100034 boolean operation - 0x100038 pixel shift - 0x10003C line address - 0x100040 bresh 1 - 0x100044 bresh 2 - 0x100048 bresh 3 - 0x10004C bresh continue - 0x100050 deep register - 0x100054 start register - 0x100058 Clear Interrupt - 0x10005C reserved 2 - 0x100060 refresh count - 0x100064 video horiz - 0x100068 video vertical - 0x10006C refresh base - 0x100070 video valid - 0x100074 Interrupt Enable -*/ - -u32 decsfb_device::read(offs_t offset) -{ - return m_regs[offset]; -} - -void decsfb_device::write(offs_t offset, u32 data, u32 mem_mask) -{ - COMBINE_DATA(&m_regs[offset]); - - if ((offset == (0x30/4)) && (data = 7)) - { - m_copy_src = 1; - } -} - -u32 decsfb_device::vram_r(offs_t offset) -{ - return m_vram[offset]; -} - -void decsfb_device::vram_w(offs_t offset, u32 data, u32 mem_mask) -{ - switch (m_regs[0x30/4]) - { - case MODE_SIMPLE: // simple - COMBINE_DATA(&m_vram[offset]); - break; - - case MODE_TRANSPARENTSTIPPLE: - { - uint8_t *pVRAM = (uint8_t *)&m_vram[offset]; - uint8_t fgs[4]; - - fgs[0] = m_regs[0x20/4] >> 24; - fgs[1] = (m_regs[0x20/4] >> 16) & 0xff; - fgs[2] = (m_regs[0x20/4] >> 8) & 0xff; - fgs[3] = m_regs[0x20/4] & 0xff; - for (int x = 0; x < 32; x++) - { - if (data & (1<<(31-x))) - { - pVRAM[x] = fgs[x & 3]; - } - } - } - break; - - case MODE_COPY: - { - uint8_t *pVRAM = (uint8_t *)&m_vram[offset]; - uint8_t *pBuffer = (uint8_t *)&m_regs[0]; // first 8 32-bit regs are the copy buffer - - if (m_copy_src) - { - m_copy_src = 0; - - for (int x = 0; x < 32; x++) - { - if (data & (1<<(31-x))) - { - pBuffer[x] = pVRAM[x]; - } - } - } - else - { - m_copy_src = 1; - - for (int x = 0; x < 32; x++) - { - if (data & (1<<(31-x))) - { - pVRAM[x] = pBuffer[x]; - } - } - } - } - break; - - default: - logerror("SFB: Unsupported VRAM write %08x (mask %08x) at %08x in mode %x\n", data, mem_mask, offset<<2, m_regs[0x30/4]); - break; - } -} diff --git a/src/devices/video/decsfb.h b/src/devices/video/decsfb.h deleted file mode 100644 index 9181ae84dbf..00000000000 --- a/src/devices/video/decsfb.h +++ /dev/null @@ -1,38 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:R. Belmont - -#ifndef MAME_VIDEO_DECSFB_H -#define MAME_VIDEO_DECSFB_H - -#pragma once - -class decsfb_device : public device_t -{ -public: - decsfb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - auto int_cb() { return m_int_cb.bind(); } - - u32 read(offs_t offset); - void write(offs_t offset, u32 data, u32 mem_mask = ~0); - uint32_t vram_r(offs_t offset); - void vram_w(offs_t offset, u32 data, u32 mem_mask = ~0); - - u32 *get_vram() { return m_vram; } - -protected: - // standard device_interface overrides - virtual void device_start() override; - virtual void device_reset() override; - - devcb_write_line m_int_cb; - -private: - u32 m_vram[0x200000/4]; - u32 m_regs[0x80]; - int m_copy_src; -}; - -DECLARE_DEVICE_TYPE(DECSFB, decsfb_device) - -#endif // MAME_VIDEO_DECSFB_H diff --git a/src/mame/dec/dc7085.cpp b/src/mame/dec/dc7085.cpp new file mode 100644 index 00000000000..37156a08494 --- /dev/null +++ b/src/mame/dec/dc7085.cpp @@ -0,0 +1,361 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont + +/* + * An emulation of the Digital Equipment Corporation DC7085 (also called "DZ") quad-UART + * + * Used in: + * + * Several models of MIPS DECstation + * Some VAXstations + * + * Sources: + * + * http://www.vanade.com/~blc/DS3100/pmax/DS3100.func.spec.pdf + * + */ + +#include "emu.h" +#include "dc7085.h" + +#define LOG_REG (1U << 1) +#define LOG_RX (1U << 2) +#define LOG_TX (1U << 3) +#define LOG_IRQ (1U << 4) + +//#define VERBOSE (LOG_GENERAL|LOG_REG|LOG_RX|LOG_TX|LOG_IRQ) + +#include "logmacro.h" + +DEFINE_DEVICE_TYPE(DC7085, dc7085_device, "dc7085", "Digital Equipment Corporation DC7085 Quad UART") +DEFINE_DEVICE_TYPE(DC7085_CHANNEL, dc7085_channel, "dc7085_channel", "DC7085 UART channel") + +enum csr_mask : u16 +{ + CSR_TRDY = 0x8000, // transmitter ready + CSR_TIE = 0x4000, // transmitter interrupt enable + CSR_TLINE = 0x0300, // transmitter line number + CSR_RDONE = 0x0080, // receiver done + CSR_RIE = 0x0040, // receiver interrupt enable + CSR_MSE = 0x0020, // master scan enable + CSR_CLR = 0x0010, // master clear + CSR_MAINT = 0x0008, // maintenance (loopback) +}; + +enum rbuf_mask : u16 +{ + RBUF_DVAL = 0x8000, // data valid + RBUF_OERR = 0x4000, // overrun error + RBUF_FERR = 0x2000, // framing error + RBUF_PERR = 0x1000, // parity error + RBUF_RLINE = 0x0300, // received line number + RBUF_RLINE3 = 0x0300, + RBUF_RLINE2 = 0x0200, + RBUF_RLINE1 = 0x0100, + RBUF_RLINE0 = 0x0000, + RBUF_DATA = 0x00ff, // received character +}; + +enum lpr_mask : u16 +{ + LPR_RXENAB = 0x1000, // receiver enable + LPR_SC = 0x0f00, // speed code + LPR_ODDPAR = 0x0080, // odd parity + LPR_PARENB = 0x0040, // parity enable + LPR_STOP = 0x0020, // stop code + LPR_CHAR = 0x0018, // character length + LPR_LINE = 0x0003, // parameter line number +}; + +enum tcr_mask : u16 +{ + TCR_DTR3 = 0x0800, // modem control + TCR_DTR2 = 0x0400, + TCR_DTR1 = 0x0200, + TCR_DTR0 = 0x0100, + TCR_LNENB3 = 0x0008, // transmitter line enable + TCR_LNENB2 = 0x0004, + TCR_LNENB1 = 0x0002, + TCR_LNENB0 = 0x0001, +}; + +enum tdr_mask : u16 +{ + TDR_BRK3 = 0x0800, // break control + TDR_BRK2 = 0x0400, + TDR_BRK1 = 0x0200, + TDR_BRK0 = 0x0100, + TDR_TBUF = 0x00ff, // transmitter buffer +}; + +dc7085_device::dc7085_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, DC7085, tag, owner, clock) + , m_chan(*this, "ch%u", 0U) + , m_int_cb(*this) + , m_tx_cb(*this) + , m_dtr_cb(*this) + , m_int_state(false) +{ +} + +void dc7085_device::device_add_mconfig(machine_config &config) +{ + /* + * Configure all four channels such that: + * - line numbers are inesrted into received data words + * - transmitter output is looped back to receiver when enabled + * - transmitter completion is signalled + */ + for (unsigned i = 0; i < std::size(m_chan); i++) + { + DC7085_CHANNEL(config, m_chan[i], 0); + + m_chan[i]->rx_done().set([this, i](u16 data) { rx_done((i << 8) | data); }); + m_chan[i]->tx_cb().set([this, i](int state) { m_tx_cb[i](state); if (m_csr & CSR_MAINT) m_chan[i]->rx_w(state); }); + m_chan[i]->tx_done().set(*this, FUNC(dc7085_device::tx_done)); + } +} + +void dc7085_device::map(address_map &map) +{ + map(0x00, 0x01).rw(FUNC(dc7085_device::csr_r), FUNC(dc7085_device::csr_w)); + map(0x04, 0x05).rw(FUNC(dc7085_device::rbuf_r), FUNC(dc7085_device::lpr_w)); + map(0x08, 0x09).rw(FUNC(dc7085_device::tcr_r), FUNC(dc7085_device::tcr_w)); + map(0x0c, 0x0d).rw(FUNC(dc7085_device::msr_r), FUNC(dc7085_device::tdr_w)); +} + +void dc7085_device::device_start() +{ + save_item(NAME(m_csr)); + save_item(NAME(m_tcr)); + save_item(NAME(m_msr)); + //save_item(NAME(m_fifo)); + save_item(NAME(m_rx_buf)); + save_item(NAME(m_int_state)); +} + +void dc7085_device::device_reset() +{ + m_csr = 0; + m_tcr = 0; + m_msr = 0; + + m_fifo.clear(); + m_rx_buf = 0; + + set_int(false); +} + +u16 dc7085_device::rbuf_r() +{ + if (m_fifo.empty()) + return 0; + + u16 const data = m_fifo.dequeue(); + + LOGMASKED(LOG_RX, "rbuf_r 0x%04x fifo_length %d\n", data, m_fifo.queue_length()); + + if (m_fifo.empty()) + m_csr &= ~CSR_RDONE; + + // FIXME: insert pending data into fifo + if (m_rx_buf & RBUF_DVAL) + { + rx_fifo_push(m_rx_buf); + m_rx_buf = 0; + } + + recalc_irqs(); + + return data; +} + +void dc7085_device::csr_w(u16 data) +{ + LOGMASKED(LOG_REG, "csr_w %04x tie %d rie %d scan %d clear %d loopback %d\n", data, + bool(data & CSR_TIE), bool(data & CSR_RIE), bool(data & CSR_MSE), bool(data & CSR_CLR), bool(data & CSR_MAINT)); + + if (!(data & CSR_CLR)) + { + data &= (CSR_TIE | CSR_RIE | CSR_MSE | CSR_MAINT); + m_csr &= ~(CSR_TIE | CSR_RIE | CSR_MSE | CSR_MAINT); + m_csr |= data; + } + else + reset(); +} + +void dc7085_device::lpr_w(u16 data) +{ + static const int bauds[] = { 50, 75, 110, 134, 150, 300, 600, 1200, 1800, 2000, 2400, 3600, 4800, 7200, 9600, 19800 }; + + unsigned const baud = (data & LPR_SC) >> 8; + unsigned const data_bits = ((data & LPR_CHAR) >> 3) + 5; + unsigned const parity = (data & LPR_PARENB) ? ((data & LPR_ODDPAR) ? 1 : 2) : 0; + unsigned const stop_bits = (data & LPR_STOP) ? 2 : 1; + + m_chan[data & LPR_LINE]->set_format(bauds[baud], data_bits, parity, stop_bits); + m_chan[data & LPR_LINE]->set_enable(data & LPR_RXENAB); +} + +void dc7085_device::tcr_w(u16 data) +{ + LOGMASKED(LOG_REG, "tcr_w %04x\n", data); + + if ((data ^ m_tcr) & TCR_DTR0) + m_dtr_cb[0](bool(data & TCR_DTR0)); + if ((data ^ m_tcr) & TCR_DTR1) + m_dtr_cb[1](bool(data & TCR_DTR1)); + if ((data ^ m_tcr) & TCR_DTR2) + m_dtr_cb[2](bool(data & TCR_DTR2)); + if ((data ^ m_tcr) & TCR_DTR3) + m_dtr_cb[3](bool(data & TCR_DTR3)); + + m_tcr = data; + + recalc_irqs(); +} + +void dc7085_device::tdr_w(u16 data) +{ + LOGMASKED(LOG_REG, "tdr_w %04x (%s)\n", data, machine().describe_context()); + + unsigned const ch = (m_csr & CSR_TLINE) >> 8; + + if (BIT(m_tcr, ch)) + m_chan[ch]->tx_w(data & TDR_TBUF); + + m_csr &= ~CSR_TRDY; + recalc_irqs(); +} + +void dc7085_device::recalc_irqs() +{ + LOGMASKED(LOG_IRQ, "recalc_irqs enter\n"); + m_csr &= ~(CSR_TRDY | CSR_TLINE); + for (unsigned i = 0; i < 4; i++) + { + if (BIT(m_tcr, i) && m_chan[i]->tx_ready()) + { + m_csr |= CSR_TRDY; + m_csr |= (i << 8); + LOGMASKED(LOG_IRQ, "ch %u: set TRDY\n", i); + + break; + } + } + + set_int(((m_csr & CSR_TIE) && (m_csr & CSR_TRDY)) || ((m_csr & CSR_RIE) && (m_csr & CSR_RDONE))); +} + +void dc7085_device::rx_fifo_push(u16 data) +{ + if (!m_fifo.full()) + { + LOGMASKED(LOG_RX, "rx_fifo_push 0x%04x fifo_length %d\n", data, m_fifo.queue_length()); + + m_fifo.enqueue(data); + + m_csr |= CSR_RDONE; + } + else + throw emu_fatalerror("fifo overflow\n"); +} + +void dc7085_device::rx_done(u16 data) +{ + // check if receive buffer is full + if (m_rx_buf & RBUF_DVAL) + { + // push buffer into fifo if not full + if (!m_fifo.full()) + { + rx_fifo_push(m_rx_buf); + m_rx_buf = 0; + } + else + // flag buffer overrun + data |= RBUF_OERR; + } + + // store received data in fifo or buffer + if (!m_fifo.full()) + rx_fifo_push(data); + else + m_rx_buf = data; + + recalc_irqs(); +} + +void dc7085_device::tx_done(int state) +{ + recalc_irqs(); +} + +dc7085_channel::dc7085_channel(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : device_t(mconfig, DC7085_CHANNEL, tag, owner, clock) + , device_serial_interface(mconfig, *this) + , m_tx_cb(*this) + , m_tx_done(*this) + , m_rx_done(*this) + , m_rx_enabled(false) +{ +} + +void dc7085_channel::device_start() +{ + save_item(NAME(m_rx_enabled)); +} + +void dc7085_channel::device_reset() +{ + transmit_register_reset(); + + set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); + set_tra_rate(0); + set_rcv_rate(0); + + m_rx_enabled = false; +} + +void dc7085_channel::rcv_complete() +{ + receive_register_extract(); + + if (m_rx_enabled) + { + u16 data = RBUF_DVAL | get_received_char(); + + if (is_receive_framing_error()) + data |= RBUF_FERR; + if (is_receive_parity_error()) + data |= RBUF_PERR; + + m_rx_done(data); + } +} + +void dc7085_channel::tra_complete() +{ + m_tx_done(1); +} + +void dc7085_channel::tra_callback() +{ + m_tx_cb(transmit_register_get_data_bit()); +} + +void dc7085_channel::set_format(unsigned baud, unsigned data_bits, unsigned parity, unsigned stop_bits) +{ + set_data_frame(1, data_bits, parity ? (parity == 1 ? PARITY_ODD : PARITY_EVEN) : PARITY_NONE, + stop_bits == 1 ? STOP_BITS_1 : (data_bits == 5 ? STOP_BITS_1_5 : STOP_BITS_2)); + + set_tra_rate(baud); + set_rcv_rate(baud); +} + +void dc7085_channel::tx_w(u8 data) +{ + if (is_transmit_register_empty()) + transmit_register_setup(data); +} diff --git a/src/mame/dec/dc7085.h b/src/mame/dec/dc7085.h new file mode 100644 index 00000000000..b272743223d --- /dev/null +++ b/src/mame/dec/dc7085.h @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont + +#ifndef MAME_DEC_DC7085_H +#define MAME_DEC_DC7085_H + +#pragma once + +#include "diserial.h" + +class dc7085_channel + : public device_t + , public device_serial_interface +{ + friend class dc7085_device; + +public: + auto tx_cb() { return m_tx_cb.bind(); } + + dc7085_channel(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + +protected: + // device_t overrides + virtual void device_start() override; + virtual void device_reset() override; + + // device_serial overrides + virtual void rcv_complete() override; + virtual void tra_complete() override; + virtual void tra_callback() override; + + // parent interface + auto rx_done() { return m_rx_done.bind(); } + auto tx_done() { return m_tx_done.bind(); } + + void set_format(unsigned baud, unsigned data_bits, unsigned parity, unsigned stop_bits); + void set_enable(bool enable) { m_rx_enabled = enable; } + bool tx_ready() const { return is_transmit_register_empty(); } + void tx_w(u8 data); + +private: + devcb_write_line m_tx_cb; + devcb_write_line m_tx_done; + devcb_write16 m_rx_done; + + bool m_rx_enabled; +}; + +class dc7085_device : public device_t +{ +public: + dc7085_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + void map(address_map &map); + + auto int_cb() { return m_int_cb.bind(); } + + template void rx_w(int state) { m_chan[Ch]->rx_w(state); } + template auto tx_cb() { return m_tx_cb[Ch].bind(); } + template auto dtr_cb() { return m_dtr_cb[Ch].bind(); } + +protected: + // device_t overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + + // register accessors + u16 csr_r() { return m_csr; } + u16 rbuf_r(); + u16 tcr_r() { return m_tcr; } + u16 msr_r() { return m_msr; } + void csr_w(u16 data); + void lpr_w(u16 data); + void tcr_w(u16 data); + void tdr_w(u16 data); + + // helpers + void rx_fifo_push(u16 data); + void rx_done(u16 data); + void tx_done(int state); + void recalc_irqs(); + + void set_int(bool state) + { + if (state != m_int_state) + { + m_int_state = state; + m_int_cb(state); + } + } + +private: + required_device_array m_chan; + + devcb_write_line m_int_cb; + devcb_write_line::array<4> m_tx_cb; + devcb_write_line::array<4> m_dtr_cb; + + u16 m_csr; + u16 m_tcr; + u16 m_msr; + + util::fifo m_fifo; + u16 m_rx_buf; + + bool m_int_state; +}; + +DECLARE_DEVICE_TYPE(DC7085, dc7085_device) +DECLARE_DEVICE_TYPE(DC7085_CHANNEL, dc7085_channel) + +#endif // MAME_DEC_DC7085_H diff --git a/src/mame/dec/dec_lk201.cpp b/src/mame/dec/dec_lk201.cpp deleted file mode 100644 index 1dfb9a493aa..00000000000 --- a/src/mame/dec/dec_lk201.cpp +++ /dev/null @@ -1,916 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:R. Belmont, M. Burke -/* - DEC LK-201 keyboard - Emulation by R. Belmont & M. Burke -with contributions by Cracyc and Karl-Ludwig Deisenhofer (2016) - -This is the later "cost-reduced" 6805 version with green LEDs; there's also an 8048 version. - The LK-201 mechanical elements are described in US Patent 4,467,150 -*/ - -/* LK201-AA keyboard matrix (8048 version with updates) - Source: VCB02 Technical Reference. - - KBD controller scan matrix (PORT 1): 8 x BCD IN => 18 DECIMAL OUT - - Keyboard itself: - 18 x IN (KEYBOARD DRIVE) KBD 17... KBD 0 => - 8 OUT (keyboard data @ D7..D0) - - to => PORT 0 @ KBD controller. - -________|D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 -..KBD17:|[R] |F19 |[R] |F20|PF4|N- | N,| Enter (numpad) -........| | | | | | NOTE1) -........| |G22 | |G23|E23|D23|C23| A23 ---------|----|----|----|---|---|---|---|--- -..KBD16:|F18 |PF3 |[R] |N9 |C:D|N6 |N3 |N. -........|G21 |E22 | |D22|B17|C22|B22|A22 ---------|----|----|----|---|---|---|---|--- -..KBD15:|F17 |PF2 |[R] |N8 |N5 |C:R| N2|N0 (right) -........| | | | | | | |see NOTE 2) -........|G20 |E21 | |D21|C21|B18|B21|A21 ---------|----|----|----|---|---|---|---|--- - KBD14:|PF1 |Next|Rem-|C:U|N7 |N4 |N1 |N0 (left) -........| |Scrn|move|...| | | |see NOTE 2) -........|E20 |D18 |E18 |C17|D20|C20|B20|A20 ---------|----|----|----|---|---|---|---|--- -..KBD13:|Ins.|'_' |'Do'|Prev { |" |[R]|[R] -........|Here|'-' | |Scrn [ |' | | -........|E17 |E11 |G16 |D17|D11|C11|B13|A17 ---------|----|----|----|---|---|---|---|--- -..KBD12:|Find|+ |Help|Se-| } |Re-|C:L| | -........| |= | |lect ] |turn...| \ -........|E16 |E12 |G15 |D16 D12|C13|B16|C12 ---------|----|----|----|---|---|---|---|--- -..KBD11:Addtnl -........|Scrn| 2 |....| | | | |< -........|G99 |E02 |....|D00|D02|C02|B02|B00 ---------|----|----|----|---|---|---|---|--- -..KBD_2: [R] |[R] |[R] |~ |! |Q |A |Z -........|..............|...|1 -........|..............|E00 E01 D01 C01 B01 ---------|----|----|----|---|---|---|---|--- -..KBD_1: Ctrl|Lock|Comp|[R] -........|C99 |C00 |A99 | ---------|----|----|----|---|---|---|---|--- -..KBD_0: Shift -........|B99,B11 - ---- - [R] = Reserved - NOTE 1) N0-N9, N-, N. and N, refer to numeric keypad - NOTE 2) N0 can be divided into 2 keys. - Normally only the N0 keyswitch is implemented as a double-sized key. - A21 = N0 (right); A20 = N0 (left) - NOTE 3) Return key occupies 2 positions that are - decoded as the Return (C13) key. C13 = RETURN (bot.); D13 = RETURN (top) - - C:D - Cursor down (B17) - C:U - Cursor up (C17) - C:R - Cursor right (B18) - */ - -#include "emu.h" -#include "dec_lk201.h" -#include "cpu/m6805/m6805.h" -#include "speaker.h" - -//************************************************************************** -// MACROS / CONSTANTS -//************************************************************************** - -#define LK201_CPU_TAG "lk201_cpu" -#define LK201_SPK_TAG "beeper" - -//------------------------------------------------- -// SERIAL COMMUNICATIONS INTERFACE -//------------------------------------------------- - -#define SCI_BAUD 0 // Baud rate register -#define BAUD_SCR 0x07 // SCI baud rate select -#define BAUD_SCP 0x30 // SCI prescaler select - -#define SCI_SCCR1 1 // Control register 1 -#define SCCR1_WAKE 0x08 // Wakeup method -#define SCCR1_M 0x10 // Character length -#define SCCR1_T8 0x40 // Transmit bit 8 -#define SCCR1_R8 0x80 // Receive bit 8 - -#define SCI_SCCR2 2 // Control register 2 -#define SCCR2_SBK 0x01 // Send break -#define SCCR2_RWU 0x02 // Receiver wakeup enable -#define SCCR2_RE 0x04 // Receiver enable -#define SCCR2_TE 0x08 // Transmitter enable -#define SCCR2_ILIE 0x10 // Idle line interrupt enable -#define SCCR2_RIE 0x20 // Receiver interrupt enable -#define SCCR2_TCIE 0x40 // Transmit complete interrupt enable -#define SCCR2_TIE 0x80 // Transmit interrupt enable - -#define SCI_SCSR 3 // Status register -#define SCSR_FE 0x02 // Receiver framing error -#define SCSR_NF 0x04 // Receiver noise -#define SCSR_OR 0x08 // Receiver overrun -#define SCSR_IDLE 0x10 // Receiver idle -#define SCSR_RDRF 0x20 // Receive data register full -#define SCSR_TC 0x40 // Transmit complete -#define SCSR_TDRE 0x80 // Transmit data register empty -#define SCSR_INT (SCSR_IDLE | SCSR_RDRF| \ - SCSR_TC | SCSR_TDRE) // Interrupt sources - -#define SCI_SCDR 4 // Data register - -//------------------------------------------------- -// SERIAL PERIPHERAL INTERFACE -//------------------------------------------------- - -#define SPI_SPCR 0 // Control register -#define SPCR_SPR 0x03 // SPI clock rate select -#define SPCR_CPHA 0x04 // Clock phase -#define SPCR_CPOL 0x08 // Clock polarity -#define SPCR_MSTR 0x10 // Master mode select -#define SPCR_DWOM 0x20 // Port D wire-or mode option -#define SPCR_SPE 0x40 // Serial peripheral system enable -#define SPCR_SPIE 0x80 // Serial peripheral interrupt enable - -#define SPI_SPSR 1 // Status register -#define SPSR_MODF 0x10 // Mode fault flag -#define SPSR_WCOL 0x40 // Write collision -#define SPSR_SPIF 0x80 // SPI transfer complete - -#define SPI_SPDR 2 // Data I/O Register - -//************************************************************************** -// DEVICE DEFINITIONS -//************************************************************************** - -DEFINE_DEVICE_TYPE(LK201, lk201_device, "lk201", "DEC LK201 Keyboard") - -ROM_START( lk201 ) - ROM_REGION(0x2000, LK201_CPU_TAG, 0) - -// 23-001s9-00.bin is for the newer LK201 version (green LEDs, Motorola 6805) - ROM_LOAD( "23-001s9-00.bin", 0x0000, 0x2000, CRC(be293c51) SHA1(a11ae004d2d6055d7279da3560c3e56610a19fdb) ) - -// 23-004M1 or 23-004M2 are in the older LK201 keyboard with red LEDs (8051 or 8051H respectively, same code on both?) - ROM_REGION( 0x1000, "i8051cpu", 0 ) - ROM_LOAD( "23-004m2.8051h.e1", 0x0000, 0x1000, CRC(35dd04c6) SHA1(9744c561d76fe85afaccc7a2485ce2865236873a) ) - -ROM_END - -//------------------------------------------------- -// ADDRESS_MAP -//------------------------------------------------- - -void lk201_device::lk201_map(address_map &map) -{ - map(0x0000, 0x0002).rw(FUNC(lk201_device::ports_r), FUNC(lk201_device::ports_w)); - map(0x0004, 0x0006).rw(FUNC(lk201_device::ddr_r), FUNC(lk201_device::ddr_w)); - map(0x000a, 0x000c).rw(FUNC(lk201_device::spi_r), FUNC(lk201_device::spi_w)); - map(0x000d, 0x0011).rw(FUNC(lk201_device::sci_r), FUNC(lk201_device::sci_w)); - map(0x0012, 0x001b).rw(FUNC(lk201_device::timer_r), FUNC(lk201_device::timer_w)); - map(0x0050, 0x00ff).ram(); - map(0x0100, 0x1fff).rom().region(LK201_CPU_TAG, 0x100); -} - - -//------------------------------------------------- -// device_add_mconfig - add device configuration -//------------------------------------------------- - -void lk201_device::device_add_mconfig(machine_config &config) -{ - M68HC05EG(config, m_maincpu, XTAL(4'000'000)); // actually 68HC05C4, clock verified by Lord_Nightmare - m_maincpu->set_addrmap(AS_PROGRAM, &lk201_device::lk201_map); - - SPEAKER(config, "mono").front_center(); - BEEP(config, m_speaker, 2000); // clocked by a 555 timer at E8, the volume of the beep is controllable by: (8051 model) P2.0 thru P2.3, or (6805 model) the upper 4 bits of the LED data latch - m_speaker->add_route(ALL_OUTPUTS, "mono", 0.50); -} - -const tiny_rom_entry *lk201_device::device_rom_region() const -{ - return ROM_NAME( lk201 ); -} - -//------------------------------------------------- -// INPUT_PORTS( lk201 ) -//------------------------------------------------- - -/* [Foreign language caps] are referenced in software titles. Please leave them in. - - DEC omitted terms like 'Interrupt', 'Break' and 'Data / Talk' on some keyboards, - so Fn numbers are definitely important for end users. - - === CURRENT SPECIAL KEYS === - [PC-AT] ......=> [DEC] - LEFT CONTROL..=> Control - LEFT ALT .....=> Compose - - RIGHT ALT ....=> Help - RIGHT CONTROL => Do - ============================================================================================== - === (PC - AT ) keys above cursor block === - * KEYCODE_INSERT * KEYCODE_HOME * KEYCODE_PGUP - * KEYCODE_DEL... * KEYCODE_END * KEYCODE_PGDN - - === (DEC LK 201 layout above cursor) === - * Find ........| Insert Here | Remove - * Select.........| Prev ..... | Next - ============================================================================================== - === CURRENT NUM PAD ASSIGNMENTS === - [PF1] to [PF4] are mapped to NUM LOCK, SLASH etc. (=> 4 keys on top on num pad). - Num pad '+' gives ',' on the DEC. - ',' translates to '.' (=> more or less the layout of model 'LK-201-AG') - - Switch between 'full' and 'partial keyboard emulation' with Scroll Lock. -*/ - -INPUT_PORTS_START( lk201 ) - -/* -Actual membrane part number (from later 6805-based LK201 keyboard): 54-15172 - -Matrix Rows to bit translation, from schematic page 20 ( http://bitsavers.trailing-edge.com/pdf/dec/terminal/lk201/MP01395_LK201_Schematic_Oct83.pdf ) -Bit D0 - Column P3-3 - D1 - Column P3-7 - D2 - Column P3-8 - D3 - Column P3-12 - D4 - Column P2-8 - D5 - Column P1-2 - D6 - Column P3-11 - D7 - Column P1-3 - -Keyboard Matrix ---------------- -Row select -| Columns SwitchID by bit Columns Key by bit -| D5 D7 D4 D0 D1 D2 D3 D6 D5 D7 D4 D0 D1 D2 D3 D6 -V V V V V V V V V V V V V V V V V -P1-6 --- E99 E00 B01 C01 D01 E01 D99 --- N/C ` Z A Q 1 N/C -P1-7 --- G99 D00 B00 B02 C02 D02 E02 --- F1 TAB <> X S W 2 -P1-9 --- --- G01 B03 C03 D03 E03 G00 --- --- F3 C D E 3 F2 -P1-10 A99 C99 A10 --- --- --- --- C00 COMP CTRL N/C --- --- --- --- CAPS -P1-11 --- G02 E04 A0406 B04 C04 D04 G03 --- F4 4 SPACE V F R F5 -P2-2 --- --- G05 B05 C05 D05 E05 G04 --- --- F6 B G T 5 N/C -P2-3 --- --- G06 B06 C06 D06 E06 G07 --- --- F7 N H Y 6 F8 -P2-4 --- --- G09 B07 C07 D07 E07 G08 --- --- F10 M J U 7 F9 -P2-5 --- B9911 --- --- --- --- --- --- --- SHFT --- --- --- --- --- --- -P2-6 --- --- G10 B08 C08 D08 E08 G11 --- --- N/C , K I 8 F11 -P2-9 --- --- G13 B09 C09 D09 E09 G12 --- --- F13 . L O 9 F12 -P2-10 --- G14 E10 B10 C10 D13 D10 E13 --- F14 0 / ; N/C P BKSP(DEL) -P2-11 G15 E16 D16 C12 B16 C13 D12 E12 HELP FIND SLCT \ LEFT RETN ] = -P3-2 G16 E17 D17 A17 B13 C11 D11 E11 DO INST PREV N/C N/C ' [ - -P3-4 E18 E20 C17 A20 B20 C20 D20 D18 RMVE PF1 UP k0 k1 k4 k7 NEXT -P3-5 --- G20 D21 A21 B21 B18 C21 E21 --- F17 k8 N/C k2 RGHT k5 PF2 -P3-6 --- G21 D22 A22 B22 C22 B17 E22 --- F18 k9 k. k3 k6 DOWN PF3 -P3-9 --- --- G23 A23 C23 D23 E23 G22 --- --- F20 kRTN k, k- PF4 F19 - ---- = No matrix switch at all -N/C = switch present, but officially unused? - */ - - PORT_START("KBD0") // Row P2-5 - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // B99 and B11 - - PORT_START("KBD1") // Row P1-10 - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) // A10, exists but no key above this position (right compose?) - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Compose") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) // A99 - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) // C00, does not toggle/physically lock - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) // C99 - - PORT_START("KBD2") // Row P1-6 - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') // B01 - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') // C01 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') // D01 - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("1") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') // E01 - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Tilde") PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') // E00 - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) // D99, exists but no key above this position - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) // E99, exists but no key above this position - - PORT_START("KBD3") // Row P1-7 - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("<") PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('<') PORT_CHAR('>') // B00 - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') // B02 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("S") PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') // C02 - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("W") PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') // D02 - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(TAB)) // D00 - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("2") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') // E02 - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Hold Screen (F1)") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) // G99 - - PORT_START("KBD4") // Row P1-9 - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("C") PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') // B03 - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("D") PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') // C03 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("E") PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') // D03 - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("3") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') // E03 - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Setup (F3)") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) // G01 - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Print Screen (F2)") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) // G00 - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) - - PORT_START("KBD5") // Row P1-11 - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') // A04 and A06 - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("V") PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') // B04 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') // C04 - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("R") PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') // D04 - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("4") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') // E04 - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Break (F5)") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) // G03 - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Data / Talk (F4)") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) // G02 - - PORT_START("KBD6") // Row P2-2 - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') // B05 - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("G") PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') // C05 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("T") PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') // D05 - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("5") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') // E05 - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Interrupt (F6) [X]") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) // G05 - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) // G04, exists but no key above this position (between F5 and F6) - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) - - PORT_START("KBD7") // Row P2-3 - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("N") PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') // B06 - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("H") PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') // C06 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') // D06 - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("6") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') // E06 - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Resume (F7) [Fortsetzen]") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) // G06 - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cancel (F8) [Zuruecknehmen]") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) // G07 - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) - - PORT_START("KBD8") // Row P2-4 - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("M") PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') // B07 - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("J") PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') // C07 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("U") PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') // D07 - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("7") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') // E07 - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Exit (F10) [Fertig]") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) // G09 - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Main Screen (F9) [Hauptbild]") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) // G08 - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) - - PORT_START("KBD9") // Row P2-6 - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(",") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') // B08 - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("K") PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') // C08 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("I") PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') // D08 - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("8") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') // E08 - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) // G10, exists but no key above this position (between F10 and F11) - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("ESC (F11)") PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) // G11 - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) - - PORT_START("KBD10") // Row P2-9 - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(".") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') // B09 - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') // C09 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("O") PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') // D09 - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("9") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') // E09 - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("LF (F13)") PORT_CODE(KEYCODE_F13) // G13 - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("BS (F12)") PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12)) // G12 - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) - - PORT_START("KBD11") // Row P2-10 - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("/") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') // B10 - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(";") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') // C10 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) // D13, exists but no key(?) above this position (under the upper half of the 'Return' key), DOES register as return; NOT LISTED on older schematic but definitely appears on the physical membrane of the later 6805 keyboard! - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("P") PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') // D10 - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("0") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') // E10 - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Delete adjust(attotime::never); - - m_speaker->set_state(0); - m_speaker->set_output_gain(0, 0); - - ddrs[0] = ddrs[1] = ddrs[2] = 0; - ports[0] = ports[1] = ports[2] = 0; - - set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); - set_rate(4800); - m_count->adjust(attotime::from_hz(1200), 0, attotime::from_hz(1200)); - memset(m_timer.regs, 0, sizeof(m_timer.regs)); - - sci_status = (SCSR_TC | SCSR_TDRE); - - spi_status = 0; - spi_data = 0; - - kbd_data = 0; - led_data = 0; - - transmit_register_reset(); - receive_register_reset(); - - // GREEN KEYBOARD LEDs (1 = on, 0 = off): - m_led_wait = 0; // led8 - m_led_compose = 0; // led9 - m_led_lock = 0; // led10 - m_led_hold = 0; // led11 -} - -TIMER_CALLBACK_MEMBER(lk201_device::timer_irq) -{ - m_timer.tsr |= TSR_OCFL; - - if ((m_timer.tcr & TCR_OCIE) && (m_timer.tsr & TSR_OCFL)) - m_maincpu->set_input_line(M68HC05EG_INT_TIMER, ASSERT_LINE); -} - -TIMER_CALLBACK_MEMBER(lk201_device::beeper_off) -{ - m_speaker->set_output_gain(0, 0); - m_speaker->set_state(0); -} - -void lk201_device::rcv_complete() -{ - sci_status |= SCSR_RDRF; - update_interrupts(); - receive_register_extract(); - - int data = get_received_char(); - m_kbd_state = data; -// printf("\nlk201 got %02x\n", m_kbd_state); -} - -void lk201_device::tra_complete() -{ - sci_status |= (SCSR_TC | SCSR_TDRE); - update_interrupts(); -} - -void lk201_device::tra_callback() -{ - m_tx_handler(transmit_register_get_data_bit()); -} - -void lk201_device::update_interrupts() -{ - if (sci_ctl2 & sci_status & SCSR_INT) - { - m_maincpu->set_input_line(M68HC05EG_INT_CPI, 1); - } - else - { - m_maincpu->set_input_line(M68HC05EG_INT_CPI, 0); - } -} - -uint8_t lk201_device::timer_r(offs_t offset) -{ - static uint16_t count; - - uint8_t ret = m_timer.regs[offset]; - - switch (offset) - { - case 8: // ACRH (high value is stored and reused when reading low) - count = (m_maincpu->total_cycles() / 4) & 0x0000ffff; - ret = count >> 8; - break; - case 9: // ACRL - ret = count & 0x00ff; - break; - } - - if(m_timer.tsr) - { - m_timer.tsr = 0; - m_maincpu->set_input_line(M68HC05EG_INT_TIMER, CLEAR_LINE); - } - return ret; -} - -void lk201_device::timer_w(offs_t offset, uint8_t data) -{ - static uint16_t count; - static int save_tsr; - - m_timer.regs[offset] = data; - - switch (offset) - { - case 4: // OCRH - save_tsr = m_timer.tsr; // prevent crashes in between OCRH / OCRL loads - m_timer.tsr &= (255-TSR_OCFL); // OCFL flag tested for zero in TIMER routine - - count = m_timer.ocrh << 8; // store for later (when LOW is written). - break; - case 5 : // OCRL - count |= m_timer.ocrl; - m_timer.ocrh = count >> 8; - - m_timer.tsr = save_tsr; // restore flags - break; - } -} - -uint8_t lk201_device::ddr_r(offs_t offset) -{ - return ddrs[offset]; -} - -void lk201_device::ddr_w(offs_t offset, uint8_t data) -{ -// printf("%02x to PORT %c DDR (PC=%x)\n", data, 'A' + offset, m_maincpu->pc()); - - uint8_t olddata = ddrs[offset]; - ddrs[offset] = data; - send_port(offset, ports[offset] & olddata); -} - -uint8_t lk201_device::ports_r(offs_t offset) -{ - uint8_t incoming = 0; - - // apply data direction registers - incoming &= (ddrs[offset] ^ 0xff); - // add in ddr-masked version of port writes - incoming |= (ports[offset] & ddrs[offset]); - -// printf("PORT %c read = %02x (DDR = %02x latch = %02x) (PC=%x)\n", 'A' + offset, ports[offset], ddrs[offset], ports[offset], m_maincpu->pc()); - - return incoming; -} - -void lk201_device::ports_w(offs_t offset, uint8_t data) -{ - uint8_t olddata = ports[offset]; - ports[offset] = data; // "port writes are independent of DDRC" - send_port(offset, olddata & ddrs[offset]); -// printf("\nPORT %c write %02x (OLD = %02x) (DDR = %02x) (PC=%x)\n", 'A' + offset, data, olddata, ddrs[offset], m_maincpu->pc()); -} - -void lk201_device::send_port(uint8_t offset, uint8_t olddata) -{ - uint8_t porta = ports[0] & ddrs[0]; - uint8_t portb = ports[1] & ddrs[1]; - uint8_t portc = ports[2] & ddrs[2]; - - switch (offset) - { - case 0: // port A - break; - - case 1: // port B - break; - - case 2: // port C - // Check for keyboard read strobe - if (((portc & 0x40) == 0) && (olddata & 0x40)) - { - if (porta & 0x1) kbd_data = m_kbd[0]->read(); - if (porta & 0x2) kbd_data = m_kbd[1]->read(); - if (porta & 0x4) kbd_data = m_kbd[2]->read(); - if (porta & 0x8) kbd_data = m_kbd[3]->read(); - if (porta & 0x10) kbd_data = m_kbd[4]->read(); - if (porta & 0x20) kbd_data = m_kbd[5]->read(); - if (porta & 0x40) kbd_data = m_kbd[6]->read(); - if (porta & 0x80) kbd_data = m_kbd[7]->read(); - if (portb & 0x1) kbd_data = m_kbd[8]->read(); - if (portb & 0x2) kbd_data = m_kbd[9]->read(); - if (portb & 0x4) kbd_data = m_kbd[10]->read(); - if (portb & 0x8) kbd_data = m_kbd[11]->read(); - if (portb & 0x10) kbd_data = m_kbd[12]->read(); - if (portb & 0x20) kbd_data = m_kbd[13]->read(); - if (portb & 0x40) kbd_data = m_kbd[14]->read(); - if (portb & 0x80) kbd_data = m_kbd[15]->read(); - if (portc & 0x1) kbd_data = m_kbd[16]->read(); - if (portc & 0x2) kbd_data = m_kbd[17]->read(); - } - - // Check for LED update strobe - if (((portc & 0x80) == 0) && (olddata & 0x80)) - { - if(ddrs[2] != 0x00) - { // Lower nibble contains the LED values (1 = on, 0 = off) - m_led_wait = (led_data & 0x1) == 1; - m_led_compose= (led_data & 0x2) == 2; - m_led_lock = (led_data & 0x4) == 4; - m_led_hold = (led_data & 0x8) == 8; - } - if (led_data & 0xf0) - { - m_speaker->set_state(1); - // Beeps < 20 ms are clipped. A key click on a LK201 lasts 2 ms... - if(m_kbd_state == LK_CMD_BELL) - m_beeper->adjust(attotime::from_msec(125)); - else - m_beeper->adjust(attotime::from_msec(25)); // see note - } - // Upper 4 bits of LED_DATA contain encoded volume info - switch (led_data & 0xf0) - { - case 0xf0: // 8 - (see TABLE 4 in 68HC05xx ROM) - m_speaker->set_output_gain(0, 100.0f); - break; - case 0xd0: // 7 - m_speaker->set_output_gain(0, (100 - (12 * 1)) / 100.0f); - break; - case 0xc0: // 6 - m_speaker->set_output_gain(0, (100 - (12 * 2)) / 100.0f); - break; - case 0x60: // 5 - m_speaker->set_output_gain(0, (100 - (12 * 3)) / 100.0f); - break; - case 0xb0: // 4 - m_speaker->set_output_gain(0, (100 - (12 * 4)) / 100.0f); - break; - case 0xa0: // 3 - m_speaker->set_output_gain(0, (100 - (12 * 5)) / 100.0f); - break; - case 0x30: // 2 - m_speaker->set_output_gain(0, (100 - (12 * 6)) / 100.0f); - break; - case 0x90: // 1 - m_speaker->set_output_gain(0, (100 - (12 * 7)) / 100.0f); - break; - default: - ; - } // switch (volume) - - } // if (update_strobe) - - } // outer switch -} - -uint8_t lk201_device::sci_r(offs_t offset) -{ - uint8_t incoming = 0; - - switch (offset) - { - case SCI_BAUD: // Baud rate - break; - - case SCI_SCCR1: // Control 1 - break; - - case SCI_SCCR2: // Control 2 - incoming = sci_ctl2; - break; - - case SCI_SCSR: // Status - incoming = sci_status; - break; - - case SCI_SCDR: // Data - incoming = get_received_char(); - sci_status &= ~SCSR_RDRF; - m_maincpu->set_input_line(M68HC05EG_INT_CPI, 0); - update_interrupts(); - break; - } - -// printf("SCI read @ %x = %02x (PC=%x)\n", offset, incoming, m_maincpu->pc()); - - return incoming; -} - -void lk201_device::sci_w(offs_t offset, uint8_t data) -{ - switch (offset) - { - case SCI_BAUD: // Baud rate - break; - - case SCI_SCCR1: // Control 1 - break; - - case SCI_SCCR2: // Control 2 - sci_ctl2 = data; - update_interrupts(); - break; - - case SCI_SCSR: // Status - break; - - case SCI_SCDR: // Data -// printf("LK201: sending %02x\n", data); - transmit_register_setup(data); - sci_status &= ~(SCSR_TC | SCSR_TDRE); - m_maincpu->set_input_line(M68HC05EG_INT_CPI, 0); - update_interrupts(); - break; - } - -// printf("SCI %02x to %x (PC=%x)\n", data, offset, m_maincpu->pc()); -} - -uint8_t lk201_device::spi_r(offs_t offset) -{ - uint8_t incoming = 0; - - switch (offset) - { - case SPI_SPCR: // Control - break; - - case SPI_SPSR: // Status - incoming = spi_status; - spi_status &= ~SPSR_SPIF; - break; - - case SPI_SPDR: // Data I/O - incoming = spi_data; - break; - } - -// printf("SPI read @ %x = %02x (PC=%x)\n", offset, incoming, m_maincpu->pc()); - - return incoming; -} - -void lk201_device::spi_w(offs_t offset, uint8_t data) -{ - switch (offset) - { - case SPI_SPCR: // Control - break; - - case SPI_SPSR: // Status (read only) - break; - - case SPI_SPDR: // Data I/O - spi_data = data; - - // Transfer only allowed if transfer complete flag has been acknowleged - if ((spi_status & SPSR_SPIF) == 0) - { - // Data out - led_data = data; - - // Data in - spi_data = kbd_data; - - // Indicate transfer complete - spi_status |= SPSR_SPIF; - } - break; - } - -// printf("SPI %02x to %x (PC=%x)\n", data, offset, m_maincpu->pc()); -} diff --git a/src/mame/dec/dec_lk201.h b/src/mame/dec/dec_lk201.h deleted file mode 100644 index 9f564bbca38..00000000000 --- a/src/mame/dec/dec_lk201.h +++ /dev/null @@ -1,132 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:R. Belmont, M. Burke -#ifndef MAME_DEC_DEC_LK201_H -#define MAME_DEC_DEC_LK201_H - -#pragma once - -#include "sound/beep.h" - -#include "diserial.h" - - -//************************************************************************** -// MACROS / CONSTANTS -//************************************************************************** - -#define LK_CMD_LEDS_ON 0x13 /* light LEDs - 1st param: led bitmask */ -#define LK_CMD_LEDS_OFF 0x11 /* turn off LEDs */ - -#define LK_CMD_DIS_KEYCLK 0x99 /* disable the keyclick */ -#define LK_CMD_ENB_KEYCLK 0x1b /* enable the keyclick - 1st param: volume */ -#define LK_CMD_DIS_CTLCLK 0xb9 /* disable the Ctrl keyclick */ -#define LK_CMD_ENB_CTLCLK 0xbb /* enable the Ctrl keyclick */ -#define LK_CMD_SOUND_CLK 0x9f /* emit a keyclick - 1st param: volume */ -#define LK_CMD_DIS_BELL 0xa1 /* disable the bell */ -#define LK_CMD_ENB_BELL 0x23 /* enable the bell - 1st param: volume */ -#define LK_CMD_BELL 0xa7 /* emit a bell - 1st param: volume */ - -// TCR - Timer Compare Register -#define TCR_OCIE 0x40 // Bit 6 (output compare IRQ enable) -#define TCR_OLVL 0x01 // Bit 1 (output level) - -// TSR - Timer Status Register -#define TSR_OCFL 0x40 // TSR (68HC05 output compare flag) - - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -// ======================> lk201_device - -class lk201_device : public device_t, public device_serial_interface -{ -public: - // construction/destruction - lk201_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); - - uint8_t ddr_r(offs_t offset); - void ddr_w(offs_t offset, uint8_t data); - uint8_t ports_r(offs_t offset); - void ports_w(offs_t offset, uint8_t data); - uint8_t sci_r(offs_t offset); - void sci_w(offs_t offset, uint8_t data); - uint8_t spi_r(offs_t offset); - void spi_w(offs_t offset, uint8_t data); - uint8_t timer_r(offs_t offset); - void timer_w(offs_t offset, uint8_t data); - - auto tx_handler() { return m_tx_handler.bind(); } - - void lk201_map(address_map &map); -protected: - // device-level overrides - virtual void device_add_mconfig(machine_config &config) override; - virtual const tiny_rom_entry *device_rom_region() const override; - virtual ioport_constructor device_input_ports() const override; - virtual void device_start() override; - virtual void device_reset() override; - - // device_serial overrides - virtual void rcv_complete() override; // Rx completed receiving byte - virtual void tra_complete() override; // Tx completed sending byte - virtual void tra_callback() override; // Tx send bit - - TIMER_CALLBACK_MEMBER(timer_irq); - TIMER_CALLBACK_MEMBER(beeper_off); - -private: - uint8_t ddrs[3]; - uint8_t ports[3]; - uint8_t led_data; - uint8_t kbd_data; - - union { - struct { - uint8_t tcr; - uint8_t tsr; - uint8_t icrh; - uint8_t icrl; - uint8_t ocrh; - uint8_t ocrl; - uint8_t crh; - uint8_t crl; - uint8_t acrh; - uint8_t acrl; - }; - uint8_t regs[10]; - } m_timer; - - emu_timer *m_count; - emu_timer *m_beeper; - - uint8_t sci_ctl2; - uint8_t sci_status; - //uint8_t sci_data; - - uint8_t spi_status; - uint8_t spi_data; - - required_device m_maincpu; - required_device m_speaker; - - required_ioport_array<18> m_kbd; - - output_finder<> m_led_wait; - output_finder<> m_led_compose; - output_finder<> m_led_lock; - output_finder<> m_led_hold; - - void send_port(uint8_t offset, uint8_t data); - void update_interrupts(); - - int m_kbd_state; - - devcb_write_line m_tx_handler; -}; - -// device type definition -DECLARE_DEVICE_TYPE(LK201, lk201_device) - -#endif // MAME_DEC_DEC_LK201_H diff --git a/src/mame/dec/decmate2.cpp b/src/mame/dec/decmate2.cpp index cd343835246..d44b6a79723 100644 --- a/src/mame/dec/decmate2.cpp +++ b/src/mame/dec/decmate2.cpp @@ -56,7 +56,7 @@ #include "machine/ay31015.h" #include "machine/clock.h" #include "machine/com8116.h" -#include "dec_lk201.h" +#include "lk201.h" #include "machine/wd_fdc.h" #include "machine/z80sio.h" #include "video/crt9007.h" diff --git a/src/mame/dec/decstation.cpp b/src/mame/dec/decstation.cpp index 981e386e930..d0d7217a8b0 100644 --- a/src/mame/dec/decstation.cpp +++ b/src/mame/dec/decstation.cpp @@ -65,18 +65,19 @@ #include "machine/mc146818.h" #include "machine/z80scc.h" #include "machine/ncr53c90.h" -//#include "machine/dc7061.h" #include "machine/nscsi_bus.h" #include "bus/nscsi/cd.h" #include "bus/nscsi/hd.h" -#include "dec_lk201.h" #include "machine/am79c90.h" -#include "machine/dc7085.h" #include "bus/rs232/rs232.h" #include "screen.h" #include "video/bt47x.h" #include "video/bt459.h" -#include "video/decsfb.h" + +//#include "dc7061.h" +#include "dc7085.h" +#include "lk201.h" +#include "sfb.h" #include "kn01.lh" diff --git a/src/mame/dec/lk201.cpp b/src/mame/dec/lk201.cpp new file mode 100644 index 00000000000..b423e28cd70 --- /dev/null +++ b/src/mame/dec/lk201.cpp @@ -0,0 +1,916 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, M. Burke +/* + DEC LK-201 keyboard + Emulation by R. Belmont & M. Burke +with contributions by Cracyc and Karl-Ludwig Deisenhofer (2016) + +This is the later "cost-reduced" 6805 version with green LEDs; there's also an 8048 version. + The LK-201 mechanical elements are described in US Patent 4,467,150 +*/ + +/* LK201-AA keyboard matrix (8048 version with updates) + Source: VCB02 Technical Reference. + + KBD controller scan matrix (PORT 1): 8 x BCD IN => 18 DECIMAL OUT + + Keyboard itself: + 18 x IN (KEYBOARD DRIVE) KBD 17... KBD 0 => + 8 OUT (keyboard data @ D7..D0) + + to => PORT 0 @ KBD controller. + +________|D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 +..KBD17:|[R] |F19 |[R] |F20|PF4|N- | N,| Enter (numpad) +........| | | | | | NOTE1) +........| |G22 | |G23|E23|D23|C23| A23 +--------|----|----|----|---|---|---|---|--- +..KBD16:|F18 |PF3 |[R] |N9 |C:D|N6 |N3 |N. +........|G21 |E22 | |D22|B17|C22|B22|A22 +--------|----|----|----|---|---|---|---|--- +..KBD15:|F17 |PF2 |[R] |N8 |N5 |C:R| N2|N0 (right) +........| | | | | | | |see NOTE 2) +........|G20 |E21 | |D21|C21|B18|B21|A21 +--------|----|----|----|---|---|---|---|--- + KBD14:|PF1 |Next|Rem-|C:U|N7 |N4 |N1 |N0 (left) +........| |Scrn|move|...| | | |see NOTE 2) +........|E20 |D18 |E18 |C17|D20|C20|B20|A20 +--------|----|----|----|---|---|---|---|--- +..KBD13:|Ins.|'_' |'Do'|Prev { |" |[R]|[R] +........|Here|'-' | |Scrn [ |' | | +........|E17 |E11 |G16 |D17|D11|C11|B13|A17 +--------|----|----|----|---|---|---|---|--- +..KBD12:|Find|+ |Help|Se-| } |Re-|C:L| | +........| |= | |lect ] |turn...| \ +........|E16 |E12 |G15 |D16 D12|C13|B16|C12 +--------|----|----|----|---|---|---|---|--- +..KBD11:Addtnl +........|Scrn| 2 |....| | | | |< +........|G99 |E02 |....|D00|D02|C02|B02|B00 +--------|----|----|----|---|---|---|---|--- +..KBD_2: [R] |[R] |[R] |~ |! |Q |A |Z +........|..............|...|1 +........|..............|E00 E01 D01 C01 B01 +--------|----|----|----|---|---|---|---|--- +..KBD_1: Ctrl|Lock|Comp|[R] +........|C99 |C00 |A99 | +--------|----|----|----|---|---|---|---|--- +..KBD_0: Shift +........|B99,B11 + +--- + [R] = Reserved + NOTE 1) N0-N9, N-, N. and N, refer to numeric keypad + NOTE 2) N0 can be divided into 2 keys. + Normally only the N0 keyswitch is implemented as a double-sized key. + A21 = N0 (right); A20 = N0 (left) + NOTE 3) Return key occupies 2 positions that are + decoded as the Return (C13) key. C13 = RETURN (bot.); D13 = RETURN (top) + + C:D - Cursor down (B17) + C:U - Cursor up (C17) + C:R - Cursor right (B18) + */ + +#include "emu.h" +#include "lk201.h" +#include "cpu/m6805/m6805.h" +#include "speaker.h" + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LK201_CPU_TAG "lk201_cpu" +#define LK201_SPK_TAG "beeper" + +//------------------------------------------------- +// SERIAL COMMUNICATIONS INTERFACE +//------------------------------------------------- + +#define SCI_BAUD 0 // Baud rate register +#define BAUD_SCR 0x07 // SCI baud rate select +#define BAUD_SCP 0x30 // SCI prescaler select + +#define SCI_SCCR1 1 // Control register 1 +#define SCCR1_WAKE 0x08 // Wakeup method +#define SCCR1_M 0x10 // Character length +#define SCCR1_T8 0x40 // Transmit bit 8 +#define SCCR1_R8 0x80 // Receive bit 8 + +#define SCI_SCCR2 2 // Control register 2 +#define SCCR2_SBK 0x01 // Send break +#define SCCR2_RWU 0x02 // Receiver wakeup enable +#define SCCR2_RE 0x04 // Receiver enable +#define SCCR2_TE 0x08 // Transmitter enable +#define SCCR2_ILIE 0x10 // Idle line interrupt enable +#define SCCR2_RIE 0x20 // Receiver interrupt enable +#define SCCR2_TCIE 0x40 // Transmit complete interrupt enable +#define SCCR2_TIE 0x80 // Transmit interrupt enable + +#define SCI_SCSR 3 // Status register +#define SCSR_FE 0x02 // Receiver framing error +#define SCSR_NF 0x04 // Receiver noise +#define SCSR_OR 0x08 // Receiver overrun +#define SCSR_IDLE 0x10 // Receiver idle +#define SCSR_RDRF 0x20 // Receive data register full +#define SCSR_TC 0x40 // Transmit complete +#define SCSR_TDRE 0x80 // Transmit data register empty +#define SCSR_INT (SCSR_IDLE | SCSR_RDRF| \ + SCSR_TC | SCSR_TDRE) // Interrupt sources + +#define SCI_SCDR 4 // Data register + +//------------------------------------------------- +// SERIAL PERIPHERAL INTERFACE +//------------------------------------------------- + +#define SPI_SPCR 0 // Control register +#define SPCR_SPR 0x03 // SPI clock rate select +#define SPCR_CPHA 0x04 // Clock phase +#define SPCR_CPOL 0x08 // Clock polarity +#define SPCR_MSTR 0x10 // Master mode select +#define SPCR_DWOM 0x20 // Port D wire-or mode option +#define SPCR_SPE 0x40 // Serial peripheral system enable +#define SPCR_SPIE 0x80 // Serial peripheral interrupt enable + +#define SPI_SPSR 1 // Status register +#define SPSR_MODF 0x10 // Mode fault flag +#define SPSR_WCOL 0x40 // Write collision +#define SPSR_SPIF 0x80 // SPI transfer complete + +#define SPI_SPDR 2 // Data I/O Register + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(LK201, lk201_device, "lk201", "DEC LK201 Keyboard") + +ROM_START( lk201 ) + ROM_REGION(0x2000, LK201_CPU_TAG, 0) + +// 23-001s9-00.bin is for the newer LK201 version (green LEDs, Motorola 6805) + ROM_LOAD( "23-001s9-00.bin", 0x0000, 0x2000, CRC(be293c51) SHA1(a11ae004d2d6055d7279da3560c3e56610a19fdb) ) + +// 23-004M1 or 23-004M2 are in the older LK201 keyboard with red LEDs (8051 or 8051H respectively, same code on both?) + ROM_REGION( 0x1000, "i8051cpu", 0 ) + ROM_LOAD( "23-004m2.8051h.e1", 0x0000, 0x1000, CRC(35dd04c6) SHA1(9744c561d76fe85afaccc7a2485ce2865236873a) ) + +ROM_END + +//------------------------------------------------- +// ADDRESS_MAP +//------------------------------------------------- + +void lk201_device::lk201_map(address_map &map) +{ + map(0x0000, 0x0002).rw(FUNC(lk201_device::ports_r), FUNC(lk201_device::ports_w)); + map(0x0004, 0x0006).rw(FUNC(lk201_device::ddr_r), FUNC(lk201_device::ddr_w)); + map(0x000a, 0x000c).rw(FUNC(lk201_device::spi_r), FUNC(lk201_device::spi_w)); + map(0x000d, 0x0011).rw(FUNC(lk201_device::sci_r), FUNC(lk201_device::sci_w)); + map(0x0012, 0x001b).rw(FUNC(lk201_device::timer_r), FUNC(lk201_device::timer_w)); + map(0x0050, 0x00ff).ram(); + map(0x0100, 0x1fff).rom().region(LK201_CPU_TAG, 0x100); +} + + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void lk201_device::device_add_mconfig(machine_config &config) +{ + M68HC05EG(config, m_maincpu, XTAL(4'000'000)); // actually 68HC05C4, clock verified by Lord_Nightmare + m_maincpu->set_addrmap(AS_PROGRAM, &lk201_device::lk201_map); + + SPEAKER(config, "mono").front_center(); + BEEP(config, m_speaker, 2000); // clocked by a 555 timer at E8, the volume of the beep is controllable by: (8051 model) P2.0 thru P2.3, or (6805 model) the upper 4 bits of the LED data latch + m_speaker->add_route(ALL_OUTPUTS, "mono", 0.50); +} + +const tiny_rom_entry *lk201_device::device_rom_region() const +{ + return ROM_NAME( lk201 ); +} + +//------------------------------------------------- +// INPUT_PORTS( lk201 ) +//------------------------------------------------- + +/* [Foreign language caps] are referenced in software titles. Please leave them in. + + DEC omitted terms like 'Interrupt', 'Break' and 'Data / Talk' on some keyboards, + so Fn numbers are definitely important for end users. + + === CURRENT SPECIAL KEYS === + [PC-AT] ......=> [DEC] + LEFT CONTROL..=> Control + LEFT ALT .....=> Compose + + RIGHT ALT ....=> Help + RIGHT CONTROL => Do + ============================================================================================== + === (PC - AT ) keys above cursor block === + * KEYCODE_INSERT * KEYCODE_HOME * KEYCODE_PGUP + * KEYCODE_DEL... * KEYCODE_END * KEYCODE_PGDN + + === (DEC LK 201 layout above cursor) === + * Find ........| Insert Here | Remove + * Select.........| Prev ..... | Next + ============================================================================================== + === CURRENT NUM PAD ASSIGNMENTS === + [PF1] to [PF4] are mapped to NUM LOCK, SLASH etc. (=> 4 keys on top on num pad). + Num pad '+' gives ',' on the DEC. + ',' translates to '.' (=> more or less the layout of model 'LK-201-AG') + + Switch between 'full' and 'partial keyboard emulation' with Scroll Lock. +*/ + +INPUT_PORTS_START( lk201 ) + +/* +Actual membrane part number (from later 6805-based LK201 keyboard): 54-15172 + +Matrix Rows to bit translation, from schematic page 20 ( http://bitsavers.trailing-edge.com/pdf/dec/terminal/lk201/MP01395_LK201_Schematic_Oct83.pdf ) +Bit D0 - Column P3-3 + D1 - Column P3-7 + D2 - Column P3-8 + D3 - Column P3-12 + D4 - Column P2-8 + D5 - Column P1-2 + D6 - Column P3-11 + D7 - Column P1-3 + +Keyboard Matrix +--------------- +Row select +| Columns SwitchID by bit Columns Key by bit +| D5 D7 D4 D0 D1 D2 D3 D6 D5 D7 D4 D0 D1 D2 D3 D6 +V V V V V V V V V V V V V V V V V +P1-6 --- E99 E00 B01 C01 D01 E01 D99 --- N/C ` Z A Q 1 N/C +P1-7 --- G99 D00 B00 B02 C02 D02 E02 --- F1 TAB <> X S W 2 +P1-9 --- --- G01 B03 C03 D03 E03 G00 --- --- F3 C D E 3 F2 +P1-10 A99 C99 A10 --- --- --- --- C00 COMP CTRL N/C --- --- --- --- CAPS +P1-11 --- G02 E04 A0406 B04 C04 D04 G03 --- F4 4 SPACE V F R F5 +P2-2 --- --- G05 B05 C05 D05 E05 G04 --- --- F6 B G T 5 N/C +P2-3 --- --- G06 B06 C06 D06 E06 G07 --- --- F7 N H Y 6 F8 +P2-4 --- --- G09 B07 C07 D07 E07 G08 --- --- F10 M J U 7 F9 +P2-5 --- B9911 --- --- --- --- --- --- --- SHFT --- --- --- --- --- --- +P2-6 --- --- G10 B08 C08 D08 E08 G11 --- --- N/C , K I 8 F11 +P2-9 --- --- G13 B09 C09 D09 E09 G12 --- --- F13 . L O 9 F12 +P2-10 --- G14 E10 B10 C10 D13 D10 E13 --- F14 0 / ; N/C P BKSP(DEL) +P2-11 G15 E16 D16 C12 B16 C13 D12 E12 HELP FIND SLCT \ LEFT RETN ] = +P3-2 G16 E17 D17 A17 B13 C11 D11 E11 DO INST PREV N/C N/C ' [ - +P3-4 E18 E20 C17 A20 B20 C20 D20 D18 RMVE PF1 UP k0 k1 k4 k7 NEXT +P3-5 --- G20 D21 A21 B21 B18 C21 E21 --- F17 k8 N/C k2 RGHT k5 PF2 +P3-6 --- G21 D22 A22 B22 C22 B17 E22 --- F18 k9 k. k3 k6 DOWN PF3 +P3-9 --- --- G23 A23 C23 D23 E23 G22 --- --- F20 kRTN k, k- PF4 F19 + +--- = No matrix switch at all +N/C = switch present, but officially unused? + */ + + PORT_START("KBD0") // Row P2-5 + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // B99 and B11 + + PORT_START("KBD1") // Row P1-10 + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) // A10, exists but no key above this position (right compose?) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Compose") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) // A99 + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) // C00, does not toggle/physically lock + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) // C99 + + PORT_START("KBD2") // Row P1-6 + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') // B01 + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') // C01 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') // D01 + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("1") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') // E01 + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Tilde") PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') // E00 + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) // D99, exists but no key above this position + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) // E99, exists but no key above this position + + PORT_START("KBD3") // Row P1-7 + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("<") PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('<') PORT_CHAR('>') // B00 + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') // B02 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("S") PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') // C02 + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("W") PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') // D02 + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(TAB)) // D00 + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("2") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') // E02 + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Hold Screen (F1)") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) // G99 + + PORT_START("KBD4") // Row P1-9 + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("C") PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') // B03 + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("D") PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') // C03 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("E") PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') // D03 + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("3") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') // E03 + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Setup (F3)") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) // G01 + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Print Screen (F2)") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) // G00 + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KBD5") // Row P1-11 + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') // A04 and A06 + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("V") PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') // B04 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') // C04 + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("R") PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') // D04 + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("4") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') // E04 + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Break (F5)") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) // G03 + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Data / Talk (F4)") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) // G02 + + PORT_START("KBD6") // Row P2-2 + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') // B05 + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("G") PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') // C05 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("T") PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') // D05 + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("5") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') // E05 + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Interrupt (F6) [X]") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) // G05 + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) // G04, exists but no key above this position (between F5 and F6) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KBD7") // Row P2-3 + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("N") PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') // B06 + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("H") PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') // C06 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') // D06 + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("6") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') // E06 + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Resume (F7) [Fortsetzen]") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) // G06 + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cancel (F8) [Zuruecknehmen]") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) // G07 + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KBD8") // Row P2-4 + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("M") PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') // B07 + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("J") PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') // C07 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("U") PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') // D07 + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("7") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') // E07 + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Exit (F10) [Fertig]") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) // G09 + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Main Screen (F9) [Hauptbild]") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) // G08 + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KBD9") // Row P2-6 + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(",") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') // B08 + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("K") PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') // C08 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("I") PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') // D08 + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("8") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') // E08 + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) // G10, exists but no key above this position (between F10 and F11) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("ESC (F11)") PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) // G11 + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KBD10") // Row P2-9 + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(".") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') // B09 + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') // C09 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("O") PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') // D09 + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("9") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') // E09 + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("LF (F13)") PORT_CODE(KEYCODE_F13) // G13 + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("BS (F12)") PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12)) // G12 + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KBD11") // Row P2-10 + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("/") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') // B10 + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(";") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') // C10 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) // D13, exists but no key(?) above this position (under the upper half of the 'Return' key), DOES register as return; NOT LISTED on older schematic but definitely appears on the physical membrane of the later 6805 keyboard! + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("P") PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') // D10 + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("0") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') // E10 + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Delete adjust(attotime::never); + + m_speaker->set_state(0); + m_speaker->set_output_gain(0, 0); + + ddrs[0] = ddrs[1] = ddrs[2] = 0; + ports[0] = ports[1] = ports[2] = 0; + + set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); + set_rate(4800); + m_count->adjust(attotime::from_hz(1200), 0, attotime::from_hz(1200)); + memset(m_timer.regs, 0, sizeof(m_timer.regs)); + + sci_status = (SCSR_TC | SCSR_TDRE); + + spi_status = 0; + spi_data = 0; + + kbd_data = 0; + led_data = 0; + + transmit_register_reset(); + receive_register_reset(); + + // GREEN KEYBOARD LEDs (1 = on, 0 = off): + m_led_wait = 0; // led8 + m_led_compose = 0; // led9 + m_led_lock = 0; // led10 + m_led_hold = 0; // led11 +} + +TIMER_CALLBACK_MEMBER(lk201_device::timer_irq) +{ + m_timer.tsr |= TSR_OCFL; + + if ((m_timer.tcr & TCR_OCIE) && (m_timer.tsr & TSR_OCFL)) + m_maincpu->set_input_line(M68HC05EG_INT_TIMER, ASSERT_LINE); +} + +TIMER_CALLBACK_MEMBER(lk201_device::beeper_off) +{ + m_speaker->set_output_gain(0, 0); + m_speaker->set_state(0); +} + +void lk201_device::rcv_complete() +{ + sci_status |= SCSR_RDRF; + update_interrupts(); + receive_register_extract(); + + int data = get_received_char(); + m_kbd_state = data; +// printf("\nlk201 got %02x\n", m_kbd_state); +} + +void lk201_device::tra_complete() +{ + sci_status |= (SCSR_TC | SCSR_TDRE); + update_interrupts(); +} + +void lk201_device::tra_callback() +{ + m_tx_handler(transmit_register_get_data_bit()); +} + +void lk201_device::update_interrupts() +{ + if (sci_ctl2 & sci_status & SCSR_INT) + { + m_maincpu->set_input_line(M68HC05EG_INT_CPI, 1); + } + else + { + m_maincpu->set_input_line(M68HC05EG_INT_CPI, 0); + } +} + +uint8_t lk201_device::timer_r(offs_t offset) +{ + static uint16_t count; + + uint8_t ret = m_timer.regs[offset]; + + switch (offset) + { + case 8: // ACRH (high value is stored and reused when reading low) + count = (m_maincpu->total_cycles() / 4) & 0x0000ffff; + ret = count >> 8; + break; + case 9: // ACRL + ret = count & 0x00ff; + break; + } + + if(m_timer.tsr) + { + m_timer.tsr = 0; + m_maincpu->set_input_line(M68HC05EG_INT_TIMER, CLEAR_LINE); + } + return ret; +} + +void lk201_device::timer_w(offs_t offset, uint8_t data) +{ + static uint16_t count; + static int save_tsr; + + m_timer.regs[offset] = data; + + switch (offset) + { + case 4: // OCRH + save_tsr = m_timer.tsr; // prevent crashes in between OCRH / OCRL loads + m_timer.tsr &= (255-TSR_OCFL); // OCFL flag tested for zero in TIMER routine + + count = m_timer.ocrh << 8; // store for later (when LOW is written). + break; + case 5 : // OCRL + count |= m_timer.ocrl; + m_timer.ocrh = count >> 8; + + m_timer.tsr = save_tsr; // restore flags + break; + } +} + +uint8_t lk201_device::ddr_r(offs_t offset) +{ + return ddrs[offset]; +} + +void lk201_device::ddr_w(offs_t offset, uint8_t data) +{ +// printf("%02x to PORT %c DDR (PC=%x)\n", data, 'A' + offset, m_maincpu->pc()); + + uint8_t olddata = ddrs[offset]; + ddrs[offset] = data; + send_port(offset, ports[offset] & olddata); +} + +uint8_t lk201_device::ports_r(offs_t offset) +{ + uint8_t incoming = 0; + + // apply data direction registers + incoming &= (ddrs[offset] ^ 0xff); + // add in ddr-masked version of port writes + incoming |= (ports[offset] & ddrs[offset]); + +// printf("PORT %c read = %02x (DDR = %02x latch = %02x) (PC=%x)\n", 'A' + offset, ports[offset], ddrs[offset], ports[offset], m_maincpu->pc()); + + return incoming; +} + +void lk201_device::ports_w(offs_t offset, uint8_t data) +{ + uint8_t olddata = ports[offset]; + ports[offset] = data; // "port writes are independent of DDRC" + send_port(offset, olddata & ddrs[offset]); +// printf("\nPORT %c write %02x (OLD = %02x) (DDR = %02x) (PC=%x)\n", 'A' + offset, data, olddata, ddrs[offset], m_maincpu->pc()); +} + +void lk201_device::send_port(uint8_t offset, uint8_t olddata) +{ + uint8_t porta = ports[0] & ddrs[0]; + uint8_t portb = ports[1] & ddrs[1]; + uint8_t portc = ports[2] & ddrs[2]; + + switch (offset) + { + case 0: // port A + break; + + case 1: // port B + break; + + case 2: // port C + // Check for keyboard read strobe + if (((portc & 0x40) == 0) && (olddata & 0x40)) + { + if (porta & 0x1) kbd_data = m_kbd[0]->read(); + if (porta & 0x2) kbd_data = m_kbd[1]->read(); + if (porta & 0x4) kbd_data = m_kbd[2]->read(); + if (porta & 0x8) kbd_data = m_kbd[3]->read(); + if (porta & 0x10) kbd_data = m_kbd[4]->read(); + if (porta & 0x20) kbd_data = m_kbd[5]->read(); + if (porta & 0x40) kbd_data = m_kbd[6]->read(); + if (porta & 0x80) kbd_data = m_kbd[7]->read(); + if (portb & 0x1) kbd_data = m_kbd[8]->read(); + if (portb & 0x2) kbd_data = m_kbd[9]->read(); + if (portb & 0x4) kbd_data = m_kbd[10]->read(); + if (portb & 0x8) kbd_data = m_kbd[11]->read(); + if (portb & 0x10) kbd_data = m_kbd[12]->read(); + if (portb & 0x20) kbd_data = m_kbd[13]->read(); + if (portb & 0x40) kbd_data = m_kbd[14]->read(); + if (portb & 0x80) kbd_data = m_kbd[15]->read(); + if (portc & 0x1) kbd_data = m_kbd[16]->read(); + if (portc & 0x2) kbd_data = m_kbd[17]->read(); + } + + // Check for LED update strobe + if (((portc & 0x80) == 0) && (olddata & 0x80)) + { + if(ddrs[2] != 0x00) + { // Lower nibble contains the LED values (1 = on, 0 = off) + m_led_wait = (led_data & 0x1) == 1; + m_led_compose= (led_data & 0x2) == 2; + m_led_lock = (led_data & 0x4) == 4; + m_led_hold = (led_data & 0x8) == 8; + } + if (led_data & 0xf0) + { + m_speaker->set_state(1); + // Beeps < 20 ms are clipped. A key click on a LK201 lasts 2 ms... + if(m_kbd_state == LK_CMD_BELL) + m_beeper->adjust(attotime::from_msec(125)); + else + m_beeper->adjust(attotime::from_msec(25)); // see note + } + // Upper 4 bits of LED_DATA contain encoded volume info + switch (led_data & 0xf0) + { + case 0xf0: // 8 - (see TABLE 4 in 68HC05xx ROM) + m_speaker->set_output_gain(0, 100.0f); + break; + case 0xd0: // 7 + m_speaker->set_output_gain(0, (100 - (12 * 1)) / 100.0f); + break; + case 0xc0: // 6 + m_speaker->set_output_gain(0, (100 - (12 * 2)) / 100.0f); + break; + case 0x60: // 5 + m_speaker->set_output_gain(0, (100 - (12 * 3)) / 100.0f); + break; + case 0xb0: // 4 + m_speaker->set_output_gain(0, (100 - (12 * 4)) / 100.0f); + break; + case 0xa0: // 3 + m_speaker->set_output_gain(0, (100 - (12 * 5)) / 100.0f); + break; + case 0x30: // 2 + m_speaker->set_output_gain(0, (100 - (12 * 6)) / 100.0f); + break; + case 0x90: // 1 + m_speaker->set_output_gain(0, (100 - (12 * 7)) / 100.0f); + break; + default: + ; + } // switch (volume) + + } // if (update_strobe) + + } // outer switch +} + +uint8_t lk201_device::sci_r(offs_t offset) +{ + uint8_t incoming = 0; + + switch (offset) + { + case SCI_BAUD: // Baud rate + break; + + case SCI_SCCR1: // Control 1 + break; + + case SCI_SCCR2: // Control 2 + incoming = sci_ctl2; + break; + + case SCI_SCSR: // Status + incoming = sci_status; + break; + + case SCI_SCDR: // Data + incoming = get_received_char(); + sci_status &= ~SCSR_RDRF; + m_maincpu->set_input_line(M68HC05EG_INT_CPI, 0); + update_interrupts(); + break; + } + +// printf("SCI read @ %x = %02x (PC=%x)\n", offset, incoming, m_maincpu->pc()); + + return incoming; +} + +void lk201_device::sci_w(offs_t offset, uint8_t data) +{ + switch (offset) + { + case SCI_BAUD: // Baud rate + break; + + case SCI_SCCR1: // Control 1 + break; + + case SCI_SCCR2: // Control 2 + sci_ctl2 = data; + update_interrupts(); + break; + + case SCI_SCSR: // Status + break; + + case SCI_SCDR: // Data +// printf("LK201: sending %02x\n", data); + transmit_register_setup(data); + sci_status &= ~(SCSR_TC | SCSR_TDRE); + m_maincpu->set_input_line(M68HC05EG_INT_CPI, 0); + update_interrupts(); + break; + } + +// printf("SCI %02x to %x (PC=%x)\n", data, offset, m_maincpu->pc()); +} + +uint8_t lk201_device::spi_r(offs_t offset) +{ + uint8_t incoming = 0; + + switch (offset) + { + case SPI_SPCR: // Control + break; + + case SPI_SPSR: // Status + incoming = spi_status; + spi_status &= ~SPSR_SPIF; + break; + + case SPI_SPDR: // Data I/O + incoming = spi_data; + break; + } + +// printf("SPI read @ %x = %02x (PC=%x)\n", offset, incoming, m_maincpu->pc()); + + return incoming; +} + +void lk201_device::spi_w(offs_t offset, uint8_t data) +{ + switch (offset) + { + case SPI_SPCR: // Control + break; + + case SPI_SPSR: // Status (read only) + break; + + case SPI_SPDR: // Data I/O + spi_data = data; + + // Transfer only allowed if transfer complete flag has been acknowleged + if ((spi_status & SPSR_SPIF) == 0) + { + // Data out + led_data = data; + + // Data in + spi_data = kbd_data; + + // Indicate transfer complete + spi_status |= SPSR_SPIF; + } + break; + } + +// printf("SPI %02x to %x (PC=%x)\n", data, offset, m_maincpu->pc()); +} diff --git a/src/mame/dec/lk201.h b/src/mame/dec/lk201.h new file mode 100644 index 00000000000..c22f4e70827 --- /dev/null +++ b/src/mame/dec/lk201.h @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, M. Burke +#ifndef MAME_DEC_LK201_H +#define MAME_DEC_LK201_H + +#pragma once + +#include "sound/beep.h" + +#include "diserial.h" + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LK_CMD_LEDS_ON 0x13 /* light LEDs - 1st param: led bitmask */ +#define LK_CMD_LEDS_OFF 0x11 /* turn off LEDs */ + +#define LK_CMD_DIS_KEYCLK 0x99 /* disable the keyclick */ +#define LK_CMD_ENB_KEYCLK 0x1b /* enable the keyclick - 1st param: volume */ +#define LK_CMD_DIS_CTLCLK 0xb9 /* disable the Ctrl keyclick */ +#define LK_CMD_ENB_CTLCLK 0xbb /* enable the Ctrl keyclick */ +#define LK_CMD_SOUND_CLK 0x9f /* emit a keyclick - 1st param: volume */ +#define LK_CMD_DIS_BELL 0xa1 /* disable the bell */ +#define LK_CMD_ENB_BELL 0x23 /* enable the bell - 1st param: volume */ +#define LK_CMD_BELL 0xa7 /* emit a bell - 1st param: volume */ + +// TCR - Timer Compare Register +#define TCR_OCIE 0x40 // Bit 6 (output compare IRQ enable) +#define TCR_OLVL 0x01 // Bit 1 (output level) + +// TSR - Timer Status Register +#define TSR_OCFL 0x40 // TSR (68HC05 output compare flag) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> lk201_device + +class lk201_device : public device_t, public device_serial_interface +{ +public: + // construction/destruction + lk201_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + + uint8_t ddr_r(offs_t offset); + void ddr_w(offs_t offset, uint8_t data); + uint8_t ports_r(offs_t offset); + void ports_w(offs_t offset, uint8_t data); + uint8_t sci_r(offs_t offset); + void sci_w(offs_t offset, uint8_t data); + uint8_t spi_r(offs_t offset); + void spi_w(offs_t offset, uint8_t data); + uint8_t timer_r(offs_t offset); + void timer_w(offs_t offset, uint8_t data); + + auto tx_handler() { return m_tx_handler.bind(); } + + void lk201_map(address_map &map); +protected: + // device-level overrides + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; + virtual ioport_constructor device_input_ports() const override; + virtual void device_start() override; + virtual void device_reset() override; + + // device_serial overrides + virtual void rcv_complete() override; // Rx completed receiving byte + virtual void tra_complete() override; // Tx completed sending byte + virtual void tra_callback() override; // Tx send bit + + TIMER_CALLBACK_MEMBER(timer_irq); + TIMER_CALLBACK_MEMBER(beeper_off); + +private: + uint8_t ddrs[3]; + uint8_t ports[3]; + uint8_t led_data; + uint8_t kbd_data; + + union { + struct { + uint8_t tcr; + uint8_t tsr; + uint8_t icrh; + uint8_t icrl; + uint8_t ocrh; + uint8_t ocrl; + uint8_t crh; + uint8_t crl; + uint8_t acrh; + uint8_t acrl; + }; + uint8_t regs[10]; + } m_timer; + + emu_timer *m_count; + emu_timer *m_beeper; + + uint8_t sci_ctl2; + uint8_t sci_status; + //uint8_t sci_data; + + uint8_t spi_status; + uint8_t spi_data; + + required_device m_maincpu; + required_device m_speaker; + + required_ioport_array<18> m_kbd; + + output_finder<> m_led_wait; + output_finder<> m_led_compose; + output_finder<> m_led_lock; + output_finder<> m_led_hold; + + void send_port(uint8_t offset, uint8_t data); + void update_interrupts(); + + int m_kbd_state; + + devcb_write_line m_tx_handler; +}; + +// device type definition +DECLARE_DEVICE_TYPE(LK201, lk201_device) + +#endif // MAME_DEC_LK201_H diff --git a/src/mame/dec/rainbow.cpp b/src/mame/dec/rainbow.cpp index a940405ec96..df0f5a754f9 100644 --- a/src/mame/dec/rainbow.cpp +++ b/src/mame/dec/rainbow.cpp @@ -345,7 +345,7 @@ W17 pulls J1 serial port pin 1 to GND when set (chassis to logical GND). #include "bus/rs232/terminal.h" #include "machine/i8251.h" -#include "dec_lk201.h" +#include "lk201.h" #include "machine/nvram.h" #include "machine/ripple_counter.h" #include "machine/timer.h" @@ -1267,7 +1267,7 @@ void rainbow_base_state::machine_reset() m_leds[5] = 1; m_leds[6] = 1; - // GREEN KEYBOARD LEDs (see machine/dec_lk201.cpp) + // GREEN KEYBOARD LEDs (see dec/lk201.cpp) } void rainbow_modela_state::machine_reset() diff --git a/src/mame/dec/sfb.cpp b/src/mame/dec/sfb.cpp new file mode 100644 index 00000000000..73e32f39366 --- /dev/null +++ b/src/mame/dec/sfb.cpp @@ -0,0 +1,172 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont + +/* + * An emulation of the Digital Equipment Corporation SFB "Smart Frame Buffer" chip + * + * Used in: + * + * Accelerated TURBOChannel video cards for DECstations and AlphaStations + * On-board on some DECstations + * On-board on many AlphaStations + * + * Sources: + * + * http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-93-1.pdf + * + */ + +#include "emu.h" +#include "sfb.h" + +#define MODE_SIMPLE 0 +#define MODE_OPAQUESTIPPLE 1 +#define MODE_OPAQUELINE 2 +#define MODE_TRANSPARENTSTIPPLE 5 +#define MODE_TRANSPARENTLINE 6 +#define MODE_COPY 7 + +#define LOG_REG (1U << 1) +#define LOG_IRQ (1U << 2) + +//#define VERBOSE (LOG_GENERAL|LOG_REG||LOG_IRQ) + +#include "logmacro.h" + +DEFINE_DEVICE_TYPE(DECSFB, decsfb_device, "decsfb", "Digital Equipment Corporation Smart Frame Buffer") + +decsfb_device::decsfb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, DECSFB, tag, owner, clock), + m_int_cb(*this) +{ +} + +void decsfb_device::device_start() +{ + save_item(NAME(m_vram)); + save_item(NAME(m_regs)); + save_item(NAME(m_copy_src)); +} + +void decsfb_device::device_reset() +{ + m_copy_src = 1; +} + +/* + 0x100000 copy register 0 + 0x100004 copy register 1 + 0x100008 copy register 2 + 0x10000C copy register 3 + 0x100010 copy register 4 + 0x100014 copy register 5 + 0x100018 copy register 6 + 0x10001C copy register 7 + 0x100020 foreground register + 0x100024 background register + 0x100028 plane mask + 0x10002C pixel mask + 0x100030 cxt mode + 0x100034 boolean operation + 0x100038 pixel shift + 0x10003C line address + 0x100040 bresh 1 + 0x100044 bresh 2 + 0x100048 bresh 3 + 0x10004C bresh continue + 0x100050 deep register + 0x100054 start register + 0x100058 Clear Interrupt + 0x10005C reserved 2 + 0x100060 refresh count + 0x100064 video horiz + 0x100068 video vertical + 0x10006C refresh base + 0x100070 video valid + 0x100074 Interrupt Enable +*/ + +u32 decsfb_device::read(offs_t offset) +{ + return m_regs[offset]; +} + +void decsfb_device::write(offs_t offset, u32 data, u32 mem_mask) +{ + COMBINE_DATA(&m_regs[offset]); + + if ((offset == (0x30/4)) && (data = 7)) + { + m_copy_src = 1; + } +} + +u32 decsfb_device::vram_r(offs_t offset) +{ + return m_vram[offset]; +} + +void decsfb_device::vram_w(offs_t offset, u32 data, u32 mem_mask) +{ + switch (m_regs[0x30/4]) + { + case MODE_SIMPLE: // simple + COMBINE_DATA(&m_vram[offset]); + break; + + case MODE_TRANSPARENTSTIPPLE: + { + uint8_t *pVRAM = (uint8_t *)&m_vram[offset]; + uint8_t fgs[4]; + + fgs[0] = m_regs[0x20/4] >> 24; + fgs[1] = (m_regs[0x20/4] >> 16) & 0xff; + fgs[2] = (m_regs[0x20/4] >> 8) & 0xff; + fgs[3] = m_regs[0x20/4] & 0xff; + for (int x = 0; x < 32; x++) + { + if (data & (1<<(31-x))) + { + pVRAM[x] = fgs[x & 3]; + } + } + } + break; + + case MODE_COPY: + { + uint8_t *pVRAM = (uint8_t *)&m_vram[offset]; + uint8_t *pBuffer = (uint8_t *)&m_regs[0]; // first 8 32-bit regs are the copy buffer + + if (m_copy_src) + { + m_copy_src = 0; + + for (int x = 0; x < 32; x++) + { + if (data & (1<<(31-x))) + { + pBuffer[x] = pVRAM[x]; + } + } + } + else + { + m_copy_src = 1; + + for (int x = 0; x < 32; x++) + { + if (data & (1<<(31-x))) + { + pVRAM[x] = pBuffer[x]; + } + } + } + } + break; + + default: + logerror("SFB: Unsupported VRAM write %08x (mask %08x) at %08x in mode %x\n", data, mem_mask, offset<<2, m_regs[0x30/4]); + break; + } +} diff --git a/src/mame/dec/sfb.h b/src/mame/dec/sfb.h new file mode 100644 index 00000000000..59d3dbe1396 --- /dev/null +++ b/src/mame/dec/sfb.h @@ -0,0 +1,38 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont + +#ifndef MAME_DEC_SFB_H +#define MAME_DEC_SFB_H + +#pragma once + +class decsfb_device : public device_t +{ +public: + decsfb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto int_cb() { return m_int_cb.bind(); } + + u32 read(offs_t offset); + void write(offs_t offset, u32 data, u32 mem_mask = ~0); + uint32_t vram_r(offs_t offset); + void vram_w(offs_t offset, u32 data, u32 mem_mask = ~0); + + u32 *get_vram() { return m_vram; } + +protected: + // standard device_interface overrides + virtual void device_start() override; + virtual void device_reset() override; + + devcb_write_line m_int_cb; + +private: + u32 m_vram[0x200000/4]; + u32 m_regs[0x80]; + int m_copy_src; +}; + +DECLARE_DEVICE_TYPE(DECSFB, decsfb_device) + +#endif // MAME_DEC_SFB_H diff --git a/src/mame/dec/vt240.cpp b/src/mame/dec/vt240.cpp index 5411594c624..47e50500c78 100644 --- a/src/mame/dec/vt240.cpp +++ b/src/mame/dec/vt240.cpp @@ -7,7 +7,7 @@ ****************************************************************************/ #include "emu.h" -#include "dec_lk201.h" +#include "lk201.h" #include "ms7004.h" -- cgit v1.2.3