Skip to content

Phase 10: FPGA (ECP5) synthesis and UART wrapper - #7

Merged
deaneeth merged 2 commits into
mainfrom
feat/phase-10-fpga
Oct 26, 2026
Merged

deaneeth merged 2 commits into
mainfrom
feat/phase-10-fpga

Conversation

@deaneeth

Copy link
Copy Markdown
Member

Summary

Phase 10: the engine synthesizes for the ECP5 LFE5U-85F (the ULX3S chip) and runs behind a UART.

  • UART wrapper (fpga/ecp5/fpga_top.sv, uart.sv): CONFIG, LOAD, START and READ commands over 8N1; the reply carries the O words, cycles and byte counts.
  • Simulated over the UART (bash sim/run_fpga.sh): FLASH causal and non-causal, and NAIVE. O is bit-exact against the golden model, and the cycle and byte counts match the models.
  • Synthesis (bash fpga/ecp5/synth.sh, YoWASP Yosys and nextpnr): no latches, check -assert passes. 40,416 of 83,640 LUT4 positions, 8,726 flip-flops, 51 of 156 DSP blocks, no block RAM. fmax estimate 11.5 MHz, so timing is not closed at the 25 MHz board clock. No pin constraints.
  • CI: fpga.yml runs the flow and writes the numbers to the job summary.
  • RTL changes for Yosys (no behaviour change): packed LUT tables, file-scope package imports, local LUT copies before indexing, explicit sign extension in exp2_unit, and a split async reset in perf_counters. The unit suites, the 200-seed end-to-end sweep and the golden tests were rerun on them.
  • Sim runners set CFG_CXXFLAGS_PCH_I=-include, because the installed Verilator leaves it empty and some models fail to link. See ARCHITECTURE section 15.

Verification

  • bash sim/run_unit.sh: all suites passed.
  • SEEDS=200 bash sim/run_e2e.sh: 3/3 passed.
  • bash sim/run_fpga.sh: 1/1 passed.
  • pytest sim/golden: passed.
  • bash wasm/build.sh && node wasm/test.mjs: passed (the committed tiny_attn.wasm is rebuilt from this RTL).
  • bash sim/lint.sh: clean.
  • Web: pnpm lint, pnpm typecheck, pnpm build, pnpm test:e2e (35): passed.

Not done

  • ULX3S pin constraints, a board run, timing closure at 25 MHz, and block RAM for the memories (the memories have combinational reads, so they map to LUT RAM).

- fpga/ecp5: fpga_top (the engine behind an 8N1 UART: CONFIG, LOAD, START, READ) and uart.sv.
  Simulated over the UART end to end (sim/run_fpga.sh): O bit-exact, DONE cycles and bytes equal the models.
- synth.sh: Yosys synth_ecp5 with a latch assertion, then nextpnr-ecp5 (LFE5U-85F) for utilization and fmax.
  Result: 40,416 of 83,640 LUT4, 8,726 FF, 51 of 156 DSP, 0 BRAM; fmax estimate 11.5 MHz (target 25 MHz, not closed).
- fpga.yml runs the flow in CI and writes the numbers to the job summary.
- RTL changes for Yosys (no behaviour change; unit, e2e 200 seeds and golden tests rerun):
  packed LUT tables (generator updated), file-scope package imports, local copies of the LUTs before indexing,
  explicit sign extension in exp2_unit, and a split async reset in perf_counters.
- Sim runners set CFG_CXXFLAGS_PCH_I=-include (the installed Verilator leaves it empty; see ARCHITECTURE section 15).
- WASM engine rebuilt from the new RTL; Node test passes.
- Docs: ARCHITECTURE section 15, README FPGA row, verification page, PLAN and CONTEXT.

Not done: ULX3S pin constraints, a board run, timing closure at 25 MHz, block RAM for the memories.
The .gitignore excluded it (only setup.sh and emsdk.sh were allowed), so the ecp5 job failed with 'No such file'.
@deaneeth
deaneeth merged commit 050bdfb into main Oct 26, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant