diff options
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 |
commit | 22ba8d40ddb2b1e61d812bf59a38d9f9c805299f (patch) | |
tree | 9d7ae0cc863ec3a4d00f821f9df92f2cf3024676 /src/devices/machine | |
parent | d6a53357a56f1e2d1249b9e29e0ff117967b0a8b (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.cpp | 1160 | ||||
-rw-r--r-- | src/devices/machine/i8291a.h | 408 |
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 |