summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine
diff options
context:
space:
mode:
author Sven Schnelle <svens@stackframe.org>2018-06-17 08:55:51 +0200
committer Vas Crabb <cuavas@users.noreply.github.com>2018-06-17 16:55:51 +1000
commit22ba8d40ddb2b1e61d812bf59a38d9f9c805299f (patch)
tree9d7ae0cc863ec3a4d00f821f9df92f2cf3024676 /src/devices/machine
parentd6a53357a56f1e2d1249b9e29e0ff117967b0a8b (diff)
Add HP9122 floppy drive (#3657)
* Revert "Revert "Add 9122c floppy (#3647)"" This reverts commit 0aa81fc184b225547091a10f4accb8f3ae7064da. * Address pull request comments Signed-off-by: Sven Schnelle <svens@stackframe.org> * MR#3657: address comments Signed-off-by: Sven Schnelle <svens@stackframe.org> * MR#3657: address MR comments Signed-off-by: Sven Schnelle <svens@stackframe.org> * MR#3657: address MR comments Signed-off-by: Sven Schnelle <svens@stackframe.org>
Diffstat (limited to 'src/devices/machine')
-rw-r--r--src/devices/machine/i8291a.cpp1160
-rw-r--r--src/devices/machine/i8291a.h408
2 files changed, 1568 insertions, 0 deletions
diff --git a/src/devices/machine/i8291a.cpp b/src/devices/machine/i8291a.cpp
new file mode 100644
index 00000000000..ebdac02962b
--- /dev/null
+++ b/src/devices/machine/i8291a.cpp
@@ -0,0 +1,1160 @@
+// license:BSD-3-Clause
+// copyright-holders: Sven Schnelle
+/*********************************************************************
+
+ i8291a.cpp
+
+ Intel 8291A GPIB controller
+
+ *********************************************************************/
+
+#include "emu.h"
+
+
+#include "i8291a.h"
+
+#define LOG_STATE (LOG_GENERAL << 1)
+#define LOG_REG (LOG_STATE << 1)
+#define LOG_INT (LOG_REG << 1)
+#define LOG_CMD (LOG_INT << 1)
+
+#define VERBOSE 0
+
+#include "logmacro.h"
+DEFINE_DEVICE_TYPE(I8291A, i8291a_device, "i8291a", "Intel I8291A GPIB Talker/Listener")
+
+ALLOW_SAVE_TYPE(i8291a_device::listener_state);
+ALLOW_SAVE_TYPE(i8291a_device::talker_state);
+ALLOW_SAVE_TYPE(i8291a_device::talker_primary_state);
+ALLOW_SAVE_TYPE(i8291a_device::listener_primary_state);
+ALLOW_SAVE_TYPE(i8291a_device::parallel_poll_state);
+ALLOW_SAVE_TYPE(i8291a_device::device_trigger_state);
+ALLOW_SAVE_TYPE(i8291a_device::device_clear_state);
+ALLOW_SAVE_TYPE(i8291a_device::talker_serial_poll_state);
+ALLOW_SAVE_TYPE(i8291a_device::serial_poll_state);
+ALLOW_SAVE_TYPE(i8291a_device::remote_local_state);
+ALLOW_SAVE_TYPE(i8291a_device::source_handshake_state);
+ALLOW_SAVE_TYPE(i8291a_device::acceptor_handshake_state);
+
+i8291a_device::i8291a_device(const machine_config &mconfig, const char *tag,
+ device_t *owner, uint32_t clock) :
+ device_t{mconfig, I8291A, tag, owner, clock},
+ m_int_write_func{*this},
+ m_dreq_write_func{*this},
+ m_trig_write_func{*this},
+ m_eoi_write_func{*this},
+ m_dav_write_func{*this},
+ m_nrfd_write_func{*this},
+ m_ndac_write_func{*this},
+ m_srq_write_func{*this},
+ m_dio_write_func{*this},
+ m_dio_read_func{*this}
+{
+}
+
+void i8291a_device::device_reset()
+{
+ m_pon = true;
+ m_ints1 = 0;
+ m_ints2 = 0;
+ m_auxa = 0;
+ m_auxb = 0;
+ m_spoll_mode = 0;
+ m_address_status &= ~REG_ADDRESS_STATUS_EOI;
+ m_rdy = true;
+ m_nba = false;
+ m_send_eoi = false;
+ m_ist = false;
+ m_eoi = false;
+ m_ifc = false;
+ m_srq = false;
+ m_dav = false;
+ m_ndac = false;
+ m_nrfd = false;
+ m_atn = false;
+ m_ren = false;
+ update_state(m_t_state, talker_state::TIDS);
+ update_state(m_tp_state, talker_primary_state::TPIS);
+ update_state(m_tsp_state, talker_serial_poll_state::SPIS);
+ update_state(m_l_state, listener_state::LIDS);
+ update_state(m_rl_state, remote_local_state::LOCS);
+ update_state(m_pp_state, parallel_poll_state::PPIS);
+ update_state(m_dc_state, device_clear_state::DCIS);
+ update_state(m_dt_state, device_trigger_state::DTIS);
+ update_state(m_sh_state, source_handshake_state::SIDS);
+ update_state(m_ah_state, acceptor_handshake_state::AIDS);
+}
+
+void i8291a_device::device_start()
+{
+ m_int_write_func.resolve_safe();
+ m_dreq_write_func.resolve_safe();
+ m_dav_write_func.resolve_safe();
+ m_nrfd_write_func.resolve_safe();
+ m_ndac_write_func.resolve_safe();
+ m_eoi_write_func.resolve_safe();
+ m_srq_write_func.resolve_safe();
+ m_dio_read_func.resolve_safe(0xff);
+ m_dio_write_func.resolve_safe();
+
+ save_item(NAME(m_din));
+ save_item(NAME(m_dout));
+ save_item(NAME(m_ints1));
+ save_item(NAME(m_ints2));
+ save_item(NAME(m_ie1));
+ save_item(NAME(m_ie2));
+ save_item(NAME(m_address0));
+ save_item(NAME(m_address1));
+ save_item(NAME(m_eos));
+ save_item(NAME(m_spoll_mode));
+ save_item(NAME(m_address_mode));
+ save_item(NAME(m_address_status));
+ save_item(NAME(m_cpt));
+ save_item(NAME(m_auxa));
+ save_item(NAME(m_auxb));
+ save_item(NAME(m_atn));
+ save_item(NAME(m_ren));
+ save_item(NAME(m_nrfd));
+ save_item(NAME(m_ndac));
+ save_item(NAME(m_dav));
+ save_item(NAME(m_srq));
+ save_item(NAME(m_ifc));
+ save_item(NAME(m_eoi));
+ save_item(NAME(m_dio));
+ save_item(NAME(m_nrfd_out));
+ save_item(NAME(m_ndac_out));
+ save_item(NAME(m_dav_out));
+ save_item(NAME(m_srq_out));
+ save_item(NAME(m_eoi_out));
+ save_item(NAME(m_pon));
+ save_item(NAME(m_rdy));
+ save_item(NAME(m_lpe));
+ save_item(NAME(m_ist));
+ save_item(NAME(m_rtl));
+ save_item(NAME(m_apt_flag));
+ save_item(NAME(m_cpt_flag));
+ save_item(NAME(m_din_flag));
+ save_item(NAME(m_nba));
+ save_item(NAME(m_pp_sense));
+ save_item(NAME(m_pp_line));
+ save_item(NAME(m_send_eoi));
+ save_item(NAME(m_intr_out));
+ save_item(NAME(m_dreq_out));
+ save_item(NAME(m_sh_state));
+ save_item(NAME(m_ah_state));
+ save_item(NAME(m_t_state));
+ save_item(NAME(m_tp_state));
+ save_item(NAME(m_tsp_state));
+ save_item(NAME(m_l_state));
+ save_item(NAME(m_lp_state));
+ save_item(NAME(m_rl_state));
+ save_item(NAME(m_sp_state));
+ save_item(NAME(m_pp_state));
+ save_item(NAME(m_dc_state));
+ save_item(NAME(m_dt_state));
+}
+
+READ8_MEMBER(i8291a_device::din_r)
+{
+ LOGMASKED(LOG_REG, "%s: %02X\n", __FUNCTION__, m_din);
+ if (!machine().side_effects_disabled()) {
+ m_din_flag = false;
+ m_ints1 &= ~REG_INTS1_BI;
+ update_int();
+ run_fsm();
+ }
+ return m_din;
+}
+
+void i8291a_device::update_int()
+{
+ bool dreq = ((m_ie2 & REG_IE2_DMAO) && (m_ints1 & REG_INTS1_BO)) |
+ ((m_ie2 & REG_IE2_DMAI) && (m_ints1 & REG_INTS1_BI));
+
+ if (m_dreq_out != dreq) {
+ LOGMASKED(LOG_INT, "%s: dreq %s\n", __FUNCTION__, dreq ? "true" : "false");
+ m_dreq_write_func(dreq);
+ m_dreq_out = dreq;
+ }
+
+ bool intr = false;
+
+ if (m_ints1 & m_ie1)
+ intr = true;
+
+ if ((m_ints2 & m_ie2) & 0x0f)
+ intr = true;
+
+ if (intr) {
+ m_ints2 |= REG_INTS2_INT;
+ m_address0 |= REG_ADDRESS0_INT;
+ } else {
+ m_ints2 &= ~REG_INTS2_INT;
+ m_address0 &= ~REG_ADDRESS0_INT;
+ }
+
+ if (m_intr_out != intr) {
+ LOGMASKED(LOG_INT, "%s: intr %s\n", __FUNCTION__, intr ? "true" : "false");
+ m_int_write_func(intr);
+ m_intr_out = intr;
+ }
+}
+
+READ8_MEMBER(i8291a_device::ints1_r)
+{
+ uint8_t ret = m_ints1;
+
+ if (!machine().side_effects_disabled()) {
+ LOGMASKED(LOG_REG, "%s: %02X\n", __FUNCTION__, ret);
+ m_ints1 = 0;
+ update_int();
+ }
+ return ret;
+}
+
+READ8_MEMBER(i8291a_device::ints2_r)
+{
+ uint8_t ret = m_ints2;
+
+ if (!machine().side_effects_disabled()) {
+ LOGMASKED(LOG_REG, "%s: %02X\n", __FUNCTION__, ret);
+ m_ints2 = 0;
+ update_int();
+ }
+ return ret;
+}
+
+READ8_MEMBER(i8291a_device::spoll_stat_r)
+{
+ LOGMASKED(LOG_REG, "%s\n", __FUNCTION__);
+ return 0;
+}
+
+READ8_MEMBER(i8291a_device::addr_stat_r)
+{
+ LOGMASKED(LOG_REG, "%s = %02X\n", __FUNCTION__, m_address_status);
+ return m_address_status;
+}
+
+READ8_MEMBER(i8291a_device::cpt_r)
+{
+ LOGMASKED(LOG_REG, "%s\n", __FUNCTION__);
+ return m_cpt;
+}
+
+READ8_MEMBER(i8291a_device::addr0_r)
+{
+ //LOGMASKED(LOG_REG, "%s = %02X\n", __FUNCTION__, m_address0);
+ return m_address0;
+}
+
+READ8_MEMBER(i8291a_device::addr1_r)
+{
+ LOGMASKED(LOG_REG, "%s = %02X\n", __FUNCTION__, m_address1);
+ return m_address1;
+}
+
+WRITE8_MEMBER(i8291a_device::dout_w)
+{
+ LOGMASKED(LOG_REG, "%s: %02X\n", __FUNCTION__, data);
+ if (m_nba)
+ return;
+ m_dout = data;
+ m_nba = true;
+ run_fsm();
+}
+
+WRITE8_MEMBER(i8291a_device::ie1_w)
+{
+ LOGMASKED(LOG_REG, "%s: %02X\n", __FUNCTION__, data);
+ m_ie1 = data;
+ run_fsm();
+}
+
+WRITE8_MEMBER(i8291a_device::ie2_w)
+{
+ LOGMASKED(LOG_REG, "%s: %02X\n", __FUNCTION__, data);
+ m_ie2 = data;
+ run_fsm();
+}
+
+WRITE8_MEMBER(i8291a_device::spoll_mode_w)
+{
+ LOGMASKED(LOG_REG, "%s: %02X\n", __FUNCTION__, data);
+ m_spoll_mode = data;
+ run_fsm();
+}
+
+WRITE8_MEMBER(i8291a_device::addr_mode_w)
+{
+ LOGMASKED(LOG_REG, "%s: %02X\n", __FUNCTION__, data);
+ m_address_mode = data & 3;
+ run_fsm();
+}
+
+WRITE8_MEMBER(i8291a_device::aux_mode_w)
+{
+ LOGMASKED(LOG_REG, "%s: %02X\n", __FUNCTION__, data);
+ switch (data >> 5) {
+ case 0:
+ switch (data) {
+ case AUXCMD_IMMEDIATE_EXEC_PON:
+ LOGMASKED(LOG_REG, "AUXCMD_IMMEDIATE_EXEC_PON\n");
+ m_pon = 0;
+ m_rdy = 1;
+ break;
+
+ case AUXCMD_CLEAR_PP:
+ LOGMASKED(LOG_REG, "AUXCMD_CLEAR_PP\n");
+ m_ist = false;
+ break;
+
+ case AUXCMD_CHIP_RESET:
+ LOGMASKED(LOG_REG, "AUXCMD_CHIP_RESET\n");
+ device_reset();
+ break;
+
+ case AUXCMD_FINISH_HANDSHAKE:
+ LOGMASKED(LOG_REG, "AUXCMD_FINISH_HANDSHAKE\n");
+ break;
+
+ case AUXCMD_TRIGGER:
+ LOGMASKED(LOG_REG, "AUXCMD_TRIGGER\n");
+ update_state(m_dt_state, device_trigger_state::DTAS);
+ break;
+
+ case AUXCMD_CLEAR_RTL:
+ LOGMASKED(LOG_REG, "AUXCMD_CLEAR_RTL\n");
+ m_rtl = false;
+ break;
+
+ case AUXCMD_SET_RTL:
+ LOGMASKED(LOG_REG, "AUXCMD_SET_RTL\n");
+ m_rtl = true;
+ break;
+
+ case AUXCMD_SET_PP:
+ LOGMASKED(LOG_REG, "AUXCMD_SET_PP\n");
+ m_ist = true;
+ break;
+
+ case AUXCMD_SEND_EOI:
+ LOGMASKED(LOG_REG, "AUXCMD_SEND_EOI\n");
+ m_send_eoi = true;
+ break;
+
+ case AUXCMD_NON_VALID_SA:
+ LOGMASKED(LOG_REG, "AUXCMD_NON_VALID_SA\n");
+ m_apt_flag = false;
+ break;
+
+ case AUXCMD_VALID_SA:
+ LOGMASKED(LOG_REG, "AUXCMD_VALID_SA: APT %d\n", m_apt_flag);
+ if (m_tp_state == talker_primary_state::TPAS)
+ update_state(m_t_state, talker_state::TADS);
+
+ if (m_lp_state == listener_primary_state::LPAS) {
+ update_state(m_l_state, listener_state::LADS);
+ if ((m_address_mode & 3) != 1 && m_lp_state == listener_primary_state::LPAS) {
+ if (m_rl_state == remote_local_state::LOCS && !m_rtl)
+ update_state(m_rl_state, remote_local_state::REMS);
+ if (m_rl_state == remote_local_state::LWLS)
+ update_state(m_rl_state, remote_local_state::RWLS);
+ }
+ }
+
+ m_cpt_flag = false;
+ m_apt_flag = false;
+ break;
+
+ case AUXCMD_PON:
+ LOGMASKED(LOG_REG, "AUXCMD_PON\n");
+ device_reset();
+ break;
+ }
+ case 1:
+ /* preset internal clock counter */
+ break;
+ case 4:
+ LOGMASKED(LOG_REG, "AUXA = %02X\n", data & 0x1f);
+ /* AUXA write */
+ m_auxa = data;
+ break;
+ case 5:
+ LOGMASKED(LOG_REG, "AUXB = %02X\n", data & 0x1f);
+ m_auxb = data;
+ break;
+ case 3:
+ LOGMASKED(LOG_REG, "PPOLL %s (line %d)\n", (data & 0x10) ? "disable" : "enable", data & 7);
+ m_lpe = !!!(data & 0x10);
+ m_pp_sense = data & 0x08;
+ m_pp_line = data & 7;
+ break;
+ default:
+ break;
+
+ }
+ run_fsm();
+}
+
+WRITE8_MEMBER(i8291a_device::addr01_w)
+{
+ LOGMASKED(LOG_REG, "%s: %02X\n", __FUNCTION__, data);
+ if (data & REG_ADDRESS01_ARS)
+ m_address1 = data & ~REG_ADDRESS01_ARS;
+ else
+ m_address0 = data & ~REG_ADDRESS01_ARS;
+ run_fsm();
+}
+
+WRITE8_MEMBER(i8291a_device::eos_w)
+{
+ LOGMASKED(LOG_REG, "%s: %02X\n", __FUNCTION__, data);
+ m_eos = data;
+ run_fsm();
+}
+
+WRITE_LINE_MEMBER(i8291a_device::nrfd_w)
+{
+ m_nrfd = !state;
+ run_fsm();
+}
+
+WRITE_LINE_MEMBER(i8291a_device::ndac_w)
+{
+ m_ndac = !state;
+ run_fsm();
+}
+
+WRITE_LINE_MEMBER(i8291a_device::dav_w)
+{
+ m_dav = !state;
+ run_fsm();
+}
+
+WRITE_LINE_MEMBER(i8291a_device::eoi_w)
+{
+ m_eoi = !state;
+ run_fsm();
+}
+
+WRITE_LINE_MEMBER(i8291a_device::srq_w)
+{
+ m_srq = !state;
+ run_fsm();
+}
+
+WRITE_LINE_MEMBER(i8291a_device::ifc_w)
+{
+ m_ifc = !state;
+ run_fsm();
+}
+
+WRITE_LINE_MEMBER(i8291a_device::atn_w)
+{
+ m_atn = !state;
+ run_fsm();
+}
+
+WRITE_LINE_MEMBER(i8291a_device::ren_w)
+{
+ m_ren = !state;
+ run_fsm();
+}
+
+void i8291a_device::set_dav(bool state)
+{
+ if (m_dav_out == state) {
+ m_dav_out = !state;
+ m_dav_write_func(m_dav_out);
+ }
+}
+
+void i8291a_device::set_nrfd(bool state)
+{
+ if (m_nrfd_out == state) {
+ m_nrfd_out = !state;
+ m_nrfd_write_func(m_nrfd_out);
+ }
+}
+
+void i8291a_device::set_ndac(bool state)
+{
+ if (m_ndac_out == state) {
+ m_ndac_out = !state;
+ m_ndac_write_func(m_ndac_out);
+ }
+}
+
+void i8291a_device::set_eoi(bool state)
+{
+ if (m_eoi_out == state) {
+ m_eoi_out = !state;
+ m_eoi_write_func(m_eoi_out);
+ }
+}
+
+void i8291a_device::set_srq(bool state)
+{
+ if (m_srq_out == state) {
+ m_srq_out = !state;
+ m_srq_write_func(m_srq_out);
+ }
+}
+
+void i8291a_device::run_sh_fsm()
+{
+
+ if (m_pon || m_atn || !(m_t_state == talker_state::TACS || m_t_state == talker_state::SPAS)) {
+ update_state(m_sh_state, source_handshake_state::SIDS);
+ }
+
+ switch (m_sh_state) {
+ case source_handshake_state::SIDS:
+ m_dio_write_func(0xff);
+ set_eoi(false);
+ m_nba = false;
+ if (m_t_state == talker_state::TACS || m_t_state == talker_state::SPAS) {
+ update_state(m_sh_state, source_handshake_state::SGNS);
+ m_ints1 |= REG_INTS1_BO;
+ }
+ break;
+
+ case source_handshake_state::SGNS:
+ set_dav(false);
+
+ if (m_nba) {
+ update_state(m_sh_state, source_handshake_state::SDYS);
+ m_ints1 &= ~REG_INTS1_BO;
+ }
+ break;
+
+ case source_handshake_state::SDYS:
+ if (!m_nrfd)
+ update_state(m_sh_state, source_handshake_state::STRS);
+ break;
+
+ case source_handshake_state::STRS:
+ m_nba = false;
+ m_dio_write_func(~m_dout);
+ set_eoi(m_send_eoi);
+
+ set_dav(true);
+ if (!m_ndac) {
+ m_send_eoi = false;
+ m_ints1 |= REG_INTS1_BO;
+ update_state(m_sh_state, source_handshake_state::SGNS);
+ }
+ break;
+ }
+}
+
+void i8291a_device::handle_command()
+{
+ if (m_din <= 0x1f) {
+ switch (m_din) {
+ case IFCMD_DCL:
+ LOGMASKED(LOG_CMD, "DCL\n");
+ update_state(m_dc_state, device_clear_state::DCAS);
+ break;
+ case IFCMD_GTL:
+ LOGMASKED(LOG_CMD, "GTL\n");
+ if (m_l_state == listener_state::LADS)
+ update_state(m_rl_state, remote_local_state::LWLS);
+ if (m_rl_state == remote_local_state::REMS &&
+ m_l_state == listener_state::LADS && m_rtl)
+ update_state(m_rl_state, remote_local_state::LOCS);
+ break;
+ case IFCMD_SDC:
+ LOGMASKED(LOG_CMD, "SDC\n");
+ if (m_l_state == listener_state::LADS)
+ update_state(m_dc_state, device_clear_state::DCAS);
+ break;
+ case IFCMD_GET:
+ LOGMASKED(LOG_CMD, "GET\n");
+ break;
+ case IFCMD_LLO:
+ LOGMASKED(LOG_CMD, "LLO\n");
+ if (m_rl_state == remote_local_state::LOCS)
+ update_state(m_rl_state, remote_local_state::LWLS);
+ if (m_rl_state == remote_local_state::REMS)
+ update_state(m_rl_state, remote_local_state::RWLS);
+ break;
+ case IFCMD_SPE:
+ LOGMASKED(LOG_CMD, "SPE\n");
+ update_state(m_tsp_state, talker_serial_poll_state::SPMS);
+ break;
+ case IFCMD_SPD:
+ LOGMASKED(LOG_CMD, "SPD\n");
+ update_state(m_tsp_state, talker_serial_poll_state::SPIS);
+ break;
+ case 0:
+ break;
+ default:
+ LOG("unhandled message: %02X\n", m_din);
+ if (m_auxb & REG_AUXB_CPT_ENABLE) {
+ m_cpt_flag = m_din;
+ m_ints1 |= REG_INTS1_CPT;
+ }
+ break;
+ }
+ } else if (m_din >= 0x20 && m_din <= 0x3f) {
+ bool addr_matched = false;
+ LOGMASKED(LOG_CMD, "MLA%d - mode %d, my addr0 %s%s%02x addr1 %s%s%02x\n", m_din & 0x1f,
+ m_address_mode & 3,
+ (m_address0 & REG_ADDRESS_DT) ? "DT " : "",
+ (m_address0 & REG_ADDRESS_DL) ? "DL " : "",
+ m_address0 & 0x1f,
+ (m_address1 & REG_ADDRESS_DT) ? "DT " : "",
+ (m_address1 & REG_ADDRESS_DL) ? "DL " : "",
+ m_address1 & 0x1f);
+
+ if ((m_din & 0x1f) == (m_address0 & 0x1f) && !(m_address0 & REG_ADDRESS_DL)) {
+ LOGMASKED(LOG_CMD, "Address 0 matched (mode %02X)\n", m_address_mode);
+ m_address_status &= ~REG_ADDRESS_STATUS_MJMN;
+ addr_matched = true;
+ }
+
+ if ((m_address_mode & 3) != 2 && (m_din & 0x1f) == (m_address1 & 0x1f) && !(m_address1 & REG_ADDRESS_DL)) {
+ LOGMASKED(LOG_CMD, "Address 1 matched (mode %02X)\n", m_address_mode);
+ m_address_status |= REG_ADDRESS_STATUS_MJMN;
+ addr_matched = true;
+ }
+
+ if (addr_matched) {
+ update_state(m_lp_state, listener_primary_state::LPAS);
+ if (addr_matched && (m_address_mode & 3) == 1 && m_l_state == listener_state::LIDS)
+ update_state(m_l_state, listener_state::LADS);
+ } else {
+ update_state(m_lp_state, listener_primary_state::LPIS);
+ update_state(m_l_state, listener_state::LIDS);
+ m_address_status &= ~(REG_ADDRESS_STATUS_MJMN);
+ }
+
+ if (addr_matched && (m_address_mode & 3) == 1 && m_rl_state == remote_local_state::LWLS)
+ update_state(m_rl_state, remote_local_state::RWLS);
+ } else if (m_din >= 0x40 && m_din <= 0x5f) {
+ bool addr_matched = false;
+
+ LOGMASKED(LOG_CMD, "MTA%d\n", m_din & 0x1f);
+
+ if ((m_din & 0x1f) == (m_address0 & 0x1f) && !(m_address0 & REG_ADDRESS_DT)) {
+ LOGMASKED(LOG_STATE, "Address 0 matched (mode %02X)\n", m_address_mode);
+ m_address_status &= ~REG_ADDRESS_STATUS_MJMN;
+ addr_matched = true;
+ }
+
+ if ((m_address_mode & 3) != 2 && (m_din & 0x1f) == (m_address1 & 0x1f) && !(m_address1 & REG_ADDRESS_DT)) {
+ LOGMASKED(LOG_STATE, "Address 1 matched (mode %02X)\n", m_address_mode);
+ m_address_status |= REG_ADDRESS_STATUS_MJMN;
+ addr_matched = true;
+ }
+
+ if (addr_matched) {
+ update_state(m_tp_state, talker_primary_state::TPAS);
+ if ((m_address_mode & 3) == 1 && m_t_state == talker_state::TIDS)
+ update_state(m_t_state, talker_state::TADS);
+ } else {
+ update_state(m_tp_state, talker_primary_state::TPIS);
+ update_state(m_t_state, talker_state::TIDS);
+ }
+
+ } else if (m_din >= 0x60 && m_din <= 0x7f) {
+ LOGMASKED(LOG_CMD, "MSA%d\n", m_din & 0x1f);
+ if ((m_address_mode & 3) == 2 && m_t_state == talker_state::TIDS)
+ update_state(m_t_state, talker_state::TADS);
+
+ if ((m_address_mode & 3) != 1 && m_rl_state == remote_local_state::LWLS)
+ update_state(m_rl_state, remote_local_state::RWLS);
+
+ if ((m_address_mode & 3) == 3) {
+ /* In address mode 3, MSA is passed to host for verification */
+ m_ints1 |= REG_INTS1_APT;
+ m_cpt = m_din;
+ m_apt_flag = true;
+ }
+ }
+}
+
+void i8291a_device::run_ah_fsm()
+{
+ bool f2 = m_atn || m_l_state == listener_state::LACS || m_l_state == listener_state::LADS;
+
+ if ((m_pon || !f2) && m_ah_state != acceptor_handshake_state::AIDS) {
+ LOGMASKED(LOG_STATE, "reset AH: pon %d f2 %d\n", m_pon, f2);
+ update_state(m_ah_state, acceptor_handshake_state::AIDS);
+ set_nrfd(false);
+ set_ndac(false);
+ return;
+ }
+
+ switch (m_ah_state) {
+ case acceptor_handshake_state::AIDS:
+ if (f2 && !m_pon)
+ update_state(m_ah_state, acceptor_handshake_state::ANRS);
+ break;
+ case acceptor_handshake_state::ANRS:
+ set_nrfd(true);
+ set_ndac(true);
+ m_cpt_flag = false;
+ m_apt_flag = false;
+ //LOG("m_rdy: %d m_cpt_flag: %d m_apt_flag: %d, m_din_flag %d\n", m_rdy, m_cpt_flag, m_apt_flag, m_din_flag);
+ if (m_atn || m_rdy)
+ update_state(m_ah_state, acceptor_handshake_state::ACRS);
+ break;
+
+ case acceptor_handshake_state::ACRS:
+ set_nrfd(false);
+ if (m_dav)
+ update_state(m_ah_state, acceptor_handshake_state::ADYS);
+ break;
+ case acceptor_handshake_state::ADYS:
+ if (!m_dav) {
+ update_state(m_ah_state, acceptor_handshake_state::ACRS);
+ } else {
+ update_state(m_ah_state, acceptor_handshake_state::ACDS);
+ }
+ break;
+ case acceptor_handshake_state::ACDS:
+
+ if (!m_rdy) {
+ update_state(m_ah_state, acceptor_handshake_state::AWNS);
+ break;
+ }
+ m_din = ~m_dio_read_func();
+ set_nrfd(true);
+
+ if (m_atn) {
+ /* Received command */
+ m_din &= ~0x80; // TODO: parity
+ handle_command();
+ if (!m_cpt_flag && !m_apt_flag)
+ update_state(m_ah_state, acceptor_handshake_state::AWNS);
+ } else {
+ /* Received data */
+ m_din_flag = true;
+ m_ints1 |= REG_INTS1_BI;
+ if (m_eoi)
+ m_ints1 |= REG_INTS1_END;
+ // TODO: END on EOS
+ }
+ break;
+ case acceptor_handshake_state::AWNS:
+ set_ndac(false);
+ // TODO: T3 delay, rdy holdoff
+
+ if (!m_dav)
+ update_state(m_ah_state, acceptor_handshake_state::ANRS);
+ break;
+ }
+}
+
+void i8291a_device::run_t_fsm()
+{
+ switch (m_t_state) {
+ case talker_state::TIDS:
+ m_address_status &= ~REG_ADDRESS_STATUS_TA;
+ break;
+
+ case talker_state::TADS:
+ m_address_status |= REG_ADDRESS_STATUS_TA;
+ if (!m_atn) {
+ if (m_tsp_state == talker_serial_poll_state::SPMS)
+ update_state(m_t_state, talker_state::SPAS);
+ else
+ update_state(m_t_state, talker_state::TACS);
+ }
+
+ if (m_tp_state == talker_primary_state::TPIS)
+ update_state(m_t_state, talker_state::TIDS);
+ break;
+ // TODO: F4 function
+ case talker_state::TACS:
+ m_address_status |= REG_ADDRESS_STATUS_TA;
+ if (m_atn)
+ update_state(m_t_state, talker_state::TADS); // TODO: T2 delay
+ break;
+
+ case talker_state::SPAS:
+ if (m_atn)
+ update_state(m_t_state, talker_state::TADS); // TODO: T2 delay
+ break;
+ }
+}
+
+void i8291a_device::run_tp_fsm()
+{
+ switch (m_tp_state) {
+ case talker_primary_state::TPIS:
+ m_address_status &= ~REG_ADDRESS_STATUS_TPAS;
+ break;
+ case talker_primary_state::TPAS:
+ m_address_status |= REG_ADDRESS_STATUS_TPAS;
+ break;
+ }
+}
+
+void i8291a_device::run_tsp_fsm()
+{
+ if (m_pon || m_ifc)
+ update_state(m_tsp_state, talker_serial_poll_state::SPIS);
+
+ switch (m_tsp_state) {
+ case talker_serial_poll_state::SPIS:
+ break;
+ case talker_serial_poll_state::SPMS:
+ break;
+ }
+}
+
+void i8291a_device::run_l_fsm()
+{
+ switch (m_l_state) {
+ case listener_state::LIDS:
+ m_address_status &= ~REG_ADDRESS_STATUS_LA;
+ break;
+ case listener_state::LADS:
+ m_address_status |= REG_ADDRESS_STATUS_LA;
+ if (m_lp_state == listener_primary_state::LPIS)
+ update_state(m_l_state, listener_state::LIDS);
+ break;
+ case listener_state::LACS:
+ break;
+ }
+}
+
+void i8291a_device::run_dc_fsm()
+{
+ switch (m_dc_state) {
+ case device_clear_state::DCIS:
+ break;
+ case device_clear_state::DCAS:
+ m_ints1 |= REG_INTS1_DEC;
+ update_state(m_dc_state, device_clear_state::DCIS);
+ break;
+ }
+}
+
+void i8291a_device::run_dt_fsm()
+{
+ switch (m_dt_state) {
+ case device_trigger_state::DTIS:
+ break;
+ case device_trigger_state::DTAS:
+ m_trig_write_func(true);
+ m_trig_write_func(false);
+ update_state(m_dt_state, device_trigger_state::DTIS);
+ break;
+ }
+}
+
+void i8291a_device::run_pp_fsm()
+{
+ if (m_pon)
+ update_state(m_pp_state, parallel_poll_state::PPIS);
+
+ switch (m_pp_state) {
+ case parallel_poll_state::PPIS:
+ if (m_lpe && !m_pon)
+ update_state(m_pp_state, parallel_poll_state::PPSS);
+ break;
+
+ case parallel_poll_state::PPSS:
+ if (!m_lpe) {
+ update_state(m_pp_state, parallel_poll_state::PPIS);
+ break;
+ }
+
+ if (m_atn && m_eoi)
+ update_state(m_pp_state, parallel_poll_state::PPAS);
+ break;
+
+ case parallel_poll_state::PPAS:
+ if (!m_atn || !m_eoi) {
+ m_dio_write_func(0xff);
+ update_state(m_pp_state, parallel_poll_state::PPSS);
+ break;
+ }
+ if (m_ist == m_pp_sense)
+ m_dio_write_func(~(1 << m_pp_line));
+ else
+ m_dio_write_func(0xff);
+ break;
+ }
+}
+
+void i8291a_device::run_sp_fsm()
+{
+ switch (m_sp_state) {
+ case serial_poll_state::APRS:
+ break;
+ case serial_poll_state::NPRS:
+ break;
+ case serial_poll_state::SRQS:
+ break;
+ }
+}
+
+void i8291a_device::run_rl_fsm()
+{
+ if (m_pon || !m_ren)
+ update_state(m_rl_state, remote_local_state::LOCS);
+
+ switch (m_rl_state) {
+ case remote_local_state::LOCS:
+ break;
+ case remote_local_state::LWLS:
+ break;
+ case remote_local_state::REMS:
+ break;
+ case remote_local_state::RWLS:
+ break;
+ }
+}
+
+void i8291a_device::run_lp_fsm()
+{
+ switch (m_lp_state) {
+ case listener_primary_state::LPIS:
+ m_address_status &= ~REG_ADDRESS_STATUS_LPAS;
+ break;
+ case listener_primary_state::LPAS:
+ m_address_status |= REG_ADDRESS_STATUS_LPAS;
+ break;
+ }
+}
+
+void i8291a_device::run_fsm()
+{
+ if (m_ignore_ext_signals)
+ return;
+ m_ignore_ext_signals = true;
+ do {
+ m_state_changed = false;
+
+ auto m_l_state_old = m_l_state;
+ auto m_t_state_old = m_t_state;
+ auto m_rl_state_old = m_rl_state;
+ run_sh_fsm();
+ run_ah_fsm();
+ run_t_fsm();
+ run_tp_fsm();
+ run_tsp_fsm();
+ run_l_fsm();
+ run_lp_fsm();
+ run_dc_fsm();
+ run_dt_fsm();
+ run_sp_fsm();
+ run_pp_fsm();
+ run_rl_fsm();
+
+ if ((m_t_state_old == talker_state::TIDS && m_t_state == talker_state::TADS) ||
+ (m_t_state_old == talker_state::TADS && m_t_state == talker_state::TIDS) ||
+ (m_l_state_old == listener_state::LIDS && m_l_state == listener_state::LADS) ||
+ (m_l_state_old == listener_state::LADS && m_l_state == listener_state::LIDS))
+ m_ints2 |= REG_INTS2_ADSC;
+
+ if ((m_rl_state_old == remote_local_state::LOCS && m_rl_state == remote_local_state::REMS) ||
+ (m_rl_state_old == remote_local_state::REMS && m_rl_state == remote_local_state::LOCS) ||
+ (m_rl_state_old == remote_local_state::LWLS && m_rl_state == remote_local_state::RWLS) ||
+ (m_rl_state_old == remote_local_state::RWLS && m_rl_state == remote_local_state::LWLS))
+ m_ints2 |= REG_INTS2_REMC;
+
+ if ((m_rl_state_old == remote_local_state::LOCS && m_rl_state == remote_local_state::LWLS) ||
+ (m_rl_state_old == remote_local_state::REMS && m_rl_state == remote_local_state::RWLS) ||
+ (m_rl_state_old == remote_local_state::LWLS && m_rl_state == remote_local_state::LOCS) ||
+ (m_rl_state_old == remote_local_state::RWLS && m_rl_state == remote_local_state::REMS))
+ m_ints2 |= REG_INTS2_REMC;
+
+ m_rdy = !m_apt_flag && !m_cpt_flag && !m_din_flag;
+ update_int();
+ } while (m_state_changed);
+ m_ignore_ext_signals = false;
+}
+
+
+const char *i8291a_device::get_state_name(device_clear_state state)
+{
+ switch (state) {
+ case device_clear_state::DCIS:
+ return "DICS";
+ case device_clear_state::DCAS:
+ return "DCAS";
+ }
+ return "Unknown";
+}
+
+const char *i8291a_device::get_state_name(device_trigger_state state)
+{
+ switch (state) {
+ case device_trigger_state::DTIS:
+ return "DTIS";
+ case device_trigger_state::DTAS:
+ return "DTAS";
+ }
+ return "Unknown";
+}
+
+
+const char *i8291a_device::get_state_name(parallel_poll_state state)
+{
+ switch (state){
+ case parallel_poll_state::PPIS:
+ return "PPIS";
+ case parallel_poll_state::PPSS:
+ return "PPSS";
+ case parallel_poll_state::PPAS:
+ return "PPAS";
+ }
+ return "Unknown";
+}
+
+
+const char *i8291a_device::get_state_name(serial_poll_state state)
+{
+ switch (state) {
+ case serial_poll_state::APRS:
+ return "APRS";
+ case serial_poll_state::NPRS:
+ return "NPRS";
+ case serial_poll_state::SRQS:
+ return "SRQS";
+ }
+ return "Unknown";
+}
+
+const char *i8291a_device::get_state_name(remote_local_state state)
+{
+ switch (state) {
+ case remote_local_state::LOCS:
+ return "LOCS";
+ case remote_local_state::LWLS:
+ return "LWLS";
+ case remote_local_state::REMS:
+ return "REMS";
+ case remote_local_state::RWLS:
+ return "RWLS";
+ }
+ return "Unknown";
+}
+
+const char *i8291a_device::get_state_name(listener_primary_state state)
+{
+ switch (state) {
+ case listener_primary_state::LPIS:
+ return "LPIS";
+ case listener_primary_state::LPAS:
+ return "LPAS";
+ }
+ return "Unknown";
+}
+
+const char *i8291a_device::get_state_name(source_handshake_state state)
+{
+ switch (state) {
+ case source_handshake_state::SIDS:
+ return "SIDS";
+ case source_handshake_state::SGNS:
+ return "SGNS";
+ case source_handshake_state::SDYS:
+ return "SDYS";
+ case source_handshake_state::STRS:
+ return "STRS";
+ }
+ return "Unknown";
+}
+
+
+const char *i8291a_device::get_state_name(acceptor_handshake_state state)
+{
+ switch (state) {
+ case acceptor_handshake_state::AIDS:
+ return "AIDS";
+ case acceptor_handshake_state::ANRS:
+ return "ANRS";
+ case acceptor_handshake_state::ACRS:
+ return "ACRS";
+ case acceptor_handshake_state::ADYS:
+ return "ADYS";
+ case acceptor_handshake_state::ACDS:
+ return "ACDS";
+ case acceptor_handshake_state::AWNS:
+ return "AWNS";
+ }
+ return "Unknown";
+}
+
+const char *i8291a_device::get_state_name(talker_state state)
+{
+ switch (state) {
+ case talker_state::TIDS:
+ return "TIDS";
+ case talker_state::TADS:
+ return "TADS";
+ case talker_state::TACS:
+ return "TACS";
+ case talker_state::SPAS:
+ return "SPAS";
+ }
+ return "Unknown";
+}
+
+const char *i8291a_device::get_state_name(talker_primary_state state)
+{
+ switch (state) {
+ case talker_primary_state::TPIS:
+ return "TPIS";
+ case talker_primary_state::TPAS:
+ return "TPAS";
+ }
+ return "Unknown";
+}
+
+
+const char *i8291a_device::get_state_name(listener_state state)
+{
+ switch (state) {
+ case listener_state::LIDS:
+ return "LIDS";
+ case listener_state::LADS:
+ return "LADS";
+ case listener_state::LACS:
+ return "LACS";
+ }
+ return "Unknown";
+}
+
+const char *i8291a_device::get_state_name(talker_serial_poll_state state)
+{
+ switch (state) {
+ case talker_serial_poll_state::SPIS:
+ return "SPIS";
+ case talker_serial_poll_state::SPMS:
+ return "SPMS";
+ }
+ return "Unknown";
+}
+
+void i8291a_device::map(address_map &map)
+{
+ map(0x00, 0x00).rw(FUNC(i8291a_device::din_r), FUNC(i8291a_device::dout_w));
+ map(0x01, 0x01).rw(FUNC(i8291a_device::ints1_r), FUNC(i8291a_device::ie1_w));
+ map(0x02, 0x02).rw(FUNC(i8291a_device::ints2_r), FUNC(i8291a_device::ie2_w));
+ map(0x03, 0x03).rw(FUNC(i8291a_device::spoll_stat_r), FUNC(i8291a_device::spoll_mode_w));
+ map(0x04, 0x04).rw(FUNC(i8291a_device::addr_stat_r), FUNC(i8291a_device::addr_mode_w));
+ map(0x05, 0x05).rw(FUNC(i8291a_device::cpt_r), FUNC(i8291a_device::aux_mode_w));
+ map(0x06, 0x06).rw(FUNC(i8291a_device::addr0_r), FUNC(i8291a_device::addr01_w));
+ map(0x07, 0x07).rw(FUNC(i8291a_device::addr1_r), FUNC(i8291a_device::eos_w));
+
+}
+
+template<typename T> void i8291a_device::update_state(T &name, T state)
+{
+ if (name != state) {
+ m_state_changed = true;
+ LOGMASKED(LOG_STATE, "%s: %s -> %s\n", __FUNCTION__,
+ get_state_name(name),
+ get_state_name(state));
+ name = state;
+ }
+}
diff --git a/src/devices/machine/i8291a.h b/src/devices/machine/i8291a.h
new file mode 100644
index 00000000000..d607ff8f051
--- /dev/null
+++ b/src/devices/machine/i8291a.h
@@ -0,0 +1,408 @@
+// license:BSD-3-Clause
+// copyright-holders: Sven Schnelle
+/*********************************************************************
+
+ i8291a.h
+
+ I8291A GPIB controller
+
+*********************************************************************/
+
+#ifndef MAME_MACHINE_I8291A_H
+#define MAME_MACHINE_I8291A_H
+
+
+#pragma once
+
+
+#define MCFG_I8291A_INT_WRITE_CB(_write) \
+ downcast<i8291a_device &>(*device).set_int_write_cb(DEVCB_##_write);
+
+#define MCFG_I8291A_DREQ_WRITE_CB(_write) \
+ downcast<i8291a_device &>(*device).set_dreq_write_cb(DEVCB_##_write);
+
+#define MCFG_I8291A_TRIG_WRITE_CB(_write) \
+ downcast<i8291a_device &>(*device).set_trig_write_cb(DEVCB_##_write);
+
+#define MCFG_I8291A_DIO_READ_CB(_read) \
+ downcast<i8291a_device &>(*device).set_dio_read_cb(DEVCB_##_read);
+
+#define MCFG_I8291A_DIO_WRITE_CB(_write) \
+ downcast<i8291a_device &>(*device).set_dio_write_cb(DEVCB_##_write);
+
+#define MCFG_I8291A_EOI_WRITE_CB(_write) \
+ downcast<i8291a_device &>(*device).set_eoi_write_cb(DEVCB_##_write);
+
+#define MCFG_I8291A_DAV_WRITE_CB(_write) \
+ downcast<i8291a_device &>(*device).set_dav_write_cb(DEVCB_##_write);
+
+#define MCFG_I8291A_NRFD_WRITE_CB(_write) \
+ downcast<i8291a_device &>(*device).set_nrfd_write_cb(DEVCB_##_write);
+
+#define MCFG_I8291A_NDAC_WRITE_CB(_write) \
+ downcast<i8291a_device &>(*device).set_ndac_write_cb(DEVCB_##_write);
+
+#define MCFG_I8291A_SRQ_WRITE_CB(_write) \
+ downcast<i8291a_device &>(*device).set_srq_write_cb(DEVCB_##_write);
+
+
+class i8291a_device : public device_t
+{
+public:
+ // construction/destruction
+ i8291a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ template <class Object> devcb_base& set_int_write_cb(Object &&cb)
+ { return m_int_write_func.set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base& set_dreq_write_cb(Object &&cb)
+ { return m_dreq_write_func.set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base& set_trig_write_cb(Object &&cb)
+ { return m_trig_write_func.set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base& set_eoi_write_cb(Object &&cb)
+ { return m_eoi_write_func.set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base& set_dav_write_cb(Object &&cb)
+ { return m_dav_write_func.set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base& set_nrfd_write_cb(Object &&cb)
+ { return m_nrfd_write_func.set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base& set_ndac_write_cb(Object &&cb)
+ { return m_ndac_write_func.set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base& set_srq_write_cb(Object &&cb)
+ { return m_srq_write_func.set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base& set_dio_write_cb(Object &&cb)
+ { return m_dio_write_func.set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base& set_dio_read_cb(Object &&cb)
+ { return m_dio_read_func.set_callback(std::forward<Object>(cb)); }
+
+ // Signal inputs
+ DECLARE_WRITE_LINE_MEMBER(reset_w);
+ DECLARE_WRITE_LINE_MEMBER(dack_w);
+
+ // GPIB port
+ DECLARE_WRITE_LINE_MEMBER(eoi_w);
+ DECLARE_WRITE_LINE_MEMBER(dav_w);
+ DECLARE_WRITE_LINE_MEMBER(nrfd_w);
+ DECLARE_WRITE_LINE_MEMBER(ndac_w);
+ DECLARE_WRITE_LINE_MEMBER(ifc_w);
+ DECLARE_WRITE_LINE_MEMBER(srq_w);
+ DECLARE_WRITE_LINE_MEMBER(atn_w);
+ DECLARE_WRITE_LINE_MEMBER(ren_w);
+ DECLARE_WRITE8_MEMBER(dio_w);
+
+ // register r/w functions
+
+ DECLARE_WRITE8_MEMBER(dout_w);
+ DECLARE_WRITE8_MEMBER(ie1_w);
+ DECLARE_WRITE8_MEMBER(ie2_w);
+ DECLARE_WRITE8_MEMBER(spoll_mode_w);
+ DECLARE_WRITE8_MEMBER(addr_mode_w);
+ DECLARE_WRITE8_MEMBER(aux_mode_w);
+ DECLARE_WRITE8_MEMBER(addr01_w);
+ DECLARE_WRITE8_MEMBER(eos_w);
+
+ DECLARE_READ8_MEMBER(din_r);
+ DECLARE_READ8_MEMBER(ints1_r);
+ DECLARE_READ8_MEMBER(ints2_r);
+ DECLARE_READ8_MEMBER(spoll_stat_r);
+ DECLARE_READ8_MEMBER(addr_stat_r);
+ DECLARE_READ8_MEMBER(cpt_r);
+ DECLARE_READ8_MEMBER(addr0_r);
+ DECLARE_READ8_MEMBER(addr1_r);
+ void map(address_map &map);
+
+private:
+
+ // signal output
+ devcb_write_line m_int_write_func;
+ devcb_write_line m_dreq_write_func;
+ devcb_write_line m_trig_write_func;
+ devcb_write_line m_eoi_write_func;
+ devcb_write_line m_dav_write_func;
+ devcb_write_line m_nrfd_write_func;
+ devcb_write_line m_ndac_write_func;
+ devcb_write_line m_srq_write_func;
+
+ devcb_write8 m_dio_write_func;
+ devcb_read8 m_dio_read_func;
+
+ void set_dav(bool state);
+ void set_nrfd(bool state);
+ void set_ndac(bool state);
+ void set_eoi(bool state);
+ void set_srq(bool state);
+
+
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ void update_int();
+ void handle_command();
+ void run_fsm();
+ void run_sh_fsm();
+ void run_ah_fsm();
+ void run_dt_fsm();
+ void run_dc_fsm();
+ void run_l_fsm();
+ void run_lp_fsm();
+ void run_t_fsm();
+ void run_tp_fsm();
+ void run_tsp_fsm();
+ void run_sp_fsm();
+ void run_pp_fsm();
+ void run_rl_fsm();
+
+ // registers
+
+ uint8_t m_din;
+ uint8_t m_dout;
+ uint8_t m_ints1;
+ uint8_t m_ints2;
+ uint8_t m_ie1;
+ uint8_t m_ie2;
+ uint8_t m_address0;
+ uint8_t m_address1;
+ uint8_t m_eos;
+ uint8_t m_spoll_mode;
+ uint8_t m_address_mode;
+ uint8_t m_address_status;
+ uint8_t m_cpt;
+
+ uint8_t m_auxa;
+ uint8_t m_auxb;
+
+ bool m_atn;
+ bool m_ren;
+ bool m_nrfd;
+ bool m_ndac;
+ bool m_dav;
+ bool m_srq;
+ bool m_ifc;
+ bool m_eoi;
+ uint8_t m_dio;
+
+ bool m_nrfd_out;
+ bool m_ndac_out;
+ bool m_dav_out;
+ bool m_srq_out;
+ bool m_eoi_out;
+
+ // internal signals
+
+ bool m_pon;
+ bool m_rdy;
+ bool m_lpe;
+ bool m_ist;
+ bool m_rtl;
+ bool m_apt_flag;
+ bool m_cpt_flag;
+ bool m_din_flag;
+ bool m_nba;
+
+ bool m_pp_sense;
+ uint8_t m_pp_line;
+
+ bool m_send_eoi;
+
+ static constexpr int REG_INTS1_BI = 1 << 0;
+ static constexpr int REG_INTS1_BO = 1 << 1;
+ static constexpr int REG_INTS1_ERR = 1 << 2;
+ static constexpr int REG_INTS1_DEC = 1 << 3;
+ static constexpr int REG_INTS1_END = 1 << 4;
+ static constexpr int REG_INTS1_GET = 1 << 5;
+ static constexpr int REG_INTS1_APT = 1 << 6;
+ static constexpr int REG_INTS1_CPT = 1 << 7;
+
+ static constexpr int REG_INTS2_ADSC = 1 << 0;
+ static constexpr int REG_INTS2_REMC = 1 << 1;
+ static constexpr int REG_INTS2_LLOC = 1 << 2;
+ static constexpr int REG_INTS2_SPC = 1 << 3;
+ static constexpr int REG_INTS2_REM = 1 << 4;
+ static constexpr int REG_INTS2_LLO = 1 << 5;
+ static constexpr int REG_INTS2_SPAS = 1 << 6;
+ static constexpr int REG_INTS2_INT = 1 << 7;
+
+ static constexpr int REG_IE2_DMAI = 1 << 4;
+ static constexpr int REG_IE2_DMAO = 1 << 5;
+
+ static constexpr int REG_ADDRESS01_ARS = 1 << 7;
+ static constexpr int REG_ADDRESS0_INT = 1 << 7;
+ static constexpr int REG_ADDRESS_DT = 1 << 6;
+ static constexpr int REG_ADDRESS_DL = 1 << 5;
+
+ static constexpr int REG_ADDRESS_STATUS_MJMN = 1 << 0;
+ static constexpr int REG_ADDRESS_STATUS_TA = 1 << 1;
+ static constexpr int REG_ADDRESS_STATUS_LA = 1 << 2;
+ static constexpr int REG_ADDRESS_STATUS_TPAS = 1 << 3;
+ static constexpr int REG_ADDRESS_STATUS_LPAS = 1 << 4;
+ static constexpr int REG_ADDRESS_STATUS_EOI = 1 << 5;
+ static constexpr int REG_ADDRESS_STATUS_LON = 1 << 6;
+ static constexpr int REG_ADDRESS_STATUS_TON = 1 << 7;
+
+ static constexpr int REG_AUXB_CPT_ENABLE = 1 << 0;
+ static constexpr int REG_AUXB_EOI_SPAS_ENABLE = 1 << 1;
+ static constexpr int REG_AUXB_HS_TRANSFER = 1 << 2;
+ static constexpr int REG_AUXB_INT_ACTIVE_LOW = 1 << 3;
+ static constexpr int REG_AUXB_RFD_HOLDOFF_GET_DEC = 1 << 4;
+
+ static constexpr int REG_AUXA_RFD_HOLDOFF_DATA = 1 << 0;
+ static constexpr int REG_AUXA_RFD_HOLDOFF_END = 1 << 1;
+ static constexpr int REG_AUXA_END_ON_EOS = 1 << 2;
+ static constexpr int REG_AUXA_EOI_ON_EOS = 1 << 3;
+ static constexpr int REG_AUXA_EOS_8BIT = 1 << 4;
+
+ // AUX CMDs
+ static constexpr int AUXCMD_IMMEDIATE_EXEC_PON = 0;
+ static constexpr int AUXCMD_CLEAR_PP = 1;
+ static constexpr int AUXCMD_CHIP_RESET = 2;
+ static constexpr int AUXCMD_FINISH_HANDSHAKE = 3;
+ static constexpr int AUXCMD_TRIGGER = 4;
+ static constexpr int AUXCMD_CLEAR_RTL = 5;
+ static constexpr int AUXCMD_SEND_EOI = 6;
+ static constexpr int AUXCMD_NON_VALID_SA = 7;
+ static constexpr int AUXCMD_PON = 8;
+ static constexpr int AUXCMD_SET_PP = 9;
+ static constexpr int AUXCMD_SET_RTL = 13;
+ static constexpr int AUXCMD_VALID_SA = 15;
+
+ // Interface commands
+ // TODO: stolen from tms9914, move to common header file. PHI also defines this
+
+ static constexpr uint8_t IFCMD_MASK = 0x7f; // Mask of valid bits in if. commands
+ static constexpr uint8_t IFCMD_ACG_MASK = 0x70; // Mask of ACG commands
+ static constexpr uint8_t IFCMD_ACG_VALUE = 0x00; // Value of ACG commands
+ static constexpr uint8_t IFCMD_UCG_MASK = 0x70; // Mask of UCG commands
+ static constexpr uint8_t IFCMD_UCG_VALUE = 0x10; // Value of UCG commands
+ static constexpr uint8_t IFCMD_GROUP_MASK = 0x60; // Mask of group id
+ static constexpr uint8_t IFCMD_LAG_VALUE = 0x20; // Value of LAG commands
+ static constexpr uint8_t IFCMD_TAG_VALUE = 0x40; // Value of TAG commands
+ static constexpr uint8_t IFCMD_SCG_VALUE = 0x60; // Value of SCG commands
+ static constexpr uint8_t IFCMD_GTL = 0x01; // Go to local
+ static constexpr uint8_t IFCMD_SDC = 0x04; // Selected device clear
+ static constexpr uint8_t IFCMD_GET = 0x08; // Group execute trigger
+ static constexpr uint8_t IFCMD_TCT = 0x09; // Take control
+ static constexpr uint8_t IFCMD_LLO = 0x11; // Local lock-out
+ static constexpr uint8_t IFCMD_DCL = 0x14; // Device clear
+ static constexpr uint8_t IFCMD_SPE = 0x18; // Serial poll enable
+ static constexpr uint8_t IFCMD_SPD = 0x19; // Serial poll disable
+ static constexpr uint8_t IFCMD_UNL = 0x3f; // Unlisten
+ static constexpr uint8_t IFCMD_UNT = 0x5f; // Untalk
+
+ enum class source_handshake_state : uint8_t {
+ SIDS,
+ SGNS,
+ SDYS,
+ STRS
+ };
+
+ enum class acceptor_handshake_state : uint8_t {
+ AIDS,
+ ANRS,
+ ACRS,
+ AWNS,
+ ADYS,
+ ACDS
+ };
+
+ enum class talker_state : uint8_t {
+ TIDS,
+ TADS,
+ SPAS,
+ TACS
+ };
+
+ enum class talker_primary_state : uint8_t {
+ TPIS,
+ TPAS
+ };
+
+ enum class listener_primary_state : uint8_t {
+ LPIS,
+ LPAS
+ };
+
+ enum class talker_serial_poll_state : uint8_t {
+ SPIS,
+ SPMS
+ };
+
+ enum class serial_poll_state : uint8_t {
+ NPRS,
+ SRQS,
+ APRS
+ };
+
+ enum class listener_state : uint8_t {
+ LIDS,
+ LADS,
+ LACS
+ };
+
+ enum class remote_local_state : uint8_t {
+ LOCS,
+ REMS,
+ RWLS,
+ LWLS
+ };
+
+ enum class parallel_poll_state : uint8_t {
+ PPIS,
+ PPSS,
+ PPAS
+ };
+
+ enum class device_clear_state : uint8_t {
+ DCIS,
+ DCAS
+ };
+
+ enum class device_trigger_state : uint8_t {
+ DTIS,
+ DTAS
+ };
+
+ static const char *get_state_name(acceptor_handshake_state state);
+ static const char *get_state_name(source_handshake_state state);
+ static const char *get_state_name(talker_state state);
+ static const char *get_state_name(talker_primary_state state);
+ static const char *get_state_name(talker_serial_poll_state state);
+ static const char *get_state_name(listener_state state);
+ static const char *get_state_name(listener_primary_state state);
+ static const char *get_state_name(device_clear_state state);
+ static const char *get_state_name(device_trigger_state state);
+ static const char *get_state_name(parallel_poll_state state);
+ static const char *get_state_name(serial_poll_state state);
+ static const char *get_state_name(remote_local_state state);
+
+ template<typename T> void update_state(T &name, T state);
+
+ source_handshake_state m_sh_state;
+ acceptor_handshake_state m_ah_state;
+ talker_state m_t_state;
+ talker_primary_state m_tp_state;
+ talker_serial_poll_state m_tsp_state;
+ listener_state m_l_state;
+ listener_primary_state m_lp_state;
+ remote_local_state m_rl_state;
+ serial_poll_state m_sp_state;
+ parallel_poll_state m_pp_state;
+ device_clear_state m_dc_state;
+ device_trigger_state m_dt_state;
+ bool m_state_changed;
+ bool m_ignore_ext_signals;
+ bool m_intr_out;
+ bool m_dreq_out;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(I8291A, i8291a_device)
+
+#endif // MAME_MACHINE_I8291A_H