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-19 09:38:18 +07:00
|
|
|
"""POST /api/compile-rom — assemble or convert a chip-program source to ROM bytes.
|
|
|
|
|
|
|
|
|
|
Used by Velxio's "Compile" button when the active file is a chip-program file
|
|
|
|
|
(`.s` / `.asm` / `.hex` / `.bin`). The compiled ROM is base64 bytes that the
|
|
|
|
|
frontend stashes in the chip's `romBytes` property; the chip reads them on
|
|
|
|
|
chip_setup via the new `vx_rom_size` / `vx_rom_read` SDK calls.
|
|
|
|
|
|
|
|
|
|
Request body:
|
|
|
|
|
source: str chip-program source (asm text, hex text, or bin-as-hex)
|
|
|
|
|
target: str "8080" | "z80" | "8086" | "4004"
|
|
|
|
|
format: str "asm" | "hex" | "bin"
|
|
|
|
|
|
|
|
|
|
Response (mirrors compile_chip.py shape):
|
|
|
|
|
success: bool
|
|
|
|
|
rom_base64: str | null
|
|
|
|
|
byte_size: int
|
|
|
|
|
stderr: str
|
|
|
|
|
error: str | null
|
|
|
|
|
"""
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import logging
|
|
|
|
|
|
|
|
|
|
from fastapi import APIRouter, HTTPException
|
|
|
|
|
from pydantic import BaseModel
|
|
|
|
|
|
|
|
|
|
from app.services.rom_compile import compile_rom
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RomCompileRequest(BaseModel):
|
|
|
|
|
source: str
|
|
|
|
|
target: str = "8080"
|
|
|
|
|
format: str = "asm"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RomCompileResponse(BaseModel):
|
|
|
|
|
success: bool
|
|
|
|
|
rom_base64: str | None = None
|
|
|
|
|
byte_size: int = 0
|
|
|
|
|
stderr: str = ""
|
|
|
|
|
error: str | None = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/", response_model=RomCompileResponse)
|
|
|
|
|
async def compile_rom_endpoint(request: RomCompileRequest):
|
|
|
|
|
if not request.source.strip() and request.format != "bin":
|
|
|
|
|
raise HTTPException(status_code=422, detail="`source` cannot be empty.")
|
|
|
|
|
try:
|
2026-05-19 10:31:10 +07:00
|
|
|
result = await compile_rom(request.source, request.target, request.format) # type: ignore[arg-type]
|
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-19 09:38:18 +07:00
|
|
|
except Exception as e: # noqa: BLE001
|
|
|
|
|
logger.exception("ROM compile failed")
|
|
|
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
return RomCompileResponse(**result)
|