Changed the CPU and Device interface a bit.
This commit is contained in:
1 parent
a54dbc323d
commit
8df561d292
8 files changed
+90
-97
No files matched your search
@@ -4,15 +4,17 @@ import java.util.*;
|
|||||||
import com.loomcom.lm6502.devices.*;
|
import com.loomcom.lm6502.devices.*;
|
||||||
import com.loomcom.lm6502.exceptions.*;
|
import com.loomcom.lm6502.exceptions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Bus ties the whole thing together, man.
|
||||||
|
*/
|
||||||
public class Bus {
|
public class Bus {
|
||||||
|
|
||||||
/* By default, our bus starts at 0, and goes up to 64K */
|
// By default, our bus starts at 0, and goes up to 64K
|
||||||
private int startAddress = 0x0000;
|
private int startAddress = 0x0000;
|
||||||
private int endAddress = 0xffff;
|
private int endAddress = 0xffff;
|
||||||
|
// The CPU
|
||||||
/**
|
private Cpu cpu;
|
||||||
* Ordered list of IO devices.
|
// Ordered list of IO devices.
|
||||||
*/
|
|
||||||
private SortedSet<Device> devices;
|
private SortedSet<Device> devices;
|
||||||
|
|
||||||
public Bus(int size) {
|
public Bus(int size) {
|
||||||
@@ -45,9 +47,14 @@ public class Bus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add the device
|
// Add the device
|
||||||
|
device.setBus(this);
|
||||||
devices.add(device);
|
devices.add(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addCpu(Cpu cpu) {
|
||||||
|
this.cpu = cpu;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the memory map is full, i.e., there are no
|
* Returns true if the memory map is full, i.e., there are no
|
||||||
* gaps between any IO devices. All memory locations map to some
|
* gaps between any IO devices. All memory locations map to some
|
||||||
|
|||||||
@@ -5,13 +5,38 @@ package com.loomcom.lm6502;
|
|||||||
*/
|
*/
|
||||||
public class Cpu {
|
public class Cpu {
|
||||||
|
|
||||||
private int pc;
|
/* The Bus */
|
||||||
private int sp;
|
private Bus bus;
|
||||||
private Simulator sim;
|
|
||||||
|
|
||||||
public Cpu(Simulator sim) {
|
/* User Registers */
|
||||||
|
private int a; // Accumulator
|
||||||
|
private int x; // X index register
|
||||||
|
private int y; // Y index register
|
||||||
|
|
||||||
|
/* Internal Registers */
|
||||||
|
private int pc; // Program Counter register
|
||||||
|
private int sp; // Stack Pointer register
|
||||||
|
private int ir; // Instruction register
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new CPU.
|
||||||
|
*/
|
||||||
|
public Cpu() {
|
||||||
reset();
|
reset();
|
||||||
this.sim = sim;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the bus reference for this CPU.
|
||||||
|
*/
|
||||||
|
public void setBus(Bus bus) {
|
||||||
|
this.bus = bus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the Bus that this CPU is associated with.
|
||||||
|
*/
|
||||||
|
public Bus getBus() {
|
||||||
|
return bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,43 +44,8 @@ public class Cpu {
|
|||||||
*/
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
sp = 0x01ff;
|
sp = 0x01ff;
|
||||||
/* locations fffc and fffd hold the reset vector address */
|
|
||||||
pc = 0xfffc;
|
pc = 0xfffc;
|
||||||
}
|
ir = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger a maskable interrupt.
|
|
||||||
*/
|
|
||||||
public void interrupt() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger a nonmaskable interrupt.
|
|
||||||
*/
|
|
||||||
public void nmiInterrupt() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return An address specified by the two bytes immediately following the
|
|
||||||
* Program Counter.
|
|
||||||
*/
|
|
||||||
private int readAddress() {
|
|
||||||
return readAddress(pc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the two bytes located at <tt>addr</tt> and <tt>addr + 1</tt>,
|
|
||||||
* and return the address held there.
|
|
||||||
*
|
|
||||||
* @param address
|
|
||||||
* @return The address specified in the two bytes at location <tt>addr</tt>
|
|
||||||
*/
|
|
||||||
private int readAddress(int address) {
|
|
||||||
return (sim.read(address)<<8 & sim.read(address+1));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Simulator getSimulator() {
|
|
||||||
return sim;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ public class Profiler {
|
|||||||
Bus b = new Bus(0, 65535);
|
Bus b = new Bus(0, 65535);
|
||||||
|
|
||||||
// Create eight devices, each 8KB, to fill the bus.
|
// Create eight devices, each 8KB, to fill the bus.
|
||||||
b.addDevice(new Memory(0x0000, 0x2000, null)); // 8KB @ $0000-$1fff
|
b.addDevice(new Memory(0x0000, 0x2000)); // 8KB @ $0000-$1fff
|
||||||
b.addDevice(new Memory(0x2000, 0x2000, null)); // 8KB @ $2000-$3fff
|
b.addDevice(new Memory(0x2000, 0x2000)); // 8KB @ $2000-$3fff
|
||||||
b.addDevice(new Memory(0x4000, 0x2000, null)); // 8KB @ $4000-$5fff
|
b.addDevice(new Memory(0x4000, 0x2000)); // 8KB @ $4000-$5fff
|
||||||
b.addDevice(new Memory(0x6000, 0x2000, null)); // 8KB @ $6000-$7fff
|
b.addDevice(new Memory(0x6000, 0x2000)); // 8KB @ $6000-$7fff
|
||||||
b.addDevice(new Memory(0x8000, 0x2000, null)); // 8KB @ $8000-$9fff
|
b.addDevice(new Memory(0x8000, 0x2000)); // 8KB @ $8000-$9fff
|
||||||
b.addDevice(new Memory(0xa000, 0x2000, null)); // 8KB @ $a000-$bfff
|
b.addDevice(new Memory(0xa000, 0x2000)); // 8KB @ $a000-$bfff
|
||||||
b.addDevice(new Memory(0xc000, 0x2000, null)); // 8KB @ $c000-$dfff
|
b.addDevice(new Memory(0xc000, 0x2000)); // 8KB @ $c000-$dfff
|
||||||
b.addDevice(new Memory(0xe000, 0x2000, null)); // 8KB @ $e000-$ffff
|
b.addDevice(new Memory(0xe000, 0x2000)); // 8KB @ $e000-$ffff
|
||||||
|
|
||||||
// Read memory
|
// Read memory
|
||||||
long sum = 0;
|
long sum = 0;
|
||||||
@@ -42,7 +42,8 @@ public class Profiler {
|
|||||||
for (int j = 0; j < 0xffff; j++) {
|
for (int j = 0; j < 0xffff; j++) {
|
||||||
buf = b.read(j);
|
buf = b.read(j);
|
||||||
if (buf != 0xff) {
|
if (buf != 0xff) {
|
||||||
System.out.println("WARNING! MEMORY SHOULD HAVE BEEN $FF, WAS: " + buf);
|
System.out.println("WARNING! MEMORY SHOULD HAVE " +
|
||||||
|
"BEEN $FF, WAS: " + buf);
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,15 +51,13 @@ public class Profiler {
|
|||||||
long endTime = System.nanoTime();
|
long endTime = System.nanoTime();
|
||||||
long diff = endTime - startTime;
|
long diff = endTime - startTime;
|
||||||
|
|
||||||
// System.out.println("Read of 64KB took: " + diff + " ns (" + (diff / 1000) + " us)");
|
|
||||||
|
|
||||||
sum += diff;
|
sum += diff;
|
||||||
average = sum / (i + 1);
|
average = sum / (i + 1);
|
||||||
}
|
}
|
||||||
|
System.out.println("Average time to read 64KB: " + average +
|
||||||
System.out.println("Average time to read 64KB: " + average + " ns (" + (average / 1000) + " us)");
|
" ns (" + (average / 1000) + " us)");
|
||||||
System.out.println("Average time to read one byte: " + sum / (64 * 1024 * iters) + " ns");
|
System.out.println("Average time to read one byte: " +
|
||||||
|
sum / (64 * 1024 * iters) + " ns");
|
||||||
} catch (MemoryRangeException ex) {
|
} catch (MemoryRangeException ex) {
|
||||||
System.out.println("Memory Access Exception! " + ex.getMessage());
|
System.out.println("Memory Access Exception! " + ex.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,21 +10,21 @@ public class Simulator {
|
|||||||
/**
|
/**
|
||||||
* Command-line parser used by this simulator.
|
* Command-line parser used by this simulator.
|
||||||
*/
|
*/
|
||||||
CommandParser parser;
|
private CommandParser parser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The CPU itself.
|
* The CPU itself.
|
||||||
*/
|
*/
|
||||||
Cpu cpu;
|
private Cpu cpu;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Bus responsible for routing memory read/write requests to the
|
* The Bus responsible for routing memory read/write requests to the
|
||||||
* correct IO devices.
|
* correct IO devices.
|
||||||
*/
|
*/
|
||||||
Bus bus;
|
private Bus bus;
|
||||||
|
|
||||||
public Simulator() {
|
public Simulator() {
|
||||||
cpu = new Cpu(this);
|
cpu = new Cpu();
|
||||||
parser = new CommandParser(System.in, System.out, this);
|
parser = new CommandParser(System.in, System.out, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,16 +12,20 @@ public abstract class Device implements Comparable<Device> {
|
|||||||
/** The memory range for this device. */
|
/** The memory range for this device. */
|
||||||
private MemoryRange memoryRange;
|
private MemoryRange memoryRange;
|
||||||
|
|
||||||
|
/** The name of the device. */
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
/** Reference to the CPU, for interrupts. */
|
/** Reference to the bus where this Device is attached. */
|
||||||
private Cpu cpu;
|
private Bus bus;
|
||||||
|
|
||||||
public Device(int address, int size, String name, Cpu cpu)
|
public Device(int address, int size, String name)
|
||||||
throws MemoryRangeException {
|
throws MemoryRangeException {
|
||||||
this.memoryRange = new MemoryRange(address, address + size - 1);
|
this.memoryRange = new MemoryRange(address, address + size - 1);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.cpu = cpu;
|
}
|
||||||
|
|
||||||
|
public Device(int address, int size) throws MemoryRangeException {
|
||||||
|
this(address, size, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Methods required to be implemented by inheriting classes. */
|
/* Methods required to be implemented by inheriting classes. */
|
||||||
@@ -29,6 +33,10 @@ public abstract class Device implements Comparable<Device> {
|
|||||||
public abstract int read(int address);
|
public abstract int read(int address);
|
||||||
public abstract String toString();
|
public abstract String toString();
|
||||||
|
|
||||||
|
public void setBus(Bus bus) {
|
||||||
|
this.bus = bus;
|
||||||
|
}
|
||||||
|
|
||||||
public MemoryRange getMemoryRange() {
|
public MemoryRange getMemoryRange() {
|
||||||
return memoryRange;
|
return memoryRange;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,29 +8,24 @@ import com.loomcom.lm6502.exceptions.*;
|
|||||||
public class Memory extends Device {
|
public class Memory extends Device {
|
||||||
|
|
||||||
private boolean readOnly;
|
private boolean readOnly;
|
||||||
|
|
||||||
private int[] mem;
|
private int[] mem;
|
||||||
|
|
||||||
public Memory(int address, int size, Cpu cpu, boolean readOnly)
|
public Memory(int address, int size, boolean readOnly)
|
||||||
throws MemoryRangeException {
|
throws MemoryRangeException {
|
||||||
super(address, size, "RW Memory", cpu);
|
super(address, size, "RW Memory");
|
||||||
|
|
||||||
this.readOnly = readOnly;
|
this.readOnly = readOnly;
|
||||||
this.mem = new int[size];
|
this.mem = new int[size];
|
||||||
|
// Initialize all locations to 0xff
|
||||||
// Init the mem to all 0xff
|
|
||||||
Arrays.fill(this.mem, 0xff);
|
Arrays.fill(this.mem, 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Memory(int address, int size, Cpu cpu)
|
public Memory(int address, int size)
|
||||||
throws MemoryRangeException {
|
throws MemoryRangeException {
|
||||||
this(address, size, cpu, false);
|
this(address, size, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(int address, int data) {
|
public void write(int address, int data) {
|
||||||
System.out.println(String.format("[write] Before write: $%04x=$%04x", address, this.mem[address]));
|
|
||||||
this.mem[address] = data;
|
this.mem[address] = data;
|
||||||
System.out.println(String.format("[write] After write: $%04x=$%04x", address, this.mem[address]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int read(int address) {
|
public int read(int address) {
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ public class BusTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testAddDevice() throws MemoryRangeException {
|
public void testAddDevice() throws MemoryRangeException {
|
||||||
Device memory = new Memory(0x0000, 0x0100, null, true);
|
Device memory = new Memory(0x0000, 0x0100, true);
|
||||||
Device rom = new Memory(0x0100, 0x0200, null, false);
|
Device rom = new Memory(0x0100, 0x0200, false);
|
||||||
|
|
||||||
Bus b = new Bus(0x0000, 0xffff);
|
Bus b = new Bus(0x0000, 0xffff);
|
||||||
|
|
||||||
@@ -62,8 +62,8 @@ public class BusTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testOverlappingDevicesShouldFail() throws MemoryRangeException {
|
public void testOverlappingDevicesShouldFail() throws MemoryRangeException {
|
||||||
Device memory = new Memory(0x0000, 0x0100, null, true);
|
Device memory = new Memory(0x0000, 0x0100, true);
|
||||||
Device rom = new Memory(0x00ff, 0x0200, null, false);
|
Device rom = new Memory(0x00ff, 0x0200, false);
|
||||||
|
|
||||||
Bus b = new Bus(0x0000, 0xffff);
|
Bus b = new Bus(0x0000, 0xffff);
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ public class BusTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testIsCompleteWithFirstDeviceNotStartingAtStartAddress() throws MemoryRangeException {
|
public void testIsCompleteWithFirstDeviceNotStartingAtStartAddress() throws MemoryRangeException {
|
||||||
Device memory = new Memory(0x00ff, 0xff00, null, true);
|
Device memory = new Memory(0x00ff, 0xff00, true);
|
||||||
|
|
||||||
Bus b = new Bus(0x0000, 0xffff);
|
Bus b = new Bus(0x0000, 0xffff);
|
||||||
assertFalse("Address space was unexpectedly complete!", b.isComplete());
|
assertFalse("Address space was unexpectedly complete!", b.isComplete());
|
||||||
@@ -87,7 +87,7 @@ public class BusTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testIsCompleteWithOneDevice() throws MemoryRangeException {
|
public void testIsCompleteWithOneDevice() throws MemoryRangeException {
|
||||||
Device memory = new Memory(0x0000, 0x10000, null, true);
|
Device memory = new Memory(0x0000, 0x10000, true);
|
||||||
|
|
||||||
Bus b = new Bus(0x0000, 0xffff);
|
Bus b = new Bus(0x0000, 0xffff);
|
||||||
assertFalse("Address space was unexpectedly complete!", b.isComplete());
|
assertFalse("Address space was unexpectedly complete!", b.isComplete());
|
||||||
@@ -96,8 +96,8 @@ public class BusTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testIsCompleteWithTwoDevices() throws MemoryRangeException {
|
public void testIsCompleteWithTwoDevices() throws MemoryRangeException {
|
||||||
Device memory = new Memory(0x0000, 0x8000, null, true);
|
Device memory = new Memory(0x0000, 0x8000, true);
|
||||||
Device rom = new Memory(0x8000, 0x8000, null, false);
|
Device rom = new Memory(0x8000, 0x8000, false);
|
||||||
|
|
||||||
Bus b = new Bus(0x0000, 0xffff);
|
Bus b = new Bus(0x0000, 0xffff);
|
||||||
assertFalse("Address space was unexpectedly complete!", b.isComplete());
|
assertFalse("Address space was unexpectedly complete!", b.isComplete());
|
||||||
@@ -108,9 +108,9 @@ public class BusTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testIsCompleteWithThreeDevices() throws MemoryRangeException {
|
public void testIsCompleteWithThreeDevices() throws MemoryRangeException {
|
||||||
Device memory = new Memory(0x0000, 0x8000, null, true);
|
Device memory = new Memory(0x0000, 0x8000, true);
|
||||||
Device rom1 = new Memory(0x8000, 0x4000, null, false);
|
Device rom1 = new Memory(0x8000, 0x4000, false);
|
||||||
Device rom2 = new Memory(0xC000, 0x4000, null, false);
|
Device rom2 = new Memory(0xC000, 0x4000, false);
|
||||||
|
|
||||||
Bus b = new Bus(0x0000, 0xffff);
|
Bus b = new Bus(0x0000, 0xffff);
|
||||||
assertFalse("Address space was unexpectedly complete!", b.isComplete());
|
assertFalse("Address space was unexpectedly complete!", b.isComplete());
|
||||||
|
|||||||
@@ -19,14 +19,8 @@ public class CpuTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testCpu() {
|
public void testCpu() {
|
||||||
Cpu cpu = new Cpu(new Simulator());
|
Cpu cpu = new Cpu();
|
||||||
assertNotNull(cpu);
|
assertNotNull(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetSimulator() {
|
|
||||||
Simulator sim = new Simulator();
|
|
||||||
Cpu cpu = new Cpu(sim);
|
|
||||||
assertEquals(sim, cpu.getSimulator());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user