mirror of
https://github.com/simon987/Much-Assembly-Required.git
synced 2025-04-10 14:26:45 +00:00
More refactoring, easier assembly testing (#227)
This commit is contained in:
parent
ba78d2fd93
commit
ad0124508c
@ -8,6 +8,7 @@ import net.simon987.mar.server.assembly.Assembler;
|
||||
import net.simon987.mar.server.assembly.AssemblyResult;
|
||||
import net.simon987.mar.server.assembly.CPU;
|
||||
import net.simon987.mar.server.assembly.exception.CancelledException;
|
||||
import net.simon987.mar.server.event.CpuInitialisationEvent;
|
||||
import net.simon987.mar.server.event.GameEvent;
|
||||
import net.simon987.mar.server.event.GameEventListener;
|
||||
import net.simon987.mar.server.event.UserCreationEvent;
|
||||
@ -55,13 +56,20 @@ public class UserCreationListener implements GameEventListener {
|
||||
|
||||
//Create CPU
|
||||
try {
|
||||
cubot.setCpu(new CPU(GameServer.INSTANCE.getConfig(), cubot));
|
||||
CPU cpu = new CPU(config);
|
||||
cubot.setCpu(cpu);
|
||||
cubot.getCpu().setHardwareHost(cubot);
|
||||
user.setUserCode(config.getString("new_user_code"));
|
||||
|
||||
GameEvent initEvent = new CpuInitialisationEvent(cpu, cubot);
|
||||
GameServer.INSTANCE.getEventDispatcher().dispatch(event);
|
||||
if (initEvent.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
|
||||
//Compile user code
|
||||
AssemblyResult ar = new Assembler(cubot.getCpu().getInstructionSet(), cubot.getCpu().getRegisterSet(),
|
||||
GameServer.INSTANCE.getConfig()).parse(user.getUserCode());
|
||||
AssemblyResult ar = new Assembler(cpu.getInstructionSet(), cpu.getRegisterSet(),
|
||||
config).parse(user.getUserCode());
|
||||
|
||||
cubot.getCpu().getMemory().clear();
|
||||
|
||||
|
@ -22,7 +22,7 @@ public class AssemblyResult {
|
||||
/**
|
||||
* A list of labels
|
||||
*/
|
||||
HashMap<String, Character> labels = new HashMap<>(20);
|
||||
public HashMap<String, Character> labels = new HashMap<>(20);
|
||||
/**
|
||||
* List of exceptions encountered during the assembly attempt,
|
||||
* they will be displayed in the editor
|
||||
|
@ -98,7 +98,7 @@ public class CPU implements MongoSerializable {
|
||||
/**
|
||||
* Creates a new CPU
|
||||
*/
|
||||
public CPU(IServerConfiguration config, ControllableUnit unit) throws CancelledException {
|
||||
public CPU(IServerConfiguration config) throws CancelledException {
|
||||
instructionSet = new DefaultInstructionSet();
|
||||
registerSet = new DefaultRegisterSet();
|
||||
codeSectionOffset = config.getInt("org_offset");
|
||||
@ -132,12 +132,6 @@ public class CPU implements MongoSerializable {
|
||||
|
||||
status = new Status();
|
||||
memory = new Memory(config.getInt("memory_size"));
|
||||
|
||||
GameEvent event = new CpuInitialisationEvent(this, unit);
|
||||
GameServer.INSTANCE.getEventDispatcher().dispatch(event);
|
||||
if (event.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
@ -398,15 +392,20 @@ public class CPU implements MongoSerializable {
|
||||
|
||||
public static CPU deserialize(Document obj, ControllableUnit unit) throws CancelledException {
|
||||
|
||||
CPU cpu = new CPU(GameServer.INSTANCE.getConfig(), unit);
|
||||
CPU cpu = new CPU(GameServer.INSTANCE.getConfig());
|
||||
|
||||
cpu.codeSectionOffset = obj.getInteger("codeSegmentOffset");
|
||||
|
||||
cpu.memory = new Memory((Document) obj.get("memory"));
|
||||
cpu.registerSet = RegisterSet.deserialize((Document) obj.get("registerSet"));
|
||||
|
||||
return cpu;
|
||||
GameEvent event = new CpuInitialisationEvent(cpu, unit);
|
||||
GameServer.INSTANCE.getEventDispatcher().dispatch(event);
|
||||
if (event.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
|
||||
return cpu;
|
||||
}
|
||||
|
||||
public InstructionSet getInstructionSet() {
|
||||
@ -466,4 +465,15 @@ public class CPU implements MongoSerializable {
|
||||
public void setHardwareHost(HardwareHost hardwareHost) {
|
||||
this.hardwareHost = hardwareHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* For testing/debugging, this creates an copy (please be mindful of the memory usage)
|
||||
*/
|
||||
public CpuState getState() {
|
||||
return new CpuState(
|
||||
registerSet.clone(),
|
||||
memory.clone(),
|
||||
status.clone()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
16
src/main/java/net/simon987/mar/server/assembly/CpuState.java
Normal file
16
src/main/java/net/simon987/mar/server/assembly/CpuState.java
Normal file
@ -0,0 +1,16 @@
|
||||
package net.simon987.mar.server.assembly;
|
||||
|
||||
public class CpuState {
|
||||
|
||||
public RegisterSet registers;
|
||||
|
||||
public Memory memory;
|
||||
|
||||
public Status status;
|
||||
|
||||
public CpuState(RegisterSet registers, Memory memory, Status status) {
|
||||
this.registers = registers;
|
||||
this.memory = memory;
|
||||
this.status = status;
|
||||
}
|
||||
}
|
@ -9,14 +9,13 @@ class DefaultRegisterSet extends RegisterSet {
|
||||
DefaultRegisterSet() {
|
||||
super();
|
||||
|
||||
addRegister(1, new Register("A"));
|
||||
addRegister(2, new Register("B"));
|
||||
addRegister(3, new Register("C"));
|
||||
addRegister(4, new Register("D"));
|
||||
addRegister(5, new Register("X"));
|
||||
addRegister(6, new Register("Y"));
|
||||
addRegister(7, new Register("SP"));
|
||||
addRegister(8, new Register("BP"));
|
||||
|
||||
put(1, new Register("A"));
|
||||
put(2, new Register("B"));
|
||||
put(3, new Register("C"));
|
||||
put(4, new Register("D"));
|
||||
put(5, new Register("X"));
|
||||
put(6, new Register("Y"));
|
||||
put(7, new Register("SP"));
|
||||
put(8, new Register("BP"));
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ import java.util.zip.InflaterOutputStream;
|
||||
/**
|
||||
* Represents the available memory for a CPU in the game universe
|
||||
*/
|
||||
public class Memory implements Target, MongoSerializable {
|
||||
public class Memory implements Target, MongoSerializable, Cloneable {
|
||||
|
||||
|
||||
/**
|
||||
@ -105,6 +105,7 @@ public class Memory implements Target, MongoSerializable {
|
||||
address = (char) address;
|
||||
|
||||
if (address >= words.length) {
|
||||
Thread.dumpStack();
|
||||
LogManager.LOGGER.info("DEBUG: Trying to set memory out of bounds: " + address);
|
||||
return;
|
||||
}
|
||||
@ -117,25 +118,25 @@ public class Memory implements Target, MongoSerializable {
|
||||
*
|
||||
* @param blockSize Block size (in words) in which to randomly flip one bit
|
||||
*/
|
||||
public void corrupt(int blockSize) {
|
||||
Random rand = new Random();
|
||||
public void corrupt(int blockSize) {
|
||||
Random rand = new Random();
|
||||
|
||||
// Increment offset by blockSize
|
||||
for (int offset = 0; offset < words.length; offset += blockSize) {
|
||||
// Increment offset by blockSize
|
||||
for (int offset = 0; offset < words.length; offset += blockSize) {
|
||||
|
||||
// Calculate address to corrupt by adding a random value between 0 to (blocksize-1) to offset
|
||||
int address = rand.nextInt(blockSize) + offset;
|
||||
// Calculate address to corrupt by adding a random value between 0 to (blocksize-1) to offset
|
||||
int address = rand.nextInt(blockSize) + offset;
|
||||
|
||||
// Checking here avoids having a protected area at the end of the address space
|
||||
if(address < words.length) {
|
||||
// Checking here avoids having a protected area at the end of the address space
|
||||
if (address < words.length) {
|
||||
|
||||
// Calculate bitmask by left-shifting 1 by a random value between 0 and 15
|
||||
int bitmask = 1 << rand.nextInt(16);
|
||||
// Calculate bitmask by left-shifting 1 by a random value between 0 and 15
|
||||
int bitmask = 1 << rand.nextInt(16);
|
||||
|
||||
// Flip the bit with XOR
|
||||
words[address] ^= bitmask;
|
||||
}
|
||||
}
|
||||
// Flip the bit with XOR
|
||||
words[address] ^= bitmask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -186,4 +187,12 @@ public class Memory implements Target, MongoSerializable {
|
||||
public char[] getWords() {
|
||||
return words;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Memory clone() {
|
||||
Memory memory = new Memory(words.length);
|
||||
memory.words = new char[words.length];
|
||||
System.arraycopy(memory.words, 0, words, 0, words.length);
|
||||
return memory;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package net.simon987.mar.server.assembly;
|
||||
/**
|
||||
* Represents a register in a cpu
|
||||
*/
|
||||
public class Register {
|
||||
public class Register implements Cloneable {
|
||||
|
||||
/**
|
||||
* Name of the register
|
||||
@ -47,4 +47,14 @@ public class Register {
|
||||
return name + "=" + value;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Register clone() {
|
||||
try {
|
||||
return (Register) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -2,29 +2,23 @@ package net.simon987.mar.server.assembly;
|
||||
|
||||
|
||||
import net.simon987.mar.server.io.MongoSerializable;
|
||||
import net.simon987.mar.server.logging.LogManager;
|
||||
import org.bson.Document;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A set of registers for a CPU
|
||||
*/
|
||||
public class RegisterSet implements Target, MongoSerializable {
|
||||
public class RegisterSet implements Target, MongoSerializable, Cloneable {
|
||||
|
||||
/**
|
||||
* List of registers
|
||||
*/
|
||||
private final HashMap<Integer, Register> registers = new HashMap<>(8);
|
||||
// TODO configurable number of registers
|
||||
private static final int REG_COUNT = 8 + 1;
|
||||
|
||||
private final Register[] registers = new Register[REG_COUNT];
|
||||
|
||||
/**
|
||||
* Create an empty Register set
|
||||
*/
|
||||
public RegisterSet() {
|
||||
|
||||
}
|
||||
@ -40,9 +34,8 @@ public class RegisterSet implements Target, MongoSerializable {
|
||||
|
||||
name = name.toUpperCase();
|
||||
|
||||
for (Integer i : registers.keySet()) {
|
||||
if (registers.get(i).getName().equals(name)) {
|
||||
|
||||
for (int i = 1; i < REG_COUNT; i++) {
|
||||
if (registers[i].getName().equals(name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@ -56,7 +49,7 @@ public class RegisterSet implements Target, MongoSerializable {
|
||||
* @param index index of the register
|
||||
*/
|
||||
public Register getRegister(int index) {
|
||||
return registers.get(index);
|
||||
return registers[index];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,7 +61,8 @@ public class RegisterSet implements Target, MongoSerializable {
|
||||
|
||||
name = name.toUpperCase();
|
||||
|
||||
for (Register r : registers.values()) {
|
||||
for (Register r : registers) {
|
||||
if (r == null) continue;
|
||||
if (r.getName().equals(name)) {
|
||||
return r;
|
||||
}
|
||||
@ -86,15 +80,11 @@ public class RegisterSet implements Target, MongoSerializable {
|
||||
*/
|
||||
@Override
|
||||
public int get(int address) {
|
||||
|
||||
Register register = registers.get(address);
|
||||
|
||||
if (register != null) {
|
||||
return register.getValue();
|
||||
} else {
|
||||
if (address <= 0 || address >= REG_COUNT) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return registers[address].getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,23 +95,17 @@ public class RegisterSet implements Target, MongoSerializable {
|
||||
*/
|
||||
@Override
|
||||
public void set(int address, int value) {
|
||||
|
||||
Register register = registers.get(address);
|
||||
|
||||
if (register != null) {
|
||||
register.setValue(value);
|
||||
} else {
|
||||
LogManager.LOGGER.info("DEBUG: trying to set unknown reg index : " + address);
|
||||
if (address <= 0 || address >= REG_COUNT) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void put(int index, Register register) {
|
||||
registers.put(index, register);
|
||||
registers[address].setValue(value);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
for (Register register : registers.values()) {
|
||||
register.setValue(0);
|
||||
for (Register r : registers) {
|
||||
if (r == null) continue;
|
||||
r.setValue(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,24 +118,24 @@ public class RegisterSet implements Target, MongoSerializable {
|
||||
* @param index Index of the register
|
||||
* @param reg Register to add
|
||||
*/
|
||||
void addRegister(int index, Register reg) {
|
||||
registers.put(index, reg);
|
||||
public void put(int index, Register reg) {
|
||||
registers[index] = reg;
|
||||
}
|
||||
|
||||
int size() {
|
||||
return registers.size();
|
||||
return REG_COUNT - 1;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Document mongoSerialise() {
|
||||
List<Document> registers = new ArrayList<>();
|
||||
for (Integer index : this.registers.keySet()) {
|
||||
for (int i = 1; i < REG_COUNT; i++) {
|
||||
Document register = new Document();
|
||||
|
||||
register.put("index", index);
|
||||
register.put("name", getRegister(index).getName());
|
||||
register.put("value", (int) getRegister(index).getValue());
|
||||
register.put("index", i);
|
||||
register.put("name", getRegister(i).getName());
|
||||
register.put("value", (int) getRegister(i).getValue());
|
||||
|
||||
registers.add(register);
|
||||
}
|
||||
@ -169,11 +153,12 @@ public class RegisterSet implements Target, MongoSerializable {
|
||||
List registers = (ArrayList) obj.get("registers");
|
||||
|
||||
for (Object sRegister : registers) {
|
||||
if (sRegister == null) continue;
|
||||
|
||||
Register register = new Register((String) ((Document) sRegister).get("name"));
|
||||
register.setValue(((Document) sRegister).getInteger("value"));
|
||||
|
||||
registerSet.registers.put(((Document) sRegister).getInteger("index"), register);
|
||||
registerSet.put(((Document) sRegister).getInteger("index"), register);
|
||||
|
||||
}
|
||||
|
||||
@ -191,7 +176,7 @@ public class RegisterSet implements Target, MongoSerializable {
|
||||
Register register = new Register((String) jsonRegister.get("name"));
|
||||
register.setValue((int) (long) jsonRegister.get("value"));
|
||||
|
||||
registerSet.registers.put((int) (long) jsonRegister.get("index"), register);
|
||||
registerSet.put((int) (long) jsonRegister.get("index"), register);
|
||||
|
||||
}
|
||||
|
||||
@ -202,10 +187,20 @@ public class RegisterSet implements Target, MongoSerializable {
|
||||
public String toString() {
|
||||
String str = "";
|
||||
|
||||
for (Integer index : registers.keySet()) {
|
||||
str += index + " " + registers.get(index).getName() + "=" + Util.toHex(registers.get(index).getValue()) + "\n";
|
||||
for (int i = 1; i < REG_COUNT; i++) {
|
||||
str += i + " " + getRegister(i).getName() + "=" + Util.toHex(getRegister(i).getValue()) + "\n";
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterSet clone() {
|
||||
RegisterSet rs = new RegisterSet();
|
||||
|
||||
for (int i = 1; i < REG_COUNT; i++) {
|
||||
rs.put(i, getRegister(i).clone());
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package net.simon987.mar.server.assembly;
|
||||
/**
|
||||
* Represents the state of the processor
|
||||
*/
|
||||
public class Status {
|
||||
public class Status implements Cloneable {
|
||||
|
||||
/**
|
||||
* Set to true when the result of
|
||||
@ -148,4 +148,14 @@ public class Status {
|
||||
setCarryFlag((stat & (1 << 1)) != 0);
|
||||
setOverflowFlag((stat & 1) != 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status clone() {
|
||||
try {
|
||||
return (Status) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -23,17 +23,12 @@ public class HwiInstruction extends Instruction {
|
||||
@Override
|
||||
public Status execute(Target src, int srcIndex, Status status) {
|
||||
status.setErrorFlag(cpu.getHardwareHost().hardwareInterrupt(src.get(srcIndex), cpu.getStatus()));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status execute(int src, Status status) {
|
||||
|
||||
status.setErrorFlag(cpu.getHardwareHost().hardwareInterrupt(src, cpu.getStatus()));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -12,5 +12,4 @@ public interface HardwareHost {
|
||||
boolean hardwareInterrupt(int address, Status status);
|
||||
|
||||
int hardwareQuery(int address);
|
||||
|
||||
}
|
||||
|
53
src/test/java/net/simon987/mar/server/FakeHardwareHost.java
Normal file
53
src/test/java/net/simon987/mar/server/FakeHardwareHost.java
Normal file
@ -0,0 +1,53 @@
|
||||
package net.simon987.mar.server;
|
||||
|
||||
import net.simon987.mar.server.assembly.CPU;
|
||||
import net.simon987.mar.server.assembly.CpuState;
|
||||
import net.simon987.mar.server.assembly.HardwareModule;
|
||||
import net.simon987.mar.server.assembly.Status;
|
||||
import net.simon987.mar.server.game.objects.HardwareHost;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class FakeHardwareHost implements HardwareHost {
|
||||
|
||||
public final List<HwiCall> callHistory = new ArrayList<>();
|
||||
private final CPU cpu;
|
||||
|
||||
public FakeHardwareHost(CPU cpu) {
|
||||
this.cpu = cpu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachHardware(HardwareModule hardware, int address) {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachHardware(int address) {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hardwareInterrupt(int address, Status status) {
|
||||
callHistory.add(new HwiCall(address, cpu.getState()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hardwareQuery(int address) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static class HwiCall {
|
||||
public HwiCall(int address, CpuState state) {
|
||||
this.address = address;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public int address;
|
||||
public CpuState state;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
package net.simon987.mar.server;
|
||||
|
||||
import net.simon987.mar.server.assembly.AssemblyResult;
|
||||
import net.simon987.mar.server.assembly.CpuState;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TestExecutionResult {
|
||||
|
||||
public CpuState state;
|
||||
|
||||
public List<FakeHardwareHost.HwiCall> hwiHistory;
|
||||
|
||||
private AssemblyResult ar;
|
||||
|
||||
public TestExecutionResult(CpuState state, List<FakeHardwareHost.HwiCall> hwiHistory, AssemblyResult ar) {
|
||||
this.state = state;
|
||||
this.hwiHistory = hwiHistory;
|
||||
this.ar = ar;
|
||||
}
|
||||
|
||||
public int regValue(String register) {
|
||||
return state.registers.getRegister(register).getValue();
|
||||
}
|
||||
|
||||
public int labelOffset(String label) {
|
||||
return ar.labels.get(label);
|
||||
}
|
||||
|
||||
public int memValue(int offset) {
|
||||
return state.memory.get(offset);
|
||||
}
|
||||
|
||||
// Add more utility methods here
|
||||
}
|
@ -74,5 +74,4 @@ public class RegisterSetTest {
|
||||
//Test unknown indexes
|
||||
registerSet.set(3, 10);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,18 +1,57 @@
|
||||
package net.simon987.mar.server.assembly;
|
||||
|
||||
import net.simon987.mar.server.FakeConfiguration;
|
||||
import net.simon987.mar.server.FakeHardwareHost;
|
||||
import net.simon987.mar.server.IServerConfiguration;
|
||||
import net.simon987.mar.server.TestExecutionResult;
|
||||
import net.simon987.mar.server.assembly.exception.CancelledException;
|
||||
|
||||
class TestHelper {
|
||||
public class TestHelper {
|
||||
|
||||
static Assembler getTestAsm() {
|
||||
private static final int TIMEOUT = 100;
|
||||
|
||||
IServerConfiguration configuration = new FakeConfiguration();
|
||||
|
||||
configuration.setInt("memory_size", 1000);
|
||||
configuration.setInt("org_offset", 400);
|
||||
|
||||
return new Assembler(new DefaultInstructionSet(), new DefaultRegisterSet(), configuration);
|
||||
public static Assembler getTestAsm() {
|
||||
IServerConfiguration config = getTestConfig();
|
||||
CPU cpu = getTestCpu();
|
||||
return new Assembler(cpu.getInstructionSet(), cpu.getRegisterSet(), config);
|
||||
}
|
||||
|
||||
public static IServerConfiguration getTestConfig() {
|
||||
IServerConfiguration configuration = new FakeConfiguration();
|
||||
|
||||
configuration.setInt("memory_size", 65536);
|
||||
configuration.setInt("org_offset", 400);
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public static CPU getTestCpu() {
|
||||
|
||||
CPU cpu = null;
|
||||
try {
|
||||
cpu = new CPU(getTestConfig());
|
||||
} catch (CancelledException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return cpu;
|
||||
}
|
||||
|
||||
public static TestExecutionResult executeCode(String code) {
|
||||
AssemblyResult ar = getTestAsm().parse(code);
|
||||
CPU cpu = TestHelper.getTestCpu();
|
||||
|
||||
FakeHardwareHost host = new FakeHardwareHost(cpu);
|
||||
cpu.setHardwareHost(host);
|
||||
|
||||
cpu.getMemory().clear();
|
||||
|
||||
char[] assembledCode = ar.getWords();
|
||||
|
||||
cpu.getMemory().write((char) ar.origin, assembledCode, 0, assembledCode.length);
|
||||
cpu.setCodeSectionOffset(ar.getCodeSectionOffset());
|
||||
|
||||
cpu.reset();
|
||||
cpu.execute(TIMEOUT);
|
||||
|
||||
return new TestExecutionResult(cpu.getState(), host.callHistory, ar);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,30 @@
|
||||
package net.simon987.mar.server.assembly.instruction;
|
||||
|
||||
import net.simon987.mar.server.FakeConfiguration;
|
||||
import net.simon987.mar.server.IServerConfiguration;
|
||||
import net.simon987.mar.server.TestExecutionResult;
|
||||
import net.simon987.mar.server.assembly.*;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class CallInstructionTest {
|
||||
|
||||
@Test
|
||||
public void callSimple1() {
|
||||
String code = "" +
|
||||
"my_routine: \n" +
|
||||
" MOV X, 0x1234 \n" +
|
||||
" RET \n" +
|
||||
".text \n" +
|
||||
"CALL my_routine \n" +
|
||||
"MOV Y, 0x4567 \n" +
|
||||
"brk \n";
|
||||
|
||||
TestExecutionResult res = TestHelper.executeCode(code);
|
||||
|
||||
assertEquals(0x1234, res.regValue("X"));
|
||||
assertEquals(0x4567, res.regValue("Y"));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
package net.simon987.mar.server.assembly.instruction;
|
||||
|
||||
import net.simon987.mar.server.FakeHardwareHost;
|
||||
import net.simon987.mar.server.TestExecutionResult;
|
||||
import net.simon987.mar.server.assembly.TestHelper;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class HwiInstructionTest {
|
||||
|
||||
@Test
|
||||
public void hwiSimple1() {
|
||||
String code = "" +
|
||||
"MOV A, 0x123 \n" +
|
||||
"HWI 0x4567 \n" +
|
||||
"MOV A, 0x789 \n" +
|
||||
"brk \n";
|
||||
|
||||
TestExecutionResult res = TestHelper.executeCode(code);
|
||||
|
||||
FakeHardwareHost.HwiCall call = res.hwiHistory.get(0);
|
||||
assertEquals(0x4567, call.address);
|
||||
assertEquals(0x123, call.state.registers.getRegister("A").getValue());
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user