summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus
diff options
context:
space:
mode:
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
commit943fc34f3994a7dd2b2e63ae844cef2dc4645fe9 (patch)
tree8b661a1bc0589e3f78d9cc06813536bfa310e58b /src/devices/bus
parentb31859d6c534a192a5e36d2fc6a6de40b3629ec0 (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.cpp252
-rw-r--r--src/devices/bus/hp_ipc_io/82919.h73
-rw-r--r--src/devices/bus/hp_ipc_io/hp_ipc_io.cpp86
-rw-r--r--src/devices/bus/hp_ipc_io/hp_ipc_io.h82
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