1
0
mirror of https://github.com/sethm/symon.git synced 2025-08-09 11:25:13 +00:00

rework bus. Don't throw an Exception any more with overlapping device addresses - this is normal for some machines. Introduce the concept of priorities to ensure that device overlap in the correct order.

This commit is contained in:
Maik Merten
2014-07-25 19:32:00 +02:00
parent 222772648d
commit d7f8045b61
3 changed files with 61 additions and 81 deletions

View File

@@ -26,6 +26,11 @@ package com.loomcom.symon;
import com.loomcom.symon.devices.Device; import com.loomcom.symon.devices.Device;
import com.loomcom.symon.exceptions.MemoryAccessException; import com.loomcom.symon.exceptions.MemoryAccessException;
import com.loomcom.symon.exceptions.MemoryRangeException; import com.loomcom.symon.exceptions.MemoryRangeException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
@@ -45,11 +50,8 @@ public class Bus {
// The CPU // The CPU
private Cpu cpu; private Cpu cpu;
// Ordered list of IO devices. // Ordered sets of IO devices, associated with their priority
private SortedSet<Device> devices; private Map<Integer, SortedSet<Device>> deviceMap;
// Ordered list of IO devices that have overlapping memory locations
private SortedSet<Device> overlapDevices;
// an array for quick lookup of adresses, brute-force style // an array for quick lookup of adresses, brute-force style
private Device[] deviceAddressArray; private Device[] deviceAddressArray;
@@ -60,8 +62,7 @@ public class Bus {
} }
public Bus(int startAddress, int endAddress) { public Bus(int startAddress, int endAddress) {
this.devices = new TreeSet<Device>(); this.deviceMap = new HashMap<Integer, SortedSet<Device>>();
this.overlapDevices = new TreeSet<Device>();
this.startAddress = startAddress; this.startAddress = startAddress;
this.endAddress = endAddress; this.endAddress = endAddress;
} }
@@ -78,48 +79,37 @@ public class Bus {
// TODO: Find out why +2 and not +1 is needed here // TODO: Find out why +2 and not +1 is needed here
int size = (this.endAddress - this.startAddress) + 2; int size = (this.endAddress - this.startAddress) + 2;
deviceAddressArray = new Device[size]; deviceAddressArray = new Device[size];
for(Device device : devices) {
MemoryRange range = device.getMemoryRange(); List<Integer> priorities = new ArrayList<Integer>(deviceMap.keySet());
for(int address = range.startAddress; address <= range.endAddress; ++address) { Collections.sort(priorities);
deviceAddressArray[address] = device;
} for(int priority : priorities) {
} SortedSet<Device> deviceSet = deviceMap.get(priority);
for(Device device : overlapDevices) { for(Device device : deviceSet) {
MemoryRange range = device.getMemoryRange(); MemoryRange range = device.getMemoryRange();
for(int address = range.startAddress; address <= range.endAddress; ++address) { for(int address = range.startAddress; address <= range.endAddress; ++address) {
deviceAddressArray[address] = device; deviceAddressArray[address] = device;
}
}
}
/**
* Add a device to the bus. Throws a MemoryRangeException if the device overlaps with any others, unless the overlap parameter is true.
*
* @param device
* @param overlap
* @throws MemoryRangeException
*/
public void addDevice(Device device, boolean overlap) throws MemoryRangeException {
// Make sure there's no memory overlap.
MemoryRange memRange = device.getMemoryRange();
if(!overlap) {
for (Device d : devices) {
if (d.getMemoryRange().overlaps(memRange)) {
throw new MemoryRangeException("The device being added at " +
String.format("$%04X", memRange.startAddress()) +
" overlaps with an existing " +
"device, '" + d + "'");
} }
} }
} }
}
// Add the device /**
device.setBus(this); * Add a device to the bus.
if(overlap) { *
overlapDevices.add(device); * @param device
} else { * @param priority
devices.add(device); */
public void addDevice(Device device, int priority) {
SortedSet<Device> deviceSet = deviceMap.get(priority);
if(deviceSet == null) {
deviceSet = new TreeSet<Device>();
deviceMap.put(priority, deviceSet);
} }
deviceSet.add(device);
buildDeviceAddressArray(); buildDeviceAddressArray();
} }
@@ -130,7 +120,7 @@ public class Bus {
* @throws MemoryRangeException * @throws MemoryRangeException
*/ */
public void addDevice(Device device) throws MemoryRangeException { public void addDevice(Device device) throws MemoryRangeException {
addDevice(device, false); addDevice(device, 0);
} }
@@ -140,14 +130,10 @@ public class Bus {
* @param device * @param device
*/ */
public void removeDevice(Device device) { public void removeDevice(Device device) {
if (devices.contains(device)) { for(SortedSet<Device> deviceSet : deviceMap.values()) {
devices.remove(device); deviceSet.remove(device);
buildDeviceAddressArray();
}
if (overlapDevices.contains(device)) {
overlapDevices.remove(device);
buildDeviceAddressArray();
} }
buildDeviceAddressArray();
} }
public void addCpu(Cpu cpu) { public void addCpu(Cpu cpu) {
@@ -161,19 +147,17 @@ public class Bus {
* device. * device.
*/ */
public boolean isComplete() { public boolean isComplete() {
// Empty maps cannot be complete. if(deviceAddressArray == null) {
if (devices.isEmpty()) { buildDeviceAddressArray();
return false;
} }
// Loop over devices and add their size for(int address = startAddress; address <= endAddress; ++address) {
int filledMemory = 0; if(deviceAddressArray[address] == null) {
for (Device d : devices) { return false;
filledMemory += d.getSize(); }
} }
// Returns if the total size of the devices fill the bus' memory space return true;
return filledMemory == endAddress - startAddress + 1;
} }
public int read(int address) throws MemoryAccessException { public int read(int address) throws MemoryAccessException {
@@ -225,7 +209,19 @@ public class Bus {
public SortedSet<Device> getDevices() { public SortedSet<Device> getDevices() {
// Expose a copy of the device list, not the original // Expose a copy of the device list, not the original
return new TreeSet<Device>(devices); SortedSet<Device> devices = new TreeSet<Device>();
List<Integer> priorities = new ArrayList<Integer>(deviceMap.keySet());
Collections.sort(priorities);
for(int priority : priorities) {
SortedSet<Device> deviceSet = deviceMap.get(priority);
for(Device device : deviceSet) {
devices.add(device);
}
}
return devices;
} }
public Cpu getCpu() { public Cpu getCpu() {

View File

@@ -73,7 +73,7 @@ public class MulticompMachine implements Machine {
bus.addCpu(cpu); bus.addCpu(cpu);
bus.addDevice(ram); bus.addDevice(ram);
bus.addDevice(acia, true); bus.addDevice(acia, 1);
// TODO: Make this configurable, of course. // TODO: Make this configurable, of course.
File romImage = new File("rom.bin"); File romImage = new File("rom.bin");

View File

@@ -59,22 +59,6 @@ public class BusTest extends TestCase {
assertEquals(2, b.getDevices().size()); 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 { public void testIsCompleteWithFirstDeviceNotStartingAtStartAddress() throws MemoryRangeException {
Device memory = new Memory(0x00ff, 0xff00, true); Device memory = new Memory(0x00ff, 0xff00, true);