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.
Build and program
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:
make FPGA_BOARD=ti375c529 fpga-bitstream \
EFINITY_HOME=/path/to/efinity/<version>
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:
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:
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:
make FPGA_BOARD=ti375c529 fpga-debug-openocd
In a second terminal:
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 |