summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/hp9845_io/98032.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/hp9845_io/98032.cpp')
-rw-r--r--src/devices/bus/hp9845_io/98032.cpp569
1 files changed, 569 insertions, 0 deletions
diff --git a/src/devices/bus/hp9845_io/98032.cpp b/src/devices/bus/hp9845_io/98032.cpp
new file mode 100644
index 00000000000..c4838331b87
--- /dev/null
+++ b/src/devices/bus/hp9845_io/98032.cpp
@@ -0,0 +1,569 @@
+// license:BSD-3-Clause
+// copyright-holders: F. Ulivi
+/*********************************************************************
+
+ 98032.cpp
+
+ 98032 module (GPIO interface)
+
+ Main reference for this module:
+ HP, 98032A 16-bit Interface Installation and Service Manual
+
+*********************************************************************/
+
+#include "emu.h"
+#include "98032.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_CLR(T& w , unsigned n)
+ {
+ w &= ~BIT_MASK<T>(n);
+ }
+
+ template<typename T> void BIT_SET(T& w , unsigned n)
+ {
+ w |= BIT_MASK<T>(n);
+ }
+}
+
+// device type definition
+DEFINE_DEVICE_TYPE(HP98032_IO_CARD, hp98032_io_card_device, "hp98032" , "HP98032 card")
+DEFINE_DEVICE_TYPE(HP98032_GPIO_SLOT , hp98032_gpio_slot_device , "hp98032_gpio_slot" , "HP98032 GPIO slot")
+DEFINE_DEVICE_TYPE(HP98032_GPIO_LOOPBACK , hp98032_gpio_loopback_device , "hp98032_loopback" , "HP98032 loopback connector")
+
+// +----------------------+
+// |hp98032_io_card_device|
+// +----------------------+
+
+hp98032_io_card_device::hp98032_io_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : hp9845_io_card_device(mconfig , HP98032_IO_CARD , tag , owner , clock)
+ , m_gpio(*this , "gpio")
+{
+}
+
+hp98032_io_card_device::~hp98032_io_card_device()
+{
+}
+
+MACHINE_CONFIG_START(hp98032_io_card_device::device_add_mconfig)
+ HP98032_GPIO_SLOT(config , m_gpio , 0);
+ m_gpio->pflg_cb().set(FUNC(hp98032_io_card_device::pflg_w));
+ m_gpio->psts_cb().set(FUNC(hp98032_io_card_device::psts_w));
+ m_gpio->eir_cb().set(FUNC(hp98032_io_card_device::eir_w));
+MACHINE_CONFIG_END
+
+static INPUT_PORTS_START(hp98032_port)
+ MCFG_HP9845_IO_SC(2)
+INPUT_PORTS_END
+
+ioport_constructor hp98032_io_card_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(hp98032_port);
+}
+
+void hp98032_io_card_device::device_start()
+{
+ save_item(NAME(m_output));
+ save_item(NAME(m_input));
+ save_item(NAME(m_int_en));
+ save_item(NAME(m_dma_en));
+ save_item(NAME(m_busy));
+ save_item(NAME(m_pready));
+ save_item(NAME(m_flag));
+ save_item(NAME(m_auto_ah));
+ save_item(NAME(m_eir));
+}
+
+void hp98032_io_card_device::device_reset()
+{
+ // m_output is not reset
+ // m_input is not reset
+ m_int_en = false;
+ m_dma_en = false;
+ m_busy = true; // Force reset
+ m_auto_ah = false;
+ set_busy(false);
+ update_irq();
+ update_dmar();
+ m_gpio->preset_w(1);
+ m_gpio->preset_w(0);
+}
+
+READ16_MEMBER(hp98032_io_card_device::reg_r)
+{
+ uint16_t res = 0;
+
+ switch (offset) {
+ case 0:
+ // R4
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_C)) {
+ latch_input_LSB();
+ }
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_B) &&
+ m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_A)) {
+ latch_input_MSB();
+ }
+ res = m_input & 0x00ff;
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_B)) {
+ res |= (m_input & 0xff00);
+ }
+ // Set direction to input
+ m_gpio->io_w(0);
+ if (m_auto_ah) {
+ start_hs();
+ }
+ break;
+
+ case 1:
+ // R5
+ BIT_SET(res , 5);
+ res |= (m_gpio->ext_status_r() & 3);
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_2)) {
+ BIT_SET(res , 2);
+ }
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_1)) {
+ BIT_SET(res , 3);
+ }
+ if (m_dma_en) {
+ BIT_SET(res , 6);
+ }
+ if (m_int_en) {
+ BIT_SET(res , 7);
+ }
+ break;
+
+ case 2:
+ // R6
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_B) &&
+ m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_C)) {
+ latch_input_LSB();
+ }
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_A)) {
+ latch_input_MSB();
+ }
+ res = m_input & 0xff00;
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_B)) {
+ res |= (m_input & 0x00ff);
+ }
+ m_dma_en = false;
+ update_irq();
+ update_dmar();
+ break;
+
+ case 3:
+ // R7: not mapped
+ default:
+ break;
+ }
+
+ LOG("rd R%u=%04x\n" , offset + 4 , res);
+ return res;
+}
+
+WRITE16_MEMBER(hp98032_io_card_device::reg_w)
+{
+ LOG("wr R%u=%04x\n" , offset + 4 , data);
+
+ switch (offset) {
+ case 0:
+ // R4
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_F)) {
+ m_output = data;
+ } else {
+ m_output = (m_output & 0xff00) | (data & 0x00ff);
+ }
+ m_gpio->output_w(m_output);
+ // Set direction to output
+ m_gpio->io_w(1);
+ if (m_auto_ah) {
+ start_hs();
+ }
+ break;
+
+ case 1:
+ // R5
+ m_gpio->ext_control_w(data & 3);
+ if (BIT(data , 5)) {
+ // Reset pulse
+ device_reset();
+ } else {
+ m_auto_ah = BIT(data , 4);
+ m_dma_en = BIT(data , 6);
+ m_int_en = BIT(data , 7);
+ update_irq();
+ update_dmar();
+ }
+ break;
+
+ case 2:
+ // R6
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_F)) {
+ m_output = data;
+ } else {
+ m_output = (m_output & 0x00ff) | (data & 0xff00);
+ }
+ m_gpio->output_w(m_output);
+ // Set direction to output
+ m_gpio->io_w(1);
+ if (m_auto_ah) {
+ start_hs();
+ }
+ m_dma_en = false;
+ update_irq();
+ update_dmar();
+ break;
+
+ case 3:
+ // R7
+ start_hs();
+ break;
+
+ default:
+ break;
+ }
+}
+
+WRITE_LINE_MEMBER(hp98032_io_card_device::pflg_w)
+{
+ bool prev_pready = m_pready;
+ m_pready = state;
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_4)) {
+ m_pready = !m_pready;
+ }
+ LOG("pready = %d\n" , m_pready);
+ if (!prev_pready && m_pready) {
+ // Going to ready state
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_9)) {
+ latch_input_MSB();
+ }
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_D)) {
+ latch_input_LSB();
+ }
+ } else if (prev_pready && !m_pready) {
+ // Going to not ready state
+ set_busy(false);
+ }
+ if (prev_pready != m_pready) {
+ update_flag();
+ }
+}
+
+WRITE_LINE_MEMBER(hp98032_io_card_device::psts_w)
+{
+ bool sts = !state;
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_5)) {
+ sts = !sts;
+ }
+ LOG("sts = %d\n" , sts);
+ sts_w(sts);
+}
+
+WRITE_LINE_MEMBER(hp98032_io_card_device::eir_w)
+{
+ m_eir = state;
+ LOG("eir = %d\n" , m_eir);
+ update_irq();
+}
+
+void hp98032_io_card_device::start_hs()
+{
+ set_busy(true);
+}
+
+void hp98032_io_card_device::set_busy(bool state)
+{
+ LOG("busy = %d\n" , state);
+ if (m_busy && !state) {
+ // BUSY -> !BUSY
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_8)) {
+ latch_input_MSB();
+ }
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_E)) {
+ latch_input_LSB();
+ }
+ }
+ if (m_busy != state) {
+ m_busy = state;
+ update_flag();
+ bool pctl = m_busy;
+ if (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_3)) {
+ pctl = !pctl;
+ }
+ LOG("pctl = %d\n" , pctl);
+ m_gpio->pctl_w(pctl);
+ }
+}
+
+void hp98032_io_card_device::update_flag()
+{
+ bool new_flag = !m_busy && (m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_6) || m_pready);
+ if (new_flag != m_flag) {
+ m_flag = new_flag;
+ LOG("flag = %d\n" , m_flag);
+ update_irq();
+ update_dmar();
+ flg_w(m_flag);
+ }
+}
+
+void hp98032_io_card_device::update_irq()
+{
+ bool irq = m_int_en && (m_eir || (!m_dma_en && m_flag));
+ LOG("irq = %d\n" , irq);
+ irq_w(irq);
+}
+
+void hp98032_io_card_device::update_dmar()
+{
+ bool dmar = m_gpio->is_jumper_present(hp98032_gpio_slot_device::JUMPER_7) && m_flag && m_dma_en;
+ LOG("dmar = %d\n" , dmar);
+ dmar_w(dmar);
+}
+
+void hp98032_io_card_device::latch_input_MSB()
+{
+ m_input = (m_input & 0x00ff) | (m_gpio->input_r() & 0xff00);
+}
+
+void hp98032_io_card_device::latch_input_LSB()
+{
+ m_input = (m_input & 0xff00) | (m_gpio->input_r() & 0x00ff);
+}
+
+// +------------------------+
+// |hp98032_gpio_slot_device|
+// +------------------------+
+
+hp98032_gpio_slot_device::hp98032_gpio_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig , HP98032_GPIO_SLOT , tag , owner , clock)
+ , device_slot_interface(mconfig , *this)
+ , m_pflg_handler(*this)
+ , m_psts_handler(*this)
+ , m_eir_handler(*this)
+{
+ option_reset();
+ option_add("loopback" , HP98032_GPIO_LOOPBACK);
+ set_default_option(nullptr);
+ set_fixed(false);
+}
+
+hp98032_gpio_slot_device::~hp98032_gpio_slot_device()
+{
+}
+
+uint16_t hp98032_gpio_slot_device::get_jumpers() const
+{
+ hp98032_gpio_card_device *card = downcast<hp98032_gpio_card_device*>(get_card_device());
+ if (card != nullptr) {
+ return card->get_jumpers();
+ } else {
+ return 0;
+ }
+}
+
+uint16_t hp98032_gpio_slot_device::input_r() const
+{
+ hp98032_gpio_card_device *card = downcast<hp98032_gpio_card_device*>(get_card_device());
+ if (card != nullptr) {
+ return card->input_r();
+ } else {
+ return 0;
+ }
+}
+
+uint8_t hp98032_gpio_slot_device::ext_status_r() const
+{
+ hp98032_gpio_card_device *card = downcast<hp98032_gpio_card_device*>(get_card_device());
+ if (card != nullptr) {
+ return card->ext_status_r();
+ } else {
+ return 0;
+ }
+}
+
+void hp98032_gpio_slot_device::output_w(uint16_t data)
+{
+ hp98032_gpio_card_device *card = downcast<hp98032_gpio_card_device*>(get_card_device());
+ if (card != nullptr) {
+ card->output_w(data);
+ }
+}
+
+void hp98032_gpio_slot_device::ext_control_w(uint8_t data)
+{
+ hp98032_gpio_card_device *card = downcast<hp98032_gpio_card_device*>(get_card_device());
+ if (card != nullptr) {
+ card->ext_control_w(data);
+ }
+}
+
+WRITE_LINE_MEMBER(hp98032_gpio_slot_device::pflg_w)
+{
+ m_pflg_handler(state);
+}
+
+WRITE_LINE_MEMBER(hp98032_gpio_slot_device::psts_w)
+{
+ m_psts_handler(state);
+}
+
+WRITE_LINE_MEMBER(hp98032_gpio_slot_device::eir_w)
+{
+ m_eir_handler(state);
+}
+
+WRITE_LINE_MEMBER(hp98032_gpio_slot_device::pctl_w)
+{
+ hp98032_gpio_card_device *card = downcast<hp98032_gpio_card_device*>(get_card_device());
+ if (card != nullptr) {
+ card->pctl_w(state);
+ }
+}
+
+WRITE_LINE_MEMBER(hp98032_gpio_slot_device::io_w)
+{
+ hp98032_gpio_card_device *card = downcast<hp98032_gpio_card_device*>(get_card_device());
+ if (card != nullptr) {
+ card->io_w(state);
+ }
+}
+
+WRITE_LINE_MEMBER(hp98032_gpio_slot_device::preset_w)
+{
+ hp98032_gpio_card_device *card = downcast<hp98032_gpio_card_device*>(get_card_device());
+ if (card != nullptr) {
+ card->preset_w(state);
+ }
+}
+
+void hp98032_gpio_slot_device::device_start()
+{
+ m_pflg_handler.resolve_safe();
+ m_psts_handler.resolve_safe();
+ m_eir_handler.resolve_safe();
+}
+
+void hp98032_gpio_slot_device::device_reset()
+{
+ // When nothing is connected to GPIO, set input signals to 0
+ if (get_card_device() == nullptr) {
+ m_pflg_handler(0);
+ m_psts_handler(0);
+ m_eir_handler(0);
+ }
+}
+
+// +------------------------+
+// |hp98032_gpio_card_device|
+// +------------------------+
+
+hp98032_gpio_card_device::hp98032_gpio_card_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig , type , tag , owner , clock)
+ , device_slot_card_interface(mconfig , *this)
+{
+}
+
+hp98032_gpio_card_device::~hp98032_gpio_card_device()
+{
+}
+
+WRITE_LINE_MEMBER(hp98032_gpio_card_device::pflg_w)
+{
+ hp98032_gpio_slot_device *slot = downcast<hp98032_gpio_slot_device*>(owner());
+ slot->pflg_w(state);
+}
+
+WRITE_LINE_MEMBER(hp98032_gpio_card_device::psts_w)
+{
+ hp98032_gpio_slot_device *slot = downcast<hp98032_gpio_slot_device*>(owner());
+ slot->psts_w(state);
+}
+
+WRITE_LINE_MEMBER(hp98032_gpio_card_device::eir_w)
+{
+ hp98032_gpio_slot_device *slot = downcast<hp98032_gpio_slot_device*>(owner());
+ slot->eir_w(state);
+}
+
+// +----------------------------+
+// |hp98032_gpio_loopback_device|
+// +----------------------------+
+
+hp98032_gpio_loopback_device::hp98032_gpio_loopback_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : hp98032_gpio_card_device(mconfig, HP98032_GPIO_LOOPBACK, tag, owner, clock)
+{
+}
+
+hp98032_gpio_loopback_device::~hp98032_gpio_loopback_device()
+{
+}
+
+uint16_t hp98032_gpio_loopback_device::get_jumpers() const
+{
+ return hp98032_gpio_slot_device::JUMPER_1 |
+ hp98032_gpio_slot_device::JUMPER_2 |
+ hp98032_gpio_slot_device::JUMPER_4 |
+ hp98032_gpio_slot_device::JUMPER_7 |
+ hp98032_gpio_slot_device::JUMPER_A |
+ hp98032_gpio_slot_device::JUMPER_B |
+ hp98032_gpio_slot_device::JUMPER_C |
+ hp98032_gpio_slot_device::JUMPER_F;
+}
+
+uint16_t hp98032_gpio_loopback_device::input_r() const
+{
+ return m_output;
+}
+
+uint8_t hp98032_gpio_loopback_device::ext_status_r() const
+{
+ uint8_t res = m_ext_control;
+ if (m_io) {
+ BIT_SET(res , 0);
+ }
+ return res;
+}
+
+void hp98032_gpio_loopback_device::output_w(uint16_t data)
+{
+ m_output = data;
+}
+
+void hp98032_gpio_loopback_device::ext_control_w(uint8_t data)
+{
+ m_ext_control = data;
+}
+
+WRITE_LINE_MEMBER(hp98032_gpio_loopback_device::pctl_w)
+{
+ pflg_w(state);
+}
+
+WRITE_LINE_MEMBER(hp98032_gpio_loopback_device::io_w)
+{
+ m_io = state;
+}
+
+WRITE_LINE_MEMBER(hp98032_gpio_loopback_device::preset_w)
+{
+ eir_w(state);
+}
+
+void hp98032_gpio_loopback_device::device_start()
+{
+}
+
+void hp98032_gpio_loopback_device::device_reset()
+{
+ psts_w(0);
+}