summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/tms9914.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/tms9914.cpp')
-rw-r--r--src/devices/machine/tms9914.cpp265
1 files changed, 202 insertions, 63 deletions
diff --git a/src/devices/machine/tms9914.cpp b/src/devices/machine/tms9914.cpp
index eef06895493..2d77f3dd1bd 100644
--- a/src/devices/machine/tms9914.cpp
+++ b/src/devices/machine/tms9914.cpp
@@ -7,7 +7,6 @@
Texas Instruments TMS9914(A) GPIB Controller
TODO:
- - A few minor FSMs only used in non-controller devices (SR,PP)
- A few interface commands
- A few auxiliary commands
@@ -21,11 +20,13 @@
// Debugging
#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_NOISY(...) LOGMASKED(LOG_NOISY_MASK, __VA_ARGS__)
+#define LOG_REG(...) LOGMASKED(LOG_REG_MASK, __VA_ARGS__)
#define LOG_INT(...) LOGMASKED(LOG_INT_MASK, __VA_ARGS__)
+
//#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"
@@ -77,8 +78,8 @@ 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_SRQ_BIT = 1; // SRQ asserted
+constexpr unsigned REG_INT1_MA_BIT = 2; // My address received
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
@@ -173,69 +174,111 @@ constexpr uint8_t IFCMD_UNT = 0x5f; // Untalk
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),
- m_accrq_write_func(*this)
+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, 0xff),
+ m_dio_write_func(*this),
+ m_signal_wr_fns(*this),
+ m_int_write_func(*this),
+ m_accrq_write_func(*this),
+ m_int_line{false},
+ m_accrq_line{false},
+ m_dio{0},
+ m_signals{false},
+ m_ext_signals{false},
+ m_no_reflection{false},
+ m_ext_state_change{false},
+ m_reg_int0_status{0},
+ m_reg_int0_mask{0},
+ m_reg_int1_status{0},
+ m_reg_int1_mask{0},
+ m_reg_address{0},
+ m_reg_serial_p{0},
+ m_reg_2nd_serial_p{0},
+ m_reg_parallel_p{0},
+ m_reg_2nd_parallel_p{0},
+ m_reg_di{0},
+ m_reg_do{0},
+ m_reg_ulpa{false},
+ m_swrst{false},
+ m_hdfa{false},
+ m_hdfe{false},
+ m_rtl{false},
+ m_gts{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_rsvd2{false},
+ 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{false},
+ 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},
+ m_next_eoi{false}
{
// Silence compiler complaints about unused variables
- (void)REG_INT0_RLC_BIT;
- (void)REG_INT0_SPAS_BIT;
(void)REG_INT1_IFC_BIT;
- (void)REG_INT1_SRQ_BIT;
(void)REG_INT1_GET_BIT;
- (void)REG_SERIAL_P_MASK;
- (void)REG_SERIAL_P_RSV1_BIT;
}
// Signal inputs
-WRITE_LINE_MEMBER(tms9914_device::eoi_w)
+void tms9914_device::eoi_w(int state)
{
set_ext_signal(IEEE_488_EOI , state);
}
-WRITE_LINE_MEMBER(tms9914_device::dav_w)
+void tms9914_device::dav_w(int state)
{
set_ext_signal(IEEE_488_DAV , state);
}
-WRITE_LINE_MEMBER(tms9914_device::nrfd_w)
+void tms9914_device::nrfd_w(int state)
{
set_ext_signal(IEEE_488_NRFD , state);
}
-WRITE_LINE_MEMBER(tms9914_device::ndac_w)
+void tms9914_device::ndac_w(int state)
{
set_ext_signal(IEEE_488_NDAC , state);
}
-WRITE_LINE_MEMBER(tms9914_device::ifc_w)
+void tms9914_device::ifc_w(int state)
{
set_ext_signal(IEEE_488_IFC , state);
}
-WRITE_LINE_MEMBER(tms9914_device::srq_w)
+void tms9914_device::srq_w(int state)
{
+ bool prev_srq = get_signal(IEEE_488_SRQ);
set_ext_signal(IEEE_488_SRQ , state);
+ if (cont_r() && !prev_srq && get_signal(IEEE_488_SRQ)) {
+ set_int1_bit(REG_INT1_SRQ_BIT);
+ }
}
-WRITE_LINE_MEMBER(tms9914_device::atn_w)
+void tms9914_device::atn_w(int state)
{
set_ext_signal(IEEE_488_ATN , state);
}
-WRITE_LINE_MEMBER(tms9914_device::ren_w)
+void tms9914_device::ren_w(int state)
{
set_ext_signal(IEEE_488_REN , state);
}
@@ -271,15 +314,17 @@ void tms9914_device::write(offs_t offset, uint8_t data)
break;
case REG_W_SERIAL_P:
- m_reg_serial_p = data;
- // TODO: update FSM?
+ {
+ uint8_t diff = m_reg_2nd_serial_p ^ data;
+ m_reg_2nd_serial_p = data;
+ if (BIT(diff , REG_SERIAL_P_RSV1_BIT)) {
+ 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:
@@ -422,7 +467,7 @@ uint8_t tms9914_device::read(offs_t offset)
return res;
}
-READ_LINE_MEMBER(tms9914_device::cont_r)
+int tms9914_device::cont_r()
{
return m_c_state != FSM_C_CIDS && m_c_state != FSM_C_CADS;
}
@@ -443,6 +488,7 @@ void tms9914_device::device_start()
save_item(NAME(m_reg_int1_mask));
save_item(NAME(m_reg_address));
save_item(NAME(m_reg_serial_p));
+ save_item(NAME(m_reg_2nd_serial_p));
save_item(NAME(m_reg_parallel_p));
save_item(NAME(m_reg_2nd_parallel_p));
save_item(NAME(m_reg_di));
@@ -461,6 +507,7 @@ void tms9914_device::device_start()
save_item(NAME(m_stdl));
save_item(NAME(m_shdw));
save_item(NAME(m_vstdl));
+ save_item(NAME(m_rsvd2));
save_item(NAME(m_ah_state));
save_item(NAME(m_ah_adhs));
save_item(NAME(m_ah_anhs));
@@ -479,17 +526,9 @@ void tms9914_device::device_start()
save_item(NAME(m_c_state));
save_item(NAME(m_next_eoi));
- 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_accrq_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);
+ m_sh_dly_timer = timer_alloc(FUNC(tms9914_device::fsm_tick), this);
+ m_ah_dly_timer = timer_alloc(FUNC(tms9914_device::fsm_tick), this);
+ m_c_dly_timer = timer_alloc(FUNC(tms9914_device::fsm_tick), this);
}
void tms9914_device::device_reset()
@@ -504,13 +543,17 @@ void tms9914_device::device_reset()
m_sic = false;
m_sre = false;
m_dai = false;
- m_pts = false;
m_stdl = false;
m_shdw = false;
m_vstdl = false;
+ m_rsvd2 = false;
+ m_int_line = true;
m_accrq_line = true; // Ensure change is propagated
+ m_reg_int0_status = 0;
+ m_reg_int1_status = 0;
m_reg_serial_p = 0;
+ m_reg_2nd_serial_p = 0;
m_reg_parallel_p = 0;
m_reg_2nd_parallel_p = 0;
@@ -521,9 +564,8 @@ void tms9914_device::device_reset()
update_ren();
}
-void tms9914_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(tms9914_device::fsm_tick)
{
- LOG_NOISY("tmr %d\n" , id);
update_fsm();
}
@@ -745,6 +787,10 @@ void tms9914_device::update_fsm()
// BO interrupt is raised when SGNS state is entered
set_int0_bit(REG_INT0_BO_BIT);
}
+ if (prev_state == FSM_SH_STRS && m_t_state == FSM_T_SPAS &&
+ (m_sr_state == FSM_SR_APRS1 || m_sr_state == FSM_SR_APRS2)) {
+ set_int0_bit(REG_INT0_SPAS_BIT);
+ }
}
// SH outputs
// EOI is controlled by SH & C FSMs
@@ -753,14 +799,22 @@ void tms9914_device::update_fsm()
uint8_t dio_byte = 0;
set_signal(IEEE_488_DAV , m_sh_state == FSM_SH_STRS);
if (sh_active()) {
- dio_byte = m_t_state == FSM_T_SPAS ? m_reg_serial_p : m_reg_do;
+ if (m_t_state == FSM_T_SPAS) {
+ dio_byte = m_reg_serial_p & REG_SERIAL_P_MASK;
+ if (m_sr_state == FSM_SR_APRS1 || m_sr_state == FSM_SR_APRS2) {
+ // Set RQS
+ BIT_SET(dio_byte , 6);
+ }
+ } else {
+ dio_byte = 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) && cont_r()) ||
(!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;
@@ -851,6 +905,9 @@ void tms9914_device::update_fsm()
if (!get_signal(IEEE_488_ATN)) {
if (m_t_spms) {
m_t_state = FSM_T_SPAS;
+ // When entering SPAS, serial poll register is copied into the
+ // register that is actually output (as it's double buffered)
+ m_reg_serial_p = m_reg_2nd_serial_p;
} else {
m_t_state = FSM_T_TACS;
}
@@ -872,7 +929,7 @@ void tms9914_device::update_fsm()
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))) {
+ if (m_t_spms && (m_swrst || get_ifcin() || cont_r())) {
m_t_spms = false;
changed = true;
}
@@ -909,7 +966,77 @@ void tms9914_device::update_fsm()
}
// No direct L outputs
- // TODO: SR & PP FSMs
+ // PP FSM
+ if (!m_pp_ppas) {
+ // PPSS
+ if (!m_swrst && get_signal(IEEE_488_ATN) && get_signal(IEEE_488_EOI) && !cont_r()) {
+ m_pp_ppas = true;
+ changed = true;
+ // Copy m_reg_2nd_parallel_p when entering PPAS
+ m_reg_parallel_p = m_reg_2nd_parallel_p;
+ }
+ } else {
+ // PPAS
+ if (m_swrst || !get_signal(IEEE_488_ATN) || !get_signal(IEEE_488_EOI) || cont_r()) {
+ m_pp_ppas = false;
+ changed = true;
+ }
+ }
+ // PP output
+ if (m_pp_ppas) {
+ dio_byte |= m_reg_parallel_p;
+ }
+
+ // SR FSM
+ prev_state = m_sr_state;
+ if (m_swrst) {
+ m_sr_state = FSM_SR_NPRS;
+ } else {
+ switch (m_sr_state) {
+ case FSM_SR_NPRS:
+ if (m_t_state != FSM_T_SPAS &&
+ (BIT(m_reg_2nd_serial_p , REG_SERIAL_P_RSV1_BIT) || m_rsvd2)) {
+ m_sr_state = FSM_SR_SRQS;
+ }
+ break;
+
+ case FSM_SR_SRQS:
+ if (m_t_state == FSM_T_SPAS) {
+ m_sr_state = FSM_SR_APRS1;
+ } else if (!BIT(m_reg_2nd_serial_p , REG_SERIAL_P_RSV1_BIT) && !m_rsvd2) {
+ m_sr_state = FSM_SR_NPRS;
+ }
+ break;
+
+ case FSM_SR_APRS1:
+ if (m_t_state == FSM_T_SPAS && m_sh_state == FSM_SH_STRS) {
+ m_rsvd2 = false;
+ }
+ if (!BIT(m_reg_2nd_serial_p , REG_SERIAL_P_RSV1_BIT) && !m_rsvd2) {
+ m_sr_state = FSM_SR_APRS2;
+ }
+ break;
+
+ case FSM_SR_APRS2:
+ if (m_t_state == FSM_T_SPAS) {
+ if (m_sh_state == FSM_SH_STRS) {
+ m_rsvd2 = false;
+ }
+ } else {
+ m_sr_state = FSM_SR_NPRS;
+ }
+ break;
+
+ default:
+ LOG("Invalid SR state %d\n" , m_sr_state);
+ m_sr_state = FSM_SR_NPRS;
+ }
+ }
+ if (m_sr_state != prev_state) {
+ changed = true;
+ }
+ // SR outputs
+ set_signal(IEEE_488_SRQ , m_sr_state == FSM_SR_SRQS);
// RL FSM
if (m_rl_state != FSM_RL_LOCS && (m_swrst || !get_signal(IEEE_488_REN))) {
@@ -927,7 +1054,10 @@ void tms9914_device::update_fsm()
} else {
switch (m_c_state) {
case FSM_C_CIDS:
- // sic | rqc -> CADS
+ // See also sic & rqc aux commands
+ if (m_sic) {
+ m_c_state = FSM_C_CADS;
+ }
break;
case FSM_C_CADS:
@@ -1107,11 +1237,17 @@ void tms9914_device::if_cmd_received(uint8_t if_cmd)
break;
case IFCMD_SPE:
- // TODO:
+ if (!get_ifcin() && !m_t_spms) {
+ m_t_spms = true;
+ m_ext_state_change = true;
+ }
break;
case IFCMD_SPD:
- // TODO:
+ if (m_t_spms) {
+ m_t_spms = false;
+ m_ext_state_change = true;
+ }
break;
case IFCMD_UNL:
@@ -1397,7 +1533,7 @@ void tms9914_device::do_aux_cmd(unsigned cmd , bool set_bit)
break;
case AUXCMD_STDL:
- LOG("Unimplemented STDL cmd\n");
+ LOG("Unimplemented STDL=%d cmd\n" , set_bit);
break;
case AUXCMD_SHDW:
@@ -1411,11 +1547,14 @@ void tms9914_device::do_aux_cmd(unsigned cmd , bool set_bit)
break;
case AUXCMD_VSTDL:
- LOG("Unimplemented VSTDL cmd\n");
+ LOG("Unimplemented VSTDL=%d cmd\n" , set_bit);
break;
case AUXCMD_RSV2:
- LOG("Unimplemented RSV2 cmd\n");
+ if (set_bit != m_rsvd2) {
+ m_rsvd2 = set_bit;
+ update_fsm();
+ }
break;
default: