Commit Graph

12 Commits

Author SHA1 Message Date
David Montero Crespo 17e9e5a8c2 refactor(custom-chips): move the AI entry point out of OSS into an overlay slot
The 'Create with AI' button referenced the Pro AI agent (hardcoded
prompt, agent event) inside the anonymous OSS dialog — chat/agent logic
must live in the velxio-prod overlay, not here. CustomChipDialog now
just exposes a generic `data-velxio-slot="custom-chip-actions"`
extension point (empty in OSS) and hangs its close handler on the slot
element so the overlay can dismiss the dialog after acting. The button
itself, its prompt and the Pro entitlement gate move to the overlay.
2026-07-17 04:36:14 +02:00
David Montero Crespo cd22335838 feat(custom-chips): AI entry point + friendly auth error
- 'Create with AI' button in CustomChipDialog dispatches the generic
  velxio:agent-prompt window event (no-op without a listener — the pro
  overlay's chat panel picks it up and prefills the composer).
- chipCompileService maps the hosted deployment's 401 gate to a human
  'sign in to compile custom chips' message instead of a raw status
  line. Self-hosted OSS keeps the route open and never sees either.
2026-07-16 20:34:42 +02:00
David Montero Crespo 47adb0b1c8 fix(chipbus): Galaksija boots + displays + types live in the browser
The gallery example loaded but the Z80 never visibly ran: the screen stayed
frozen on garbage. Two multi-chip async-load races, neither caught by the
existing headless tests (which drive RESET manually and attach the display
before boot):

1. RESET edge-vs-level race. The Z80 only left reset on the RISING edge of
   RESET (a pin watch). In the browser the 7 chips instantiate asynchronously,
   so the small power-on-reset chip releases RESET before the larger Z80 has
   registered its watch -> the edge is lost and the CPU stays in reset forever.
   Fix: on_clock samples the RESET level (hardware-accurate; RESET is
   level-sensitive) so a missed edge self-corrects. An undriven RESET reads low,
   so the CPU safely stays in reset until something drives it high.
   Repro/guard: chipbus-galaksija-reset-race (race ordering must still boot).

2. Display-snoop load-order race. galaksija-display was a passive write-snoop;
   the ROM paints the screen ONCE at boot then idles, so a display that comes up
   late misses every write and shows stale content forever. A snoop cannot
   recover writes it never saw. Fix: fold the screen into the RAM chip
   (galaksija-ram-display) and render from the ACTUAL video RAM (0x2800-0x2BFF,
   internal 0x0800 with A0-A12 wiring) on a ~30 fps timer - correct regardless
   of load order, exactly how the real machine scans video RAM.
   Repro/guard: chipbus-galaksija-display-snoop-race (late snoop shows nothing)
   + chipbus-galaksija-ram-display (renders even when first paint is post-boot).

The example now has 6 chips (RAM+display merged, gdisp dropped), 76 wires.
Verified live in the browser: boots to "@'READY", shows the ">" prompt, and
pressing A echoes ">A_" through keyboard -> Z80 -> video RAM -> display. The
full chipbus suite is 45/45.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 15:47:30 -03:00
David Montero Crespo 94627b99d2 feat(chipbus): Galaksija keyboard - type BASIC over the bus
Adds a memory-mapped keyboard so you can type into the Galaksija. Based on
the libretro Galaksija core's scheme (not guessed): reading 0x2000+offset
returns 0xFE when the key at that matrix offset is held, 0xFF otherwise;
the keyMap gives the offset per key ('A'=1 ... Enter=48, Space=31, etc.).

- galaksija-keyboard.c: drives reads of 0x2000-0x203F from a keys[] table and
  exports set_key(offset, down) for the host to push key events. Never drives
  outside the keyboard range.
- galaksija-ram.c: ram-64k variant that yields reads of 0x2000-0x203F to the
  keyboard (writes still go to RAM), so the two never fight for the bus.
- ChipRuntime: ChipInstance.hasKeyboard + setKey() expose the chip's set_key.
- CustomChipPart: bridges browser keydown/keyup (by KeyboardEvent.code, via
  GALAKSIJA_KEY_OFFSET) into the chip, ignoring keystrokes while the code
  editor or an input is focused so typing code is never hijacked.
- The gallery example gains the keyboard chip (now 7 chips, 99 wires) and uses
  galaksija-ram.

Test chipbus-galaksija-keyboard: pressing 'A' (offset 1) makes the BASIC
monitor echo "A" after its ">" prompt and advances the cursor. 41 chipbus
tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 14:37:42 -03:00
David Montero Crespo a393e3e91d feat(chipbus): Galaksija home computer gallery example + browser perf throttle
Ships the full Galaksija (1983 Z80 home computer) as a runnable Retro
gallery example, plus the pieces needed to run a multi-chip bus live in the
browser.

Gallery example (examples-retro-intel.ts, id 'galaksija-z80-computer'):
Z80 + galaksija-rom (public-domain ROM A+B) + ram-64k + inverter (A13
decode) + galaksija-display + a power-on reset chip, wired chip-to-chip
over the bus (76 wires), no board. Click Resume and it boots the real ROM
to the "READY" prompt on the green display. Chip wasm is embedded
(wasmBase64) so it runs without a backend compile.

- ChipRuntime.tickTimers gains a wall-clock budget (CustomChipPart passes
  6 ms): a faithful-but-slow event-driven bus can't run a real-time CPU in
  one animation frame, so without a cap a Z80 fetching over the settle
  kernel froze the tab. With the budget the sim advances slower than real
  time (boots over a few seconds) and the UI stays responsive; fast
  single-chip examples finish under budget and are unaffected.
- galaksija-display: blits its framebuffer on a ~30 fps timer instead of on
  every character write, so a clear-screen burst doesn't flood the canvas.
- reset-gen: power-on reset (pulses RESET high, ties WAIT/BUSREQ/INT/NMI
  high) so the machine boots on Resume without a manual reset.
- chipbus flag now defaults ON (override with ?chipbus=off): chip-to-chip
  buses are a core capability; single-chip and board nets never take this
  path, so the only thing enabled is multi-chip buses, previously broken.

Verified live in the browser: the example boots and renders "@'READY" with
the ">_" prompt, responsive. Full suite 2084 pass (5 pre-existing,
unrelated env failures).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 13:49:33 -03:00
David Montero a68e7f8e94 feat(editor): rename boards & custom chips; show which target owns each file
Phase 2 of the run-system/UX work.

- BoardInstance gains an optional user ; boardDisplayName(board) resolver
  (name || kind label) routes every INSTANCE-label surface: file-explorer
  section header, compile console (EditorToolbar), canvas selector/tooltip/
  context-menu, Serial Monitor tabs, Oscilloscope board picker, Board Options
  subtitle. Board/component pickers keep the KIND label (they pick new boards).
- Inline rename on board AND chip section headers (double-click the name, or a
  hover pencil button). Board -> updateBoard(id,{name}); chip -> chipName in
  properties. Enter commits, Escape cancels (cancel-flag ref guards the
  unmount-fires-onBlur footgun), empty clears to the kind / 'Custom Chip'.
- FileTabs shows an owner badge naming the board/chip whose files are shown
  (resolved as a selector so it doesn't re-render on every sim pin toggle).
- CustomChipDialog no longer clobbers a user-given chipName: chip.json's name
  only seeds the blank defaults (My Chip / Custom Chip); loading an example
  relabels explicitly.
- Persistence: board name round-trips via projectPayload (+ dirty hash),
  vlxFile, ProjectByIdPage load + loadProjectState; chipName rides components_json.
- Drive-by: fixed a pre-existing rules-of-hooks violation in BoardOptionsModal
  (early return before a useCallback).

Reviewed by a 3-agent adversarial pass (completeness / persistence / correctness);
all major findings folded in.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 06:22:25 +02:00
David Montero 1d6961d03c fix(z80-cpu): map RAM over the whole 0x8000-0xFFFF so vanilla SDCC C runs
SDCC's z80 crt0 sets SP=0x0000 and makes its first stack push at 0xFFFF.
The chip only mapped RAM at 0x8000-0xBFFF (0xC000+ was MMIO/ignored), so the
stack landed on unmapped memory and a plain C program crashed inside crt0 —
before main — which is why z80-led-chaser-c compiled but drove nothing.

Extend RAM to cover 0x8000-0xFFFF (32 KB) with the MMIO window 0xC000-0xC0FF
carved out and checked first, in scripts/make-z80-cpu.py + regenerated
z80-cpu.c. Now SDCC's default stack works and "write C from scratch, click
Run" just works — no manual `LD SP` needed (dropped from chaser.c). Bumped
the chip WASM initial memory to 4 pages to hold the larger RAM buffer. Larson
(asm, SP=0xBFFF, LED at 0xC000) is unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 13:31:26 +02:00
David Montero Crespo 96ef12b585 feat(chips): programmable Z80 chip + Larson scanner example
Adds the Zilog Z80 to the programmable-retro-CPU lineup. Same compile-rom
flow that landed for the 8080 in PR #189: write Z80 asm in a project
file, click Compile (backend assembles via in-tree two-pass asm-z80),
click Run, the chip emulator boots from the resulting ROM bytes.

Backend:
- backend/app/services/asmz80.py — two-pass Z80 assembler covering the
  practical demo subset: LD r,n / r,r' / rp,nn / (nn),A / A,(nn) +
  ALU r/n + INC/DEC + JP/JR/DJNZ/CALL/RET + PUSH/POP + IN/OUT +
  EX/EXX + LDIR/LDDR/IM/NEG + RLCA/RRCA/RLA/RRA + the simple
  ED-prefix variants. Not yet: CB-prefix bit ops, DD/FD index ops.
- rom_compile.py routes target=z80 through the new assembler.

Chip:
- frontend/src/components/customChips/examples/intel/z80-cpu.{c,chip.json}
  Generated by scripts/make-z80-cpu.py from the existing z80.c emulator
  (same clean-room implementation that passes ZEXDOC end-to-end). The
  external pin/bus protocol is replaced with internal RAM + ROM + MMIO
  for LED/BTN/UART. 35 KB WASM.

Example:
- /examples/z80-larson-scanner — Knight-Rider-style walking LED.
  Demonstrates JR/DJNZ/RLCA which the 8080 can't run.

Plus a small Z80 smoke-test asm under scripts/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 00:21:08 -03:00
David Montero Crespo bbf8cd0303 feat(chips): programmable retro CPU chips with external ROM
Adds a new way to use the retro CPU chips: write your program in a
project file (.s / .asm / .hex / .bin), click Compile, click Run, and
the same chip emulates whatever you wrote. Same chip + different ROMs =
mini PC, calculator, LED demo, Kill-the-Bit game, etc.

SDK:
- velxio-chip.h gets two new host imports:
    uint32_t vx_rom_size(void);
    void     vx_rom_read(uint32_t off, uint8_t* dst, uint32_t len);
  CPU-emulator chips call these in chip_setup to pull their program out
  of the host's romBytes property.

Frontend runtime:
- ChipRuntime accepts opts.romBytes (Uint8Array) and exposes the new
  imports, copying bytes into chip memory on vx_rom_read.
- CustomChipPart pulls component.properties.romBytes (base64) and passes
  it through.
- Component registry declares three new custom-chip properties:
  romBytes (base64), programFile (matching project filename), and
  programTarget (cpu name).

New programmable bundled chip:
- frontend/src/components/customChips/examples/intel/i8080-cpu.{c,chip.json}
  Same clean-room 8080 emulator as i8080-repl/i8080-counter, but ROM is
  loaded externally via vx_rom_*. Has 8 LEDs, 8 buttons, UART, 16 KB RAM,
  32 KB of external ROM.

Backend:
- New /api/compile-rom endpoint and rom_compile service that turns
  chip-program source into ROM bytes. 8080 ASM is assembled by the
  in-tree two-pass assembler (moved to backend/app/services/asm8080.py).
  Intel HEX records are parsed; raw .bin is passed through. Future targets
  (z80, 8086, 4004) are scaffolded but not wired yet.

EditorToolbar:
- Compile button detects when the active file is .s/.asm/.hex/.bin and
  routes to compile-rom instead of arduino-cli. The compiled bytes are
  injected into every custom-chip on the canvas whose programFile property
  matches the active filename (or is empty).

Example:
- /examples/i8080-killbits loads Dean McDaniel's 1975 Kill-the-Bit on
  the programmable i8080-cpu chip. killbits.s is shipped as a project
  file alongside sketch.ino; the user clicks Compile then Run and the
  LED walks across 8 outputs, buttons kill it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 23:38:18 -03:00
David Montero Crespo b714c79e3d feat(chips): port retro Intel/Zilog CPUs as Velxio custom chips + 2 demos
Adds 17 chips from the test/test_intel clean-room research to the Custom
Chip gallery, all sourced from manufacturer datasheets and validated by
the existing 129-test vitest harness (CPUDIAG end-to-end for the 8080,
ZEXDOC for the Z80).

CPUs: 4004, 4040, 8080, 8086, Z80 (categoria retro-cpu)
Bus chips: rom-32k, ram-64k, rom-1m, latch-8282, 4001-rom, 4002-ram,
           8255-ppi, 8251-usart, 8259-pic, 8253-pit (retro-bus)

Two bundled "mini-computer" demos under retro-bundle that drop on the
canvas as a single chip and run real 8080 code out of an embedded ROM:

  * i8080-repl     8080 + RAM + ROM + UART, prints a banner and an
                   "uptime ticks: 0xNN" counter every ~50 ms via a real
                   DCR/JNZ busy-wait. Visible in Serial Monitor.

  * i8080-counter  8080 + RAM + ROM + 8 LED pins + 2 button pins.
                   Counts up in binary on BTN_INC, clears on BTN_RST.

Two example projects under /examples reuse these chips end-to-end:

  * /examples/i8080-banner-streamer
  * /examples/i8080-button-counter

The bundled chips inline a 328 / 34-byte 8080 ROM produced by a new
two-pass 8080 assembler in Python (scripts/asm8080.py) from the .s
sources in scripts/. Both ROMs are pre-assembled and committed under
scripts/*.txt so contributors can rebuild deterministically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 02:27:53 -03:00
David Montero Crespo 99156c9c9d feat(editor): translate Oscilloscope + property dialog + selection bar + console + custom chips + sensor + board picker (Editor block 9)
This commit closes the cluster of small editor surfaces that touch
the active simulation experience. Every visible control on these
panels now reads from t() keys.

Translated:
- Oscilloscope panel (title, Add Channel button + tooltip, Time/div
  label, Run / Pause toggle copy + tooltips, Clear, empty-state copy
  + hint, per-channel remove tooltip).
- ComponentPropertyDialog (close, pin-roles header with two
  wire-mode variants, Arduino Pin label, rotate / delete buttons +
  the inline confirm-delete prompt with name interpolation).
- SelectionActionBar (toolbar aria-label, Rotate / Delete / Deselect
  with kind-aware delete labels for wire / component / board).
- CompilationConsole (Output title, error / warning badge counts
  with i18next pluralisation, filter dropdown, autoscroll label,
  Clear + Close icon tooltips, empty-state).
- CustomChipDialog (header with chipName interpolation, Examples /
  Editor tabs, Attributes panel header, compile status messages
  including the "✓ Compiled — N KB" success line, footer
  Cancel / Save & Place / Compile first buttons).
- SensorControlPanel (close button).
- BoardPickerModal (Add Board heading).

Translation pipeline
- en.json gets the new keys hand-curated.
- The 8 non-English locales were auto-translated via DeepSeek
  using the existing scripts/translate-i18n.mjs pipeline (one
  --force run, ~1 min total). Output validated with sameShape()
  before write so any LLM-introduced key drift would have failed
  loudly.

Quality note
- DeepSeek's translations now cover the entire bundle, including
  earlier hand-translated content. Tone may differ slightly from
  the prior hand passes but the meaning is consistent and brand /
  technical terms (Velxio, ngspice-WASM, ATmega328P, ESP32-C3,
  etc.) are preserved unchanged in every locale per the prompt
  invariants.
2026-05-09 12:25:30 -03:00
David Montero Crespo 7f2014bef7 Add ESP32 chip demos and comprehensive tests for I2C, SPI, and UART interactions
- 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.
2026-04-28 19:24:39 -03:00