You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

210 lines
8.6 KiB
Java

package net.brokenmoon.redcontrol.api;
import com.simon816.j65el02.Bus;
import com.simon816.j65el02.Cpu;
import com.simon816.j65el02.CpuState;
import com.simon816.j65el02.device.Memory;
import com.simon816.j65el02.device.RedBus;
import com.simon816.j65el02.device.RedBusState;
import net.brokenmoon.redcontrol.RedControl;
import net.brokenmoon.redcontrol.mixin.BusAccessor;
import net.brokenmoon.redcontrol.mixin.CpuAccessor;
import net.brokenmoon.redcontrol.mixin.MemoryAccessor;
import net.minecraft.nbt.NbtCompound;
import java.io.IOException;
import java.nio.file.Paths;
/**
* A serializable emulator
*/
public class Emulator {
private RedBus bus;
public Cpu cpu;
private Memory ram;
public Emulator(RedBus bus){
this.bus = bus;
cpu = new Cpu();
cpu.setLogCallback((i) -> RedControl.LOGGER.info("CPU emitted a byte {}",i));
cpu.setBus(new Bus(bus));
ram = new Memory(0x0000, 0x4000 - 1, ((CpuAccessor)cpu).getRedBusState());
ram.loadFromBytes(RedControl.images.get("rpcboot.bin"),0x400,0x100);
cpu.getBus().addDevice(ram, ((CpuAccessor)cpu).getRedBusState());
cpu.reset();
ram.write(0, 2, ((CpuAccessor)cpu).getRedBusState());
ram.write(1, 1, ((CpuAccessor)cpu).getRedBusState());
}
/**
* gets the RedBus attached to this Emulator
* @return the red bus attached to this emulator
*/
public RedBus getBus() {
return bus;
}
/**
* sets the bus and sets redbus on the CPU
* @param bus the bus to set the cpu and this emu to
*/
public void setBus(RedBus bus) {
this.bus = bus;
((BusAccessor)this.cpu.getBus()).setRedBus(bus);
}
/**
* returns if the CPU is waiting on interupt
* @return if the cpu is waiting on a interupt
*/
public boolean isWaitingOnInterrupt(){
return cpu.isWaitingForInterrupt();
}
/**
* sets the CPU's interupt state
* @param interrupt the new interupt state
*/
public void setWaitingOnInterrupt(boolean interrupt){
cpu.getCpuState().intWait = interrupt;
}
/**
* steps the CPU by 1 instruction
* and updates all bus/redbus attached devices
*/
public void step() {
if(!isWaitingOnInterrupt()) {
this.cpu.step();
this.cpu.getBus().update(((CpuAccessor)cpu).getRedBusState());
}
}
/**
* resets the CPU to default values, and loads driveID and monitorID back for bootloader to use
* @param driveId the drive bootloader will read from
* @param monitorId the monitor id bootloder and initial program will write to
*/
public void reset(int driveId, int monitorId){
cpu.reset();
ram.write(0, driveId, ((CpuAccessor)cpu).getRedBusState());
ram.write(1, monitorId, ((CpuAccessor)cpu).getRedBusState());
}
/**
* save the emulator into NBT
* @param nbt the NBT to write state into
*/
public void writeNbt(NbtCompound nbt) {
//Cpu write nbt
//Cpu state write nbt
nbt.putInt("aRegister", cpu.getCpuState().a);
nbt.putInt("aTopRegister", cpu.getCpuState().aTop);
nbt.putInt("xRegister", cpu.getCpuState().x);
nbt.putInt("yRegister", cpu.getCpuState().y);
nbt.putInt("spRegister", cpu.getCpuState().sp);
nbt.putInt("pcRegister", cpu.getCpuState().pc);
nbt.putInt("irRegister", cpu.getCpuState().ir);
nbt.putInt("iRegister", cpu.getCpuState().i);
nbt.putInt("rRegister", cpu.getCpuState().r);
nbt.putInt("dRegister", cpu.getCpuState().d);
nbt.putInt("brkRegister", cpu.getCpuState().brk);
nbt.putInt("porRegister", cpu.getCpuState().por);
nbt.putInt("nextirRegister", cpu.getCpuState().nextIr);
nbt.putInt("args1Register", cpu.getCpuState().args[0]);
nbt.putInt("args2Register", cpu.getCpuState().args[1]);
nbt.putInt("nextArgs1Register", cpu.getCpuState().nextArgs[0]);
nbt.putInt("nextArgs2Register", cpu.getCpuState().nextArgs[1]);
nbt.putInt("instSizeRegister", cpu.getCpuState().instSize);
nbt.putBoolean("opTrap", cpu.getCpuState().opTrap);
nbt.putBoolean("irqAsserted", cpu.getCpuState().irqAsserted);
nbt.putBoolean("nmiAsserted", cpu.getCpuState().nmiAsserted);
nbt.putInt("lastPc", cpu.getCpuState().lastPc);
nbt.putBoolean("intWait", cpu.getCpuState().intWait);
nbt.putBoolean("signalStop", cpu.getCpuState().signalStop);
nbt.putBoolean("carryFlag", cpu.getCpuState().carryFlag);
nbt.putBoolean("negativeFlag", cpu.getCpuState().negativeFlag);
nbt.putBoolean("zeroFlag", cpu.getCpuState().zeroFlag);
nbt.putBoolean("irqDisable", cpu.getCpuState().irqDisableFlag);
nbt.putBoolean("decimalMode", cpu.getCpuState().decimalModeFlag);
nbt.putBoolean("breakFlag", cpu.getCpuState().breakFlag);
nbt.putBoolean("overflowFlag", cpu.getCpuState().overflowFlag);
nbt.putBoolean("emuFlag", cpu.getCpuState().emulationFlag);
nbt.putBoolean("mWidth", cpu.getCpuState().mWidthFlag);
nbt.putBoolean("indexWidth", cpu.getCpuState().indexWidthFlag);
nbt.putLong("stepCounter", cpu.getCpuState().stepCounter);
//Redbus state write nbt
RedBusState redBusState = ((CpuAccessor)cpu).getRedBusState();
nbt.putInt("deviceId", redBusState.activeDeviceId);
nbt.putInt("offset", redBusState.offset);
nbt.putInt("memoryWindow", redBusState.memoryWindow);
nbt.putBoolean("enabled", redBusState.enabled);
nbt.putBoolean("enableWindow", redBusState.enableWindow);
//Ram write nbt.
nbt.putByteArray("ramValues", ((MemoryAccessor)this.ram).getMem());
}
/**
* load emulator state from NBT
* @param nbt the NBT to load from.
*/
public void readNbt(NbtCompound nbt) {
//Cpu write nbt
//Cpu state write nbt
cpu.getCpuState().a = nbt.getInt("aRegister");
cpu.getCpuState().aTop = nbt.getInt("aTopRegister");
cpu.getCpuState().x = nbt.getInt("xRegister");
cpu.getCpuState().y = nbt.getInt("yRegister");
cpu.getCpuState().pc = nbt.getInt("pcRegister");
cpu.getCpuState().sp = nbt.getInt("spRegister");
cpu.getCpuState().ir = nbt.getInt("irRegister");
cpu.getCpuState().i = nbt.getInt("iRegister");
cpu.getCpuState().r = nbt.getInt("rRegister");
cpu.getCpuState().d = nbt.getInt("dRegister");
cpu.getCpuState().brk = nbt.getInt("brkRegister");
cpu.getCpuState().por = nbt.getInt("porRegister");
cpu.getCpuState().nextIr = nbt.getInt("nextirRegister");
cpu.getCpuState().args[0] = nbt.getInt("args1Register");
cpu.getCpuState().args[1] = nbt.getInt("args2Register");
cpu.getCpuState().nextArgs[0] = nbt.getInt("nextArgs1Register");
cpu.getCpuState().nextArgs[1] = nbt.getInt("nextArgs2Register");
cpu.getCpuState().instSize = nbt.getInt("instSizeRegister");
cpu.getCpuState().opTrap = nbt.getBoolean("opTrap");
cpu.getCpuState().irqAsserted = nbt.getBoolean("irqAsserted");
cpu.getCpuState().nmiAsserted = nbt.getBoolean("nmiAsserted");
cpu.getCpuState().lastPc = nbt.getInt("lastPc");
cpu.getCpuState().intWait = nbt.getBoolean("intWait");
cpu.getCpuState().signalStop = nbt.getBoolean("signalStop");
cpu.getCpuState().carryFlag = nbt.getBoolean("carryFlag");
cpu.getCpuState().negativeFlag = nbt.getBoolean("negativeFlag");
cpu.getCpuState().zeroFlag = nbt.getBoolean("zeroFlag");
cpu.getCpuState().irqDisableFlag = nbt.getBoolean("irqDisable");
cpu.getCpuState().decimalModeFlag = nbt.getBoolean("decimalMode");
cpu.getCpuState().breakFlag = nbt.getBoolean("breakFlag");
cpu.getCpuState().overflowFlag = nbt.getBoolean("overflowFlag");
cpu.getCpuState().emulationFlag = nbt.getBoolean("emuFlag");
cpu.getCpuState().mWidthFlag = nbt.getBoolean("mWidth");
cpu.getCpuState().indexWidthFlag = nbt.getBoolean("indexWidth");
cpu.getCpuState().stepCounter = nbt.getLong("stepCounter");
//Redbus state write nbt
RedBusState redBusState = ((CpuAccessor)cpu).getRedBusState();
redBusState.activeDeviceId = nbt.getInt("deviceId");
redBusState.offset = nbt.getInt("offset");
redBusState.memoryWindow = nbt.getInt("memoryWindow");
redBusState.enabled = nbt.getBoolean("enabled");
redBusState.enableWindow = nbt.getBoolean("enableWindow");
//Ram write nbt.
((MemoryAccessor)ram).setMem(nbt.getByteArray("ramValues"));
}
}