Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | 4x 9x 248x 248x 248x 248x 256x 256x 494x 494x 34x 34x 34x 9x 494x 494x 2x 512x 512x 9x 9x 9x 9x 9x 9x 9x 27x 9x 2x 2x 2x | import { hexword } from "../hex.js";
import { machineSheilaBlocks, sheilaName, sheilaRegister } from "../sheila.js";
import { tightLoopAt } from "../tight-loop.js";
import { addressRange } from "./debug-dom.js";
import { textButton } from "./dom-utils.js";
import { DebugGroup } from "./floating-panel.js";
/** The decoded panel, by id, of each SHEILA device that has one, by its block's `device`. */
const DevicePanels = {
CRTC: "crtc",
FDC: "fdc",
Paging: "paging",
SysVIA: "sysvia",
UserVIA: "uservia",
};
/** `nodes` listed as in prose: "a", "a and b", "a, b and c". */
function inProse(nodes) {
return nodes.flatMap((node, i) => (i === 0 ? [node] : [i < nodes.length - 1 ? ", " : " and ", node]));
}
/**
* A line saying, while the machine is stopped in a tight loop, where the loop is and what it polls, by its SHEILA
* register's name where it has one, with a button to open each polled device's decoded panel.
*/
export class TightLoopNote {
/**
* @param {HTMLElement} line
* @param {import("./floating-panel.js").PanelArrangement} arrangement
*/
constructor(line, arrangement) {
this._line = line;
this._arrangement = arrangement;
this._cpu = null;
this._sheila = [];
}
/** @param {import("../6502.js").Cpu6502} cpu */
setCpu(cpu) {
this._cpu = cpu;
this._sheila = machineSheilaBlocks(cpu);
}
/** Shows the tight loop the machine is stopped in, if it is in one. */
show() {
const loop = tightLoopAt(this._cpu.disassembler, this._cpu.pc);
if (!loop) return this.clear();
const reads = loop.reads.map((address) => this._polled(address));
const panels = new Set(reads.flatMap(({ panel }) => (panel ? [panel] : [])));
const polling = reads.length
? [" polling ", ...inProse(reads.map(({ node }) => node))]
: [" that reads nothing"];
this._line.hidden = false;
this._line.replaceChildren(
`In a loop at ${addressRange(loop)}`,
...polling,
...[...panels].flatMap((panel) => [" ", this._opener(panel)]),
);
}
clear() {
this._line.hidden = true;
this._line.replaceChildren();
}
_polled(address) {
const node = document.createElement("span");
node.className = "polled";
const found = sheilaRegister(this._sheila, address, "read");
const named = sheilaName(this._sheila, address, ["read"]);
node.textContent = named ? `${named.name} ($${hexword(address)})` : `$${hexword(address)}`;
if (named) node.title = named.title;
const id = found && DevicePanels[found.block.device];
const panel = id && this._arrangement.panelsIn(DebugGroup).find((floating) => floating.id === id);
return { node, panel };
}
_opener(floating) {
const button = textButton("", `open ${floating.title}`, "");
button.addEventListener("click", () => floating.open());
return button;
}
}
|