bulk commit before breaking everything

This commit is contained in:
Alexander Bass 2024-03-25 23:03:20 -04:00
parent 96f1104734
commit b550a62af8
22 changed files with 211 additions and 61 deletions

View file

@ -163,17 +163,6 @@ export default class Computer {
this.events.dispatch(CpuEvent.SetVramBank, { bank }); this.events.dispatch(CpuEvent.SetVramBank, { bank });
} }
reset(): void {
this.events.dispatch(CpuEvent.Reset);
this.banks = initBanks();
this.registers = new Uint8Array(8);
this.call_stack = [];
this.current_instr = null;
this.program_counter = 0;
this.carry_flag = false;
this.vram_bank = 3;
}
initEvents(ui: UiCpuSignalHandler): void { initEvents(ui: UiCpuSignalHandler): void {
ui.listen(UiCpuSignal.RequestCpuCycle, (cycle_count) => { ui.listen(UiCpuSignal.RequestCpuCycle, (cycle_count) => {
for (let i = 0; i < cycle_count; i++) this.cycle(); for (let i = 0; i < cycle_count; i++) this.cycle();
@ -185,6 +174,31 @@ export default class Computer {
ui.listen(UiCpuSignal.RequestProgramCounterChange, ({ address }) => { ui.listen(UiCpuSignal.RequestProgramCounterChange, ({ address }) => {
this.setProgramCounter(address); this.setProgramCounter(address);
}); });
ui.listen(UiCpuSignal.RequestCpuSoftReset, () => this.softReset());
}
softReset(): void {
this.events.dispatch(CpuEvent.SoftReset);
for (let i = 0; i < 8; i++) this.setRegister(i as u3, 0);
while (this.popCallStack() !== null) 0;
this.setVramBank(DEFAULT_VRAM_BANK);
this.setCarry(false);
this.current_instr = null;
this.setProgramCounter(0);
this.setBank(0);
}
reset(): void {
this.events.dispatch(CpuEvent.Reset);
// Hard reset
this.banks = initBanks();
// Soft reset
for (let i = 0; i < 8; i++) this.setRegister(i as u3, 0);
while (this.popCallStack() !== null) 0;
this.setVramBank(DEFAULT_VRAM_BANK);
this.setCarry(false);
this.current_instr = null;
this.setProgramCounter(0);
this.setBank(0);
} }
loadMemory(program: Array<u8>): void { loadMemory(program: Array<u8>): void {

View file

@ -21,6 +21,7 @@ export enum CpuEvent {
Cycle, Cycle,
Print, Print,
Reset, Reset,
SoftReset,
Halt, Halt,
MemoryAccessed, MemoryAccessed,
SwitchBank, SwitchBank,
@ -28,7 +29,7 @@ export enum CpuEvent {
SetVramBank, SetVramBank,
} }
type VoidDataCpuEventList = CpuEvent.Halt | CpuEvent.Reset | CpuEvent.Cycle; type VoidDataCpuEventList = CpuEvent.Halt | CpuEvent.Reset | CpuEvent.SoftReset | CpuEvent.Cycle;
interface CpuEventMap { interface CpuEventMap {
[CpuEvent.MemoryChanged]: { address: u8; bank: u2; value: u8 }; [CpuEvent.MemoryChanged]: { address: u8; bank: u2; value: u8 };
@ -67,11 +68,12 @@ export enum UiCpuSignal {
RequestMemoryChange, RequestMemoryChange,
RequestRegisterChange, RequestRegisterChange,
RequestCpuReset, RequestCpuReset,
RequestCpuSoftReset,
RequestMemoryDump, RequestMemoryDump,
RequestProgramCounterChange, RequestProgramCounterChange,
} }
type VoidDataUiCpuSignalList = UiCpuSignal.RequestCpuReset; type VoidDataUiCpuSignalList = UiCpuSignal.RequestCpuReset | UiCpuSignal.RequestCpuSoftReset;
interface UiCpuSignalMap { interface UiCpuSignalMap {
[UiCpuSignal.RequestCpuCycle]: number; [UiCpuSignal.RequestCpuCycle]: number;

View file

@ -48,6 +48,7 @@ function main(): void {
window.ui = ui; window.ui = ui;
// Todo, move to ui component // Todo, move to ui component
// or move to documentation
$("ISA").textContent = generateIsa(ISA); $("ISA").textContent = generateIsa(ISA);
let fire = false; let fire = false;

View file

@ -0,0 +1,5 @@
.hover_text_box {
border: 5px solid yellow;
background-color: black;
user-select: none;
}

View file

@ -1,4 +1,5 @@
@use "memory_registers"; @use "memory_registers";
@use "hover_text_box";
@use "windows"; @use "windows";
@use "buttons"; @use "buttons";
@use "vars"; @use "vars";

View file

@ -47,9 +47,8 @@ export default class UI {
} }
initEvents(cpu_events: CpuEventHandler): void { initEvents(cpu_events: CpuEventHandler): void {
cpu_events.listen(CpuEvent.Reset, () => { cpu_events.listen(CpuEvent.Reset, () => this.reset());
this.reset(); cpu_events.listen(CpuEvent.SoftReset, () => this.softReset());
});
for (const c of this.components) if (c.initCpuEvents) c.initCpuEvents(cpu_events); for (const c of this.components) if (c.initCpuEvents) c.initCpuEvents(cpu_events);
} }
@ -57,4 +56,8 @@ export default class UI {
reset(): void { reset(): void {
for (const c of this.components) if (c.reset) c.reset(); for (const c of this.components) if (c.reset) c.reset();
} }
softReset(): void {
for (const c of this.components) if (c.softReset) c.softReset();
}
} }

View file

@ -6,7 +6,7 @@ import UiComponent from "../uiComponent";
export default class BankSelector implements UiComponent { export default class BankSelector implements UiComponent {
container: HTMLElement; container: HTMLElement;
events: UiEventHandler; events: UiEventHandler;
private bank_buttons: Array<HTMLButtonElement>; bank_buttons: Array<HTMLButtonElement>;
constructor(element: HTMLElement, events: UiEventHandler) { constructor(element: HTMLElement, events: UiEventHandler) {
this.container = element; this.container = element;
this.events = events; this.events = events;
@ -28,8 +28,13 @@ export default class BankSelector implements UiComponent {
this.container.appendChild(bank_boxes); this.container.appendChild(bank_boxes);
} }
reset(): void { reset(): void {
for (const b of this.bank_buttons) b.classList.remove("selected"); for (const b of this.bank_buttons) b.classList.remove("selected");
this.bank_buttons[0].classList.add("selected"); this.bank_buttons[0].classList.add("selected");
} }
softReset(): void {
this.reset();
}
} }

View file

@ -12,18 +12,18 @@ export default class EditButton implements UiComponent {
this.cpu_signals = cpu_signals; this.cpu_signals = cpu_signals;
const image = el("img").at("src", "pencil.png").st("width", "20px").st("height", "20px").fin(); const image = el("img").at("src", "pencil.png").st("width", "20px").st("height", "20px").fin();
this.container.classList.add("editor_toggle"); this.container.classList.add("editor_toggle");
this.container.addEventListener("click", () => this.edit_toggle()); this.container.addEventListener("click", () => this.editToggle());
this.container.appendChild(image); this.container.appendChild(image);
} }
reset(): void { disable(): void {
const is_on = this.container.classList.contains("on"); const is_on = this.container.classList.contains("on");
if (is_on) { if (is_on) {
this.edit_toggle(); this.editToggle();
} }
} }
edit_toggle(): void { editToggle(): void {
const is_on = this.container.classList.contains("on"); const is_on = this.container.classList.contains("on");
if (is_on) { if (is_on) {
this.container.classList.remove("on"); this.container.classList.remove("on");
@ -35,7 +35,14 @@ export default class EditButton implements UiComponent {
$("root").classList.add("editor"); $("root").classList.add("editor");
this.container.classList.add("on"); this.container.classList.add("on");
this.container.classList.remove("off"); this.container.classList.remove("off");
this.cpu_signals.dispatch(UiCpuSignal.RequestProgramCounterChange, { address: 0 });
} }
} }
reset(): void {
this.disable();
}
softReset(): void {
this.disable();
}
} }

View file

@ -3,10 +3,10 @@ import UiComponent from "../uiComponent";
export default class frequencyIndicator implements UiComponent { export default class frequencyIndicator implements UiComponent {
container: HTMLElement; container: HTMLElement;
private running: number | null = null; running: number | null = null;
private count: number = 0; count: number = 0;
private last_value: number = 0; last_value: number = 0;
private last_time: number = 0; last_time: number = 0;
events: UiEventHandler; events: UiEventHandler;
constructor(element: HTMLElement, events: UiEventHandler) { constructor(element: HTMLElement, events: UiEventHandler) {
this.container = element; this.container = element;
@ -19,16 +19,16 @@ export default class frequencyIndicator implements UiComponent {
if (this.running !== null) { if (this.running !== null) {
throw new Error("Tried starting frequencyIndicator twice!"); throw new Error("Tried starting frequencyIndicator twice!");
} }
setInterval(this.update_indicator.bind(this), 1000); window.setInterval(this.updateIndicator.bind(this), 1000);
} }
stop(): void { stop(): void {
if (this.running === null) return; if (this.running === null) return;
clearInterval(this.running); window.clearInterval(this.running);
this.running = null; this.running = null;
} }
update_indicator(): void { updateIndicator(): void {
const new_time = performance.now(); const new_time = performance.now();
const dt = (new_time - this.last_time) / 1000 || 1; const dt = (new_time - this.last_time) / 1000 || 1;
const value = Math.round(this.count / dt); const value = Math.round(this.count / dt);
@ -44,15 +44,21 @@ export default class frequencyIndicator implements UiComponent {
this.count = 0; this.count = 0;
} }
clock_cycle(): void { clockCycle(): void {
this.count += 1; this.count += 1;
} }
reset(): void { reset(): void {
this.stop(); this.stop();
this.count = 0; this.count = 0;
this.last_value = 0; this.last_value = 0;
this.start(); this.start();
} }
softReset(): void {
this.reset();
}
initCpuEvents(c: CpuEventHandler): void { initCpuEvents(c: CpuEventHandler): void {
c.listen(CpuEvent.Cycle, () => { c.listen(CpuEvent.Cycle, () => {
this.count += 1; this.count += 1;

View file

@ -53,6 +53,7 @@ export default class MemoryView implements UiComponent {
}); });
} }
this.events.listen(UiEvent.ChangeViewBank, ({ bank }) => this.setBank(bank)); this.events.listen(UiEvent.ChangeViewBank, ({ bank }) => this.setBank(bank));
this.setProgramCounter(0);
} }
get program(): CelledViewer { get program(): CelledViewer {
@ -76,6 +77,12 @@ export default class MemoryView implements UiComponent {
this.setProgramCounter(0); this.setProgramCounter(0);
} }
softReset(): void {
for (const viewer of this.banks) viewer.clearAllClasses();
this.last_accessed_cell = null;
this.setProgramCounter(0);
}
initCpuEvents(c: CpuEventHandler): void { initCpuEvents(c: CpuEventHandler): void {
c.listen(CpuEvent.MemoryAccessed, ({ address, bank, value }) => { c.listen(CpuEvent.MemoryAccessed, ({ address, bank, value }) => {
if (this.last_accessed_cell?.address !== address || this.last_accessed_cell?.bank !== bank) { if (this.last_accessed_cell?.address !== address || this.last_accessed_cell?.bank !== bank) {

View file

@ -1,6 +1,7 @@
import { el } from "../../etc"; import { el } from "../../etc";
import { UiEventHandler, UiEvent, CpuEventHandler, UiCpuSignalHandler, UiCpuSignal } from "../../events"; import { UiEventHandler, UiEvent, CpuEventHandler, UiCpuSignalHandler, UiCpuSignal } from "../../events";
import UiComponent from "../uiComponent"; import UiComponent from "../uiComponent";
import HoverTextBox from "../hoverTextBox";
const MAX_SLIDER = 1000; const MAX_SLIDER = 1000;
@ -41,18 +42,22 @@ export default class pausePlay implements UiComponent {
this.events.listen(UiEvent.EditOn, () => this.disable()); this.events.listen(UiEvent.EditOn, () => this.disable());
this.events.listen(UiEvent.EditOff, () => this.enable()); this.events.listen(UiEvent.EditOff, () => this.enable());
const tb = new HoverTextBox(this.start_button, el("span").tx("hover test").st("color", "yellow").fin(), "left", 10);
tb.show();
} }
disable(): void { disable(): void {
this.stop(); this.stop();
this.start_button.setAttribute("disabled", "true"); this.start_button.setAttribute("disabled", "true");
this.step_button.setAttribute("disabled", "true"); this.step_button.setAttribute("disabled", "true");
this.range.setAttribute("disabled", "true"); this.range.setAttribute("disabled", "true");
} }
enable(): void { enable(): void {
this.start_button.removeAttribute("disabled"); this.start_button.removeAttribute("disabled");
this.step_button.removeAttribute("disabled"); this.step_button.removeAttribute("disabled");
this.range.removeAttribute("disabled"); this.range.removeAttribute("disabled");
} }
@ -76,6 +81,7 @@ export default class pausePlay implements UiComponent {
}; };
loop(); loop();
} }
private step(): void { private step(): void {
if (this.on) { if (this.on) {
this.stop(); this.stop();
@ -98,4 +104,8 @@ export default class pausePlay implements UiComponent {
this.stop(); this.stop();
this.enable(); this.enable();
} }
softReset(): void {
this.reset();
}
} }

View file

@ -7,10 +7,7 @@ export default class RegisterView extends CelledViewer implements UiComponent {
events: UiEventHandler; events: UiEventHandler;
cpu_signals: UiCpuSignalHandler; cpu_signals: UiCpuSignalHandler;
constructor(element: HTMLElement, events: UiEventHandler, cpu_signals: UiCpuSignalHandler) { constructor(element: HTMLElement, events: UiEventHandler, cpu_signals: UiCpuSignalHandler) {
super(8, 1, element, (address: u8, value: u8) => { super(8, 1, element, (a, v) => this.onEdit(a, v));
if (!isU3(address)) throw new Error("unreachable");
this.cpu_signals.dispatch(UiCpuSignal.RequestRegisterChange, { register_no: address as u3, value });
});
this.events = events; this.events = events;
this.cpu_signals = cpu_signals; this.cpu_signals = cpu_signals;
@ -24,8 +21,16 @@ export default class RegisterView extends CelledViewer implements UiComponent {
}); });
} }
onEdit(address: u8, value: u8): void {
if (!isU3(address)) throw new Error("unreachable");
this.cpu_signals.dispatch(UiCpuSignal.RequestRegisterChange, { register_no: address as u3, value });
}
initCpuEvents(c: CpuEventHandler): void { initCpuEvents(c: CpuEventHandler): void {
c.listen(CpuEvent.RegisterChanged, ({ register_no, value }) => this.setCellValue(register_no, value)); c.listen(CpuEvent.RegisterChanged, ({ register_no, value }) => this.setCellValue(register_no, value));
c.listen(CpuEvent.Reset, () => this.reset()); }
softReset(): void {
this.clearAllClasses();
} }
} }

View file

@ -1,5 +1,5 @@
import { el } from "../../etc"; import { el } from "../../etc";
import { UiEventHandler, UiCpuSignalHandler, UiEvent, UiCpuSignal } from "../../events"; import { UiEventHandler, UiCpuSignalHandler, UiCpuSignal } from "../../events";
import UiComponent from "../uiComponent"; import UiComponent from "../uiComponent";
export default class ResetButtons implements UiComponent { export default class ResetButtons implements UiComponent {
@ -10,17 +10,22 @@ export default class ResetButtons implements UiComponent {
this.container = element; this.container = element;
this.events = events; this.events = events;
this.cpu_signals = cpu_signals; this.cpu_signals = cpu_signals;
const reset_button = el("button").cl("nostyle").tx("R").fin(); const reset_button = el("button").cl("nostyle").ti("Reset State").tx("⟳").fin();
const trash_button = el("button").cl("nostyle").tx("T").fin(); const trash_button = el("button").cl("nostyle").ti("Delete Code").tx("🗑").fin();
reset_button.addEventListener("click", () => this.resetClicked()); reset_button.addEventListener("click", () => this.resetClicked());
trash_button.addEventListener("click", () => this.trashClicked()); trash_button.addEventListener("click", () => this.trashClicked());
this.container.append(reset_button, trash_button); this.container.append(reset_button, trash_button);
} }
resetClicked(): void {} resetClicked(): void {
this.cpu_signals.dispatch(UiCpuSignal.RequestCpuSoftReset);
}
trashClicked(): void { trashClicked(): void {
const a = confirm("Clear all code? Irreversible");
if (a) {
this.cpu_signals.dispatch(UiCpuSignal.RequestCpuReset); this.cpu_signals.dispatch(UiCpuSignal.RequestCpuReset);
} }
} }
}

View file

@ -1,6 +1,6 @@
import { el } from "../../etc"; import { el } from "../../etc";
import { UiEventHandler, UiCpuSignalHandler, UiCpuSignal } from "../../events"; import { UiEventHandler, UiCpuSignalHandler, UiCpuSignal } from "../../events";
import { u2, u8, m256, isU2 } from "../../num"; import { u8, m256, isU2 } from "../../num";
import UiComponent from "../uiComponent"; import UiComponent from "../uiComponent";
export default class SaveLoad implements UiComponent { export default class SaveLoad implements UiComponent {
@ -14,16 +14,16 @@ export default class SaveLoad implements UiComponent {
this.events = events; this.events = events;
this.cpu_signals = cpu_signals; this.cpu_signals = cpu_signals;
this.save_button = el("button").id("save_button").tx("Save").fin(); this.save_button = el("button").id("save_button").tx("").fin();
this.binary_upload = el("input") this.binary_upload = el("input")
.id("binary_upload") .id("binary_upload")
.at("type", "file") .at("type", "file")
.at("name", "binary_upload") .at("name", "binary_upload")
.st("display", "none") .st("display", "none")
.fin(); .fin();
const label = el("label").cl("button").at("for", "binary_upload").tx("Load Binary").fin(); const label = el("label").cl("button").at("for", "binary_upload").tx("").fin();
this.container.append(this.binary_upload, label, this.save_button); this.container.append(this.save_button, this.binary_upload, label);
this.save_button.addEventListener("click", () => { this.save_button.addEventListener("click", () => {
this.download(); this.download();

48
src/ui/hoverTextBox.ts Normal file
View file

@ -0,0 +1,48 @@
import { el } from "../etc";
type RelativePosition = "top" | "bottom" | "left" | "right";
export default class HoverTextBox {
parent: HTMLElement;
position: RelativePosition;
gap: number;
contents: HTMLElement;
shown: false | { container: HTMLElement; resize_event_fn: () => void };
constructor(parent: HTMLElement, contents: HTMLElement, position: RelativePosition, gap: number) {
this.gap = gap;
this.position = position;
this.parent = parent;
this.contents = contents;
this.shown = false;
}
show(): void {
if (this.shown) return;
const container = el("div").st("position", "absolute").cl("hover_text_box").fin();
container.appendChild(this.contents);
const adjustBoxPosition = (cont: HTMLElement, parent: HTMLElement): void => {
const parent_x = parent.offsetLeft;
const parent_y = parent.offsetTop;
const style = window.getComputedStyle(cont);
const new_cont_x = parent_x;
const new_cont_y = parent_y + this.gap + cont.offsetHeight + 5;
cont.style.setProperty("top", `${new_cont_y}px`);
cont.style.setProperty("left", `${new_cont_x}px`);
};
document.body.appendChild(container);
adjustBoxPosition(container, this.parent);
const adjust_fn = adjustBoxPosition.bind(undefined, container, this.parent);
window.addEventListener("resize", adjust_fn);
this.shown = { container: container, resize_event_fn: adjust_fn };
}
hide(): void {
if (!this.shown) return;
this.shown.container.innerHTML = "";
this.shown.container.remove();
window.removeEventListener("resize", this.shown.resize_event_fn);
this.shown = false;
}
}

View file

@ -12,7 +12,7 @@ export default abstract class WindowBox {
title_bar: HTMLElement; title_bar: HTMLElement;
readonly title: string; readonly title: string;
private collapse_button: HTMLButtonElement; private collapse_button: HTMLButtonElement;
private collapsed = false; private is_collapsed = false;
private fit_content = false; private fit_content = false;
private resize?: HTMLElement; private resize?: HTMLElement;
private resize_func?: (e: MouseEvent) => void; private resize_func?: (e: MouseEvent) => void;
@ -44,7 +44,7 @@ export default abstract class WindowBox {
} else { } else {
this.resize = el("div").id("resize").fin(); this.resize = el("div").id("resize").fin();
this.container.appendChild(this.resize); this.container.appendChild(this.resize);
this.resize_func = this.resize_move.bind(this); this.resize_func = this.resizeMove.bind(this);
this.resize.addEventListener("mousedown", (e) => { this.resize.addEventListener("mousedown", (e) => {
if (this.resize_func) window.addEventListener("mousemove", this.resize_func); if (this.resize_func) window.addEventListener("mousemove", this.resize_func);
}); });
@ -58,7 +58,7 @@ export default abstract class WindowBox {
this.removeResizeListeners(); this.removeResizeListeners();
if (this.resize) this.resize.style.visibility = "hidden"; if (this.resize) this.resize.style.visibility = "hidden";
this.setHeight(this.title_bar.offsetHeight - BORDER_STROKE); this.setHeight(this.title_bar.offsetHeight - BORDER_STROKE);
this.collapsed = true; this.is_collapsed = true;
} }
correctHeightValue(height: number): number { correctHeightValue(height: number): number {
@ -74,7 +74,7 @@ export default abstract class WindowBox {
} }
toggleCollapse(): void { toggleCollapse(): void {
if (this.collapsed) { if (this.is_collapsed) {
this.uncollapse(); this.uncollapse();
} else { } else {
this.collapse(); this.collapse();
@ -91,15 +91,15 @@ export default abstract class WindowBox {
const new_height = this.correctHeightValue(this.title_bar.offsetHeight + 200); const new_height = this.correctHeightValue(this.title_bar.offsetHeight + 200);
this.setHeight(new_height); this.setHeight(new_height);
this.collapsed = false; this.is_collapsed = false;
} }
removeResizeListeners(): void { removeResizeListeners(): void {
if (this.resize_func) window.removeEventListener("mousemove", this.resize_func); if (this.resize_func) window.removeEventListener("mousemove", this.resize_func);
} }
resize_move(e: MouseEvent): void { resizeMove(e: MouseEvent): void {
if (this.collapsed) { if (this.is_collapsed) {
this.uncollapse(); this.uncollapse();
this.removeResizeListeners(); this.removeResizeListeners();
return; return;
@ -111,4 +111,8 @@ export default abstract class WindowBox {
} }
this.setHeight(e.clientY - this.container.offsetTop + window.scrollY); this.setHeight(e.clientY - this.container.offsetTop + window.scrollY);
} }
isCollapsed(): boolean {
return this.is_collapsed;
}
} }

View file

@ -32,4 +32,8 @@ export default class BankVisualizer extends WindowBox implements UiComponent {
this.cpu_banks[0].setAttribute("stroke", "yellow"); this.cpu_banks[0].setAttribute("stroke", "yellow");
} }
softReset(): void {
this.reset();
}
} }

View file

@ -67,4 +67,8 @@ export default class InstructionExplainer extends WindowBox implements UiCompone
reset(): void { reset(): void {
this.container.querySelectorAll("#expl_box").forEach((e) => e.remove()); this.container.querySelectorAll("#expl_box").forEach((e) => e.remove());
} }
softReset(): void {
this.reset();
}
} }

View file

@ -24,4 +24,8 @@ export default class Printout extends WindowBox implements UiComponent {
reset(): void { reset(): void {
this.text_box.textContent = ""; this.text_box.textContent = "";
} }
softReset(): void {
this.reset();
}
} }

View file

@ -15,6 +15,7 @@ export default class Screen extends WindowBox implements UiComponent {
ctx: CanvasRenderingContext2D; ctx: CanvasRenderingContext2D;
scale: number; scale: number;
current_vram_bank: u2 = DEFAULT_VRAM_BANK; current_vram_bank: u2 = DEFAULT_VRAM_BANK;
constructor(element: HTMLElement, event: UiEventHandler, cpu_signals: UiCpuSignalHandler) { constructor(element: HTMLElement, event: UiEventHandler, cpu_signals: UiCpuSignalHandler) {
super(element, "TV", { collapsed: true, fit_content: true }); super(element, "TV", { collapsed: true, fit_content: true });
this.cpu_signals = cpu_signals; this.cpu_signals = cpu_signals;
@ -25,27 +26,31 @@ export default class Screen extends WindowBox implements UiComponent {
this.screen.width = CANVAS_SIZE; this.screen.width = CANVAS_SIZE;
this.screen.height = CANVAS_SIZE; this.screen.height = CANVAS_SIZE;
const ctx = this.screen.getContext("2d"); const ctx = this.screen.getContext("2d");
if (ctx === null) {
throw new Error("could not load screen"); if (ctx === null) throw new Error("could not load screen");
}
this.ctx = ctx; this.ctx = ctx;
this.container.appendChild(this.screen); this.container.appendChild(this.screen);
this.test_pattern();
this.renderTestPattern();
} }
private test_pattern(): void { private renderTestPattern(): void {
for (let x = 0; x < 256; x++) { for (let x = 0; x < 256; x++) {
this.setPixel(x as u8, x as u8); this.setPixel(x as u8, x as u8);
} }
} }
reset(): void { reset(): void {
const ctx = this.screen.getContext("2d"); for (let i = 0; i < 256; i++) {
if (ctx === null) { this.setPixel(i as u8, 0);
throw new Error("todo");
} }
} }
softReset(): void {
this.reset();
}
initCpuEvents(c: CpuEventHandler): void { initCpuEvents(c: CpuEventHandler): void {
c.listen(CpuEvent.MemoryChanged, ({ address, bank, value }) => { c.listen(CpuEvent.MemoryChanged, ({ address, bank, value }) => {
if (bank !== 1) return; if (bank !== 1) return;
@ -68,6 +73,8 @@ export default class Screen extends WindowBox implements UiComponent {
const y = Math.floor(address / 16) as u4; const y = Math.floor(address / 16) as u4;
const point: [number, number] = [x * this.scale, y * this.scale]; const point: [number, number] = [x * this.scale, y * this.scale];
// TODO, come up with better color scheme.
// Probable a lookup table
const RED_SCALE = 255 / 2 ** 3; const RED_SCALE = 255 / 2 ** 3;
const GREEN_SCALE = 255 / 2 ** 3; const GREEN_SCALE = 255 / 2 ** 3;
const BLUE_SCALE = 255 / 2 ** 2; const BLUE_SCALE = 255 / 2 ** 2;

View file

@ -34,6 +34,12 @@ class ElementInProgress<E extends HTMLElement> {
return this; return this;
} }
/** Set title */
ti(title: string): ElementInProgress<E> {
this.element.title = title;
return this;
}
/** Return created element */ /** Return created element */
fin(): E { fin(): E {
return this.element; return this.element;

View file

@ -29,7 +29,9 @@ Limit size to printout text buffer
Improve instruction explainer. Clearly show what is an instruction and what is a parameter Improve instruction explainer. Clearly show what is an instruction and what is a parameter
Ui showing CPU flag(s) (Carry) Ui showing CPU flag(s) (Carry) and call stack
Share programs from encoded url
Responsive layout Responsive layout
@ -37,4 +39,4 @@ standardize names of all things
Documentation with standard names Documentation with standard names
Example Programs Example Programs (loaded as one of those encoded string url things)