Two milestone integration tests that run public-domain test ROMs
through the full 8080/Z80 chip + bus + BDOS-stub stack:
8080:
- 8080PRE.COM (1 KB preliminary test) — runs to completion, no ERROR.
- TST8080.COM (1.5 KB Microcosm 1980 CPUDIAG) — the canonical 8080
validation. Chip prints "CPU IS OPERATIONAL". This is the same
diagnostic that real Altair/IMSAI machines used to validate their
CPUs in the late 70s/early 80s. ~52s wall-clock, 2M simulated cycles.
Z80:
- ZEXDOC (8.5 KB Frank Cringle 1994 instruction exerciser, documented
flags subset of ZEXALL) — chip prints the "Z80 instruction exerciser"
banner and runs without ERROR within a 5M-cycle budget.
Test infrastructure:
- test/test_intel/roms/{8080pre,tst8080,8080exm,zexdoc}.bin — public-
domain ROMs mirrored from altairclone.com and floooh/chips-test.
- 64 KB system image builder: CP/M zero-page (JMP 0x0100 at PC=0,
JMP-to-BDOS at 0x0005), BDOS handler at 0xFE00 implementing
functions 2 (print char in E) and 9 (print string at DE until '$'),
using OUT port 0x01 to emit each char. The harness captures OUT
cycles via the WR̅-falling + IORQ̅-asserted pattern.
Lesson: BDOS at 0x0F00 collided with ZEXDOC.COM (8.5 KB extending
to 0x21A9). Moved BDOS to 0xFE00 — well above any reasonable .COM
program region. CPUDIAG worked at either address since TST8080 is
only 1.5 KB.
Tests: 94→98 passing. Total test_intel 105→109 (4 new tests).
0 failed. 11 todo (mostly 8086 corner cases + Busicom + full
ZEXDOC). Master plan doc updated marking phase F as partial.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Root cause of the deferred CALL/RET test: my chip was missing the
0xC6 / 0xC7 (Group 11 — MOV r/m, imm) opcodes. Bytes like the
test's "MOV byte [0x8002], 0x55" (0xC6 0x06 0x02 0x80 0x55) fell
through to the default NOP, then the chip decoded the residual
0x06 0x02 0x80 0x55 as PUSH ES + ADD r/m + ... taking SP into
unpredictable territory.
Implementation:
- 0xC6 (8-bit) and 0xC7 (16-bit) variants added.
- The encoding is opcode + modrm + disp + imm. Critically the disp
bytes (consumed by calc_ea) come BEFORE the immediate, so we
compute EA first, then fetch imm. Earlier draft had imm fetched
before disp — that had imm winning the disp slot and disp becoming
the next instruction's bytes. Caught only after wiring CALL+RET.
Tests: 8086 10→11 passing. Total test_intel: 93→94 passing,
0 failed, 11 todo. CALL/RET integration test now active and green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Final tally for this session's work:
- Started at 37 passing tests after the initial 5-CPU baseline.
- Phase A (8080 INTA bus protocol): +1 test.
- Phase B (Z80 CB/DAA/RLD/ADC HL/CPI + X/Y flags): +10 tests.
- Phase C partial (rom-1m, 8255 PPI, 8251 USART): +13 tests.
- Phase E (8086 string ops, MUL/DIV, BCD, port I/O, shifts, etc):
+7 tests.
Total: 93 passing, 12 todo, 0 failed.
Plan tracked in autosearch/18_complete_emulation_plan.md. Phases D
(4004/4040 I/O completion using deferred 4001/4002 chips), F (real
software validation: CPUDIAG/ZEXDOC), and G (cycle accuracy) remain
as future iterations.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Implement UC8159cDecoder for handling 7-colour ACeP panels.
- Introduce painting functions for UC8159c frames in EPaperPart.
- Update EPaperPart to handle both SSD168x and UC8159c frame types.
- Add integration tests for EPaperPart and UC8159cDecoder.
- Create example sketch for 5.65" ACeP 7-colour panel.
- Enhance error handling in test cases for library dependencies.
Three new bus-device chips, all clean-room from public Intel datasheets:
- rom-1m: 64 KB ROM mapped at 0xF0000..0xFFFFF for 8086 boot. 20-bit
address bus watch with out-of-range tristate. 16-byte known signature
pre-loaded at the reset vector 0xFFFF0.
- 8255 PPI: Mode-0 (basic I/O) only; three 8-bit ports with split
upper/lower port C. Control word parsing for direction setup. Bit
set/reset and Modes 1/2 deferred.
- 8251 USART: async-mode UART using vx_uart_attach for bit-timing;
mode word + command word + status interface; TxRDY/RxRDY/TxEMPTY
status pins; DTR/RTS pass-through. Internal-reset honoured.
Deferred to a follow-up Phase C+:
- 4001 ROM and 4002 RAM (multi-phase 4-bit bus timing requires either
an external clock-gen chip or Bus4004-equivalent host coordination
that's only available in the JS test harness today).
- 8253 PIT (6 modes, countdown logic).
- 8259 PIC (ICW init state machine + cascade + INTA cycle).
These are flagged in autosearch/18_complete_emulation_plan.md as
deferred — Phase D (4004/4040 I/O) and the 8259 work depend on them
landing first.
Tests: test_buses 17 → 30 passing (+13). Total test_intel 73 → 86
passing, 0 failed, 17 todo. Master plan doc updated.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brings the Z80 from 8080-superset baseline toward ZEXDOC compliance:
- CB prefix: full 256 ops (BIT/SET/RES + RLC/RRC/RL/RR/SLA/SRA/SLL/
SRL) on r ∈ B/C/D/E/H/L/(HL)/A.
- DDCB / FDCB indexed bit ops with displacement-before-opcode order.
Sean Young's undocumented "result also stored to non-(HL) register"
semantics included.
- Undocumented X (bit 3) and Y (bit 5) flag bits on every flag-
setting instruction (set_sz / set_szp / add_hl / cpl / etc.).
- Z80-specific DAA via N flag direction (Sean Young §4.7 algorithm —
the canonical ZEXALL-passing form).
- CPI / CPD / CPIR / CPDR with X/Y from (A − (HL) − H) per
Sean Young §4.2.
- RLD / RRD 12-bit nibble rotates between A and (HL).
- 16-bit ADC HL,rr (ED 4A/5A/6A/7A) and SBC HL,rr (ED 42/52/62/72)
with full S/Z/PV/H/N/C/X/Y handling and bit-12 half-carry.
Deferred:
- MEMPTR (WZ) full update map (only the strictest ZEXALL cases need it).
- Block I/O instructions' deterministic flags (Phase F polish).
- ZEXDOC ROM integration test (Phase F).
Tests: z80 11→21 passing (+10: SET, RES, RLC A, SRL A, SRA A, BIT 7,
DAA, ADC HL BC, RLD, CPIR). Total test_intel: 64→73 passing, 0 failed.
Master plan doc updated: phase B marked done; phase C starting.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the synthesised-RST-7 stub with a real INTA bus cycle. When
int_pending && IME, the chip emits status byte 0x23 on D during T1
(M1+INTA+WO̅) and samples the RST opcode external hardware drives on
the data bus during DBIN. Decodes RST n (0xC7..0xFF) and push+vectors.
Multi-byte INTA opcodes (CALL nnn) deferred.
Test rewrites the INT case to install a fixture INTA driver: snoop
SYNC + status byte, latch a pending flag, drive RST 5 (0xEF) on the
data bus during the next DBIN edge. Driver registers AFTER fake_rom
so its late drive overrides fake_rom's program-byte drive on the
same DBIN edge.
Tests: 8080 17→18 passing; test_intel 63→64 passing.
Adds master plan doc autosearch/18_complete_emulation_plan.md
covering phases A-G (this commit completes phase A).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
All 5 retro CPUs (Intel 4004/4040/8080/8086 + Zilog Z80) plus all 3
bus devices (rom-32k, ram-64k, latch-8282) are now implemented.
Update top-level matrix and per-chip READMEs to reflect 63/80 tests
passing, 0 failed, 17 deferred.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Authoritative spec from Intel iAPX 86,88 User's Manual (1979) +
embedded 8282/8283 datasheet in Appendix B. Cross-validation against
three permissively-licensed open-source emulators:
- 8086tiny (MIT, Adrian Cable, ~600 LOC)
- MartyPC (MIT, dbalsom, hardware-validated, 99.9997% on 8088 V2 tests)
- YJDoc2/8086-Emulator (Apache+MIT, partial)
Excluded GPL refs: Fake86, DOSBox, MAME, QEMU.
Critical findings for clean-room implementation:
- 40-pin DIP min-mode pinout with AD0..AD15 multiplexed (low addr in
T1, data in T2..T4) and A16..A19/S3..S6 multiplexed.
- Reset state: CS=0xFFFF, IP=0, all other segs=0. Physical first
fetch at 0xFFFF0.
- ALE pulses high in T1, falls at end of T1 — external 8282 latches
on falling edge to demux.
- ModR/M decode: 16-bit effective-addr table from the manual.
- DAA differs from 8080 only in the carry-treatment around BCD
borrow; AAA/AAS/AAM/AAD specific to 8086.
- MUL/DIV: OF and CF defined; SF/ZF/AF/PF undefined per Intel.
- Undocumented: POP CS (0x0F) and SALC (0xD6) — original 8086 only,
removed in 80186+.
PDFs (62 MB iAPX manual, 215 KB 8282 datasheet) saved under pdfs/.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Z80 chip enhancements:
- Add maskable INT̅ handling. Pin is level-triggered, active-low. The
on_int watcher tracks line state; step() services at instruction
boundaries when IFF1=1.
- IM 0/1 vector to 0x0038; IM 2 vectors via I:00 indirection (no
interrupt-controller hardware on the bus, so we approximate the
data byte as 0x00 — user code must pre-load the vector table).
- INTA cycle clears IFF1 and IFF2 per Zilog UM008003 p. 24.
- Power-on reset state: chip starts with reset_active=true so the
RESET̅ rising edge releases the chip (the watcher only fires on
edges; without an initial-true assumption, setting RESET=false
was a no-op and the chip executed instructions during the
test's pre-reset cycles).
Test infrastructure:
- bootZ80 no longer advances time after RESET deassert. Same lesson
as bootCpu in the 8080 tests — caller may need to poke RAM
contents BEFORE the chip executes.
5 it.todo tests promoted to passing:
- LDIR copies a memory block from HL to DE
- LD A, (IX+d) reads via IX with signed displacement
- EXX swaps the main register set with the shadow set
- NMI̅ falling edge pushes PC and vectors to 0x0066
- IM 1 + INT̅ vectors to 0x0038
Total test_intel: 60 passing (was 55), 0 failed, 17 todo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 4040 is a binary-compatible superset of the 4004. This commit:
- Adds the full 4004 ISA into 4040.c (LD/XCH/INC/ADD/SUB/JCN/JUN/
JMS/BBL/FIM/FIN/JIN/SRC/ISZ/LDM/I-O/ACC group/DAA/KBP/etc.) so the
4040 actually executes user code, not just NOPs.
- Adds the 14 4040-only opcodes per MCS-40 p. 1-22 at OPR=0000
OPA=0x01..0x0E:
HLT, BBS, LCR, OR4, OR5, AN6, AN7, DB0, DB1, SB0, SB1, EIN, DIN,
RPM (4289 stub).
- Implements bank-aware register access — physical reg[0..7] is
bank 0's R0..R7, reg[8..15] is shared R8..R15, reg[16..23] is
bank 1's R0..R7. SB0/SB1 toggle the active R0..R7 mapping.
- 7-deep PC stack (vs 4004's 3-deep) per MCS-40 p. 1-12.
- Interrupt vectoring already in place from prior commit; BBS now
pops PC and clears INTA.
3 it.todo tests promoted to passing:
- INT high after EIN vectors PC to 0x003 and asserts INTA.
- BBS pops PC and clears INTA.
- SB1 + FIM writes to bank-1 R0..R7 (verified by ISZ wrap behaviour:
bank-0 R0=F → ISZ wraps to 0 → no branch, distinguishing from a
buggy SB1 that would have aliased the write to bank 0).
Adds Bus4040 helper (parallel to Bus4004) for feeding opcodes via
the multiplexed nibble bus. Total test_intel: 55 passing (was 52),
0 failed, 22 todo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
All 46 4004 instructions implemented per MCS-4 manual ([M4] Table V):
- ALU: NOP, INC Rn, ADD/SUB Rn, LD/XCH Rn, IAC/DAC, RAL/RAR, CMA, CMC,
STC, CLB, CLC, TCC, TCS, DAA, KBP
- Memory/IO: SRC Pn (no-op stub), I/O group (WRM/WMP/WRR/WPM/WR0..3,
RDM/RDR/ADM/RD0..3, SBM) all decoded; RAM-side effects stubbed
pending real 4001/4002 chips
- Control flow: JUN (12-bit jump), JMS (push+jump), BBL (pop+ACC),
JCN with full C1/C2/C3/C4 condition logic, ISZ in-page branch,
FIM (load reg pair), FIN/JIN (indirect via P0)
- DCL: load CMRAM bank select
Plus a Bus4004 helper class in 4004.test.js that mirrors a 4001 ROM
chip — pre-drives D0..D3 with the appropriate nibble during M1/M2,
tracks observed PC via the chip's A1/A2/A3 address-bus drives. This
mechanism lets the test feed arbitrary opcode streams without
needing a separate 4001 ROM chip on the canvas.
5 new ISA tests promoted from it.todo to passing:
- NOP advances PC by 1
- JUN jumps to 12-bit target
- JMS+BBL stack push/pop
- JCN with C4 jumps when TEST is logic-0
- JCN does not jump when condition false
3 it.todo remain: LDM, FIM, Busicom-style integration. These need
accumulator-state observability (a fake 4002 RAM via SRC+WRM) to
test, which is deferred.
Total test_intel: 52 passing (was 43), 0 failed, 25 todo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Introduced EPaperPanels.ts to define configurations for various ePaper panels including dimensions, refresh rates, and controller details.
- Implemented SSD168xDecoder.ts to handle the decoding of SPI commands for the SSD168x family of ePaper displays.
- Created EPaperPart.ts to manage the simulation of ePaper panels, integrating with the existing simulator architecture and handling events.
- Added example sketches for 2.13", 2.9", 4.2", and 7.5" ePaper displays, demonstrating basic functionality and text rendering.
- Ensured compatibility with AVR, RP2040, and ESP32 platforms, with appropriate pin configurations for each.
Companion chip for 8086 minimum-mode boards that demultiplexes
AD0..AD15 → A0..A15 under control of ALE. ~80 LOC clean-room from
the public Intel 8282/8283 datasheet.
Pin contract (20-pin DIP): DI0..7 in, DO0..7 out, STB strobe, OE̅
output enable, VCC, GND. Behaviour:
STB=1, OE̅=0 → DO follows DI (transparent)
STB falling → latch held while STB=0
OE̅=1 → DO pins released (modelled as VX_INPUT)
Tests: 4/4 passing (pin contract, transparent mode, latch hold,
output enable). Brings test_intel total to 47 passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The two earliest commercial Intel CPUs as velxio custom chips:
- 4004.c (~150 LOC): 16-pin DIP, 8-phase frame (A1..X3), SYNC at A1
with PC nibble walk on D0..D3 (low-first per MCS-4 Fig. 2), CMROM
strobe during M1. ISA decoded as NOP for now — full 46-instruction
set deferred to ISA phase.
- 4040.c (~250 LOC): 24-pin DIP per MCS-40 pp. 1-5/1-6 (STP/STPA/INT/
INTA/CY/dual CMROM/dual standby Vdd). 4004-compatible bus + STP
latched at M2 → STPA asserts at X3 + INT forced JMS to PC=0x003.
14 new opcodes decoded as NOP for now.
Test refinements (analogous to bootCpu fix from 8080 work):
- bootChip no longer advances time post-RESET so first observed cycle
starts at A1 of cycle 0 with PC=0.
- SYNC sampler latches on first edge (was over-collecting on
subsequent SYNC pulses).
- 4040 test renamed STOP→STP, STOPACK→STPA per MCS-40 datasheet pin
names; added INTA, CY, VDD1, VDD2 pins; SYNC-stops assertion
removed (manual: STOP mode keeps clock and SYNC running).
Brings test_intel suite from 37 to 43 passing tests; 0 failures;
remaining 3 active are 8086 (deferred), 29 todo are intentional
deferred integration tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Authoritative spec docs cite Intel MCS-4 (Feb 1973) and MCS-40 (Nov 1974)
manuals page-by-page. Reference-implementations doc surveys four
permissively-licensed open-source emulators (markablov/i40xx,
Kostu96/K4004, lpg2709/emulator-Intel-4004, alshapton/Pyntel4004) for
cross-validation, explicitly excluding GPL sources (MAME mcs40,
carlini/intel-4004-in-4004-bytes-of-c).
Critical findings:
- 4040 interrupt vector is fixed at PC=0x003 (no vector table).
- New 4040 instructions all live at OPR=0000, OPA=0x01..0x0E.
- 4004 DAA (opcode 0xFB) is single-nibble, very different from 8080.
- 4040 STP/STPA/INTA pin names per datasheet (not STOP/STOPACK).
- R16..R23 are not directly named — they're Bank-1 R0..R7 via SB0/SB1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Added tcp_nat.py to handle TCP NAT, implementing the three-way handshake, data flow, and connection state management.
- Introduced udp_nat.py for UDP NAT, managing chip-initiated datagrams and maintaining flow state.
- Created integration tests in test_picow_net_bridge.py to validate the functionality of the TCP and UDP NAT implementations, including ARP, DHCP, ICMP, and DNS interactions.
- Introduced SVG layout dimensions for Phase 1 (B/W mono) and Phase 2 (colour) ePaper panels, detailing active areas, bezels, and pin layouts.
- Developed a phased emulation plan outlining the architecture and deliverables for different panel types, including SSD168x and UC81xx.
- Created a canonical "Hello, World!" sketch for the 1.54" ePaper panel, ensuring compatibility across ESP32, Raspberry Pi Pico, and Arduino Uno.
- Implemented a pure Python SSD168x decoder to validate SPI command sets and framebuffers against specifications.
- Added tests for compiling the hello-world sketch across supported boards and for the SSD168x protocol to ensure correct framebuffer behavior.
- Implemented handshake tests to validate initial bus state and register responses.
- Created end-to-end tests for Pico W LED blinking using MicroPython firmware.
- Added SDPCM framing tests to ensure proper encoding and decoding of control frames.
- Developed IOCTL tests to verify command responses and state changes in the emulator.
- Established a full lifecycle test for WiFi operations, including scanning, connecting, and packet handling.
- Introduced TypeScript configuration for test files to ensure compatibility and strict type checking.
- Implemented `esp32_spi_chip_demo.ino` to demonstrate SPI communication with a 74HC595 shift register.
- Created `esp32_uart_chip_demo.ino` for UART loopback testing with ROT13 transformation.
- Added Python tests for compiling chips and sketches, ensuring valid WASM output and successful compilation for various board families.
- Developed end-to-end tests for ESP32 with custom chips using I2C and SPI, validating synchronous communication through the backend.
- Introduced GPIO bridge tests to verify serial communication and GPIO state changes.
- Ensured all tests validate the expected behavior of the custom chips and their interaction with the ESP32 firmware.
https://github.com/kritishmohapatra/100_Days_100_IoT_Projects
- Introduced `_lib.py` containing shared validators for board support and static source analysis for MicroPython projects.
- Added `conftest.py` to configure pytest for the test suite, simplifying import paths.
- Created `NOT_SUPPORTED.md` files for two projects indicating they cannot be emulated in Velxio due to lack of source code.
- Implemented unit tests for the unsupported projects to verify the presence of the NOT_SUPPORTED marker and source preservation.
Fixes the user-reported bug where two RPi Pico W boards wired GP0↔GP1
running SerialPassthrough don't communicate. Replaces the broken
broadcast-style cross-board logic in addBoard (only routed AVR↔Pi3B,
ignored wires entirely, no RP2040↔anything path) with a wire-aware
Interconnect singleton.
Architecture: digital pin transitions are the lowest-common-denominator
abstraction. Each simulator's hardware peripherals (UART/I2C/SPI) and
bit-banging libraries (SoftwareSerial, software I2C) decode the
transitions naturally — propagate the pin and the protocols come for
free. For cross-process boards (ESP32 backend QEMU, Pi3B QEMU) a
byte-level shortcut is additionally enabled on hardware-UART pin
pairs to handle high-baud links over WebSocket latency.
Implementation:
- New simulation/Interconnect.ts singleton subscribes to wire/board
changes via the Zustand store. Handlers per tier: browser-sim →
pinManager.onPinChange, ESP32 → Esp32Bridge.sendPinEvent, Pi3B →
bridge.sendPinEvent. Re-entrancy guard via per-(board,pin) Set.
- New utils/boardProtocols.ts classifies pins (uart-tx, i2c-sda, etc.)
per board kind, used as optimization hint for the byte shortcut.
- types/wire.ts: added signalType field, exports WireSignalType /
WireColorMap (fixes a pre-existing TS import error in wireColors).
- Deleted the bridgeMap/simulatorMap broadcast forEach blocks in
addBoard. Initial board + future boards register with Interconnect
via setInterconnectRuntime + store subscription.
- PinManager.resetPinStates() helper for test isolation.
Tests (16 new files, 96 tests, all passing):
- Per-pair × per-protocol matrix: dual-arduino-digital,
dual-pico-digital, arduino-pico-digital, triple-pico-digital-chain,
dual-arduino-hw-uart, dual-arduino-software-serial,
arduino-pico-mixed-uart, arduino-esp32-uart, dual-esp32-uart,
pi3-pico-uart, arduino-pico-i2c, arduino-arduino-spi,
interconnect-routing, dual-arduino-multi-protocol (UART+I2C+SPI+
digital + concurrent), dual-pico-multi-protocol (UART0+UART1 alt+
I2C0+I2C1+SPI0+digital + 3-Pico star topology)
- Updated dual-pico-serial-passthrough to assert correct behaviour
- Backend test/multi_board_esp32/test_dual_esp32_serial.py for two
real QEMU instances (skip-graceful when lcgamboa lib absent)
Verified: 1107/1107 tests pass, zero regressions, vite build OK.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Track per-user, per-project, and per-board usage to inform pricing tier
decisions. Adds an admin dashboard with KPIs (DAU/WAU/MAU, totals,
success rate), time-series charts for compiles/runs, board family +
FQBN breakdowns, "board diversity" pie chart (key freemium signal),
top users/projects, and per-country breakdown via Cloudflare's
CF-IPCountry header. Admin can now also view private projects.
Backend:
- New UsageEvent table (append-only event log with user_id, project_id,
event_type, board_fqbn/family, country, error_kind, duration_ms)
- Aggregate counters on User (total_compiles/runs/errors, last_active,
signup_country, last_country) and Project (compile/run/update counts,
last_compiled/run timestamps) kept in sync by MetricsService for O(1)
dashboard reads
- 10 admin endpoints under /api/admin/metrics/{overview, timeseries,
boards, board-diversity, top-users, top-projects, countries,
users/{id}, projects/{id}}
- POST /api/metrics/run for client-side run telemetry
- Country detection via cf-ipcountry header (no DB / no API calls)
- Auto-migrations in lifespan for legacy DBs
Frontend:
- recharts-powered Dashboard tab with KPI cards and 4 charts
- New Boards tab with per-family + per-FQBN breakdown
- Country column with flag emoji on Users tab
- Top countries card on Dashboard
- compileCode now forwards project_id; Run button reports via WS
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
A user (st_stefanov on Discord) reported the manual setup steps clone
avr8js, wokwi-elements, and rp2040js but skip wokwi-boards. The frontend
imports board.svg assets from wokwi-libs/wokwi-boards/boards/* (ESP32
DevKit V1, ESP32-S3, ESP32-C3, Pi Pico W, etc.), so without that repo
the Vite build fails on missing imports.
Dockerfile.standalone:77 already clones it; the README's Option C
(manual setup) was the only path missing the line. wokwi-boards is
asset-only — no npm install or build step needed.
Registers test_esp32_spice_photodiode.mjs (added in the previous commit)
in the ESP32 + ngspice section of the backend e2e workflow, with a 150s
timeout to accommodate ESP32 firmware compile + QEMU boot.
Follows the same pattern as test_esp32_spice_analog.mjs and
test_esp32_spice_ntc_bridge.mjs: compile an ESP32 sketch on-the-fly via
/api/compile/, boot QEMU through the backend WebSocket, and sweep lux
levels while verifying analogRead() returns what ngspice solved.
The netlist uses the exact photodiode cards emitted by
frontend/.../componentToSpice.ts (D_<id> + I_<id>_ph + DPHOTO model), so
any drift in the frontend SPICE mapper surfaces here.
Validated against the live Docker container — lux=0/1000/2500 produce
raw=4095/2854/992, matching the expected 4095/2854/993 within ±1 LSB
and monotonically decreasing with brightness as expected.
The package-lock.json churn is a pre-existing drift: eecircuit-engine
was in package.json but missing from the lock — npm install re-added it.
Companion workflow change (registering the test in backend-e2e-tests.yml)
lives in a separate commit that requires a PAT with workflow scope to push.
Mirrors the /v2 page structure but targets the 2.5 launch: ngspice-WASM
analog simulation, hybrid digital + analog co-simulation with Arduino /
ESP32 / RP2040, expanded component catalog, live instruments, 40 new
analog/hybrid examples.
- Reuses Velxio2Page.css + SEOPage.css — no new stylesheet to maintain
- Adds SoftwareApplication, BreadcrumbList, and FAQPage JSON-LD for
rich-results eligibility
- Registers the route in App, entry-server (SSR prerender), and
seoRoutes (sitemap, priority 0.95 / changefreq weekly)
The SPICE emitter already reads properties.lux (default 500, 100 nA/lux)
but the UI had no way to set it — the static dialog rejected the "range"
control type and there was no entry in SENSOR_CONTROLS for the live panel.
- Add photodiode entry in SENSOR_CONTROLS (slider 0-1000 lux)
- Register a minimal PartSimulationRegistry handler that forwards slider
values via emitPropertyChange so the netlist memo invalidates
- Switch the photodiode lux control from "range" to "number" so the
static ComponentPropertyDialog renders an editable input
Loading an analog-only example removes every board. The single-board
branch of loadExample then called setBoardType, which only maps over
existing entries in boards[] and silently did nothing when the array
was empty — components rendered but no board. Fall back to addBoard +
setActiveBoardId when there are no boards.