From c7fd7ad2c881ca785ff56d8c2340a14117b6a920 Mon Sep 17 00:00:00 2001 From: fulivi Date: Thu, 26 Apr 2018 16:27:47 +0200 Subject: [PATCH] hp_ipc: added HPIB interface chip & remotizer device --- scripts/src/machine.lua | 12 + scripts/target/mame/mess.lua | 1 + src/devices/machine/tms9914.cpp | 1333 +++++++++++++++++++++++++++++++ src/devices/machine/tms9914.h | 295 +++++++ src/mame/drivers/hp_ipc.cpp | 29 +- 5 files changed, 1668 insertions(+), 2 deletions(-) create mode 100644 src/devices/machine/tms9914.cpp create mode 100644 src/devices/machine/tms9914.h diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index 91d5da4519a..6b0c191eebc 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -2706,6 +2706,18 @@ if (MACHINES["TMS9902"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/machine/phi.h,MACHINES["PHI"] = true +--------------------------------------------------- + +if (MACHINES["TMS9914"]~=null) then + files { + MAME_DIR .. "src/devices/machine/tms9914.cpp", + MAME_DIR .. "src/devices/machine/tms9914.h", + } +end + --------------------------------------------------- -- --@src/devices/machine/tube.h,MACHINES["TUBE"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 97463be6685..2e77530536a 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -565,6 +565,7 @@ MACHINES["TMS5501"] = true MACHINES["TMS6100"] = true MACHINES["TMS9901"] = true MACHINES["TMS9902"] = true +MACHINES["TMS9914"] = true MACHINES["TPI6525"] = true MACHINES["TTL7400"] = true MACHINES["TTL7404"] = true diff --git a/src/devices/machine/tms9914.cpp b/src/devices/machine/tms9914.cpp new file mode 100644 index 00000000000..052ed4e8ee4 --- /dev/null +++ b/src/devices/machine/tms9914.cpp @@ -0,0 +1,1333 @@ +// license:BSD-3-Clause +// copyright-holders:F. Ulivi +/********************************************************************* + + tms9914.cpp + + Texas Instruments TMS9914(A) GPIB Controller + + TODO: + - A few minor FSMs only used in non-controller devices (RL,SR,PP) + - A few interface commands + - A few auxiliary commands + + Main reference for this IC: + TI, jun 89, TMS9914A GPIB Controller - Data Manual + +**********************************************************************/ + +#include "emu.h" +#include "tms9914.h" + +// Debugging +#include "logmacro.h" +#define LOG_NOISY_MASK (LOG_GENERAL << 1) +#define LOG_NOISY(...) LOGMASKED(LOG_NOISY_MASK, __VA_ARGS__) +#define LOG_REG_MASK (LOG_NOISY_MASK << 1) +#define LOG_REG(...) LOGMASKED(LOG_REG_MASK, __VA_ARGS__) +#define LOG_INT_MASK (LOG_REG_MASK << 1) +#define LOG_INT(...) LOGMASKED(LOG_INT_MASK, __VA_ARGS__) +#undef VERBOSE +#define VERBOSE (LOG_GENERAL) + +// Bit manipulation +namespace { + template constexpr T BIT_MASK(unsigned n) + { + return (T)1U << n; + } + + template void BIT_CLR(T& w , unsigned n) + { + w &= ~BIT_MASK(n); + } + + template void BIT_SET(T& w , unsigned n) + { + w |= BIT_MASK(n); + } +} + +// Registers +enum { + REG_R_INT_STAT0 = 0, // R 0: Interrupt status 0 + REG_R_INT_STAT1 = 1, // R 1: Interrupt status 1 + REG_R_ADDR_STAT = 2, // R 2: Address status + REG_R_BUS_STAT = 3, // R 3: Bus status + REG_R_CMD_PT = 6, // R 6: Command pass-through + REG_R_DI = 7, // R 7: Data input + REG_W_INT_MASK0 = 0, // W 0: Interrupt mask 0 + REG_W_INT_MASK1 = 1, // W 1: Interrupt mask 1 + REG_W_AUX_CMD = 3, // W 3: Auxiliary command + REG_W_ADDRESS = 4, // W 4: Address + REG_W_SERIAL_P = 5, // W 5: Serial poll + REG_W_PARALLEL_P = 6, // W 6: Parallel poll + REG_W_DO = 7 // W 7: Data output +}; + +// Interrupt status/mask 0 +constexpr unsigned REG_INT0_MAC_BIT = 0; // My Address status Changed +constexpr unsigned REG_INT0_RLC_BIT = 1; // Remote/Local status Changed +constexpr unsigned REG_INT0_SPAS_BIT = 2; // Polled by serial poll +constexpr unsigned REG_INT0_END_BIT = 3; // EOI received +constexpr unsigned REG_INT0_BO_BIT = 4; // Byte Out interrupt +constexpr unsigned REG_INT0_BI_BIT = 5; // Byte In interrupt +constexpr unsigned REG_INT0_INT1_BIT = 6; // Interrupt(s) pending from INT1 register +constexpr unsigned REG_INT0_INT0_BIT = 7; // Interrupt(s) pending from INT0 register +constexpr uint8_t REG_INT0_INT_MASK = 0x3f; // Mask of actual interrupt bits + +// Interrupt status/mask 1 +constexpr unsigned REG_INT1_IFC_BIT = 0; // IFC received +constexpr unsigned REG_INT1_MA_BIT = 1; // My address received +constexpr unsigned REG_INT1_SRQ_BIT = 2; // SRQ asserted +constexpr unsigned REG_INT1_DCAS_BIT = 3; // DCAS state active +constexpr unsigned REG_INT1_APT_BIT = 4; // Address Pass-Through +constexpr unsigned REG_INT1_UNC_BIT = 5; // Unrecognized command +constexpr unsigned REG_INT1_ERR_BIT = 6; // Source handshake error +constexpr unsigned REG_INT1_GET_BIT = 7; // Group Execute Trigger + +// Address status register +constexpr unsigned REG_AS_ULPA_BIT = 0; // LSB of last recognized address +constexpr unsigned REG_AS_TADS_BIT = 1; // Addressed to talk +constexpr unsigned REG_AS_LADS_BIT = 2; // Addressed to listen +constexpr unsigned REG_AS_TPAS_BIT = 3; // TPAS state active +constexpr unsigned REG_AS_LPAS_BIT = 4; // LPAS state active +constexpr unsigned REG_AS_ATN_BIT = 5; // ATN asserted +constexpr unsigned REG_AS_LLO_BIT = 6; // Local lockout enabled +constexpr unsigned REG_AS_REM_BIT = 7; // Remote state enabled + +// Bus status register +constexpr unsigned REG_BS_REN_BIT = 0; +constexpr unsigned REG_BS_IFC_BIT = 1; +constexpr unsigned REG_BS_SRQ_BIT = 2; +constexpr unsigned REG_BS_EOI_BIT = 3; +constexpr unsigned REG_BS_NRFD_BIT = 4; +constexpr unsigned REG_BS_NDAC_BIT = 5; +constexpr unsigned REG_BS_DAV_BIT = 6; +constexpr unsigned REG_BS_ATN_BIT = 7; + +// Auxiliary command register +constexpr uint8_t REG_AUXCMD_CMD_MASK = 0x1f; // Mask of auxiliary command +constexpr unsigned REG_AUXCMD_CS_BIT = 7; // Clear/set bit + +// Auxiliary commands +enum { + AUXCMD_SWRST = 0x00, + AUXCMD_DACR = 0x01, + AUXCMD_RHDF = 0x02, + AUXCMD_HDFA = 0x03, + AUXCMD_HDFE = 0x04, + AUXCMD_NBAF = 0x05, + AUXCMD_FGET = 0x06, + AUXCMD_RTL = 0x07, + AUXCMD_FEOI = 0x08, + AUXCMD_LON = 0x09, + AUXCMD_TON = 0x0a, + AUXCMD_GTS = 0x0b, + AUXCMD_TCA = 0x0c, + AUXCMD_TCS = 0x0d, + AUXCMD_RPP = 0x0e, + AUXCMD_SIC = 0x0f, + AUXCMD_SRE = 0x10, + AUXCMD_RQC = 0x11, + AUXCMD_RLC = 0x12, + AUXCMD_DAI = 0x13, + AUXCMD_PTS = 0x14, + AUXCMD_STDL = 0x15, + AUXCMD_SHDW = 0x16, + AUXCMD_VSTDL = 0x17, + AUXCMD_RSV2 = 0x18 +}; + +// Address register +constexpr uint8_t REG_ADDR_ADDR_MASK = 0x1f; // Address mask +constexpr unsigned REG_ADDR_DAT_BIT = 5; // Disable talker +constexpr unsigned REG_ADDR_DAL_BIT = 6; // Disable listener +constexpr unsigned REG_ADDR_EDPA_BIT = 7; // Dual primary address mode + +// Serial poll register +constexpr uint8_t REG_SERIAL_P_MASK = 0xbf; // Serial status mask +constexpr unsigned REG_SERIAL_P_RSV1_BIT = 6; // Request service 1 + +// Interface commands +constexpr uint8_t IFCMD_MASK = 0x7f; // Mask of valid bits in if. commands +constexpr uint8_t IFCMD_ACG_MASK = 0x70; // Mask of ACG commands +constexpr uint8_t IFCMD_ACG_VALUE = 0x00; // Value of ACG commands +constexpr uint8_t IFCMD_UCG_MASK = 0x70; // Mask of UCG commands +constexpr uint8_t IFCMD_UCG_VALUE = 0x10; // Value of UCG commands +constexpr uint8_t IFCMD_GROUP_MASK = 0x60; // Mask of group id +constexpr uint8_t IFCMD_LAG_VALUE = 0x20; // Value of LAG commands +constexpr uint8_t IFCMD_TAG_VALUE = 0x40; // Value of TAG commands +constexpr uint8_t IFCMD_SCG_VALUE = 0x60; // Value of SCG commands +constexpr uint8_t IFCMD_GTL = 0x01; // Go to local +constexpr uint8_t IFCMD_SDC = 0x04; // Selected device clear +constexpr uint8_t IFCMD_GET = 0x08; // Group execute trigger +constexpr uint8_t IFCMD_TCT = 0x09; // Take control +constexpr uint8_t IFCMD_LLO = 0x11; // Local lock-out +constexpr uint8_t IFCMD_DCL = 0x14; // Device clear +constexpr uint8_t IFCMD_SPE = 0x18; // Serial poll enable +constexpr uint8_t IFCMD_SPD = 0x19; // Serial poll disable +constexpr uint8_t IFCMD_UNL = 0x3f; // Unlisten +constexpr uint8_t IFCMD_UNT = 0x5f; // Untalk + +// Device type definition +DEFINE_DEVICE_TYPE(TMS9914, tms9914_device, "tms9914", "TMS9914 GPIB Controller") + +// Constructors +tms9914_device::tms9914_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig , TMS9914 , tag , owner , clock), + m_dio_read_func(*this), + m_dio_write_func(*this), + m_signal_wr_fns{ + devcb_write_line(*this), + devcb_write_line(*this), + devcb_write_line(*this), + devcb_write_line(*this), + devcb_write_line(*this), + devcb_write_line(*this), + devcb_write_line(*this), + devcb_write_line(*this) }, + m_int_write_func(*this) +{ +} + +// Signal inputs +WRITE_LINE_MEMBER(tms9914_device::eoi_w) +{ + set_ext_signal(IEEE_488_EOI , state); +} + +WRITE_LINE_MEMBER(tms9914_device::dav_w) +{ + set_ext_signal(IEEE_488_DAV , state); +} + +WRITE_LINE_MEMBER(tms9914_device::nrfd_w) +{ + set_ext_signal(IEEE_488_NRFD , state); +} + +WRITE_LINE_MEMBER(tms9914_device::ndac_w) +{ + set_ext_signal(IEEE_488_NDAC , state); +} + +WRITE_LINE_MEMBER(tms9914_device::ifc_w) +{ + set_ext_signal(IEEE_488_IFC , state); +} + +WRITE_LINE_MEMBER(tms9914_device::srq_w) +{ + set_ext_signal(IEEE_488_SRQ , state); +} + +WRITE_LINE_MEMBER(tms9914_device::atn_w) +{ + set_ext_signal(IEEE_488_ATN , state); +} + +WRITE_LINE_MEMBER(tms9914_device::ren_w) +{ + set_ext_signal(IEEE_488_REN , state); +} + +// Register I/O +WRITE8_MEMBER(tms9914_device::reg8_w) +{ + LOG_REG("W %u=%02x\n" , offset , data); + + switch (offset) { + case REG_W_INT_MASK0: + m_reg_int0_mask = data & REG_INT0_INT_MASK; + update_int(); + break; + + case REG_W_INT_MASK1: + m_reg_int1_mask = data; + update_int(); + break; + + case REG_W_AUX_CMD: + do_aux_cmd(data & REG_AUXCMD_CMD_MASK , BIT(data , REG_AUXCMD_CS_BIT)); + break; + + case REG_W_ADDRESS: + { + uint8_t diff = m_reg_address ^ data; + m_reg_address = data; + if (BIT(diff , REG_ADDR_DAT_BIT) || BIT(diff , REG_ADDR_DAL_BIT)) { + update_fsm(); + } + } + break; + + case REG_W_SERIAL_P: + m_reg_serial_p = data; + // TODO: update FSM? + break; + + case REG_W_PARALLEL_P: + m_reg_2nd_parallel_p = data; + if (!m_pp_ppas) { + m_reg_parallel_p = data; + } + break; + + case REG_W_DO: + m_reg_do = data; + if (!m_swrst) { + BIT_CLR(m_reg_int0_status , REG_INT0_BO_BIT); + update_int(); + if (m_t_eoi_state == FSM_T_ENRS) { + m_t_eoi_state = FSM_T_ERAS; + } else if (m_t_eoi_state == FSM_T_ENAS) { + m_t_eoi_state = FSM_T_ENIS; + } + if (m_sh_shfs) { + m_sh_shfs = false; + update_fsm(); + } + } + break; + + default: + LOG("Write to unmapped reg %u\n" , offset); + break; + } +} + +READ8_MEMBER(tms9914_device::reg8_r) +{ + uint8_t res; + + switch (offset) { + case REG_R_INT_STAT0: + res = m_reg_int0_status; + m_reg_int0_status = 0; + update_int(); + break; + + case REG_R_INT_STAT1: + res = m_reg_int1_status; + m_reg_int1_status = 0; + update_int(); + break; + + case REG_R_ADDR_STAT: + res = 0; + if (m_reg_ulpa) { + BIT_SET(res , REG_AS_ULPA_BIT); + } + if (m_t_state != FSM_T_TIDS) { + BIT_SET(res , REG_AS_TADS_BIT); + } + if (m_l_state != FSM_L_LIDS) { + BIT_SET(res , REG_AS_LADS_BIT); + } + if (m_t_tpas) { + BIT_SET(res , REG_AS_TPAS_BIT); + } + if (m_l_lpas) { + BIT_SET(res , REG_AS_LPAS_BIT); + } + if (get_signal(IEEE_488_ATN)) { + BIT_SET(res , REG_AS_ATN_BIT); + } + if (m_rl_state == FSM_RL_RWLS || m_rl_state == FSM_RL_LWLS) { + BIT_SET(res , REG_AS_LLO_BIT); + } + if (m_rl_state == FSM_RL_REMS || m_rl_state == FSM_RL_RWLS) { + BIT_SET(res , REG_AS_REM_BIT); + } + break; + + case REG_R_BUS_STAT: + res = 0; + if (get_signal(IEEE_488_REN)) { + BIT_SET(res , REG_BS_REN_BIT); + } + if (get_ifcin()) { + BIT_SET(res , REG_BS_IFC_BIT); + } + if (get_signal(IEEE_488_SRQ)) { + BIT_SET(res , REG_BS_SRQ_BIT); + } + if (get_signal(IEEE_488_EOI)) { + BIT_SET(res , REG_BS_EOI_BIT); + } + if (get_signal(IEEE_488_NRFD)) { + BIT_SET(res , REG_BS_NRFD_BIT); + } + if (get_signal(IEEE_488_NDAC)) { + BIT_SET(res , REG_BS_NDAC_BIT); + } + if (get_signal(IEEE_488_DAV)) { + BIT_SET(res , REG_BS_DAV_BIT); + } + if (get_signal(IEEE_488_ATN)) { + BIT_SET(res , REG_BS_ATN_BIT); + } + break; + + case REG_R_CMD_PT: + res = get_dio(); + break; + + case REG_R_DI: + res = m_reg_di; + if (!m_hdfa && m_ah_anhs) { + m_ah_anhs = false; + update_fsm(); + } + // TODO: ACRS -> ANRS ? + break; + + default: + LOG("Read from unmapped reg %u\n" , offset); + res = 0; + break; + } + + LOG_REG("R %u=%02x\n" , offset , res); + return res; +} + +// device-level overrides +void tms9914_device::device_start() +{ + m_dio_read_func.resolve_safe(0xff); + m_dio_write_func.resolve_safe(); + for (auto& f : m_signal_wr_fns) { + f.resolve_safe(); + } + m_int_write_func.resolve_safe(); + + m_sh_dly_timer = timer_alloc(SH_DELAY_TMR_ID); + m_ah_dly_timer = timer_alloc(AH_DELAY_TMR_ID); + m_c_dly_timer = timer_alloc(C_DELAY_TMR_ID); +} + +void tms9914_device::device_reset() +{ + m_no_reflection = false; + m_ext_state_change = false; + m_swrst = true; + m_hdfa = false; + m_hdfe = false; + m_rpp = false; + m_sic = false; + m_sre = false; + m_dai = false; + m_pts = false; + m_stdl = false; + m_shdw = false; + m_vstdl = false; + + m_reg_serial_p = 0; + m_reg_parallel_p = 0; + m_reg_2nd_parallel_p = 0; + + do_swrst(); + update_fsm(); + update_int(); + update_ifc(); + update_ren(); +} + +void tms9914_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + LOG_NOISY("tmr %d\n" , id); + update_fsm(); +} + +uint8_t tms9914_device::get_dio() +{ + return ~m_dio_read_func(); +} + +void tms9914_device::set_dio(uint8_t data) +{ + if (data != m_dio) { + LOG_NOISY("DIO=%02x\n" , data); + m_dio = data; + m_dio_write_func(~data); + } +} + +bool tms9914_device::get_signal(ieee_488_signal_t signal) const +{ + return m_ext_signals[ signal ]; +} + +bool tms9914_device::get_ifcin() const +{ + return get_signal(IEEE_488_IFC) && !m_sic; +} + +void tms9914_device::set_ext_signal(ieee_488_signal_t signal , int state) +{ + state = !state; + if (m_ext_signals[ signal ] != state) { + m_ext_signals[ signal ] = state; + LOG_NOISY("EXT EOI %d DAV %d NRFD %d NDAC %d IFC %d SRQ %d ATN %d REN %d\n" , + m_ext_signals[ IEEE_488_EOI ] , + m_ext_signals[ IEEE_488_DAV ] , + m_ext_signals[ IEEE_488_NRFD ] , + m_ext_signals[ IEEE_488_NDAC ] , + m_ext_signals[ IEEE_488_IFC ] , + m_ext_signals[ IEEE_488_SRQ ] , + m_ext_signals[ IEEE_488_ATN ] , + m_ext_signals[ IEEE_488_REN ]); + update_fsm(); + } +} + +void tms9914_device::set_signal(ieee_488_signal_t signal , bool state) +{ + if (state != m_signals[ signal ]) { + m_signals[ signal ] = state; + LOG_NOISY("INT EOI %d DAV %d NRFD %d NDAC %d IFC %d SRQ %d ATN %d REN %d\n" , + m_signals[ IEEE_488_EOI ] , + m_signals[ IEEE_488_DAV ] , + m_signals[ IEEE_488_NRFD ] , + m_signals[ IEEE_488_NDAC ] , + m_signals[ IEEE_488_IFC ] , + m_signals[ IEEE_488_SRQ ] , + m_signals[ IEEE_488_ATN ] , + m_signals[ IEEE_488_REN ]); + m_signal_wr_fns[ signal ](!state); + } +} + +void tms9914_device::do_swrst() +{ + m_reg_int0_status = 0; + m_reg_int1_status = 0; + + m_ah_state = FSM_AH_AIDS; + m_ah_adhs = false; + m_ah_anhs = false; + m_ah_aehs = false; + m_sh_state = FSM_SH_SIDS; + m_sh_shfs = true; + m_sh_vsts = false; + m_t_state = FSM_T_TIDS; + m_t_tpas = false; + m_t_spms = false; + m_t_eoi_state = FSM_T_ENIS; + m_l_state = FSM_L_LIDS; + m_l_lpas = false; + m_sr_state = FSM_SR_NPRS; + m_rl_state = FSM_RL_LOCS; + m_pp_ppas = false; + m_c_state = FSM_C_CIDS; + + update_int(); +} + +bool tms9914_device::listener_reset() const +{ + return m_swrst || BIT(m_reg_address , REG_ADDR_DAL_BIT) || m_sic || get_ifcin(); +} + +bool tms9914_device::talker_reset() const +{ + return m_swrst || BIT(m_reg_address , REG_ADDR_DAT_BIT) || m_sic || get_ifcin(); +} + +bool tms9914_device::controller_reset() const +{ + return m_swrst || get_ifcin(); +} + +void tms9914_device::update_fsm() +{ + if (m_no_reflection) { + return; + } + + m_no_reflection = true; + + bool changed = true; + int prev_state; + // Loop until all changes settle + while (changed) { + LOG_NOISY("SH %d SHFS %d AH %d T %d TPAS %d L %d LPAS %d PP %d C %d\n" , + m_sh_state , m_sh_shfs , m_ah_state , m_t_state , m_t_tpas , + m_l_state , m_l_lpas , m_pp_ppas , m_c_state); + changed = m_ext_state_change; + m_ext_state_change = false; + + // SH FSM + prev_state = m_sh_state; + bool sh_reset = m_swrst || + (get_signal(IEEE_488_ATN) && m_c_state != FSM_C_CACS) || + (!get_signal(IEEE_488_ATN) && !(m_t_state == FSM_T_TACS || m_t_state == FSM_T_SPAS)); + + if (get_signal(IEEE_488_ATN) || !m_vstdl) { + m_sh_vsts = false; + } + if (sh_reset) { + m_sh_state = FSM_SH_SIDS; + m_sh_dly_timer->reset(); + } else { + switch (m_sh_state) { + case FSM_SH_SIDS: + if (m_t_state == FSM_T_TACS || + m_t_state == FSM_T_SPAS || + m_c_state == FSM_C_CACS) { + m_sh_state = FSM_SH_SGNS; + } + break; + + case FSM_SH_SGNS: + if (!m_sh_shfs || m_t_state == FSM_T_SPAS) { + m_sh_state = FSM_SH_SDYS; + unsigned clocks = m_sh_vsts ? 4 : (m_stdl ? 8 : 12); + m_sh_dly_timer->adjust(clocks_to_attotime(clocks)); + LOG_NOISY("SH DLY %u\n" , clocks); + } + break; + + case FSM_SH_SDYS: + if (!m_t_spms) { + if (m_t_eoi_state == FSM_T_ENRS) { + m_t_eoi_state = FSM_T_ENIS; + } else if (m_t_eoi_state == FSM_T_ERAS) { + m_t_eoi_state = FSM_T_ENAS; + } + } + if (!m_sh_dly_timer->enabled() && !get_signal(IEEE_488_NRFD)) { + if (get_signal(IEEE_488_NDAC)) { + m_sh_state = FSM_SH_STRS; + } else { + m_sh_state = FSM_SH_SERS; + set_int1_bit(REG_INT1_ERR_BIT); + } + } + break; + + case FSM_SH_SERS: + if (get_signal(IEEE_488_NDAC)) { + m_sh_state = FSM_SH_STRS; + } + break; + + case FSM_SH_STRS: + if (m_t_state != FSM_T_SPAS) { + m_sh_shfs = true; + } + if (!get_signal(IEEE_488_ATN) && m_vstdl) { + m_sh_vsts = true; + } + if (!get_signal(IEEE_488_NDAC)) { + LOG("%.6f TX %02x/%d\n" , machine().time().as_double() , m_dio , m_signals[ IEEE_488_EOI ]); + m_sh_state = FSM_SH_SGNS; + } + break; + + default: + LOG("Invalid SH state %d\n" , m_sh_state); + m_sh_state = FSM_SH_SIDS; + } + } + if (m_sh_state != prev_state) { + changed = true; + if (m_sh_state == FSM_SH_SGNS && m_sh_shfs && + m_t_state != FSM_T_SPAS) { + // BO interrupt is raised when SGNS state is entered + set_int0_bit(REG_INT0_BO_BIT); + } + } + // SH outputs + // EOI is controlled by SH & C FSMs + // DIO is controlled by SH & PP FSMs + bool eoi_signal = false; + uint8_t dio_byte = 0; + set_signal(IEEE_488_DAV , m_sh_state == FSM_SH_STRS); + if (m_sh_state == FSM_SH_SDYS || m_sh_state == FSM_SH_STRS) { + dio_byte = m_t_state == FSM_T_SPAS ? m_reg_serial_p : m_reg_do; + eoi_signal = m_t_eoi_state == FSM_T_ERAS || m_t_eoi_state == FSM_T_ENAS; + } + + // AH FSM + prev_state = m_ah_state; + bool ah_reset = m_swrst || + (get_signal(IEEE_488_ATN) && m_c_state != FSM_C_CIDS && m_c_state != FSM_C_CADS) || + (!get_signal(IEEE_488_ATN) && m_l_state != FSM_L_LADS && m_l_state != FSM_L_LACS); + if (ah_reset) { + m_ah_state = FSM_AH_AIDS; + m_ah_dly_timer->reset(); + } else { + switch (m_ah_state) { + case FSM_AH_AIDS: + m_ah_state = FSM_AH_ANRS; + break; + + case FSM_AH_ANRS: + // See also the reading of DI register & RHDF command + if (m_c_state != FSM_C_CWAS && + !get_signal(IEEE_488_DAV) && + (get_signal(IEEE_488_ATN) || + (!m_ah_anhs && !m_ah_aehs))) { + m_ah_state = FSM_AH_ACRS; + m_ah_dly_timer->adjust(clocks_to_attotime(1)); + } else if (get_signal(IEEE_488_DAV)) { + m_ah_state = FSM_AH_AWNS; + } + break; + + case FSM_AH_ACRS: + if (!get_signal(IEEE_488_ATN) && + (m_ah_anhs || m_ah_aehs)) { + m_ah_state = FSM_AH_ANRS; + m_ah_dly_timer->reset(); + } else if (!m_ah_dly_timer->enabled() && get_signal(IEEE_488_DAV)) { + m_ah_state = FSM_AH_ACDS1; + m_ah_dly_timer->adjust(clocks_to_attotime(get_signal(IEEE_488_ATN) ? 5 : 1)); + } + break; + + case FSM_AH_ACDS1: + if (!get_signal(IEEE_488_DAV)) { + m_ah_state = FSM_AH_ACRS; + m_ah_dly_timer->adjust(clocks_to_attotime(1)); + } else if (!m_ah_dly_timer->enabled()) { + m_ah_state = FSM_AH_ACDS2; + if (get_signal(IEEE_488_ATN)) { + // Got a command + uint8_t if_cmd = get_dio(); + if_cmd_received(if_cmd & IFCMD_MASK); + } else { + // Got a DAB + dab_received(get_dio() , get_signal(IEEE_488_EOI)); + } + } + break; + + case FSM_AH_ACDS2: + if (!m_ah_adhs || !get_signal(IEEE_488_ATN)) { + m_ah_state = FSM_AH_AWNS; + } else if (!get_signal(IEEE_488_DAV)) { + m_ah_state = FSM_AH_ANRS; + } + break; + + case FSM_AH_AWNS: + if (!get_signal(IEEE_488_DAV)) { + m_ah_state = FSM_AH_ANRS; + } + break; + + default: + LOG("Invalid AH state %d\n" , m_ah_state); + m_ah_state = FSM_AH_AIDS; + } + } + if (m_ah_state != prev_state) { + changed = true; + } + // AH outputs + set_signal(IEEE_488_NRFD , m_ah_state == FSM_AH_ANRS || m_ah_state == FSM_AH_ACDS1 || m_ah_state == FSM_AH_ACDS2 || m_ah_state == FSM_AH_AWNS); + set_signal(IEEE_488_NDAC , m_ah_state == FSM_AH_ANRS || m_ah_state == FSM_AH_ACRS || m_ah_state == FSM_AH_ACDS1 || m_ah_state == FSM_AH_ACDS2); + + // T FSM + prev_state = m_t_state; + if (talker_reset()) { + m_t_state = FSM_T_TIDS; + } else { + switch (m_t_state) { + case FSM_T_TIDS: + break; + + case FSM_T_TADS: + if (!get_signal(IEEE_488_ATN)) { + if (m_t_spms) { + m_t_state = FSM_T_SPAS; + } else { + m_t_state = FSM_T_TACS; + } + } + break; + + case FSM_T_TACS: + case FSM_T_SPAS: + if (get_signal(IEEE_488_ATN)) { + m_t_state = FSM_T_TADS; + } + break; + + default: + LOG("Invalid T state %d\n" , m_t_state); + m_t_state = FSM_T_TIDS; + } + } + if (m_t_state != prev_state) { + changed = true; + } + if (m_t_spms && (m_swrst || get_ifcin() || (m_c_state != FSM_C_CIDS && m_c_state != FSM_C_CADS))) { + m_t_spms = false; + changed = true; + } + // No direct T outputs + + // L FSM + prev_state = m_l_state; + if (listener_reset()) { + m_l_state = FSM_L_LIDS; + } else { + switch (m_l_state) { + case FSM_L_LIDS: + break; + + case FSM_L_LADS: + if (!get_signal(IEEE_488_ATN)) { + m_l_state = FSM_L_LACS; + } + break; + + case FSM_L_LACS: + if (get_signal(IEEE_488_ATN)) { + m_l_state = FSM_L_LADS; + } + break; + + default: + LOG("Invalid L state %d\n" , m_l_state); + m_l_state = FSM_L_LIDS; + } + } + if (m_l_state != prev_state) { + changed = true; + } + // No direct L outputs + + // TODO: SR, RL & PP FSMs + + // C outputs + prev_state = m_c_state; + if (controller_reset()) { + m_c_state = FSM_C_CIDS; + m_c_dly_timer->reset(); + } else { + switch (m_c_state) { + case FSM_C_CIDS: + // sic | rqc -> CADS + break; + + case FSM_C_CADS: + if (!get_signal(IEEE_488_ATN)) { + m_c_state = FSM_C_CACS; + } + break; + + case FSM_C_CACS: + if (m_rpp) { + m_c_state = FSM_C_CPWS; + } + // gts -> CSBS + break; + + case FSM_C_CSBS: + // tcs -> CWAS + // tca -> CSHS + break; + + case FSM_C_CWAS: + if (m_ah_state == FSM_AH_ANRS) { + m_c_state = FSM_C_CSHS; + m_c_dly_timer->adjust(clocks_to_attotime(8)); + } + break; + + case FSM_C_CSHS: + if (!m_c_dly_timer->enabled()) { + m_c_state = FSM_C_CSWS; + m_c_dly_timer->adjust(clocks_to_attotime(2)); + } + break; + + case FSM_C_CSWS: + if (!m_c_dly_timer->enabled()) { + m_c_state = FSM_C_CAWS; + m_c_dly_timer->adjust(clocks_to_attotime(8)); + } + break; + + case FSM_C_CAWS: + if (!m_c_dly_timer->enabled()) { + m_c_state = FSM_C_CACS; + } + break; + + case FSM_C_CPWS: + if (!m_rpp) { + m_c_state = FSM_C_CAWS; + m_c_dly_timer->adjust(clocks_to_attotime(8)); + } + break; + + default: + LOG("Invalid C state %d\n" , m_c_state); + m_c_state = FSM_C_CIDS; + } + } + if (m_c_state != prev_state) { + changed = true; + } + set_signal(IEEE_488_ATN , m_c_state == FSM_C_CACS || + m_c_state == FSM_C_CSWS || m_c_state == FSM_C_CAWS || + m_c_state == FSM_C_CPWS); + eoi_signal = eoi_signal || m_c_state == FSM_C_CPWS; + set_signal(IEEE_488_EOI , eoi_signal); + set_dio(dio_byte); + } + + m_no_reflection = false; +} + +bool tms9914_device::is_my_address(uint8_t addr) +{ + uint8_t diff = (addr ^ m_reg_address) & REG_ADDR_ADDR_MASK; + if (BIT(m_reg_address , REG_ADDR_EDPA_BIT)) { + // If dual-address mode is enabled, difference in LSB of address is ignored + BIT_CLR(diff , 0); + } + if (diff == 0) { + m_reg_ulpa = BIT(addr , 0); + } + return diff == 0; +} + +void tms9914_device::do_LAF() +{ + if (m_l_state == FSM_L_LIDS) { + m_l_state = FSM_L_LADS; + m_ext_state_change = true; + } + if (m_t_state == FSM_T_TADS) { + m_t_state = FSM_T_TIDS; + m_ext_state_change = true; + } +} + +void tms9914_device::do_TAF() +{ + if (m_t_state == FSM_T_TIDS) { + m_t_state = FSM_T_TADS; + m_ext_state_change = true; + } + if (m_l_state == FSM_L_LADS) { + m_l_state = FSM_L_LIDS; + m_ext_state_change = true; + } +} + +void tms9914_device::if_cmd_received(uint8_t if_cmd) +{ + LOG("%.6f RX cmd:%02x\n" , machine().time().as_double() , if_cmd); + + bool sahf = false; + + // Any PCG command that is not MLA nor MTA clears LPAS & TPAS + if ((if_cmd & IFCMD_GROUP_MASK) != IFCMD_SCG_VALUE) { + m_l_lpas = false; + m_t_tpas = false; + } + + switch (if_cmd) { + case IFCMD_GTL: + // TODO: + break; + + case IFCMD_SDC: + if (m_l_state == FSM_L_LADS) { + set_int1_bit(REG_INT1_DCAS_BIT); + sahf = BIT(m_reg_int1_mask , REG_INT1_DCAS_BIT); + } + break; + + case IFCMD_GET: + // TODO: + break; + + case IFCMD_TCT: + if (m_t_state == FSM_T_TADS) { + set_int1_bit(REG_INT1_UNC_BIT); + sahf = BIT(m_reg_int1_mask , REG_INT1_UNC_BIT); + } + break; + + case IFCMD_LLO: + // TODO: + break; + + case IFCMD_DCL: + set_int1_bit(REG_INT1_DCAS_BIT); + sahf = BIT(m_reg_int1_mask , REG_INT1_DCAS_BIT); + break; + + case IFCMD_SPE: + // TODO: + break; + + case IFCMD_SPD: + // TODO: + break; + + case IFCMD_UNL: + if (m_l_state != FSM_L_LIDS) { + m_l_state = FSM_L_LIDS; + set_int0_bit(REG_INT0_MAC_BIT); + } + break; + + case IFCMD_UNT: + if (m_t_state != FSM_T_TIDS) { + m_t_state = FSM_T_TIDS; + set_int0_bit(REG_INT0_MAC_BIT); + } + break; + + default: + if ((if_cmd & IFCMD_ACG_MASK) == IFCMD_ACG_VALUE) { + // ACG + if (m_l_state == FSM_L_LADS) { + set_int1_bit(REG_INT1_UNC_BIT); + sahf = BIT(m_reg_int1_mask , REG_INT1_UNC_BIT); + } + } else if ((if_cmd & IFCMD_UCG_MASK) == IFCMD_UCG_VALUE) { + // UCG + set_int1_bit(REG_INT1_UNC_BIT); + sahf = BIT(m_reg_int1_mask , REG_INT1_UNC_BIT); + } else if ((if_cmd & IFCMD_GROUP_MASK) == IFCMD_LAG_VALUE) { + // LAG + if (is_my_address(if_cmd)) { + // MLA + m_l_lpas = true; + if (!BIT(m_reg_int1_mask , REG_INT1_APT_BIT)) { + // Not using secondary addressing + if (!listener_reset()) { + if (m_l_state != FSM_L_LADS) { + set_int0_bit(REG_INT0_MAC_BIT); + } + do_LAF(); + } + if (!m_t_spms) { + set_int1_bit(REG_INT1_MA_BIT); + sahf = BIT(m_reg_int1_mask , REG_INT1_MA_BIT); + } + } + } + } else if ((if_cmd & IFCMD_GROUP_MASK) == IFCMD_TAG_VALUE) { + // TAG + if (is_my_address(if_cmd)) { + // MTA + m_t_tpas = true; + if (!BIT(m_reg_int1_mask , REG_INT1_APT_BIT)) { + // Not using secondary addressing + if (!talker_reset()) { + if (m_t_state != FSM_T_TADS) { + set_int0_bit(REG_INT0_MAC_BIT); + } + do_TAF(); + } + if (!m_t_spms) { + set_int1_bit(REG_INT1_MA_BIT); + sahf = BIT(m_reg_int1_mask , REG_INT1_MA_BIT); + } + } + } else { + // OTA + if (m_t_state != FSM_T_TIDS) { + set_int0_bit(REG_INT0_MAC_BIT); + } + m_t_state = FSM_T_TIDS; + } + } else { + // SCG + if (m_pts) { + set_int1_bit(REG_INT1_UNC_BIT); + sahf = BIT(m_reg_int1_mask , REG_INT1_UNC_BIT); + m_pts = false; + } else if (m_l_lpas || m_t_tpas) { + set_int1_bit(REG_INT1_APT_BIT); + sahf = BIT(m_reg_int1_mask , REG_INT1_APT_BIT); + } + } + break; + } + + if (sahf) { + m_ah_adhs = true; + } +} + +void tms9914_device::dab_received(uint8_t dab , bool eoi) +{ + LOG("%.6f RX DAB:%02x/%d\n" , machine().time().as_double() , dab , eoi); + if (!m_shdw) { + m_ah_anhs = true; + set_int0_bit(REG_INT0_BI_BIT); + if (eoi) { + set_int0_bit(REG_INT0_END_BIT); + } + } + if (m_hdfe && eoi) { + m_ah_aehs = true; + } + m_reg_di = dab; +} + +void tms9914_device::do_aux_cmd(unsigned cmd , bool set_bit) +{ + switch (cmd) { + case AUXCMD_SWRST: + if (set_bit && !m_swrst) { + do_swrst(); + } + if (m_swrst != set_bit) { + m_swrst = set_bit; + update_fsm(); + } + break; + + case AUXCMD_DACR: + if (m_ah_adhs) { + m_ah_adhs = false; + if (BIT(m_reg_int1_mask , REG_INT1_APT_BIT)) { + // Using secondary addressing + if (set_bit && !listener_reset() && m_l_lpas) { + do_LAF(); + } + if (!set_bit && m_t_state == FSM_T_TADS && m_t_tpas) { + m_t_state = FSM_T_TIDS; + m_ext_state_change = true; + } + if (set_bit && !talker_reset() && m_t_tpas) { + do_TAF(); + } + } + update_fsm(); + } + break; + + case AUXCMD_RHDF: + // TODO: ACRS -> ANRS + if (m_ah_anhs || m_ah_aehs) { + m_ah_anhs = false; + m_ah_aehs = false; + update_fsm(); + } + break; + + case AUXCMD_HDFA: + if (!m_swrst) { + m_hdfa = set_bit; + } + break; + + case AUXCMD_HDFE: + if (!m_swrst) { + m_hdfe = set_bit; + } + break; + + case AUXCMD_NBAF: + m_t_eoi_state = FSM_T_ENIS; + if (!m_sh_shfs) { + m_sh_shfs = true; + update_fsm(); + } + break; + + case AUXCMD_FGET: + LOG("Unimplemented FGET cmd\n"); + break; + + case AUXCMD_RTL: + LOG("Unimplemented RTL cmd\n"); + break; + + case AUXCMD_FEOI: + if (!m_swrst) { + if (m_t_eoi_state == FSM_T_ENIS) { + m_t_eoi_state = FSM_T_ENRS; + } else if (m_t_eoi_state == FSM_T_ENAS) { + m_t_eoi_state = FSM_T_ERAS; + } + } + break; + + case AUXCMD_LON: + if (set_bit) { + if (!listener_reset()) { + do_LAF(); + } + } else { + m_l_state = FSM_L_LIDS; + m_ext_state_change = true; + } + update_fsm(); + break; + + case AUXCMD_TON: + if (set_bit) { + if (!talker_reset()) { + do_TAF(); + } + } else { + m_t_state = FSM_T_TIDS; + m_ext_state_change = true; + } + update_fsm(); + break; + + case AUXCMD_GTS: + if (m_c_state == FSM_C_CACS && m_sh_state != FSM_SH_SDYS && m_sh_state != FSM_SH_STRS) { + m_c_state = FSM_C_CSBS; + m_ext_state_change = true; + // This ensures a BO interrupt is generated if TACS is active + m_sh_state = FSM_SH_SIDS; + update_fsm(); + } + break; + + case AUXCMD_TCA: + if (m_c_state == FSM_C_CSBS) { + m_c_state = FSM_C_CSHS; + m_ext_state_change = true; + m_c_dly_timer->adjust(clocks_to_attotime(8)); + update_fsm(); + } + break; + + case AUXCMD_TCS: + if (m_c_state == FSM_C_CSBS) { + m_c_state = FSM_C_CWAS; + m_ext_state_change = true; + update_fsm(); + } + break; + + case AUXCMD_RPP: + if (!m_swrst && m_rpp != set_bit) { + m_rpp = set_bit; + update_fsm(); + } + break; + + case AUXCMD_SIC: + if (m_sic != set_bit) { + m_sic = set_bit; + update_ifc(); + if (!controller_reset() && m_sic && m_c_state == FSM_C_CIDS) { + m_c_state = FSM_C_CADS; + m_ext_state_change = true; + } + update_fsm(); + } + break; + + case AUXCMD_SRE: + m_sre = set_bit; + update_ren(); + break; + + case AUXCMD_RQC: + if (!controller_reset() && m_c_state == FSM_C_CIDS) { + m_c_state = FSM_C_CADS; + m_ext_state_change = true; + update_fsm(); + } + break; + + case AUXCMD_RLC: + if (m_c_state != FSM_C_CIDS) { + m_c_state = FSM_C_CIDS; + m_ext_state_change = true; + update_fsm(); + } + break; + + case AUXCMD_DAI: + m_dai = set_bit; + update_int(); + break; + + case AUXCMD_PTS: + m_pts = true; + break; + + case AUXCMD_STDL: + LOG("Unimplemented STDL cmd\n"); + break; + + case AUXCMD_SHDW: + if (!m_swrst) { + m_shdw = set_bit; + if (m_shdw && m_ah_anhs) { + m_ah_anhs = false; + update_fsm(); + } + } + break; + + case AUXCMD_VSTDL: + LOG("Unimplemented VSTDL cmd\n"); + break; + + case AUXCMD_RSV2: + LOG("Unimplemented RSV2 cmd\n"); + break; + + default: + LOG("Unrecognized aux cmd %u\n" , cmd); + break; + } +} + +void tms9914_device::set_int0_bit(unsigned bit_no) +{ + BIT_SET(m_reg_int0_status , bit_no); + update_int(); +} + +void tms9914_device::set_int1_bit(unsigned bit_no) +{ + BIT_SET(m_reg_int1_status , bit_no); + update_int(); +} + +void tms9914_device::update_int() +{ + bool new_int_line = false; + m_reg_int0_status &= REG_INT0_INT_MASK; + if (m_reg_int0_status & m_reg_int0_mask) { + BIT_SET(m_reg_int0_status , REG_INT0_INT0_BIT); + new_int_line = true; + } + if (m_reg_int1_status & m_reg_int1_mask) { + BIT_SET(m_reg_int0_status , REG_INT0_INT1_BIT); + new_int_line = true; + } + if (m_dai) { + new_int_line = false; + } + if (new_int_line != m_int_line) { + LOG_INT("INT=%d\n" , new_int_line); + m_int_line = new_int_line; + m_int_write_func(m_int_line); + } +} + +void tms9914_device::update_ifc() +{ + set_signal(IEEE_488_IFC , m_sic); +} + +void tms9914_device::update_ren() +{ + set_signal(IEEE_488_REN , m_sre); +} diff --git a/src/devices/machine/tms9914.h b/src/devices/machine/tms9914.h new file mode 100644 index 00000000000..8b57c27694c --- /dev/null +++ b/src/devices/machine/tms9914.h @@ -0,0 +1,295 @@ +// license:BSD-3-Clause +// copyright-holders:F. Ulivi +/********************************************************************* + + tms9914.h + + Texas Instruments TMS9914(A) GPIB Controller + + _____ _____ + ACCRQ/ 1 |* \_/ | 40 Vcc + ACCGR/ 2 | | 39 TR + CE/ 3 | | 38 DIO1 + WE/ 4 | | 37 DIO2 + DBIN 5 | | 36 DIO3 + RS0 6 | | 35 DIO4 + RS1 7 | | 34 DIO5 + RS2 8 | | 33 DIO6 + INT/ 9 | | 32 DIO7 + D7 10 | TMS9914 | 31 DIO8 + D6 11 | TMS9914A | 30 CONT/ + D5 12 | | 29 SRQ + D4 13 | | 28 ATN + D3 14 | | 27 EOI + D2 15 | | 26 DAV + D1 16 | | 25 NRFD + D0 17 | | 24 NDAC + O/ 18 | | 23 IFC + RESET/ 19 | | 22 REN + Vss 20 |_____________| 21 TE + +**********************************************************************/ + +#ifndef MAME_MACHINE_TMS9914_H +#define MAME_MACHINE_TMS9914_H + +#pragma once + +// Set read and write callbacks to access DIO bus on IEEE-488 +#define MCFG_TMS9914_DIO_READWRITE_CB(_read , _write) \ + downcast(*device).set_dio_read_cb(DEVCB_##_read); \ + downcast(*device).set_dio_write_cb(DEVCB_##_write); + +// Set write callbacks to access uniline signals on IEEE-488 +#define MCFG_TMS9914_EOI_WRITE_CB(_write) \ + downcast(*device).set_488_signal_write_cb(tms9914_device::IEEE_488_EOI , DEVCB_##_write); + +#define MCFG_TMS9914_DAV_WRITE_CB(_write) \ + downcast(*device).set_488_signal_write_cb(tms9914_device::IEEE_488_DAV , DEVCB_##_write); + +#define MCFG_TMS9914_NRFD_WRITE_CB(_write) \ + downcast(*device).set_488_signal_write_cb(tms9914_device::IEEE_488_NRFD , DEVCB_##_write); + +#define MCFG_TMS9914_NDAC_WRITE_CB(_write) \ + downcast(*device).set_488_signal_write_cb(tms9914_device::IEEE_488_NDAC , DEVCB_##_write); + +#define MCFG_TMS9914_IFC_WRITE_CB(_write) \ + downcast(*device).set_488_signal_write_cb(tms9914_device::IEEE_488_IFC , DEVCB_##_write); + +#define MCFG_TMS9914_SRQ_WRITE_CB(_write) \ + downcast(*device).set_488_signal_write_cb(tms9914_device::IEEE_488_SRQ , DEVCB_##_write); + +#define MCFG_TMS9914_ATN_WRITE_CB(_write) \ + downcast(*device).set_488_signal_write_cb(tms9914_device::IEEE_488_ATN , DEVCB_##_write); + +#define MCFG_TMS9914_REN_WRITE_CB(_write) \ + downcast(*device).set_488_signal_write_cb(tms9914_device::IEEE_488_REN , DEVCB_##_write); + +// Set write callback for INT signal +#define MCFG_TMS9914_INT_WRITE_CB(_write) \ + downcast(*device).set_int_write_cb(DEVCB_##_write); + +class tms9914_device : public device_t +{ +public: + // construction/destruction + tms9914_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + // See ieee488.h + enum ieee_488_signal_t { + IEEE_488_EOI, + IEEE_488_DAV, + IEEE_488_NRFD, + IEEE_488_NDAC, + IEEE_488_IFC, + IEEE_488_SRQ, + IEEE_488_ATN, + IEEE_488_REN, + IEEE_488_SIGNAL_COUNT + }; + + template devcb_base& set_dio_read_cb(Object &&cb) + { return m_dio_read_func.set_callback(std::forward(cb)); } + + template devcb_base& set_dio_write_cb(Object &&cb) + { return m_dio_write_func.set_callback(std::forward(cb)); } + + template devcb_base& set_488_signal_write_cb(ieee_488_signal_t signal , Object &&cb) + { return m_signal_wr_fns[ signal ].set_callback(std::forward(cb)); } + + template devcb_base& set_int_write_cb(Object &&cb) + { return m_int_write_func.set_callback(std::forward(cb)); } + + 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(reg8_w); + DECLARE_READ8_MEMBER(reg8_r); + +private: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + + devcb_read8 m_dio_read_func; + devcb_write8 m_dio_write_func; + devcb_write_line m_signal_wr_fns[ IEEE_488_SIGNAL_COUNT ]; + devcb_write_line m_int_write_func; + bool m_int_line; + + uint8_t m_dio; + bool m_signals[ IEEE_488_SIGNAL_COUNT ]; + bool m_ext_signals[ IEEE_488_SIGNAL_COUNT ]; + bool m_no_reflection; + bool m_ext_state_change; + + // Registers + uint8_t m_reg_int0_status; + uint8_t m_reg_int0_mask; + uint8_t m_reg_int1_status; + uint8_t m_reg_int1_mask; + uint8_t m_reg_address; + uint8_t m_reg_serial_p; + uint8_t m_reg_parallel_p; + uint8_t m_reg_2nd_parallel_p; + uint8_t m_reg_di; + uint8_t m_reg_do; + bool m_reg_ulpa; + + // Auxiliary cmd states + bool m_swrst; + bool m_hdfa; + bool m_hdfe; + bool m_rpp; + bool m_sic; + bool m_sre; + bool m_dai; + bool m_pts; + bool m_stdl; + bool m_shdw; + bool m_vstdl; + + // AH (Acceptor Handshake) states + enum { + FSM_AH_AIDS, + FSM_AH_ANRS, + FSM_AH_ACRS, + FSM_AH_ACDS1, + FSM_AH_ACDS2, + FSM_AH_AWNS + }; + + int m_ah_state; + bool m_ah_adhs; + bool m_ah_anhs; + bool m_ah_aehs; + + // SH (Source Handshake) states + enum { + FSM_SH_SIDS, + FSM_SH_SGNS, + FSM_SH_SDYS, + FSM_SH_SERS, + FSM_SH_STRS + }; + + int m_sh_state; + bool m_sh_shfs; + bool m_sh_vsts; + + // T (Talker) states + enum { + FSM_T_TIDS, + FSM_T_TADS, + FSM_T_TACS, + FSM_T_SPAS + }; + + int m_t_state; + bool m_t_tpas; + bool m_t_spms; + + // Talker EOI generator states + enum { + FSM_T_ENIS, + FSM_T_ENRS, + FSM_T_ERAS, + FSM_T_ENAS + }; + + int m_t_eoi_state; + + // L (Listener) states + enum { + FSM_L_LIDS, + FSM_L_LADS, + FSM_L_LACS + }; + + int m_l_state; + bool m_l_lpas; + + // SR (Service request) states + enum { + FSM_SR_NPRS, + FSM_SR_SRQS, + FSM_SR_APRS1, + FSM_SR_APRS2 + }; + + int m_sr_state; + + // RL (Remote Local) states + enum { + FSM_RL_LOCS, + FSM_RL_REMS, + FSM_RL_RWLS, + FSM_RL_LWLS + }; + + int m_rl_state; + + // PP (Parallel poll) states + bool m_pp_ppas; + + // C (Controller) states + enum { + FSM_C_CIDS, + FSM_C_CADS, + FSM_C_CACS, + FSM_C_CSBS, + FSM_C_CWAS, + FSM_C_CSHS, + FSM_C_CSWS, + FSM_C_CAWS, + FSM_C_CPWS + }; + + int m_c_state; + + // Timers + enum { + SH_DELAY_TMR_ID, + AH_DELAY_TMR_ID, + C_DELAY_TMR_ID + }; + + emu_timer *m_sh_dly_timer; + emu_timer *m_ah_dly_timer; + emu_timer *m_c_dly_timer; + + uint8_t get_dio(); + void set_dio(uint8_t data); + bool get_signal(ieee_488_signal_t signal) const; + bool get_ifcin() const; + void set_ext_signal(ieee_488_signal_t signal , int state); + void set_signal(ieee_488_signal_t signal , bool state); + void do_swrst(); + bool listener_reset() const; + bool talker_reset() const; + bool controller_reset() const; + void update_fsm(); + bool is_my_address(uint8_t addr); + void do_LAF(); + void do_TAF(); + void if_cmd_received(uint8_t if_cmd); + void dab_received(uint8_t dab , bool eoi); + void do_aux_cmd(unsigned cmd , bool set_bit); + void set_int0_bit(unsigned bit_no); + void set_int1_bit(unsigned bit_no); + void update_int(); + void update_ifc(); + void update_ren(); +}; + +// device type definition +DECLARE_DEVICE_TYPE(TMS9914, tms9914_device) + +#endif // MAME_MACHINE_TMS9914_H diff --git a/src/mame/drivers/hp_ipc.cpp b/src/mame/drivers/hp_ipc.cpp index ea43edef19a..13e159798f3 100644 --- a/src/mame/drivers/hp_ipc.cpp +++ b/src/mame/drivers/hp_ipc.cpp @@ -371,6 +371,8 @@ Software to look for #include "machine/ram.h" #include "machine/wd_fdc.h" #include "video/hp1ll3.h" +#include "machine/tms9914.h" +#include "bus/ieee488/ieee488.h" #include "rendlay.h" @@ -496,7 +498,7 @@ void hp_ipc_state::hp_ipc_mem_inner_base(address_map &map) map(0x0610000, 0x0610007).rw(this, FUNC(hp_ipc_state::floppy_id_r), FUNC(hp_ipc_state::floppy_id_w)).umask16(0x00ff); map(0x0610008, 0x061000F).rw(m_fdc, FUNC(wd2797_device::read), FUNC(wd2797_device::write)).umask16(0x00ff); map(0x0620000, 0x062000F).rw("gpu", FUNC(hp1ll3_device::read), FUNC(hp1ll3_device::write)).umask16(0x00ff); - map(0x0630000, 0x063FFFF).noprw(); // AM_DEVREADWRITE8(TMS9914_TAG, tms9914_device, read, write, 0x00ff) + map(0x0630000, 0x063FFFF).mask(0xf).rw("hpib" , FUNC(tms9914_device::reg8_r) , FUNC(tms9914_device::reg8_w)).umask16(0x00ff); map(0x0640000, 0x064002F).rw("rtc", FUNC(mm58167_device::read), FUNC(mm58167_device::write)).umask16(0x00ff); map(0x0660000, 0x06600FF).rw("mlc", FUNC(hp_hil_mlc_device::read), FUNC(hp_hil_mlc_device::write)).umask16(0x00ff); // 'caravan', scrn/caravan.h map(0x0670000, 0x067FFFF).noprw(); // Speaker (NatSemi COP 452) @@ -614,7 +616,8 @@ READ8_MEMBER(hp_ipc_state::floppy_id_r) { uint8_t data = 0; - data = (m_fdc->intrq_r() << 6); + // TODO: fix sys controller switch + data = (m_fdc->intrq_r() << 6) | 0x80; if (m_floppy) { @@ -757,6 +760,28 @@ MACHINE_CONFIG_START(hp_ipc_state::hp_ipc_base) MCFG_HP_HIL_NMI_CALLBACK(WRITELINE(hp_ipc_state, irq_7)) MCFG_HP_HIL_SLOT_ADD("mlc", "hil1", hp_hil_devices, "hp_ipc_kbd") + MCFG_DEVICE_ADD("hpib" , TMS9914 , XTAL(4000000)) + MCFG_TMS9914_INT_WRITE_CB(WRITELINE(hp_ipc_state, irq_3)) + MCFG_TMS9914_DIO_READWRITE_CB(DEVREAD8(IEEE488_TAG , ieee488_device , dio_r) , DEVWRITE8(IEEE488_TAG , ieee488_device , dio_w)) + MCFG_TMS9914_EOI_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , eoi_w)) + MCFG_TMS9914_DAV_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , dav_w)) + MCFG_TMS9914_NRFD_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , nrfd_w)) + MCFG_TMS9914_NDAC_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , ndac_w)) + MCFG_TMS9914_IFC_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , ifc_w)) + MCFG_TMS9914_SRQ_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , srq_w)) + MCFG_TMS9914_ATN_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , atn_w)) + MCFG_TMS9914_REN_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , ren_w)) + MCFG_IEEE488_BUS_ADD() + MCFG_IEEE488_EOI_CALLBACK(DEVWRITELINE("hpib" , tms9914_device , eoi_w)) + MCFG_IEEE488_DAV_CALLBACK(DEVWRITELINE("hpib" , tms9914_device , dav_w)) + MCFG_IEEE488_NRFD_CALLBACK(DEVWRITELINE("hpib" , tms9914_device , nrfd_w)) + MCFG_IEEE488_NDAC_CALLBACK(DEVWRITELINE("hpib" , tms9914_device , ndac_w)) + MCFG_IEEE488_IFC_CALLBACK(DEVWRITELINE("hpib" , tms9914_device , ifc_w)) + MCFG_IEEE488_SRQ_CALLBACK(DEVWRITELINE("hpib" , tms9914_device , srq_w)) + MCFG_IEEE488_ATN_CALLBACK(DEVWRITELINE("hpib" , tms9914_device , atn_w)) + MCFG_IEEE488_REN_CALLBACK(DEVWRITELINE("hpib" , tms9914_device , ren_w)) + MCFG_IEEE488_SLOT_ADD("ieee_rem" , 0 , remote488_devices , nullptr) + MCFG_RAM_ADD(RAM_TAG) MCFG_RAM_DEFAULT_SIZE("512K") MCFG_RAM_EXTRA_OPTIONS("768K,1M,1576K,2M,3M,4M,5M,6M,7M,7680K")