Skip to content

Commit

Permalink
Refactor multiple components and add new unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
craigthomas committed Feb 19, 2025
1 parent 491e389 commit ae7a6f3
Show file tree
Hide file tree
Showing 14 changed files with 328 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ public int call(IOController io) {
if (operation.apply(io).equals(true)) {
io.regs.pc.add(byteRead.isNegative() ? byteRead.getSignedShort() : byteRead.getShort());
}

return ticks;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,7 @@ public static void decimalAdditionAdjust(IOController io, UnsignedByte registerB
}
io.regs.a.set(new UnsignedByte(io.regs.a.getShort() + result.getShort()));
io.regs.cc.or(io.regs.a.isZero() ? CC_Z : 0);
io.regs.cc.or(carryPreviouslySet ? CC_C : 0);
io.regs.cc.or(result.isNegative() ? CC_N : 0);
io.regs.a.set(result);
io.regs.cc.or(io.regs.a.isNegative() ? CC_N : 0);
}


Expand Down
66 changes: 22 additions & 44 deletions src/main/java/ca/craigthomas/yacoco3e/components/CPU.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,13 @@
public class CPU
{
/* CPU Internal Variables */
private UnsignedWord lastPC;
private UnsignedByte lastOperand;
private final IOController io;
public Instruction instruction;

/* Interrupt request flags */
private boolean fireIRQ;
private boolean fireFIRQ;
private boolean fireNMI;
protected boolean fireIRQ;
protected boolean fireFIRQ;
protected boolean fireNMI;

public CPU(IOController ioController) {
io = ioController;
Expand All @@ -35,8 +33,8 @@ public CPU(IOController ioController) {
* @return the number of ticks taken up by the instruction
*/
public int executeInstruction() throws MalformedInstructionException {
UnsignedWord opWord = io.readWord(io.regs.pc);
instruction = InstructionTable.get(opWord);
UnsignedWord op = io.readWord(io.regs.pc);
instruction = InstructionTable.get(op);
return instruction.execute(io);
}

Expand All @@ -56,7 +54,7 @@ public void interruptRequest() {
io.regs.cc.or(CC_E);
io.pushStack(Register.S, io.regs.cc);
io.regs.cc.or(CC_I);
io.regs.pc.set(io.readWord(new UnsignedWord(0xFFF8)));
io.regs.pc.set(io.readWord(0xFFF8));
}

/**
Expand All @@ -70,7 +68,7 @@ public void fastInterruptRequest() {
io.pushStack(Register.S, io.regs.cc);
io.regs.cc.or(CC_F);
io.regs.cc.or(CC_I);
io.regs.pc.set(io.readWord(new UnsignedWord(0xFFF6)));
io.regs.pc.set(io.readWord(0xFFF6));
}

/**
Expand All @@ -90,75 +88,55 @@ public void nonMaskableInterruptRequest() {
io.pushStack(Register.S, io.regs.cc);
io.regs.cc.or(CC_I);
io.regs.cc.or(CC_F);
io.regs.pc.set(io.readWord(new UnsignedWord(0xFFFC)));
}

/**
* Schedules an IRQ interrupt to occur.
*/
public void scheduleIRQ() {
fireIRQ = true;
}

public boolean irqWaiting() {
return fireIRQ;
}

public void clearIRQ() {
fireIRQ = false;
io.regs.pc.set(io.readWord(0xFFFC));
}

/**
* Check to see if there was any interrupt request. If so, execute the code associated
* with it.
*/
public void serviceInterrupts() {
if (fireIRQ | fireFIRQ | fireNMI) {
io.waitForIRQ = false;
}

if (fireIRQ) {
interruptRequest();
clearIRQ();
fireIRQ = false;
}

if (fireFIRQ) {
fastInterruptRequest();
clearFIRQ();
fireFIRQ = false;
}

if (fireNMI) {
nonMaskableInterruptRequest();
clearNMI();
fireNMI = false;
}
}

/**
* Schedules an IRQ interrupt to occur.
*/
public void scheduleIRQ() {
fireIRQ = true;
}

/**
* Schedules a fast interrupt to occur.
*/
public void scheduleFIRQ() {
fireFIRQ = true;
}

public boolean firqWaiting() {
return fireFIRQ;
}

public void clearFIRQ() {
fireFIRQ = false;
}

/**
* Schedules a non-maskable interrupt to occur.
*/
public void scheduleNMI() {
fireNMI = true;
}

public boolean nmiWaiting() {
return fireNMI;
}

public void clearNMI() {
fireNMI = false;
}

public void reset() {

}
Expand Down
29 changes: 16 additions & 13 deletions src/main/java/ca/craigthomas/yacoco3e/components/Emulator.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class Emulator extends Thread
private Screen screen;
private Keyboard keyboard;
private CPU cpu;
private IOController ioController;
private IOController io;
private Cassette cassette;
private Memory memory;

Expand Down Expand Up @@ -105,9 +105,9 @@ private Emulator(Builder builder) {
keyboard = new EmulatedKeyboard();
screen = new Screen(builder.scale);
cassette = new Cassette();
ioController = new IOController(memory, new RegisterSet(), keyboard, screen, cassette);
cpu = new CPU(ioController);
ioController.setCPU(cpu);
io = new IOController(memory, new RegisterSet(), keyboard, screen, cassette);
cpu = new CPU(io);
io.setCPU(cpu);
trace = builder.trace;
verbose = builder.verbose;
status = EmulatorStatus.STOPPED;
Expand Down Expand Up @@ -192,7 +192,7 @@ public void loadFromConfigFile(ConfigFile config) {
if (drive0 != null) {
JV1Disk disk = new JV1Disk();
if (disk.loadFile(drive0)) {
ioController.disk[0].loadFromVirtualDisk(disk);
io.disk[0].loadFromVirtualDisk(disk);
}
}
}
Expand All @@ -202,7 +202,7 @@ public void loadFromConfigFile(ConfigFile config) {
*/
public void reset() {
memory.resetMemory();
ioController.reset();
io.reset();
cpu.reset();
}

Expand Down Expand Up @@ -379,7 +379,7 @@ public void switchKeyListener(Keyboard newKeyboard) {
canvas.removeKeyListener(keyboard);
canvas.addKeyListener(newKeyboard);
keyboard = newKeyboard;
ioController.setKeyboard(keyboard);
io.setKeyboard(keyboard);
}

/**
Expand All @@ -404,7 +404,7 @@ private void refreshScreen()
* 60th of a second time slice.
*/
public void refreshTicks() {
remainingTicks = ioController.tickRefreshAmount;
remainingTicks = io.tickRefreshAmount;
}

/**
Expand Down Expand Up @@ -435,21 +435,23 @@ public void run() {
while (status != EmulatorStatus.KILLED) {
while (status == EmulatorStatus.RUNNING) {
if (this.trace) {
System.out.print(ioController.regs.toString() + " | ");
System.out.print(io.regs.toString() + " | ");
}

try {
if (remainingTicks > 0) {
if (remainingTicks > 0 && !io.waitForIRQ) {
operationTicks = cpu.executeInstruction();
remainingTicks -= operationTicks;
remainingTicks = remainingTicks - operationTicks;
}
} catch (MalformedInstructionException e) {
System.out.println(e.getMessage());
status = EmulatorStatus.PAUSED;
}

/* Increment timers if necessary */
ioController.timerTick(operationTicks);
io.timerTick(operationTicks);

// System.out.print(" new pc: " + ioController.regs.pc);

/* Fire interrupts if set */
cpu.serviceInterrupts();
Expand All @@ -460,6 +462,7 @@ public void run() {
// + cpu.getLastOperand() + " | " + cpu.instruction.getShortDescription());
if (cpu.instruction != null) {
System.out.print(cpu.instruction.getShortDescription());
System.out.print(" new pc: " + io.regs.pc);
System.out.println();
}
}
Expand Down Expand Up @@ -492,7 +495,7 @@ public Memory getMemory() {
}

public IOController getIOController() {
return ioController;
return io;
}

public Cassette getCassette() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ public class IOController
/* GIME FIRQ status */
public UnsignedByte firqStatus;

/* Whether the CPU should wait for an interrupt request */
public boolean waitForIRQ;

/* The number of ticks to pass in 63.5 microseconds */
public static final int TIMER_63_5_MICROS = 56;

Expand Down Expand Up @@ -166,6 +169,7 @@ public IOController(Memory memory, RegisterSet registerSet, Keyboard keyboard, S

samClockSpeed = new UnsignedByte();
tickRefreshAmount = LOW_SPEED_CLOCK_FREQUENCY;
waitForIRQ = false;
}

/**
Expand Down Expand Up @@ -1189,7 +1193,7 @@ public void reset() {
memory.disableAllRAMMode();

/* Load PC with Reset Interrupt Vector */
regs.pc = readWord(new UnsignedWord(0xFFFE));
regs.pc = readWord(0xFFFE);
}

/**
Expand Down
22 changes: 11 additions & 11 deletions src/main/java/ca/craigthomas/yacoco3e/components/Instruction.java
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public void getIndexed(IOController io) throws MalformedInstructionException {
UnsignedWord r;
UnsignedWord d;
UnsignedByte n;
UnsignedWord nWord;
UnsignedWord w;
numBytesRead = 1;

/* 5-bit offset - check for signed values */
Expand Down Expand Up @@ -248,10 +248,10 @@ public void getIndexed(IOController io) throws MalformedInstructionException {
/* n,R -> 16-bit offset from R */
case 0x09:
r = io.getWordRegister(io.getIndexedRegister(postByte));
nWord = io.readWord(io.regs.pc);
w = io.readWord(io.regs.pc);
io.regs.incrementPC();
io.regs.incrementPC();
addressRead = new UnsignedWord(r.getInt() + nWord.getSignedInt());
addressRead = new UnsignedWord(r.getInt() + w.getSignedInt());
wordRead = io.readWord(addressRead);
byteRead = wordRead.getHigh();
numBytesRead = 3;
Expand Down Expand Up @@ -280,10 +280,10 @@ public void getIndexed(IOController io) throws MalformedInstructionException {
/* n,PC -> 16-bit offset from PC */
case 0x0D:
r = io.getWordRegister(Register.PC);
nWord = io.readWord(io.regs.pc);
w = io.readWord(io.regs.pc);
io.regs.incrementPC();
io.regs.incrementPC();
addressRead = new UnsignedWord(r.getInt() + nWord.getSignedInt());
addressRead = new UnsignedWord(r.getInt() + w.getSignedInt());
wordRead = io.readWord(addressRead);
byteRead = wordRead.getHigh();
numBytesRead = 3;
Expand Down Expand Up @@ -345,10 +345,10 @@ public void getIndexed(IOController io) throws MalformedInstructionException {
/* [n,R] -> 16-bit offset from R - indirect */
case 0x19:
r = io.getWordRegister(io.getIndexedRegister(postByte));
nWord = io.readWord(io.regs.pc);
w = io.readWord(io.regs.pc);
io.regs.incrementPC();
io.regs.incrementPC();
addressRead = io.readWord(new UnsignedWord(r.getInt() + nWord.getSignedInt()));
addressRead = io.readWord(new UnsignedWord(r.getInt() + w.getSignedInt()));
wordRead = io.readWord(addressRead);
byteRead = wordRead.getHigh();
numBytesRead = 3;
Expand Down Expand Up @@ -376,21 +376,21 @@ public void getIndexed(IOController io) throws MalformedInstructionException {
/* [n,PC] -> 16-bit offset from PC - indirect */
case 0x1D:
r = io.getWordRegister(Register.PC);
nWord = io.readWord(io.regs.pc);
w = io.readWord(io.regs.pc);
io.regs.incrementPC();
io.regs.incrementPC();
addressRead = io.readWord(new UnsignedWord(r.getInt() + nWord.getSignedInt()));
addressRead = io.readWord(new UnsignedWord(r.getInt() + w.getSignedInt()));
wordRead = io.readWord(addressRead);
byteRead = wordRead.getHigh();
numBytesRead = 3;
return;

/* [n] -> extended indirect */
case 0x1F:
nWord = io.readWord(io.regs.pc);
w = io.readWord(io.regs.pc);
io.regs.incrementPC();
io.regs.incrementPC();
addressRead = io.readWord(nWord);
addressRead = io.readWord(w);
wordRead = io.readWord(addressRead);
byteRead = wordRead.getHigh();
numBytesRead = 3;
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/ca/craigthomas/yacoco3e/components/Memory.java
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,10 @@ public UnsignedByte readROMByte(int address) {
return new UnsignedByte(rom[0x3FF0 + (address & 0x000F)]);
}

public void writeByte(int address, int value) {
writeByte(new UnsignedWord(address), new UnsignedByte(value));
}

/**
* Writes an UnsignedByte to the specified memory address. If the system
* is in a ROM mode, will not write bytes to a ROM location.
Expand Down Expand Up @@ -332,6 +336,10 @@ public void setTaskPAR(int par, UnsignedByte value) {
taskPAR[par] = value.getShort();
}

public UnsignedByte readByte(int address) {
return readByte(new UnsignedWord(address));
}

/**
* Reads an UnsignedByte from the specified address.
*
Expand Down
Loading

0 comments on commit ae7a6f3

Please sign in to comment.