diff --git a/src/devices/machine/z80scc.cpp b/src/devices/machine/z80scc.cpp index 019275d00ee..a756195dd9e 100644 --- a/src/devices/machine/z80scc.cpp +++ b/src/devices/machine/z80scc.cpp @@ -85,7 +85,7 @@ DONE (x) (p=partly) NMOS CMOS ESCC EMSCC #define LOGSETUP(x) {} LOGPRINT(x) #define LOGINT(x) {} LOGPRINT(x) #define LOGTX(x) {} LOGPRINT(x) -#define LOGRCV(x) {} +#define LOGRCV(x) {} LOGPRINT(x) #define LOGCTS(x) {} LOGPRINT(x) #define LOGDCD(x) {} LOGPRINT(x) #if VERBOSE == 2 @@ -288,13 +288,42 @@ void z80scc_device::device_reset() /* * Interrupts -Each of the SCC's two channels contain three sources of interrupts, making a total of six interrupt -sources. These three sources of interrupts are: 1) Receiver, 2) Transmitter, and 3) External/Status -conditions. In addition, there are several conditions that may cause these interrupts. +Each of the SCC's two channels contain three priority levels of interrupts, making a total of six interrupt +levels. These three sources of interrupts are: 1) Receiver, 2) Transmitter, and 3) External/Status +conditions. In addition, there are four sources per channel: 0) Transmitt 1) External 2) Receiver 3) Special +which affects the way the interrupt vector is formed. The sources in more detail + +INT_RECEIVE: The sources of receive interrupts consist of Receive Character Available and Special Receive Condition. + The Special Receive Condition can be subdivided into Receive Overrun, Framing Error (Asynchronous) or + End of Frame (SDLC). In addition, a parity error can be a special receive condition by programming + +INT_EXTERNAL: The External/status interrupts have several sources which may be individually enabled in WR15. + The sources are zero count, /DCD, Sync/Hunt, /CTS, transmitter under-run/EOM and Break/Abort. + +INT_TRANSMIT: The NMOS/CMOS version of the SCC only has a one byte deep transmit buffer. The status of the + transmit buffer can be determined through TBE bit in RR0, bit D2, which shows whether the + transmit buffer is empty or not. After a hardware reset (including a hardware reset by software), or + a channel reset, this bit is set to 1. + While transmit interrupts are enabled, the NMOS/CMOS version sets the Transmit Interrupt Pending + (TxIP) bit whenever the transmit buffer becomes empty. This means that the transmit buffer + must be full before the TxIP can be set. Thus, when transmit interrupts are first enabled, the TxIP + will not be set until after the first character is written to the NMOS/CMOS. + +INT_SPECIAL: This mode allows the receiver to interrupt only on + characters with a special receive condition. When an interrupt occurs, the data containing the error + is held in the Receive FIFO until an Error Reset command is issued. When using this mode in conjunction + with a DMA, the DMA is initialized and enabled before any characters have been + received by the ESCC. This eliminates the time-critical section of code required in the Receive + Interrupt on First Character or Special Condition mode. Hence, all data can be transferred via the + DMA so that the CPU need not handle the first received character as a special case. In SDLC + mode, if the SDLC Frame Status FIFO is enabled and an EOF is received, an interrupt with vector + for receive data available is generated and the Receive FIFO is not locked. To allow for control over the daisy chain, the SCC has a Disable Lower Chain (DLC) software command (WR9 bit 2) that pulls IEO Low. This selectively deactivates parts of the daisy chain regardless of the interrupt status. + */ + //------------------------------------------------- // z80daisy_irq_state - get interrupt status //------------------------------------------------- @@ -302,7 +331,7 @@ int z80scc_device::z80daisy_irq_state() { int state = 0; - LOG(("%s %s A:%d%d%d B:%d%d%d ",tag(), FUNCNAME, + LOGINT(("%s %s A:%d%d%d B:%d%d%d ",tag(), 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])); @@ -321,7 +350,7 @@ int z80scc_device::z80daisy_irq_state() // Last chance to keep the control of the interrupt line state |= (m_wr9 & z80scc_channel::WR9_BIT_DLC) ? Z80_DAISY_IEO : 0; - LOG(("Interrupt State %u\n", state)); + LOGINT(("- Interrupt State %u\n", state)); return state; } @@ -330,9 +359,9 @@ int z80scc_device::z80daisy_irq_state() //------------------------------------------------- // z80daisy_irq_ack - interrupt acknowledge //------------------------------------------------- - int z80scc_device::z80daisy_irq_ack() { + LOGINT(("%s %s \n",tag(), FUNCNAME)); // loop over all interrupt sources for (auto & elem : m_int_state) { @@ -355,8 +384,6 @@ int z80scc_device::z80daisy_irq_ack() } } - //logerror("z80scc_irq_ack: failed to find an interrupt to ack!\n"); - return -1; } @@ -373,6 +400,7 @@ daisy chain, the SCC has a Disable Lower Chain (DLC) software command (WR9 bit 2 */ void z80scc_device::z80daisy_irq_reti() { + LOGINT(("%s %s - No RETI detection needed on SCC\n",tag(), FUNCNAME)); } @@ -439,11 +467,25 @@ uint8_t z80scc_device::modify_vector(uint8_t vec, int i, uint8_t src) return vec; } +int z80scc_device::get_extint_priority(int type) +{ + int prio = 0; + + switch(type) + { + case z80scc_channel::INT_RECEIVE: prio = z80scc_channel::INT_RECEIVE_PRIO; break; + case z80scc_channel::INT_EXTERNAL: prio = z80scc_channel::INT_EXTERNAL_PRIO; break; + case z80scc_channel::INT_TRANSMIT: prio = z80scc_channel::INT_TRANSMIT_PRIO; break; + case z80scc_channel::INT_SPECIAL: prio = z80scc_channel::INT_SPECIAL_PRIO; break; + default: logerror("Bad interrupt source beeing prioritized!"); + } + return prio; +} //------------------------------------------------- // trigger_interrupt - //------------------------------------------------- -void z80scc_device::trigger_interrupt(int index, int state) +void z80scc_device::trigger_interrupt(int index, int type) { uint8_t vector = m_chanA->m_rr2; uint8_t source = 0; @@ -451,67 +493,29 @@ void z80scc_device::trigger_interrupt(int index, int state) int prio_level = 0; - LOG(("%s %s:%c %02x \n",FUNCNAME, tag(), 'A' + index, state)); + LOGINT(("%s %s:%c %02x \n",FUNCNAME, tag(), 'A' + index, type)); /* The Master Interrupt Enable (MIE) bit, WR9 D3, must be set to enable the SCC to generate interrupts.*/ if (!(m_wr9 & z80scc_channel::WR9_BIT_MIE)) { - LOG(("Master Interrupt Enable is not set, blocking attempt to interrupt\n")); + LOGINT(("Master Interrupt Enable is not set, blocking attempt to interrupt\n")); return; } - switch(state) + source = type; + prio_level = get_extint_priority(type); + if (source < z80scc_channel::INT_TRANSMIT || source > z80scc_channel::INT_SPECIAL || prio_level < 0 || prio_level > 2) { - case z80scc_channel::INT_RECEIVE: - /*The sources of receive interrupts consist of Receive Character Available and Special Receive Condition. - The Special Receive Condition can be subdivided into Receive Overrun, Framing Error (Asynchronous) or - End of Frame (SDLC). In addition, a parity error can be a special receive condition by programming*/ - source = 2; - prio_level = 2; - break; - case z80scc_channel::INT_EXTERNAL: - /* The External/status interrupts have several sources which may be individually enabled in WR15. - The sources are zero count, /DCD, Sync/Hunt, /CTS, transmitter under-run/EOM and Break/Abort.*/ - source = 1; - prio_level = 0; - break; - case z80scc_channel::INT_TRANSMIT: - /*The NMOS/CMOS version of the SCC only has a one byte deep transmit buffer. The status of the - transmit buffer can be determined through TBE bit in RR0, bit D2, which shows whether the - transmit buffer is empty or not. After a hardware reset (including a hardware reset by software), or - a channel reset, this bit is set to 1. - While transmit interrupts are enabled, the NMOS/CMOS version sets the Transmit Interrupt Pending - (TxIP) bit whenever the transmit buffer becomes empty. This means that the transmit buffer - must be full before the TxIP can be set. Thus, when transmit interrupts are first enabled, the TxIP - will not be set until after the first character is written to the NMOS/CMOS.*/ - source = 0; - prio_level = 1; - break; - case z80scc_channel::INT_SPECIAL: - /*This mode allows the receiver to interrupt only on - characters with a special receive condition. When an interrupt occurs, the data containing the error - is held in the Receive FIFO until an Error Reset command is issued. When using this mode in conjunction - with a DMA, the DMA is initialized and enabled before any characters have been - received by the ESCC. This eliminates the time-critical section of code required in the Receive - Interrupt on First Character or Special Condition mode. Hence, all data can be transferred via the - DMA so that the CPU need not handle the first received character as a special case. In SDLC - mode, if the SDLC Frame Status FIFO is enabled and an EOF is received, an interrupt with vector - for receive data available is generated and the Receive FIFO is not locked.*/ - source = 3; - prio_level = 0; - break; - default: - logerror("Attempt to trigger interrupt of unknown origin blocked: %02x on channel %c\n", state, 'A' + index); + logerror("Attempt to trigger interrupt of unknown origin blocked: %02x/%02x on channel %c\n", source, prio_level, 'A' + index); return; } - // Vector modification requested? if (m_wr9 & z80scc_channel::WR9_BIT_VIS) { vector = modify_vector(vector, index, source); } - LOG((" Interrupt Request fired of type %u and vector %02x\n", state, vector)); + LOGINT((" Interrupt Request fired of type %u and vector %02x\n", type, vector)); // update vector register m_chanB->m_rr2 = vector; @@ -526,7 +530,7 @@ void z80scc_device::trigger_interrupt(int index, int state) Channel B External/Status */ // Add channel offset to priority according to table above - priority = prio_level + (index == CHANNEL_A ? 3 : 0 ); + priority = prio_level + (index == CHANNEL_A ? 0 : 3 ); // trigger interrupt m_int_state[priority] |= Z80_DAISY_INT; @@ -535,13 +539,38 @@ void z80scc_device::trigger_interrupt(int index, int state) m_int_source[priority] = source; // Based on the fact that prio levels are aligned with the bitorder of rr3 we can do this... - m_chanA->m_rr3 &= ~( 0x07 << (index == CHANNEL_A ? 3 : 0 )); - m_chanA->m_rr3 |= (prio_level << (index == CHANNEL_A ? 3 : 0 )); + m_chanA->m_rr3 |= ((1 << prio_level) + (index == CHANNEL_A ? 3 : 0 )); // check for interrupt check_interrupts(); } +int z80scc_device::update_extint(int index) +{ + int ret = 1; // Assume there is more interrupts to serve + uint8_t rr0 = (index == CHANNEL_A ? m_chanA->m_rr0 : m_chanB->m_rr0); + uint8_t wr15 = (index == CHANNEL_A ? m_chanA->m_wr15 : m_chanB->m_wr15); + uint8_t lrr0 = (index == CHANNEL_A ? m_chanA->m_extint_states : m_chanB->m_extint_states); + + LOGINT(("%s(%02x)\n", FUNCNAME, index)); + // Check if any of the enabled external interrupt sources has changed and requiresd service TODO: figure out Zero Count + if ( ((lrr0 & wr15 & 0xf8) ^ (rr0 & wr15 & 0xf8)) == 0 ) // mask off disabled and non relevant bits + { + LOGINT((" - All interrupts serviced\n")); + + // Reset IP bit for external interrupts in both internal structure and rr3 + // - External and Special interripts has the same prio, just add channel offset + m_int_state[z80scc_channel::INT_EXTERNAL_PRIO + (index == CHANNEL_A ? 0 : 3 )] = 0; + // Based on the fact that prio levels are aligned with the bitorder of rr3 we can do this... + m_chanA->m_rr3 &= ~((1 << z80scc_channel::INT_EXTERNAL_PRIO) + (index == CHANNEL_A ? 3 : 0 )); + ret = 0; // indicate that we are done + } + else + { + LOGINT((" - More external/status interrupts to serve: %02x\n", ((lrr0 & wr15 & 0xf8) ^ (rr0 & wr15 & 0xf8)))); + } + return ret; +} //------------------------------------------------- // m1_r - interrupt acknowledge @@ -821,10 +850,9 @@ z80scc_channel::z80scc_channel(const machine_config &mconfig, const char *tag, d m_rx_clock(0), m_rx_first(0), m_rx_break(0), - m_rx_rr0_latch(0), + m_extint_latch(0), + m_extint_states(0), m_rxd(0), - m_cts(1), - m_dcd(1), m_tx_clock(0), m_dtr(0), m_rts(0), @@ -922,10 +950,9 @@ void z80scc_channel::device_start() save_item(NAME(m_rx_clock)); save_item(NAME(m_rx_first)); save_item(NAME(m_rx_break)); - save_item(NAME(m_rx_rr0_latch)); + save_item(NAME(m_extint_latch)); + save_item(NAME(m_extint_states)); save_item(NAME(m_ri)); - save_item(NAME(m_cts)); - save_item(NAME(m_dcd)); save_item(NAME(m_tx_clock)); save_item(NAME(m_dtr)); save_item(NAME(m_rts)); @@ -1290,8 +1317,21 @@ int z80scc_channel::get_tx_word_length() * Break/Abort latch. */ uint8_t z80scc_channel::do_sccreg_rr0() { - LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, m_rr0)); - return m_rr0; + uint8_t rr0 = m_rr0; + + LOGINT(("%s %c %s <- %02x\n",tag(), 'A' + m_index, FUNCNAME, m_rr0)); + if (m_extint_latch == 1) + { + rr0 &= ((~m_wr15) | WR15_WR7PRIME | WR15_STATUS_FIFO); // clear enabled bits, saving 2 unrelated bits + rr0 |= (m_extint_states & ~((~m_wr15) | WR15_WR7PRIME | WR15_STATUS_FIFO)); // set enabled bits to latched states + LOGINT(("- %c returning latched value RR0:%02x WR15:%02x => %02x\n", 'A' + m_index, m_rr0, m_wr15, rr0)); + } + else + { + LOGINT(("- %c returning unlatched value: %02x\n", 'A' + m_index, rr0)); + } + + return rr0; } /* @@ -1311,7 +1351,7 @@ on the state of the Status High/Status Low bit in WR9 and independent of the sta in WR9."*/ uint8_t z80scc_channel::do_sccreg_rr2() { - LOGR(("%s\n", FUNCNAME)); + LOGINT(("%s\n", FUNCNAME)); // Assume the unmodified in polled mode m_rr2 = m_uart->m_chanA->m_wr2; @@ -1351,7 +1391,7 @@ B, all 0s are returned. The two unused bits are always returned as 0. Figure dis */ uint8_t z80scc_channel::do_sccreg_rr3() { - LOGR(("%s\n", FUNCNAME)); + LOGINT(("%s(%02x)\n", FUNCNAME, m_rr3)); return m_rr3; // TODO Update all bits of this status register } @@ -1564,7 +1604,7 @@ uint8_t z80scc_channel::scc_register_read( uint8_t reg) uint8_t z80scc_channel::control_read() { uint8_t data = 0; - int reg = m_uart->m_wr0_ptrbits; + int reg = m_uart->m_wr0_ptrbits; int regmask = (WR0_REGISTER_MASK | (m_uart->m_wr0_ptrbits & WR0_POINT_HIGH)); LOGR(("%s(%02x) reg %02x, regmask %02x, WR0 %02x\n", FUNCNAME, data, reg, regmask, m_wr0)); @@ -1644,12 +1684,12 @@ void z80scc_channel::do_sccreg_wr0(uint8_t data) External/Status interrupt. However, if this second status change does not persist (there are two transitions), another interrupt is not generated. Exceptions to this rule are detailed in the RR0 description.*/ - // do_sccreg_wr0(data); - if (!m_zc) - { - m_rr0 |= RR0_ZC; - } - LOG(("\"%s\" %s: %c : %s - Reset External/Status Interrupt\n", m_owner->tag(), FUNCNAME, 'A' + m_index, FUNCNAME)); + + LOG(("%s %s %c - Reset External/Status Interrupt, latch %s\n", m_owner->tag(), FUNCNAME, 'A' + m_index, + m_extint_latch == 1? "is released" : "was already released")); + // Release latch if no other external or status sources are active + if ((m_extint_latch = m_uart->update_extint(m_index)) == 0) + m_uart->check_interrupts(); break; case WR0_RESET_HIGHEST_IUS: /* This command resets the highest priority Interrupt Under Service (IUS) bit, allowing lower @@ -1659,12 +1699,23 @@ void z80scc_channel::do_sccreg_wr0(uint8_t data) if (m_uart->m_variant & (SET_NMOS)) { logerror("WR0 SWI ack command not supported on NMOS\n"); - LOG(("\"%s\" %s: %c : Reset Highest IUS command not available on NMOS!\n", m_owner->tag(), FUNCNAME, 'A' + m_index)); + LOGINT(("\"%s\" %s: %c : Reset Highest IUS command not available on NMOS!\n", m_owner->tag(), FUNCNAME, 'A' + m_index)); } else { - m_uart->z80daisy_irq_ack(); - LOG(("\"%s\" %s: %c : Reset Highest IUS\n", m_owner->tag(), FUNCNAME, 'A' + m_index)); + LOGINT(("\"%s\" %s: %c : Reset Highest IUS\n", m_owner->tag(), FUNCNAME, 'A' + m_index)); + // loop over all interrupt sources + for (auto & elem : m_uart->m_int_state) + { + // find the first channel with an interrupt requested + if (elem & Z80_DAISY_INT) + { + LOG(("- %c found IUS bit to clear\n", 'A' + m_index)); + elem = 0; // Clear IUS bit (called IEO in z80 daisy lingo) + m_uart->check_interrupts(); + break; + } + } } break; case WR0_ERROR_RESET: @@ -1839,15 +1890,15 @@ void z80scc_channel::do_sccreg_wr9(uint8_t data) LOG(("\"%s\": %c : Master Interrupt Control - No reset %02x\n", m_owner->tag(), 'A' + m_index, data)); break; case WR9_CMD_CHNB_RESET: - LOG(("\"%s\": %c : Master Interrupt Control - Channel B reset %02x\n", m_owner->tag(), 'A' + m_index, data)); + LOGINT(("\"%s\": %c : Master Interrupt Control - Channel B reset %02x\n", m_owner->tag(), 'A' + m_index, data)); m_uart->m_chanB->reset(); break; case WR9_CMD_CHNA_RESET: - LOG(("\"%s\": %c : Master Interrupt Control - Channel A reset %02x\n", m_owner->tag(), 'A' + m_index, data)); + LOGINT(("\"%s\": %c : Master Interrupt Control - Channel A reset %02x\n", m_owner->tag(), 'A' + m_index, data)); m_uart->m_chanA->reset(); break; case WR9_CMD_HW_RESET: - LOG(("\"%s\": %c : Master Interrupt Control - Device reset %02x\n", m_owner->tag(), 'A' + m_index, data)); + LOGINT(("\"%s\": %c : Master Interrupt Control - Device reset %02x\n", m_owner->tag(), 'A' + m_index, data)); /*"The effects of this command are identical to those of a hardware reset, except that the Shift Right/Shift Left bit is not changed and the MIE, Status High/Status Low and DLC bits take the programmed values that accompany this command." */ @@ -2304,7 +2355,7 @@ void z80scc_channel::data_write(uint8_t data) if (m_tx_fifo_sz == 1) { LOGTX(("- TX FIFO has only one slot so is now completelly filled, clearing TBE bit\n")); - m_rr0 &= ~RR0_TX_BUFFER_EMPTY; // If only one FIFO position it is full now! + m_rr0 &= ~RR0_TX_BUFFER_EMPTY; // If only one FIFO position it is full now! } else if (m_tx_fifo_wp + 1 == m_tx_fifo_rp || ( (m_tx_fifo_wp + 1 == m_tx_fifo_sz) && (m_tx_fifo_rp == 0) )) { @@ -2422,7 +2473,7 @@ WRITE_LINE_MEMBER( z80scc_channel::cts_w ) { LOG(("\"%s\" %s: %c : CTS %u\n", m_owner->tag(), FUNCNAME, 'A' + m_index, state)); - if (m_cts != state) + if ((m_rr0 & RR0_CTS) != (state ? RR0_CTS : 0)) // SCC change detection logic { // enable transmitter if in auto enables mode if (!state) @@ -2435,33 +2486,18 @@ WRITE_LINE_MEMBER( z80scc_channel::cts_w ) } } - // set clear to send - m_cts = state; + if (state) m_rr0 |= RR0_CTS; else m_rr0 &= ~RR0_CTS; // Raw pin/status value - if (!m_rx_rr0_latch) - { - LOGCTS((" - RR0 not latched so updating RR0 with CTS state\n")); - if (!m_cts) - m_rr0 |= RR0_CTS; - else - m_rr0 &= ~RR0_CTS; + if (m_extint_latch == 0 && (m_wr1 & WR1_EXT_INT_ENABLE) && (m_wr15 & WR15_CTS)) + { + // trigger interrupt + LOGCTS((" - Trigger CTS interrupt\n")); + m_uart->trigger_interrupt(m_index, INT_EXTERNAL); - /* If the CTS IE bit in WR15 is set, this bit indicates the state of the /CTS pin while no interrupt is - pending, latches the state of the /CTS pin and generates an External/Status interrupt. Any odd - number of transitions on the /CTS pin causes another External/Status interrupt condition. If the - CTS IE bit is reset, it merely reports the current unlatched state of the /CTS pin. - - Check that external interrupts are enabled and this one in particular and generate an interrupt on any change */ - if ((m_wr1 & WR1_EXT_INT_ENABLE) && (m_wr15 & WR15_CTS)) - { - // trigger interrupt - LOGCTS((" - Trigger CTS interrupt\n")); - m_uart->trigger_interrupt(m_index, INT_EXTERNAL); - - // latch read register 0 - LOGCTS((" - Latches RR0\n")); - m_rx_rr0_latch = 1; - } + // latch read register 0 + LOGCTS((" - Latches RR0\n")); + m_extint_latch = 1; + m_extint_states = m_rr0; } } } @@ -2472,17 +2508,17 @@ WRITE_LINE_MEMBER( z80scc_channel::cts_w ) //------------------------------------------------- WRITE_LINE_MEMBER( z80scc_channel::dcd_w ) { - LOG(("\"%s\": %c : DCD %u\n", m_owner->tag(), 'A' + m_index, state)); + // LOG(("\"%s\": %c : DCD %u\n", m_owner->tag(), 'A' + m_index, state)); - if (m_dcd != state) + if ((m_rr0 & RR0_DCD) != (state ? RR0_DCD : 0)) // SCC change detection logic { - if (!state) + // enable transmitter if in auto enables mode + if (!state) { - LOGDCD((" - DCD active\n")); - // enable receiver if in auto enables mode + // LOGDCD((" - DCD active\n")); if (m_wr3 & WR3_AUTO_ENABLES) { - LOGCTS((" - RX auto enabled\n")); + LOGDCD((" - RX auto enabled\n")); m_wr3 |= WR3_RX_ENABLE; #if START_BIT_HUNT m_rcv_mode = RCV_SEEKING; @@ -2490,39 +2526,18 @@ WRITE_LINE_MEMBER( z80scc_channel::dcd_w ) } } - // set data carrier detect - m_dcd = state; + if (state) m_rr0 |= RR0_DCD; else m_rr0 &= ~RR0_DCD; // Raw pin/status value -/*About RR0 D3: If the DCD IE bit in WR15 is set, this bit indicates the state of the /DCD pin the last time the -Enabled External/Status bits changed. Any transition on the /DCD pin, while no interrupt is pending, -latches the state of the /DCD pin and generates an External/Status interrupt. Any odd number -of transitions on the /DCD pin while another External/Status interrupt condition. If the DCD IE is -reset, this bit merely reports the current, unlatched state of the /DCD pin.*/ - if (!m_rx_rr0_latch) + if (m_extint_latch == 0 && (m_wr1 & WR1_EXT_INT_ENABLE) && (m_wr15 & WR15_DCD)) { - LOGDCD((" - RR0 not latched so updating RR0 with DCD state\n")); - if (m_dcd) - m_rr0 |= RR0_DCD; - else - m_rr0 &= ~RR0_DCD; + // latch read register 0 + LOGDCD((" - Latches RR0\n")); + m_extint_latch = 1; + m_extint_states = m_rr0; - /* If the DCD IE bit in WR15 is set, this bit indicates the state of the /DCD pin the last time the - Enabled External/Status bits changed. Any transition on the /DCD pin, while no interrupt is pending, - latches the state of the /DCD pin and generates an External/Status interrupt. Any odd number - of transitions on the /DCD pin while another External/Status interrupt condition. If the DCD IE is - reset, this bit merely reports the current, unlatched state of the /DCD pin. - - Check that external interrupts are enabled and this one in particular and generate an interrupt on any change */ - if ((m_wr1 & WR1_EXT_INT_ENABLE) && (m_wr15 & WR15_DCD)) - { - // trigger interrupt - LOGDCD((" - Trigger DCD interrupt\n")); - m_uart->trigger_interrupt(m_index, INT_EXTERNAL); - - // latch read register 0 - LOGDCD((" - Latches RR0\n")); - m_rx_rr0_latch = 1; - } + // trigger interrupt + LOGDCD((" - Trigger DCD interrupt\n")); + m_uart->trigger_interrupt(m_index, INT_EXTERNAL); } } } @@ -2531,11 +2546,11 @@ reset, this bit merely reports the current, unlatched state of the /DCD pin.*/ //------------------------------------------------- // ri_w - ring indicator handler //------------------------------------------------- - WRITE_LINE_MEMBER( z80scc_channel::ri_w ) { - LOG(("\"%s\": %c : RI %u\n", m_owner->tag(), 'A' + m_index, state)); + LOGINT(("\"%s\": %c : RI %u - not implemented\n", m_owner->tag(), 'A' + m_index, state)); +#if 0 // TODO: This code is inherited from another device driver and not correct for SCC if (m_ri != state) { // set ring indicator state @@ -2558,6 +2573,7 @@ WRITE_LINE_MEMBER( z80scc_channel::ri_w ) } } } +#endif } //------------------------------------------------- @@ -2565,7 +2581,7 @@ WRITE_LINE_MEMBER( z80scc_channel::ri_w ) //------------------------------------------------- WRITE_LINE_MEMBER( z80scc_channel::sync_w ) { - LOG(("\"%s\": %c : SYNC %u\n", m_owner->tag(), 'A' + m_index, state)); + LOGINT(("\"%s\": %c : SYNC %u - not implemented\n", m_owner->tag(), 'A' + m_index, state)); } //------------------------------------------------- @@ -2744,11 +2760,11 @@ void z80scc_channel::update_serial() set_rcv_rate(0); set_tra_rate(0); } - // TODO: Check registers for use of RTxC and TRxC, if used as direct Tx and/or Rx clocks set them to value as programmed + // TODO: Check registers for use of RTxC and TRxC, if used as direct Tx and/or Rx clocks set them to value as programmed // in m_uart->txca/txcb and rxca/rxcb respectivelly if (m_rxc > 0) { - set_rcv_rate(m_rxc / clocks); // TODO Check/Fix this to get the right tx/rx clocks, seems to be missing a divider or two + set_rcv_rate(m_rxc / clocks); // TODO Check/Fix this to get the right tx/rx clocks, seems to be missing a divider or two LOG((" - Receiver clock: %d mode: %d rate: %d/%xh\n", m_rxc, clocks, m_rxc / clocks, m_rxc / clocks)); } diff --git a/src/devices/machine/z80scc.h b/src/devices/machine/z80scc.h index 2e0f22fdfe1..6884221fcf0 100644 --- a/src/devices/machine/z80scc.h +++ b/src/devices/machine/z80scc.h @@ -273,7 +273,15 @@ protected: INT_TRANSMIT = 0, INT_EXTERNAL = 1, INT_RECEIVE = 2, - INT_SPECIAL = 3 + INT_SPECIAL = 3, + }; + + enum + { + INT_TRANSMIT_PRIO = 1, + INT_EXTERNAL_PRIO = 0, + INT_RECEIVE_PRIO = 2, + INT_SPECIAL_PRIO = 0, }; // Read registers @@ -320,11 +328,10 @@ protected: enum { - RR0_RX_CHAR_AVAILABLE = 0x01, // SIO bit - RR0_ZC = 0x02, // SCC bit - RR0_TX_BUFFER_EMPTY = 0x04, // SIO - RR0_DCD = 0x08, // SIO - RR0_RI = 0x10, // DART bit? TODO: investigate function and remove + RR0_RX_CHAR_AVAILABLE = 0x01, + RR0_ZC = 0x02, + RR0_TX_BUFFER_EMPTY = 0x04, + RR0_DCD = 0x08, RR0_SYNC_HUNT = 0x10, // SIO bit, not supported RR0_CTS = 0x20, // SIO bit RR0_TX_UNDERRUN = 0x40, // SIO bit, not supported @@ -573,12 +580,12 @@ protected: int m_rx_clock; // receive clock pulse count int m_rx_first; // first character received int m_rx_break; // receive break condition - uint8_t m_rx_rr0_latch; // read register 0 latched + + uint8_t m_extint_latch; // external/status Int latch enable + uint8_t m_extint_states; // external/status Int latches state int m_rxd; int m_ri; // ring indicator latch - int m_cts; // clear to send latch - int m_dcd; // data carrier detect latch // transmitter state uint8_t m_tx_data_fifo[4]; // data FIFO @@ -587,7 +594,6 @@ protected: int m_tx_fifo_wp; // FIFO write pointer int m_tx_fifo_sz; // FIFO size uint8_t m_tx_error; // current error - // uint8_t m_tx_data; // transmit data register int m_tx_clock; // transmit clock pulse count int m_dtr; // data terminal ready @@ -687,6 +693,9 @@ public: DECLARE_WRITE_LINE_MEMBER( rxtxcb_w ) { m_chanB->rxc_w(state); m_chanB->txc_w(state); } DECLARE_WRITE_LINE_MEMBER( synca_w ) { m_chanA->sync_w(state); } DECLARE_WRITE_LINE_MEMBER( syncb_w ) { m_chanB->sync_w(state); } + int update_extint(int i ); + int get_extint_priority(int type); + protected: // device-level overrides