# Ti375C529 Rocket FPGA flow This target keeps the project's RV64 Rocket/GPS subsystem in FPGA fabric and replaces only the Xilinx board shell and build flow with Efinix equivalents. It does not use the Ti375 hardened RV32 subsystem. Detailed porting, synthesis, clocking, JTAG, and verification notes are in [`flow/efinity/README.md`](flow/efinity/README.md). ## Build and program ```bash make FPGA_BOARD=ti375c529 fpga-config make FPGA_BOARD=ti375c529 fpga-rtl make FPGA_BOARD=ti375c529 fpga-bitstream make FPGA_BOARD=ti375c529 fpga-program ``` The Makefile auto-discovers versioned Efinity installations under `/tools/efinix/efinity`, `/tools/Efinix/efinity`, `/opt`, the current user's home directory, and `tools/local/efinity`. Override discovery when required: ```bash make FPGA_BOARD=ti375c529 fpga-bitstream \ EFINITY_HOME=/path/to/efinity/ ``` `fpga-rtl` does not require Efinity. The `interface`, `bitstream`, and programming targets require a complete Efinity installation containing `bin/setup.sh` and `scripts/efx_run.py`; they now stop before hardware elaboration with a direct diagnostic when it is absent. Concurrent Ti375 `map` or `bitstream` invocations are rejected because they share generated FIRRTL, SystemVerilog, and Efinity work directories. Efinity is run with unbuffered Python output so `map`, `pnr`, and `pgm` progress remains visible in the terminal and `out/logs/full.log`. Programming auto-selects the connected Ti375 development kit. If more than one compatible FTDI device is attached, run `make FPGA_BOARD=ti375c529 fpga-detect` to list the bus-qualified URLs and pass the selected one as `FTDI_URL=...`. Volatile JTAG programming and GDB loading into Rocket DTIM remain available. Persistent boot uses the board's Lower 512-Mbit SPI flash with this map: | Region | Flash offset | Contents | |---|---:|---| | FPGA configuration | `0x00000000` | Efinity active-mode configuration HEX | | Rocket application | `0x00800000` | Boot header and ELF-derived payload | | Navigation context | `0x03FC0000` | Two 64-KiB journal sectors | | Ephemeris cache | `0x03FE0000` | Two 64-KiB journal sectors | The application starts at 8 MiB because the compressed Ti375 configuration is currently about 5.19 MB; the previous 4 MiB trial offset would overlap it. Generate or program the Efinity raw HEX images with: ```bash make FPGA_BOARD=ti375c529 fpga-mcs APP=hello_uart make FPGA_BOARD=ti375c529 fpga-flash-app APP=hello_uart make FPGA_BOARD=ti375c529 fpga-flash-bitstream make FPGA_BOARD=ti375c529 fpga-flash-mcs APP=hello_uart ``` `fpga-mcs` is the repository-wide compatibility target name. For this Efinix board it produces `.hex`, not Xilinx `.mcs`. `fpga-flash-app` changes only the application region; `fpga-flash-mcs` erases/programs configuration plus the application through Efinity's pre-built JTAG-to-SPI bridge and verifies the readback. Cold boot from this layout was verified by a complete board power cycle: Ti375 configured from flash and Rocket loaded and completed `hello_uart` from the application region without a JTAG/GDB load. ## Debug and load Use the host OpenOCD build, not the OpenOCD shipped with Efinity. The build must include `riscv set_bscan_tunnel_ir`; Ti375 uses a 5-bit outer TAP and selects `JTAG_USER1` with instruction `0x08`. OpenOCD 0.12 can be given that upstream-compatible command with `flow/debug/openocd-0.12-ti375-bscan.patch`. Apply it from a clean OpenOCD 0.12 source tree before configuring and building the host tool: ```bash git apply --check /path/to/gps/targets/fpga/ti375c529/flow/debug/openocd-0.12-ti375-bscan.patch git apply /path/to/gps/targets/fpga/ti375c529/flow/debug/openocd-0.12-ti375-bscan.patch ``` Place the resulting `openocd` in `PATH`, or pass its absolute path with `OPENOCD=/path/to/openocd`. In one terminal: ```bash make FPGA_BOARD=ti375c529 fpga-debug-openocd ``` In a second terminal: ```bash make FPGA_BOARD=ti375c529 fpga-debug-load APP=hello_uart make FPGA_BOARD=ti375c529 fpga-uart ``` The target deliberately selects `/tools/toolchain/bin/riscv64-unknown-elf-gdb` when it exists. The medany compiler toolchain is still used to build software, but it is not expected to contain GDB. Efinity 2025.2 leaves Rocket's block-local packed store-data array undriven (`VDB-1002`). `tools/prepare_efinity_rtl.py` rewrites that generated RTL expression as an equivalent explicit `case`. Without the rewrite, DMI itself works, but GPR/CSR values stored into Debug Module data registers read as zero; OpenOCD consequently reports a misleading `misa=0`. The patch is deliberately post-generation: Chisel and `firtool` first emit the Ti375 SystemVerilog tree, then `prepare_efinity_rtl.py` modifies only the generated Ti375 `Rocket.sv` before Efinity synthesis. It does not edit Rocket's native/upstream Chisel sources. Two equivalent four-entry packed temporaries in the generated pbus/cbus `TLAtomicAutomata` modules are rewritten for the same reason, preserving the four atomic-operation mappings while removing their `VDB-1002` risk. The same script generates Ti375-only copies of the acquisition carrier NCO, tracking carrier NCO, and FFT twiddle ROM under `out/build/generated/gps_efinity/`. This avoids Efinity 2025.2 whole-array/`initial`/`$sin` elaboration failures without editing the shared GPS RTL. Only the Ti375 source list selects these copies; Genesys2 and VCU118 still use the originals. Detailed source paths, warning interpretation, and Questa RTL/post-map equivalence results are in the Efinity flow notes. The affected generated source is `hardware/generated/ti375c529-soc-verilog/Rocket.sv`; Efinity records the original diagnostic in `targets/fpga/ti375c529/flow/efinity/outflow/ti375c529_rocket.warn.log`. The checked-in repair is `targets/fpga/ti375c529/tools/prepare_efinity_rtl.py` and runs after every `firtool` invocation, before Efinity synthesis. ## Board connections PMOD0/J13 carries the GPS RF sampler: | Signal | PMOD pin | FPGA resource | Package pin | |---|---:|---|---| | `rf_clk` | 10 | GPIOR_95_CLK12 | A12 | | `rf_data[0]` | 2 | GPIOR_89 | G16 | | `rf_data[1]` | 3 | GPIOR_90 | F16 | | `rf_data[2]` | 4 | GPIOR_91 | F17 | | `rf_data[3]` | 7 | GPIOR_92 | G17 | | `max2771_spi_sclk` | 1 | GPIOR_88_PLLIN1 | G15 | | `max2771_spi_csn` | 8 | GPIOR_93_PLLIN1 | A11 | | `max2771_spi_sdata` | 9 | GPIOR_94 | A13 | `rf_clk` must be wired to J13 pin 10. Pin 10 is the PMOD0 header's dedicated 3.3 V global-clock input. J13 pin 1 is used as the MAX2771 serial clock output; using it as the raw AFE clock would make Efinity promote normal GPIO routing into a GBUF and issue an extra-clock-insertion-delay warning. As on Genesys2 and VCU118, the AX2771 clock is both the raw AFE sample clock and the source of the GPS processing-clock chain. Two Titanium PLLs generate an intermediate 55.5556 MHz clock, then 100 MHz acquisition and 125 MHz tracking clocks. The Rocket fabric uses the independent on-board 100 MHz oscillator. PMOD1/J14 carries the sensor SPI, interrupt, and PPS: | Signal | PMOD pin | FPGA resource | Package pin | |---|---:|---|---| | `pmod_spi_csn` | 1 | GPIOR_96_CLK13 | B12 | | `pmod_spi_dq[0]` | 2 | GPIOR_97 | C14 | | `pmod_spi_dq[1]` | 3 | GPIOR_98 | C13 | | `pmod_spi_sck` | 4 | GPIOR_99 | C12 | | `pmod_spi_dq[2]` | 7 | GPIOR_100 | D12 | | `pmod_spi_dq[3]` | 8 | GPIOR_101_PLLIN1 | F12 | | `pmod_irq` | 9 | GPIOR_102 | D13 | | `gps_pps` | 10 | GPIOR_103 | E13 | The FTDI UART is `/dev/ttyUSB2` on the current Linux enumeration. SW3 is the active-low Rocket reset. JTAG uses Efinix `JTAG_USER1` and the existing Rocket DMI tunnel protocol. The Lower flash user-mode connection is internal to the development kit: | Signal | FPGA resource | Package pin | |---|---|---| | `flash_csn` | GPIOB_N_38 / SSL_N | A7 | | `flash_sck` | GPIOB_P_39 / CCK | G6 | | `flash_dq[0]` | GPIOB_N_40 / CDI0 | H4 | | `flash_dq[1]` | GPIOB_P_40 / CDI1 | H5 | | `flash_dq[2]` | GPIOB_N_39 / CDI2 | G5 | | `flash_dq[3]` | GPIOB_P_38 / CDI3 | B7 |