diff options
author | fulivi <fulivi@users.noreply.github.com> | 2020-07-27 20:12:05 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-27 14:12:05 -0400 |
commit | 943fc34f3994a7dd2b2e63ae844cef2dc4645fe9 (patch) | |
tree | 8b661a1bc0589e3f78d9cc06813536bfa310e58b /src/devices/bus | |
parent | b31859d6c534a192a5e36d2fc6a6de40b3629ec0 (diff) |
HP IPC: support for I/O slots and 82919 serial card added (#7001)
* mc68681: tx/rx clocking from timer fixed, added partial support for
break signal
* hp_ipc: support for I/O slots added, 82919 serial I/O card added
Diffstat (limited to 'src/devices/bus')
-rw-r--r-- | src/devices/bus/hp_ipc_io/82919.cpp | 252 | ||||
-rw-r--r-- | src/devices/bus/hp_ipc_io/82919.h | 73 | ||||
-rw-r--r-- | src/devices/bus/hp_ipc_io/hp_ipc_io.cpp | 86 | ||||
-rw-r--r-- | src/devices/bus/hp_ipc_io/hp_ipc_io.h | 82 |
4 files changed, 493 insertions, 0 deletions
diff --git a/src/devices/bus/hp_ipc_io/82919.cpp b/src/devices/bus/hp_ipc_io/82919.cpp new file mode 100644 index 00000000000..f9b5024d4c3 --- /dev/null +++ b/src/devices/bus/hp_ipc_io/82919.cpp @@ -0,0 +1,252 @@ +// license:BSD-3-Clause +// copyright-holders: F. Ulivi +/********************************************************************* + + 82919.cpp + + 82919 module (RS232 interface) + + Main reference for this module is: + HP 82919-90009, feb 85, HP82919A Integral PC Serial Interface - + Component level service manual + +*********************************************************************/ + +#include "emu.h" +#include "82919.h" +#include "coreutil.h" + +// Debugging +#define VERBOSE 0 +#include "logmacro.h" + +// Bit manipulation +namespace { + template<typename T> constexpr T BIT_MASK(unsigned n) + { + return (T)1U << n; + } + + template<typename T> void BIT_SET(T& w , unsigned n) + { + w |= BIT_MASK<T>(n); + } +} + +hp82919_io_card_device::hp82919_io_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig , HP82919_IO_CARD , tag , owner , clock) + , device_hp_ipc_io_interface(mconfig, *this) + , m_rs232_prim(*this , "rs232_prim") + , m_rs232_sec(*this , "rs232_sec") + , m_uart(*this , "uart") + , m_loopback_en(*this, "loop") +{ +} + +hp82919_io_card_device::~hp82919_io_card_device() +{ +} + +uint8_t hp82919_io_card_device::read(offs_t addr) +{ + uint8_t res = 0; + offs_t uart_addr = (addr ^ 0xc) & 0xf; + + if (BIT(addr , 4)) { + res = m_uart->read(uart_addr); + } else { + // 2 is 82919 ID code + res = 2; + res |= (m_int_level << 4); + if (m_int_pending) { + BIT_SET(res , 6); + } + if (m_int_en) { + BIT_SET(res , 7); + } + m_uart->write(uart_addr , res); + } + LOG("RD %04x=%02x\n" , addr , res); + return res; +} + +void hp82919_io_card_device::write(offs_t addr , uint8_t data) +{ + LOG("WR %04x=%02x\n" , addr , data); + offs_t uart_addr = (addr ^ 0xc) & 0xf; + m_uart->write(uart_addr , data); + if (!BIT(addr , 4)) { + m_int_level = (data >> 4) & 3; + m_int_forced = BIT(data , 6); + m_int_en = BIT(data , 7); + update_irq(); + } +} + +WRITE_LINE_MEMBER(hp82919_io_card_device::uart_irq) +{ + m_uart_int = state; + update_irq(); +} + +WRITE_LINE_MEMBER(hp82919_io_card_device::uart_a_tx) +{ + m_rs232_prim->write_txd(state); + if (m_loopback) { + m_uart->rx_b_w(state); + } +} + +WRITE_LINE_MEMBER(hp82919_io_card_device::uart_b_tx) +{ + m_rs232_sec->write_txd(state); + if (m_loopback) { + m_uart->rx_a_w(state); + } +} + +void hp82919_io_card_device::uart_output(uint8_t data) +{ + m_rs232_prim->write_dtr(BIT(data , 0)); + m_rs232_prim->write_rts(BIT(data , 1)); + // b2 is TxClock + m_rs232_prim->write_spds(BIT(data , 3)); + m_rs232_sec->write_rts(BIT(data , 4)); + if (m_loopback) { + m_uart->ip0_w(BIT(data , 0)); + m_uart->ip1_w(BIT(data , 1)); + m_uart->ip2_w(BIT(data , 2)); + m_uart->ip3_w(BIT(data , 3)); + m_uart->ip4_w(BIT(data , 4)); + m_uart->ip5_w(BIT(data , 4)); + } +} + +WRITE_LINE_MEMBER(hp82919_io_card_device::prim_rxd) +{ + if (!m_loopback) { + m_uart->rx_a_w(state); + } +} + +WRITE_LINE_MEMBER(hp82919_io_card_device::prim_dcd) +{ + if (!m_loopback) { + m_uart->ip3_w(state); + } +} + +WRITE_LINE_MEMBER(hp82919_io_card_device::prim_dsr) +{ + if (!m_loopback) { + m_uart->ip1_w(state); + } +} + +WRITE_LINE_MEMBER(hp82919_io_card_device::prim_ri) +{ + if (!m_loopback) { + m_uart->ip2_w(state); + } +} + +WRITE_LINE_MEMBER(hp82919_io_card_device::prim_cts) +{ + if (!m_loopback) { + m_uart->ip0_w(state); + } +} + +WRITE_LINE_MEMBER(hp82919_io_card_device::sec_rxd) +{ + if (!m_loopback) { + m_uart->rx_b_w(state); + } +} + +WRITE_LINE_MEMBER(hp82919_io_card_device::sec_dcd) +{ + if (!m_loopback) { + m_uart->ip5_w(state); + } +} + +WRITE_LINE_MEMBER(hp82919_io_card_device::sec_cts) +{ + if (!m_loopback) { + m_uart->ip4_w(state); + } +} + +void hp82919_io_card_device::install_read_write_handlers(address_space& space , uint32_t base_addr) +{ + offs_t end_addr = base_addr + 0xffffU; + + // Supervisor mode + space.install_readwrite_handler(base_addr, end_addr, read8sm_delegate(*this, FUNC(hp82919_io_card_device::read)), write8sm_delegate(*this, FUNC(hp82919_io_card_device::write)), 0x00ff); + // User mode + space.install_readwrite_handler(base_addr + USER_SPACE_OFFSET, end_addr + USER_SPACE_OFFSET, read8sm_delegate(*this, FUNC(hp82919_io_card_device::read)), write8sm_delegate(*this, FUNC(hp82919_io_card_device::write)), 0x00ff); +} + +void hp82919_io_card_device::device_start() +{ +} + +void hp82919_io_card_device::device_reset() +{ + m_loopback = m_loopback_en->read() != 0; + m_int_level = 0; + m_int_forced = false; + m_int_en = false; + m_uart_int = false; + m_irq = true; + update_irq(); +} + +void hp82919_io_card_device::device_add_mconfig(machine_config &config) +{ + RS232_PORT(config, m_rs232_prim, default_rs232_devices, nullptr); + RS232_PORT(config, m_rs232_sec, default_rs232_devices, nullptr); + + MC68681(config , m_uart , 3.6864_MHz_XTAL); + m_uart->irq_cb().set(FUNC(hp82919_io_card_device::uart_irq)); + m_uart->a_tx_cb().set(FUNC(hp82919_io_card_device::uart_a_tx)); + m_uart->b_tx_cb().set(FUNC(hp82919_io_card_device::uart_b_tx)); + m_uart->outport_cb().set(FUNC(hp82919_io_card_device::uart_output)); + + m_rs232_prim->rxd_handler().set(FUNC(hp82919_io_card_device::prim_rxd)); + m_rs232_prim->dcd_handler().set(FUNC(hp82919_io_card_device::prim_dcd)); + m_rs232_prim->dsr_handler().set(FUNC(hp82919_io_card_device::prim_dsr)); + m_rs232_prim->ri_handler().set(FUNC(hp82919_io_card_device::prim_ri)); + m_rs232_prim->cts_handler().set(FUNC(hp82919_io_card_device::prim_cts)); + + m_rs232_sec->rxd_handler().set(FUNC(hp82919_io_card_device::sec_rxd)); + m_rs232_sec->dcd_handler().set(FUNC(hp82919_io_card_device::sec_dcd)); + m_rs232_sec->cts_handler().set(FUNC(hp82919_io_card_device::sec_cts)); +} + +static INPUT_PORTS_START(hp82919_port) + PORT_START("loop") + PORT_CONFNAME(1 , 0 , "Test loopback") + PORT_CONFSETTING(0 , DEF_STR(Off)) + PORT_CONFSETTING(1 , DEF_STR(On)) +INPUT_PORTS_END + +ioport_constructor hp82919_io_card_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(hp82919_port); +} + +void hp82919_io_card_device::update_irq() +{ + m_int_pending = m_int_forced || m_uart_int; + bool irq = m_int_en && m_int_pending; + if (m_irq != irq) { + m_irq = irq; + LOG("IRQ %u=%d\n" , m_int_level , irq); + irq_w(m_int_level , irq); + } +} + +// device type definition +DEFINE_DEVICE_TYPE(HP82919_IO_CARD, hp82919_io_card_device, "hp82919", "HP82919 card") diff --git a/src/devices/bus/hp_ipc_io/82919.h b/src/devices/bus/hp_ipc_io/82919.h new file mode 100644 index 00000000000..331a42b0b00 --- /dev/null +++ b/src/devices/bus/hp_ipc_io/82919.h @@ -0,0 +1,73 @@ +// license:BSD-3-Clause +// copyright-holders: F. Ulivi +/********************************************************************* + + 82919.h + + 82919 module (RS232 interface) + +*********************************************************************/ + +#ifndef MAME_BUS_HP_IPC_IO_82919_H +#define MAME_BUS_HP_IPC_IO_82919_H + +#pragma once + +#include "hp_ipc_io.h" +#include "machine/mc68681.h" +#include "bus/rs232/rs232.h" + +class hp82919_io_card_device : public device_t, public device_hp_ipc_io_interface +{ +public: + // construction/destruction + hp82919_io_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + virtual ~hp82919_io_card_device(); + + uint8_t read(offs_t addr); + void write(offs_t addr , uint8_t data); + + DECLARE_WRITE_LINE_MEMBER(uart_irq); + DECLARE_WRITE_LINE_MEMBER(uart_a_tx); + DECLARE_WRITE_LINE_MEMBER(uart_b_tx); + void uart_output(uint8_t data); + DECLARE_WRITE_LINE_MEMBER(prim_rxd); + DECLARE_WRITE_LINE_MEMBER(prim_dcd); + DECLARE_WRITE_LINE_MEMBER(prim_dsr); + DECLARE_WRITE_LINE_MEMBER(prim_ri); + DECLARE_WRITE_LINE_MEMBER(prim_cts); + DECLARE_WRITE_LINE_MEMBER(sec_rxd); + DECLARE_WRITE_LINE_MEMBER(sec_dcd); + DECLARE_WRITE_LINE_MEMBER(sec_cts); + +protected: + virtual void device_start() override; + virtual void device_reset() override; + + // device-level overrides + virtual void device_add_mconfig(machine_config &config) override; + virtual ioport_constructor device_input_ports() const override; + + virtual void install_read_write_handlers(address_space& space , uint32_t base_addr) override; + +private: + required_device<rs232_port_device> m_rs232_prim; + required_device<rs232_port_device> m_rs232_sec; + required_device<mc68681_device> m_uart; + required_ioport m_loopback_en; + + uint8_t m_int_level; + bool m_int_en; + bool m_int_forced; + bool m_int_pending; + bool m_uart_int; + bool m_irq; + bool m_loopback; + + void update_irq(); +}; + +// device type definition +DECLARE_DEVICE_TYPE(HP82919_IO_CARD, hp82919_io_card_device) + +#endif // MAME_BUS_HP_IPC_IO_82919_H diff --git a/src/devices/bus/hp_ipc_io/hp_ipc_io.cpp b/src/devices/bus/hp_ipc_io/hp_ipc_io.cpp new file mode 100644 index 00000000000..0f44b60cec5 --- /dev/null +++ b/src/devices/bus/hp_ipc_io/hp_ipc_io.cpp @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders: F. Ulivi +/********************************************************************* + + hp_ipc_io.cpp + + I/O bus of HP IPC system + +*********************************************************************/ + +#include "emu.h" +#include "hp_ipc_io.h" + +// Debugging +#define VERBOSE 0 +#include "logmacro.h" + +// device type definition +DEFINE_DEVICE_TYPE(HP_IPC_IO_SLOT, hp_ipc_io_slot_device, "hp ipc io slot", "HP IPC I/O Slot") + +// +---------------------+ +// |hp_ipc_io_slot_device| +// +---------------------+ +hp_ipc_io_slot_device::hp_ipc_io_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, HP_IPC_IO_SLOT, tag, owner, clock), + device_single_card_slot_interface<device_hp_ipc_io_interface>(mconfig, *this), + m_irq_cb_func(*this), + m_slot_idx(0) +{ +} + +hp_ipc_io_slot_device::~hp_ipc_io_slot_device() +{ +} + +void hp_ipc_io_slot_device::device_start() +{ + m_irq_cb_func.resolve_all_safe(); +} + +uint32_t hp_ipc_io_slot_device::get_slot_base_addr() const +{ + return m_slot_idx ? 0x710000 : 0x700000; +} + +void hp_ipc_io_slot_device::install_read_write_handlers(address_space& space) +{ + device_hp_ipc_io_interface *card = get_card_device(); + + if (card != nullptr) { + card->install_read_write_handlers(space , get_slot_base_addr()); + } +} + +void hp_ipc_io_slot_device::irq_w(unsigned idx , bool state) +{ + m_irq_cb_func[ 0 ](state && idx == 0); + m_irq_cb_func[ 1 ](state && idx == 1); + m_irq_cb_func[ 2 ](state && idx == 2); + m_irq_cb_func[ 3 ](state && idx == 3); +} + +// +--------------------------+ +// |device_hp_ipc_io_interface| +// +--------------------------+ +device_hp_ipc_io_interface::device_hp_ipc_io_interface(const machine_config &mconfig, device_t &device) : + device_interface(device, "hp_ipcio") +{ +} + +device_hp_ipc_io_interface::~device_hp_ipc_io_interface() +{ +} + +void device_hp_ipc_io_interface::irq_w(unsigned idx , bool state) +{ + hp_ipc_io_slot_device *slot = downcast<hp_ipc_io_slot_device *>(device().owner()); + slot->irq_w(idx , state); +} + +#include "82919.h" + +void hp_ipc_io_slot_devices(device_slot_interface &device) +{ + device.option_add("82919_serial" , HP82919_IO_CARD); +} diff --git a/src/devices/bus/hp_ipc_io/hp_ipc_io.h b/src/devices/bus/hp_ipc_io/hp_ipc_io.h new file mode 100644 index 00000000000..856b140c7ef --- /dev/null +++ b/src/devices/bus/hp_ipc_io/hp_ipc_io.h @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders: F. Ulivi +/********************************************************************* + + hp_ipc_io.h + + I/O bus of HP IPC system + +*********************************************************************/ + +#ifndef MAME_BUS_HP_IPC_IO_HP_IPC_IO_H +#define MAME_BUS_HP_IPC_IO_HP_IPC_IO_H + +#pragma once + +void hp_ipc_io_slot_devices(device_slot_interface &device); + +class device_hp_ipc_io_interface; + +class hp_ipc_io_slot_device : public device_t, + public device_single_card_slot_interface<device_hp_ipc_io_interface> +{ +public: + // construction/destruction + hp_ipc_io_slot_device(machine_config const &mconfig, char const *tag, device_t *owner) + : hp_ipc_io_slot_device(mconfig, tag, owner, (uint32_t)0) + { + option_reset(); + hp_ipc_io_slot_devices(*this); + set_default_option(nullptr); + set_fixed(false); + } + + hp_ipc_io_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + virtual ~hp_ipc_io_slot_device(); + + // Set A/B slot + void set_slot_idx(unsigned idx) { m_slot_idx = idx; } + + // Callback setups + auto irq3_cb() { return m_irq_cb_func[ 0 ].bind(); } + auto irq4_cb() { return m_irq_cb_func[ 1 ].bind(); } + auto irq5_cb() { return m_irq_cb_func[ 2 ].bind(); } + auto irq6_cb() { return m_irq_cb_func[ 3 ].bind(); } + + uint32_t get_slot_base_addr() const; + + void install_read_write_handlers(address_space& space); + + void irq_w(unsigned idx , bool state); + +protected: + // device-level overrides + virtual void device_start() override; + +private: + devcb_write_line::array<4> m_irq_cb_func; + // 0: slot A + // 1: slot B + unsigned m_slot_idx; +}; + +class device_hp_ipc_io_interface : public device_interface +{ +public: + virtual ~device_hp_ipc_io_interface(); + + virtual void install_read_write_handlers(address_space& space , uint32_t base_addr) = 0; + + static constexpr offs_t USER_SPACE_OFFSET = 0x1800000; + +protected: + device_hp_ipc_io_interface(const machine_config &mconfig, device_t &device); + + // card device handling + void irq_w(unsigned idx , bool state); +}; + +// device type definition +DECLARE_DEVICE_TYPE(HP_IPC_IO_SLOT, hp_ipc_io_slot_device) + +#endif // MAME_BUS_HP_IPC_IO_HP_IPC_IO_H |