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:
@@ -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() {
|
||||||
|
@@ -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");
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user