// 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 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; } }