diff --git a/.gitignore b/.gitignore index 4e26477..dd7f575 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ # Generated build outputs. /out/ /soc/out/ +/hardware/generated/ /soc/software/*/build/ /soc/software/gps_system/tests/test_* !/soc/software/gps_system/tests/test_*.c @@ -21,6 +22,7 @@ clockInfo.txt /targets/fpga/*/out/logs/ /targets/fpga/*/out/reports/ /targets/fpga/*/out/build/checkpoints/ +/targets/fpga/vcu118/out/ # Python runtime caches and privacy-sensitive raw board captures. __pycache__/ diff --git a/Makefile b/Makefile index c8c3d0d..20284e5 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,8 @@ FPGA_BOARD ?= vcu118 endif FPGA_TARGET_DIR := targets/fpga/$(FPGA_BOARD) -.PHONY: help doctor soc-hw fpga-rtl fpga-bitstream fpga-elf-flash-image fpga-mcs fpga-flash-app fpga-flash fpga-flash-bitstream fpga-flash-mcs fpga-flash-all fpga-program fpga-debug-openocd fpga-debug-load fpga-uart fpga-config asic-rtl asic-sim clean -.PHONY: fpga_rtl fpga_bitstream fpga_elf_flash_image fpga_mcs fpga_flash_app fpga_flash fpga_flash_bitstream fpga_flash_mcs fpga_flash_all fpga_program fpga_debug_openocd fpga_debug_load fpga_uart fpga_config +.PHONY: help doctor soc-hw fpga-rtl fpga-bitstream fpga-elf-flash-image fpga-mcs fpga-flash-app fpga-flash fpga-flash-bitstream fpga-flash-mcs fpga-flash-all fpga-program fpga-detect fpga-debug-openocd fpga-debug-load fpga-uart fpga-config asic-rtl asic-sim clean +.PHONY: fpga_rtl fpga_bitstream fpga_elf_flash_image fpga_mcs fpga_flash_app fpga_flash fpga_flash_bitstream fpga_flash_mcs fpga_flash_all fpga_program fpga_detect fpga_debug_openocd fpga_debug_load fpga_uart fpga_config help: @printf '%s\n' \ @@ -19,11 +19,12 @@ help: ' make doctor # check local JDK/Mill/CIRCT and RISC-V tools' \ ' make soc-hw # emit shared SoC FIRRTL through FPGA config' \ ' make fpga-rtl # emit selected FPGA SystemVerilog and wrapper' \ - ' make fpga-bitstream # run selected FPGA Vivado bitstream flow' \ + ' make fpga-bitstream # run selected board vendor bitstream flow' \ ' make fpga-elf-flash-image' \ ' # build APP ELF and board flash-format app image' \ ' make fpga-mcs # generate combined bitstream + app MCS/BIN' \ ' make fpga-program # program selected FPGA SRAM' \ + ' make fpga-detect # run selected board USB/JTAG detection target' \ ' make fpga-flash-app # build flash-format app image and program app flash region' \ ' make fpga-flash # alias for fpga-flash-app' \ ' make fpga-flash-bitstream' \ @@ -39,7 +40,7 @@ help: ' make asic-sim # run ASIC-style Questa sanity simulation' \ '' \ 'Config:' \ - ' FPGA_BOARD=$(FPGA_BOARD) # vcu118 or genesys2' \ + ' FPGA_BOARD=$(FPGA_BOARD) # vcu118, genesys2, or ti375c529' \ ' UART_BAUD=460800 # FPGA firmware and host listener default' \ ' GPS_ESKF_ENABLE=1 # gps_system: 1 ESKF, 0 GPS-only' \ ' IMU_SENSOR=auto # gps_system: auto, tdk, st or stm' \ @@ -49,6 +50,7 @@ help: ' make -C hardware/soc help' \ ' make -C targets/fpga/vcu118 help' \ ' make -C targets/fpga/genesys2 help' \ + ' make -C targets/fpga/ti375c529 help' \ ' make -C targets/asic/rocket help' doctor: @@ -72,6 +74,9 @@ fpga-mcs: fpga-program: $(MAKE) -C $(FPGA_TARGET_DIR) program-fpga +fpga-detect: + $(MAKE) -C $(FPGA_TARGET_DIR) detect + fpga-flash-app fpga-flash: $(MAKE) -C $(FPGA_TARGET_DIR) program-flash @@ -106,6 +111,7 @@ fpga_flash_bitstream: fpga-flash-bitstream fpga_flash_mcs: fpga-flash-mcs fpga_flash_all: fpga-flash-all fpga_program: fpga-program +fpga_detect: fpga-detect fpga_debug_openocd: fpga-debug-openocd fpga_debug_load: fpga-debug-load fpga_uart: fpga-uart diff --git a/README.md b/README.md index d4d22df..a1f5b02 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Rocket Project -Bu agac VCU118/Genesys2 FPGA ve ASIC-style Rocket akislari icin sade proje duzenidir. +Bu agac VCU118, Genesys2 ve Ti375C529 FPGA akislari ile ASIC-style Rocket +akisi icin sade proje duzenidir. Upstream Rocket-Chip kaynaklari daginik kok klasorlerde tutulmaz; gerekli upstream kaynaklar `hardware/upstream/rocket-chip/` altindadir. @@ -22,6 +23,7 @@ hardware/ soc/software/ Bootloader, BSP, uygulamalar, flash image tool targets/fpga/vcu118/ VCU118 build/programlama akisi targets/fpga/genesys2/ Genesys2 build/programlama akisi +targets/fpga/ti375c529/ Ti375C529 Efinity build/programlama akisi targets/asic/rocket/ ASIC wrapper/filelist/sim akisi setup_tools.sh /tools/soc-tools host araci kurulum betigi ``` @@ -209,6 +211,7 @@ make -C hardware/fpga/vcu118/rtl help make -C hardware/sim/fpga/vcu118 help make -C targets/fpga/vcu118 help make -C targets/fpga/genesys2 help +make -C targets/fpga/ti375c529 help make -C targets/asic/rocket help ``` @@ -219,6 +222,7 @@ FPGA karti kok Makefile'dan `FPGA_BOARD` ile secilir: ```sh make FPGA_BOARD=vcu118 fpga-config make FPGA_BOARD=genesys2 fpga-config +make FPGA_BOARD=ti375c529 fpga-config ``` Top-level `BOARD=...` alias'i da desteklenir. Orneklerde Genesys2 kullanilir: @@ -232,7 +236,7 @@ Yanlislikla underscore kullanilmasi durumunda yaygin FPGA hedefleri icin alias'lar da vardir (`fpga_program`, `fpga_debug_openocd` gibi). `fpga-config` secilen kartin clock, flash, UART, DTIM ve RF ayarlarini -gosterir. RF kaynagi `RF_INPUT_MODE` ile secilir: +gosterir. Genesys2 ve VCU118'de RF kaynagi `RF_INPUT_MODE` ile secilir: ```text RF_INPUT_MODE=pmod Varsayilan. Harici 4-bit RF data + RF clock PMOD'dan gelir. @@ -270,10 +274,19 @@ VCU118 icin ayrilan bos PMOD0/J52 pinleri: VCU118'in U41 level shifter'i PMOD header tarafini 3.3 V'a cevirir. Mevcut standart PMOD SPI pinleri degistirilmemistir: +Ti375C529, PMOD0/J13'te RF veri ve saatinden arta kalan uc pini kullanir: + +| MAX2771 sinyali | FPGA yonu | Ti375C529 PMOD | FPGA pini | Elektrik standardi | +|---|---|---|---|---| +| `SCLK` | cikis | `J13.1` | `G15` | 3.3_V_LVCMOS | +| `CSN` | cikis | `J13.8` | `A11` | 3.3_V_LVCMOS | +| `SDATA` | yazmada cikis, okumada giris | `J13.9` | `A13` | 3.3_V_LVCMOS | + | Kart | Standart PMOD SPI CSN/MOSI/MISO/SCLK | MAX2771 CSN/SDATA/SCLK | |---|---|---| | Genesys2 | `JC1/JC2/JC3/JC4` | `JB3/JB4/JB2` | | VCU118 | `J53.1/J53.3/J53.5/J53.7` | `J52.6/J52.8/J52.4` | +| Ti375C529 | `J14.1/J14.2/J14.3/J14.4` | `J13.8/J13.9/J13.1` | MAX2771 register varsayilanlarini yazip tek-hat `SDATA` uzerinden geri okuyarak dogrulayan bare-metal uygulama: @@ -286,10 +299,14 @@ Test MAX2771 register `0x0`-`0xA` icerigini veri sayfasindaki degerlerle degistirir. EVKIT uzerindeki MAX32625 kontrolcusunun seri hatlari test boyunca high-Z olmali ve EVKIT GUI ayni anda kullanilmamalidir. +Ti375C529 Efinity wrapper'i su anda yalniz harici PMOD RF girisini kullanir; +bu kartta `RF_INPUT_MODE=pmod` birakilmalidir. `generated` ve `ethernet` +yollari Ti375C529 wrapper'ina henuz uygulanmamistir. + Top-level FPGA wrapper'lar elle yazilmaz; `targets/fpga/*/tools/gen_*_wrapper.py` -scriptleri tarafindan uretilir. Bu yuzden RF secimi RTL `ifdef` ile degil, -generator parametresi ile yapilir. `make rtl` ve Vivado `build.tcl` ayni -`RF_INPUT_MODE` degerini wrapper generator'a gecirir. +scriptleri tarafindan uretilir. Genesys2 ve VCU118'de RF secimi RTL `ifdef` +ile degil, generator parametresi ile yapilir. `make rtl` ve Vivado `build.tcl` +ayni `RF_INPUT_MODE` degerini wrapper generator'a gecirir. Varsayilan `pmod` modunda Ethernet RF IP/RTL okunmaz ve top'ta Ethernet PHY portlari olusmaz. Ethernet RF akisi gerektiginde: @@ -321,11 +338,23 @@ uzerinden 1.8 V bank/LVCMOS18: rf_data_pmod[1] AW15 PMOD0_2 J52.5 LVCMOS18 3.3 V rf_data_pmod[2] AV15 PMOD0_3 J52.7 LVCMOS18 3.3 V rf_data_pmod[3] AV16 PMOD0_4 J52.2 LVCMOS18 3.3 V + +Ti375C529 PMOD0/J13, connector ve FPGA tarafi 3.3 V: + port FPGA pin PMOD pin FPGA resource FPGA I/O + rf_clk A12 J13.10 GPIOR_95_CLK12 3.3_V_LVCMOS + rf_data[0] G16 J13.2 GPIOR_89 3.3_V_LVCMOS + rf_data[1] F16 J13.3 GPIOR_90 3.3_V_LVCMOS + rf_data[2] F17 J13.4 GPIOR_91 3.3_V_LVCMOS + rf_data[3] G17 J13.7 GPIOR_92 3.3_V_LVCMOS ``` VCU118'de disaridan PMOD header'a 3.3 V seviye verilir. FPGA U1 package pinlerine dogrudan 3.3 V uygulanmaz; o tarafta XDC `LVCMOS18` kullanir. +Ti375C529'de AX2771 `rf_clk` hatti mutlaka J13 pin 10'a baglanmalidir. Bu pin +global-clock girisidir. J13 pin 1 / G15 (`GPIOR_88_PLLIN1`) MAX2771 `SCLK` +cikisidir; dedicated fabric GCLK olmadigi icin RF saati oradan alinmaz. + PMOD SPI portu her RF modunda aktiftir ve ayri MMIO register block olarak `0x10015000` adresindedir. Kart uzerindeki konfig flash SPI'si `0x10014000` adresinde kalir. Yazilim driver'i single/quad calisma modunu `ctrl.bit2` @@ -351,6 +380,15 @@ uzerinden 1.2 V bank/LVCMOS12: pmod_spi_sck P30 PMOD1_3 J53.7 SCK LVCMOS12 3.3 V pmod_spi_dq[2] P29 PMOD1_4 J53.2 LVCMOS12 3.3 V pmod_spi_dq[3] L31 PMOD1_5 J53.4 LVCMOS12 3.3 V + +Ti375C529 PMOD1/J14, connector ve FPGA tarafi 3.3 V: + port FPGA pin PMOD pin FPGA resource FPGA I/O + pmod_spi_csn B12 J14.1 GPIOR_96_CLK13 3.3_V_LVCMOS + pmod_spi_dq[0] C14 J14.2 MOSI GPIOR_97 3.3_V_LVCMOS + pmod_spi_dq[1] C13 J14.3 MISO GPIOR_98 3.3_V_LVCMOS + pmod_spi_sck C12 J14.4 SCK GPIOR_99 3.3_V_LVCMOS + pmod_spi_dq[2] D12 J14.7 GPIOR_100 3.3_V_LVCMOS + pmod_spi_dq[3] F12 J14.8 GPIOR_101_PLLIN1 3.3_V_LVCMOS ``` Sensorden gelen external interrupt hatti SPI'dan bagimsizdir. `pmod_irq` @@ -365,8 +403,16 @@ Genesys2: VCU118: port FPGA pin PMOD pin FPGA I/O PMOD header level pmod_irq M31 PMOD1_6 J53.6 LVCMOS12 3.3 V + +Ti375C529: + port FPGA pin PMOD pin FPGA resource FPGA I/O + pmod_irq D13 J14.9 GPIOR_102 3.3_V_LVCMOS + gps_pps E13 J14.10 GPIOR_103 3.3_V_LVCMOS ``` +Ti375C529'de `gps_pps` J14.10 uzerinden cikan 3.3 V PPS sinyalidir; +`pmod_irq` ise J14.9 uzerinden FPGA'ya girer. + Bu pinler mod bazli companion XDC dosyalarinda tutulur: `hardware/fpga/genesys2/constraints/genesys2_pmod_rf.xdc`, `hardware/fpga/vcu118/constraints/vcu118_pmod_rf.xdc`, @@ -375,13 +421,47 @@ Bu pinler mod bazli companion XDC dosyalarinda tutulur: `hardware/fpga/genesys2/constraints/genesys2_pmod_irq.xdc`, `hardware/fpga/vcu118/constraints/vcu118_pmod_irq.xdc`, `hardware/fpga/genesys2/constraints/genesys2_ethernet.xdc` ve -`hardware/fpga/vcu118/constraints/vcu118_ethernet.xdc`. +`hardware/fpga/vcu118/constraints/vcu118_ethernet.xdc`. Ti375C529 pinleri, +I/O standartlari, PLL'ler ve hard-JTAG baglantisi tek Efinity interface +scriptinde tutulur: +`hardware/fpga/ti375c529/constraints/ti375c529_rocket.isf`. + +### Ti375C529 kart uzeri baglantilar + +Ti375C529 development kit'te Rocket sistem saati kart uzerindeki 100 MHz +osilatorden, GPS isleme saatleri ise AX2771'in J13.10 uzerindeki +16.367981 MHz RF saatinden uretilir. SW3 active-low Rocket resetidir. FTDI +UART varsayilan olarak 460800 baud ve mevcut Linux enumeration'inda +`/dev/ttyUSB2` kullanir. Birden fazla kart veya farkli enumeration icin +`UART_PORT=...` ve `FTDI_URL=...` ile override edilebilir. + +Lower 512-Mbit konfig flash'i kart icinde su pinlere baglidir; PMOD'a kablo +cekilmez: + +```text +port FPGA pin FPGA resource +flash_csn A7 GPIOB_N_38 / SSL_N +flash_sck G6 GPIOB_P_39 / CCK +flash_dq[0] H4 GPIOB_N_40 / CDI0 +flash_dq[1] H5 GPIOB_P_40 / CDI1 +flash_dq[2] G5 GPIOB_N_39 / CDI2 +flash_dq[3] B7 GPIOB_P_38 / CDI3 +``` + +Efinity `JTAG_USER1`, mevcut Rocket DMI tunnel protokolunu kullanir. Host +OpenOCD build'inde `riscv set_bscan_tunnel_ir` destegi bulunmalidir; Efinity +ile gelen OpenOCD yerine uyumlu host OpenOCD kullanilir. OpenOCD 0.12 icin +gerekli host yamasi +`targets/fpga/ti375c529/flow/debug/openocd-0.12-ti375-bscan.patch` +dosyasindadir. Ayrintili Efinity, clock, JTAG ve dogrulama notlari icin +`targets/fpga/ti375c529/README.md` dosyasina bakin. ## FPGA Flash ve MCS Akislari Bu hedefler kok Makefile'dan secilen karta yonlenir. Genesys2 icin -`BOARD=genesys2`, VCU118 icin `BOARD=vcu118` kullanilir. `APP` verilmezse -varsayilan uygulama `hello_uart` olur. +`BOARD=genesys2`, VCU118 icin `BOARD=vcu118`, Ti375C529 icin +`BOARD=ti375c529` kullanilir. `APP` verilmezse varsayilan uygulama +`hello_uart` olur. Sadece ELF'i derleyip bootloader'in okuyacagi flash-format app imajina cevirmek: @@ -478,6 +558,57 @@ flash size: 32 MiB interface: SPIx4 ``` +### Ti375C529 Efinity build ve flash + +Efinity varsayilan olarak `/tools/efinix/efinity` altinda aranir. Farkli bir +kurulum `EFINITY_HOME=/path/to/efinity` ile secilebilir. Build, SRAM'e gecici +programlama ve kart tespiti kokten su sekilde yapilir: + +```sh +make FPGA_BOARD=ti375c529 fpga-config +make FPGA_BOARD=ti375c529 fpga-bitstream +make -C targets/fpga/ti375c529 detect +make FPGA_BOARD=ti375c529 fpga-program +``` + +Ti375C529'de repository genelindeki `fpga-mcs` hedef adi korunur fakat cikti +Xilinx MCS/BIN degil, Efinity raw HEX'tir. Lower 512-Mbit flash yerlesimi: + +```text +configuration offset: 0x00000000 +app offset: 0x00800000 +flash size: 64 MiB +interface: active-x1 configuration / user-mode quad SPI +``` + +Konfig ve uygulama imajlarini uretmek ve programlamak icin: + +```sh +make FPGA_BOARD=ti375c529 APP=hello_uart fpga-mcs +make FPGA_BOARD=ti375c529 APP=hello_uart fpga-flash-app +make FPGA_BOARD=ti375c529 fpga-flash-bitstream +make FPGA_BOARD=ti375c529 APP=hello_uart fpga-flash-mcs +``` + +Ciktilar: + +```text +targets/fpga/ti375c529/out/bitstream/ti375c529_rocket.bit +targets/fpga/ti375c529/out/bitstream/ti375c529_rocket.hex +targets/fpga/ti375c529/out/flash/ti375c529_rocket.hex +targets/fpga/ti375c529/out/flash/ti375c529_rocket.json +``` + +Flash programlama Efinity'nin Ti375'e uygun JTAG-to-SPI bridge'ini gecici +olarak yukler. Gercek persistent boot testi icin programlamadan sonra karta +power-cycle uygulanmalidir. GDB ile DTIM'e yukleme ve UART dinleme: + +```sh +make FPGA_BOARD=ti375c529 fpga-debug-openocd +make FPGA_BOARD=ti375c529 APP=hello_uart fpga-debug-load +make FPGA_BOARD=ti375c529 fpga-uart +``` + ## GPS Reset Davranisi OpenOCD/GDB `monitor reset` yolu Rocket debug module `ndmreset` sinyalini diff --git a/hardware/fpga/ti375c529/constraints/ti375c529_rocket.isf b/hardware/fpga/ti375c529/constraints/ti375c529_rocket.isf new file mode 100644 index 0000000..ad04b44 --- /dev/null +++ b/hardware/fpga/ti375c529/constraints/ti375c529_rocket.isf @@ -0,0 +1,235 @@ +# Efinity Interface Configuration for the Ti375C529 development kit. +# Pin assignments follow the kit user guide and the Efinity 2025.2 device DB. + +# Board I/O bank voltages. Keep these aligned with the Efinix out-of-box +# Ti375C529 development-kit project. +design.set_device_property("2A", "DYNAMIC_VOLTAGE", "0", "IOBANK") +design.set_mode_sel_name("2A", "2A_MODE_SEL", "2A") +design.set_device_property("2A", "VOLTAGE", "1.8", "IOBANK") +design.set_device_property("2B", "DYNAMIC_VOLTAGE", "0", "IOBANK") +design.set_mode_sel_name("2B", "2B_MODE_SEL", "2B") +design.set_device_property("2B", "VOLTAGE", "1.8", "IOBANK") +design.set_device_property("2C", "DYNAMIC_VOLTAGE", "0", "IOBANK") +design.set_mode_sel_name("2C", "2C_MODE_SEL", "2C") +design.set_device_property("2C", "VOLTAGE", "1.8", "IOBANK") +design.set_device_property("2D", "DYNAMIC_VOLTAGE", "0", "IOBANK") +design.set_mode_sel_name("2D", "2D_MODE_SEL", "2D") +design.set_device_property("2D", "VOLTAGE", "1.8", "IOBANK") +design.set_device_property("2E", "DYNAMIC_VOLTAGE", "0", "IOBANK") +design.set_mode_sel_name("2E", "2E_MODE_SEL", "2E") +design.set_device_property("2E", "VOLTAGE", "1.8", "IOBANK") +design.set_device_property("4A_4B", "DYNAMIC_VOLTAGE", "0", "IOBANK") +design.set_mode_sel_name("4A_4B", "4A_4B_MODE_SEL", "4A_4B") +design.set_device_property("4A_4B", "VOLTAGE", "1.8", "IOBANK") +design.set_device_property("4C", "DYNAMIC_VOLTAGE", "0", "IOBANK") +design.set_mode_sel_name("4C", "4C_MODE_SEL", "4C") +design.set_device_property("4C", "VOLTAGE", "1.8", "IOBANK") +design.set_device_property("4D", "DYNAMIC_VOLTAGE", "0", "IOBANK") +design.set_mode_sel_name("4D", "4D_MODE_SEL", "4D") +design.set_device_property("4D", "VOLTAGE", "1.8", "IOBANK") +design.set_device_property("BL2_BL3", "DYNAMIC_VOLTAGE", "0", "IOBANK") +design.set_mode_sel_name("BL2_BL3", "BL2_MODE_SEL", "BL2") +design.set_mode_sel_name("BL2_BL3", "BL3_MODE_SEL", "BL3") +design.set_device_property("BL2_BL3", "VOLTAGE", "3.3", "IOBANK") +design.set_device_property("BR0", "DYNAMIC_VOLTAGE", "0", "IOBANK") +design.set_mode_sel_name("BR0", "BR0_MODE_SEL", "BR0") +design.set_device_property("BR0", "VOLTAGE", "3.3", "IOBANK") +design.set_device_property("BR3_BR4", "DYNAMIC_VOLTAGE", "0", "IOBANK") +design.set_mode_sel_name("BR3_BR4", "BR3_MODE_SEL", "BR3") +design.set_mode_sel_name("BR3_BR4", "BR4_MODE_SEL", "BR4") +design.set_device_property("BR3_BR4", "VOLTAGE", "3.3", "IOBANK") +design.set_device_property("TL1_TL5", "DYNAMIC_VOLTAGE", "0", "IOBANK") +design.set_mode_sel_name("TL1_TL5", "TL1_MODE_SEL", "TL1") +design.set_mode_sel_name("TL1_TL5", "TL5_MODE_SEL", "TL5") +design.set_device_property("TL1_TL5", "VOLTAGE", "3.3", "IOBANK") +design.set_device_property("TR0", "DYNAMIC_VOLTAGE", "0", "IOBANK") +design.set_mode_sel_name("TR0", "TR0_MODE_SEL", "TR0") +design.set_device_property("TR0", "VOLTAGE", "3.3", "IOBANK") +design.set_device_property("TR1", "DYNAMIC_VOLTAGE", "0", "IOBANK") +design.set_mode_sel_name("TR1", "TR1_MODE_SEL", "TR1") +design.set_device_property("TR1", "VOLTAGE", "3.3", "IOBANK") +design.set_device_property("TR2", "DYNAMIC_VOLTAGE", "0", "IOBANK") +design.set_mode_sel_name("TR2", "TR2_MODE_SEL", "TR2") +design.set_device_property("TR2", "VOLTAGE", "3.3", "IOBANK") + +# External GPIO. +design.create_input_gpio("reset_n") +design.set_property("reset_n", "PULL_OPTION", "WEAK_PULLUP") +design.create_input_gpio("uart_rx") +design.create_output_gpio("uart_tx") +# Lower 512-Mbit configuration flash. After active configuration completes, +# these dedicated SPI pins become fabric GPIO and are driven by Rocket's MMIO +# SPI controller so the BootROM can read the application region. +design.create_output_gpio("flash_sck") +design.create_output_gpio("flash_csn") +design.create_inout_gpio("flash_dq", 3, 0) +# The AX2771 sample clock is routed to J13 pin 10 / GPIOR_95_CLK12 so it +# enters the fabric through a dedicated global-clock input instead of being +# promoted from normal GPIO routing by the placer. +design.create_input_clock_gpio("rf_clk") +design.create_input_gpio("rf_data", 3, 0) +design.create_output_gpio("pmod_spi_sck") +design.create_output_gpio("pmod_spi_csn") +design.create_inout_gpio("pmod_spi_dq", 3, 0) +design.create_input_gpio("pmod_irq") +design.create_output_gpio("max2771_spi_sclk") +design.create_output_gpio("max2771_spi_csn") +design.create_inout_gpio("max2771_spi_sdata") +design.create_output_gpio("gps_pps") +design.create_output_gpio("led", 4, 0) + +# The two PMOD headers, FTDI UART, reset switch, 100 MHz oscillator, and +# LED9/LED10 use the development kit's 3.3 V banks. GPIOs otherwise default +# to 1.8 V LVCMOS, so state these assignments explicitly. +design.set_property("reset_n", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("uart_rx", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("uart_tx", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("flash_sck", "IO_STANDARD", "1.8_V_LVCMOS") +design.set_property("flash_csn", "IO_STANDARD", "1.8_V_LVCMOS") +design.set_property("flash_dq[0]", "IO_STANDARD", "1.8_V_LVCMOS") +design.set_property("flash_dq[1]", "IO_STANDARD", "1.8_V_LVCMOS") +design.set_property("flash_dq[2]", "IO_STANDARD", "1.8_V_LVCMOS") +design.set_property("flash_dq[3]", "IO_STANDARD", "1.8_V_LVCMOS") +design.set_property("flash_csn", "PULL_OPTION", "WEAK_PULLUP") +design.set_property("flash_dq[0]", "PULL_OPTION", "WEAK_PULLUP") +design.set_property("flash_dq[1]", "PULL_OPTION", "WEAK_PULLUP") +design.set_property("flash_dq[2]", "PULL_OPTION", "WEAK_PULLUP") +design.set_property("flash_dq[3]", "PULL_OPTION", "WEAK_PULLUP") +design.set_property("rf_clk", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("rf_data[0]", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("rf_data[1]", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("rf_data[2]", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("rf_data[3]", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("pmod_spi_sck", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("pmod_spi_csn", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("pmod_spi_dq[0]", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("pmod_spi_dq[1]", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("pmod_spi_dq[2]", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("pmod_spi_dq[3]", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("pmod_irq", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("max2771_spi_sclk", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("max2771_spi_csn", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("max2771_spi_sdata", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("gps_pps", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("led[0]", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("led[1]", "IO_STANDARD", "3.3_V_LVCMOS") + +# Rocket/fabric clock: 100 MHz board oscillator -> 100 MHz GCLK. +design.create_block("fabric_pll", "PLL") +design.gen_pll_ref_clock("fabric_pll", pll_res="PLL_BL0", refclk_src="EXTERNAL", refclk_name="board_clk_100", ext_refclk_no="1") +design.set_property("board_clk_100", "IO_STANDARD", "3.3_V_LVCMOS") +design.set_property("fabric_pll", "REFCLK_FREQ", "100", "PLL") +design.set_property("fabric_pll", "CLKOUT0_PIN", "fabric_clk", "PLL") +design.set_property("fabric_pll", "CLKOUT0_CONN_TYPE", "gclk", "PLL") +design.set_property("fabric_pll", "LOCKED_PIN", "fabric_pll_locked", "PLL") +design.auto_calc_pll_clock("fabric_pll", {"CLKOUT0_FREQ": "100.0", "CLKOUT0_PHASE": "0"}) + +# RF-coherent GPS processing clocks. The AX2771's 16.367981 MHz clock enters +# the fabric on J13 pin 10 / A12 (GPIOR_95_CLK12) and drives the same two-stage +# clock chain used by the Xilinx targets: +# RF -> ~55.55556 MHz -> 100 MHz acquisition / 125 MHz tracking. +design.create_block("gps_ref_pll", "PLL") +design.gen_pll_ref_clock("gps_ref_pll", pll_res="PLL_TR0", refclk_src="CORE") +design.set_property("gps_ref_pll", "CORE_CLK_PIN", "rf_clk", "PLL") +design.set_property("gps_ref_pll", "REFCLK_FREQ", "16.367981", "PLL") +design.set_property("gps_ref_pll", "CLKOUT1_EN", "1", "PLL") +design.set_property("gps_ref_pll", "CLKOUT0_PIN", "gps_ref_clk_gen", "PLL") +design.set_property("gps_ref_pll", "CLKOUT0_CONN_TYPE", "gclk", "PLL") +design.set_property("gps_ref_pll", "CLKOUT1_PIN", "gps_ref_feedback", "PLL") +design.set_property("gps_ref_pll", "CLKOUT1_CONN_TYPE", "gclk", "PLL") +design.set_property("gps_ref_pll", "LOCKED_PIN", "gps_ref_pll_locked", "PLL") +design.set_property("gps_ref_pll", "FEEDBACK_MODE", "LOCAL", "PLL") +design.set_property("gps_ref_pll", "FEEDBACK_CLK", "CLK1", "PLL") +design.set_property("gps_ref_pll", "FRACTIONAL_MODE_EN", "1", "PLL") +design.set_property("gps_ref_pll", "FRACTIONAL_COEFFICIENT", "10715375", "PLL") +design.set_property("gps_ref_pll", "M", "4", "PLL") +design.set_property("gps_ref_pll", "N", "1", "PLL") +design.set_property("gps_ref_pll", "O", "1", "PLL") +design.set_property("gps_ref_pll", "CLKOUT0_DIV", "42", "PLL") +design.set_property("gps_ref_pll", "CLKOUT1_DIV", "35", "PLL") +design.set_property("gps_ref_pll", "CLKOUT1_PDIV", "5", "PLL") +design.set_property("gps_ref_pll", "CLKOUT1_SDIV", "30", "PLL") +design.calc_pll_clock("gps_ref_pll") + +design.create_block("gps_domain_pll", "PLL") +design.gen_pll_ref_clock("gps_domain_pll", pll_res="PLL_TR1", refclk_src="CORE") +design.set_property("gps_domain_pll", "CORE_CLK_PIN", "gps_ref_clk_gen", "PLL") +design.set_property("gps_domain_pll", "REFCLK_FREQ", "55.55555593", "PLL") +design.set_property("gps_domain_pll", "CLKOUT3_EN", "1", "PLL") +design.set_property("gps_domain_pll", "CLKOUT4_EN", "1", "PLL") +design.set_property("gps_domain_pll", "CLKOUT0_PIN", "gps_domain_feedback", "PLL") +design.set_property("gps_domain_pll", "CLKOUT0_CONN_TYPE", "gclk", "PLL") +design.set_property("gps_domain_pll", "CLKOUT3_PIN", "gps_acq_clk_gen", "PLL") +design.set_property("gps_domain_pll", "CLKOUT3_CONN_TYPE", "gclk", "PLL") +design.set_property("gps_domain_pll", "CLKOUT4_PIN", "gps_trck_clk_gen", "PLL") +design.set_property("gps_domain_pll", "CLKOUT4_CONN_TYPE", "gclk", "PLL") +design.set_property("gps_domain_pll", "LOCKED_PIN", "gps_domain_pll_locked", "PLL") +design.set_property("gps_domain_pll", "FEEDBACK_MODE", "LOCAL", "PLL") +design.set_property("gps_domain_pll", "FEEDBACK_CLK", "CLK0", "PLL") +design.set_property("gps_domain_pll", "M", "2", "PLL") +design.set_property("gps_domain_pll", "N", "1", "PLL") +design.set_property("gps_domain_pll", "O", "2", "PLL") +design.set_property("gps_domain_pll", "CLKOUT0_DIV", "18", "PLL") +design.set_property("gps_domain_pll", "CLKOUT3_DIV", "20", "PLL") +design.set_property("gps_domain_pll", "CLKOUT4_DIV", "16", "PLL") +design.calc_pll_clock("gps_domain_pll") + +# Hard JTAG USER1 exposes the TAP handshake at the FPGA core boundary. +design.create_block("rocket_jtag", "JTAG") +design.set_property("rocket_jtag", "NAME", "rocket_jtag", "JTAG") +design.set_property("rocket_jtag", "RESOURCE", "JTAG_USER1", "JTAG") +design.set_property("rocket_jtag", "CAPTURE", "jtag_CAPTURE", "JTAG") +design.set_property("rocket_jtag", "DRCK", "jtag_DRCK", "JTAG") +design.set_property("rocket_jtag", "RESET", "jtag_RESET", "JTAG") +design.set_property("rocket_jtag", "RUNTEST", "jtag_RUNTEST", "JTAG") +design.set_property("rocket_jtag", "SEL", "jtag_SEL", "JTAG") +design.set_property("rocket_jtag", "SHIFT", "jtag_SHIFT", "JTAG") +design.set_property("rocket_jtag", "TCK", "jtag_TCK", "JTAG") +design.set_property("rocket_jtag", "TDI", "jtag_TDI", "JTAG") +design.set_property("rocket_jtag", "TMS", "jtag_TMS", "JTAG") +design.set_property("rocket_jtag", "UPDATE", "jtag_UPDATE", "JTAG") +design.set_property("rocket_jtag", "TDO", "jtag_TDO", "JTAG") +design.assign_resource("rocket_jtag", "JTAG_USER1", "JTAG") + +# Package assignments. +design.assign_pkg_pin("board_clk_100", "U4") +design.assign_pkg_pin("reset_n", "U19") +design.assign_pkg_pin("uart_rx", "E10") +design.assign_pkg_pin("uart_tx", "E9") + +# Lower configuration flash U47: CDI0..3, CCK, and SSL_N. These assignments +# match Efinix's Ti375C529 JTAG-to-SPI loader reference design. +design.assign_pkg_pin("flash_dq[0]", "H4") +design.assign_pkg_pin("flash_dq[1]", "H5") +design.assign_pkg_pin("flash_dq[2]", "G5") +design.assign_pkg_pin("flash_dq[3]", "B7") +design.assign_pkg_pin("flash_sck", "G6") +design.assign_pkg_pin("flash_csn", "A7") + +# PMOD0/J13 RF input plus the independent MAX2771 three-wire control bus. +# J13 pin 10 is the header's dedicated GCLK-capable RF-clock input. +design.assign_pkg_pin("max2771_spi_sclk", "G15") +design.assign_pkg_pin("max2771_spi_csn", "A11") +design.assign_pkg_pin("max2771_spi_sdata", "A13") +design.assign_pkg_pin("rf_clk", "A12") +design.assign_pkg_pin("rf_data[0]", "G16") +design.assign_pkg_pin("rf_data[1]", "F16") +design.assign_pkg_pin("rf_data[2]", "F17") +design.assign_pkg_pin("rf_data[3]", "G17") + +# PMOD1/J14 SPI + interrupt + PPS. +design.assign_pkg_pin("pmod_spi_csn", "B12") +design.assign_pkg_pin("pmod_spi_dq[0]", "C14") +design.assign_pkg_pin("pmod_spi_dq[1]", "C13") +design.assign_pkg_pin("pmod_spi_sck", "C12") +design.assign_pkg_pin("pmod_spi_dq[2]", "D12") +design.assign_pkg_pin("pmod_spi_dq[3]", "F12") +design.assign_pkg_pin("pmod_irq", "D13") +design.assign_pkg_pin("gps_pps", "E13") + +# User LEDs LED9..LED13. +design.assign_pkg_pin("led[0]", "V4") +design.assign_pkg_pin("led[1]", "U6") +design.assign_pkg_pin("led[2]", "L18") +design.assign_pkg_pin("led[3]", "R20") +design.assign_pkg_pin("led[4]", "E19") diff --git a/hardware/fpga/ti375c529/constraints/ti375c529_rocket.sdc b/hardware/fpga/ti375c529/constraints/ti375c529_rocket.sdc new file mode 100644 index 0000000..a5f092f --- /dev/null +++ b/hardware/fpga/ti375c529/constraints/ti375c529_rocket.sdc @@ -0,0 +1,8 @@ +# AX2771 sample clock on PMOD J13. The 100/125 MHz GPS clocks generated by the +# two Efinity PLLs are frequency-related to this input; the Rocket fabric clock +# comes from the independent on-board 100 MHz oscillator. +create_clock -period 61.09495 -name rf_clk [get_ports {rf_clk}] + +# The FTDI adapter is normally run at 1 MHz. Constraining the hard-TAP fabric +# interface to 10 MHz leaves margin if the debug adapter speed is increased. +create_clock -period 100.000 -name jtag_TCK [get_ports {jtag_TCK}] diff --git a/hardware/fpga/ti375c529/constraints/ti375c529_rocket_clock_groups.sdc b/hardware/fpga/ti375c529/constraints/ti375c529_rocket_clock_groups.sdc new file mode 100644 index 0000000..c0a1e08 --- /dev/null +++ b/hardware/fpga/ti375c529/constraints/ti375c529_rocket_clock_groups.sdc @@ -0,0 +1,10 @@ +# Efinity's generated .pt.sdc is read before this file and defines the fabric +# and PLL-output clocks. The Rocket oscillator, AX2771-derived GPS clocks, and +# hard-TAP JTAG clock are independent domains. +set_clock_groups -asynchronous \ + -group [get_clocks {fabric_clk}] \ + -group [get_clocks {rf_clk}] \ + -group [get_clocks {gps_ref_clk_gen}] \ + -group [get_clocks {gps_acq_clk_gen}] \ + -group [get_clocks {gps_trck_clk_gen}] \ + -group [get_clocks {jtag_TCK}] diff --git a/hardware/fpga/ti375c529/rtl/Makefile b/hardware/fpga/ti375c529/rtl/Makefile new file mode 100644 index 0000000..9d9fb78 --- /dev/null +++ b/hardware/fpga/ti375c529/rtl/Makefile @@ -0,0 +1,18 @@ +.PHONY: help all shell generated clean + +help: + @echo "Ti375C529 RTL targets:" + @echo " make shell # list hand-written FPGA shell RTL" + @echo " make generated # generate Rocket SystemVerilog and Efinix wrapper" + @echo " make clean # remove generated wrapper/verilog" + +all: generated + +shell: + @find . -type f -name '*.sv' -print | sort + +generated: + @$(MAKE) -C ../../../../targets/fpga/ti375c529 rtl + +clean: + rm -rf ../../../generated/ti375c529-soc-verilog ../../../../targets/fpga/ti375c529/out/build/generated diff --git a/soc/software/Makefile b/soc/software/Makefile index 816254b..a4601fa 100644 --- a/soc/software/Makefile +++ b/soc/software/Makefile @@ -14,12 +14,15 @@ GPS_DEBUG_LEVEL ?= 1 GPS_ESKF_ENABLE ?= 1 GPS_EPHEMERIS_FLASH_ENABLE ?= 1 GPS_EPHEMERIS_FLASH_SEED_INITIAL ?= 1 +GPS_EPHEMERIS_FLASH_BASE ?= 0x01fe0000 GPS_NAV_CONTEXT_ENABLE ?= 1 +GPS_NAV_CONTEXT_FLASH_BASE ?= 0x01fc0000 IMU_SENSOR ?= auto BSP_UART_CLOCK_HZ ?= 100000000 BSP_UART_BAUDRATE ?= 460800 GPS_SYSTEM_UART_BAUDRATE ?= 460800 BSP_CLINT_TIMEBASE_HZ ?= 1000000 +BSP_SPI_FLASH_PROFILE ?= 1 GPS_SYSTEM_CLINT_TIMEBASE_HZ ?= 500000 GPS_SYSTEM_IMU_PUBLISH_EVERY_N_SAMPLES ?= 5 # BSP_DTIM_* mirrors the FPGA DTIM_* knobs and is used by C code plus linker scripts. @@ -51,9 +54,12 @@ help: @echo " GPS_ESKF_ENABLE=$(GPS_ESKF_ENABLE)" @echo " GPS_EPHEMERIS_FLASH_ENABLE=$(GPS_EPHEMERIS_FLASH_ENABLE)" @echo " GPS_EPHEMERIS_FLASH_SEED_INITIAL=$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)" + @echo " GPS_EPHEMERIS_FLASH_BASE=$(GPS_EPHEMERIS_FLASH_BASE)" @echo " GPS_NAV_CONTEXT_ENABLE=$(GPS_NAV_CONTEXT_ENABLE)" + @echo " GPS_NAV_CONTEXT_FLASH_BASE=$(GPS_NAV_CONTEXT_FLASH_BASE)" @echo " IMU_SENSOR=$(IMU_SENSOR)" @echo " BSP_CLINT_TIMEBASE_HZ=$(BSP_CLINT_TIMEBASE_HZ)" + @echo " BSP_SPI_FLASH_PROFILE=$(BSP_SPI_FLASH_PROFILE)" @echo " GPS_SYSTEM_CLINT_TIMEBASE_HZ=$(GPS_SYSTEM_CLINT_TIMEBASE_HZ)" @echo " GPS_SYSTEM_IMU_PUBLISH_EVERY_N_SAMPLES=$(GPS_SYSTEM_IMU_PUBLISH_EVERY_N_SAMPLES)" @echo " BSP_DTIM_BASE=$(BSP_DTIM_BASE)" @@ -62,7 +68,7 @@ help: all: bootloader hello bootloader: - @make -C bootloader TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(OUT_DIR)/bootloader" APP_FLASH_OFFSET="$(APP_FLASH_OFFSET)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_DTIM_BASE="$(BSP_DTIM_BASE)" BSP_DTIM_SIZE="$(BSP_DTIM_SIZE)" all + @make -C bootloader TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(OUT_DIR)/bootloader" APP_FLASH_OFFSET="$(APP_FLASH_OFFSET)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_SPI_FLASH_PROFILE="$(BSP_SPI_FLASH_PROFILE)" BSP_DTIM_BASE="$(BSP_DTIM_BASE)" BSP_DTIM_SIZE="$(BSP_DTIM_SIZE)" all hello: @make -C hello_uart TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(OUT_DIR)/hello_uart" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_DTIM_BASE="$(BSP_DTIM_BASE)" BSP_DTIM_SIZE="$(BSP_DTIM_SIZE)" all @@ -77,11 +83,11 @@ steval-mki217v1-test: @make -C steval_mki217v1_test TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(OUT_DIR)/steval_mki217v1_test" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_DTIM_BASE="$(BSP_DTIM_BASE)" BSP_DTIM_SIZE="$(BSP_DTIM_SIZE)" all gps-system: - @make -C gps_system TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(OUT_DIR)/gps_system" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" GPS_ESKF_ENABLE="$(GPS_ESKF_ENABLE)" GPS_EPHEMERIS_FLASH_ENABLE="$(GPS_EPHEMERIS_FLASH_ENABLE)" GPS_EPHEMERIS_FLASH_SEED_INITIAL="$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)" GPS_NAV_CONTEXT_ENABLE="$(GPS_NAV_CONTEXT_ENABLE)" IMU_SENSOR="$(IMU_SENSOR)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(GPS_SYSTEM_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(GPS_SYSTEM_CLINT_TIMEBASE_HZ)" IMU_CORRECTED_PUBLISH_EVERY_N_SAMPLES="$(GPS_SYSTEM_IMU_PUBLISH_EVERY_N_SAMPLES)" BSP_DTIM_BASE="$(BSP_DTIM_BASE)" BSP_DTIM_SIZE="$(BSP_DTIM_SIZE)" all + @make -C gps_system TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(OUT_DIR)/gps_system" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" GPS_ESKF_ENABLE="$(GPS_ESKF_ENABLE)" GPS_EPHEMERIS_FLASH_ENABLE="$(GPS_EPHEMERIS_FLASH_ENABLE)" GPS_EPHEMERIS_FLASH_SEED_INITIAL="$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)" GPS_EPHEMERIS_FLASH_BASE="$(GPS_EPHEMERIS_FLASH_BASE)" GPS_NAV_CONTEXT_ENABLE="$(GPS_NAV_CONTEXT_ENABLE)" GPS_NAV_CONTEXT_FLASH_BASE="$(GPS_NAV_CONTEXT_FLASH_BASE)" IMU_SENSOR="$(IMU_SENSOR)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(GPS_SYSTEM_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(GPS_SYSTEM_CLINT_TIMEBASE_HZ)" BSP_SPI_FLASH_PROFILE="$(BSP_SPI_FLASH_PROFILE)" IMU_CORRECTED_PUBLISH_EVERY_N_SAMPLES="$(GPS_SYSTEM_IMU_PUBLISH_EVERY_N_SAMPLES)" BSP_DTIM_BASE="$(BSP_DTIM_BASE)" BSP_DTIM_SIZE="$(BSP_DTIM_SIZE)" all app: @test -d "$(APP)" - @make -C "$(APP)" TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(OUT_DIR)/$(APP)" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" GPS_ESKF_ENABLE="$(GPS_ESKF_ENABLE)" GPS_EPHEMERIS_FLASH_ENABLE="$(GPS_EPHEMERIS_FLASH_ENABLE)" GPS_EPHEMERIS_FLASH_SEED_INITIAL="$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)" GPS_NAV_CONTEXT_ENABLE="$(GPS_NAV_CONTEXT_ENABLE)" IMU_SENSOR="$(IMU_SENSOR)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_DTIM_BASE="$(BSP_DTIM_BASE)" BSP_DTIM_SIZE="$(BSP_DTIM_SIZE)" all + @make -C "$(APP)" TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(OUT_DIR)/$(APP)" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" GPS_ESKF_ENABLE="$(GPS_ESKF_ENABLE)" GPS_EPHEMERIS_FLASH_ENABLE="$(GPS_EPHEMERIS_FLASH_ENABLE)" GPS_EPHEMERIS_FLASH_SEED_INITIAL="$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)" GPS_EPHEMERIS_FLASH_BASE="$(GPS_EPHEMERIS_FLASH_BASE)" GPS_NAV_CONTEXT_ENABLE="$(GPS_NAV_CONTEXT_ENABLE)" GPS_NAV_CONTEXT_FLASH_BASE="$(GPS_NAV_CONTEXT_FLASH_BASE)" IMU_SENSOR="$(IMU_SENSOR)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_SPI_FLASH_PROFILE="$(BSP_SPI_FLASH_PROFILE)" BSP_DTIM_BASE="$(BSP_DTIM_BASE)" BSP_DTIM_SIZE="$(BSP_DTIM_SIZE)" all flash-image: app @mkdir -p "$(FLASH_DIR)" diff --git a/soc/software/bootloader/Makefile b/soc/software/bootloader/Makefile index 736caec..864a1db 100644 --- a/soc/software/bootloader/Makefile +++ b/soc/software/bootloader/Makefile @@ -14,12 +14,14 @@ MARCH ?= rv64imafdc_zicsr_zifencei MABI ?= lp64d BSP_UART_CLOCK_HZ ?= 100000000 BSP_UART_BAUDRATE ?= 460800 +BSP_CLINT_TIMEBASE_HZ ?= 1000000 +BSP_SPI_FLASH_PROFILE ?= 1 BSP_DTIM_BASE ?= 0x80000000 BSP_DTIM_SIZE ?= 0x00100000 CONFIG_STAMP := $(BUILD_DIR)/build_config.txt # C uses BSP_DTIM_* for bounds checks; linker uses __dtim_* for RAM origin/length. -CFLAGS := -march=$(MARCH) -mabi=$(MABI) -mcmodel=medany -Os -ffreestanding -fno-builtin -fno-common -Wall -Wextra -I$(BSP_DIR)/include -DAPP_FLASH_OFFSET=$(APP_FLASH_OFFSET)UL -DBSP_UART_CLOCK_HZ=$(BSP_UART_CLOCK_HZ)UL -DBSP_UART_BAUDRATE=$(BSP_UART_BAUDRATE)UL -DBSP_DTIM_BASE=$(BSP_DTIM_BASE)UL -DBSP_DTIM_SIZE=$(BSP_DTIM_SIZE)UL +CFLAGS := -march=$(MARCH) -mabi=$(MABI) -mcmodel=medany -Os -ffreestanding -fno-builtin -fno-common -Wall -Wextra -I$(BSP_DIR)/include -DAPP_FLASH_OFFSET=$(APP_FLASH_OFFSET)UL -DBSP_UART_CLOCK_HZ=$(BSP_UART_CLOCK_HZ)UL -DBSP_UART_BAUDRATE=$(BSP_UART_BAUDRATE)UL -DBSP_CLINT_TIMEBASE_HZ=$(BSP_CLINT_TIMEBASE_HZ)UL -DBSP_SPI_FLASH_PROFILE=$(BSP_SPI_FLASH_PROFILE) -DBSP_DTIM_BASE=$(BSP_DTIM_BASE)UL -DBSP_DTIM_SIZE=$(BSP_DTIM_SIZE)UL LDFLAGS := -T linker.ld -nostdlib -static -Wl,--gc-sections -Wl,--defsym=__dtim_base=$(BSP_DTIM_BASE) -Wl,--defsym=__dtim_size=$(BSP_DTIM_SIZE) -Wl,-Map,$(BUILD_DIR)/$(TARGET).map SRCS := start.S main.c @@ -42,6 +44,8 @@ $(CONFIG_STAMP): FORCE | $(BUILD_DIR) 'MABI=$(MABI)' \ 'BSP_UART_CLOCK_HZ=$(BSP_UART_CLOCK_HZ)' \ 'BSP_UART_BAUDRATE=$(BSP_UART_BAUDRATE)' \ + 'BSP_CLINT_TIMEBASE_HZ=$(BSP_CLINT_TIMEBASE_HZ)' \ + 'BSP_SPI_FLASH_PROFILE=$(BSP_SPI_FLASH_PROFILE)' \ 'BSP_DTIM_BASE=$(BSP_DTIM_BASE)' \ 'BSP_DTIM_SIZE=$(BSP_DTIM_SIZE)' > "$$tmp"; \ if ! cmp -s "$$tmp" "$@"; then mv "$$tmp" "$@"; else rm "$$tmp"; fi diff --git a/soc/software/bsp/drivers/spi_flash.c b/soc/software/bsp/drivers/spi_flash.c index 473b494..195c73e 100644 --- a/soc/software/bsp/drivers/spi_flash.c +++ b/soc/software/bsp/drivers/spi_flash.c @@ -17,17 +17,27 @@ #define FLASH_CMD_WRITE_DISABLE 0x04u #define FLASH_CMD_WRITE_ENABLE 0x06u #define FLASH_CMD_READ_CONFIG 0x35u -#define FLASH_CMD_CLEAR_STATUS 0x30u -#define FLASH_CMD_RESET 0xf0u #define FLASH_CMD_READ_4B 0x13u #define FLASH_CMD_PROGRAM_4B 0x12u #define FLASH_CMD_ERASE_4B 0xdcu -#define FLASH_STATUS_WIP (1u << 0) -#define FLASH_STATUS_WEL (1u << 1) -#define FLASH_STATUS_E_ERR (1u << 5) -#define FLASH_STATUS_P_ERR (1u << 6) -#define FLASH_STATUS_ERROR (FLASH_STATUS_E_ERR | FLASH_STATUS_P_ERR) +#define FLASH_STATUS_WIP (1u << 0) +#define FLASH_STATUS_WEL (1u << 1) + +#if BSP_SPI_FLASH_PROFILE == BSP_SPI_FLASH_PROFILE_S25FL256S +#define FLASH_CMD_CLEAR_STATUS 0x30u +#define FLASH_CMD_RESET 0xf0u +#define FLASH_STATUS_ERROR ((1u << 5) | (1u << 6)) +#elif BSP_SPI_FLASH_PROFILE == BSP_SPI_FLASH_PROFILE_MT25QU01G +#define FLASH_CMD_RESET_ENABLE 0x66u +#define FLASH_CMD_RESET_MEMORY 0x99u +#define FLASH_CMD_READ_FLAG_STATUS 0x70u +#define FLASH_CMD_CLEAR_FLAG_STATUS 0x50u +#define FLASH_FLAG_STATUS_ERROR ((1u << 1) | (1u << 4) | (1u << 5)) +#elif BSP_SPI_FLASH_PROFILE == BSP_SPI_FLASH_PROFILE_IS25WP512M +#define FLASH_CMD_RESET_ENABLE 0x66u +#define FLASH_CMD_RESET_MEMORY 0x99u +#endif #define FLASH_RESET_DELAY_US 300u #define FLASH_PROGRAM_TIMEOUT_US 100000u @@ -104,6 +114,7 @@ static bool flash_wait_complete(uint32_t timeout_us) do { status = bsp_spi_flash_read_status(); +#if BSP_SPI_FLASH_PROFILE == BSP_SPI_FLASH_PROFILE_S25FL256S if ((status & FLASH_STATUS_ERROR) != 0u) { /* S25FL-S deliberately holds WIP high after a program/erase error * until CLSR is issued. Clear the latched failure so a later request @@ -111,7 +122,15 @@ static bool flash_wait_complete(uint32_t timeout_us) flash_cmd(FLASH_CMD_CLEAR_STATUS); return false; } +#endif if ((status & FLASH_STATUS_WIP) == 0u) { +#if BSP_SPI_FLASH_PROFILE == BSP_SPI_FLASH_PROFILE_MT25QU01G + uint8_t flags = flash_read_register(FLASH_CMD_READ_FLAG_STATUS); + if ((flags & FLASH_FLAG_STATUS_ERROR) != 0u) { + flash_cmd(FLASH_CMD_CLEAR_FLAG_STATUS); + return false; + } +#endif return true; } } while ((bsp_read64(BSP_CLINT_MTIME) - start) < timeout_ticks); @@ -121,11 +140,20 @@ static bool flash_wait_complete(uint32_t timeout_us) static bool flash_write_enable(void) { +#if BSP_SPI_FLASH_PROFILE == BSP_SPI_FLASH_PROFILE_S25FL256S flash_cmd(FLASH_CMD_CLEAR_STATUS); +#elif BSP_SPI_FLASH_PROFILE == BSP_SPI_FLASH_PROFILE_MT25QU01G + flash_cmd(FLASH_CMD_CLEAR_FLAG_STATUS); +#endif flash_cmd(FLASH_CMD_WRITE_ENABLE); +#if BSP_SPI_FLASH_PROFILE == BSP_SPI_FLASH_PROFILE_S25FL256S return (bsp_spi_flash_read_status() & (FLASH_STATUS_WIP | FLASH_STATUS_WEL | FLASH_STATUS_ERROR)) == FLASH_STATUS_WEL; +#else + return (bsp_spi_flash_read_status() & + (FLASH_STATUS_WIP | FLASH_STATUS_WEL)) == FLASH_STATUS_WEL; +#endif } static bool flash_verify(uint32_t flash_addr, const uint8_t *expected, @@ -156,7 +184,12 @@ void bsp_spi_flash_init(void) void bsp_spi_flash_reset(void) { spi_select(0); +#if BSP_SPI_FLASH_PROFILE == BSP_SPI_FLASH_PROFILE_S25FL256S flash_cmd(FLASH_CMD_RESET); +#else + flash_cmd(FLASH_CMD_RESET_ENABLE); + flash_cmd(FLASH_CMD_RESET_MEMORY); +#endif flash_delay_us(FLASH_RESET_DELAY_US); } @@ -179,7 +212,11 @@ uint8_t bsp_spi_flash_read_status(void) uint8_t bsp_spi_flash_read_config(void) { +#if BSP_SPI_FLASH_PROFILE == BSP_SPI_FLASH_PROFILE_S25FL256S return flash_read_register(FLASH_CMD_READ_CONFIG); +#else + return 0u; +#endif } void bsp_spi_flash_read(uint32_t flash_addr, void *dst, uint32_t len) @@ -202,9 +239,13 @@ void bsp_spi_flash_read(uint32_t flash_addr, void *dst, uint32_t len) bool bsp_spi_flash_erase_sector(uint32_t flash_addr) { if ((flash_addr & (BSP_SPI_FLASH_SECTOR_SIZE - 1u)) != 0u || - !flash_range_valid(flash_addr, BSP_SPI_FLASH_SECTOR_SIZE) || + !flash_range_valid(flash_addr, BSP_SPI_FLASH_SECTOR_SIZE) +#if BSP_SPI_FLASH_PROFILE == BSP_SPI_FLASH_PROFILE_S25FL256S + || ((flash_addr >= (BSP_SPI_FLASH_SIZE - (2u * BSP_SPI_FLASH_SECTOR_SIZE))) && - ((bsp_spi_flash_read_config() & BSP_SPI_FLASH_CONFIG_TBPARM) != 0u))) { + ((bsp_spi_flash_read_config() & BSP_SPI_FLASH_CONFIG_TBPARM) != 0u)) +#endif + ) { return false; } if (!flash_wait_complete(FLASH_PROGRAM_TIMEOUT_US) || !flash_write_enable()) { diff --git a/soc/software/bsp/include/bsp/spi_flash.h b/soc/software/bsp/include/bsp/spi_flash.h index bd462e3..ef365e1 100644 --- a/soc/software/bsp/include/bsp/spi_flash.h +++ b/soc/software/bsp/include/bsp/spi_flash.h @@ -4,10 +4,29 @@ #include #include -#define BSP_SPI_FLASH_SIZE 0x02000000UL +#define BSP_SPI_FLASH_PROFILE_S25FL256S 1 +#define BSP_SPI_FLASH_PROFILE_MT25QU01G 2 +#define BSP_SPI_FLASH_PROFILE_IS25WP512M 3 + +#ifndef BSP_SPI_FLASH_PROFILE +#define BSP_SPI_FLASH_PROFILE BSP_SPI_FLASH_PROFILE_S25FL256S +#endif + +#if BSP_SPI_FLASH_PROFILE == BSP_SPI_FLASH_PROFILE_S25FL256S +#define BSP_SPI_FLASH_SIZE 0x02000000UL +#define BSP_SPI_FLASH_JEDEC_ID 0x00010219UL +#elif BSP_SPI_FLASH_PROFILE == BSP_SPI_FLASH_PROFILE_MT25QU01G +#define BSP_SPI_FLASH_SIZE 0x08000000UL +#define BSP_SPI_FLASH_JEDEC_ID 0x0020bb21UL +#elif BSP_SPI_FLASH_PROFILE == BSP_SPI_FLASH_PROFILE_IS25WP512M +#define BSP_SPI_FLASH_SIZE 0x04000000UL +#define BSP_SPI_FLASH_JEDEC_ID 0x009d701aUL +#else +#error "Unsupported BSP_SPI_FLASH_PROFILE" +#endif + #define BSP_SPI_FLASH_PAGE_SIZE 256UL #define BSP_SPI_FLASH_SECTOR_SIZE 0x00010000UL -#define BSP_SPI_FLASH_JEDEC_ID 0x00010219UL #define BSP_SPI_FLASH_CONFIG_TBPARM (1u << 2) void bsp_spi_flash_init(void); diff --git a/soc/software/common/app.mk b/soc/software/common/app.mk index c8b46a6..031007b 100644 --- a/soc/software/common/app.mk +++ b/soc/software/common/app.mk @@ -15,12 +15,13 @@ MABI ?= lp64d BSP_UART_CLOCK_HZ ?= 100000000 BSP_UART_BAUDRATE ?= 460800 BSP_CLINT_TIMEBASE_HZ ?= 1000000 +BSP_SPI_FLASH_PROFILE ?= 1 BSP_DTIM_BASE ?= 0x80000000 BSP_DTIM_SIZE ?= 0x00100000 CONFIG_STAMP := $(BUILD_DIR)/build_config.txt # C sees BSP_DTIM_* while ld sees __dtim_*; both come from the same Makefile knobs. -CFLAGS ?= -march=$(MARCH) -mabi=$(MABI) -mcmodel=medany -Os -ffreestanding -fno-builtin -fno-common -Wall -Wextra -I$(BSP_DIR)/include -DBSP_UART_CLOCK_HZ=$(BSP_UART_CLOCK_HZ)UL -DBSP_UART_BAUDRATE=$(BSP_UART_BAUDRATE)UL -DBSP_CLINT_TIMEBASE_HZ=$(BSP_CLINT_TIMEBASE_HZ)UL -DBSP_DTIM_BASE=$(BSP_DTIM_BASE)UL -DBSP_DTIM_SIZE=$(BSP_DTIM_SIZE)UL +CFLAGS ?= -march=$(MARCH) -mabi=$(MABI) -mcmodel=medany -Os -ffreestanding -fno-builtin -fno-common -Wall -Wextra -I$(BSP_DIR)/include -DBSP_UART_CLOCK_HZ=$(BSP_UART_CLOCK_HZ)UL -DBSP_UART_BAUDRATE=$(BSP_UART_BAUDRATE)UL -DBSP_CLINT_TIMEBASE_HZ=$(BSP_CLINT_TIMEBASE_HZ)UL -DBSP_SPI_FLASH_PROFILE=$(BSP_SPI_FLASH_PROFILE) -DBSP_DTIM_BASE=$(BSP_DTIM_BASE)UL -DBSP_DTIM_SIZE=$(BSP_DTIM_SIZE)UL LDFLAGS ?= -T $(LINKER_SCRIPT) -nostartfiles -static -Wl,--gc-sections -Wl,--defsym=__dtim_base=$(BSP_DTIM_BASE) -Wl,--defsym=__dtim_size=$(BSP_DTIM_SIZE) -Wl,-Map,$(BUILD_DIR)/$(TARGET).map LDLIBS ?= -Wl,--start-group -lc -lgcc -Wl,--end-group @@ -47,6 +48,7 @@ $(CONFIG_STAMP): FORCE | $(BUILD_DIR) 'BSP_UART_CLOCK_HZ=$(BSP_UART_CLOCK_HZ)' \ 'BSP_UART_BAUDRATE=$(BSP_UART_BAUDRATE)' \ 'BSP_CLINT_TIMEBASE_HZ=$(BSP_CLINT_TIMEBASE_HZ)' \ + 'BSP_SPI_FLASH_PROFILE=$(BSP_SPI_FLASH_PROFILE)' \ 'BSP_DTIM_BASE=$(BSP_DTIM_BASE)' \ 'BSP_DTIM_SIZE=$(BSP_DTIM_SIZE)' \ 'GPS_DEBUG=$(GPS_DEBUG)' \ diff --git a/soc/software/gps_system/Makefile b/soc/software/gps_system/Makefile index 857b523..14a8b82 100644 --- a/soc/software/gps_system/Makefile +++ b/soc/software/gps_system/Makefile @@ -102,7 +102,9 @@ GPS_EPHEMERIS_FLASH_ENABLE ?= 1 GPS_EPHEMERIS_STORE_MAX_SLOTS ?= 0 GPS_EPHEMERIS_FLASH_FORCE_FORMAT ?= 0 GPS_EPHEMERIS_FLASH_SEED_INITIAL ?= 1 +GPS_EPHEMERIS_FLASH_BASE ?= 0x01fe0000 GPS_NAV_CONTEXT_ENABLE ?= 1 +GPS_NAV_CONTEXT_FLASH_BASE ?= 0x01fc0000 GPS_PPS_STATUS_LOG_INTERVAL ?= 10 GPS_PPS_DOPPLER_PREDICTOR_ENABLE ?= 1 GPS_PPS_DOPPLER_PREDICTOR_AB_UPDATES ?= 0 @@ -123,7 +125,9 @@ CFLAGS += $(IMU_BACKEND_CFLAG) \ -DGPS_EPHEMERIS_STORE_MAX_SLOTS=$(GPS_EPHEMERIS_STORE_MAX_SLOTS)u \ -DGPS_EPHEMERIS_FLASH_FORCE_FORMAT=$(GPS_EPHEMERIS_FLASH_FORCE_FORMAT) \ -DGPS_EPHEMERIS_FLASH_SEED_INITIAL=$(GPS_EPHEMERIS_FLASH_SEED_INITIAL) \ + -DGPS_EPHEMERIS_FLASH_BASE=$(GPS_EPHEMERIS_FLASH_BASE)UL \ -DGPS_NAV_CONTEXT_ENABLE=$(GPS_NAV_CONTEXT_ENABLE) \ + -DGPS_NAV_CONTEXT_FLASH_BASE=$(GPS_NAV_CONTEXT_FLASH_BASE)UL \ -DGPS_PPS_STATUS_LOG_INTERVAL=$(GPS_PPS_STATUS_LOG_INTERVAL) \ -DGPS_PPS_DOPPLER_PREDICTOR_ENABLE=$(GPS_PPS_DOPPLER_PREDICTOR_ENABLE) \ -DGPS_PPS_DOPPLER_PREDICTOR_AB_UPDATES=$(GPS_PPS_DOPPLER_PREDICTOR_AB_UPDATES) diff --git a/soc/software/gps_system/header/gps/gps_ip_defines.h b/soc/software/gps_system/header/gps/gps_ip_defines.h index 81ac602..99b6828 100644 --- a/soc/software/gps_system/header/gps/gps_ip_defines.h +++ b/soc/software/gps_system/header/gps/gps_ip_defines.h @@ -144,10 +144,9 @@ * 20 ms navigation bit; at a few ppm the 15 minute bound leaves * roughly two orders of magnitude of margin, and broadcast * ephemeris validity caps reuse well before that anyway. */ - /* Persistent ephemeris cache. The Genesys2 image places the - * bitstream at 0 and the application at 0x01800000 on a 32 MiB - * S25FL256S, so the last two 64 KiB sectors are free. Keeping the - * store at the very top leaves the application region free to grow. */ + /* Persistent ephemeris cache. Board Makefiles place this store in + * two reserved 64 KiB sectors near the top of the selected flash. + * The defaults describe the 32 MiB Genesys2 layout. */ #ifndef GPS_EPHEMERIS_FLASH_ENABLE #define GPS_EPHEMERIS_FLASH_ENABLE 1 #endif @@ -170,8 +169,8 @@ /* * Persistent navigation context (almanac, ionosphere model, last * position) in the two 64 KiB sectors immediately below the - * ephemeris store. The application image lives at 0x01800000 and - * is far smaller than the gap. + * ephemeris store. Board Makefiles override both bases together for + * larger flash devices. */ #ifndef GPS_NAV_CONTEXT_FLASH_BASE #define GPS_NAV_CONTEXT_FLASH_BASE 0x01FC0000UL diff --git a/soc/software/gps_system/src/gps/gps_interrupt_handlers.c b/soc/software/gps_system/src/gps/gps_interrupt_handlers.c index be3a86d..4207b74 100644 --- a/soc/software/gps_system/src/gps/gps_interrupt_handlers.c +++ b/soc/software/gps_system/src/gps/gps_interrupt_handlers.c @@ -16,6 +16,30 @@ #include #include +#if (GPS_EPHEMERIS_FLASH_ENABLE == 1) +_Static_assert((GPS_EPHEMERIS_FLASH_BASE % BSP_SPI_FLASH_SECTOR_SIZE) == 0u, + "ephemeris flash base must be sector aligned"); +_Static_assert(GPS_EPHEMERIS_FLASH_BASE <= + (BSP_SPI_FLASH_SIZE - (2u * BSP_SPI_FLASH_SECTOR_SIZE)), + "ephemeris store exceeds selected flash"); +#endif +#if (GPS_NAV_CONTEXT_ENABLE == 1) +_Static_assert((GPS_NAV_CONTEXT_FLASH_BASE % BSP_SPI_FLASH_SECTOR_SIZE) == 0u, + "navigation context flash base must be sector aligned"); +_Static_assert(GPS_NAV_CONTEXT_FLASH_BASE <= + (BSP_SPI_FLASH_SIZE - (2u * BSP_SPI_FLASH_SECTOR_SIZE)), + "navigation context store exceeds selected flash"); +#endif +#if ((GPS_EPHEMERIS_FLASH_ENABLE == 1) && (GPS_NAV_CONTEXT_ENABLE == 1)) +_Static_assert((GPS_NAV_CONTEXT_FLASH_BASE + + (2u * BSP_SPI_FLASH_SECTOR_SIZE) <= + GPS_EPHEMERIS_FLASH_BASE) || + (GPS_EPHEMERIS_FLASH_BASE + + (2u * BSP_SPI_FLASH_SECTOR_SIZE) <= + GPS_NAV_CONTEXT_FLASH_BASE), + "persistent flash stores overlap"); +#endif + typedef enum { GPS_ISR_EVENT_ACQ_DONE = 0, GPS_ISR_EVENT_TRK_STATUS diff --git a/targets/fpga/genesys2/Makefile b/targets/fpga/genesys2/Makefile index 617ee16..213e268 100644 --- a/targets/fpga/genesys2/Makefile +++ b/targets/fpga/genesys2/Makefile @@ -72,7 +72,10 @@ GPS_DEBUG_LEVEL ?= 1 GPS_ESKF_ENABLE ?= 1 GPS_EPHEMERIS_FLASH_ENABLE ?= 1 GPS_EPHEMERIS_FLASH_SEED_INITIAL ?= 1 +GPS_EPHEMERIS_FLASH_BASE ?= 0x01fe0000 GPS_NAV_CONTEXT_ENABLE ?= 1 +GPS_NAV_CONTEXT_FLASH_BASE ?= 0x01fc0000 +BSP_SPI_FLASH_PROFILE ?= 1 IMU_SENSOR ?= auto FLASH_MCS ?= $(OUT_DIR)/flash/genesys2_rocket.mcs @@ -180,7 +183,10 @@ help: ' GPS_ESKF_ENABLE=$(GPS_ESKF_ENABLE)' \ ' GPS_EPHEMERIS_FLASH_ENABLE=$(GPS_EPHEMERIS_FLASH_ENABLE)' \ ' GPS_EPHEMERIS_FLASH_SEED_INITIAL=$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)' \ + ' GPS_EPHEMERIS_FLASH_BASE=$(GPS_EPHEMERIS_FLASH_BASE)' \ ' GPS_NAV_CONTEXT_ENABLE=$(GPS_NAV_CONTEXT_ENABLE)' \ + ' GPS_NAV_CONTEXT_FLASH_BASE=$(GPS_NAV_CONTEXT_FLASH_BASE)' \ + ' BSP_SPI_FLASH_PROFILE=$(BSP_SPI_FLASH_PROFILE)' \ ' IMU_SENSOR=$(IMU_SENSOR)' \ ' UART_PORT=$(UART_PORT)' \ ' ETH_RF_IFACE=$(ETH_RF_IFACE)' \ @@ -222,17 +228,20 @@ fpga-config: ' GPS_ESKF_ENABLE=$(GPS_ESKF_ENABLE)' \ ' GPS_EPHEMERIS_FLASH_ENABLE=$(GPS_EPHEMERIS_FLASH_ENABLE)' \ ' GPS_EPHEMERIS_FLASH_SEED_INITIAL=$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)' \ + ' GPS_EPHEMERIS_FLASH_BASE=$(GPS_EPHEMERIS_FLASH_BASE)' \ ' GPS_NAV_CONTEXT_ENABLE=$(GPS_NAV_CONTEXT_ENABLE)' \ + ' GPS_NAV_CONTEXT_FLASH_BASE=$(GPS_NAV_CONTEXT_FLASH_BASE)' \ + ' BSP_SPI_FLASH_PROFILE=$(BSP_SPI_FLASH_PROFILE)' \ ' IMU_SENSOR=$(IMU_SENSOR)' \ ' ETH_RF_IFACE=$(ETH_RF_IFACE)' \ ' ETH_RF_INPUT=$(ETH_RF_INPUT)' \ ' ETH_RF_SAMPLE_FORMAT=$(ETH_RF_SAMPLE_FORMAT)' software: - @$(MAKE_BIN) -C "$(SOC_SW_DIR)" TOOLCHAIN="$(TOOLCHAIN)" APP="$(APP)" APP_FLASH_OFFSET="$(APP_FLASH_OFFSET)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_DTIM_BASE="$(DTIM_BASE)" BSP_DTIM_SIZE="$(DTIM_SIZE)" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" GPS_ESKF_ENABLE="$(GPS_ESKF_ENABLE)" GPS_EPHEMERIS_FLASH_ENABLE="$(GPS_EPHEMERIS_FLASH_ENABLE)" GPS_EPHEMERIS_FLASH_SEED_INITIAL="$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)" GPS_NAV_CONTEXT_ENABLE="$(GPS_NAV_CONTEXT_ENABLE)" IMU_SENSOR="$(IMU_SENSOR)" bootloader flash-image + @$(MAKE_BIN) -C "$(SOC_SW_DIR)" TOOLCHAIN="$(TOOLCHAIN)" APP="$(APP)" APP_FLASH_OFFSET="$(APP_FLASH_OFFSET)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_SPI_FLASH_PROFILE="$(BSP_SPI_FLASH_PROFILE)" BSP_DTIM_BASE="$(DTIM_BASE)" BSP_DTIM_SIZE="$(DTIM_SIZE)" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" GPS_ESKF_ENABLE="$(GPS_ESKF_ENABLE)" GPS_EPHEMERIS_FLASH_ENABLE="$(GPS_EPHEMERIS_FLASH_ENABLE)" GPS_EPHEMERIS_FLASH_SEED_INITIAL="$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)" GPS_EPHEMERIS_FLASH_BASE="$(GPS_EPHEMERIS_FLASH_BASE)" GPS_NAV_CONTEXT_ENABLE="$(GPS_NAV_CONTEXT_ENABLE)" GPS_NAV_CONTEXT_FLASH_BASE="$(GPS_NAV_CONTEXT_FLASH_BASE)" IMU_SENSOR="$(IMU_SENSOR)" bootloader flash-image $(APP_ELF): FORCE - @$(MAKE_BIN) -C "$(SOC_SW_DIR)" TOOLCHAIN="$(TOOLCHAIN)" APP="$(APP)" APP_FLASH_OFFSET="$(APP_FLASH_OFFSET)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_DTIM_BASE="$(DTIM_BASE)" BSP_DTIM_SIZE="$(DTIM_SIZE)" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" GPS_ESKF_ENABLE="$(GPS_ESKF_ENABLE)" GPS_EPHEMERIS_FLASH_ENABLE="$(GPS_EPHEMERIS_FLASH_ENABLE)" GPS_EPHEMERIS_FLASH_SEED_INITIAL="$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)" GPS_NAV_CONTEXT_ENABLE="$(GPS_NAV_CONTEXT_ENABLE)" IMU_SENSOR="$(IMU_SENSOR)" app + @$(MAKE_BIN) -C "$(SOC_SW_DIR)" TOOLCHAIN="$(TOOLCHAIN)" APP="$(APP)" APP_FLASH_OFFSET="$(APP_FLASH_OFFSET)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_SPI_FLASH_PROFILE="$(BSP_SPI_FLASH_PROFILE)" BSP_DTIM_BASE="$(DTIM_BASE)" BSP_DTIM_SIZE="$(DTIM_SIZE)" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" GPS_ESKF_ENABLE="$(GPS_ESKF_ENABLE)" GPS_EPHEMERIS_FLASH_ENABLE="$(GPS_EPHEMERIS_FLASH_ENABLE)" GPS_EPHEMERIS_FLASH_SEED_INITIAL="$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)" GPS_EPHEMERIS_FLASH_BASE="$(GPS_EPHEMERIS_FLASH_BASE)" GPS_NAV_CONTEXT_ENABLE="$(GPS_NAV_CONTEXT_ENABLE)" GPS_NAV_CONTEXT_FLASH_BASE="$(GPS_NAV_CONTEXT_FLASH_BASE)" IMU_SENSOR="$(IMU_SENSOR)" app chisel: software @cd "$(REPO_DIR)" diff --git a/targets/fpga/genesys2/out/bitstream/vivado.jou b/targets/fpga/genesys2/out/bitstream/vivado.jou deleted file mode 100644 index ffd9628..0000000 --- a/targets/fpga/genesys2/out/bitstream/vivado.jou +++ /dev/null @@ -1,24 +0,0 @@ -#----------------------------------------------------------- -# Vivado v2025.2 (64-bit) -# SW Build 6299465 on Fri Nov 14 12:34:56 MST 2025 -# IP Build 6300035 on Fri Nov 14 10:48:45 MST 2025 -# SharedData Build 6298862 on Thu Nov 13 04:50:51 MST 2025 -# Start of session at: Tue Jul 7 01:14:33 2026 -# Process ID : 505349 -# Current directory : /home/onur/Desktop/tmp/rocket-chip/targets/fpga/genesys2/out/bitstream -# Command line : vivado -# Log file : /home/onur/Desktop/tmp/rocket-chip/targets/fpga/genesys2/out/bitstream/vivado.log -# Journal file : /home/onur/Desktop/tmp/rocket-chip/targets/fpga/genesys2/out/bitstream/vivado.jou -# Running On : onur -# Platform : Ubuntu -# Operating System : Ubuntu 22.04.5 LTS -# Processor Detail : AMD Ryzen 7 7800X3D 8-Core Processor -# CPU Frequency : 4199.900 MHz -# CPU Physical cores : 12 -# CPU Logical cores : 12 -# Host memory : 22112 MB -# Swap memory : 2147 MB -# Total Virtual : 24260 MB -# Available Virtual : 20472 MB -#----------------------------------------------------------- -start_gui diff --git a/targets/fpga/genesys2/out/bitstream/vivado.log b/targets/fpga/genesys2/out/bitstream/vivado.log deleted file mode 100644 index 1df371f..0000000 --- a/targets/fpga/genesys2/out/bitstream/vivado.log +++ /dev/null @@ -1,118 +0,0 @@ -#----------------------------------------------------------- -# Vivado v2025.2 (64-bit) -# SW Build 6299465 on Fri Nov 14 12:34:56 MST 2025 -# IP Build 6300035 on Fri Nov 14 10:48:45 MST 2025 -# SharedData Build 6298862 on Thu Nov 13 04:50:51 MST 2025 -# Start of session at: Tue Jul 7 01:14:33 2026 -# Process ID : 505349 -# Current directory : /home/onur/Desktop/tmp/rocket-chip/targets/fpga/genesys2/out/bitstream -# Command line : vivado -# Log file : /home/onur/Desktop/tmp/rocket-chip/targets/fpga/genesys2/out/bitstream/vivado.log -# Journal file : /home/onur/Desktop/tmp/rocket-chip/targets/fpga/genesys2/out/bitstream/vivado.jou -# Running On : onur -# Platform : Ubuntu -# Operating System : Ubuntu 22.04.5 LTS -# Processor Detail : AMD Ryzen 7 7800X3D 8-Core Processor -# CPU Frequency : 4199.900 MHz -# CPU Physical cores : 12 -# CPU Logical cores : 12 -# Host memory : 22112 MB -# Swap memory : 2147 MB -# Total Virtual : 24260 MB -# Available Virtual : 20472 MB -#----------------------------------------------------------- -start_gui -Sourcing tcl script '/home/onur/.Xilinx/Vivado/Vivado_init.tcl' -Configured Digilent board repo: /home/onur/.local/share/digilent-vivado-boards/new/board_files -WARNING: [Board 49-26] cannot add Board Part digilentinc.com:gzu_3eg:part0:1.0 available at /home/onur/.local/share/digilent-vivado-boards/new/board_files/genesys-zu-3eg/B.0/board.xml as part xczu3eg-sfvc784-1-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part digilentinc.com:gzu_3eg:part0:1.1 available at /home/onur/.local/share/digilent-vivado-boards/new/board_files/genesys-zu-3eg/D.0/board.xml as part xczu3eg-sfvc784-1-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part digilentinc.com:gzu_5ev:part0:1.1 available at /home/onur/.local/share/digilent-vivado-boards/new/board_files/genesys-zu-5ev/C.0/board.xml as part xczu5ev-sfvc784-1-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:emb-plus-vpr-4616:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/emb-plus-vpr-4616/1.0/board.xml as part xcve2302-sfva784-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:emb-plus-vpr-4616:part0:1.1 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/emb-plus-vpr-4616/1.1/board.xml as part xcve2302-sfva784-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:k24c:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/k24c/1.0/board.xml as part xck24-ubva530-2lv-c specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:k24c:part0:1.1 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/k24c/1.1/board.xml as part xck24-ubva530-2lv-c specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:k24i:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/k24i/1.0/board.xml as part xck24-ubva530-2lvi-i specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:k26c:part0:1.2 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/k26c/1.2/board.xml as part xck26-sfvc784-2lv-c specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:k26c:part0:1.3 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/k26c/1.3/board.xml as part xck26-sfvc784-2lv-c specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:k26c:part0:1.4 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/k26c/1.4/board.xml as part xck26-sfvc784-2lv-c specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:k26i:part0:1.2 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/k26i/1.2/board.xml as part xck26-sfvc784-2lvi-i specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:k26i:part0:1.3 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/k26i/1.3/board.xml as part xck26-sfvc784-2lvi-i specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:k26i:part0:1.4 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/k26i/1.4/board.xml as part xck26-sfvc784-2lvi-i specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:kcu105:part0:1.6 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/kcu105/1.6/board.xml as part xcku040-ffva1156-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:kcu105:part0:1.7 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/kcu105/1.7/board.xml as part xcku040-ffva1156-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:kcu116:part0:1.4 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/kcu116/1.4/board.xml as part xcku5p-ffvb676-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:kcu116:part0:1.5 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/kcu116/1.5/board.xml as part xcku5p-ffvb676-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:kcu1500:part0:1.2 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/kcu1500/1.2/board.xml as part xcku115-flvb2104-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:kd240_som:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/kd240_som/1.0/board.xml as part xck24-ubva530-2lv-c specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:kd240_som:part0:1.1 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/kd240_som/1.1/board.xml as part xck24-ubva530-2lv-c specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:kr260_som:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/kr260_som/1.0/board.xml as part xck26-sfvc784-2lv-c specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:kr260_som:part0:1.1 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/kr260_som/1.1/board.xml as part xck26-sfvc784-2lv-c specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:kv260_som:part0:1.2 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/kv260_som/1.2/board.xml as part xck26-sfvc784-2lv-c specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:kv260_som:part0:1.3 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/kv260_som/1.3/board.xml as part xck26-sfvc784-2lv-c specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:kv260_som:part0:1.4 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/kv260_som/1.4/board.xml as part xck26-sfvc784-2lv-c specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:scu35:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/scu35/1.0/board.xml as part xcsu35p-sbvb625-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:v80:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/v80/1.0/board.xml as part xcv80-lsva4737-2mhp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vck190:part0:2.2 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vck190/production/2.2/board.xml as part xcvc1902-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vck190:part0:3.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vck190/production/3.0/board.xml as part xcvc1902-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vck190:part0:3.1 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vck190/production/3.1/board.xml as part xcvc1902-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vck190:part0:3.2 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vck190/production/3.2/board.xml as part xcvc1902-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vck190:part0:3.3 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vck190/production/3.3/board.xml as part xcvc1902-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vck190:part0:3.4 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vck190/production/3.4/board.xml as part xcvc1902-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vck190_newl:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vck190_newl/production/1.0/board.xml as part xcvc1902-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vck190_newl:part0:1.1 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vck190_newl/production/1.1/board.xml as part xcvc1902-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vck190_newl:part0:1.2 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vck190_newl/production/1.2/board.xml as part xcvc1902-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vck190_newl:part0:1.3 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vck190_newl/production/1.3/board.xml as part xcvc1902-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vcu108:part0:1.6 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vcu108/1.6/board.xml as part xcvu095-ffva2104-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vcu108:part0:1.7 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vcu108/1.7/board.xml as part xcvu095-ffva2104-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vcu110:part0:1.4 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vcu110/1.4/board.xml as part xcvu190-flgc2104-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vcu118:part0:2.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vcu118/2.0/board.xml as part xcvu9p-flga2104-2l-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vcu118:part0:2.3 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vcu118/2.3/board.xml as part xcvu9p-flga2104-2l-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vcu118:part0:2.4 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vcu118/2.4/board.xml as part xcvu9p-flga2104-2l-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vcu128:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vcu128/production/1.0/board.xml as part xcvu37p-fsvh2892-2l-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vcu129:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vcu129/production/1.0/board.xml as part xcvu29p-fsga2577-2l-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vcu1525:part0:1.3 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vcu1525/1.3/board.xml as part xcvu9p-fsgd2104-2l-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vek280:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vek280/production/1.0/board.xml as part xcve2802-vsvh1760-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vek280:part0:1.1 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vek280/production/1.1/board.xml as part xcve2802-vsvh1760-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vek280:part0:1.2 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vek280/production/1.2/board.xml as part xcve2802-vsvh1760-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vek385:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vek385/1.0/board.xml as part xc2ve3858-ssva2112-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vek385:part0:1.1 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vek385/1.1/board.xml as part xc2ve3858-ssva2112-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vek385_1:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vek385_2/1.0/board.xml as part xc2ve3858-ssva2112-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vermeo_t1_mpsoc:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vermeo_t1_mpsoc/1.0/board.xml as part xczu19eg-ffvd1760-2l-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vermeo_t1_rfsoc:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vermeo_t1_rfsoc/1.0/board.xml as part xczu21dr-ffvd1156-2l-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vhk158:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vhk158/production/1.0/board.xml as part xcvh1582-vsva3697-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vhk158:part0:1.1 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vhk158/production/1.1/board.xml as part xcvh1582-vsva3697-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vhk158:part0:1.2 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vhk158/production/1.2/board.xml as part xcvh1582-vsva3697-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vmk180:part0:2.2 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vmk180/production/2.2/board.xml as part xcvm1802-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vmk180:part0:3.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vmk180/production/3.0/board.xml as part xcvm1802-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vmk180:part0:3.1 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vmk180/production/3.1/board.xml as part xcvm1802-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vmk180:part0:3.2 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vmk180/production/3.2/board.xml as part xcvm1802-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vmk180:part0:3.3 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vmk180/production/3.3/board.xml as part xcvm1802-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vmk180_newl:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vmk180_newl/production/1.0/board.xml as part xcvm1802-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vmk180_newl:part0:1.1 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vmk180_newl/production/1.1/board.xml as part xcvm1802-vsva2197-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vpk120:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vpk120/production/1.0/board.xml as part xcvp1202-vsva2785-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vpk120:part0:1.1 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vpk120/production/1.1/board.xml as part xcvp1202-vsva2785-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vpk120:part0:1.2 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vpk120/production/1.2/board.xml as part xcvp1202-vsva2785-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vpk180:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vpk180/production/1.0/board.xml as part xcvp1802-lsvc4072-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vpk180:part0:1.1 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vpk180/production/1.1/board.xml as part xcvp1802-lsvc4072-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vpk180:part0:1.2 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vpk180/production/1.2/board.xml as part xcvp1802-lsvc4072-2mp-e-s specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vrk160:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vrk160/1.0/board.xml as part xcvr1602-vsva2488-2mp-e-s-es1 specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:vrk160:part0:1.1 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/vrk160/1.1/board.xml as part xcvr1602-vsva2488-2mp-e-s-es1 specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu102:part0:3.3 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu102/3.3/board.xml as part xczu9eg-ffvb1156-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu102:part0:3.4 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu102/3.4/board.xml as part xczu9eg-ffvb1156-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu104:part0:1.1 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu104/1.1/board.xml as part xczu7ev-ffvc1156-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu106:part0:2.4 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu106/2.4/board.xml as part xczu7ev-ffvc1156-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu106:part0:2.5 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu106/2.5/board.xml as part xczu7ev-ffvc1156-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu106:part0:2.6 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu106/2.6/board.xml as part xczu7ev-ffvc1156-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu111:part0:1.2 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu111/1.2/board.xml as part xczu28dr-ffvg1517-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu111:part0:1.3 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu111/1.3/board.xml as part xczu28dr-ffvg1517-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu111:part0:1.4 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu111/1.4/board.xml as part xczu28dr-ffvg1517-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu1275:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu1275/1.0/board.xml as part xczu29dr-ffvf1760-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu1285:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu1285/1.0/board.xml as part xczu39dr-ffvf1760-2-i specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu208:part0:2.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu208/production/2.0/board.xml as part xczu48dr-fsvg1517-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu208ld:part0:2.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu208ld/production/2.0/board.xml as part xczu58dr-fsvg1517-2-i specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu216:part0:2.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu216/production/2.0/board.xml as part xczu49dr-ffvf1760-2-e specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu216ld:part0:2.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu216ld/production/2.0/board.xml as part xczu59dr-ffvf1760-2-i specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu670:part0:2.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu670/2.0/board.xml as part xczu67dr-fsve1156-2-i specified in board_part file is either invalid or not available -WARNING: [Board 49-26] cannot add Board Part xilinx.com:zcu670ld:part0:1.0 available at /tools/Xilinx/2025.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx/zcu670ld/1.0/board.xml as part xczu57dr-fsve1156-2-i specified in board_part file is either invalid or not available -exit -INFO: [Common 17-206] Exiting Vivado at Tue Jul 7 01:14:42 2026... diff --git a/targets/fpga/ti375c529/.gitignore b/targets/fpga/ti375c529/.gitignore new file mode 100644 index 0000000..21d7d8e --- /dev/null +++ b/targets/fpga/ti375c529/.gitignore @@ -0,0 +1,12 @@ +/out/ +/flow/efinity/ti375c529_rocket.isf +/flow/efinity/ti375c529_rocket.peri.xml +/flow/efinity/ti375c529_rocket.pt.sdc +/flow/efinity/ti375c529_rocket.pt.rpt +/flow/efinity/ti375c529_rocket.pinout.* +/flow/efinity/ti375c529_rocket.interface.csv +/flow/efinity/ti375c529_rocket_template.v +/flow/efinity/outflow/ +/flow/efinity/work_pnr/ +/flow/efinity/work_syn/ +/flow/efinity/RUNPNR_* diff --git a/targets/fpga/ti375c529/Makefile b/targets/fpga/ti375c529/Makefile new file mode 100644 index 0000000..9b4ba14 --- /dev/null +++ b/targets/fpga/ti375c529/Makefile @@ -0,0 +1,438 @@ +SHELL := /bin/bash +.SHELLFLAGS := -euo pipefail -c +.ONESHELL: + +FPGA_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +REPO_DIR := $(abspath $(FPGA_DIR)/../../..) +SOC_SW_DIR := $(REPO_DIR)/soc/software +SOC_OUT_DIR := $(REPO_DIR)/soc/out +HW_DIR := $(REPO_DIR)/hardware +HW_GENERATED_DIR := $(HW_DIR)/generated +GPS_SYSTEM_DIR ?= $(HW_DIR)/external/gps/rtl +FLOW_DIR := $(FPGA_DIR)/flow/efinity +DEBUG_DIR := $(FPGA_DIR)/flow/debug +TOOL_SCRIPT_DIR := $(FPGA_DIR)/tools +OUT_DIR := $(FPGA_DIR)/out +LOG_DIR := $(OUT_DIR)/logs + +include $(REPO_DIR)/tools/project.mk + +BOARD ?= ti375c529 +DEVICE ?= Ti375C529 +TIMING_MODEL ?= C4 +SOC_CLK_HZ ?= 100000000 +GPS_ACQ_CLK_HZ ?= 100000000 +GPS_TRCK_CLK_HZ ?= 125000000 +GPS_RF_CLK_HZ ?= 16367981 +RF_INPUT_MODE ?= pmod +UART_PORT ?= /dev/ttyUSB2 +UART_BAUD ?= 460800 +OPENOCD ?= $(shell command -v openocd) +OPENOCD_ADAPTER_SPEED ?= 1000 +GDB_HOST ?= localhost +GDB_PORT ?= 3333 +GDB ?= $(firstword $(wildcard /tools/toolchain/bin/riscv64-unknown-elf-gdb) $(CROSS)gdb) +# Leave empty for Efinity's board-profile auto-detection. Boards without an +# FTDI serial number require a bus/device-qualified URL, which changes after +# re-enumeration; users with multiple boards can override this explicitly. +FTDI_URL ?= +BSP_UART_CLOCK_HZ ?= $(SOC_CLK_HZ) +BSP_UART_BAUDRATE ?= $(UART_BAUD) +BSP_CLINT_TIMEBASE_HZ ?= 1000000 +DTIM_BASE ?= 0x80000000 +DTIM_SIZE ?= 0x00100000 +# The compressed Ti375 configuration currently occupies about 5.2 MB. +# Keep the application on a 64-KiB boundary with ample growth margin. +APP_FLASH_OFFSET ?= 0x00800000 +FLASH_SIZE ?= 0x04000000 +GPS_DEBUG ?= 1 +GPS_DEBUG_LEVEL ?= 4 +GPS_ESKF_ENABLE ?= 1 +GPS_EPHEMERIS_FLASH_ENABLE ?= 1 +GPS_EPHEMERIS_FLASH_SEED_INITIAL ?= 1 +GPS_EPHEMERIS_FLASH_BASE ?= 0x03fe0000 +GPS_NAV_CONTEXT_ENABLE ?= 1 +GPS_NAV_CONTEXT_FLASH_BASE ?= 0x03fc0000 +BSP_SPI_FLASH_PROFILE ?= 3 +IMU_SENSOR ?= auto +app ?= +ifneq ($(strip $(app)),) +APP ?= $(app) +else +APP ?= hello_uart +endif + +FIRRTL_DIR ?= $(HW_GENERATED_DIR)/ti375c529-soc +VERILOG_DIR ?= $(HW_GENERATED_DIR)/ti375c529-soc-verilog +WRAPPER := $(OUT_DIR)/build/generated/ti375c529_rocket_top.sv +GPS_EFINITY_DIR := $(OUT_DIR)/build/generated/gps_efinity +SOURCE_LIST := $(OUT_DIR)/build/efinity_sources.f +PROJECT_XML := $(FLOW_DIR)/ti375c529_rocket.xml +INTERFACE_SOURCE := $(HW_DIR)/fpga/ti375c529/constraints/ti375c529_rocket.isf +INTERFACE_SCRIPT := $(FLOW_DIR)/ti375c529_rocket.isf +BIT_FILE ?= $(OUT_DIR)/bitstream/ti375c529_rocket.bit +CONFIG_HEX ?= $(OUT_DIR)/bitstream/ti375c529_rocket.hex +APP_ELF ?= $(SOC_OUT_DIR)/software/$(APP)/$(APP).elf +APP_FLASH_IMAGE ?= $(SOC_OUT_DIR)/flash/$(APP).flash.bin +FLASH_DIR := $(OUT_DIR)/flash +FLASH_REGION_DIR := $(FLASH_DIR)/regions +APP_HEX ?= $(FLASH_REGION_DIR)/app.hex +FLASH_HEX ?= $(FLASH_DIR)/ti375c529_rocket.hex +FLASH_MANIFEST ?= $(FLASH_DIR)/ti375c529_rocket.json +FLASH_LOADER ?= $(EFINITY_HOME)/pgm/fli/titanium/u006A0A79.bit +FLASH_VERIFY ?= onchipx2 +OPENOCD_CFG ?= $(DEBUG_DIR)/openocd_ti375c529_bscan.cfg +GDB_LOAD_SCRIPT ?= $(DEBUG_DIR)/gdb_load_and_run.gdb +GDB_ATTACH_SCRIPT ?= $(DEBUG_DIR)/gdb_attach.gdb + +.PHONY: help all fpga-config detect software chisel rtl soc interface map bitstream \ + program-fpga debug-openocd debug-load debug-gdb uart-listen \ + flash-image flash-regions program-flash program-flash-elf \ + program-flash-bitstream program-flash-regions program-flash-all \ + program-flash-combined program-flash-loader program-app program-bitstream \ + clean clean-sw clean-fpga FORCE + +help: + @printf '%s\n' \ + 'Ti375C529 Efinity targets:' \ + ' make detect Scan USB and read the Ti375 JTAG IDCODE' \ + ' make software Build the Rocket boot ROM and selected RV64 app' \ + ' make chisel Emit Rocket FIRRTL with the existing FPGA config' \ + ' make rtl Emit split SystemVerilog, Efinix shell, and file list' \ + ' make interface Generate Efinity pin/PLL/JTAG interface data' \ + ' make map Run Efinity synthesis only' \ + ' make bitstream Run the complete Efinity flow' \ + ' make program-fpga Load BIT_FILE into Ti375 SRAM over JTAG' \ + ' make flash-image Generate combined Lower-flash Efinity HEX' \ + ' make program-flash Program only the application flash region' \ + ' make program-flash-bitstream' \ + ' Program only the configuration region' \ + ' make program-flash-combined' \ + ' Program configuration + application HEX' \ + ' make debug-openocd Start Rocket DMI/GDB server through JTAG_USER1' \ + ' make debug-load Load APP ELF into DTIM through GDB' \ + ' make uart-listen Listen to FTDI UART interface 2' \ + ' make fpga-config Print resolved tools, clocks, files, and USB config' + +all: bitstream + +fpga-config: + @printf '%s\n' \ + 'Ti375C529 FPGA config:' \ + ' EFINITY_HOME=$(EFINITY_HOME)' \ + ' EFX_RUN=$(EFX_RUN)' \ + ' EFX_PGM=$(EFX_PGM)' \ + ' OPENOCD=$(OPENOCD)' \ + ' GDB=$(GDB)' \ + ' DEVICE=$(DEVICE)' \ + ' TIMING_MODEL=$(TIMING_MODEL)' \ + ' SOC_CLK_HZ=$(SOC_CLK_HZ)' \ + ' GPS_ACQ_CLK_HZ=$(GPS_ACQ_CLK_HZ)' \ + ' GPS_TRCK_CLK_HZ=$(GPS_TRCK_CLK_HZ)' \ + ' GPS_RF_CLK_HZ=$(GPS_RF_CLK_HZ)' \ + ' RF_INPUT_MODE=$(RF_INPUT_MODE)' \ + ' BIT_FILE=$(BIT_FILE)' \ + ' CONFIG_HEX=$(CONFIG_HEX)' \ + ' FLASH_HEX=$(FLASH_HEX)' \ + ' APP_FLASH_OFFSET=$(APP_FLASH_OFFSET)' \ + ' GPS_EPHEMERIS_FLASH_ENABLE=$(GPS_EPHEMERIS_FLASH_ENABLE)' \ + ' GPS_EPHEMERIS_FLASH_SEED_INITIAL=$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)' \ + ' GPS_EPHEMERIS_FLASH_BASE=$(GPS_EPHEMERIS_FLASH_BASE)' \ + ' GPS_NAV_CONTEXT_ENABLE=$(GPS_NAV_CONTEXT_ENABLE)' \ + ' GPS_NAV_CONTEXT_FLASH_BASE=$(GPS_NAV_CONTEXT_FLASH_BASE)' \ + ' BSP_SPI_FLASH_PROFILE=$(BSP_SPI_FLASH_PROFILE)' \ + ' FLASH_LOADER=$(FLASH_LOADER)' \ + ' FTDI_URL=$(FTDI_URL)' \ + ' UART_PORT=$(UART_PORT)' \ + ' UART_BAUD=$(UART_BAUD)' + +detect: + @set +u + source "$(EFINITY_SETUP)" >/dev/null 2>&1 + set -u + "$(EFX_PGM)" --scan_usb + +software: + @$(MAKE) -C "$(SOC_SW_DIR)" \ + TOOLCHAIN="$(TOOLCHAIN)" APP="$(APP)" \ + APP_FLASH_OFFSET="$(APP_FLASH_OFFSET)" \ + BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" \ + BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" \ + GPS_SYSTEM_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" \ + BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" \ + BSP_DTIM_BASE="$(DTIM_BASE)" BSP_DTIM_SIZE="$(DTIM_SIZE)" \ + GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" \ + GPS_ESKF_ENABLE="$(GPS_ESKF_ENABLE)" \ + GPS_EPHEMERIS_FLASH_ENABLE="$(GPS_EPHEMERIS_FLASH_ENABLE)" \ + GPS_EPHEMERIS_FLASH_SEED_INITIAL="$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)" \ + GPS_EPHEMERIS_FLASH_BASE="$(GPS_EPHEMERIS_FLASH_BASE)" \ + GPS_NAV_CONTEXT_ENABLE="$(GPS_NAV_CONTEXT_ENABLE)" \ + GPS_NAV_CONTEXT_FLASH_BASE="$(GPS_NAV_CONTEXT_FLASH_BASE)" \ + BSP_SPI_FLASH_PROFILE="$(BSP_SPI_FLASH_PROFILE)" \ + IMU_SENSOR="$(IMU_SENSOR)" \ + bootloader flash-image + +$(APP_ELF): FORCE + @$(MAKE) -C "$(SOC_SW_DIR)" \ + TOOLCHAIN="$(TOOLCHAIN)" APP="$(APP)" \ + BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" \ + BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" \ + GPS_SYSTEM_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" \ + BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" \ + BSP_DTIM_BASE="$(DTIM_BASE)" BSP_DTIM_SIZE="$(DTIM_SIZE)" \ + GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" \ + GPS_ESKF_ENABLE="$(GPS_ESKF_ENABLE)" \ + GPS_EPHEMERIS_FLASH_ENABLE="$(GPS_EPHEMERIS_FLASH_ENABLE)" \ + GPS_EPHEMERIS_FLASH_SEED_INITIAL="$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)" \ + GPS_EPHEMERIS_FLASH_BASE="$(GPS_EPHEMERIS_FLASH_BASE)" \ + GPS_NAV_CONTEXT_ENABLE="$(GPS_NAV_CONTEXT_ENABLE)" \ + GPS_NAV_CONTEXT_FLASH_BASE="$(GPS_NAV_CONTEXT_FLASH_BASE)" \ + BSP_SPI_FLASH_PROFILE="$(BSP_SPI_FLASH_PROFILE)" \ + IMU_SENSOR="$(IMU_SENSOR)" app + +chisel: software + @cd "$(REPO_DIR)" + "$(MILL)" -i 'rocketchip[6.7.0].assembly' + rm -rf "$(FIRRTL_DIR)" + mkdir -p "$(FIRRTL_DIR)" + "$(JAVA_HOME)/bin/java" \ + -DROCKET_DTIM_BASE="$(DTIM_BASE)" \ + -DROCKET_DTIM_SIZE="$(DTIM_SIZE)" \ + -DROCKET_SOC_CLOCK_HZ="$(SOC_CLK_HZ)" \ + -jar out/rocketchip/6.7.0/assembly.dest/out.jar \ + --dir "$(FIRRTL_DIR)" \ + --top freechips.rocketchip.fpga.VCU118RocketSystem \ + --config freechips.rocketchip.fpga.VCU118RocketConfig + +rtl: chisel + @cd "$(REPO_DIR)" + rm -rf "$(VERILOG_DIR)" + mkdir -p "$(VERILOG_DIR)" "$(dir $(WRAPPER))" + $(FIRTOOL_ENV) "$(FIRTOOL)" \ + "$(FIRRTL_DIR)/VCU118RocketSystem.fir" \ + --split-verilog -o "$(VERILOG_DIR)" \ + --preserve-aggregate=none \ + --disable-annotation-unknown \ + --disable-all-randomization \ + --strip-debug-info + find "$(VERILOG_DIR)" -maxdepth 1 -type f \( -name '*.sv' -o -name '*.v' \) \ + -printf './%f\n' | sort > "$(VERILOG_DIR)/filelist.f" + perl -0pi -e 's/^([ \t]*)if \([^\n]*\)\n[ \t]*assert__[^\n]*:\s*assert\([^\n]*\);\n//mg; s/^[ \t]*assert__[^\n]*:\s*assert\([^\n]*\);\n//mg' "$(VERILOG_DIR)"/*.sv + python3 "$(TOOL_SCRIPT_DIR)/prepare_efinity_rtl.py" \ + --verilog-dir "$(VERILOG_DIR)" \ + --gps-source-dir "$(GPS_SYSTEM_DIR)" \ + --gps-output-dir "$(GPS_EFINITY_DIR)" + python3 "$(TOOL_SCRIPT_DIR)/gen_ti375c529_wrapper.py" \ + --rocket-top "$(VERILOG_DIR)/VCU118RocketSystem.sv" \ + --out "$(WRAPPER)" + : > "$(SOURCE_LIST)" + while IFS= read -r rel; do + rel="$${rel#./}" + printf '%s\n' "$(VERILOG_DIR)/$$rel" >> "$(SOURCE_LIST)" + done < "$(VERILOG_DIR)/filelist.f" + printf '%s\n' "$(HW_DIR)/upstream/rocket-chip/src/main/resources/vsrc/plusarg_reader.v" >> "$(SOURCE_LIST)" + while IFS= read -r rel; do + [[ -z "$$rel" || "$$rel" == \#* ]] && continue + case "$$rel" in + trck_src/xil_fifo.sv|trck_src/pulp_fifo/top.sv) continue ;; + acq_src/acq_nco_carr.sv) + printf '%s\n' "$(GPS_EFINITY_DIR)/acq_nco_carr.sv" >> "$(SOURCE_LIST)" + continue ;; + acq_src/twiddle_ram.sv) + printf '%s\n' "$(GPS_EFINITY_DIR)/twiddle_ram.sv" >> "$(SOURCE_LIST)" + continue ;; + trck_src/NCO_carr.sv) + printf '%s\n' "$(GPS_EFINITY_DIR)/NCO_carr.sv" >> "$(SOURCE_LIST)" + continue ;; + esac + printf '%s\n' "$(GPS_SYSTEM_DIR)/$$rel" >> "$(SOURCE_LIST)" + done < "$(GPS_SYSTEM_DIR)/filelist.f" + printf '%s\n' "$(HW_DIR)/ip/max2771_spi/rtl/max2771_spi_engine.sv" >> "$(SOURCE_LIST)" + # Efinix JTAG_USER1 has the same two-bit TDO lead-in as the Kintex-7 + # BSCANE2 path, so use the Genesys2-aligned Rocket DMI tunnel. + printf '%s\n' "$(HW_DIR)/fpga/genesys2/rtl/rocket_bscan_dmi_tunnel.sv" >> "$(SOURCE_LIST)" + $(MAKE) -C "$(FPGA_DIR)" "$(INTERFACE_SCRIPT)" + +soc: rtl + +$(INTERFACE_SCRIPT): $(INTERFACE_SOURCE) + cp "$<" "$@" + +interface: $(INTERFACE_SCRIPT) + @mkdir -p "$(LOG_DIR)" + cd "$(FLOW_DIR)" + # Efinity prefers a matching generated .peri.xml over the source .isf. + # Remove it so pin/PLL changes in the checked-in interface script are applied. + rm -f "$(FLOW_DIR)/ti375c529_rocket.peri.xml" + set +u + source "$(EFINITY_SETUP)" >/dev/null 2>&1 + set -u + python3 "$(EFX_RUN)" "$(PROJECT_XML)" --flow interface --un_flow \ + --pt_opts "peri_scripts=$(INTERFACE_SCRIPT)" 2>&1 | tee "$(LOG_DIR)/interface.log" + +map: rtl interface + @mkdir -p "$(LOG_DIR)" + cd "$(FLOW_DIR)" + set +u + source "$(EFINITY_SETUP)" >/dev/null 2>&1 + set -u + python3 "$(EFX_RUN)" "$(PROJECT_XML)" --flow map 2>&1 | tee "$(LOG_DIR)/map.log" + +bitstream: rtl interface + @mkdir -p "$(LOG_DIR)" "$(dir $(BIT_FILE))" + cd "$(FLOW_DIR)" + set +u + source "$(EFINITY_SETUP)" >/dev/null 2>&1 + set -u + : > "$(LOG_DIR)/full.log" + python3 "$(EFX_RUN)" "$(PROJECT_XML)" --flow map 2>&1 | tee -a "$(LOG_DIR)/full.log" + python3 "$(EFX_RUN)" "$(PROJECT_XML)" --flow pnr --work_dir work_pnr 2>&1 | tee -a "$(LOG_DIR)/full.log" + python3 "$(EFX_RUN)" "$(PROJECT_XML)" --flow pgm --work_dir work_pnr 2>&1 | tee -a "$(LOG_DIR)/full.log" + generated_bit="$$(find "$(FLOW_DIR)/outflow" "$(OUT_DIR)" -type f -name 'ti375c529_rocket.bit' 2>/dev/null | head -n 1)" + if [[ -z "$$generated_bit" ]]; then + echo "Efinity completed without a discoverable ti375c529_rocket.bit" >&2 + exit 1 + fi + if [[ "$$generated_bit" != "$(BIT_FILE)" ]]; then + cp "$$generated_bit" "$(BIT_FILE)" + fi + generated_hex="$$(find "$(FLOW_DIR)/outflow" "$(OUT_DIR)" -type f -name 'ti375c529_rocket.hex' ! -path '$(FLASH_DIR)/*' 2>/dev/null | head -n 1)" + if [[ -z "$$generated_hex" ]]; then + echo "Efinity completed without a discoverable ti375c529_rocket.hex" >&2 + exit 1 + fi + if [[ "$$generated_hex" != "$(CONFIG_HEX)" ]]; then + cp "$$generated_hex" "$(CONFIG_HEX)" + fi + printf 'Bitstream: %s\nConfiguration HEX: %s\n' "$(BIT_FILE)" "$(CONFIG_HEX)" + +program-fpga: + @if [[ ! -f "$(BIT_FILE)" ]]; then + echo "Missing bitstream: $(BIT_FILE)" >&2 + echo "Run: make -C $(FPGA_DIR) bitstream" >&2 + exit 1 + fi + set +u + source "$(EFINITY_SETUP)" >/dev/null 2>&1 + set -u + ftdi_args=() + if [[ -n "$(FTDI_URL)" ]]; then + ftdi_args+=(--url "$(FTDI_URL)") + fi + "$(EFX_PGM)" --mode jtag "$${ftdi_args[@]}" "$(BIT_FILE)" + +debug-openocd: + @"$(OPENOCD)" \ + -c "set ADAPTER_SPEED $(OPENOCD_ADAPTER_SPEED)" \ + -c "gdb_port $(GDB_PORT)" \ + -f "$(OPENOCD_CFG)" + +debug-load: $(APP_ELF) + @"$(GDB)" -q "$(APP_ELF)" \ + -ex "set confirm off" \ + -ex "set pagination off" \ + -ex "target extended-remote $(GDB_HOST):$(GDB_PORT)" \ + -x "$(GDB_LOAD_SCRIPT)" + +debug-gdb: $(APP_ELF) + @"$(GDB)" -q "$(APP_ELF)" \ + -ex "set confirm off" \ + -ex "set pagination off" \ + -ex "target extended-remote $(GDB_HOST):$(GDB_PORT)" \ + -x "$(GDB_ATTACH_SCRIPT)" + +uart-listen: + @stty -F "$(UART_PORT)" "$(UART_BAUD)" cs8 -cstopb -parenb -ixon -ixoff raw + @cat "$(UART_PORT)" + +flash-image: flash-regions + +flash-regions: software + @if [[ ! -f "$(CONFIG_HEX)" ]]; then + echo "Missing Efinity configuration HEX: $(CONFIG_HEX)" >&2 + echo "Run: make -C $(FPGA_DIR) bitstream" >&2 + exit 1 + fi + mkdir -p "$(FLASH_DIR)" "$(FLASH_REGION_DIR)" + python3 "$(TOOL_SCRIPT_DIR)/make_flash_hex.py" \ + --config-hex "$(CONFIG_HEX)" \ + --app-bin "$(APP_FLASH_IMAGE)" \ + --app-offset "$(APP_FLASH_OFFSET)" \ + --flash-size "$(FLASH_SIZE)" \ + --nav-context-offset "$(GPS_NAV_CONTEXT_FLASH_BASE)" \ + --ephemeris-offset "$(GPS_EPHEMERIS_FLASH_BASE)" \ + --combined-hex "$(FLASH_HEX)" \ + --app-hex "$(APP_HEX)" \ + --manifest "$(FLASH_MANIFEST)" + +program-flash-loader: + @if [[ ! -f "$(FLASH_LOADER)" ]]; then + echo "Missing Ti375 JTAG-to-SPI loader: $(FLASH_LOADER)" >&2 + exit 1 + fi + set +u + source "$(EFINITY_SETUP)" >/dev/null 2>&1 + set -u + ftdi_args=() + if [[ -n "$(FTDI_URL)" ]]; then + ftdi_args+=(--url "$(FTDI_URL)") + fi + "$(EFX_PGM)" --mode jtag "$${ftdi_args[@]}" "$(FLASH_LOADER)" + +program-flash program-flash-elf program-app: flash-regions + @$(MAKE) -C "$(FPGA_DIR)" program-flash-loader + set +u + source "$(EFINITY_SETUP)" >/dev/null 2>&1 + set -u + ftdi_args=() + if [[ -n "$(FTDI_URL)" ]]; then + ftdi_args+=(--url "$(FTDI_URL)") + fi + "$(EFX_PGM)" --mode jtag_bridge --jtag_bridge_mode all \ + --verify_method "$(FLASH_VERIFY)" --address "$(APP_FLASH_OFFSET)" \ + "$${ftdi_args[@]}" "$(APP_HEX)" + +program-flash-bitstream program-bitstream: + @if [[ ! -f "$(CONFIG_HEX)" ]]; then + echo "Missing Efinity configuration HEX: $(CONFIG_HEX)" >&2 + echo "Run: make -C $(FPGA_DIR) bitstream" >&2 + exit 1 + fi + $(MAKE) -C "$(FPGA_DIR)" program-flash-loader + set +u + source "$(EFINITY_SETUP)" >/dev/null 2>&1 + set -u + ftdi_args=() + if [[ -n "$(FTDI_URL)" ]]; then + ftdi_args+=(--url "$(FTDI_URL)") + fi + "$(EFX_PGM)" --mode jtag_bridge --jtag_bridge_mode all \ + --verify_method "$(FLASH_VERIFY)" --address 0 \ + "$${ftdi_args[@]}" "$(CONFIG_HEX)" + +program-flash-regions program-flash-all program-flash-combined: flash-image + @$(MAKE) -C "$(FPGA_DIR)" program-flash-loader + set +u + source "$(EFINITY_SETUP)" >/dev/null 2>&1 + set -u + ftdi_args=() + if [[ -n "$(FTDI_URL)" ]]; then + ftdi_args+=(--url "$(FTDI_URL)") + fi + "$(EFX_PGM)" --mode jtag_bridge --jtag_bridge_mode all \ + --verify_method "$(FLASH_VERIFY)" --address 0 \ + "$${ftdi_args[@]}" "$(FLASH_HEX)" + +clean-sw: + @$(MAKE) -C "$(SOC_SW_DIR)" clean + +clean-fpga: + rm -rf "$(OUT_DIR)" "$(FIRRTL_DIR)" "$(VERILOG_DIR)" + rm -f "$(INTERFACE_SCRIPT)" \ + "$(FLOW_DIR)/ti375c529_rocket.peri.xml" \ + "$(FLOW_DIR)/ti375c529_rocket.pt.sdc" \ + "$(FLOW_DIR)/ti375c529_rocket.pt.rpt" + +clean: clean-fpga + +FORCE: diff --git a/targets/fpga/ti375c529/README.md b/targets/fpga/ti375c529/README.md new file mode 100644 index 0000000..f367e0f --- /dev/null +++ b/targets/fpga/ti375c529/README.md @@ -0,0 +1,175 @@ +# 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 Efinity under `/tools/efinix/efinity`. Override +`EFINITY_HOME` when another installation is required. + +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 | diff --git a/targets/fpga/ti375c529/board.me b/targets/fpga/ti375c529/board.me new file mode 100644 index 0000000..24ca87c --- /dev/null +++ b/targets/fpga/ti375c529/board.me @@ -0,0 +1,12 @@ +Board name: Efinix Titanium Ti375 C529 Development Kit +Official link: https://www.efinixinc.com/products-devkits-titaniumti375c529.html + +FPGA device: Ti375C529 +Efinity family: Titanium +Efinity timing model: C4 + +Initial soft-Rocket flow clocks: + SoC/fabric: 100 MHz from the on-board 100 MHz oscillator + GPS RF: external AX2771 PMOD0/J13 clock, nominally 16.367981 MHz + GPS acquisition: 100 MHz, PLL-derived from the GPS RF clock + GPS tracking: 125 MHz, PLL-derived from the GPS RF clock diff --git a/targets/fpga/ti375c529/flow/debug/gdb_attach.gdb b/targets/fpga/ti375c529/flow/debug/gdb_attach.gdb new file mode 100644 index 0000000..f027923 --- /dev/null +++ b/targets/fpga/ti375c529/flow/debug/gdb_attach.gdb @@ -0,0 +1 @@ +monitor halt diff --git a/targets/fpga/ti375c529/flow/debug/gdb_load_and_run.gdb b/targets/fpga/ti375c529/flow/debug/gdb_load_and_run.gdb new file mode 100644 index 0000000..db56f1c --- /dev/null +++ b/targets/fpga/ti375c529/flow/debug/gdb_load_and_run.gdb @@ -0,0 +1,13 @@ +monitor halt +monitor reset halt +set $mie = 0 +set $mstatus = 0x6000 +set {unsigned long long}0x02004000 = 0xffffffffffffffff +load +set $mie = 0 +set $mstatus = 0x6000 +set $sp = (unsigned long)&_stack_top +set $pc = _start +monitor resume +disconnect +quit diff --git a/targets/fpga/ti375c529/flow/debug/openocd-0.12-ti375-bscan.patch b/targets/fpga/ti375c529/flow/debug/openocd-0.12-ti375-bscan.patch new file mode 100644 index 0000000..a5ccf3d --- /dev/null +++ b/targets/fpga/ti375c529/flow/debug/openocd-0.12-ti375-bscan.patch @@ -0,0 +1,62 @@ +--- a/src/target/riscv/riscv.c ++++ b/src/target/riscv/riscv.c +@@ -127,6 +127,7 @@ + + static bscan_tunnel_type_t bscan_tunnel_type; + int bscan_tunnel_ir_width; /* if zero, then tunneling is not present/active */ ++static int bscan_tunnel_ir_id; /* outer TAP IR used to access the tunnel */ + + static const uint8_t bscan_zero[4] = {0}; + static const uint8_t bscan_one[4] = {1}; +@@ -451,8 +452,12 @@ + select_idcode.num_bits = target->tap->ir_length; + + if (bscan_tunnel_ir_width != 0) { +- assert(target->tap->ir_length >= 6); +- uint32_t ir_user4_raw = 0x23 << (target->tap->ir_length - 6); ++ uint32_t ir_user4_raw = bscan_tunnel_ir_id; ++ /* Preserve the legacy Xilinx USER4 default when no IR was supplied. */ ++ if (ir_user4_raw == 0) { ++ assert(target->tap->ir_length >= 6); ++ ir_user4_raw = 0x23 << (target->tap->ir_length - 6); ++ } + h_u32_to_le(ir_user4, ir_user4_raw); + select_user4.num_bits = target->tap->ir_length; + bscan_tunneled_ir_width[0] = bscan_tunnel_ir_width; +@@ -2859,6 +2864,21 @@ + return ERROR_OK; + } + ++COMMAND_HANDLER(riscv_set_bscan_tunnel_ir) ++{ ++ int ir_id = 0; ++ ++ if (CMD_ARGC > 1) ++ return ERROR_COMMAND_SYNTAX_ERROR; ++ ++ if (CMD_ARGC == 1) ++ COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], ir_id); ++ ++ LOG_INFO("Bscan tunnel IR 0x%x selected", ir_id); ++ bscan_tunnel_ir_id = ir_id; ++ return ERROR_OK; ++} ++ + COMMAND_HANDLER(riscv_set_enable_virt2phys) + { + if (CMD_ARGC != 1) { +@@ -3072,6 +3092,14 @@ + "1: DATA_REGISTER}" + }, + { ++ .name = "set_bscan_tunnel_ir", ++ .handler = riscv_set_bscan_tunnel_ir, ++ .mode = COMMAND_ANY, ++ .usage = "[value]", ++ .help = "Specify the outer JTAG TAP IR used to access the BSCAN tunnel. " ++ "The default remains the Xilinx FPGA USER4 instruction." ++ }, ++ { + .name = "set_enable_virt2phys", + .handler = riscv_set_enable_virt2phys, + .mode = COMMAND_ANY, diff --git a/targets/fpga/ti375c529/flow/debug/openocd_ti375c529_bscan.cfg b/targets/fpga/ti375c529/flow/debug/openocd_ti375c529_bscan.cfg new file mode 100644 index 0000000..3c183b0 --- /dev/null +++ b/targets/fpga/ti375c529/flow/debug/openocd_ti375c529_bscan.cfg @@ -0,0 +1,32 @@ +# Rocket debug through the Ti375 hard TAP, JTAG_USER1, and the project's DMI tunnel. + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6011 +ftdi channel 1 +ftdi layout_init 0x08 0x0b + +if {![info exists ADAPTER_SPEED]} { + set ADAPTER_SPEED 1000 +} +adapter speed $ADAPTER_SPEED + +jtag newtap ti375 fpga -expected-id 0x006A0A79 -irlen 5 -ircapture 0x5 -irmask 0xF +target create rocket.cpu riscv -chain-position ti375.fpga -coreid 0 + +# The outer Ti375 USER1 instruction is 0x08. The inner tunnel implements the +# same 5-bit Rocket DTM IR and framing used by the Xilinx targets. +riscv set_ir dtmcs 0x10 +riscv set_ir dmi 0x11 +riscv use_bscan_tunnel 5 0 +# Ti375 requires an OpenOCD build with the upstream configurable outer BSCAN +# instruction support. Keep the catch only so older builds produce a readable +# diagnostic before their legacy Xilinx-specific BSCAN path rejects this TAP. +if {[catch {riscv set_bscan_tunnel_ir 8}]} { + echo "OpenOCD lacks 'riscv set_bscan_tunnel_ir'; Ti375 requires that command" +} + +riscv set_reset_timeout_sec 10 +riscv set_command_timeout_sec 10 + +init +halt diff --git a/targets/fpga/ti375c529/flow/efinity/README.md b/targets/fpga/ti375c529/flow/efinity/README.md new file mode 100644 index 0000000..9ecd46e --- /dev/null +++ b/targets/fpga/ti375c529/flow/efinity/README.md @@ -0,0 +1,328 @@ +# 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 pins 1, 8, and 9 carry the MAX2771 control bus; pin 1 + / G15 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. + +## 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 patched host binary in `PATH` is +used. 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. + +Apply the patch 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 +``` + +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 | +| `0x03FC0000` | Persistent navigation context (two 64-KiB sectors) | +| `0x03FE0000` | Persistent ephemeris cache (two 64-KiB sectors) | + +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. diff --git a/targets/fpga/ti375c529/flow/efinity/ti375c529_rocket.xml b/targets/fpga/ti375c529/flow/efinity/ti375c529_rocket.xml new file mode 100644 index 0000000..4d1aad7 --- /dev/null +++ b/targets/fpga/ti375c529/flow/efinity/ti375c529_rocket.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/targets/fpga/ti375c529/tools/gen_ti375c529_wrapper.py b/targets/fpga/ti375c529/tools/gen_ti375c529_wrapper.py new file mode 100644 index 0000000..a86bf66 --- /dev/null +++ b/targets/fpga/ti375c529/tools/gen_ti375c529_wrapper.py @@ -0,0 +1,276 @@ +#!/usr/bin/env python3 +"""Generate the Efinix Ti375 board shell around the shared Rocket subsystem.""" + +import argparse +import re +from pathlib import Path + + +def width_bits(width): + if not width: + return 1 + match = re.fullmatch(r"\[(\d+):(\d+)\]", width.strip()) + if not match: + raise ValueError(f"unsupported width: {width}") + return abs(int(match.group(1)) - int(match.group(2))) + 1 + + +def parse_ports(verilog_path): + text = Path(verilog_path).read_text() + module_name = Path(verilog_path).stem + start = text.index(f"module {module_name}(") + end = text.index(");", start) + header = re.sub(r"//.*", "", text[start:end]) + pieces = re.split(r"\b(input|output)\b", header)[1:] + ports = [] + for direction, body in zip(pieces[0::2], pieces[1::2]): + body = body.replace("\n", " ") + body = re.split(r"\b(input|output)\b", body)[0] + default_width = "" + width_match = re.match(r"\s*(\[[^\]]+\])\s*(.*)", body) + if width_match: + default_width = width_match.group(1) + rest = width_match.group(2) + else: + rest = body + for item in rest.split(","): + item = item.strip() + if not item: + continue + item_match = re.match(r"(\[[^\]]+\])\s*(\w+)$", item) + if item_match: + width, name = item_match.groups() + else: + width = default_width + name = item.split()[-1] + if re.fullmatch(r"\w+", name): + ports.append((direction, width, name)) + return ports + + +def const_for(width): + bits = width_bits(width) + return "1'b0" if bits == 1 else f"{bits}'d0" + + +def is_clock(name): + return name.endswith("_clock") or name == "debug_clock" + + +def is_reset(name): + return name.endswith("_reset") or name == "debug_reset" + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--rocket-top", required=True) + parser.add_argument("--out", required=True) + args = parser.parse_args() + + ports = parse_ports(args.rocket_top) + port_by_name = {name: (direction, width) for direction, width, name in ports} + + required = { + "uart_rxd", "uart_txd", + "spi_sck", "spi_csn", "spi_dq_i", "spi_dq_o", "spi_dq_oe", + "pmod_spi_sck", "pmod_spi_csn", + "pmod_spi_dq_i", "pmod_spi_dq_o", "pmod_spi_dq_oe", + "max2771_spi_sclk", "max2771_spi_csn", + "max2771_spi_sdata_i", "max2771_spi_sdata_o", + "max2771_spi_sdata_oe", + "pmod_irq", "gps_acq_clk", "gps_trck_clk", + "gps_rf_clk", "gps_rf_data", "gps_pps", + } + missing = sorted(required - port_by_name.keys()) + if missing: + raise RuntimeError(f"Rocket top is missing required Ti375 ports: {', '.join(missing)}") + + passthrough = { + "pmod_spi_sck", "pmod_spi_csn", + "max2771_spi_sclk", "max2771_spi_csn", + "pmod_irq", "gps_pps", + } + + def decl(width, name): + return f" wire {width + ' ' if width else ''}{name};" + + assigns = [] + for direction, width, name in ports: + if direction != "input" or name in passthrough: + continue + if name.startswith("debug_clockeddmi_dmi_req"): + continue + if name in { + "debug_clockeddmi_dmi_resp_ready", + "debug_clockeddmi_dmiClock", + "debug_clockeddmi_dmiReset", + }: + continue + if name == "resetctrl_hartIsInReset_0": + value = "soc_reset" + elif name == "debug_reset": + value = "fabric_reset" + elif is_reset(name): + value = "soc_reset" + elif name == "gps_acq_clk": + value = "gps_acq_clk_gen" + elif name == "gps_trck_clk": + value = "gps_trck_clk_gen" + elif name in {"gps_rf_clk", "gps_afe_clk"}: + value = "rf_clk" + elif name == "gps_rf_data": + value = "rf_data" + elif is_clock(name): + value = "fabric_clk" + elif name == "debug_dmactiveAck": + value = "debug_dmactive" + elif name == "uart_rxd": + value = "uart_rx" + elif name == "spi_dq_i": + value = "flash_dq_IN" + elif name == "pmod_spi_dq_i": + value = "pmod_spi_dq_IN" + elif name == "max2771_spi_sdata_i": + value = "max2771_spi_sdata_IN" + elif name == "interrupts": + value = "2'b00" + else: + value = const_for(width) + assigns.append(f" assign {name} = {value};") + + port_map = ",\n".join(f" .{name}({name})" for _, _, name in ports) + internal_decls = "\n".join( + decl(width, name) for _, width, name in ports if name not in passthrough + ) + + content = f"""`timescale 1ns/1ps + +module ti375c529_rocket_top ( + (* syn_peri_port = 0 *) input wire fabric_clk, + (* syn_peri_port = 0 *) input wire fabric_pll_locked, + (* syn_peri_port = 0 *) input wire board_clk_100, + (* syn_peri_port = 0 *) input wire gps_ref_clk_gen, + (* syn_peri_port = 0 *) input wire gps_acq_clk_gen, + (* syn_peri_port = 0 *) input wire gps_trck_clk_gen, + (* syn_peri_port = 0 *) input wire gps_domain_feedback, + (* syn_peri_port = 0 *) input wire gps_ref_pll_locked, + (* syn_peri_port = 0 *) input wire gps_domain_pll_locked, + (* syn_peri_port = 0 *) input wire reset_n, + (* syn_peri_port = 0 *) input wire uart_rx, + (* syn_peri_port = 0 *) output wire uart_tx, + (* syn_peri_port = 0 *) output wire flash_sck, + (* syn_peri_port = 0 *) output wire flash_csn, + (* syn_peri_port = 0 *) input wire [3:0] flash_dq_IN, + (* syn_peri_port = 0 *) output wire [3:0] flash_dq_OUT, + (* syn_peri_port = 0 *) output wire [3:0] flash_dq_OE, + (* syn_peri_port = 0 *) input wire rf_clk, + (* syn_peri_port = 0 *) input wire [3:0] rf_data, + (* syn_peri_port = 0 *) output wire pmod_spi_sck, + (* syn_peri_port = 0 *) output wire pmod_spi_csn, + (* syn_peri_port = 0 *) input wire [3:0] pmod_spi_dq_IN, + (* syn_peri_port = 0 *) output wire [3:0] pmod_spi_dq_OUT, + (* syn_peri_port = 0 *) output wire [3:0] pmod_spi_dq_OE, + (* syn_peri_port = 0 *) input wire pmod_irq, + (* syn_peri_port = 0 *) output wire max2771_spi_sclk, + (* syn_peri_port = 0 *) output wire max2771_spi_csn, + (* syn_peri_port = 0 *) input wire max2771_spi_sdata_IN, + (* syn_peri_port = 0 *) output wire max2771_spi_sdata_OUT, + (* syn_peri_port = 0 *) output wire max2771_spi_sdata_OE, + (* syn_peri_port = 0 *) output wire gps_pps, + (* syn_peri_port = 0 *) input wire jtag_CAPTURE, + (* syn_peri_port = 0 *) input wire jtag_DRCK, + (* syn_peri_port = 0 *) input wire jtag_RESET, + (* syn_peri_port = 0 *) input wire jtag_RUNTEST, + (* syn_peri_port = 0 *) input wire jtag_SEL, + (* syn_peri_port = 0 *) input wire jtag_SHIFT, + (* syn_peri_port = 0 *) input wire jtag_TCK, + (* syn_peri_port = 0 *) input wire jtag_TDI, + (* syn_peri_port = 0 *) input wire jtag_TMS, + (* syn_peri_port = 0 *) input wire jtag_UPDATE, + (* syn_peri_port = 0 *) output wire jtag_TDO, + (* syn_peri_port = 0 *) output wire [4:0] led +); + wire gps_clock_locked = gps_ref_pll_locked & gps_domain_pll_locked; + wire pll_ready_async = fabric_pll_locked & gps_clock_locked & reset_n; + (* async_reg = "true" *) reg [2:0] pll_ready_sync = 3'b000; + reg [15:0] reset_shift = 16'hffff; + + always @(posedge fabric_clk) begin + pll_ready_sync <= {{pll_ready_sync[1:0], pll_ready_async}}; + if (!pll_ready_sync[2]) + reset_shift <= 16'hffff; + else + reset_shift <= {{reset_shift[14:0], 1'b0}}; + end + + wire fabric_reset = reset_shift[15]; + reg [31:0] heartbeat = 32'd0; + always @(posedge fabric_clk) begin + if (fabric_reset) + heartbeat <= 32'd0; + else + heartbeat <= heartbeat + 32'd1; + end + +{internal_decls} + + wire soc_reset = fabric_reset | debug_ndreset; + + rocket_bscan_dmi_tunnel u_rocket_dmi_tunnel ( + .tck(jtag_TCK), + .reset(fabric_reset | jtag_RESET), + .bscan_capture(jtag_CAPTURE), + .bscan_sel(jtag_SEL), + .bscan_shift(jtag_SHIFT), + .bscan_tdi(jtag_TDI), + .bscan_update(jtag_UPDATE), + .bscan_tdo(jtag_TDO), + .dmi_clock(debug_clockeddmi_dmiClock), + .dmi_reset(debug_clockeddmi_dmiReset), + .dmi_req_ready(debug_clockeddmi_dmi_req_ready), + .dmi_req_valid(debug_clockeddmi_dmi_req_valid), + .dmi_req_addr(debug_clockeddmi_dmi_req_bits_addr), + .dmi_req_data(debug_clockeddmi_dmi_req_bits_data), + .dmi_req_op(debug_clockeddmi_dmi_req_bits_op), + .dmi_resp_ready(debug_clockeddmi_dmi_resp_ready), + .dmi_resp_valid(debug_clockeddmi_dmi_resp_valid), + .dmi_resp_data(debug_clockeddmi_dmi_resp_bits_data), + .dmi_resp_resp(debug_clockeddmi_dmi_resp_bits_resp) + ); + + assign pmod_spi_dq_OUT = pmod_spi_dq_o; + assign pmod_spi_dq_OE = pmod_spi_dq_oe; + assign max2771_spi_sdata_OUT = max2771_spi_sdata_o; + assign max2771_spi_sdata_OE = max2771_spi_sdata_oe; + assign flash_sck = spi_sck; + assign flash_csn = spi_csn; + assign flash_dq_OUT = spi_dq_o; + assign flash_dq_OE = spi_dq_oe; + assign uart_tx = uart_txd; + + // The kit LEDs are active-low. Show heartbeat, PLL locks, reset release, + // and debug-module activity from LED13 down to LED9. + assign led = ~{{heartbeat[25], gps_clock_locked, fabric_pll_locked, + ~fabric_reset, debug_dmactive}}; + +{chr(10).join(assigns)} + + (* syn_preserve = 1 *) + {Path(args.rocket_top).stem} u_rocket ( +{port_map} + ); + + // These hard-TAP outputs are intentionally unused by the DMI framing logic. + wire _unused_hard_signals = jtag_DRCK ^ jtag_RUNTEST ^ jtag_TMS ^ + board_clk_100 ^ gps_ref_clk_gen ^ + gps_domain_feedback; +endmodule +""" + + output = Path(args.out) + output.parent.mkdir(parents=True, exist_ok=True) + output.write_text(content) + + +if __name__ == "__main__": + main() diff --git a/targets/fpga/ti375c529/tools/make_flash_hex.py b/targets/fpga/ti375c529/tools/make_flash_hex.py new file mode 100644 index 0000000..480000c --- /dev/null +++ b/targets/fpga/ti375c529/tools/make_flash_hex.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 +"""Build Efinity raw-HEX images for Ti375C529 persistent Rocket boot.""" + +import argparse +import hashlib +import json +import re +from pathlib import Path + + +HEX_BYTE = re.compile(r"[0-9a-fA-F]{2}") + + +def parse_int(value): + return int(value, 0) + + +def read_raw_hex(path): + data = bytearray() + with path.open() as source: + for line_number, line in enumerate(source, 1): + value = line.strip() + if not HEX_BYTE.fullmatch(value): + raise SystemExit( + f"{path}:{line_number}: expected one hexadecimal byte per line" + ) + data.append(int(value, 16)) + return bytes(data) + + +def write_raw_hex(path, chunks): + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w") as output: + for chunk in chunks: + for value in chunk: + output.write(f"{value:02X}\n") + + +def sha256(data): + return hashlib.sha256(data).hexdigest() + + +def main(): + parser = argparse.ArgumentParser( + description="Combine an Efinity configuration HEX and Rocket app image" + ) + parser.add_argument("--config-hex", type=Path, required=True) + parser.add_argument("--app-bin", type=Path, required=True) + parser.add_argument("--app-offset", type=parse_int, required=True) + parser.add_argument("--flash-size", type=parse_int, default=0x04000000) + parser.add_argument("--nav-context-offset", type=parse_int, required=True) + parser.add_argument("--ephemeris-offset", type=parse_int, required=True) + parser.add_argument("--combined-hex", type=Path, required=True) + parser.add_argument("--app-hex", type=Path, required=True) + parser.add_argument("--manifest", type=Path, required=True) + args = parser.parse_args() + + config = read_raw_hex(args.config_hex) + app = args.app_bin.read_bytes() + app_end = args.app_offset + len(app) + + if args.app_offset & 0xFFFF: + raise SystemExit("application offset must be aligned to a 64-KiB sector") + if len(config) > args.app_offset: + raise SystemExit( + f"configuration image (0x{len(config):x} bytes) overlaps application " + f"at 0x{args.app_offset:x}" + ) + if app_end > args.flash_size: + raise SystemExit( + f"application ends at 0x{app_end:x}, beyond flash size 0x{args.flash_size:x}" + ) + reserved_size = 2 * 0x10000 + if args.nav_context_offset + reserved_size > args.ephemeris_offset: + raise SystemExit("navigation context overlaps ephemeris flash region") + if args.ephemeris_offset + reserved_size > args.flash_size: + raise SystemExit("ephemeris flash region exceeds device capacity") + if app_end > args.nav_context_offset: + raise SystemExit( + f"application ends at 0x{app_end:x}, overlapping persistent data at " + f"0x{args.nav_context_offset:x}" + ) + + padding_size = args.app_offset - len(config) + write_raw_hex(args.app_hex, (app,)) + write_raw_hex(args.combined_hex, (config, bytes([0xFF]) * padding_size, app)) + + manifest = { + "format": "Efinity raw HEX (one byte per line)", + "flash": "Ti375C529 lower SPI NOR (U47)", + "flash_size": f"0x{args.flash_size:08x}", + "configuration": { + "source": str(args.config_hex), + "offset": "0x00000000", + "size": len(config), + "sha256": sha256(config), + }, + "application": { + "source": str(args.app_bin), + "offset": f"0x{args.app_offset:08x}", + "size": len(app), + "sha256": sha256(app), + }, + "navigation_context": { + "offset": f"0x{args.nav_context_offset:08x}", + "size": reserved_size, + }, + "ephemeris_cache": { + "offset": f"0x{args.ephemeris_offset:08x}", + "size": reserved_size, + }, + "combined": { + "image": str(args.combined_hex), + "programmed_length": app_end, + }, + } + args.manifest.parent.mkdir(parents=True, exist_ok=True) + args.manifest.write_text(json.dumps(manifest, indent=2) + "\n") + + print(f"configuration: 0x00000000..0x{len(config) - 1:08x}") + print(f"application: 0x{args.app_offset:08x}..0x{app_end - 1:08x}") + print(f"combined HEX: {args.combined_hex}") + + +if __name__ == "__main__": + main() diff --git a/targets/fpga/ti375c529/tools/prepare_efinity_rtl.py b/targets/fpga/ti375c529/tools/prepare_efinity_rtl.py new file mode 100644 index 0000000..d97684c --- /dev/null +++ b/targets/fpga/ti375c529/tools/prepare_efinity_rtl.py @@ -0,0 +1,316 @@ +#!/usr/bin/env python3 +"""Apply small, deterministic Efinity synthesis adaptations to generated RTL.""" + +from __future__ import annotations + +import argparse +import math +import re +from pathlib import Path + + +ROCKET_STORE_DATA = """ else begin + automatic logic [3:0][63:0] _GEN_24 = + {{ex_rs_1}, {{2{ex_rs_1[31:0]}}}, {{4{ex_rs_1[15:0]}}}, {{8{ex_rs_1[7:0]}}}}; + mem_reg_rs2 <= _GEN_24[ex_reg_mem_size]; + end""" + +EFINITY_STORE_DATA = """ else begin + // Efinity 2025.2 leaves the block-local packed automatic array above + // undriven (VDB-1002). Spell out the byte-lane replication instead. + case (ex_reg_mem_size) + 2'h0: mem_reg_rs2 <= {8{ex_rs_1[7:0]}}; + 2'h1: mem_reg_rs2 <= {4{ex_rs_1[15:0]}}; + 2'h2: mem_reg_rs2 <= {2{ex_rs_1[31:0]}}; + default: mem_reg_rs2 <= ex_rs_1; + endcase + end""" + +ATOMIC_LUT_DECLARATION = re.compile( + r"^(?P\s*)automatic logic \[3:0\]\[3:0\] (?P_GEN_[0-9]+) " + r"= '\{4'hC, 4'h8, 4'hE, 4'h6\};$", + re.MULTILINE, +) + +NCO_ROM_START = '(*rom_style = "distributed" *) logic [PH_ACC_WL-1 : 0] freq_word_arr' +NCO_ROM_END = "logic [PH_ACC_WL-1 : 0] sin_phase, cos_phase;" + + +def parse_integer_parameter(text: str, name: str) -> int: + match = re.search(rf"\bparameter\s+{re.escape(name)}\s*=\s*([0-9]+)\s*;", text) + if match is None: + raise RuntimeError(f"could not find integer parameter {name}") + return int(match.group(1)) + + +def parse_sv_integer(token: str) -> tuple[int, int | None]: + token = token.strip().replace("_", "") + match = re.fullmatch(r"(-)?([0-9]+)'([dDhHbB])([0-9a-fA-F]+)", token) + if match is not None: + sign, width_text, radix_text, digits = match.groups() + radix = {"d": 10, "h": 16, "b": 2}[radix_text.lower()] + value = int(digits, radix) + if sign: + value = -value + return value, int(width_text) + if re.fullmatch(r"-?[0-9]+", token): + return int(token), None + raise RuntimeError(f"unsupported SystemVerilog integer literal: {token!r}") + + +def parse_array_parameter(text: str, name: str) -> list[tuple[int, int | None]]: + match = re.search( + rf"\bparameter\s+\[[^\]]+\]\s+{re.escape(name)}\s*\[[^\]]+\]\s*=\s*\{{(.*?)\}}\s*;", + text, + re.DOTALL, + ) + if match is None: + raise RuntimeError(f"could not find array parameter {name}") + return [parse_sv_integer(token) for token in match.group(1).split(",") if token.strip()] + + +def sv_case_function( + name: str, + input_width: str, + output_width: str, + values: list[int], + literal_width: int, +) -> str: + lines = [ + f"function automatic logic [{output_width}-1 : 0] {name};", + f" input logic [{input_width}-1 : 0] index;", + " begin", + " case (index)", + ] + for index, value in enumerate(values): + literal = f"-{literal_width}'sd{-value}" if value < 0 else f"{literal_width}'d{value}" + lines.append(f" {index}: {name} = {literal};") + lines.extend( + [ + f" default: {name} = '0;", + " endcase", + " end", + "endfunction", + ] + ) + return "\n".join(lines) + + +def round_sv_real(value: float) -> int: + """Match real-to-integral assignment rounding used by SystemVerilog.""" + return math.floor(value + 0.5) if value >= 0 else math.ceil(value - 0.5) + + +def build_nco_rom_functions(definitions: str) -> str: + phase_width = parse_integer_parameter(definitions, "ACQ_NCO_PH_ACC_WL") + sine_integer_bits = parse_integer_parameter(definitions, "ACQ_SIN_IL") + sine_fraction_bits = parse_integer_parameter(definitions, "ACQ_SIN_FL") + lut_address_width = parse_integer_parameter(definitions, "ACQ_SIN_LUT_DEPTH_WL") + freq_values = [value for value, _ in parse_array_parameter(definitions, "FREQ_WORD_ARRAY")] + pullin_values = [value for value, _ in parse_array_parameter(definitions, "PULLIN_FREQ_WORD_ARRAY")] + sine_width = sine_integer_bits + sine_fraction_bits + sine_values = [ + round_sv_real( + math.sin(2.0 * math.pi * index / (1 << lut_address_width)) + * (1 << sine_fraction_bits) + ) + for index in range(1 << lut_address_width) + ] + return "\n\n".join( + [ + "// Efinity 2025.2 mis-elaborates the original initial/$sin ROMs.\n" + "// These constant functions are generated from definitions.sv for Ti375 only.", + sv_case_function( + "efinity_freq_word", "FREQ_BIN_WL", "PH_ACC_WL", freq_values, phase_width + ), + sv_case_function( + "efinity_pullin_word", "NUM_PULLIN_WL", "PH_ACC_WL", pullin_values, phase_width + ), + sv_case_function( + "efinity_sine", "LUT_DEPTH_WL", "ACQ_SIN_IL + ACQ_SIN_FL", sine_values, sine_width + ), + ] + ) + + +def rewrite_acquisition_nco(source: Path, destination: Path, definitions: str) -> None: + text = source.read_text(encoding="utf-8") + start = text.find(NCO_ROM_START) + end = text.find(NCO_ROM_END, start) + if start < 0 or end < 0: + raise RuntimeError(f"could not locate acquisition NCO ROM block in {source}") + text = text[:start] + build_nco_rom_functions(definitions) + "\n\n" + text[end:] + old_sum = ( + "freq_word_arr[freq_bin_idx_i] + " + "pullin_freq_word_arr[pullin_freq_bin_idx_i]" + ) + new_sum = ( + "efinity_freq_word(freq_bin_idx_i) + " + "efinity_pullin_word(pullin_freq_bin_idx_i)" + ) + if text.count(old_sum) != 2: + raise RuntimeError(f"expected two NCO phase increments in {source}") + text = text.replace(old_sum, new_sum) + if text.count("sinwav_lut[truncated_sin_phase]") != 1: + raise RuntimeError(f"expected one sine ROM read in {source}") + if text.count("sinwav_lut[truncated_cos_phase]") != 1: + raise RuntimeError(f"expected one cosine ROM read in {source}") + text = text.replace("sinwav_lut[truncated_sin_phase]", "efinity_sine(truncated_sin_phase)") + text = text.replace("sinwav_lut[truncated_cos_phase]", "efinity_sine(truncated_cos_phase)") + destination.write_text(text, encoding="utf-8") + + +def rewrite_tracking_nco(source: Path, destination: Path, definitions: str) -> None: + text = source.read_text(encoding="utf-8") + declaration = ( + '(*rom_style = "distributed" *) logic [SIN_IL-1 : -SIN_FL] ' + "sinwav_lut [0 : 2**LUT_DEPTH_WL-1];" + ) + values = [value for value, _ in parse_array_parameter(definitions, "TRCK_SINWAV_LUT")] + expected_entries = parse_integer_parameter(definitions, "NUM_TRCK_SINWAV_LUT") + if len(values) != expected_entries: + raise RuntimeError( + f"expected {expected_entries} tracking sine entries, got {len(values)}" + ) + function = ( + "// Efinity 2025.2 leaves the original package-array initialized ROM undriven.\n" + "// This Ti375-only constant function preserves the exact definitions.sv values.\n" + + sv_case_function( + "efinity_tracking_sine", + "LUT_DEPTH_WL", + "SIN_IL + SIN_FL", + values, + parse_integer_parameter(definitions, "TRCK_CARR_NCO_SIN_WL"), + ) + ) + if text.count(declaration) != 1: + raise RuntimeError(f"expected one tracking sine ROM declaration in {source}") + text = text.replace(declaration, function) + initializer = """initial begin + sinwav_lut = TRCK_SINWAV_LUT; +end + +""" + if text.count(initializer) != 1: + raise RuntimeError(f"expected one tracking sine ROM initializer in {source}") + text = text.replace(initializer, "") + if text.count("sinwav_lut[accum_truncated_sin]") != 1: + raise RuntimeError(f"expected one tracking sine ROM read in {source}") + if text.count("sinwav_lut[accum_truncated_cos]") != 1: + raise RuntimeError(f"expected one tracking cosine ROM read in {source}") + text = text.replace( + "sinwav_lut[accum_truncated_sin]", "efinity_tracking_sine(accum_truncated_sin)" + ) + text = text.replace( + "sinwav_lut[accum_truncated_cos]", "efinity_tracking_sine(accum_truncated_cos)" + ) + destination.write_text(text, encoding="utf-8") + + +def write_mem_file(path: Path, entries: list[tuple[int, int | None]], width: int) -> None: + mask = (1 << width) - 1 + path.write_text( + # Binary keeps each row exactly TWIDDLE_WIDTH bits. A hexadecimal row + # would round 15 bits up to four digits and Efinity warns about a + # spurious 16-to-15-bit truncation even though the value is correct. + "".join(f"{value & mask:0{width}b}\n" for value, _ in entries), + encoding="ascii", + ) + + +def rewrite_twiddle_rom(source: Path, destination: Path) -> None: + text = source.read_text(encoding="utf-8") + old = """initial begin + cos_rom = COS_ROM_ARRAY; + sin_rom = SIN_ROM_ARRAY; +end""" + new = """initial begin + // Generated Ti375 files are resolved through Efinity's memory-init include path. + $readmemb("ti375_twiddle_cos_15.mem", cos_rom); + $readmemb("ti375_twiddle_sin_15.mem", sin_rom); +end""" + if text.count(old) != 1: + raise RuntimeError(f"expected one twiddle ROM initializer in {source}") + destination.write_text(text.replace(old, new), encoding="utf-8") + + +def prepare_gps_rtl(source_dir: Path, output_dir: Path) -> None: + definitions_path = source_dir / "common" / "definitions.sv" + definitions = definitions_path.read_text(encoding="utf-8") + output_dir.mkdir(parents=True, exist_ok=True) + rewrite_acquisition_nco( + source_dir / "acq_src" / "acq_nco_carr.sv", + output_dir / "acq_nco_carr.sv", + definitions, + ) + rewrite_tracking_nco( + source_dir / "trck_src" / "NCO_carr.sv", + output_dir / "NCO_carr.sv", + definitions, + ) + rewrite_twiddle_rom( + source_dir / "acq_src" / "twiddle_ram.sv", + output_dir / "twiddle_ram.sv", + ) + cos_entries = parse_array_parameter(definitions, "COS_ROM_ARRAY") + sin_entries = parse_array_parameter(definitions, "SIN_ROM_ARRAY") + expected_entries = parse_integer_parameter(definitions, "NUM_TWIDDLE_ROM_IDX") + if len(cos_entries) != expected_entries or len(sin_entries) != expected_entries: + raise RuntimeError( + f"expected {expected_entries} twiddle entries, got " + f"cos={len(cos_entries)} sin={len(sin_entries)}" + ) + write_mem_file(output_dir / "ti375_twiddle_cos_15.mem", cos_entries, 15) + write_mem_file(output_dir / "ti375_twiddle_sin_15.mem", sin_entries, 15) + + +def rewrite_rocket_store_data(path: Path) -> None: + text = path.read_text(encoding="utf-8") + if EFINITY_STORE_DATA in text: + return + if text.count(ROCKET_STORE_DATA) != 1: + raise RuntimeError(f"expected one Rocket store-data array in {path}") + path.write_text(text.replace(ROCKET_STORE_DATA, EFINITY_STORE_DATA), encoding="utf-8") + + +def rewrite_tilelink_atomic_lut(path: Path) -> None: + text = path.read_text(encoding="utf-8") + if "// Avoid Efinity VDB-1002 on the block-local packed LUT." in text: + return + match = ATOMIC_LUT_DECLARATION.search(text) + if match is None: + raise RuntimeError(f"expected one TileLink atomic packed LUT in {path}") + if ATOMIC_LUT_DECLARATION.search(text, match.end()) is not None: + raise RuntimeError(f"expected only one TileLink atomic packed LUT in {path}") + indent = match.group("indent") + temporary = match.group("name") + old_read = f"{indent}cam_a_0_lut <= {temporary}[auto_in_a_bits_param[1:0]];" + new_read = f"""{indent}// Avoid Efinity VDB-1002 on the block-local packed LUT. +{indent}case (auto_in_a_bits_param[1:0]) +{indent} 2'h0: cam_a_0_lut <= 4'h6; +{indent} 2'h1: cam_a_0_lut <= 4'hE; +{indent} 2'h2: cam_a_0_lut <= 4'h8; +{indent} default: cam_a_0_lut <= 4'hC; +{indent}endcase""" + if text.count(old_read) != 1: + raise RuntimeError(f"expected one TileLink atomic packed LUT read in {path}") + text = text[: match.start()] + text[match.end() + 1 :] + text = text.replace(old_read, new_read) + path.write_text(text, encoding="utf-8") + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("--verilog-dir", type=Path, required=True) + parser.add_argument("--gps-source-dir", type=Path, required=True) + parser.add_argument("--gps-output-dir", type=Path, required=True) + args = parser.parse_args() + + rewrite_rocket_store_data(args.verilog_dir / "Rocket.sv") + rewrite_tilelink_atomic_lut(args.verilog_dir / "TLAtomicAutomata_pbus.sv") + rewrite_tilelink_atomic_lut(args.verilog_dir / "TLAtomicAutomata_cbus.sv") + prepare_gps_rtl(args.gps_source_dir, args.gps_output_dir) + + +if __name__ == "__main__": + main() diff --git a/targets/fpga/vcu118/Makefile b/targets/fpga/vcu118/Makefile index fc2dbc6..b608e52 100644 --- a/targets/fpga/vcu118/Makefile +++ b/targets/fpga/vcu118/Makefile @@ -69,6 +69,12 @@ FLASH_FORCE ?= 0 GPS_DEBUG ?= 1 GPS_DEBUG_LEVEL ?= 4 GPS_ESKF_ENABLE ?= 1 +GPS_EPHEMERIS_FLASH_ENABLE ?= 1 +GPS_EPHEMERIS_FLASH_SEED_INITIAL ?= 1 +GPS_EPHEMERIS_FLASH_BASE ?= 0x07fe0000 +GPS_NAV_CONTEXT_ENABLE ?= 1 +GPS_NAV_CONTEXT_FLASH_BASE ?= 0x07fc0000 +BSP_SPI_FLASH_PROFILE ?= 2 IMU_SENSOR ?= auto FLASH_MCS ?= $(OUT_DIR)/flash/vcu118_rocket.mcs @@ -213,13 +219,19 @@ fpga-config: ' UART_PORT=$(UART_PORT)' \ ' UART_BAUD=$(UART_BAUD)' \ ' GPS_ESKF_ENABLE=$(GPS_ESKF_ENABLE)' \ + ' GPS_EPHEMERIS_FLASH_ENABLE=$(GPS_EPHEMERIS_FLASH_ENABLE)' \ + ' GPS_EPHEMERIS_FLASH_SEED_INITIAL=$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)' \ + ' GPS_EPHEMERIS_FLASH_BASE=$(GPS_EPHEMERIS_FLASH_BASE)' \ + ' GPS_NAV_CONTEXT_ENABLE=$(GPS_NAV_CONTEXT_ENABLE)' \ + ' GPS_NAV_CONTEXT_FLASH_BASE=$(GPS_NAV_CONTEXT_FLASH_BASE)' \ + ' BSP_SPI_FLASH_PROFILE=$(BSP_SPI_FLASH_PROFILE)' \ ' IMU_SENSOR=$(IMU_SENSOR)' software: - @$(MAKE_BIN) -C "$(SOC_SW_DIR)" TOOLCHAIN="$(TOOLCHAIN)" APP="$(APP)" APP_FLASH_OFFSET="$(APP_FLASH_OFFSET)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_DTIM_BASE="$(DTIM_BASE)" BSP_DTIM_SIZE="$(DTIM_SIZE)" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" GPS_ESKF_ENABLE="$(GPS_ESKF_ENABLE)" IMU_SENSOR="$(IMU_SENSOR)" bootloader flash-image + @$(MAKE_BIN) -C "$(SOC_SW_DIR)" TOOLCHAIN="$(TOOLCHAIN)" APP="$(APP)" APP_FLASH_OFFSET="$(APP_FLASH_OFFSET)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_SPI_FLASH_PROFILE="$(BSP_SPI_FLASH_PROFILE)" BSP_DTIM_BASE="$(DTIM_BASE)" BSP_DTIM_SIZE="$(DTIM_SIZE)" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" GPS_ESKF_ENABLE="$(GPS_ESKF_ENABLE)" GPS_EPHEMERIS_FLASH_ENABLE="$(GPS_EPHEMERIS_FLASH_ENABLE)" GPS_EPHEMERIS_FLASH_SEED_INITIAL="$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)" GPS_EPHEMERIS_FLASH_BASE="$(GPS_EPHEMERIS_FLASH_BASE)" GPS_NAV_CONTEXT_ENABLE="$(GPS_NAV_CONTEXT_ENABLE)" GPS_NAV_CONTEXT_FLASH_BASE="$(GPS_NAV_CONTEXT_FLASH_BASE)" IMU_SENSOR="$(IMU_SENSOR)" bootloader flash-image $(APP_ELF): FORCE - @$(MAKE_BIN) -C "$(SOC_SW_DIR)" TOOLCHAIN="$(TOOLCHAIN)" APP="$(APP)" APP_FLASH_OFFSET="$(APP_FLASH_OFFSET)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_DTIM_BASE="$(DTIM_BASE)" BSP_DTIM_SIZE="$(DTIM_SIZE)" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" GPS_ESKF_ENABLE="$(GPS_ESKF_ENABLE)" IMU_SENSOR="$(IMU_SENSOR)" app + @$(MAKE_BIN) -C "$(SOC_SW_DIR)" TOOLCHAIN="$(TOOLCHAIN)" APP="$(APP)" APP_FLASH_OFFSET="$(APP_FLASH_OFFSET)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_SPI_FLASH_PROFILE="$(BSP_SPI_FLASH_PROFILE)" BSP_DTIM_BASE="$(DTIM_BASE)" BSP_DTIM_SIZE="$(DTIM_SIZE)" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" GPS_ESKF_ENABLE="$(GPS_ESKF_ENABLE)" GPS_EPHEMERIS_FLASH_ENABLE="$(GPS_EPHEMERIS_FLASH_ENABLE)" GPS_EPHEMERIS_FLASH_SEED_INITIAL="$(GPS_EPHEMERIS_FLASH_SEED_INITIAL)" GPS_EPHEMERIS_FLASH_BASE="$(GPS_EPHEMERIS_FLASH_BASE)" GPS_NAV_CONTEXT_ENABLE="$(GPS_NAV_CONTEXT_ENABLE)" GPS_NAV_CONTEXT_FLASH_BASE="$(GPS_NAV_CONTEXT_FLASH_BASE)" IMU_SENSOR="$(IMU_SENSOR)" app chisel: software @cd "$(REPO_DIR)" diff --git a/tools/project.mk b/tools/project.mk index d80222a..27cb321 100644 --- a/tools/project.mk +++ b/tools/project.mk @@ -16,6 +16,10 @@ FIRTOOL ?= $(firstword $(wildcard $(SOC_TOOLS_ROOT)/circt-current/bin/firtool) $ Z3_LIB_DIR ?= $(firstword $(wildcard $(SOC_TOOLS_ROOT)/z3-current/bin) $(wildcard $(PROJECT_TOOLS_DIR)/z3/*/bin)) CIRCT_LIB_DIR ?= $(patsubst %/bin/firtool,%/lib,$(FIRTOOL)) VIVADO ?= $(lastword $(sort $(wildcard /tools/Xilinx/*/Vivado/bin/vivado) $(shell command -v vivado 2>/dev/null))) +EFINITY_HOME ?= $(lastword $(sort $(wildcard /tools/efinix/efinity/*))) +EFINITY_SETUP ?= $(EFINITY_HOME)/bin/setup.sh +EFX_RUN ?= $(EFINITY_HOME)/scripts/efx_run.py +EFX_PGM ?= $(EFINITY_HOME)/pgm/bin/ftdi_pgm.sh # RISCV_TOOLCHAIN may point either to the toolchain root or its bin directory. # TOOLCHAIN keeps compatibility with the existing software Makefiles.