summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine
diff options
context:
space:
mode:
author 68bit <info@68bit.org>2020-05-21 22:07:52 +1000
committer 68bit <info@68bit.org>2020-05-21 22:27:46 +1000
commit52c7b830a9e11c3ae53b4930e2f4e48129f96cfc (patch)
treeb033b742256a967d9dba90aff0d74d9485bf5f7e /src/devices/machine
parent60592a35f64c9b23650c779d5baa7d8fd18ea2bf (diff)
mc6850: TDRE should read clear in reset, and set coming out of reset
Fixes a lockup running UniFlex on the SWTPC09. Tested on hardware, the TDRE flag reads as zero in the reset state and reads as set when taken out of reset, and even if data has been written to the data register while in the reset state.
Diffstat (limited to 'src/devices/machine')
-rw-r--r--src/devices/machine/6850acia.cpp37
1 files changed, 23 insertions, 14 deletions
diff --git a/src/devices/machine/6850acia.cpp b/src/devices/machine/6850acia.cpp
index efd557daff1..0a89b94d337 100644
--- a/src/devices/machine/6850acia.cpp
+++ b/src/devices/machine/6850acia.cpp
@@ -159,13 +159,13 @@ uint8_t acia6850_device::status_r()
{
uint8_t status = m_status;
- if (!machine().side_effects_disabled())
+ if (m_divide == 0 || (status & SR_CTS))
{
- if (status & SR_CTS)
- {
- status &= ~SR_TDRE;
- }
+ status &= ~SR_TDRE;
+ }
+ if (!machine().side_effects_disabled())
+ {
if (m_dcd_irq_pending == DCD_IRQ_READ_STATUS)
{
m_dcd_irq_pending = DCD_IRQ_READ_DATA;
@@ -219,9 +219,13 @@ void acia6850_device::control_w(uint8_t data)
m_tx_state = STATE_START;
output_txd(1);
- /// TODO: find out whether this has any immediate effect on TDRE
- /// TDRE probably shouldn't be cleared here if TDR wasn't loaded, despite what the datasheet implies
- /// If TDRE is cleared, then a separate internal flag is needed to avoid transmitting a spurious first character
+ // TDRE flag reads as zero in this reset state, but the drivers
+ // internal SR_TDRE is masked elsewhere when in the reset
+ // state. When taken out of reset the TDRE flag reads as one.
+ m_status |= SR_TDRE;
+
+ // SR_CTS is not affected by a reset, it should still reflect
+ // the pin status.
m_status &= SR_CTS | SR_TDRE;
if (m_dcd)
@@ -238,12 +242,12 @@ void acia6850_device::control_w(uint8_t data)
int acia6850_device::calculate_txirq()
{
- return !(m_tx_irq_enable && ((m_status & SR_TDRE) && !(m_status & SR_CTS)));
+ return !(m_tx_irq_enable && m_divide && (m_status & SR_TDRE) && !(m_status & SR_CTS));
}
int acia6850_device::calculate_rxirq()
{
- return !(m_rx_irq_enable && ((m_status & SR_RDRF) || m_dcd_irq_pending != DCD_IRQ_NONE));
+ return !(m_rx_irq_enable && m_divide && ((m_status & SR_RDRF) || m_dcd_irq_pending != DCD_IRQ_NONE));
}
void acia6850_device::update_irq()
@@ -255,15 +259,20 @@ void acia6850_device::data_w(uint8_t data)
{
LOG("MC6850 '%s' Data: %02x\n", tag(), data);
- /// TODO: find out if data stored during master reset is sent after divider is set (and if TDRE can be cleared by such a write)
if (m_divide == 0)
{
logerror("%s: ACIA data write while in reset!\n", machine().describe_context());
}
+ else
+ {
+ // TDRE reads as set when taken out of reset even if data is
+ // written while in reset.
- /// TODO: find out whether this overwrites previous data or has no effect if TDRE is already clear when you write
- m_tdr = data;
- m_status &= ~SR_TDRE;
+ // TODO: find out whether this overwrites previous data or has
+ // no effect if TDRE is already clear when you write?
+ m_tdr = data;
+ m_status &= ~SR_TDRE;
+ }
update_irq();
}