summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/scnxx562.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/scnxx562.cpp')
-rw-r--r--src/devices/machine/scnxx562.cpp240
1 files changed, 123 insertions, 117 deletions
diff --git a/src/devices/machine/scnxx562.cpp b/src/devices/machine/scnxx562.cpp
index a14110879d4..e49c586d00c 100644
--- a/src/devices/machine/scnxx562.cpp
+++ b/src/devices/machine/scnxx562.cpp
@@ -1,4 +1,4 @@
-// license:BSD-3-Clause
+// license:BSD-3-Clause
// copyright-holders: Joakim Larsson Edstrom
/***************************************************************************
@@ -87,7 +87,6 @@ DONE (x) (p=partly) NMOS CMOS
/* Useful temporary debug printout format */
// printf("TAG %s%s Data:%d\n", __PRETTY_FUNCTION__, owner()->tag(), data);
-#define LOG_GENERAL (1U << 0)
#define LOG_R (1U << 1)
#define LOG_TX (1U << 2)
#define LOG_RX (1U << 3)
@@ -207,23 +206,6 @@ void duscc_device::device_start()
{
LOG("%s\n", FUNCNAME);
- // resolve callbacks
- m_out_txda_cb.resolve_safe();
- m_out_dtra_cb.resolve_safe();
- m_out_rtsa_cb.resolve_safe();
- m_out_synca_cb.resolve_safe();
- m_out_rtxca_cb.resolve_safe();
- m_out_trxca_cb.resolve_safe();
-
- m_out_txdb_cb.resolve_safe();
- m_out_dtrb_cb.resolve_safe();
- m_out_rtsb_cb.resolve_safe();
- m_out_syncb_cb.resolve_safe();
- m_out_rtxcb_cb.resolve_safe();
- m_out_trxcb_cb.resolve_safe();
-
- m_out_int_cb.resolve_safe();
-
// state saving - stuff with runtime values
save_item(NAME(m_int_state));
save_item(NAME(m_gsr));
@@ -242,7 +224,7 @@ void duscc_device::device_start()
void duscc_device::device_reset()
{
- LOG("%s %s \n",tag(), FUNCNAME);
+ LOG("%s\n", FUNCNAME);
m_chanA->reset();
m_chanB->reset();
@@ -297,7 +279,7 @@ int duscc_device::z80daisy_irq_state()
{
int state = 0;
- LOGINT("%s %s A:[%02x][%02x][%02x][%02x] B:[%02x][%02x][%02x][%02x] ",tag(), FUNCNAME,
+ LOGINT("%s A:[%02x][%02x][%02x][%02x] B:[%02x][%02x][%02x][%02x] ", FUNCNAME,
m_int_state[0], m_int_state[1], m_int_state[2], m_int_state[3],
m_int_state[4], m_int_state[5], m_int_state[6], m_int_state[7]);
@@ -325,7 +307,7 @@ int duscc_device::z80daisy_irq_state()
int duscc_device::z80daisy_irq_ack()
{
- LOGINT("%s %s()\n",tag(), FUNCNAME);
+ LOGINT("%s()\n", FUNCNAME);
// loop over all interrupt sources
for (auto & elem : m_int_state)
@@ -360,7 +342,7 @@ int duscc_device::z80daisy_irq_ack()
void duscc_device::z80daisy_irq_reti()
{
- LOGINT("%s %s \n",tag(), FUNCNAME);
+ LOGINT("%s\n", FUNCNAME);
// loop over all interrupt sources
for (auto & elem : m_int_state)
@@ -379,7 +361,7 @@ void duscc_device::z80daisy_irq_reti()
uint8_t duscc_device::iack()
{
- LOGINT("%s %s - returning vector:%02x\n",tag(), FUNCNAME, m_ivrm);
+ LOGINT("%s - returning vector:%02x\n", FUNCNAME, m_ivrm);
int vec = z80daisy_irq_ack();
z80daisy_irq_reti();
return vec;
@@ -387,8 +369,8 @@ uint8_t duscc_device::iack()
void duscc_device::check_interrupts()
{
- LOGINT("%s %s()\n",tag(), FUNCNAME);
int state = (z80daisy_irq_state() & Z80_DAISY_INT) ? ASSERT_LINE : CLEAR_LINE;
+ LOGINT("%s(icr %02x ierA %02x ierB %02x state %d)\n", FUNCNAME, m_icr, m_chanA->m_ier, m_chanB->m_ier, state);
// "If no interrupt is pending, an H'FF' is output when reading the IVRM."
if (state == CLEAR_LINE)
@@ -406,7 +388,7 @@ void duscc_device::check_interrupts()
void duscc_device::reset_interrupts()
{
- LOGINT("%s %s\n",tag(), FUNCNAME);
+ LOGINT("%s\n", FUNCNAME);
// reset internal interrupt sources
for (auto & elem : m_int_state)
@@ -435,7 +417,7 @@ uint8_t duscc_device::modify_vector(uint8_t vec, int index, uint8_t src)
1 1 1 Ch B external or C/T status
--------------------------------------------------
*/
- LOGINT("%s %c %s, vec:%02x src=%02x\n",tag(), 'A' + index, FUNCNAME, vec, src);
+ LOGINT("%c %s, vec:%02x src=%02x\n", 'A' + index, FUNCNAME, vec, src);
// TODO: Prevent modification if no vector has been programmed, even if it is the default vector.
if ((m_icr & REG_ICR_VEC_MOD) != 0) // Affect vector?
@@ -472,6 +454,35 @@ uint8_t duscc_device::modify_vector(uint8_t vec, int index, uint8_t src)
7. General status register (GSR)
*/
+int duscc_device::interrupt_priority(int index, int state)
+{
+ int priority_level = 0;
+
+ switch (m_icr & REG_ICR_PRIO_MASK)
+ {
+ case REG_ICR_PRIO_AHI: priority_level = state + (index == CHANNEL_A ? 0 : 4); break;
+ case REG_ICR_PRIO_BHI: priority_level = state + (index == CHANNEL_A ? 4 : 0); break;
+ case REG_ICR_PRIO_AINT: priority_level = state * 2 + (index == CHANNEL_A ? 0 : 1); break;
+ case REG_ICR_PRIO_BINT: priority_level = state * 2 + (index == CHANNEL_A ? 1 : 0); break;
+ default: logerror("DUSCC Programming error, please report/fix\n"); // Will not happen
+ }
+
+ return priority_level;
+}
+
+void duscc_device::clear_interrupt(int index, int state)
+{
+ LOGINT("%s:%c %02x\n", FUNCNAME, 'A' + index, state);
+
+ m_int_state[interrupt_priority(index, state)] &= ~Z80_DAISY_INT;
+ if ((m_icr & (index == CHANNEL_A ? REG_ICR_CHA : REG_ICR_CHB)) == 0)
+ {
+ LOGINT("The Interrupt Control Register [%02x] bit for this channel is not set, blocking attempt to interrupt\n", m_icr);
+ return;
+ }
+ check_interrupts();
+}
+
//-----------------------------------------------------------------------
// trigger_interrupt - called when a potential interrupt condition occurs and will only issue an interrupt if the DUSCC is
// programmed to do so.
@@ -482,7 +493,7 @@ void duscc_device::trigger_interrupt(int index, int state)
uint8_t source = 0;
int priority_level = 0;
- LOGINT("%s %s:%c %02x \n",FUNCNAME, tag(), 'A' + index, state);
+ LOGINT("%s:%c %02x \n",FUNCNAME, 'A' + index, state);
// The Interrupt Control Register (ICR) bits, must be set for the corresponding channel
// ICR Check is probably by the caller but we check again to be sure
@@ -493,14 +504,7 @@ void duscc_device::trigger_interrupt(int index, int state)
}
// Modify priority level
- switch (m_icr & REG_ICR_PRIO_MASK)
- {
- case REG_ICR_PRIO_AHI: priority_level = state + (index == CHANNEL_A ? 0 : 4); break;
- case REG_ICR_PRIO_BHI: priority_level = state + (index == CHANNEL_A ? 4 : 0); break;
- case REG_ICR_PRIO_AINT: priority_level = state * 2 + (index == CHANNEL_A ? 0 : 1); break;
- case REG_ICR_PRIO_BINT: priority_level = state * 2 + (index == CHANNEL_A ? 1 : 0); break;
- default: logerror("DUSCC Programming error, please report/fix\n"); // Will not happen
- }
+ priority_level = interrupt_priority(index, state);
// Vector modification requested?
source = state + (index == CHANNEL_A ? 0 : 4); // bit in interrupt queue register of a certain priotiry level
@@ -596,9 +600,9 @@ void duscc_channel::device_start()
m_cid = (m_uart->m_variant & duscc_device::SET_CMOS) ? 0x7f : 0xff; // TODO: support CMOS rev A = 0xbf
// Timers
- duscc_timer = timer_alloc(TIMER_ID);
- rtxc_timer = timer_alloc(TIMER_ID_RTXC);
- trxc_timer = timer_alloc(TIMER_ID_TRXC);
+ duscc_timer = timer_alloc(FUNC(duscc_channel::check_zero_detect), this);
+ rtxc_timer = timer_alloc(FUNC(duscc_channel::rtxc_tick), this);
+ trxc_timer = timer_alloc(FUNC(duscc_channel::trxc_tick), this);
// state saving
save_item(NAME(m_cmr1));
@@ -723,95 +727,90 @@ void duscc_channel::device_reset()
m_a7 = 0;
}
-void duscc_channel::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(duscc_channel::check_zero_detect)
{
- switch(id)
+ if (m_ct-- == 0) // Zero detect
{
- case TIMER_ID:
- if (m_ct-- == 0) // Zero detect
+ m_ictsr |= REG_ICTSR_ZERO_DET; // set zero detection bit
+
+ // Generate interrupt?
+ if ( ( (m_ctcr & REG_CTCR_ZERO_DET_INT) == REG_CTCR_ZERO_DET_INT ) &&
+ ( (m_uart->m_icr & (m_index == duscc_device::CHANNEL_A ? duscc_device::REG_ICR_CHA : duscc_device::REG_ICR_CHB) ) != 0) )
{
- m_ictsr |= REG_ICTSR_ZERO_DET; // set zero detection bit
+ LOG("Zero Detect Interrupt pending\n");
+ m_uart->trigger_interrupt(m_index, INT_EXTCTSTAT);
+ }
- // Generate interrupt?
- if ( ( (m_ctcr & REG_CTCR_ZERO_DET_INT) == REG_CTCR_ZERO_DET_INT ) &&
- ( (m_uart->m_icr & (m_index == duscc_device::CHANNEL_A ? duscc_device::REG_ICR_CHA : duscc_device::REG_ICR_CHB) ) != 0) )
- {
- LOG("Zero Detect Interrupt pending\n");
- m_uart->trigger_interrupt(m_index, INT_EXTCTSTAT);
- }
+ // Preload or rollover?
+ if (( m_ctcr & REG_CTCR_ZERO_DET_CTL) == 0)
+ {
+ m_ct = m_ctpr;
+ }
+ else
+ {
+ m_ct = 0xffff;
+ }
- // Preload or rollover?
- if (( m_ctcr & REG_CTCR_ZERO_DET_CTL) == 0)
+ // Is Counter/Timer output on the RTxC pin?
+ if (( m_pcr & REG_PCR_RTXC_MASK) == REG_PCR_RTXC_CNTR_OUT)
+ {
+ if ((m_ctcr & REG_CTCR_TIM_OC) == 0) // Toggle?
{
- m_ct = m_ctpr;
+ m_rtxc = (~m_rtxc) & 1;
}
- else
+ else // Pulse!
{
- m_ct = 0xffff;
+ m_rtxc = 1;
+ rtxc_timer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock()));
}
+ if (m_index == duscc_device::CHANNEL_A)
+ m_uart->m_out_rtxca_cb(m_rtxc);
+ else
+ m_uart->m_out_rtxcb_cb(m_rtxc);
+ }
- // Is Counter/Timer output on the RTxC pin?
- if (( m_pcr & REG_PCR_RTXC_MASK) == REG_PCR_RTXC_CNTR_OUT)
+ // Is Counter/Timer output on the TRXC pin?
+ if (( m_pcr & REG_PCR_TRXC_MASK) == REG_PCR_TRXC_CNTR_OUT)
+ {
+ if ((m_ctcr & REG_CTCR_TIM_OC) == 0) // Toggle?
{
- if ((m_ctcr & REG_CTCR_TIM_OC) == 0) // Toggle?
- {
- m_rtxc = (~m_rtxc) & 1;
- }
- else // Pulse!
- {
- m_rtxc = 1;
- rtxc_timer->adjust(attotime::from_hz(clock()), TIMER_ID_RTXC, attotime::from_hz(clock()));
- }
- if (m_index == duscc_device::CHANNEL_A)
- m_uart->m_out_rtxca_cb(m_rtxc);
- else
- m_uart->m_out_rtxcb_cb(m_rtxc);
+ m_trxc = (~m_trxc) & 1;
}
-
- // Is Counter/Timer output on the TRXC pin?
- if (( m_pcr & REG_PCR_TRXC_MASK) == REG_PCR_TRXC_CNTR_OUT)
+ else // Pulse!
{
- if ((m_ctcr & REG_CTCR_TIM_OC) == 0) // Toggle?
- {
- m_trxc = (~m_trxc) & 1;
- }
- else // Pulse!
- {
- m_trxc = 1;
- trxc_timer->adjust(attotime::from_hz(clock()), TIMER_ID_TRXC, attotime::from_hz(clock()));
- }
- if (m_index == duscc_device::CHANNEL_A)
- m_uart->m_out_trxca_cb(m_trxc);
- else
- m_uart->m_out_trxcb_cb(m_trxc);
+ m_trxc = 1;
+ trxc_timer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock()));
}
+ if (m_index == duscc_device::CHANNEL_A)
+ m_uart->m_out_trxca_cb(m_trxc);
+ else
+ m_uart->m_out_trxcb_cb(m_trxc);
}
- else
- { // clear zero detection bit
- m_ictsr &= ~REG_ICTSR_ZERO_DET;
- }
- break;
- case TIMER_ID_RTXC: // Terminate zero detection pulse
- m_rtxc = 0;
- rtxc_timer->adjust(attotime::never);
- if (m_index == duscc_device::CHANNEL_A)
- m_uart->m_out_rtxca_cb(m_rtxc);
- else
- m_uart->m_out_rtxcb_cb(m_rtxc);
- break;
- case TIMER_ID_TRXC: // Terminate zero detection pulse
- m_trxc = 0;
- trxc_timer->adjust(attotime::never);
- if (m_index == duscc_device::CHANNEL_A)
- m_uart->m_out_trxca_cb(m_trxc);
- else
- m_uart->m_out_trxcb_cb(m_trxc);
- break;
- default:
- LOGR("Unhandled Timer ID %d\n", id);
- break;
}
- // LOG("%s %d\n", FUNCNAME, id);
+ else
+ { // clear zero detection bit
+ m_ictsr &= ~REG_ICTSR_ZERO_DET;
+ }
+}
+
+TIMER_CALLBACK_MEMBER(duscc_channel::rtxc_tick)
+{
+ m_rtxc = 0;
+ rtxc_timer->adjust(attotime::never);
+ if (m_index == duscc_device::CHANNEL_A)
+ m_uart->m_out_rtxca_cb(m_rtxc);
+ else
+ m_uart->m_out_rtxcb_cb(m_rtxc);
+}
+
+TIMER_CALLBACK_MEMBER(duscc_channel::trxc_tick)
+{
+ m_trxc = 0;
+ trxc_timer->adjust(attotime::never);
+ if (m_index == duscc_device::CHANNEL_A)
+ m_uart->m_out_trxca_cb(m_trxc);
+ else
+ m_uart->m_out_trxcb_cb(m_trxc);
}
/* The DUSCC 16 bit Timer
@@ -1288,7 +1287,7 @@ uint8_t duscc_channel::do_dusccreg_gsr_r()
uint8_t duscc_channel::do_dusccreg_ier_r()
{
- LOGINT("%s <- %02x\n", FUNCNAME, m_ier);
+ LOGINT("%s(%02x)\n", FUNCNAME, m_ier);
return (uint8_t) m_ier;
}
@@ -1955,6 +1954,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data)
m_tx_fifo_wp = m_tx_fifo_rp = 0;
m_trsr &= 0x0f;
m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY);
+ m_uart->clear_interrupt(m_index, INT_TXREADY);
break;
/* Enable transmitter. Enables transmitter operation, conditioned by the state of
@@ -1975,6 +1975,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data)
set_tra_rate(0);
m_tra = 0;
m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY);
+ m_uart->clear_interrupt(m_index, INT_TXREADY);
break;
// RECEIVER COMMANDS
@@ -1989,6 +1990,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data)
m_trsr &= 0xf0;
m_rsr = 0;
m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY);
+ m_uart->clear_interrupt(m_index, INT_RXREADY);
break;
/* Enable receiver. Causes receiver operation to begin, conditioned by the state of the DCD
@@ -2004,6 +2006,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data)
case REG_CCR_DISABLE_RX: LOGINT("- Disable Rx\n");
m_rcv = 0;
m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY);
+ m_uart->clear_interrupt(m_index, INT_RXREADY);
break;
// COUNTER/TIMER COMMANDS
@@ -2011,7 +2014,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data)
/* Start. Starts the counteritimer and prescaler. */
case REG_CCR_START_TIMER: LOG("- Start Counter/Timer\n");
rate = 100; // TODO: calculate correct rate
- duscc_timer->adjust(attotime::from_hz(rate), TIMER_ID_RTXC, attotime::from_hz(rate));
+ duscc_timer->adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate));
break;
/* Stop. Stops the counter/timer and prescaler. Since the command may be asynchronous with the selected clock source,
@@ -2039,7 +2042,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data)
void duscc_channel::do_dusccreg_txfifo_w(uint8_t data)
{
- LOGTX(" - TX %s(%02x)'%c'\n", FUNCNAME,data, isalnum(data) ? data : ' ');
+ LOGTX(" - TX %s(%02x)'%c' wp %d rp %d\n", FUNCNAME,data, isprint(data) ? data : ' ', m_tx_fifo_wp, m_tx_fifo_rp);
/* Tx FIFO is full or...? */
if (m_tx_fifo_wp + 1 == m_tx_fifo_rp || ( (m_tx_fifo_wp + 1 == m_tx_fifo_sz) && (m_tx_fifo_rp == 0) ))
@@ -2070,6 +2073,7 @@ void duscc_channel::do_dusccreg_txfifo_w(uint8_t data)
if (m_tx_fifo_wp + 1 == m_tx_fifo_rp || ( (m_tx_fifo_wp + 1 == m_tx_fifo_sz) && (m_tx_fifo_rp == 0) ))
{
m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY);
+ m_uart->clear_interrupt(m_index, INT_TXREADY);
}
else
{
@@ -2213,7 +2217,7 @@ uint8_t duscc_channel::read(offs_t &offset)
{
uint8_t data = 0;
int reg = (offset | m_a7) & ~0x20; // Add extended rgisters and remove the channel B bit from offset
- LOG("\"%s\" %s: %c : Register read '%02x' <- [%02x]", owner()->tag(), FUNCNAME, 'A' + m_index, data, reg );
+ LOGR("\"%s\" %s: %c : Register read '%02x' <- [%02x]", owner()->tag(), FUNCNAME, 'A' + m_index, data, reg );
LOGR(" * %c Reg %02x -> %02x \n", 'A' + m_index, reg, data);
switch (reg)
{
@@ -2264,7 +2268,7 @@ void duscc_channel::write(uint8_t data, offs_t &offset)
int reg = (offset | m_a7) & ~0x20; // Add extended rgisters and remove the channel B bit from offset
LOGSETUP(" * %s%c Reg %02x <- %02x \n", owner()->tag(), 'A' + m_index, reg, data);
- LOG("\"%s\" %s: %c : Register write '%02x' -> [%02x]", owner()->tag(), FUNCNAME, 'A' + m_index, data, reg );
+ LOG("\"%s\" %s: %c : Register write '%02x' -> [%02x]\n", owner()->tag(), FUNCNAME, 'A' + m_index, data, reg );
switch (reg)
{
case REG_CMR1: do_dusccreg_cmr1_w(data); break;
@@ -2337,6 +2341,7 @@ void duscc_channel::m_rx_fifo_rp_step()
// no more characters available in the FIFO
LOGINT("Clear RXRDY in GSR because FIFO is emptied\n");
m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY);
+ m_uart->clear_interrupt(m_index, INT_RXREADY);
}
}
@@ -2418,6 +2423,7 @@ void duscc_channel::cts_w(int state)
if (m_tpr & REG_TPR_CTS && m_tra)
{
m_uart->m_gsr |= (m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY);
+ m_uart->trigger_interrupt(m_index, INT_TXREADY);
}
// set clear to send