diff --git a/src/main/java/com/loomcom/symon/devices/Acia6850.java b/src/main/java/com/loomcom/symon/devices/Acia6850.java index bd70eed..e957bb4 100644 --- a/src/main/java/com/loomcom/symon/devices/Acia6850.java +++ b/src/main/java/com/loomcom/symon/devices/Acia6850.java @@ -30,8 +30,8 @@ import com.loomcom.symon.exceptions.MemoryRangeException; /** * This is a simulation of the Motorola 6850 ACIA, with limited - * functionality. Interrupts are not supported. - *

+ * functionality. + * * Unlike a 16550 UART, the 6850 ACIA has only one-byte transmit and * receive buffers. It is the programmer's responsibility to check the * status (full or empty) for transmit and receive buffers before @@ -56,9 +56,6 @@ public class Acia6850 extends Acia { public int read(int address, boolean cpuAccess) throws MemoryAccessException { switch (address) { case RX_REG: - if (cpuAccess) { - interrupt = false; - } return rxRead(cpuAccess); case STAT_REG: return statusReg(cpuAccess); @@ -72,9 +69,6 @@ public class Acia6850 extends Acia { public void write(int address, int data) throws MemoryAccessException { switch (address) { case TX_REG: - if (cpuAccess) { - interrupt = false; - } txWrite(data); break; case CTRL_REG: @@ -119,6 +113,10 @@ public class Acia6850 extends Acia { stat |= 0x80; } + if (cpuAccess) { + interrupt = false; + } + return stat; } diff --git a/src/test/java/com/loomcom/symon/AciaTest6850.java b/src/test/java/com/loomcom/symon/Acia6850Test.java similarity index 63% rename from src/test/java/com/loomcom/symon/AciaTest6850.java rename to src/test/java/com/loomcom/symon/Acia6850Test.java index 0f7425c..e37539d 100644 --- a/src/test/java/com/loomcom/symon/AciaTest6850.java +++ b/src/test/java/com/loomcom/symon/Acia6850Test.java @@ -7,7 +7,7 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.*; -public class AciaTest6850 { +public class Acia6850Test { private final static int CMD_STAT_REG = 0; private final static int DATA_REG = 1; @@ -91,6 +91,78 @@ public class AciaTest6850 { verify(mockBus, never()).assertIrq(); } + @Test + public void shouldTriggerInterruptFlagOnRxFullIfRxIrqEnabled() throws Exception { + Bus mockBus = mock(Bus.class); + + Acia acia = newAcia(); + acia.setBus(mockBus); + + // Disable TX IRQ, Enable RX IRQ + acia.write(CMD_STAT_REG, 0x80); + + acia.rxWrite('a'); + + // Receive should cause IRQ flag to be set + assertEquals(0x80, acia.read(0x0000, true) & 0x80); + } + + @Test + public void shouldNotTriggerInterruptFlagOnRxFullIfRxIrqNotEnabled() throws Exception { + Bus mockBus = mock(Bus.class); + + Acia acia = newAcia(); + acia.setBus(mockBus); + + // Disable TX IRQ, Disable RX IRQ + acia.write(CMD_STAT_REG, 0x00); + + acia.rxWrite('a'); + + // Receive should not cause IRQ flag to be set + assertEquals(0x00, acia.read(0x0000, true) & 0x80); + } + + @Test + public void shouldTriggerInterruptFlagOnTxEmptyIfTxIrqEnabled() throws Exception { + Bus mockBus = mock(Bus.class); + + Acia acia = newAcia(); + acia.setBus(mockBus); + + // Enable TX IRQ, Disable RX IRQ + acia.write(CMD_STAT_REG, 0x20); + + // Write data + acia.write(1, 'a'); + + verify(mockBus, never()).assertIrq(); + + // Transmission should cause IRQ flag to be set + acia.txRead(true); + + assertEquals(0x80, acia.read(0x0000, true) & 0x80); + } + + @Test + public void shouldNotTriggerInterruptFlagOnTxEmptyIfTxIrqNotEnabled() throws Exception { + Bus mockBus = mock(Bus.class); + + Acia acia = newAcia(); + acia.setBus(mockBus); + + // Disable TX IRQ, Disable RX IRQ + acia.write(CMD_STAT_REG, 0x02); + + // Write data + acia.write(DATA_REG, 'a'); + + // Transmission should not cause IRQ flag to be set + acia.txRead(true); + + assertEquals(0x00, acia.read(0x0000, true) & 0x80); + } + @Test public void newAciaShouldHaveTxEmptyStatus() throws Exception { Acia acia = newAcia(); @@ -129,6 +201,24 @@ public class AciaTest6850 { @Test public void aciaShouldOverrunAndReadShouldReset() throws Exception { + + Acia acia = newAcia(); + + // overrun ACIA + acia.rxWrite('a'); + acia.rxWrite('b'); + + assertEquals(0x20, acia.read(CMD_STAT_REG, true) & 0x20); + + // read should reset + acia.rxRead(true); + assertEquals(0x00, acia.read(CMD_STAT_REG, true) & 0x20); + + } + + @Test + public void aciaShouldOverrunAndMemoryWindowReadShouldNotReset() + throws Exception { Acia acia = newAcia(); @@ -138,9 +228,9 @@ public class AciaTest6850 { assertEquals(0x20, acia.read(CMD_STAT_REG, true) & 0x20); - // read should reset - acia.rxRead(true); - assertEquals(0x00, acia.read(CMD_STAT_REG, true) & 0x20); + // memory window read should not reset + acia.rxRead(false); + assertEquals(0x20, acia.read(CMD_STAT_REG, true) & 0x20); } diff --git a/src/test/java/com/loomcom/symon/AciaTest.java b/src/test/java/com/loomcom/symon/AciaTest.java index 4e5bb1f..ba29b27 100644 --- a/src/test/java/com/loomcom/symon/AciaTest.java +++ b/src/test/java/com/loomcom/symon/AciaTest.java @@ -73,12 +73,84 @@ public class AciaTest { // Write data acia.write(0, 'a'); - // Transmission should cause IRQ + // Transmission should not cause IRQ acia.txRead(true); verify(mockBus, never()).assertIrq(); } + @Test + public void shouldTriggerInterruptFlagOnRxFullIfRxIrqEnabled() throws Exception { + Bus mockBus = mock(Bus.class); + + Acia acia = new Acia6551(0x000); + acia.setBus(mockBus); + + // Disable TX IRQ, Enable RX IRQ + acia.write(2, 0x00); + + acia.rxWrite('a'); + + // Receive should cause IRQ flag to be set + assertEquals(0x80, acia.read(0x0001, true) & 0x80); + } + + @Test + public void shouldNotTriggerInterruptFlagOnRxFullIfRxIrqNotEnabled() throws Exception { + Bus mockBus = mock(Bus.class); + + Acia acia = new Acia6551(0x000); + acia.setBus(mockBus); + + // Disable TX IRQ, Disable RX IRQ + acia.write(2, 0x02); + + acia.rxWrite('a'); + + // Receive should not cause IRQ flag to be set + assertEquals(0x00, acia.read(0x0001, true) & 0x80); + } + + @Test + public void shouldTriggerInterruptFlagOnTxEmptyIfTxIrqEnabled() throws Exception { + Bus mockBus = mock(Bus.class); + + Acia acia = new Acia6551(0x000); + acia.setBus(mockBus); + + // Enable TX IRQ, Disable RX IRQ + acia.write(2, 0x06); + + // Write data + acia.write(0, 'a'); + + verify(mockBus, never()).assertIrq(); + + // Transmission should cause IRQ flag to be set + acia.txRead(true); + + assertEquals(0x80, acia.read(0x0001, true) & 0x80); + } + + @Test + public void shouldNotTriggerInterruptFlagOnTxEmptyIfTxIrqNotEnabled() throws Exception { + Bus mockBus = mock(Bus.class); + + Acia acia = new Acia6551(0x000); + acia.setBus(mockBus); + + // Disable TX IRQ, Disable RX IRQ + acia.write(2, 0x02); + + // Write data + acia.write(0, 'a'); + + // Transmission should not cause IRQ flag to be set + acia.txRead(true); + + assertEquals(0x00, acia.read(0x0001, true) & 0x80); + } + @Test public void newAciaShouldHaveTxEmptyStatus() throws Exception { Acia acia = new Acia6551(0x000);