/** * Chip pin drive registry — the bridge between a custom-chip's WASM-driven * output pins and the SPICE electrical engine. * * When a custom-chip drives an OUTPUT pin (ChipRuntime), it records the pin's * voltage here keyed by `${chipId}:${pinName}`. The SPICE netlist builder's * `custom-chip` mapper (spice/componentToSpice) reads these to emit a DC * voltage source on the chip pin's net, exactly like a board GPIO. That makes * the chip drive LEDs, resistors and any analog part wired to it through * ngspice, in addition to the digital PinManager path. * * Presence of a key == that pin is a driven output. Absence == input / Hi-Z. */ const drives = new Map(); function key(chipId: string, pinName: string): string { return `${chipId}${pinName}`; } /** * Record (or clear) a chip output pin's drive voltage. Pass `null` to mark the * pin as a non-driving input. Returns true if the registry actually changed * (so callers can skip a redundant SPICE re-solve). */ export function setChipPinDrive(chipId: string, pinName: string, voltage: number | null): boolean { const k = key(chipId, pinName); if (voltage == null) { return drives.delete(k); } if (drives.get(k) === voltage) return false; drives.set(k, voltage); return true; } /** All driven output pins for a chip, with their voltages. */ export function getChipDrivenPins(chipId: string): { pin: string; voltage: number }[] { const prefix = `${chipId}`; const out: { pin: string; voltage: number }[] = []; for (const [k, v] of drives) { if (k.startsWith(prefix)) out.push({ pin: k.slice(prefix.length), voltage: v }); } return out; } /** Forget every drive for a chip (on dispose / simulation stop). */ export function clearChipDrives(chipId: string): void { const prefix = `${chipId}`; for (const k of Array.from(drives.keys())) { if (k.startsWith(prefix)) drives.delete(k); } }