A browser-based emulator for iCE40 FPGAs. Write Verilog, synthesize with Yosys, and watch it run on a virtual board — no install, no server, no toolchain.
Live demo: https://senolgulgonul.github.io/softfpga/
softfpga compiles real Verilog to an iCE40 logic netlist and simulates it cycle-by-cycle in your browser. Synthesis is done by Yosys (compiled to WebAssembly); simulation is a small LUT/flip-flop engine. The result is wired to a fixed virtual board with LEDs, a hex display, and switches.
- Verilog mode — real Verilog, synthesized in-browser by Yosys WASM
- JSON mode — hand-written LUT/FF netlists for instant simulation, zero dependencies
- iCE40UP5K model — LUT4 + D-flip-flop fabric, up to 5,280 LUTs
- Virtual FPGA board — a fixed board with 8 LEDs, a 2-digit hex display, and 8 switches
- Open / save — load and save Verilog files from your local disk
- Netlist dump — export the Yosys netlist and the converted netlist for inspection
A real FPGA needs a constraint file (a .pcf) that maps each top-level
signal to a physical pin. softfpga removes that step entirely. Instead, the
board is fixed, and you connect to its peripherals simply by naming your
Verilog ports with reserved names. The port name is the pin assignment.
| Verilog port | Connects to | Notes |
|---|---|---|
input clk |
the clock | advances one tick per simulated cycle |
input [7:0] sw |
8 toggle switches | click a switch in the UI to set its bit |
output [7:0] led |
8 LEDs | bit 0 = led[0], shown rightmost |
output [7:0] hex |
2-digit hex display | shows the 8-bit value as two hex digits |
Rules:
- Names are matched by prefix: any output beginning with
leddrives LEDs, any beginning withhexdrives the hex display, any input beginning withswbecomes switches. - The hex display is driven only by a
hexport. A design with nohexoutput leaves the display blank — there is no fallback to the LED value. - LEDs are shown MSB-left, LSB-right, so the row reads like a binary number.
- An output port that isn't recognized as
hexdefaults to driving LEDs.
This is why no place & route is needed. A normal FPGA flow is synthesis → place & route → bitstream, where place & route assigns physical locations and pins. softfpga does real synthesis but replaces place & route with the naming convention above. You trade physical realism (signal timing, pin locations, routing) for a zero-configuration experience — the right trade-off for learning and experimenting with digital logic.
All actions live in the toolbar across the top of the window.
- Make sure the Verilog mode button (top-right) is selected.
- Click 📁 Examples and pick a design (counter, blink, shift, pwm, adder), or write your own in the editor.
- Press ⚡ Synthesize. On first use this downloads Yosys WASM (~8 MB from a CDN, cached afterwards), then synthesizes your design. The console below the editor reports the LUT / flip-flop / IO counts.
- Press ▶ Run to start the clock, or ⏭ Step to advance one cycle at a time. ↺ Reset clears all flip-flops back to zero.
- Use the clock speed dropdown to slow fast designs down enough to watch.
- For designs with switches, click the switch toggles on the board to set input bits, then Run or Step to see the effect.
The typical loop is just Synthesize → Run. Edit, Synthesize again, Run again.
The window has three areas: the Verilog editor with a console on the left, the virtual FPGA board in the middle (always visible — LEDs on top, hex display, switches below), and an Information panel on the right showing the device and resource usage. The ❓ Help button opens this documentation.
The toolbar's file buttons let you work with Verilog files on your own disk:
- 📂 Open — load a Verilog (
.v,.sv,.vh) or netlist (.json) file into the editor. The mode switches automatically to match the file type. - 💾 Save — write the editor contents back to a file. Edit the filename in
the field next to the editor title first to choose the name. On Chromium
browsers (Chrome, Edge) served over
https/localhost, this opens a native Save As dialog; elsewhere it downloads the file to your download folder.
Everything is fully client-side — no upload, no server. The Save extension is
corrected automatically to .v or .json to match the current mode.
// An 8-bit counter shown on the LEDs and the hex display
module top (
input clk,
output [7:0] led,
output [7:0] hex
);
reg [7:0] count = 0;
always @(posedge clk)
count <= count + 1;
assign led = count;
assign hex = count;
endmoduleThe top module must be named top. Declare only the reserved ports you need.
Keep designs synchronous (always @(posedge clk)) — that is what the
flip-flop-based simulation models.
| Example | Demonstrates |
|---|---|
| counter | An 8-bit synchronous counter on LEDs and hex |
| blink | A single flip-flop toggling every clock |
| shift | An 8-bit shift register; sw[0] is the serial input |
| pwm | A PWM generator; sw[0] selects the duty cycle |
| adder | A 4-bit adder: sw[3:0] + sw[7:4], result on LEDs and hex |
| switches | Switch passthrough: sw drives the LEDs and hex directly |
| gates | Primitives — a half adder from xor / and gates |
| fulladder | Hierarchical modeling — a full adder from two half adders |
| dataflow | Dataflow modeling — continuous assignment, bitwise operators |
| fsm | Behavioral modeling — an up/down counter (sw[0] sets direction) |
Verilog source
│
▼ Yosys WASM (@yowasp/yosys, runs in the browser)
│ synth_ice40 -nocarry -flatten -json → Yosys netlist JSON
│
▼ yosysJsonToNetlist()
│ maps SB_LUT4 and SB_DFF cells; resolves nets; tags IO by reserved name
│
▼ ICE40Emu.tick() — once per clock cycle:
1. settle all combinational logic (LUT truth tables)
2. sample every flip-flop's D input, then apply the clock edge
3. read the IO nets and update LEDs / hex display
The whole simulation core is a LUT4 evaluator and a flip-flop update. A LUT4 is a 16-bit truth table indexed by its four inputs:
evalLUT(lut) {
let addr = 0;
for (let i = 0; i < 4; i++)
addr |= this.rd(lut.inputs[i]) << i; // I0 = LSB, I3 = MSB
return (lut.truth_table >> addr) & 1;
}synth_ice40 is run with -nocarry so adders map onto plain LUTs, which keeps
the simulation engine simple.
softfpga/
├── index.html ← the entire app: HTML, CSS, JS in one file, no build step
├── README.md
├── _headers ← Cross-origin headers (Cloudflare Pages)
├── netlify.toml ← Cross-origin headers (Netlify)
└── vercel.json ← Cross-origin headers (Vercel)
index.html is fully self-contained. The only external dependency is the
Yosys WASM module, loaded from a CDN on first compile in Verilog mode.
JSON mode is fully offline.
git clone https://github.com/senolgulgonul/softfpga
cd softfpga
# edit files, then:
git add . && git commit -m "update" && git push
# Settings → Pages → Source: main / root → SaveThe repo includes _headers, netlify.toml, and vercel.json which set the
Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers used
for optimal Yosys WASM performance. Connect the repo, set the output directory
to . with no build command, and deploy.
softfpga models the chip's logic fabric faithfully (real LUT4s, real flip-flops, real Yosys synthesis), but the board peripherals are a fixed simplification. A real iCE40UP5K has 39 general-purpose IO pins and no built-in LEDs or displays — what those pins connect to depends on the physical board. softfpga instead provides one fixed board (8 LEDs, hex display, 8 switches) addressed by reserved names.
Not modeled: signal timing and propagation delay, place & route, block RAM, DSP/multiplier blocks, the hardened RGB LED driver, PLLs, and bitstream generation. For a tool aimed at learning logic design, none of these are needed — the logic itself runs correctly.
- JSON netlist emulation
- Yosys WASM Verilog synthesis
- LUT4 + D-flip-flop fabric (up to 5280 LUTs)
- Fixed virtual board: 8 LEDs, hex display, 8 switches
- Reserved-name IO model (no constraint file needed)
- Netlist dump for inspection
- Open / save .v files from local disk
- Gowin-style light theme UI with a virtual FPGA board
- Clock prescaler for visually slowing fast designs
- Block RAM emulation
- UART terminal peripheral
- Waveform (VCD) export
If you use softfpga in academic work, teaching material, or a publication, please cite it. Update the year and URL as appropriate.
Plain text:
Gülgönül, S. (2026). softfpga: A browser-based iCE40 FPGA emulator. https://github.com/senolgulgonul/softfpga
BibTeX:
@software{softfpga,
author = {G\"ulg\"on\"ul, \c{S}enol},
title = {softfpga: A browser-based iCE40 FPGA emulator},
year = {2026},
url = {https://github.com/senolgulgonul/softfpga},
version = {1.29}
}softfpga uses Yosys for synthesis, via the YoWASP WebAssembly build. Yosys is developed by Claire Xenia Wolf and the YosysHQ team.
MIT