1
0
mirror of https://github.com/sethm/symon.git synced 2024-06-20 10:29:33 +00:00

Tests for AddressDecoder. Fixed a bug in isComplete().

This commit is contained in:
Seth J. Morabito 2008-12-10 19:57:38 -08:00
parent af7743b385
commit 0e212e71e5
7 changed files with 229 additions and 32 deletions

View File

@ -4,30 +4,45 @@ import java.util.*;
public class AddressDecoder {
public static final int MEMORY_BOTTOM = 0x0000;
public static final int MEMORY_TOP = 0xFFFF;
private int bottom = 0x0000;
private int top = 0xffff;
/**
* Ordered map of memory ranges to IO devices.
* Ordered list of IO devices.
*/
private SortedMap<MemoryRange, Device> ioMap;
private List<Device> devices;
public AddressDecoder() {
ioMap = new TreeMap();
public AddressDecoder(int size) {
this(0, size - 1);
}
public void addDevice(Device d)
public AddressDecoder(int bottom, int top) {
this.devices = new ArrayList(8);
this.bottom = bottom;
this.top = top;
}
public int bottom() {
return bottom;
}
public int top() {
return top;
}
public void addDevice(Device device)
throws MemoryRangeException {
// Make sure there's no memory overlap.
for (MemoryRange memRange : ioMap.keySet()) {
MemoryRange memRange = device.getMemoryRange();
for (Device d : devices) {
if (d.getMemoryRange().overlaps(memRange)) {
throw new MemoryRangeException("The device being added overlaps " +
"with an existing device.");
}
}
// Add the device to the map.
ioMap.put(d.getMemoryRange(), d);
// Add the device
devices.add(device);
}
/**
@ -37,27 +52,32 @@ public class AddressDecoder {
*/
public boolean isComplete() {
// Emtpy maps cannot be complete.
if (ioMap.isEmpty()) { return false; }
if (devices.isEmpty()) { return false; }
// Loop over devices and ensure they are contiguous.
MemoryRange prev = null;
int i = 0;
int size = ioMap.size();
for (Map.Entry e : ioMap.entrySet()) {
MemoryRange cur = (MemoryRange)e.getKey();
int length = devices.size();
for (Device d : devices) {
MemoryRange cur = d.getMemoryRange();
if (i == 0) {
// If the first entry doesn't start at MEMORY_BOTTOM, return false.
if (cur.getStartAddress() != MEMORY_BOTTOM) { return false; }
} else if (i < size - 1) {
// If the first entry doesn't start at 'bottom', return false.
if (cur.getStartAddress() != bottom) { return false; }
}
if (prev != null && i < length - 1) {
// Otherwise, compare previous map's end against this map's
// top. They must be adjacent!
if (cur.getStartAddress() - 1 != prev.getEndAddress()) {
return false;
}
} else {
// If the last entry doesn't end at MEMORY_TOP, return false;
if (cur.getEndAddress() != MEMORY_TOP) { return false; }
}
if (i == length - 1) {
// If the last entry doesn't end at top, return false;
if (cur.getEndAddress() != top) { return false; }
}
i++;
prev = cur;
}
@ -66,10 +86,8 @@ public class AddressDecoder {
return true;
}
/**
* Returns true if there are any gap in the memory map.
*/
public boolean hasGaps() {
return !isComplete();
public List getDevices() {
// Expose a copy of the device list, not the original
return new ArrayList(devices);
}
}

View File

@ -9,14 +9,22 @@ public abstract class Device {
/** The memory range for this device. */
private MemoryRange memoryRange;
private String name;
/** Reference to the CPU, for interrupts. */
private Cpu cpu;
public Device(MemoryRange range, Cpu cpu) {
this.memoryRange = range;
public Device(int address, int size, String name, Cpu cpu)
throws MemoryRangeException {
this.memoryRange = new MemoryRange(address, address + size - 1);
this.name = name;
this.cpu = cpu;
}
public abstract void write(int address, int data);
public abstract int read(int address);
public MemoryRange getMemoryRange() {
return memoryRange;
}
@ -29,12 +37,12 @@ public abstract class Device {
return memoryRange.getStartAddress();
}
public void generateInterrupt() {
cpu.interrupt();
public String getName() {
return name;
}
public void generateNonMaskableInterrupt() {
cpu.nmiInterrupt();
public void setName(String name) {
this.name = name;
}
}

View File

@ -58,4 +58,12 @@ public class MemoryRange implements Comparable<MemoryRange> {
Integer thatStartAddr = new Integer(other.getStartAddress());
return thisStartAddr.compareTo(thatStartAddr);
}
public String toString() {
StringBuffer desc = new StringBuffer("@");
desc.append(String.format("0x%04x", startAddress));
desc.append("-");
desc.append(String.format("0x%04x", endAddress));
return desc.toString();
}
}

View File

@ -3,7 +3,7 @@ package com.loomcom.lm6502;
/**
* Exception that will be thrown if devices conflict in the IO map.
*/
class MemoryRangeException extends Exception {
public class MemoryRangeException extends Exception {
public MemoryRangeException(String msg) {
super(msg);
}

View File

@ -0,0 +1,27 @@
package com.loomcom.lm6502.devices;
import com.loomcom.lm6502.*;
public class Memory extends Device {
private boolean readOnly;
public Memory(int address, int size, Cpu cpu, boolean readOnly)
throws MemoryRangeException {
super(address, size, "RW Memory", cpu);
this.readOnly = readOnly;
}
public Memory(int address, int size, Cpu cpu)
throws MemoryRangeException {
this(address, size, cpu, false);
}
public void write(int address, int data) {
}
public int read(int address) {
return 0;
}
}

View File

@ -0,0 +1,125 @@
package com.loomcom.lm6502;
import junit.framework.*;
import com.loomcom.lm6502.devices.*;
import java.util.HashMap;
import java.util.Map;
/**
*
*/
public class AddressDecoderTest extends TestCase {
public AddressDecoderTest(String testName) {
super(testName);
}
public static Test suite() {
return new TestSuite(AddressDecoderTest.class);
}
public void testCreatingWithTopAndBottom() {
AddressDecoder ad = null;
ad = new AddressDecoder(0x00, 0xff);
assertEquals(0x00, ad.bottom());
assertEquals(0xff, ad.top());
ad = new AddressDecoder(0x20, 0xea);
assertEquals(0x20, ad.bottom());
assertEquals(0xea, ad.top());
}
public void testCreatingWithSize() {
AddressDecoder ad = null;
ad = new AddressDecoder(256);
assertEquals(0x00, ad.bottom());
assertEquals(0xff, ad.top());
ad = new AddressDecoder(4096);
assertEquals(0x000, ad.bottom());
assertEquals(0xfff, ad.top());
ad = new AddressDecoder(65536);
assertEquals(0x0000, ad.bottom());
assertEquals(0xffff, ad.top());
}
public void testAddDevice() throws MemoryRangeException {
Device memory = new Memory(0x0000, 0x0100, null, true);
Device rom = new Memory(0x0100, 0x0200, null, false);
AddressDecoder ad = new AddressDecoder(0x0000, 0xffff);
assertEquals(0, ad.getDevices().size());
ad.addDevice(memory);
assertEquals(1, ad.getDevices().size());
ad.addDevice(rom);
assertEquals(2, ad.getDevices().size());
}
public void testOverlappingDevicesShouldFail() throws MemoryRangeException {
Device memory = new Memory(0x0000, 0x0100, null, true);
Device rom = new Memory(0x00ff, 0x0200, null, false);
AddressDecoder ad = new AddressDecoder(0x0000, 0xffff);
ad.addDevice(memory);
try {
ad.addDevice(rom);
fail("Should have thrown a MemoryRangeException.");
} catch (MemoryRangeException ex) {
// expected
}
}
public void testIsCompleteWithFirstDeviceNotStartingAtBottom() throws MemoryRangeException {
Device memory = new Memory(0x00ff, 0xff00, null, true);
AddressDecoder ad = new AddressDecoder(0x0000, 0xffff);
assertFalse("Address space was unexpectedly complete!", ad.isComplete());
ad.addDevice(memory);
assertFalse("Address space was unexpectedly complete!", ad.isComplete());
}
public void testIsCompleteWithOneDevice() throws MemoryRangeException {
Device memory = new Memory(0x0000, 0x10000, null, true);
AddressDecoder ad = new AddressDecoder(0x0000, 0xffff);
assertFalse("Address space was unexpectedly complete!", ad.isComplete());
ad.addDevice(memory);
assertTrue("Address space should have been complete!", ad.isComplete());
}
public void testIsCompleteWithTwoDevices() throws MemoryRangeException {
Device memory = new Memory(0x0000, 0x8000, null, true);
Device rom = new Memory(0x8000, 0x8000, null, false);
AddressDecoder ad = new AddressDecoder(0x0000, 0xffff);
assertFalse("Address space was unexpectedly complete!", ad.isComplete());
ad.addDevice(memory);
assertFalse("Address space was unexpectedly complete!", ad.isComplete());
ad.addDevice(rom);
assertTrue("Address space should have been complete!", ad.isComplete());
}
public void testIsCompleteWithThreeDevices() throws MemoryRangeException {
Device memory = new Memory(0x0000, 0x8000, null, true);
Device rom1 = new Memory(0x8000, 0x4000, null, false);
Device rom2 = new Memory(0xC000, 0x4000, null, false);
AddressDecoder ad = new AddressDecoder(0x0000, 0xffff);
assertFalse("Address space was unexpectedly complete!", ad.isComplete());
ad.addDevice(memory);
assertFalse("Address space was unexpectedly complete!", ad.isComplete());
ad.addDevice(rom1);
assertFalse("Address space was unexpectedly complete!", ad.isComplete());
ad.addDevice(rom2);
assertTrue("Address space should have been complete!", ad.isComplete());
}
}

View File

@ -80,6 +80,17 @@ public class MemoryRangeTest extends TestCase {
assertTrue(h.overlaps(b));
}
public void testToString() throws MemoryRangeException {
MemoryRange a = new MemoryRange(0x0abf, 0xff00);
assertEquals("@0x0abf-0xff00", a.toString());
MemoryRange b = new MemoryRange(0, 255);
assertEquals("@0x0000-0x00ff", b.toString());
MemoryRange c = new MemoryRange(0, 65535);
assertEquals("@0x0000-0xffff", c.toString());
}
public void testIncluded() throws MemoryRangeException {
MemoryRange a = new MemoryRange(0x0100, 0x0fff);