Added the Interupt (int <imm>) and Return from Interupt (intr) command.

Interupt pushes the flag register and the instruction pointer, then resets
execution to 0x0200 + (imm)*2.

Return from interupt pops the flags back and sets the ip. Returning execution
to the interupting code.

Implemented using a CPU hook that can be used to later implement interupts generated
from hardware, or for errors like divide by 0.
This commit is contained in:
Brent O'Neil 2017-12-30 02:02:18 +11:00
parent dab5cab602
commit 1b18426c5c
4 changed files with 89 additions and 2 deletions

View File

@ -97,6 +97,8 @@ public class CPU implements JSONSerialisable {
instructionSet.add(new JncInstruction(this));
instructionSet.add(new JnoInstruction(this));
instructionSet.add(new JoInstruction(this));
instructionSet.add(new IntInstruction(this));
instructionSet.add(new IntrInstruction(this));
status = new Status();
memory = new Memory(config.getInt("memory_size"));
@ -466,6 +468,14 @@ public class CPU implements JSONSerialisable {
return attachedHardware.get(address);
}
/**
* Sets the IP to 0x0200 + Offset and pushes flags then the old IP
*
*/
public void Interrupt(int hw, int offset, boolean retry) {
Instruction push = instructionSet.get("push");
push.execute(status.toByte(), status);
push.execute(ip, status);
this.setIp((char)(0x0200 + offset*2 + 0x0080*hw));
}
}

View File

@ -132,4 +132,20 @@ public class Status {
public void setErrorFlag(boolean errorFlag) {
this.errorFlag = errorFlag;
}
public char toByte() {
char stat = 0;
stat = (char) (stat | ((signFlag ? 1 : 0) << 3));
stat = (char) (stat | ((zeroFlag ? 1 : 0) << 2));
stat = (char) (stat | ((carryFlag ? 1 : 0) << 1));
stat = (char) (stat | (overflowFlag ? 1 : 0));
return stat;
}
public void fromByte(char stat) {
setSignFlag((stat & (1 << 3)) != 0);
setZeroFlag((stat & (1 << 2)) != 0);
setCarryFlag((stat & (1 << 1)) != 0);
setOverflowFlag((stat & 1) != 0);
}
}

View File

@ -0,0 +1,35 @@
package net.simon987.server.assembly.instruction;
import net.simon987.server.assembly.CPU;
import net.simon987.server.assembly.Instruction;
import net.simon987.server.assembly.Status;
/**
* Sets the PC to 0x0200 + Immediate operand
*
*
*
*/
public class IntInstruction extends Instruction{
public static final int OPCODE = 48;
private CPU cpu;
public IntInstruction(CPU cpu) {
super("int", OPCODE);
this.cpu = cpu;
}
@Override
public Status execute(int src, Status status) {
cpu.Interrupt(0, src, false);
return status;
}
public Status execute(Status status) {
cpu.Interrupt(0,0, false);
return status;
}
}

View File

@ -0,0 +1,26 @@
package net.simon987.server.assembly.instruction;
import net.simon987.server.assembly.CPU;
import net.simon987.server.assembly.Instruction;
import net.simon987.server.assembly.Status;
public class IntrInstruction extends Instruction{
public static final int OPCODE = 49;
private CPU cpu;
public IntrInstruction(CPU cpu) {
super("intr", OPCODE);
this.cpu = cpu;
}
public Status execute(Status status) {
cpu.setIp((char)cpu.getMemory().get(cpu.getRegisterSet().getRegister("SP").getValue()));
status.fromByte((char) cpu.getMemory().get(cpu.getRegisterSet().getRegister("SP").getValue() + 1));
cpu.getRegisterSet().getRegister("SP").setValue(cpu.getRegisterSet().getRegister("SP").getValue() + 2); //Increment SP (stack grows towards smaller)
return status;
}
}