diff --git a/HelloWorld.bin b/HelloWorld.bin
index e14a5b3..995036f 100644
Binary files a/HelloWorld.bin and b/HelloWorld.bin differ
diff --git a/index.html b/index.html
index f4a8573..8850f76 100644
--- a/index.html
+++ b/index.html
@@ -20,6 +20,7 @@
diff --git a/src/computer.ts b/src/computer.ts
index a71f1de..a202dec 100644
--- a/src/computer.ts
+++ b/src/computer.ts
@@ -1,5 +1,5 @@
-import { CpuEvent, MemoryCellType } from "./events";
-import { u8 } from "./etc";
+import { CpuEvent, CpuEventHandler, MemoryCellType, UiEvent, UiEventHandler } from "./events";
+import { byte_array_to_js_source, format_hex, u8 } from "./etc";
import { EventHandler } from "./eventHandler";
import { ConstParam, Instruction, ISA, MemorParam, RegisParam } from "./instructionSet";
@@ -17,21 +17,13 @@ export type ComputerState = {
};
export class Computer {
- private memory: Uint8Array;
- private program_counter: u8;
- private registers: Uint8Array;
- private current_instr: TempInstrState | null;
- events: EventHandler
;
+ private memory = new Uint8Array(256);
+ private registers = new Uint8Array(8);
+ private program_counter: u8 = 0;
+ private current_instr: TempInstrState | null = null;
+ events: CpuEventHandler = new EventHandler() as CpuEventHandler;
constructor() {
- // 256 bytes for both program and general purpose memory.
- this.memory = new Uint8Array(256);
- // 8 registers
- this.registers = new Uint8Array(8);
- this.program_counter = 0;
- this.current_instr = null;
- this.events = new EventHandler();
-
// Add events
for (const [, e_type] of Object.entries(CpuEvent)) {
this.events.register_event(e_type as CpuEvent);
@@ -47,8 +39,9 @@ export class Computer {
this.events.dispatch(CpuEvent.MemoryByteParsed, {
type: MemoryCellType.InvalidInstruction,
pos: this.program_counter,
+ code: current_byte,
});
- console.log(`Invalid instruction: ${current_byte.toString(16).toUpperCase().padStart(2, "0")}`);
+ console.log(`Invalid instruction: ${format_hex(current_byte)}`);
this.step_forward();
return;
}
@@ -62,6 +55,7 @@ export class Computer {
type: MemoryCellType.Instruction,
pos: this.program_counter,
instr: parsed_instruction,
+ code: current_byte,
});
}
@@ -80,7 +74,15 @@ export class Computer {
} else if (b instanceof MemorParam) {
a = MemoryCellType.Memory;
}
- this.events.dispatch(CpuEvent.MemoryByteParsed, { type: a, pos: this.program_counter, param: b });
+ if (a === undefined) {
+ throw new Error("Shouldn't");
+ }
+ this.events.dispatch(CpuEvent.MemoryByteParsed, {
+ type: a,
+ pos: this.program_counter,
+ code: current_byte,
+ param: b,
+ });
this.current_instr.params[this.current_instr.params_found] = current_byte;
this.current_instr.params_found += 1;
if (this.current_instr.params.length !== this.current_instr.params_found) {
@@ -93,10 +95,10 @@ export class Computer {
noStep: function (): void {
this.should_step = false;
},
- event: this.events.dispatch.bind(this.events),
+ dispatch: this.events.dispatch.bind(this.events),
};
this.current_instr.instr.execute(this, this.current_instr.params, execution_post_action_state);
-
+ this.events.dispatch(CpuEvent.InstructionExecuted, { instr: this.current_instr.instr });
this.current_instr = null;
if (execution_post_action_state.should_step) {
@@ -136,9 +138,20 @@ export class Computer {
this.events.dispatch(CpuEvent.Reset, null);
}
+ init_events(ui: UiEventHandler): void {
+ ui.listen(UiEvent.RequestCpuCycle, () => {
+ this.cycle();
+ });
+ }
+
load_memory(program: Array): void {
+ console.log(byte_array_to_js_source(program));
const max_loop = Math.min(this.memory.length, program.length);
for (let i = 0; i < max_loop; i++) {
+ // Don't fire event if no change is made
+ if (this.memory[i] === program[i]) {
+ continue;
+ }
this.memory[i] = program[i];
this.events.dispatch(CpuEvent.MemoryChanged, { address: i, value: program[i] });
}
diff --git a/src/etc.ts b/src/etc.ts
index 04243c1..924d35e 100644
--- a/src/etc.ts
+++ b/src/etc.ts
@@ -4,6 +4,17 @@ export type u8 = number;
// Jquery lite
export const $ = (s: string): HTMLElement => document.getElementById(s) as HTMLElement;
+export const format_hex = (n: number): string => n.toString(16).toUpperCase().padStart(2, "0");
+
+export const byte_array_to_js_source = (a: Array): string => {
+ let str = "[";
+ for (const b of a) {
+ str += `0x${format_hex(b)},`;
+ }
+ str += "]";
+ return str;
+};
+
export function el(type: string, id?: string): HTMLElement {
const element = document.createElement(type);
if (id === undefined) {
diff --git a/src/eventHandler.ts b/src/eventHandler.ts
index 6ddead8..68972b4 100644
--- a/src/eventHandler.ts
+++ b/src/eventHandler.ts
@@ -1,18 +1,16 @@
export class Event {
identifier: T;
- callbacks: Array<(event_data: unknown) => void>;
+ callbacks: Array<(event_data: unknown) => void> = [];
constructor(identifier: T) {
this.identifier = identifier;
- this.callbacks = [];
}
}
export class EventHandler {
- events: Array>;
+ events: Array> = [];
private sealed: boolean;
constructor() {
this.sealed = false;
- this.events = [];
}
seal(): void {
@@ -38,7 +36,7 @@ export class EventHandler {
callback(event_data);
}
}
- add_listener(identifier: T, callback: (event_data: unknown) => void): void {
+ listen(identifier: T, callback: (event_data: unknown) => void): void {
if (!this.sealed) throw new Error("Event handler must be sealed before adding listener");
const event = this.events.find((e) => e.identifier === identifier);
if (event === undefined) {
diff --git a/src/events.ts b/src/events.ts
index 1df9206..0fa883a 100644
--- a/src/events.ts
+++ b/src/events.ts
@@ -1,8 +1,13 @@
+import { u8 } from "./etc";
+import { EventHandler } from "./eventHandler";
+import { Instruction, ParameterType } from "./instructionSet";
+
export enum CpuEvent {
MemoryChanged,
RegisterChanged,
- MemoryByteParsed,
ProgramCounterChanged,
+ MemoryByteParsed,
+ InstructionExecuted,
Print,
Reset,
}
@@ -14,3 +19,32 @@ export enum MemoryCellType {
Memory,
Constant,
}
+
+// Handily explained in https://www.cgjennings.ca/articles/typescript-events/
+interface CpuEventMap {
+ [CpuEvent.MemoryChanged]: { address: u8; value: u8 };
+ [CpuEvent.RegisterChanged]: { register_no: u8; value: u8 };
+ [CpuEvent.ProgramCounterChanged]: { counter: u8 };
+ [CpuEvent.Reset]: null;
+ [CpuEvent.MemoryByteParsed]: { type: MemoryCellType; pos: u8; code: u8; param?: ParameterType; instr?: Instruction };
+ [CpuEvent.InstructionExecuted]: { instr: Instruction };
+ [CpuEvent.Print]: string;
+}
+
+export interface CpuEventHandler extends EventHandler {
+ listen(type: E, listener: (ev: CpuEventMap[E]) => void): void;
+ dispatch(type: E, data: CpuEventMap[E]): void;
+}
+
+export enum UiEvent {
+ RequestCpuCycle,
+}
+
+interface UiEventMap {
+ [UiEvent.RequestCpuCycle]: null;
+}
+
+export interface UiEventHandler extends EventHandler {
+ listen(type: E, listener: (ev: UiEventMap[E]) => void): void;
+ dispatch(type: E, data: UiEventMap[E]): void;
+}
diff --git a/src/index.ts b/src/index.ts
index bde19a1..e97a127 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -5,8 +5,22 @@ import { generate_isa } from "./isaGenerator";
import { UI } from "./ui";
function main(): void {
- // const program = [0x2f, 0x01, 0x01, 0x40, 0x00, 0x01, 0x21, 0x00, 0x02, 0x10, 0x00];
- const program = [0x2f, 0x00, 0x41, 0xfe, 0x00, 0x30, 0x00, 0x10, 0x03];
+ const program = [
+ 0x2f, 0x00, 0xf0, 0x20, 0x07, 0x00, 0x50, 0x05, 0x06, 0x07, 0x11, 0x00, 0x05, 0xfe, 0x07, 0x30, 0x00, 0x10, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57,
+ 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x0a, 0x00, 0x00, 0x00,
+ ];
const container = $("container");
if (container === null) {
@@ -14,9 +28,10 @@ function main(): void {
}
const computer = new Computer();
- const ui = new UI(container, computer.events);
+ const ui = new UI(container);
+ ui.init_events(computer.events);
computer.load_memory(program);
- ui.set_step_func(computer.cycle.bind(computer));
+ computer.init_events(ui.events);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window).comp = computer;
diff --git a/src/instructionSet.ts b/src/instructionSet.ts
index 4c44927..dafec60 100644
--- a/src/instructionSet.ts
+++ b/src/instructionSet.ts
@@ -1,10 +1,10 @@
-import { CpuEvent } from "./events";
-import { u8 } from "./etc";
+import { CpuEvent, CpuEventHandler } from "./events";
+import { format_hex, u8 } from "./etc";
-class ParameterType {
- readonly description: string;
+export class ParameterType {
+ readonly desc: string;
constructor(description: string) {
- this.description = description;
+ this.desc = description;
}
}
@@ -24,7 +24,7 @@ interface GenericComputer {
interface AfterExecutionComputerAction {
// Does not step forward the program counter
noStep: () => void;
- event: (e: CpuEvent, data: unknown) => void;
+ dispatch: CpuEventHandler["dispatch"];
}
export interface Instruction {
@@ -43,7 +43,7 @@ export class InstructionSet {
insertInstruction(hexCode: u8, instruction: Instruction): void {
if (this.instructions.has(hexCode)) {
- throw new Error(`Instruction "${hexCode.toString(16)}" already exists`);
+ throw new Error(`Instruction "${format_hex(hexCode)}" already exists`);
}
this.instructions.set(hexCode, instruction);
}
@@ -75,17 +75,17 @@ ISA.insertInstruction(0x10, {
ISA.insertInstruction(0x20, {
name: "LoadToRegister",
- desc: "Sets the byte in register (P1) to be the contents of memory cell (P2)",
- params: [new RegisParam(""), new MemorParam("")],
+ desc: "Sets the byte in register (P1) to be the contents of memory cell at address in register (P2)",
+ params: [new RegisParam("Set this register to"), new MemorParam("the byte held in this memory address")],
execute(c, p) {
const [register_no, mem_address] = p;
- c.setRegister(register_no, c.getMemory(mem_address));
+ c.setRegister(register_no, c.getMemory(c.getRegister(mem_address)));
},
});
ISA.insertInstruction(0x21, {
name: "SaveToMemory",
- desc: "Writes the byte in register (P1) to the processing memory location (P2)",
+ desc: "Writes the byte in register (P1) to the memory cell (P2)",
params: [new RegisParam(""), new MemorParam("")],
execute(c, p) {
const [register_no, mem_address] = p;
@@ -96,7 +96,7 @@ ISA.insertInstruction(0x21, {
ISA.insertInstruction(0x2f, {
name: "AssignRegister",
desc: "Assigns constant value (P2) to register (P1)",
- params: [new RegisParam(""), new ConstParam("")],
+ params: [new RegisParam("Set this register"), new ConstParam("to this constant")],
execute(c, p) {
const [register_no, value] = p;
c.setRegister(register_no, value);
@@ -104,9 +104,9 @@ ISA.insertInstruction(0x2f, {
});
ISA.insertInstruction(0x11, {
- name: "GotoIfLowBit",
+ name: "GotoIfLowBitHigh",
desc: "Moves the CPU instruction counter to the value in (P1) if the value in register (P2) has the lowest bit true",
- params: [new ConstParam("new instruction counter location"), new RegisParam("Register to check")],
+ params: [new ConstParam("Set program counter to this constant"), new RegisParam("if this register's 1 bit is set")],
execute(c, p, a) {
const [new_address, check_register_no] = p;
if (c.getRegister(check_register_no) % 2 === 1) {
@@ -150,24 +150,28 @@ ISA.insertInstruction(0x40, {
ISA.insertInstruction(0x50, {
name: "Equals",
- desc: "If byte in register (P1) equals byte in register (P2), set byte in register (P3) to 0x01",
- params: [new RegisParam(""), new RegisParam(""), new RegisParam("")],
+ desc: "If byte in register (P2) equals byte in register (P3), set byte in register (P1) to 0x01",
+ params: [
+ new RegisParam("Set this register to be 0x01"),
+ new RegisParam("if this register and"),
+ new RegisParam("this register are equal (else 0x00)"),
+ ],
execute(c, p) {
const [register_no_1, register_no_2, register_no_3] = p;
- const truth = c.getRegister(register_no_1) === c.getRegister(register_no_2) ? 0x01 : 0x00;
- c.setRegister(register_no_3, truth);
+ const truth = c.getRegister(register_no_2) === c.getRegister(register_no_3) ? 0x01 : 0x00;
+ c.setRegister(register_no_1, truth);
},
});
ISA.insertInstruction(0xfe, {
name: "PrintASCII",
desc: "Prints the ASCII byte in register (P1) to console",
- params: [new RegisParam("")],
+ params: [new RegisParam("Register to print from")],
execute(c, p, a) {
const register_no = p[0];
const asciiByte = c.getRegister(register_no);
const char = String.fromCharCode(asciiByte);
- a.event(CpuEvent.Print, { data: char });
+ a.dispatch(CpuEvent.Print, char);
},
});
diff --git a/src/isaGenerator.ts b/src/isaGenerator.ts
index 0538ac6..2b4a088 100644
--- a/src/isaGenerator.ts
+++ b/src/isaGenerator.ts
@@ -1,4 +1,4 @@
-import { u8 } from "./etc";
+import { format_hex, u8 } from "./etc";
import { Instruction, InstructionSet } from "./instructionSet";
export function generate_isa(iset: InstructionSet): string {
@@ -13,7 +13,7 @@ export function generate_isa(iset: InstructionSet): string {
max_instr_name_len = Math.max(max_instr_name_len, short_description.length);
}
for (const instruction of instructions) {
- const hex_code = instruction[0].toString(16).toUpperCase().padStart(2, "0");
+ const hex_code = format_hex(instruction[0]);
const short_description = instruction[1].name.padEnd(max_instr_name_len, " ");
const parameter_count = instruction[1].params.length;
const description = instruction[1].desc;
diff --git a/src/ui.ts b/src/ui.ts
index 4d6b844..ef7ad6e 100644
--- a/src/ui.ts
+++ b/src/ui.ts
@@ -1,24 +1,33 @@
import { ComputerState } from "./computer";
-import { CpuEvent, MemoryCellType } from "./events";
-import { $, el, u8 } from "./etc";
+import { CpuEvent, CpuEventHandler, MemoryCellType, UiEvent, UiEventHandler } from "./events";
+import { $, el, format_hex, u8 } from "./etc";
+import { Instruction, ParameterType } from "./instructionSet";
import { EventHandler } from "./eventHandler";
export class UI {
container: HTMLElement;
program_memory: HTMLElement;
- program_memory_cells: Array;
+ program_memory_cells: Array = [];
registers: HTMLElement;
- register_cells: Array;
- step_func: null | (() => void);
-
- program_counter: u8;
+ printout: HTMLElement;
+ instruction_explainer: HTMLElement;
+ register_cells: Array = [];
+ instruction_parsing_addresses: Array = [];
+ program_counter: u8 = 0;
auto_running: boolean;
- constructor(parent: HTMLElement, cpu_events: EventHandler) {
+
+ events: UiEventHandler = new EventHandler() as UiEventHandler;
+
+ constructor(parent: HTMLElement) {
+ for (const [, e_type] of Object.entries(UiEvent)) {
+ this.events.register_event(e_type as UiEvent);
+ }
+ this.events.seal();
this.container = parent;
- this.program_counter = 0;
+ this.printout = $("printout");
+ this.instruction_explainer = $("instruction_explainer");
const program_mem = $("memory");
- this.program_memory_cells = [];
for (let i = 0; i < 256; i++) {
const mem_cell = el("div", `p_${i}`);
mem_cell.textContent = "00";
@@ -28,10 +37,9 @@ export class UI {
this.program_memory_cells[0].classList.add("div", "program_counter");
this.program_memory = program_mem;
- this.register_cells = [];
const registers = $("registers");
for (let i = 0; i < 8; i++) {
- const reg_cell = el("div", `R_${i}`);
+ const reg_cell = el("div", `r_${i}`);
reg_cell.textContent = "00";
registers.appendChild(reg_cell);
this.register_cells.push(reg_cell);
@@ -39,7 +47,6 @@ export class UI {
this.registers = registers;
- this.step_func = null;
this.auto_running = false;
const pp_button = $("pause_play_button");
if (pp_button === null) {
@@ -54,48 +61,32 @@ export class UI {
pp_button.textContent = "Storp";
}
});
- document.getElementById("step_button")?.addEventListener("click", () => {
+ $("step_button")?.addEventListener("click", () => {
if (this.auto_running) {
this.stop_auto();
}
- if (this.step_func === null) {
- return;
- }
- this.step_func();
- });
- cpu_events.add_listener(CpuEvent.MemoryChanged, (e) => {
- const { address, value } = e as { address: u8; value: u8 };
- this.program_memory_cells[address].textContent = value.toString(16).toUpperCase().padStart(2, "0");
+ this.events.dispatch(UiEvent.RequestCpuCycle, null);
});
- cpu_events.add_listener(CpuEvent.RegisterChanged, (e) => {
- const { register_no, value } = e as { register_no: u8; value: u8 };
- this.register_cells[register_no].textContent = value.toString(16).toUpperCase().padStart(2, "0");
+ }
+
+ init_events(cpu_events: CpuEventHandler): void {
+ cpu_events.listen(CpuEvent.MemoryChanged, ({ address, value }) => {
+ this.program_memory_cells[address].textContent = format_hex(value);
});
- cpu_events.add_listener(CpuEvent.ProgramCounterChanged, (e) => {
- const { counter } = e as { counter: u8 };
+ cpu_events.listen(CpuEvent.RegisterChanged, ({ register_no, value }) => {
+ this.register_cells[register_no].textContent = format_hex(value);
+ });
+ cpu_events.listen(CpuEvent.ProgramCounterChanged, ({ counter }) => {
this.program_memory_cells[this.program_counter].classList.remove("program_counter");
this.program_memory_cells[counter].classList.add("program_counter");
this.program_counter = counter;
});
- cpu_events.add_listener(CpuEvent.Print, (e) => {
- const { data } = e as { data: u8 };
- const printout = $("printout");
- if (printout === null) {
- throw new Error("Couldn't get printout");
- }
- printout.textContent = (printout.textContent ?? "") + data;
+ cpu_events.listen(CpuEvent.Print, (char) => {
+ this.printout.textContent = (this.printout.textContent ?? "") + char;
});
- cpu_events.add_listener(CpuEvent.Reset, () => {
- this.stop_auto();
- this.program_memory_cells.forEach((c) => {
- c.className = "";
- c.textContent = "00";
- });
- this.register_cells.forEach((r) => {
- r.textContent = "00";
- });
- this.program_counter = 0;
+ cpu_events.listen(CpuEvent.Reset, () => {
+ this.reset();
});
const map: Map = new Map();
@@ -105,8 +96,8 @@ export class UI {
map.set(MemoryCellType.InvalidInstruction, "invalid_instruction");
map.set(MemoryCellType.Memory, "memory");
map.set(MemoryCellType.Register, "register");
- cpu_events.add_listener(CpuEvent.MemoryByteParsed, (e) => {
- const { type, pos } = e as { type: MemoryCellType; pos: u8 };
+ cpu_events.listen(CpuEvent.MemoryByteParsed, (e) => {
+ const { type, pos, code } = e;
const css_class = map.get(type);
if (css_class === undefined) {
throw new Error("Something went wrong");
@@ -115,27 +106,74 @@ export class UI {
if (other_class === css_class) continue;
this.program_memory_cells[pos].classList.remove(other_class);
}
+ if (type === MemoryCellType.Instruction) {
+ while (this.instruction_parsing_addresses.length > 0) {
+ const num = this.instruction_parsing_addresses.pop();
+ if (num === undefined) {
+ throw new Error("Shouldn't happen");
+ }
+ this.program_memory_cells[num].classList.remove("instruction_argument");
+ this.program_memory_cells[num].classList.remove("current_instruction");
+ }
+ this.instruction_explainer.innerHTML = "";
+ const { instr } = e as { instr: Instruction };
+ this.program_memory_cells[pos].classList.add("current_instruction");
+ this.instruction_parsing_addresses.push(pos);
+ const instr_box = el("div", "expl_box");
+ const instr_icon = el("span", "expl_icon");
+ instr_icon.classList.add(css_class);
+ instr_icon.setAttribute("title", css_class.toUpperCase());
+ instr_icon.textContent = format_hex(code);
+ const instr_box_text = el("span", "expl_text");
+ instr_box_text.textContent = `${instr.name}`;
+ instr_box.appendChild(instr_icon);
+ instr_box.appendChild(instr_box_text);
+ this.instruction_explainer.appendChild(instr_box);
+ } else if (type !== MemoryCellType.InvalidInstruction) {
+ const { param } = e as { param: ParameterType };
+ this.program_memory_cells[pos].classList.add("instruction_argument");
+ this.instruction_parsing_addresses.push(pos);
+ const instr_box = el("div", "expl_box");
+ const instr_icon = el("span", "expl_icon");
+ instr_icon.classList.add(css_class);
+ instr_icon.setAttribute("title", css_class.toUpperCase());
+ instr_icon.textContent = format_hex(code);
+ const instr_box_text = el("span", "expl_text");
+ instr_box_text.textContent = `${param.desc}`;
+ instr_box.appendChild(instr_icon);
+ instr_box.appendChild(instr_box_text);
+ this.instruction_explainer.appendChild(instr_box);
+ }
this.program_memory_cells[pos].classList.add(css_class);
});
+
+ cpu_events.listen(CpuEvent.InstructionExecuted, ({ instr }) => {});
+ }
+
+ reset(): void {
+ this.stop_auto();
+ this.program_memory_cells.forEach((c) => {
+ c.className = "";
+ c.textContent = "00";
+ });
+ this.register_cells.forEach((r) => {
+ r.textContent = "00";
+ });
+ this.program_counter = 0;
+ this.program_memory_cells[0].classList.add("program_counter");
+ this.printout.textContent = "";
}
start_auto(speed: number = 200): void {
- if (this.step_func === null) {
- return;
- }
if (this.auto_running) {
return;
}
this.auto_running = true;
const loop = (): void => {
- if (this.step_func === null) {
- this.auto_running = false;
- return;
- }
if (this.auto_running === false) {
return;
}
- this.step_func();
+ this.events.dispatch(UiEvent.RequestCpuCycle, null);
setTimeout(loop, speed);
// requestAnimationFrame(loop);
};
@@ -146,10 +184,6 @@ export class UI {
this.auto_running = false;
}
- set_step_func(f: () => void): void {
- this.step_func = f;
- }
-
state_update_event(state: ComputerState): void {
const current_instr = state.current_instruction;
if (current_instr !== null) {