RTL Bench PRO

WebSerial FPGA Flasher: From RTL to Physical Silicon

Deploying hardware to an FPGA usually demands gigabytes of vendor software, proprietary cable drivers, and complex project managers. This guide breaks down the open-source physical synthesis pipeline (Yosys + nextpnr) and how the browser WebSerial API programs development boards directly over USB.

1. The open-source FPGA toolchain pipeline

Building a bitstream transforms behavioral Verilog code into physical configuration bits that configure Look-Up Tables (LUTs), flip-flops, Block RAMs (BRAM), and routing multiplexers. RTL Bench automates this entire four-stage pipeline in cloud build runners:

  • 1. Logic Synthesis (Yosys): Maps high-level language constructs into target FPGA primitive cells (e.g., synth_gowin for GW1N/GW2A architectures, or synth_ice40 for Lattice iCE40).
  • 2. Physical Place & Route (nextpnr): Places logic cells onto the FPGA die grid and routes interconnection wires while meeting timing constraints. Uses nextpnr-himbaechel for Gowin and nextpnr-ice40 for Lattice.
  • 3. Bitstream Packing: Takes the completed routing database (JSON or ASC) and generates the exact binary layout (output.bin) expected by the FPGA's configuration state machine (via gowin_pack or icepack).
  • 4. Telemetry Extraction: Extracts hardware resource consumption (LUTs, registers, BRAMs) and achieved maximum operating frequency ($F_{max}$) directly from the layout log.
๐Ÿ’ก Split Build & Flash Workflow: In RTL Bench, โš™ Synthesize Bitstream compiles the toolchain and caches the binary in memory. Once built, you can flash the board or download the .bin file instantly without re-running synthesis. If you modify the top module or I/O standards, the cache automatically invalidates.

2. Supported hardware targets & specifications

RTL Bench supports three primary open-source development targets, each backed by native architecture definitions, default onboard clock pins, and I/O banks:

Board FPGA Part Logic Resources Memory & DSP Default Clock
Tang Nano 9K Gowin GW1NR-LV9QN88PC6/I5 8,640 LUT4, 6,480 FF 468 Kbits BRAM, 2 Multipliers 27 MHz (Pin 52)
Tang Nano 20K Gowin GW2AR-LV18QN88C8/I7 20,736 LUT4, 15,552 FF 828 Kbits BRAM, 48 Multipliers 27 MHz (Pin 52)
iCE40UP5K Lattice iCE40UP5K-SG48 5,280 LUT4, 5,280 FF 120 Kb BRAM + 1 Mb SPRAM, 8 DSP 12 MHz (Pin 35)

3. Pin constraints: CST vs. PCF

Because an FPGA's pins can be wired to buttons, LEDs, HDMI transmitters, or external headers, the Place & Route engine requires a physical constraint file mapping module ports to package pin numbers:

  • Gowin Physical Constraints (pins.cst): Uses IO_LOC "port" pin; syntax with optional IO_TYPE and PULL_MODE rules.
  • Lattice Pin Constraints (pins.pcf): Uses set_io [-pullup yes] port pin syntax.

Synthesizable example: Clock divider & LED blinker

This Verilog module divides a 27 MHz clock down to blink an onboard LED once per second:

module led_blinker (
  input  wire clk,   // Tang Nano 9K/20K: Pin 52 (27 MHz)
  input  wire rst_n, // Tang Nano Button S1: Pin 3 (active-low)
  output reg  led    // Tang Nano Onboard LED 0: Pin 10 (active-low)
);
  reg [24:0] counter;

  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      counter <= 25'd0;
      led     <= 1'b1; // LED off
    end else begin
      if (counter >= 25'd13_500_000) begin
        counter <= 25'd0;
        led     <= ~led; // Toggle state
      end else begin
        counter <= counter + 1'b1;
      end
    end
  end
endmodule
โš ๏ธ Hardware Pin Protection: Development boards dedicate specific pins to JTAG lines, internal Flash SPI communication, and power rails. RTL Bench enforces an automated filter that detects and blocks dangerous pin assignments (such as JTAG TMS/TCK pins 25, 26, 27, 28) to prevent bricking your hardware.

4. How WebSerial transfers bitstreams

Historically, browser sandboxes were isolated from external hardware. The WebSerial API allows web applications running on Chromium browsers (Chrome, Edge, Opera) to read from and write to physical serial ports:

  1. User Gesture Prompt: Clicking โšก Flash to FPGA triggers navigator.serial.requestPort(), prompting you to select the board's USB-to-UART bridge from a system dialog.
  2. Opening Serial Stream: The port opens at the target baud rate (typically 115,200 baud for MCU programming bridges).
  3. Direct Stream Writing: An activeSerialWriter streams the packed binary array (Uint8Array) directly to the on-board USB interface controller (such as a CH552 or FT2232 chip).
  4. SRAM Configuration: The on-board controller decodes the incoming stream and drives JTAG TDI/TCK signals into the FPGA's configuration core, switching the chip into user logic mode immediately.
  5. Integrated UART Console: Once flashing finishes, RTL Bench automatically binds an asynchronous TextDecoderStream to the open port, giving you a live serial monitor to interact with soft-core CPUs or custom UART interfaces in real time!

Frequently asked questions

How does WebSerial program an FPGA from a web browser?

The WebSerial API lets modern web browsers connect directly to local USB COM ports. The browser sends compiled bitstream binaries straight to the FPGA board's on-board USB-JTAG bridge without installing vendor software suites.

Which FPGA boards can be flashed directly in the browser?

RTL Bench supports open-source development boards including the Sipeed Tang Nano 9K (Gowin GW1NR-9C), Tang Nano 20K (Gowin GW2AR-18C), and Lattice iCE40 UltraPlus (iCE40UP5K-SG48).

What happens if nextpnr fails place and route?

If your logic exceeds device LUT capacities, fails timing constraints, or assigns an invalid pin, the build runner halts with the exact line number and netlist error from nextpnr. Pin issues trigger automatic safe-pin retries where available.

Next

Go to FPGA workspace โ†’