Production-grade TypeScript-to-SystemVerilog compiler and FPGA toolchain.
Write hardware in TypeScript. Compile to IEEE 1800-2017 SystemVerilog. Synthesise and flash with a 100% open-source toolchain.
Author: Radoslav Sandov
- TypeScript class-style hardware source (
@Module,@Sequential,@Combinational) compiled into standard, portable SystemVerilog. - Board constraint generation from JSON board definitions: add your own board in minutes.
- Containerised synthesis, place-and-route, and bitstream packaging (Yosys + nextpnr + gowin_pack).
- Persistent FPGA programming using
openFPGALoader --external-flash --write-flash --verify. - TypeScript-native UVM-style verification: write testbench specs in TypeScript, simulate in-container.
Install the runtime package to write synthesisable TypeScript hardware modules by cloning this repository
For the full hardware toolchain (synthesis, place-and-route, and FPGA flashing), clone the repository and follow the getting started guide.
Use this exact sequence on Linux.
- Bun 1.3+
- Podman or Docker
- Git
- USB access to your board programmer
bun installbun run toolchain:image:buildbun run qualityUse the Tang Nano 20K board workflow (buttons/switches per board manual), then verify USB probe visibility.
lsusb
podman run --rm --device /dev/bus/usb ts2v-gowin-oss:latest openFPGALoader --scan-usbThe blinker uses the @Hardware ergonomics decorator - no need to choose
between @Sequential and @Combinational; the compiler infers the right
always_ff block from the presence of the clock signal.
// blinker.ts - minimal example using @Hardware ergonomics API
import { HardwareModule, Module, ModuleConfig, Input, Output, Hardware } from '@ts2v/runtime';
import type { Bit, Logic } from '@ts2v/runtime';
const HALF_PERIOD = 13_500_000; // ~0.5 s at 27 MHz
@Module
@ModuleConfig('resetSignal: "no_rst"')
class Blinker extends HardwareModule {
@Input clk: Bit = 0;
@Output led: Logic<6> = 0x3F;
private counter: Logic<25> = 0;
@Hardware('clk') // inferred as always_ff @(posedge clk)
tick(): void {
this.counter = this.counter + 1;
if (this.counter === HALF_PERIOD) {
this.counter = 0;
this.led = this.led ^ 1;
}
}
}bun run apps/cli/src/index.ts compile \
examples/hardware/tang_nano_20k/blinker/blinker.ts \
--board boards/tang_nano_20k.board.json \
--out .artifacts/blinker \
--flashConfirmed flash output (Winbond W25Q64, Tang Nano 20K):
Detected: Winbond W25Q64 128 sectors size: 64Mb
Writing: [==================================================] 100.00% Done
Verifying write ... Reading: [==================================================] Done
Power off/on the board. Behavior should persist because image was written to external flash.
The WS2812 demo cycles a connected strip through a 6-colour rainbow (GRB order: RED, YELLOW, GREEN, CYAN, BLUE, MAGENTA) while walking the six board LEDs. Tang Nano 20K pin 79 carries the WS2812 data line.
- S2 (pin 87) held: strip cycles colours. Released: strip goes dark.
- S1 (pin 88) held: 6 board LEDs walk one at a time. Released: all LEDs off.
Both buttons are active-high (pull-down to GND at rest, press drives pin to 3.3V).
bun run apps/cli/src/index.ts compile \
examples/hardware/tang_nano_20k/ws2812_demo \
--board boards/tang_nano_20k.board.json \
--out .artifacts/ws2812_demo \
--flashThis demo has been confirmed flashed to a Tang Nano 20K (Winbond W25Q64).
Drives an 8-LED WS2812 strip with a slowly rotating rainbow. Every pixel is always on, each showing a different colour, so the strip looks like a full rainbow at once. Hold S2 (pin 87) for 8x speed.
WS2812 data line: pin 79. No external strip? The onboard WS2812C-2020 shows pixel 0.
bun run apps/cli/src/index.ts compile \
examples/hardware/tang_nano_20k/aurora_wave \
--board boards/tang_nano_20k.board.json \
--out .artifacts/aurora_wave \
--flashSame rainbow as aurora_wave, but you can change colours and speed live from your PC over USB serial. Flash and run with the included scripts:
./examples/hardware/tang_nano_20k/aurora_uart/flash.sh
./examples/hardware/tang_nano_20k/aurora_uart/run.shCommands: a=aurora r=red g=green b=blue f=faster s=slower x=freeze q=quit.
The FPGA replies K after every command it understands.
See examples/hardware/tang_nano_20k/aurora_uart/README.md for full details.
Send two numbers and an operation to the FPGA over USB serial. The FPGA computes the result in hardware and sends it back. The client uses JSON.
./examples/hardware/tang_nano_20k/calc_uart/flash.sh
./examples/hardware/tang_nano_20k/calc_uart/run.sh> {"op": "add", "a": 42, "b": 13}
{"op":"add","a":42,"b":13,"result":55,"hex":"0x0037","ms":2}
Operations: add, sub, mul. Operands: 0-255. Result: 16-bit.
See examples/hardware/tang_nano_20k/calc_uart/README.md for full details.
See docs/guides/examples-matrix.md for the full examples list.
bun run quality: typecheck + lint + test + build.bun run test:root: run focused root regression suite (tests/class-compiler.test.ts).bun run test:uvm: compileexamples/alu/alu.tsandexamples/hardware/tang_nano_20k/blinker/blinker.ts, generate UVM-style benches from TypeScript specs, run simulation in Podman/Docker, and emit per-suite reports (.artifacts/uvm/reports/*.json|*.md).bun run toolchain:image:build: build local synth/flash image.bun run compile:example: compile default example.bun run flash:tang20k <bitstream.fs>: direct flash helper entrypoint.
- docs/guides/getting-started.md: newcomer onboarding, from empty folder to flashed blinker with testbench (start here if you are new).
- docs/guides/runtime-api.md: runtime API reference - all decorators, hardware types (
Logic,Bit,LogicArray),HardwareModule,Bitsnamespace, recommended tsconfig, multi-file patterns. - docs/quickstart.md: WS2812-first end-to-end quickstart with explicit pass/fail checks.
- docs/guides/end-to-end-delivery.md: step-by-step compile-to-flash delivery guide (reference for new hardware modules).
- docs/guides/board-definition-authoring.md: complete board definition guide.
- docs/guides/board-definition-properties-reference.md: complete property reference (
std,drive,pull,freq, vendor mappings). - docs/guides/tang_nano_20k_programming.md: Tang Nano 20K flashing runbook.
- docs/guides/debugging-and-troubleshooting.md: end-to-end debug flow and failure signatures.
- docs/guides/production-reality-check.md: production acceptance workflow with proof commands.
- docs/production-readiness.md: production analysis - compiler status, WS2812 timing verification, known limitations, disclaimers.
- docs/guides/programmer-profiles-and-usb-permissions.md: profile and permission model.
- docs/guides/user-usb-debugger-onboarding.md: practical USB probe onboarding.
- docs/guides/uart-serial-debugging.md: UART and serial port debugging - find correct ttyUSB port, test hardware with Python, stty configuration, Bun serial I/O patterns, Tang Nano board references.
- docs/guides/stdlib-protocol-library.md:
@ts2v/stdlibprotocol modules - I2C, SPI, UART, CAN, PWM, 1-Wire, WS2812, VGA, HDMI. - docs/guides/formal-verification.md: formal verification -
@Assert,@Assume,.sbyauto-generation,bun run verify, SymbiYosys BMC. - docs/guides/multiclock-domain.md: multiclock domain design -
@ClockDomain,ClockDomainCrossing,AsyncFifo, clock constraints. - docs/guides/ergonomics.md: ergonomics API -
SignalBus,Reg,Edge,rising/falling,@Hardware. - docs/guides/examples-matrix.md: examples, intent, and expected hardware behavior.
- docs/guides/uvm-simulation-with-podman.md: containerized simple UVM-style simulation flow.
- docs/guides/uvm-suite-authoring.md: how to add future UVM-style verification suites and reports.
- docs/guides/ws2812-protocol-and-brightness.md: WS2812 protocol semantics and brightness behavior.
- docs/guides/ws2812-debug-guide.md: WS2812 NeoPixel debug guide - protocol root causes, chip variant timing (WS2812B vs WS2812C-2020), oscilloscope verification checklist.
- docs/development.md: contributor/developer workflow.
- docs/hardware-toolchain.md: synth/programming architecture and command flow.
- docs/architecture.md: system architecture with Mermaid diagrams.
- docs/specification.md: language and generation spec.
- docs/compliance.md: standards and subset compliance.
- docs/qa-testing.md: test strategy and quality gates.
- docs/package-inventory.md: package boundaries and responsibilities.
- docs/security-compliance.md: repository compliance and security posture.
- docs/append-only-engineering-log.md: append-only operational log.
- cpu/README_ASSEMBLY.md: nibble4 CPU architecture and assembly guide.
- CLAUDE.md: AI/LLM project context - supported TypeScript subset, compiler limitations, workarounds, DX guidance for human and AI contributors.
- docs/release-notes-aurora-wave.md: Aurora wave demo release notes - design patterns, compiler fix, gap list, social caption.
apps/cli: CLI argument parsing and command handlers.packages/core: compiler facade and legacy adapter wrapper.packages/runtime: decorators and TS-side hardware types.packages/toolchain: synthesis and flashing adapters.packages/config: workspace and board config services.packages/process: process runtime abstraction.packages/types: shared interfaces/contracts.boards: board definitions used by compile/flash flow.examples/: hardware examples for Tang Nano 20K and simulation.examples/hardware/tang_nano_20k/blinker/: 6-LED chaser (good first test)examples/hardware/tang_nano_20k/ws2812_demo/: WS2812 rainbow - see ws2812-debug-guide.mdexamples/hardware/tang_nano_20k/aurora_wave/: 8-pixel smooth rainbow, no PC neededexamples/hardware/tang_nano_20k/aurora_uart/hw/: Aurora rainbow with live serial control - see READMEexamples/hardware/tang_nano_20k/calc_uart/hw/: FPGA calculator over serial (JSON in, JSON out) - see READMEexamples/hardware/tang_nano_20k/uart-echo/: UART loopback (UartTx + UartRx from stdlib)examples/hardware/tang_nano_20k/pwm-fade/: LED fade via PwmGenerator stdlib moduleexamples/hardware/tang_nano_20k/ws2812-stdlib/: WS2812 rainbow importing Ws2812Serialiser from@ts2v/stdlibexamples/hardware/tang_nano_20k/spi-loopback/: SPI controller-peripheral loopback (SpiController + SpiPeripheral)examples/hardware/tang_nano_20k/i2c-scan/: I2C bus scanner (address 0x08..0x77 via I2cController)examples/hardware/tang_nano_20k/dual-clock-sync/: CDC two-FF synchroniser (ClockDomainCrossing primitive)examples/hardware/tang_nano_20k/dual-clock-fifo/: Async FIFO CDC (AsyncFifo with gray-code pointers)examples/hardware/tang_nano_20k/hdmi-colour-bars/: HDMI colour bars via TMDS encoding (VgaTimingGenerator + HdmiDviOutput)examples/hardware/tang_nano_20k/knight_rider/: Knight Rider LED scannerexamples/hardware/tang_nano_20k/breathe/: Breathing LED (PWM submodule demo)examples/hardware/tang_nano_20k/matrix_uart/hw/: 4x4 matrix multiply over UART (JSON matrices in, result out) - see READMEexamples/hardware/tang_nano_20k/tpu_uart/hw/: FPGA TPU (dot product, MAC, ReLU, reset_acc) over UART - see READMEexamples/cpu/nibble4/: nibble4 4-bit soft-CPU - 16-opcode core + SoC (UART, LEDs, dual-core arbiter)examples/adder/,examples/alu/,examples/uart_tx/: simulation examples
testbenches/uvm/: UVM-style testbench specs (TypeScript) compiled to SV for simulation.
WS2812 chip variant reset requirement: The on-board WS2812C-2020 (Tang Nano 20K pin 79) requires T_RESET > 280 µs. The commonly-cited 50 µs value applies only to WS2812B strips. Using 50 µs reset will cause the LED to silently do nothing. The serialiser in this repo uses 370 µs (10 000 clocks at 27 MHz).
3.3 V logic vs 5 V WS2812B strips: FPGA GPIO outputs 3.3 V. External 5 V WS2812B strips may require a 74AHCT125 level shifter on the data line for reliable operation. The on-board LED works directly at 3.3 V.
Confirmed flash status scope: The
ws2812_democonfirmed-flash status reflects the on-board LED only. External strip behavior depends on your power supply, level shifting, and the exact WS2812 variant in use.
Open-source toolchain only: This project targets Yosys + nextpnr exclusively. No Quartus, Vivado, or Gowin EDA proprietary bits are required. The Arty A7 board definition generates
.xdcconstraint files but has no synthesis flow - constraint output only until a fully self-contained OSS path exists for Xilinx 7-series.
MIT. See LICENSE.
See AUTHORS.md.