From 60c763167d9bed3d50587d78c17dc189fa62509c Mon Sep 17 00:00:00 2001 From: simon987 Date: Sun, 9 Aug 2020 21:18:30 -0400 Subject: [PATCH] More work on debugger --- .../java/net/simon987/mar/cubot/Cubot.java | 5 ++ .../net/simon987/mar/server/GameServer.java | 2 +- .../net/simon987/mar/server/assembly/CPU.java | 7 ++ .../mar/server/assembly/RegisterSet.java | 20 +++++- .../simon987/mar/server/assembly/Util.java | 4 ++ .../server/websocket/CodeUploadHandler.java | 1 + .../server/websocket/DebugStepHandler.java | 2 +- .../server/websocket/StateRequestHandler.java | 2 +- src/main/resources/static/css/mar.css | 2 +- src/main/typescript/GameClient.ts | 64 ++++++++++++------- src/main/typescript/MarGame.ts | 1 + 11 files changed, 83 insertions(+), 27 deletions(-) diff --git a/src/main/java/net/simon987/mar/cubot/Cubot.java b/src/main/java/net/simon987/mar/cubot/Cubot.java index d08670c..2642c57 100644 --- a/src/main/java/net/simon987/mar/cubot/Cubot.java +++ b/src/main/java/net/simon987/mar/cubot/Cubot.java @@ -157,6 +157,11 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Me @Override public void update() { + + if (getCpu().isPaused() || getCpu().isExecuting()) { + return; + } + if (currentAction == Action.WALKING) { if (spendEnergy(100)) { if (!incrementLocation()) { diff --git a/src/main/java/net/simon987/mar/server/GameServer.java b/src/main/java/net/simon987/mar/server/GameServer.java index 0f759ab..d163986 100644 --- a/src/main/java/net/simon987/mar/server/GameServer.java +++ b/src/main/java/net/simon987/mar/server/GameServer.java @@ -276,7 +276,7 @@ public class GameServer implements Runnable { int allocation = Math.min(user.getControlledUnit().getEnergy() * CPU.INSTRUCTION_COST, maxExecutionInstructions); cpu.setInstructionAlloction(allocation); - if (!cpu.isPaused()) { + if (!cpu.isPaused() && !cpu.isExecuting()) { cpu.reset(); executeUserCode(user); } diff --git a/src/main/java/net/simon987/mar/server/assembly/CPU.java b/src/main/java/net/simon987/mar/server/assembly/CPU.java index 551a98f..374e3a9 100755 --- a/src/main/java/net/simon987/mar/server/assembly/CPU.java +++ b/src/main/java/net/simon987/mar/server/assembly/CPU.java @@ -23,6 +23,7 @@ public class CPU implements MongoSerializable { private final Status status; private boolean trapFlag = false; + private boolean executing = false; /** * Memory associated with the CPU, 64kb max @@ -161,6 +162,7 @@ public class CPU implements MongoSerializable { public int execute() { + executing = true; int counter = 0; status.clear(); @@ -190,6 +192,7 @@ public class CPU implements MongoSerializable { writeExecutionStats(counter); + executing = false; return counter / INSTRUCTION_COST; } @@ -507,6 +510,10 @@ public class CPU implements MongoSerializable { return trapFlag; } + public boolean isExecuting() { + return executing; + } + public void setTrapFlag(boolean trapFlag) { this.trapFlag = trapFlag; } diff --git a/src/main/java/net/simon987/mar/server/assembly/RegisterSet.java b/src/main/java/net/simon987/mar/server/assembly/RegisterSet.java index f410161..77470fe 100755 --- a/src/main/java/net/simon987/mar/server/assembly/RegisterSet.java +++ b/src/main/java/net/simon987/mar/server/assembly/RegisterSet.java @@ -1,6 +1,7 @@ package net.simon987.mar.server.assembly; +import net.simon987.mar.server.io.JSONSerializable; import net.simon987.mar.server.io.MongoSerializable; import org.bson.Document; import org.json.simple.JSONArray; @@ -12,7 +13,7 @@ import java.util.List; /** * A set of registers for a CPU */ -public class RegisterSet implements Target, MongoSerializable, Cloneable { +public class RegisterSet implements Target, MongoSerializable, Cloneable, JSONSerializable { private int size = 0; @@ -210,4 +211,21 @@ public class RegisterSet implements Target, MongoSerializable, Cloneable { } return rs; } + + @Override + public JSONObject jsonSerialise() { + JSONObject json = new JSONObject(); + + for (int i = 1; i <= size; i++) { + Register reg = getRegister(i); + json.put(reg.getName(), (int)reg.getValue()); + } + + return json; + } + + @Override + public JSONObject debugJsonSerialise() { + return jsonSerialise(); + } } diff --git a/src/main/java/net/simon987/mar/server/assembly/Util.java b/src/main/java/net/simon987/mar/server/assembly/Util.java index 4fcd42a..c3dad3f 100755 --- a/src/main/java/net/simon987/mar/server/assembly/Util.java +++ b/src/main/java/net/simon987/mar/server/assembly/Util.java @@ -45,6 +45,10 @@ public class Util { return String.format("%04X ", a); } + public static String toHex16(int a) { + return String.format("%04X", a & 0x0000FFFF); + } + public static String toHex(byte[] byteArray) { StringBuilder result = new StringBuilder(); diff --git a/src/main/java/net/simon987/mar/server/websocket/CodeUploadHandler.java b/src/main/java/net/simon987/mar/server/websocket/CodeUploadHandler.java index 1e17bc4..057996d 100644 --- a/src/main/java/net/simon987/mar/server/websocket/CodeUploadHandler.java +++ b/src/main/java/net/simon987/mar/server/websocket/CodeUploadHandler.java @@ -41,6 +41,7 @@ public class CodeUploadHandler implements MessageHandler { cpu.setCodeSectionOffset(ar.getCodeSectionOffset()); cpu.reset(); + cpu.getRegisterSet().clear(); //Clear keyboard buffer if (user.getUser().getControlledUnit() != null && user.getUser().getControlledUnit().getKeyboardBuffer() != null) { diff --git a/src/main/java/net/simon987/mar/server/websocket/DebugStepHandler.java b/src/main/java/net/simon987/mar/server/websocket/DebugStepHandler.java index bd9417c..aa90c59 100644 --- a/src/main/java/net/simon987/mar/server/websocket/DebugStepHandler.java +++ b/src/main/java/net/simon987/mar/server/websocket/DebugStepHandler.java @@ -31,7 +31,7 @@ public class DebugStepHandler implements MessageHandler { CPU cpu = user.getUser().getControlledUnit().getCpu(); - if (!cpu.isPaused()) { + if (!cpu.isPaused() || cpu.isExecuting()) { return; } diff --git a/src/main/java/net/simon987/mar/server/websocket/StateRequestHandler.java b/src/main/java/net/simon987/mar/server/websocket/StateRequestHandler.java index 2e3f4ea..9ec5fe8 100644 --- a/src/main/java/net/simon987/mar/server/websocket/StateRequestHandler.java +++ b/src/main/java/net/simon987/mar/server/websocket/StateRequestHandler.java @@ -35,7 +35,7 @@ public class StateRequestHandler implements MessageHandler { response.put("t", "state"); response.put("memory", cpu.getMemory().toString()); response.put("status", cpu.getStatus().toString()); - response.put("registers", cpu.getRegisterSet().toString()); + response.put("registers", cpu.getRegisterSet().jsonSerialise()); Map codeLineMap = user.getUser().getCodeLineMap(); Integer line = codeLineMap == null ? null : codeLineMap.get(cpu.getIp()); response.put("line", line == null ? 0 : line); diff --git a/src/main/resources/static/css/mar.css b/src/main/resources/static/css/mar.css index 27bbc98..48c8065 100644 --- a/src/main/resources/static/css/mar.css +++ b/src/main/resources/static/css/mar.css @@ -372,7 +372,7 @@ text-align: right; } -#disassembly-hl { +.disassembly-hl { background: #ff000077; display: inline-block; width: 100%; diff --git a/src/main/typescript/GameClient.ts b/src/main/typescript/GameClient.ts index 19c2f53..88d570d 100644 --- a/src/main/typescript/GameClient.ts +++ b/src/main/typescript/GameClient.ts @@ -158,40 +158,60 @@ class StateListener implements MessageListener { stateStatus.removeChild(stateStatus.firstChild); } - stateMemory.insertAdjacentHTML("beforeend", message.memory.replace(/(0000 )+/g, '$&')); - // stateMemory.insertAdjacentHTML("beforeend", message.memory); - stateRegisters.insertAdjacentHTML("beforeend", message.registers.replace(/(0000 )+/g, '$&')); + // stateMemory.insertAdjacentHTML("beforeend", message.memory.replace(/(0000 )+/g, '$&')); + stateMemory.insertAdjacentHTML("beforeend", message.memory); + let registers = ""; + let regKeys = Object.keys(message.registers); + for (let i = 0; i < regKeys.length; i++) { + registers += regKeys[i] + "=" + message.registers[regKeys[i]].toString(16).padStart(4, "0").toUpperCase() + if (i != regKeys.length - 1) { + registers += " "; + } + } + stateRegisters.insertAdjacentHTML("beforeend", registers.replace(/(0000)+/g, '$&')); stateStatus.insertAdjacentHTML("beforeend", message.status.replace(/=0/g, '=0')); updateDisassemblyPane() } } +function hlDisassembly(lines) { + let text = "" + for (let i = 0; i < lines.length; i++) { + text += "" + lines[i] + .replace(/^\s*([a-zA-Z_]\w*):/gm, ' $1:') + .replace(/^.*INT 0003$/gm, '$&') + .replace(/^[0-9A-F]{4}/gm, '$&') + .replace(/ (MOV|ADD|SUB|AND|OR|TEST|CMP|SHL|SHR|MUL|PUSH|POP|DIV|XOR|DW|NOP|EQU|NEG|HWQ|NOT|ROR|ROL|SAL|SAR|INC|DEC|RCL|XCHG|RCR|PUSHF|POPF|INT|IRET|INTO|SETA|SETNBE|SETAE|SETNB|SETNC|SETBE|SETNA|SETB|SETC|SETNAE|SETE|SETZ|SETNE|SETNZ|SETG|SETNLE|SETGE|SETNL|SETLE|SETNG|SETL|SETNGE|SETO|SETNO|SETS|SETNS)/g, ' $1') + .replace(/ (CALL|RET|JMP|JNZ|JG|JL|JGE|JLE|HWI|JZ|JS|JNS|JC|JNC|JO|JNO|JA|JNA)/g, ' $1 ') + .replace(/ (BRK)$/gm, ' $1') + + "\n"; + } + return text; +} + function updateDisassemblyPane() { + const line = mar.pausedLine; - const lines = mar.disassembly.slice(); + if (mar.disassembly == undefined || line == -1 || !mar.isPaused) { + return; + } + const stateDisassembly = document.getElementById("state-disassembly"); - while (stateDisassembly.firstChild) { - stateDisassembly.removeChild(stateDisassembly.firstChild); - } + if (!mar.disassemblyInitialized) { + mar.disassemblyInitialized = true; + while (stateDisassembly.firstChild) { + stateDisassembly.removeChild(stateDisassembly.firstChild); + } - if (line != -1 && mar.isPaused) { - lines[line] = `${lines[line]}` - } - - stateDisassembly.innerHTML = lines.join("\n") - .replace(/^\s*([a-zA-Z_]\w*):/gm, ' $1:') - .replace(/^.*INT 0003$/gm, '$&') - .replace(/^[0-9A-F]{4}/gm, '$&') - .replace(/ (MOV|ADD|SUB|AND|OR|TEST|CMP|SHL|SHR|MUL|PUSH|POP|DIV|XOR|DW|NOP|EQU|NEG|HWQ|NOT|ROR|ROL|SAL|SAR|INC|DEC|RCL|XCHG|RCR|PUSHF|POPF|INT|IRET|INTO|SETA|SETNBE|SETAE|SETNB|SETNC|SETBE|SETNA|SETB|SETC|SETNAE|SETE|SETZ|SETNE|SETNZ|SETG|SETNLE|SETGE|SETNL|SETLE|SETNG|SETL|SETNGE|SETO|SETNO|SETS|SETNS)/g, ' $1') - .replace(/ (CALL|RET|JMP|JNZ|JG|JL|JGE|JLE|HWI|JZ|JS|JNS|JC|JNC|JO|JNO|JA|JNA) /g, ' $1 ') - .replace(/ (BRK)$/gm, ' $1') - - const hl = document.getElementById("disassembly-hl"); - if (hl != null) { - hl.scrollIntoView({block: "center"}); + stateDisassembly.innerHTML = hlDisassembly(mar.disassembly) + } else { + [].forEach.call(document.getElementsByClassName("disassembly-hl"), el => el.setAttribute("class", null)); } + const lineElem = document.getElementById("line-" + line); + lineElem.classList.add("disassembly-hl"); + lineElem.scrollIntoView({block: "center"}); } class DisassemblyListener implements MessageListener { diff --git a/src/main/typescript/MarGame.ts b/src/main/typescript/MarGame.ts index fc82acb..1652ab5 100644 --- a/src/main/typescript/MarGame.ts +++ b/src/main/typescript/MarGame.ts @@ -1,6 +1,7 @@ class MarGame { disassembly : string[]; + disassemblyInitialized = false pausedLine: number = -1; _isPaused = false