From 0c5035fc56812a5d52ddd602847224ee5d8b9ea4 Mon Sep 17 00:00:00 2001 From: Seth Morabito Date: Sat, 25 Jan 2014 19:53:53 -0800 Subject: [PATCH] Add interrupt flag to CPU --- src/main/java/com/loomcom/symon/Bus.java | 12 ++ src/main/java/com/loomcom/symon/Cpu.java | 25 ++- src/test/java/com/loomcom/symon/BusTest.java | 216 ++++++++++--------- 3 files changed, 151 insertions(+), 102 deletions(-) diff --git a/src/main/java/com/loomcom/symon/Bus.java b/src/main/java/com/loomcom/symon/Bus.java index 0122593..429853b 100644 --- a/src/main/java/com/loomcom/symon/Bus.java +++ b/src/main/java/com/loomcom/symon/Bus.java @@ -151,6 +151,18 @@ public class Bus { throw new MemoryAccessException("Bus write failed. No device at address " + String.format("$%04X", address)); } + public void assertInterrupt() { + if (cpu != null) { + cpu.assertInterrupt(); + } + } + + public void clearInterrupt() { + if (cpu != null) { + cpu.clearInterrupt(); + } + } + public SortedSet getDevices() { // Expose a copy of the device list, not the original return new TreeSet(devices); diff --git a/src/main/java/com/loomcom/symon/Cpu.java b/src/main/java/com/loomcom/symon/Cpu.java index 4b19002..c5ab304 100644 --- a/src/main/java/com/loomcom/symon/Cpu.java +++ b/src/main/java/com/loomcom/symon/Cpu.java @@ -113,7 +113,9 @@ public class Cpu implements InstructionTable { * Reset the CPU to known initial values. */ public void reset() throws MemoryAccessException { - // Registers + /* TODO: In reality, the stack pointer could be anywhere + on the stack after reset. This non-deterministic behavior might be + worth while to simulate. */ state.sp = 0xff; // Set the PC to the address stored in the reset vector @@ -131,6 +133,8 @@ public class Cpu implements InstructionTable { state.overflowFlag = false; state.negativeFlag = false; + state.interruptAsserted = false; + // Clear illegal opcode trap. state.opTrap = false; @@ -1161,6 +1165,20 @@ public class Cpu implements InstructionTable { return state.getStatusFlag(); } + /** + * Simulate transition from logic-high to logic-low on the INT line. + */ + public void assertInterrupt() { + state.interruptAsserted = true; + } + + /** + * Simulate transition from logic-low to logic-high of the INT line. + */ + public void clearInterrupt() { + state.interruptAsserted = false; + } + /** * Push an item onto the stack, and decrement the stack counter. * Will wrap-around if already at the bottom of the stack (This @@ -1305,6 +1323,8 @@ public class Cpu implements InstructionTable { public int[] args = new int[2]; public int instSize; public boolean opTrap; + /* True if the INT line was held low */ + public boolean interruptAsserted; /* Status Flag Register bits */ public boolean carryFlag; @@ -1341,6 +1361,7 @@ public class Cpu implements InstructionTable { this.args[1] = s.args[1]; this.instSize = s.instSize; this.opTrap = s.opTrap; + this.interruptAsserted = s.interruptAsserted; this.carryFlag = s.carryFlag; this.negativeFlag = s.negativeFlag; this.zeroFlag = s.zeroFlag; @@ -1349,7 +1370,7 @@ public class Cpu implements InstructionTable { this.breakFlag = s.breakFlag; this.overflowFlag = s.overflowFlag; this.stepCounter = s.stepCounter; - } + } /** * Returns a string formatted for the trace log. diff --git a/src/test/java/com/loomcom/symon/BusTest.java b/src/test/java/com/loomcom/symon/BusTest.java index f4aedd0..f2eb35a 100644 --- a/src/test/java/com/loomcom/symon/BusTest.java +++ b/src/test/java/com/loomcom/symon/BusTest.java @@ -10,113 +10,129 @@ import com.loomcom.symon.exceptions.*; */ public class BusTest extends TestCase { - public BusTest(String testName) { - super(testName); - } - - public static Test suite() { - return new TestSuite(BusTest.class); - } - - public void testCreatingWithStartAndEndAddresses() { - Bus b = null; - - b = new Bus(0x00, 0xff); - assertEquals(0x00, b.startAddress()); - assertEquals(0xff, b.endAddress()); - - b = new Bus(0x20, 0xea); - assertEquals(0x20, b.startAddress()); - assertEquals(0xea, b.endAddress()); - } - - public void testCreatingWithSize() { - Bus b = null; - - b = new Bus(256); - assertEquals(0x00, b.startAddress()); - assertEquals(0xff, b.endAddress()); - - b = new Bus(4096); - assertEquals(0x000, b.startAddress()); - assertEquals(0xfff, b.endAddress()); - - b = new Bus(65536); - assertEquals(0x0000, b.startAddress()); - assertEquals(0xffff, b.endAddress()); - } - - public void testAddDevice() throws MemoryRangeException { - Device memory = new Memory(0x0000, 0x00ff, true); - Device rom = new Memory(0x0100, 0x02ff, false); - - Bus b = new Bus(0x0000, 0xffff); - - assertEquals(0, b.getDevices().size()); - b.addDevice(memory); - assertEquals(1, b.getDevices().size()); - b.addDevice(rom); - assertEquals(2, b.getDevices().size()); - } - - public void testOverlappingDevicesShouldFail() throws MemoryRangeException { - Device memory = new Memory(0x0000, 0x0100, true); - Device rom = new Memory(0x00ff, 0x0200, false); - - Bus b = new Bus(0x0000, 0xffff); - - b.addDevice(memory); - - try { - b.addDevice(rom); - fail("Should have thrown a MemoryRangeException."); - } catch (MemoryRangeException ex) { - // expected + public BusTest(String testName) { + super(testName); } - } - public void testIsCompleteWithFirstDeviceNotStartingAtStartAddress() throws MemoryRangeException { - Device memory = new Memory(0x00ff, 0xff00, true); + public static Test suite() { + return new TestSuite(BusTest.class); + } - Bus b = new Bus(0x0000, 0xffff); - assertFalse("Address space was unexpectedly complete!", b.isComplete()); - b.addDevice(memory); - assertFalse("Address space was unexpectedly complete!", b.isComplete()); - } + public void testCreatingWithStartAndEndAddresses() { + Bus b = null; - public void testIsCompleteWithOneDevice() throws MemoryRangeException { - Device memory = new Memory(0x0000, 0xffff, true); - Bus b = new Bus(0x0000, 0xffff); - assertFalse("Address space was unexpectedly complete!", b.isComplete()); - b.addDevice(memory); - assertTrue("Address space should have been complete!", b.isComplete()); - } + b = new Bus(0x00, 0xff); + assertEquals(0x00, b.startAddress()); + assertEquals(0xff, b.endAddress()); - public void testIsCompleteWithTwoDevices() throws MemoryRangeException { - Device memory = new Memory(0x0000, 0x7fff, true); - Device rom = new Memory(0x8000, 0xffff, false); + b = new Bus(0x20, 0xea); + assertEquals(0x20, b.startAddress()); + assertEquals(0xea, b.endAddress()); + } - Bus b = new Bus(0x0000, 0xffff); - assertFalse("Address space was unexpectedly complete!", b.isComplete()); - b.addDevice(memory); - assertFalse("Address space was unexpectedly complete!", b.isComplete()); - b.addDevice(rom); - assertTrue("Address space should have been complete!", b.isComplete()); - } + public void testCreatingWithSize() { + Bus b = null; - public void testIsCompleteWithThreeDevices() throws MemoryRangeException { - Device memory = new Memory(0x0000, 0x7fff, true); - Device rom1 = new Memory(0x8000, 0xBfff, false); - Device rom2 = new Memory(0xC000, 0xffff, false); + b = new Bus(256); + assertEquals(0x00, b.startAddress()); + assertEquals(0xff, b.endAddress()); - Bus b = new Bus(0x0000, 0xffff); - assertFalse("Address space was unexpectedly complete!", b.isComplete()); - b.addDevice(memory); - assertFalse("Address space was unexpectedly complete!", b.isComplete()); - b.addDevice(rom1); - assertFalse("Address space was unexpectedly complete!", b.isComplete()); - b.addDevice(rom2); - assertTrue("Address space should have been complete!", b.isComplete()); - } + b = new Bus(4096); + assertEquals(0x000, b.startAddress()); + assertEquals(0xfff, b.endAddress()); + + b = new Bus(65536); + assertEquals(0x0000, b.startAddress()); + assertEquals(0xffff, b.endAddress()); + } + + public void testAddDevice() throws MemoryRangeException { + Device memory = new Memory(0x0000, 0x00ff, true); + Device rom = new Memory(0x0100, 0x02ff, false); + + Bus b = new Bus(0x0000, 0xffff); + + assertEquals(0, b.getDevices().size()); + b.addDevice(memory); + assertEquals(1, b.getDevices().size()); + b.addDevice(rom); + assertEquals(2, b.getDevices().size()); + } + + public void testOverlappingDevicesShouldFail() throws MemoryRangeException { + Device memory = new Memory(0x0000, 0x0100, true); + Device rom = new Memory(0x00ff, 0x0200, false); + + Bus b = new Bus(0x0000, 0xffff); + + b.addDevice(memory); + + try { + b.addDevice(rom); + fail("Should have thrown a MemoryRangeException."); + } catch (MemoryRangeException ex) { + // expected + } + } + + public void testIsCompleteWithFirstDeviceNotStartingAtStartAddress() throws MemoryRangeException { + Device memory = new Memory(0x00ff, 0xff00, true); + + Bus b = new Bus(0x0000, 0xffff); + assertFalse("Address space was unexpectedly complete!", b.isComplete()); + b.addDevice(memory); + assertFalse("Address space was unexpectedly complete!", b.isComplete()); + } + + public void testIsCompleteWithOneDevice() throws MemoryRangeException { + Device memory = new Memory(0x0000, 0xffff, true); + Bus b = new Bus(0x0000, 0xffff); + assertFalse("Address space was unexpectedly complete!", b.isComplete()); + b.addDevice(memory); + assertTrue("Address space should have been complete!", b.isComplete()); + } + + public void testIsCompleteWithTwoDevices() throws MemoryRangeException { + Device memory = new Memory(0x0000, 0x7fff, true); + Device rom = new Memory(0x8000, 0xffff, false); + + Bus b = new Bus(0x0000, 0xffff); + assertFalse("Address space was unexpectedly complete!", b.isComplete()); + b.addDevice(memory); + assertFalse("Address space was unexpectedly complete!", b.isComplete()); + b.addDevice(rom); + assertTrue("Address space should have been complete!", b.isComplete()); + } + + public void testIsCompleteWithThreeDevices() throws MemoryRangeException { + Device memory = new Memory(0x0000, 0x7fff, true); + Device rom1 = new Memory(0x8000, 0xBfff, false); + Device rom2 = new Memory(0xC000, 0xffff, false); + + Bus b = new Bus(0x0000, 0xffff); + assertFalse("Address space was unexpectedly complete!", b.isComplete()); + b.addDevice(memory); + assertFalse("Address space was unexpectedly complete!", b.isComplete()); + b.addDevice(rom1); + assertFalse("Address space was unexpectedly complete!", b.isComplete()); + b.addDevice(rom2); + assertTrue("Address space should have been complete!", b.isComplete()); + } + + public void testSetAndClearInterrupt() throws Exception { + Bus b = new Bus(0x0000, 0xffff); + Cpu c = new Cpu(); + b.addCpu(c); + + assertFalse(c.getCpuState().interruptAsserted); + + b.assertInterrupt(); + + assertTrue(c.getCpuState().interruptAsserted); + + b.clearInterrupt(); + + assertFalse(c.getCpuState().interruptAsserted); + } }