328 lines
14 KiB
Markdown
328 lines
14 KiB
Markdown
# Ti375C529 Efinity flow notes
|
|
|
|
This directory contains the Efinity project for the Ti375C529 development kit.
|
|
The port keeps the same RV64 Rocket/GPS subsystem used by the Genesys2 and
|
|
VCU118 targets. Only the FPGA shell, clocks, pin constraints, programming flow,
|
|
and JTAG transport are vendor-specific. The hardened RV32 subsystem in the
|
|
Ti375 device is not used.
|
|
|
|
## What was added
|
|
|
|
- Added `ti375c529` to the root FPGA board selection and build targets.
|
|
- Added Efinity 2025.2 discovery through `EFINITY_HOME`; the current installation
|
|
is `/tools/efinix/efinity/2025.2`.
|
|
- Added a generated Ti375 wrapper around `VCU118RocketSystem` so the existing
|
|
Rocket, DTIM, UART, GPS acquisition, tracking, PPS, and SPI logic is reused.
|
|
- Added the Efinity XML project, interface script, SDC constraints, PLLs, pin
|
|
assignments, and JTAG programming target.
|
|
- Added FTDI UART operation at 460800 baud. On the current host it enumerates as
|
|
`/dev/ttyUSB2`.
|
|
- Added host OpenOCD/GDB debug through the Ti375 hard TAP and `JTAG_USER1`.
|
|
- Added Efinity-specific generated-RTL rewrites for Rocket's store-data path and
|
|
the GPS acquisition/tracking lookup tables that Efinity 2025.2 mis-elaborates.
|
|
|
|
## Clock structure
|
|
|
|
The Rocket fabric and GPS processing clocks have separate sources:
|
|
|
|
- The on-board 100 MHz oscillator drives the fabric PLL and the 100 MHz Rocket
|
|
system clock.
|
|
- AX2771 `rf_clk` enters through the dedicated global-clock input at J13 pin 10
|
|
/ package pin A12 (`GPIOR_95_CLK12`). It is the raw AFE sample clock and feeds
|
|
the GPS PLL chain. J13 pin 1 / G15 is not used for the RF clock because it is
|
|
a PLL input, not a dedicated fabric GCLK input.
|
|
- The GPS PLL chain generates 100 MHz acquisition and 125 MHz tracking clocks.
|
|
- Acquisition and tracking reset release is gated by the relevant PLL lock
|
|
signals.
|
|
|
|
The four AX2771 data bits use J13 pins 2, 3, 4, and 7, corresponding to package
|
|
pins G16, F16, F17, and G17. The AX2771 clock must be jumpered to J13 pin 10;
|
|
do not connect it to the former J13 pin 1 location.
|
|
|
|
## Efinity synthesis adaptation
|
|
|
|
This adaptation does **not** modify Rocket's native/upstream Chisel sources or
|
|
the shared GPS SystemVerilog. The normal Chisel and `firtool` stages run first
|
|
and emit SystemVerilog into `hardware/generated/ti375c529-soc-verilog/`.
|
|
Immediately afterward,
|
|
`targets/fpga/ti375c529/tools/prepare_efinity_rtl.py` patches the generated
|
|
Ti375 `Rocket.sv` and writes Efinity-only GPS replacements under
|
|
`targets/fpga/ti375c529/out/build/generated/gps_efinity/`. The Ti375 source-list
|
|
recipe substitutes those generated copies for exactly these three shared GPS
|
|
files:
|
|
|
|
- `acq_src/acq_nco_carr.sv`
|
|
- `trck_src/NCO_carr.sv`
|
|
- `acq_src/twiddle_ram.sv`
|
|
|
|
All other GPS RTL remains shared. Efinity consumes the replacements; Genesys2
|
|
and VCU118 continue to consume the original GPS files. Deleting either
|
|
generated directory and running `make FPGA_BOARD=ti375c529 fpga-rtl` repeats
|
|
the same deterministic generation and substitution.
|
|
|
|
### Rocket store-data path
|
|
|
|
The CIRCT-generated `Rocket.sv` contains this block-local packed temporary for
|
|
store-data byte-lane replication:
|
|
|
|
```systemverilog
|
|
automatic logic [3:0][63:0] _GEN_24 = ...;
|
|
mem_reg_rs2 <= _GEN_24[ex_reg_mem_size];
|
|
```
|
|
|
|
Vivado synthesizes this construct correctly. Efinity 2025.2 reports `_GEN_24`
|
|
as `VDB-1002: net does not have a driver`, leaving Rocket store data at zero.
|
|
This initially looked like a Debug Module failure because abstract GPR/CSR
|
|
reads execute a hart instruction that stores the result into Debug Module data
|
|
registers. DMI was working, but OpenOCD received zeros and reported the
|
|
misleading result `misa=0`.
|
|
|
|
`../../tools/prepare_efinity_rtl.py` replaces only that generated expression
|
|
with an equivalent explicit `case` for byte, half-word, word, and double-word
|
|
stores. The script runs automatically after `firtool`; generated RTL is not
|
|
edited by hand. After the rewrite, the Rocket `VDB-1002` warning disappears
|
|
from the current synthesis run. `ti375c529_rocket.warn.log` is reused by
|
|
Efinity and can contain entries from older runs, so the generated source and
|
|
the final warning block should be checked together.
|
|
|
|
The same Efinity limitation also affected the four-entry packed atomic-operation
|
|
LUT emitted into generated `TLAtomicAutomata_pbus.sv` and
|
|
`TLAtomicAutomata_cbus.sv`. Those `_GEN_4`/`_GEN_13` temporaries select the
|
|
TileLink atomic ALU operation; they are unrelated to GPS acquisition but could
|
|
break software atomics. The post-generation script rewrites both to an
|
|
equivalent four-way `case`. Questa confirmed all four index mappings, and their
|
|
`VDB-1002` diagnostics disappear from the current single-run `map.out`.
|
|
|
|
The exact paths are:
|
|
|
|
- Generated failing/fixed source:
|
|
`hardware/generated/ti375c529-soc-verilog/Rocket.sv`
|
|
- Generated TileLink atomic sources:
|
|
`hardware/generated/ti375c529-soc-verilog/TLAtomicAutomata_pbus.sv` and
|
|
`hardware/generated/ti375c529-soc-verilog/TLAtomicAutomata_cbus.sv`
|
|
- Efinity synthesis warning log:
|
|
`targets/fpga/ti375c529/flow/efinity/outflow/ti375c529_rocket.warn.log`
|
|
- Deterministic repair:
|
|
`targets/fpga/ti375c529/tools/prepare_efinity_rtl.py`
|
|
- Invocation point:
|
|
`targets/fpga/ti375c529/Makefile`, in the `rtl` recipe immediately after
|
|
`firtool`
|
|
|
|
### GPS lookup-table paths
|
|
|
|
The original acquisition carrier NCO is
|
|
`hardware/external/gps/rtl/acq_src/acq_nco_carr.sv`. It initializes the
|
|
frequency and pull-in arrays with whole-package-array assignments and builds
|
|
its sine table in an `initial` loop using `$sin`. Efinity 2025.2 reports the
|
|
loop variable as never assigned and the three arrays as undriven. Stand-alone
|
|
post-map comparison confirmed that this is functional, not cosmetic: the
|
|
unpatched Efinity netlist produced incorrect sine/cosine samples in all 18,040
|
|
tested production-parameter cycles.
|
|
|
|
The generated Ti375 copy replaces the frequency, pull-in, sine, and cosine
|
|
reads with constant functions generated from `definitions.sv`. Questa compared
|
|
41 frequency bins, 11 pull-in bins, and 40 cycles per combination: all 18,040
|
|
RTL samples and all 18,040 Efinity post-map samples matched the original RTL.
|
|
The current full-project synthesis no longer reports the acquisition arrays or
|
|
its `$sin` loop as undriven.
|
|
|
|
The separate tracking carrier NCO is
|
|
`hardware/external/gps/rtl/trck_src/NCO_carr.sv`. Its
|
|
`sinwav_lut = TRCK_SINWAV_LUT` package-array initializer triggers the same
|
|
Efinity `VDB-1002` behavior. The Ti375 copy uses an exact 128-entry constant
|
|
function generated from `TRCK_SINWAV_LUT`. Questa matched every table entry at
|
|
RTL and then matched 5,000 Efinity post-map cycles while visiting all 128
|
|
addresses.
|
|
|
|
The acquisition FFT twiddle source is
|
|
`hardware/external/gps/rtl/acq_src/twiddle_ram.sv`. Its whole-array
|
|
`COS_ROM_ARRAY` and `SIN_ROM_ARRAY` assignments are converted only for Ti375 to
|
|
two generated, exactly 15-bit-wide `$readmemb` files. Efinity infers 30
|
|
`EFX_RAM10` blocks with embedded INIT data. Efinity still emits its generic
|
|
`sin_rom/cos_rom does not have a driver` elaboration warning for this recognized
|
|
ROM form, but this one is demonstrably benign: Questa matched all 8,192 RTL
|
|
addresses and all 8,192 addresses in the Efinity post-map RAM netlist. Check
|
|
the current `ti375c529_rocket.map.out` for a single run; the `.warn.log` and
|
|
`.info.log` files retain records from older builds and can otherwise make fixed
|
|
source paths look current.
|
|
|
|
## JTAG and OpenOCD
|
|
|
|
Ti375 and the Xilinx boards expose the same inner Rocket DTM protocol, but the
|
|
outer FPGA TAP is different:
|
|
|
|
| Item | Xilinx flow | Ti375 flow |
|
|
|---|---|---|
|
|
| Outer TAP IR width | Xilinx-specific | 5 bits |
|
|
| User instruction | legacy USER4 handling | `JTAG_USER1 = 0x08` |
|
|
| Inner DTM IR width | 5 bits | 5 bits |
|
|
| DTMCS / DMI IR | `0x10` / `0x11` | `0x10` / `0x11` |
|
|
|
|
The host OpenOCD must therefore implement:
|
|
|
|
```text
|
|
riscv set_bscan_tunnel_ir 8
|
|
```
|
|
|
|
A fixed OpenOCD pathname is **not** required. The target Makefile evaluates
|
|
`command -v openocd`, so the first compatible binary in `PATH` is used. On the
|
|
current machine this resolves to:
|
|
|
|
```text
|
|
/home/onur/.local/bin/openocd
|
|
```
|
|
|
|
That location is only the installation choice for the patched host OpenOCD; it
|
|
is not part of the hardware flow. Another compatible build can be selected
|
|
without changing files:
|
|
|
|
```bash
|
|
make FPGA_BOARD=ti375c529 fpga-debug-openocd OPENOCD=/path/to/openocd
|
|
```
|
|
|
|
The original `/usr/local/bin/openocd` 0.12 build assumes the Xilinx USER4
|
|
instruction and asserts that the outer TAP IR is at least six bits. It cannot
|
|
drive the Ti375 5-bit TAP unchanged. `../debug/openocd-0.12-ti375-bscan.patch`
|
|
adds the configurable outer instruction to OpenOCD 0.12. The OpenOCD shipped
|
|
with Efinity is not required by this flow.
|
|
|
|
The selected paths can be checked with:
|
|
|
|
```bash
|
|
make FPGA_BOARD=ti375c529 fpga-config
|
|
command -v openocd
|
|
strings "$(command -v openocd)" | grep set_bscan_tunnel_ir
|
|
```
|
|
|
|
The line `Disabling abstract command reads/writes from CSRs` is informational,
|
|
not a failure. OpenOCD falls back to Rocket's Program Buffer for CSR access.
|
|
|
|
## GDB selection
|
|
|
|
Software is still compiled with the medany toolchain. That toolchain does not
|
|
contain GDB, so the debug target deliberately selects:
|
|
|
|
```text
|
|
/tools/toolchain/bin/riscv64-unknown-elf-gdb
|
|
```
|
|
|
|
This can also be overridden with `GDB=/path/to/riscv64-unknown-elf-gdb`.
|
|
|
|
## Build, program, and debug
|
|
|
|
From the repository root:
|
|
|
|
```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
|
|
```
|
|
|
|
Start the host OpenOCD server in one terminal:
|
|
|
|
```bash
|
|
make FPGA_BOARD=ti375c529 fpga-debug-openocd
|
|
```
|
|
|
|
Load and run an application, then monitor UART, from another terminal:
|
|
|
|
```bash
|
|
make FPGA_BOARD=ti375c529 fpga-debug-load APP=hello_uart
|
|
make FPGA_BOARD=ti375c529 fpga-uart
|
|
```
|
|
|
|
## Persistent Lower-flash boot
|
|
|
|
The kit has Lower and Upper 512-Mbit SPI NOR devices. This port intentionally
|
|
uses one MCS-like combined layout in the Lower ISSI IS25WP512 because Efinity's
|
|
command-line `jtag_bridge` mode directly addresses that flash:
|
|
|
|
| Offset | Image |
|
|
|---:|---|
|
|
| `0x00000000` | Compressed, active-x1 FPGA configuration |
|
|
| `0x00800000` | Rocket boot header followed by the application payload |
|
|
|
|
The application offset is 64-KiB-sector aligned and leaves roughly 3.2 MB
|
|
between the current 5,190,596-byte configuration and the firmware region.
|
|
`spi_low_power_mode=off` is embedded in the configuration so the Lower flash
|
|
stays available when Rocket enters user mode.
|
|
|
|
Rocket's existing MMIO SPI controller is connected to the configuration pins
|
|
after configuration completes:
|
|
|
|
```text
|
|
spi_sck/spi_csn/spi_dq_* -> A7/G6/H4/H5/G5/B7 -> Lower flash U47
|
|
```
|
|
|
|
Generate the configuration, per-application, and combined raw Efinity HEX
|
|
files:
|
|
|
|
```bash
|
|
make FPGA_BOARD=ti375c529 fpga-bitstream
|
|
make FPGA_BOARD=ti375c529 fpga-mcs APP=hello_uart
|
|
```
|
|
|
|
Outputs are:
|
|
|
|
- `out/bitstream/ti375c529_rocket.hex`: configuration region
|
|
- `out/flash/regions/app.hex`: application region
|
|
- `out/flash/ti375c529_rocket.hex`: combined image
|
|
- `out/flash/ti375c529_rocket.json`: offsets, sizes, and SHA-256 manifest
|
|
|
|
Program only the application, only the configuration, or the combined image:
|
|
|
|
```bash
|
|
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
|
|
```
|
|
|
|
The Makefile first loads Efinity's device-matched bridge
|
|
`/tools/efinix/efinity/2025.2/pgm/fli/titanium/u006A0A79.bit`, then uses
|
|
`jtag_bridge` programming with on-chip verification. A fixed Efinity install
|
|
path is not required; `FLASH_LOADER` is derived from `EFINITY_HOME` and can be
|
|
overridden.
|
|
|
|
After bridge programming, the FPGA still contains the bridge design. Power
|
|
cycle the kit for a true active-flash boot, or use `fpga-program` to load the
|
|
normal design immediately and test the BootROM/application flash path.
|
|
|
|
## On-board verification
|
|
|
|
The completed flow was checked on the connected Ti375C529 kit with AX2771
|
|
attached:
|
|
|
|
- Efinity interface, map, PNR, and programming-image stages passed.
|
|
- Final patched timing passed with WNS `+0.101 ns` and WHS `+0.021 ns`.
|
|
- The Ti375 JTAG IDCODE was read as `0x006a0a79`.
|
|
- OpenOCD found one RV64 hart and read `misa=0x800000000080112d`.
|
|
- A raw Program Buffer GPR/store test returned `0x5a` through DMI.
|
|
- `/tools/toolchain/bin/riscv64-unknown-elf-gdb` loaded 40,880 bytes into DTIM.
|
|
- `hello_uart` printed the expected Rocket/DTIM/UART messages at 460800 baud.
|
|
- The persistent image passed with setup slack `+0.094 ns` and hold slack
|
|
`+0.021 ns`.
|
|
- The Lower flash was detected as ISSI IS25WP512, JEDEC `0x9d701a`.
|
|
- The combined 8,429,552-byte HEX completed erase, write, readback, and verify.
|
|
- BootROM read the payload at `0x00800040`, verified CRC `0xed3bbdf5`, copied
|
|
40,880 bytes into DTIM, and ran `hello_uart` without GDB.
|
|
- A full board power cycle then configured Ti375 from Lower flash. Host OpenOCD
|
|
found the RV64 hart through `JTAG_USER1`; its PC was at
|
|
`0x8000017e <_exit>` after `hello_uart` returned, and GDB `compare-sections`
|
|
matched the complete ELF `.text` range in DTIM. This confirms cold boot of
|
|
both hardware and software without a volatile JTAG/GDB load.
|
|
|
|
## Relevant files
|
|
|
|
- `ti375c529_rocket.xml`: Efinity project definition.
|
|
- `ti375c529_rocket.isf`: generated/copy of the checked-in interface script.
|
|
- `../../../../../hardware/fpga/ti375c529/constraints/`: source interface and SDC
|
|
constraints.
|
|
- `../../tools/gen_ti375c529_wrapper.py`: Efinix board-shell generator.
|
|
- `../../tools/prepare_efinity_rtl.py`: deterministic Rocket and GPS
|
|
Efinity-only RTL generation/rewrite.
|
|
- `../../tools/make_flash_hex.py`: validated Efinity raw-HEX image builder.
|
|
- `../debug/openocd_ti375c529_bscan.cfg`: Ti375 hard-TAP/OpenOCD configuration.
|
|
- `../debug/openocd-0.12-ti375-bscan.patch`: host OpenOCD 0.12 compatibility
|
|
patch.
|