This post documents running Verilog on a Lattice ECP5 Versa EVB using a fully open-source toolchain. The trigger: Lattice Diamond doesn't support the LFE5UM-45F variant on my board, so proprietary tools were out.
The Clock Pin Problem
The trickiest part was finding the correct FPGA clock input pins. The board's User Manual mentions a 100 MHz LVDS oscillator connected to differential inputs P3 and P4, but this isn't spelled out in a table anywhere — it took digging through the litex-board project to confirm.
Pin Constraints (ecp5evn.lpf)
FREQUENCY PORT "clk" 100.0 MHz;
LOCATE COMP "clk" SITE "P3";
IOBUF PORT "clk" IO_TYPE=LVDS;
LOCATE COMP "rst" SITE "T1";
IOBUF PORT "rst" IO_TYPE=LVCMOS33;
LOCATE COMP "led[0]" SITE "E16";
IOBUF PORT "led[0]" IO_TYPE=LVCMOS33;
# led[1]–led[7] follow the same pattern
Simple 8-bit CPU Design
A minimal CPU to validate the full toolchain flow:
- 16-bit instruction format
- Opcodes:
LI(load immediate),ADD,OUT - 4 general-purpose registers
- Test program computes 1 + 10 and outputs the result to the LEDs
Open Source Toolchain
- Yosys — Verilog synthesis → JSON netlist
- nextpnr-ecp5 — Place & Route
- ecppack — Generate bitstream
- openFPGALoader — Flash to hardware
Makefile
VERILOG_SRC = cpu.v
LPF = ecp5evn.lpf
DEVICE = LFE5UM-45F-8BG381C
PACKAGE = BG381
synth:
yosys -p "synth_ecp5 -json cpu.json" $(VERILOG_SRC)
pnr:
nextpnr-ecp5 --device $(DEVICE) --package $(PACKAGE) \
--json cpu.json --lpf $(LPF) --textcfg cpu.config
pack:
ecppack cpu.config cpu.bit
prog:
openFPGALoader -b ecp5_evn cpu.bit
sim:
verilator --cc --trace cpu.v --exe sim_main.cpp
make -C obj_dir -f Vcpu.mk
Simulation First
Running Verilator simulation to generate VCD waveforms before flashing to hardware saves significant debugging time. Highly recommended as part of the workflow.