Skip to content

thecharge/sndv-hdl

Repository files navigation

ts2v

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

What This Repository Delivers

  • 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.

Installation

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.


Quickstart From Zero To Blinky

Use this exact sequence on Linux.

1. Install Prerequisites

  • Bun 1.3+
  • Podman or Docker
  • Git
  • USB access to your board programmer

2. Install Dependencies

bun install

3. Build Toolchain Image

bun run toolchain:image:build

4. Validate Workspace Quality

bun run quality

5. Put Board Into Programming Mode

Use 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-usb

6. Compile And Flash Blinky (Persistent)

The 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 \
  --flash

Confirmed flash output (Winbond W25Q64, Tang Nano 20K):

Detected: Winbond W25Q64 128 sectors size: 64Mb
Writing:  [==================================================] 100.00%  Done
Verifying write ... Reading: [==================================================] Done

7. Power Cycle And Recheck

Power off/on the board. Behavior should persist because image was written to external flash.

Quickstart From Zero To WS2812 Interactive Demo

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 \
  --flash

This demo has been confirmed flashed to a Tang Nano 20K (Winbond W25Q64).

Quickstart: Aurora Wave - 8-Pixel Rainbow Demo

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 \
  --flash

Quickstart: Aurora UART - Rainbow You Can Control Over Serial

Same 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.sh

Commands: 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.

Quickstart: Calc UART - Calculator Running on the FPGA

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.

Core Commands

  • 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: compile examples/alu/alu.ts and examples/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.

Documentation Index

Repository Layout

  • 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.md
    • examples/hardware/tang_nano_20k/aurora_wave/: 8-pixel smooth rainbow, no PC needed
    • examples/hardware/tang_nano_20k/aurora_uart/hw/: Aurora rainbow with live serial control - see README
    • examples/hardware/tang_nano_20k/calc_uart/hw/: FPGA calculator over serial (JSON in, JSON out) - see README
    • examples/hardware/tang_nano_20k/uart-echo/: UART loopback (UartTx + UartRx from stdlib)
    • examples/hardware/tang_nano_20k/pwm-fade/: LED fade via PwmGenerator stdlib module
    • examples/hardware/tang_nano_20k/ws2812-stdlib/: WS2812 rainbow importing Ws2812Serialiser from @ts2v/stdlib
    • examples/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 scanner
    • examples/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 README
    • examples/hardware/tang_nano_20k/tpu_uart/hw/: FPGA TPU (dot product, MAC, ReLU, reset_acc) over UART - see README
    • examples/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.

Hardware Warnings

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_demo confirmed-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 .xdc constraint files but has no synthesis flow - constraint output only until a fully self-contained OSS path exists for Xilinx 7-series.

License

MIT. See LICENSE.

Authors

See AUTHORS.md.

About

A Typescript to SystemVerilog Compiler

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors