diff --git a/src/assets/error.png b/src/assets/error.png new file mode 100644 index 0000000..5365ce3 Binary files /dev/null and b/src/assets/error.png differ diff --git a/src/assets/ok.png b/src/assets/ok.png new file mode 100644 index 0000000..d12c49d Binary files /dev/null and b/src/assets/ok.png differ diff --git a/src/assets/pause.png b/src/assets/pause.png new file mode 100644 index 0000000..4f55430 Binary files /dev/null and b/src/assets/pause.png differ diff --git a/src/components/ControlPanel.vue b/src/components/ControlPanel.vue index e947463..6a81685 100644 --- a/src/components/ControlPanel.vue +++ b/src/components/ControlPanel.vue @@ -1,18 +1,32 @@ @@ -25,11 +35,15 @@ runner.AddEventListener("PCChanged", (_) => {
- {{ index + 1 }} + {{ index }}
{{ instruction[0] }} {{ instruction[1] }} {{ instruction[2] }} +
+ {{ asmCode[index][0] }} + {{ asmCode[index][1] }}, + {{ asmCode[index][2] }}
@@ -81,10 +95,31 @@ span { .operand { color: rgb(224, 108, 117); + } .gutter { display: inline; width: 9px; } + +.split { + margin-left: 10px; + background-color: #9e9e9e; + width: 1px; + height: 28px; +} + +.asm-mnemonic { + color: rgb(198, 120, 221); + margin-left: 10px; + padding-right: 10px; + width: 50px; +} + +.asm-operand { + color: rgb(224, 108, 117); + margin-left: 5px; + width: 30px; +} \ No newline at end of file diff --git a/src/components/MemoryLayout.vue b/src/components/MemoryLayout.vue index fb2f697..6ab76cc 100644 --- a/src/components/MemoryLayout.vue +++ b/src/components/MemoryLayout.vue @@ -96,7 +96,7 @@ let memory = computed(() => { } .register-loose-layout { - grid-template-columns: repeat(7, 1fr); + grid-template-columns: repeat(8, 1fr); } .register-compact-layout { @@ -150,6 +150,7 @@ span { .screen-row { color: rgb(224, 188, 105); + white-space: nowrap; } .screen-memory { diff --git a/src/utils/Complier.ts b/src/utils/Complier.ts index 815217d..dcdaec0 100644 --- a/src/utils/Complier.ts +++ b/src/utils/Complier.ts @@ -5,7 +5,6 @@ export class CompileError extends Error { super(message); this.index = index; } - index: number; } @@ -204,6 +203,8 @@ export class Compiler { mnemonicAndVals[i] = this.Labels.get(mnemonicAndVals[i])!.toString(16).padStart(2,'0'); else mnemonicAndVals[i] = parseInt(mnemonicAndVals[i]).toString(16).padStart(2,'0'); + if (mnemonicAndVals[1] === 'NaN'||mnemonicAndVals[2] === 'NaN') + throw new CompileError("Invalid operand", index); this.PCToMachineCode.set(pc, Compiler.KeyWordsToMachineCode.get(mnemonicAndVals[0])! + mnemonicAndVals[1] + mnemonicAndVals[2]); }); } catch (e) { diff --git a/src/utils/Runner.ts b/src/utils/Runner.ts index 1f74a5a..8a7a6ab 100644 --- a/src/utils/Runner.ts +++ b/src/utils/Runner.ts @@ -1,6 +1,15 @@ import {MemoryManager, Byte} from "./MemoryManager"; import {Compiler} from "./Complier.ts"; +export class RunningError extends Error { + constructor(message: string, index: number) { + super(message); + this.index = index; + } + + index: number; +} + export enum RunnerState { Stop, Running, @@ -9,7 +18,7 @@ export enum RunnerState { export class Runner { // 与Compiler 类似的事件机制 要是再来一个我就把这段逻辑单独抽出来 - //[PCChanged,RegistersChanged] + //[PCChanged,RegistersChanged,RunningError(string,RunningError)] _events: Map void)[]> = new Map void)[]>(); AddEventListener(event: string, callback: (arg0: string, arg1?: any) => void) { @@ -28,6 +37,7 @@ export class Runner { } State: RunnerState = RunnerState.Stop; + _runningSpeed: number = 20; _processor: Processor; _memory: MemoryManager; _processCounter: number = 0; @@ -35,6 +45,18 @@ export class Runner { _stack: [Byte[], number][] = []; _intervalId: NodeJS.Timeout | null = null; + set RunningSpeed(speed: number) { + this._runningSpeed = speed; + if (this.State === RunnerState.Running) { + this.Pause(); + this.Resume(); + } + } + + get RunningSpeed() { + return this._runningSpeed; + } + StartInterval() { if (this._intervalId === null) this._intervalId = setInterval(() => { @@ -43,7 +65,7 @@ export class Runner { return; } this.RunOneLineCode(); - }, 20); + }, this._runningSpeed); } StopInterval() { @@ -73,30 +95,44 @@ export class Runner { if (this._compiler.PCToCode.has(this._processCounter)) code = this._compiler.PCToCode.get(this._processCounter) as string; else - throw new Error("PC out of range"); + throw new RunningError("PC out of range", 0); this._processCounter++; let mnemonicAndVals = code.split(/[\s,]+/); // 如果指令不合法 Compiler应该会有异常抛出 则不能执行到这里 if (mnemonicAndVals.length !== 3) - throw new Error("Invalid code"); + throw new RunningError("Invalid code", this._processCounter); let mnemonic = mnemonicAndVals[0]; - function getVal(runner:Runner, val: string) { + + function getVal(runner: Runner, val: string) { if (runner._processor._registers.has(val)) return val; - else if(runner._compiler.Labels.has(val)) + else if (runner._compiler.Labels.has(val)) return runner._compiler.Labels.get(val) as number; else { let t = parseInt(val); - if(isNaN(t)) - throw new Error("Invalid argument"); + if (isNaN(t)) { + throw new RunningError("Invalid argument", runner._processCounter); + } return t; } } - return [mnemonic, getVal(this,mnemonicAndVals[1]), getVal(this,mnemonicAndVals[2])]; + + return [mnemonic, getVal(this, mnemonicAndVals[1]), getVal(this, mnemonicAndVals[2])]; } RunOneLineCode() { - this._processor.RunCode(...this.CommandParsing(), this.GetMemory, this.SetMemory, this.SetPC, this.SaveEnv, this.RestoreEnv); + try { + this._processor.RunCode(...this.CommandParsing(), this.GetMemory, this.SetMemory, this.SetPC, this.SaveEnv, this.RestoreEnv); + }catch (e:any) + { + console.log(e); + e = e as RunningError; + if(e === undefined) + throw new RunningError("Unknown error",this._processCounter); + e.index = e.index === -1? this._processCounter : e.index; + this.Pause(); + this.Notify("RunningError", e); + } this.Notify("PCChanged"); this.Notify("RegistersChanged"); } @@ -128,9 +164,16 @@ export class Runner { this.RunOneLineCode() } + Pause() { + this.State = RunnerState.Stop; + this.StopInterval() + } + Stop() { this.State = RunnerState.Stop; this.StopInterval() + this._processCounter = 0; + this._memory.clear(); } Refresh() { @@ -138,38 +181,31 @@ export class Runner { } GetMemory(t: number): Byte { - console.log(this._memory) return this._memory.GetVal(t); } SetMemory(t: number, val: Byte): void { - console.log("mem Test:") - console.log(this) - console.log(this._memory) - this._memory.SetVal(t, val); } SaveEnv() { if (this._stack.length > 8) - throw new Error("Stack overflow"); - this._stack.push([this._processor.GetRegisters().map(x=>x.Copy()), this._processCounter]); + throw new RunningError("Stack overflow",this._processCounter); + this._stack.push([this._processor.GetRegisters().map(x => x.Copy()), this._processCounter]); } RestoreEnv() { if (this._stack.length === 0) { - this.Stop(); + this.Pause(); return; } let [regs, pc] = this._stack.pop()!; - console.log('restore',regs); this._processor.SetRegisters(regs); this._processCounter = pc; } SetPC(addr: number) { this._processCounter = addr; - console.log("PC set to", addr); } GetRegisters(): Byte[] { @@ -202,17 +238,15 @@ class Processor { if (this._registers.has(register as string)) return this._registers.get(register as string)!; else - throw new Error("Invalid register"); + throw new RunningError("Invalid register",-1); } GetRegisters(): Byte[] { - console.log("Get", this._registers.values()); return Array.from(this._registers.values()); } SetRegisters(registers: Byte[]) { for (let i = 0; i < 7; i++) { - console.log("Set", String.fromCharCode('A'.charCodeAt(0) + i) + 'X',registers[i].value); this._registers.get(String.fromCharCode('A'.charCodeAt(0) + i) + 'X')!.SetValue(registers[i]); } } @@ -222,7 +256,12 @@ class Processor { } SetRegisterValue(register: string | number, value: number) { - this.GetRegister(register).SetValue(value); + try { + this.GetRegister(register).SetValue(value); + }catch (e) + { + throw new RunningError("Invalid value",-1); + } } InRegister(register: string | number): boolean { @@ -230,11 +269,15 @@ class Processor { } RunCode(mnemonic: string, operandA: number | string, operandB: number | string, getMemory: (addr: number) => Byte, setMemory: (addr: number, value: Byte) => void, setPC: (addr: number) => void, saveEnv: () => void, restoreEnv: () => void) { - console.log(mnemonic, operandA, operandB); - if(this.InRegister(operandA)) - console.log(this.GetRegisterValue(operandA)); - if(this.InRegister(operandB)) - console.log(this.GetRegisterValue(operandB)); + { + let a = operandA; + let b = operandB; + if (this.InRegister(a)) + a = a + '(' + this.GetRegisterValue(a) + ')'; + if (this.InRegister(b)) + b = b + '(' + this.GetRegisterValue(b) + ')'; + console.log(mnemonic,a,b); + } switch (mnemonic) { case "nop": break; @@ -301,7 +344,6 @@ class Processor { } break; case "st": - console.log(operandA, operandB); if (this.InRegister(operandA) && typeof operandB === 'number') { setMemory(operandB as number, this.GetRegister(operandA)); return; @@ -311,18 +353,15 @@ class Processor { if (this.InRegister(operandA) && this.InRegister(operandB)) { this.GetRegister(operandA).SetValue(this.GetRegister(operandB)); return; - } - else if(this.InRegister(operandA) && typeof operandB === 'number') { + } else if (this.InRegister(operandA) && typeof operandB === 'number') { this.GetRegister(operandA).SetValue(operandB); return; } break; case "cp": - console.log(operandA, operandB); operandA = this.InRegister(operandA) ? this.GetRegisterValue(operandA) : operandA; operandB = this.InRegister(operandB) ? this.GetRegisterValue(operandB) : operandB; if (typeof operandA === 'number' && typeof operandB === 'number') { - console.log(operandA, operandB); for (let i = 0; i < (this._registers.get("BX")!.GetValue() as number); i++) setMemory(operandB + i, getMemory(operandA + i)); return; @@ -368,7 +407,9 @@ class Processor { return; } break + default: + throw new RunningError("Invalid mnemonic",-1); } - throw new Error("Invalid argument"); + throw new RunningError("Invalid argument",-1); } }