All files / src/web uservia-panel.js

96.55% Statements 28/29
100% Branches 8/8
85.71% Functions 6/7
96.29% Lines 26/27

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 85 86 87          2x 2x 2x 2x     2x                         16x 16x 16x         16x 16x 128x 128x 128x 128x   16x     2x                       3x                 6x 6x             4x   6x 6x 6x       6x       16x 32x      
import { hexbyte } from "../hex.js";
import { decodedPanel, DecodedRegisters, fixed, lit } from "./decoded-registers.js";
import { Centred, StartEdge } from "./panel-layout.js";
import { controlSection, portsSection, TimersSection, viaState } from "./via-registers.js";
 
const MinPanelSize = { w: 240, h: 120 };
const PortLines = 8;
const FirstPrintable = 0x20;
const LastPrintable = 0x7e;
 
/** @type {import("./via-registers.js").ViaWiring} */
const Wiring = {
    ca1: {
        name: "CA1",
        wiring: "printer ack",
        title: "the printer's acknowledge, pulsed low as it takes each character",
    },
    ca2: { name: "CA2", wiring: "printer strobe", title: "the printer's strobe, pulsed low to hand it a character" },
    cb1: { name: "CB1", wiring: "user port", title: "a control line on the user port" },
    cb2: { name: "CB2", wiring: "user port", title: "a control line on the user port" },
    t1: "Timer 1 has reached zero",
};
 
function decodePrinterData(pins) {
    const printable = pins >= FirstPrintable && pins <= LastPrintable;
    const char = printable ? `"${String.fromCharCode(pins)}"` : `&${hexbyte(pins)}`;
    return [fixed(`data ${char}`, "PA0-PA7: the character on the printer's data lines")];
}
 
/** Each of the user port's lines, most significant first, lit while high. */
function decodeUserPort(pins, { ddrb }) {
    const lines = [];
    for (let bit = PortLines - 1; bit >= 0; --bit) {
        const mask = 1 << bit;
        const direction = ddrb & mask ? "an output, driven" : "an input, read";
        const level = pins & mask ? "high" : "low";
        lines.push(lit(`PB${bit}`, `PB${bit} on the user port: ${direction} ${level}`, pins & mask));
    }
    return lines;
}
 
const Sections = {
    ports: portsSection({
        a: { title: "Port A's lines: the printer's data", decode: decodePrinterData },
        b: { title: "Port B's lines: the user port", decode: decodeUserPort },
    }),
    control: controlSection(Wiring),
};
 
/** A floating panel showing the user VIA decoded: the printer on port A, the user port on port B. */
export class UserViaPanel {
    /** Whether the machine has a user VIA to show: the Atom's CPU carries one it never wires up. */
    static fits(cpu) {
        return !cpu.model.isAtom;
    }
 
    /**
     * @param {object} options
     * @param {import("../6502.js").Cpu6502} options.cpu
     * @param {import("./floating-panel.js").PanelArrangement} options.arrangement
     */
    constructor({ cpu, arrangement }) {
        this._via = cpu.uservia;
        const { floating, body, part } = decodedPanel({
            id: "uservia",
            title: "User VIA",
            feature: "user_via",
            place: () => ({ x: Centred, y: StartEdge }),
            minSize: MinPanelSize,
            arrangement,
            draw: () => this.update(),
        });
        this.floating = floating;
        body.innerHTML = `<div class="uservia-ports"></div><div class="uservia-control"></div>`;
        this._registers = [
            new DecodedRegisters(part("uservia-ports"), [Sections.ports, TimersSection]),
            new DecodedRegisters(part("uservia-control"), [Sections.control]),
        ];
        this.update();
    }
 
    update() {
        const state = viaState(this._via);
        for (const registers of this._registers) registers.update(state);
    }
}