100 lines
3.1 KiB
TypeScript
100 lines
3.1 KiB
TypeScript
import { CpuEvent, CpuEventHandler, UiEvent, UiEventHandler } from "../events";
|
|
import { ParamType } from "../instructionSet";
|
|
import { u8 } from "../num.js";
|
|
import { UiComponent } from "./uiComponent";
|
|
import { CelledViewer } from "./celledViewer";
|
|
import { EditorContext } from "./editableHex";
|
|
|
|
type MemoryCell = {
|
|
el: HTMLDivElement;
|
|
};
|
|
|
|
export class MemoryView extends CelledViewer implements UiComponent {
|
|
program_counter: u8 = 0;
|
|
last_accessed_cell: u8 | null = null;
|
|
events: UiEventHandler;
|
|
constructor(element: HTMLElement, e: UiEventHandler) {
|
|
super(16, 16, element);
|
|
this.program_counter = 0;
|
|
this.events = e;
|
|
|
|
const list = this.cells.map((c) => c.el);
|
|
const editor = new EditorContext(list, this.width, this.height, (i, value) => {
|
|
this.events.dispatch(UiEvent.RequestMemoryChange, { address: i as u8, value });
|
|
});
|
|
this.events.listen(UiEvent.EditOn, () => {
|
|
editor.enable();
|
|
for (const cell of this.cells) {
|
|
cell.el.className = "";
|
|
}
|
|
});
|
|
this.events.listen(UiEvent.EditOff, () => {
|
|
editor.disable();
|
|
for (const cell of this.cells) {
|
|
cell.el.className = "";
|
|
}
|
|
});
|
|
}
|
|
|
|
set_program_counter(position: u8): void {
|
|
this.remove_cell_class(this.program_counter, "program_counter");
|
|
this.add_cell_class(position, "program_counter");
|
|
this.program_counter = position;
|
|
}
|
|
|
|
reset(): void {
|
|
super.reset();
|
|
this.last_accessed_cell = null;
|
|
this.set_program_counter(0);
|
|
}
|
|
|
|
init_cpu_events(c: CpuEventHandler): void {
|
|
c.listen(CpuEvent.MemoryAccessed, ({ address, bank, value }) => {
|
|
if (bank !== 0) return;
|
|
if (this.last_accessed_cell !== address) {
|
|
if (this.last_accessed_cell !== null) {
|
|
this.remove_cell_class(this.last_accessed_cell, "last_access");
|
|
}
|
|
this.add_cell_class(address, "last_access");
|
|
this.last_accessed_cell = address;
|
|
}
|
|
});
|
|
c.listen(CpuEvent.MemoryChanged, ({ address, bank, value }) => {
|
|
if (bank !== 0) {
|
|
return;
|
|
}
|
|
this.set_cell_value(address, value);
|
|
});
|
|
c.listen(CpuEvent.ProgramCounterChanged, ({ counter }) => {
|
|
this.set_program_counter(counter);
|
|
});
|
|
c.listen(CpuEvent.ParameterParsed, ({ param, code, pos }) => {
|
|
this.add_cell_class(pos, "instruction_argument");
|
|
const t = param.type;
|
|
this.remove_cell_class(pos, "constant", "register", "memory", "instruction", "invalid");
|
|
let name: string = "";
|
|
if (t === ParamType.Const) {
|
|
name = "constant";
|
|
} else if (t === ParamType.Memory) {
|
|
name = "memory";
|
|
} else if (t === ParamType.Register) {
|
|
name = "register";
|
|
} else {
|
|
throw new Error("unreachable");
|
|
}
|
|
this.add_cell_class(pos, name);
|
|
});
|
|
c.listen(CpuEvent.InstructionParsed, ({ instr, code, pos }) => {
|
|
this.remove_all_cell_class("instruction_argument");
|
|
this.remove_all_cell_class("current_instruction");
|
|
this.remove_cell_class(pos, "constant", "register", "memory", "invalid");
|
|
this.add_cell_class(pos, "current_instruction");
|
|
this.add_cell_class(pos, "instruction");
|
|
});
|
|
c.listen(CpuEvent.InvalidParsed, ({ code, pos }) => {
|
|
this.remove_cell_class(pos, "constant", "register", "memory", "instruction");
|
|
this.add_cell_class(pos, "invalid");
|
|
});
|
|
}
|
|
}
|