Computer/src/ui/memoryView.ts
2024-03-06 01:46:29 -05:00

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");
});
}
}