diff --git a/src/main/java/de/emilschlampp/scheCPU/emulator/ProcessorEmulator.java b/src/main/java/de/emilschlampp/scheCPU/emulator/ProcessorEmulator.java index a94c20a..3e42ad3 100644 --- a/src/main/java/de/emilschlampp/scheCPU/emulator/ProcessorEmulator.java +++ b/src/main/java/de/emilschlampp/scheCPU/emulator/ProcessorEmulator.java @@ -400,6 +400,16 @@ public void execute() { } } + public boolean fault(int errcode) { + if(restrictions.isAllowFault()) { + register[REGID_A] = errcode; + register[REGID_B] = jmp; // tell the program where the error is + jmp = io[8]; // jump to fault handler + return true; + } + return false; + } + public int[] getMemory() { return memory; } diff --git a/src/main/java/de/emilschlampp/scheCPU/util/EmulatorSandboxRestrictions.java b/src/main/java/de/emilschlampp/scheCPU/util/EmulatorSandboxRestrictions.java index 69d2e08..d6dd650 100644 --- a/src/main/java/de/emilschlampp/scheCPU/util/EmulatorSandboxRestrictions.java +++ b/src/main/java/de/emilschlampp/scheCPU/util/EmulatorSandboxRestrictions.java @@ -3,6 +3,7 @@ public class EmulatorSandboxRestrictions { private boolean allowOutput = true; private boolean allowReset = true; + private boolean allowFault = true; public boolean isAllowOutput() { @@ -22,4 +23,13 @@ public EmulatorSandboxRestrictions setAllowReset(boolean allowReset) { this.allowReset = allowReset; return this; } + + public boolean isAllowFault() { + return allowFault; + } + + public EmulatorSandboxRestrictions setAllowFault(boolean allowFault) { + this.allowFault = allowFault; + return this; + } } diff --git a/src/main/resources/Highlang.md b/src/main/resources/Highlang.md index 0cf09f2..16ddcb6 100644 --- a/src/main/resources/Highlang.md +++ b/src/main/resources/Highlang.md @@ -26,6 +26,7 @@ Die Sprache ist wie folgt aufgebaut: | putnot | | Verneint den angegebene Boolean | | out | | Gibt etwas auf dem IO-Port aus | | in | | Speichert den Wert auf Port in der Variable | +| concatvstr | | Verbindet den String in Variable1 mit Variable2, das Resultat wird in Variable1 geschrieben | Natürlich können Erweiterungen und PreCompiler die Möglichkeiten und Befehle erweitern. diff --git a/src/main/resources/Instructions.md b/src/main/resources/Instructions.md index 448b5db..8e241e7 100644 --- a/src/main/resources/Instructions.md +++ b/src/main/resources/Instructions.md @@ -60,4 +60,5 @@ | 4 | SLEEP_CYCLES | cycles to skip | | 5 | LAST_JMP | last jmp address | | 6 | RESET | resets the cpu | +| 8 | FAULT | sets the memory address of the fault handler | | 34 | SOUT | Prints ascii char to console | diff --git a/src/test/java/de/emilschlampp/scheCPU/tests/emulator/CPUExecuteTest.java b/src/test/java/de/emilschlampp/scheCPU/tests/emulator/CPUExecuteTest.java index 89066d5..880fe5c 100644 --- a/src/test/java/de/emilschlampp/scheCPU/tests/emulator/CPUExecuteTest.java +++ b/src/test/java/de/emilschlampp/scheCPU/tests/emulator/CPUExecuteTest.java @@ -2,6 +2,8 @@ import de.emilschlampp.scheCPU.compile.Compiler; import de.emilschlampp.scheCPU.emulator.ProcessorEmulator; +import de.emilschlampp.scheCPU.util.EmulatorSandboxRestrictions; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -14,4 +16,34 @@ public void testExecute() { assertEquals(processorEmulator.getIo()[1], 0); } + + @Test + public void testFault() { + String program = "JMP setup\n" + + "FUNC faulthandler\n" + + "ADDM 3 1\n" + + "JMP end\n"+ + "FUNC setup\n" + + "OUTWFUNC 8 faulthandler\n" + + "FUNC loop\n"+ + "ADDM 2 1\n"+ + "JMP loop\n" + + "FUNC end"; + + ProcessorEmulator processorEmulator = new ProcessorEmulator(5, 5, new Compiler(program).compile()); + + while (processorEmulator.canExecute()) { + processorEmulator.execute(); + if(processorEmulator.getMemory()[2] > 5) { + break; + } + } + processorEmulator.fault(5); + while (processorEmulator.canExecute()) { + processorEmulator.execute(); + Assertions.assertFalse(processorEmulator.getMemory()[2] > 6); // the code should end after the fault (see 'jmp end' and 'func end') + } + + Assertions.assertEquals(1, processorEmulator.getMemory()[3]); + } } diff --git a/src/test/java/de/emilschlampp/scheCPU/tests/emulator/CPUProtectionTest.java b/src/test/java/de/emilschlampp/scheCPU/tests/emulator/CPUProtectionTest.java index 56441b9..e3bf5fb 100644 --- a/src/test/java/de/emilschlampp/scheCPU/tests/emulator/CPUProtectionTest.java +++ b/src/test/java/de/emilschlampp/scheCPU/tests/emulator/CPUProtectionTest.java @@ -3,13 +3,14 @@ import de.emilschlampp.scheCPU.compile.Compiler; import de.emilschlampp.scheCPU.emulator.ProcessorEmulator; import de.emilschlampp.scheCPU.util.EmulatorSandboxRestrictions; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.io.PrintStream; public class CPUProtectionTest { @Test - public void testCPUProtection() { + public void testCPUOutputProtection() { String program = "OUTW 34 72\n" + //H "OUTW 34 105"; // i @@ -36,4 +37,57 @@ public void print(char c) { } System.setOut(printStream); } + + @Test + public void testCPUResetProtection() { + String program = "OUTW 6 1"; // 6 = reset trigger + + ProcessorEmulator processorEmulator = new ProcessorEmulator(5, 5, new Compiler(program).compile()); + processorEmulator.setRestrictions(new EmulatorSandboxRestrictions().setAllowReset(false)); + + int cur = 0; + + while (processorEmulator.canExecute()) { + Assertions.assertTrue(cur < 5); + processorEmulator.execute(); + cur++; + } + } + + @Test + public void testCPUFaultProtection() { + String program = "JMP setup\n" + + "FUNC faulthandler\n" + + "OUTW 34 70\n"+ // F + "OUTW 34 97\n"+ // a + "OUTW 34 117\n"+// u + "OUTW 34 108\n"+// l + "OUTW 34 116\n"+// t + "OUTW 34 10\n"+ // \n + "ADDM 3 1\n"+ + "FUNC setup\n" + + "OUTWFUNC 8 faulthandler\n" + + "FUNC loop\n"+ + "ADDM 2 1\n"+ + "JMP loop"; + + ProcessorEmulator processorEmulator = new ProcessorEmulator(5, 5, new Compiler(program).compile()); + processorEmulator.setRestrictions(new EmulatorSandboxRestrictions().setAllowFault(false)); + + while (processorEmulator.canExecute()) { + processorEmulator.execute(); + if(processorEmulator.getMemory()[2] > 5) { + break; + } + } + processorEmulator.fault(5); + while (processorEmulator.canExecute()) { + processorEmulator.execute(); + if(processorEmulator.getMemory()[2] > 15) { + break; + } + } + + Assertions.assertEquals(0, processorEmulator.getMemory()[3]); + } }