package debug; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import dcpu.CpuWatcher; import dcpu.Dcpu; public enum DebugCommandType { PAUSE(new DebugCommandAction() { public DebugResponse run(Collection<Dcpu> cpus, long[] params, DebugClientServer debugClientServer) { Dcpu c = null; if (params.length > 0) { c = CPUForId(cpus, params[0]); } DebugResponse resp = new DebugResponse(); resp.payload = new long[] {}; if (c != null) { c.pause(); resp.userAlert = "cpu paused"; resp.status = CommandStatus.PASS; } else { resp.userAlert = "id not found"; resp.status = CommandStatus.FAIL; } return resp; } }), UNPAUSE(new DebugCommandAction() { public DebugResponse run(Collection<Dcpu> cpus, long[] params, DebugClientServer debugClientServer) { Dcpu c = null; if (params.length > 0) { c = CPUForId(cpus, params[0]); } DebugResponse resp = new DebugResponse(); resp.payload = new long[] {}; if (c != null) { c.unpause(); resp.userAlert = "cpu unpaused"; resp.status = CommandStatus.PASS; } else { resp.userAlert = "id not found"; resp.status = CommandStatus.FAIL; } return resp; } }), CPUREGS(new DebugCommandAction() { public DebugResponse run(Collection<Dcpu> cpus, long[] params, DebugClientServer debugClientServer) { Dcpu c = null; if (params.length > 0) { c = CPUForId(cpus, params[0]); } DebugResponse resp = new DebugResponse(); if (c != null) { resp.payload = new long[] { c.regs.gp[0], c.regs.gp[1], c.regs.gp[2], c.regs.gp[3], c.regs.gp[4], c.regs.gp[5], c.regs.gp[6], c.regs.gp[7], c.regs.ex, c.regs.ia, c.regs.pc, c.regs.sp }; resp.userAlert = "cpu unpaused"; resp.status = CommandStatus.PASS; } else { resp.payload = new long[] {}; resp.userAlert = "id not found"; resp.status = CommandStatus.FAIL; } return resp; } }), LIST_CPUS(new DebugCommandAction() { public DebugResponse run(Collection<Dcpu> cpus, long[] params, DebugClientServer debugClientServer) { DebugResponse resp = new DebugResponse(); resp.payload = new long[cpus.size()]; int i = 0; for (Dcpu d : cpus) { resp.payload[i++] = d.id; } resp.userAlert = ""; resp.status = CommandStatus.PASS; return resp; } }), BREAK(new DebugCommandAction() { public DebugResponse run(Collection<Dcpu> cpus, long[] params, DebugClientServer debugClientServer) { if (params.length < 2) { return new DebugResponse(CommandStatus.FAIL, "not enough parameters", new long[] {}); } Dcpu c = CPUForId(cpus, params[0]); if (c == null) { return new DebugResponse(CommandStatus.FAIL, "cpu not found", new long[] {}); } return toggleBreak(c, params[1], debugClientServer); } }), STEP(new DebugCommandAction() { public DebugResponse run(Collection<Dcpu> cpus, long[] params, final DebugClientServer debugClientServer) { if (params.length < 1) { return new DebugResponse(CommandStatus.FAIL, "not enough parameters", new long[] {}); } Dcpu c = CPUForId(cpus, params[0]); if (c == null) { return new DebugResponse(CommandStatus.FAIL, "cpu not found", new long[] {}); } c.pause();// should be already, but just in case, don't create // concurrency problems with addWatcher c.addWatcher(new CpuWatcher() { CpuWatcher that; { that = this; } public void cpu_changed(final Dcpu cpu, long cyclesAdvanved, boolean idle) { cpu.pause(); cpu.runInCpuThread(new Runnable() { public void run() { cpu.removeWatcher(that); DebugResponse resp = new DebugResponse(); resp.userAlert = "Stepped"; resp.payload = new long[]{}; resp.status = CommandStatus.UNSOLICITED; debugClientServer.sendResponse(resp); } }); } }); c.unpause(); return new DebugResponse(CommandStatus.PASS, "cpu stepping", new long[] {}); } }), LISTMEM(new DebugCommandAction() { public DebugResponse run(Collection<Dcpu> cpus, long[] params, DebugClientServer debugClientServer) { DebugResponse ret = new DebugResponse(); int start = (int) params[1]; int len = (int) params[2]; if (params.length < 3 || start < 0 || start+len > 0x10000 ) { return new DebugResponse(CommandStatus.FAIL, "Invalid Address Range", new long[] {}); } Dcpu c = CPUForId(cpus, params[0]); if (c == null) { return new DebugResponse(CommandStatus.FAIL, "cpu not found", new long[] {}); } ret.userAlert = ""; ret.status = CommandStatus.PASS; ret.payload = new long[len]; for (int i = 0; i < len; i++) { ret.payload[i] = c.memory.get((char) (i + start)); } return ret; } }); public final DebugCommandAction action; DebugCommandType(DebugCommandAction d) { this.action = d; } public static interface DebugCommandAction { public DebugResponse run(Collection<Dcpu> cpus, long[] params, DebugClientServer debugClientServer); } private static Dcpu CPUForId(Collection<Dcpu> cpus, long id) { for (Dcpu d : cpus) { if (d.id == id) { return d; } } return null; } private static DebugResponse toggleBreak(final Dcpu c, long addr, final DebugClientServer debugClientServer) { synchronized (breakpoints) { if (!breakpoints.containsKey(c)) { breakpoints.put(c, new HashSet<Character>()); System.out.println("making new cpu bp set for cpu id:" + c.id); } final HashSet<Character> bpmap = breakpoints.get(c); final Character caddr = (char) addr; boolean add = !bpmap.contains(caddr); if (add) { bpmap.add(caddr); final CpuWatcher w = new CpuWatcher() { CpuWatcher that; { that = this; } public void cpu_changed(final Dcpu cpu, long cyclesAdvanved, boolean idle) { if (cpu.regs.pc == caddr) { if (bpmap.contains(caddr)) { cpu.pause(); debugClientServer.sendResponse(new DebugResponse(CommandStatus.UNSOLICITED, "breakpoint reached", new long[]{})); } else { cpu.runInCpuThread(new Runnable() { public void run() { cpu.removeWatcher(that); } }); } } } }; c.runInCpuThread(new Runnable() { public void run() { c.addWatcher(w); } }); } else { bpmap.remove(caddr); } } return new DebugResponse(CommandStatus.PASS, "breakpoint toggled", new long[] {}); } private static HashMap<Dcpu, HashSet<Character>> breakpoints = new HashMap<>(); }