From eb4d694ba91c4b9dee7ca39e347115a64df8be2e Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 27 Jul 2026 02:38:17 +0800 Subject: [PATCH 01/62] fpga_diff: add UVHS implementation flow Add an opt-in U2.2/B0/F2 UVHS flow that regenerates repository-owned Vivado IP and imports the vendor DDR IP. Keep the normal Makefile and JTAG flow unchanged, with UVHS targets isolated in uvhs.mk. Simplify generated-clock constraints and retain only the RTL and tool compatibility needed for the regenerated NutShell bitstream. Co-authored-by: Kamimiao --- fpga_diff/Makefile | 4 + fpga_diff/README.md | 12 + fpga_diff/src/rtl/common/core_def_xdma.sv | 84 +- fpga_diff/src/rtl/common/fpga_top_debug.sv | 92 +- .../src/rtl/common/uvhs_axi64_to_axi256.sv | 211 +++ fpga_diff/src/rtl/common/uvhs_ddr4_wrapper.sv | 306 ++++ fpga_diff/src/tcl/common/AXI_bridge.tcl | 32 +- fpga_diff/src/tcl/common/xdma_ep.tcl | 29 + fpga_diff/user_script/.gitignore | 3 + fpga_diff/user_script/hw_run_download.tcl | 67 + fpga_diff/uvhs/README.md | 73 + fpga_diff/uvhs/assemble_uvhs.tcl | 229 +++ fpga_diff/uvhs/assign_pin_u22_f2.tcl | 190 +++ fpga_diff/uvhs/async_clocks.tcl | 14 + fpga_diff/uvhs/backend_run.tcl | 1316 +++++++++++++++++ fpga_diff/uvhs/check_flow_tools.sh | 61 + fpga_diff/uvhs/check_modules.sh | 44 + fpga_diff/uvhs/export_vivado_ip.tcl | 386 +++++ fpga_diff/uvhs/filelist.awk | 5 + fpga_diff/uvhs/frontend_run.tcl | 238 +++ fpga_diff/uvhs/make_compat/csh | 9 + fpga_diff/uvhs/make_compat/make | 2 + fpga_diff/uvhs/patch_uvsyn_shell.sh | 28 + fpga_diff/uvhs/timing_common.tcl | 32 + fpga_diff/uvhs/uvhs.mk | 224 +++ 25 files changed, 3645 insertions(+), 46 deletions(-) create mode 100644 fpga_diff/src/rtl/common/uvhs_axi64_to_axi256.sv create mode 100644 fpga_diff/src/rtl/common/uvhs_ddr4_wrapper.sv create mode 100644 fpga_diff/user_script/.gitignore create mode 100644 fpga_diff/user_script/hw_run_download.tcl create mode 100644 fpga_diff/uvhs/README.md create mode 100644 fpga_diff/uvhs/assemble_uvhs.tcl create mode 100644 fpga_diff/uvhs/assign_pin_u22_f2.tcl create mode 100644 fpga_diff/uvhs/async_clocks.tcl create mode 100644 fpga_diff/uvhs/backend_run.tcl create mode 100644 fpga_diff/uvhs/check_flow_tools.sh create mode 100755 fpga_diff/uvhs/check_modules.sh create mode 100644 fpga_diff/uvhs/export_vivado_ip.tcl create mode 100644 fpga_diff/uvhs/filelist.awk create mode 100644 fpga_diff/uvhs/frontend_run.tcl create mode 100755 fpga_diff/uvhs/make_compat/csh create mode 100755 fpga_diff/uvhs/make_compat/make create mode 100755 fpga_diff/uvhs/patch_uvsyn_shell.sh create mode 100644 fpga_diff/uvhs/timing_common.tcl create mode 100644 fpga_diff/uvhs/uvhs.mk diff --git a/fpga_diff/Makefile b/fpga_diff/Makefile index 9f3d2ee4..7afa5eb4 100755 --- a/fpga_diff/Makefile +++ b/fpga_diff/Makefile @@ -99,3 +99,7 @@ get_synth_log: all: $(MAKE) update_core_flist CORE_DIR="$(CORE_DIR)" RTL_INCLUDE="$(RTL_INCLUDE)" $(MAKE) vivado CPU=$(CPU) SUFFIX="$(SUFFIX)" + +ifeq ($(UVHS),1) +include uvhs/uvhs.mk +endif diff --git a/fpga_diff/README.md b/fpga_diff/README.md index ec464c50..8023ad79 100755 --- a/fpga_diff/README.md +++ b/fpga_diff/README.md @@ -48,4 +48,16 @@ FPGA_DDR_LOAD_CMD="bash -lc ' \ ./fpga-host --diff -i .bin ``` +UVHS Flow +========= +The Hejian UVHS flow is opt-in and leaves the targets above unchanged. Configure +the UVHS tool environment in the runtime host shell, then invoke: + +```shell +make UVHS=1 uvhs_preflight CPU= +make UVHS=1 uvhs_all CPU= CORE_DIR=/path/to/generated/core SUFFIX= +``` + +See [`uvhs/README.md`](uvhs/README.md) for the required environment variables, +board template and vendor DDR IP inputs, stages, and runtime script. diff --git a/fpga_diff/src/rtl/common/core_def_xdma.sv b/fpga_diff/src/rtl/common/core_def_xdma.sv index 8956db12..ab5338a3 100755 --- a/fpga_diff/src/rtl/common/core_def_xdma.sv +++ b/fpga_diff/src/rtl/common/core_def_xdma.sv @@ -54,6 +54,7 @@ module core_def ( output [1:0] uhs1_drv_sth , output uhs1_swvolt_en , output sd_led_control , +`ifndef UVHS_UVW_AXI4_TO_DDR4 output [`CONFIG_RANK_WIDTH-1:0] DDR_CK_T , output [`CONFIG_RANK_WIDTH-1:0] DDR_CK_C , output [`CONFIG_RANK_WIDTH-1:0] DDR_CKE , @@ -68,6 +69,7 @@ module core_def ( inout [63:0] DDR_DQ , inout [7:0] DDR_DQS_T , inout [7:0] DDR_DQS_C , +`endif //==JTAG @@ -1124,6 +1126,7 @@ wire [7:0] br2cfg_wstrb; wire [0:0] br2cfg_wvalid; wire [31:0] XDMA_AXI_LITE_awaddr; + wire [2:0] XDMA_AXI_LITE_awprot; wire XDMA_AXI_LITE_awvalid; wire XDMA_AXI_LITE_awready; wire [31:0] XDMA_AXI_LITE_wdata; @@ -1134,6 +1137,7 @@ wire [0:0] br2cfg_wvalid; wire XDMA_AXI_LITE_bvalid; wire XDMA_AXI_LITE_bready; wire [31:0] XDMA_AXI_LITE_araddr; + wire [2:0] XDMA_AXI_LITE_arprot; wire XDMA_AXI_LITE_arvalid; wire XDMA_AXI_LITE_arready; wire [31:0] XDMA_AXI_LITE_rdata; @@ -1167,7 +1171,6 @@ wire [0:0] br2cfg_wvalid; wire difftest_startup_done_pcie; wire cpu_rstn_pcie; wire io_host_diff_enable_pcie; - wire xdma_link_up_pcie; reg [19:0] difftest_startup_wait_pcie; reg difftest_stream_enable_pcie; @@ -1175,13 +1178,6 @@ wire [0:0] br2cfg_wvalid; assign sys_rstn_io = sys_rstn & ~io_host_reset; assign cpu_rstn_io = cpu_rstn & ~io_host_reset; - reg [1:0] pcie_lnk_sync; - always @(posedge sys_clk_i) begin - if (!sys_rstn) pcie_lnk_sync <= 2'b00; - else pcie_lnk_sync <= {pcie_lnk_sync[0], pcie_ep_lnk_up}; - end - wire xdma_link_up = pcie_lnk_sync[1]; - RST_SYNC #( .SYNC_STAGES(3), .PIPELINE_STAGES(1), @@ -1202,17 +1198,9 @@ wire [0:0] br2cfg_wvalid; .sync_out (io_host_diff_enable_pcie) ); - RST_SYNC #( - .SYNC_STAGES(3), - .PIPELINE_STAGES(1), - .INIT(1'b0) - ) difftest_link_up_pcie_sync ( - .clk (difftest_pcie_clock), - .async_in (xdma_link_up), - .sync_out (xdma_link_up_pcie) - ); - - assign difftest_startup_ready_pcie = cpu_rstn_pcie & io_host_diff_enable_pcie & xdma_link_up_pcie; + // Host enables DiffTest only after XDMA is accessible. Do not feed the + // physical XDMA link-status output back into fabric logic. + assign difftest_startup_ready_pcie = cpu_rstn_pcie & io_host_diff_enable_pcie; assign difftest_startup_done_pcie = &difftest_startup_wait_pcie; always @(posedge difftest_pcie_clock) begin @@ -1244,7 +1232,7 @@ wire [0:0] br2cfg_wvalid; .M00_AXIS_0_tvalid (difftest_from_host_axis_tvalid), .XDMA_AXI_LITE_awaddr (XDMA_AXI_LITE_awaddr), - .XDMA_AXI_LITE_awprot (3'b000), + .XDMA_AXI_LITE_awprot (XDMA_AXI_LITE_awprot), .XDMA_AXI_LITE_awvalid(XDMA_AXI_LITE_awvalid), .XDMA_AXI_LITE_awready(XDMA_AXI_LITE_awready), .XDMA_AXI_LITE_wdata (XDMA_AXI_LITE_wdata), @@ -1255,7 +1243,7 @@ wire [0:0] br2cfg_wvalid; .XDMA_AXI_LITE_bvalid (XDMA_AXI_LITE_bvalid), .XDMA_AXI_LITE_bready (XDMA_AXI_LITE_bready), .XDMA_AXI_LITE_araddr (XDMA_AXI_LITE_araddr), - .XDMA_AXI_LITE_arprot (3'b000), + .XDMA_AXI_LITE_arprot (XDMA_AXI_LITE_arprot), .XDMA_AXI_LITE_arvalid(XDMA_AXI_LITE_arvalid), .XDMA_AXI_LITE_arready(XDMA_AXI_LITE_arready), .XDMA_AXI_LITE_rdata (XDMA_AXI_LITE_rdata), @@ -1276,13 +1264,13 @@ wire [0:0] br2cfg_wvalid; DifftestClockGate SOC_CLK_CTRL( .CK (sys_clk_i), - .E ((difftest_clock_enable & xdma_link_up ) || ~io_host_diff_enable || ~sys_rstn_io || ~cpu_rstn_io), + .E (difftest_clock_enable || ~io_host_diff_enable || ~sys_rstn_io || ~cpu_rstn_io), .Q (inter_soc_clk) ); DifftestClockGate RTC_CLK_CTRL( .CK (tmclk), - .E ((difftest_clock_enable & xdma_link_up) || ~io_host_diff_enable || ~sys_rstn_io || ~cpu_rstn_io ), + .E (difftest_clock_enable || ~io_host_diff_enable || ~sys_rstn_io || ~cpu_rstn_io ), .Q (inter_rtc_clk) ); @@ -1335,6 +1323,52 @@ mode_ctrl U_MODE_CTRL( .scan_mode ( ) ); +`ifdef UVHS_UVW_AXI4_TO_DDR4 +uvhs_ddr4_wrapper U_UVHS_UVW_AXI4_TO_DDR4 ( + .clk (inter_soc_clk), + .rstn (rstn_sw4), + .calib_complete (init_calib_complete), + .s_axi_awid (cpu2ddr_m2s_awid_mix), + .s_axi_awaddr (cpu2ddr_m2s_awaddr_mix), + .s_axi_awlen (cpu2ddr_m2s_awlen), + .s_axi_awsize (cpu2ddr_m2s_awsize), + .s_axi_awburst (cpu2ddr_m2s_awburst), + .s_axi_awlock (cpu2ddr_m2s_awlock), + .s_axi_awcache (cpu2ddr_m2s_awcache), + .s_axi_awprot (cpu2ddr_m2s_awprot), + .s_axi_awqos (cpu2ddr_m2s_awqos), + .s_axi_awregion (cpu2ddr_m2s_awregion), + .s_axi_awvalid (cpu2ddr_m2s_awvalid), + .s_axi_awready (cpu2ddr_s2m_awready), + .s_axi_wdata (cpu2ddr_m2s_wdata), + .s_axi_wstrb (cpu2ddr_m2s_wstrb), + .s_axi_wlast (cpu2ddr_m2s_wlast), + .s_axi_wvalid (cpu2ddr_m2s_wvalid), + .s_axi_wready (cpu2ddr_s2m_wready), + .s_axi_bid (cpu2ddr_s2m_bid), + .s_axi_bresp (cpu2ddr_s2m_bresp), + .s_axi_bvalid (cpu2ddr_s2m_bvalid), + .s_axi_bready (cpu2ddr_m2s_bready), + .s_axi_arid (cpu2ddr_m2s_arid_mix), + .s_axi_araddr (cpu2ddr_m2s_araddr_mix), + .s_axi_arlen (cpu2ddr_m2s_arlen), + .s_axi_arsize (cpu2ddr_m2s_arsize), + .s_axi_arburst (cpu2ddr_m2s_arburst), + .s_axi_arlock (cpu2ddr_m2s_arlock), + .s_axi_arcache (cpu2ddr_m2s_arcache), + .s_axi_arprot (cpu2ddr_m2s_arprot), + .s_axi_arqos (cpu2ddr_m2s_arqos), + .s_axi_arregion (cpu2ddr_m2s_arregion), + .s_axi_arvalid (cpu2ddr_m2s_arvalid), + .s_axi_arready (cpu2ddr_s2m_arready), + .s_axi_rid (cpu2ddr_s2m_rid), + .s_axi_rdata (cpu2ddr_s2m_rdata), + .s_axi_rresp (cpu2ddr_s2m_rresp), + .s_axi_rlast (cpu2ddr_s2m_rlast), + .s_axi_rvalid (cpu2ddr_s2m_rvalid), + .s_axi_rready (cpu2ddr_m2s_rready) +); +`else jtag_ddr_subsys_wrapper U_JTAG_DDR_SUBSYS( .DDR4_act_n (DDR_ACT_N), .DDR4_adr (DDR_A), @@ -1434,6 +1468,7 @@ jtag_ddr_subsys_wrapper U_JTAG_DDR_SUBSYS( .soc_rstn (rstn_sw4), .calib_complete (init_calib_complete) ); +`endif SimTop_wrapper U_CPU_TOP( .difftest_pcie_clock (difftest_pcie_clock), @@ -1649,6 +1684,9 @@ assign hpm_dig_result = 0; AXI_bridge CFG_AXI_bridge_i (.SYS_INTER_CLK (inter_soc_clk), +`ifdef UVHS_SOC_ADAPT + .SYS_INTER_ARESETN (inter_soc_sync_rstn), +`endif .ACLK (sys_clk_i), .ARESETN (axi_bclk_sync_rstn), diff --git a/fpga_diff/src/rtl/common/fpga_top_debug.sv b/fpga_diff/src/rtl/common/fpga_top_debug.sv index 9cf9bc9c..c984065d 100755 --- a/fpga_diff/src/rtl/common/fpga_top_debug.sv +++ b/fpga_diff/src/rtl/common/fpga_top_debug.sv @@ -34,14 +34,16 @@ module fpga_top_debug output uart2_sout, input uart2_sin, `endif - //PCIE + //PCIE +`ifndef UVHS_SOC_ADAPT input refclk_p, // pcie 100MHz input refclk_n, output PERST_N, - + input refclk2_p, // pcie 100MHz input refclk2_n, output PERST2_N, +`endif `ifdef XS_XDMA_EP input [`XDMA_PCIE_LANES-1:0] pci_ep_rxn, input [`XDMA_PCIE_LANES-1:0] pci_ep_rxp, @@ -53,6 +55,7 @@ module fpga_top_debug input pcie_ep_perstn, `endif //DDR +`ifndef UVHS_UVW_AXI4_TO_DDR4 output [`CONFIG_RANK_WIDTH-1:0] DDR0_CK_T, output [`CONFIG_RANK_WIDTH-1:0] DDR0_CK_C, output [`CONFIG_RANK_WIDTH-1:0] DDR0_CKE, @@ -67,6 +70,7 @@ module fpga_top_debug inout [63:0] DDR0_DQ, inout [7:0] DDR0_DQS_T, inout [7:0] DDR0_DQS_C, +`endif `ifdef XS_GMAC input RGMII_RXCLK, @@ -108,10 +112,20 @@ wire vio_sw4; wire sys_rstn; wire cpu_setn_buf; wire sys_clk_i, dev_clk_i; +wire sys_rstn_to_core; +wire cpu_rstn_to_core; +wire ddr_rstn_to_core; wire pcie_rstn; (*mark_debug = "true"*) wire cpu_setn_rflag; (*mark_debug = "true"*) reg cpu_rstn; +`ifdef UVHS_SOC_ADAPT +assign sys_rstn = rstn_sw6; +assign cpu_setn_buf = rstn_sw5; +assign sys_rstn_to_core = rstn_sw6; +assign cpu_rstn_to_core = rstn_sw5; +assign ddr_rstn_to_core = rstn_sw4; +`else IBUF sys_rstn_ibuf (.O(sys_rstn), .I(rstn_sw6)); IBUF cpu_rstn_ibuf (.O(cpu_setn_buf), .I(rstn_sw5)); OBUF pcie_rstn_obuf (.O(PERST_N), .I(vio_sw6)); @@ -133,13 +147,26 @@ always@(posedge sys_clk_i) begin cpu_rstn <= cpu_rstn; end +assign sys_rstn_to_core = sys_rstn && vio_sw6; +assign cpu_rstn_to_core = cpu_rstn; +assign ddr_rstn_to_core = rstn_sw4 && vio_sw4; +`endif + // Suppose PHY_RESET_B active high. // Although 88E1116R pin10 resetn is active low. // But this pin is on connector, which might not have current by default? assign PHY_RESET_B = cpu_rstn; -wire tmclk; wire tmclk_buf; +wire cqetmclk_buf; +wire dbg_clk_buf; + +`ifdef UVHS_SOC_ADAPT +assign tmclk_buf = clk8_p; +assign cqetmclk_buf = clk6_p; +assign dbg_clk_buf = clk5_p; +`else +wire tmclk; IBUFGDS ibufgds_tmclk_1MHz ( .I (clk8_p), @@ -153,7 +180,6 @@ BUFG bufg_tmclk ); wire cqetmclk; -wire cqetmclk_buf; IBUFGDS ibufgds_tmclk_200MHz ( .I (clk6_p), @@ -168,7 +194,6 @@ BUFG bufg_cqetmclk ); wire dbg_clk; -wire dbg_clk_buf; IBUFGDS ibufgds_dbgclk_25MHz ( .I (clk5_p), @@ -181,30 +206,44 @@ BUFG bufg_dbgclk .I (dbg_clk), .O (dbg_clk_buf) ); +`endif +`ifndef UVHS_SOC_ADAPT wire pcie_sysclk_gt; wire pcie_sysclk; IBUFDS_GTE4 refclk_ibuf ( - .O(pcie_sysclk_gt), - .ODIV2(pcie_sysclk), - .I(refclk_p), - .CEB(1'b0), + .O(pcie_sysclk_gt), + .ODIV2(pcie_sysclk), + .I(refclk_p), + .CEB(1'b0), .IB(refclk_n) ); IBUFDS_GTE4 refclk2_ibuf ( - .O(pcie2_sysclk_gt), - .ODIV2(pcie2_sysclk), - .I(refclk2_p), - .CEB(1'b0), + .O(pcie2_sysclk_gt), + .ODIV2(pcie2_sysclk), + .I(refclk2_p), + .CEB(1'b0), .IB(refclk2_n) ); +`endif +`ifdef UVHS_SOC_ADAPT +`ifdef UVHS_CPU_DEBUG_CLK assign sys_clk_i = dbg_clk_buf; assign dev_clk_i = dbg_clk_buf; +`else +assign sys_clk_i = cqetmclk_buf; +assign dev_clk_i = cqetmclk_buf; +`endif +`else +assign sys_clk_i = dbg_clk_buf; +assign dev_clk_i = dbg_clk_buf; +`endif +`ifndef UVHS_SOC_ADAPT vio_0 u_vio( .clk (dbg_clk_buf), @@ -212,6 +251,7 @@ vio_0 u_vio( .probe_out1 (vio_sw5), .probe_out2 (vio_sw4) ); +`endif //------------led test------------------ wire sdmmc_cclk_card; @@ -332,9 +372,9 @@ core_def core_def .cpu_wr_ddr_valid (led0), .sys_clk_i (sys_clk_i), .dev_clk_i (dev_clk_i), - .sys_rstn (sys_rstn && vio_sw6), - .cpu_rstn (cpu_rstn), - .rstn_sw4 (rstn_sw4 && vio_sw4), + .sys_rstn (sys_rstn_to_core), + .cpu_rstn (cpu_rstn_to_core), + .rstn_sw4 (ddr_rstn_to_core), .dft_lgc_rst_n (1'b1), .dft_se (1'b0), .chip_mode_i (2'b00), // normal mode @@ -394,7 +434,14 @@ core_def core_def .sd_card_wp_in (sdmmc_card_write_prot), .sd_cmd_in (sdmmc_sd_cmd_in), .sd_dat_in (sdmmc_sd_dat_in), - .sd_led_control ( ), + .sd_led_control ( ) +`ifdef XS_GMAC + , +`else +`ifndef UVHS_UVW_AXI4_TO_DDR4 + , +`endif +`endif `ifdef XS_GMAC // gmac @@ -407,10 +454,14 @@ core_def core_def .io_gmac_rx_clk ( io_gmac_rx_clk ), .io_gmac_rxd_vld ( io_gmac_rxd_vld ), .io_gmac_rxd ( io_gmac_rxd ), - .io_gmac_txd ( io_gmac_txd ), - `endif + .io_gmac_txd ( io_gmac_txd ) +`ifndef UVHS_UVW_AXI4_TO_DDR4 + , +`endif +`endif // ddr +`ifndef UVHS_UVW_AXI4_TO_DDR4 .DDR_CK_T (DDR0_CK_T ), .DDR_CK_C (DDR0_CK_C ), .DDR_CKE (DDR0_CKE ), @@ -424,7 +475,7 @@ core_def core_def .DDR_DM_N (DDR0_DM ), .DDR_DQ (DDR0_DQ ), .DDR_DQS_T (DDR0_DQS_T ), - .DDR_DQS_C (DDR0_DQS_C )/*, + .DDR_DQS_C (DDR0_DQS_C )/*, .DDR_ZQ (DDR0_ZQ), .gmac_gmii_mdc_o(gmac_gmii_mdc_o), .gmac_gmii_mdo_o(gmac_gmii_mdo_o), @@ -448,6 +499,7 @@ core_def core_def .jtag_tdo(jtag_tdo), */ +`endif ); diff --git a/fpga_diff/src/rtl/common/uvhs_axi64_to_axi256.sv b/fpga_diff/src/rtl/common/uvhs_axi64_to_axi256.sv new file mode 100644 index 00000000..23eaac51 --- /dev/null +++ b/fpga_diff/src/rtl/common/uvhs_axi64_to_axi256.sv @@ -0,0 +1,211 @@ +`timescale 1ns/1ps + +module uvhs_axi64_to_axi256 ( + input wire clk, + input wire rstn, + + input wire [13:0] s_axi_awid, + input wire [39:0] s_axi_awaddr, + input wire [7:0] s_axi_awlen, + input wire [2:0] s_axi_awsize, + input wire [1:0] s_axi_awburst, + input wire s_axi_awlock, + input wire [3:0] s_axi_awcache, + input wire [2:0] s_axi_awprot, + input wire [3:0] s_axi_awqos, + input wire s_axi_awvalid, + output wire s_axi_awready, + input wire [63:0] s_axi_wdata, + input wire [7:0] s_axi_wstrb, + input wire s_axi_wlast, + input wire s_axi_wvalid, + output wire s_axi_wready, + output wire [13:0] s_axi_bid, + output wire [1:0] s_axi_bresp, + output wire s_axi_bvalid, + input wire s_axi_bready, + + input wire [13:0] s_axi_arid, + input wire [39:0] s_axi_araddr, + input wire [7:0] s_axi_arlen, + input wire [2:0] s_axi_arsize, + input wire [1:0] s_axi_arburst, + input wire s_axi_arlock, + input wire [3:0] s_axi_arcache, + input wire [2:0] s_axi_arprot, + input wire [3:0] s_axi_arqos, + input wire s_axi_arvalid, + output wire s_axi_arready, + output wire [13:0] s_axi_rid, + output wire [63:0] s_axi_rdata, + output wire [1:0] s_axi_rresp, + output wire s_axi_rlast, + output wire s_axi_rvalid, + input wire s_axi_rready, + + output wire [13:0] m_axi_awid, + output wire [33:0] m_axi_awaddr, + output wire [7:0] m_axi_awlen, + output wire [2:0] m_axi_awsize, + output wire [1:0] m_axi_awburst, + output wire [0:0] m_axi_awlock, + output wire [3:0] m_axi_awcache, + output wire [2:0] m_axi_awprot, + output wire [3:0] m_axi_awqos, + output wire [3:0] m_axi_awregion, + output wire m_axi_awvalid, + input wire m_axi_awready, + output wire [255:0] m_axi_wdata, + output wire [31:0] m_axi_wstrb, + output wire m_axi_wlast, + output wire m_axi_wvalid, + input wire m_axi_wready, + input wire [13:0] m_axi_bid, + input wire [1:0] m_axi_bresp, + input wire m_axi_bvalid, + output wire m_axi_bready, + + output wire [13:0] m_axi_arid, + output wire [33:0] m_axi_araddr, + output wire [7:0] m_axi_arlen, + output wire [2:0] m_axi_arsize, + output wire [1:0] m_axi_arburst, + output wire [0:0] m_axi_arlock, + output wire [3:0] m_axi_arcache, + output wire [2:0] m_axi_arprot, + output wire [3:0] m_axi_arqos, + output wire [3:0] m_axi_arregion, + output wire m_axi_arvalid, + input wire m_axi_arready, + input wire [13:0] m_axi_rid, + input wire [255:0] m_axi_rdata, + input wire [1:0] m_axi_rresp, + input wire m_axi_rlast, + input wire m_axi_rvalid, + output wire m_axi_rready +); + + reg write_active; + reg write_resp_pending; + reg [1:0] write_lane; + reg [2:0] write_size; + reg [1:0] write_burst; + + reg read_active; + reg [1:0] read_lane; + reg [2:0] read_size; + reg [1:0] read_burst; + + wire [4:0] write_shift = {write_lane, 3'b000}; + wire [4:0] read_shift = {read_lane, 3'b000}; + wire [255:0] shifted_rdata = m_axi_rdata >> (read_shift * 8); + + assign m_axi_awid = s_axi_awid; + assign m_axi_awaddr = s_axi_awaddr[33:0]; + assign m_axi_awlen = s_axi_awlen; + assign m_axi_awsize = s_axi_awsize; + assign m_axi_awburst = s_axi_awburst; + assign m_axi_awlock = s_axi_awlock; + assign m_axi_awcache = s_axi_awcache; + assign m_axi_awprot = s_axi_awprot; + assign m_axi_awqos = s_axi_awqos; + assign m_axi_awregion = 4'b0; + assign m_axi_awvalid = s_axi_awvalid & ~write_active & ~write_resp_pending; + assign s_axi_awready = m_axi_awready & ~write_active & ~write_resp_pending; + + assign m_axi_wdata = {192'b0, s_axi_wdata} << (write_shift * 8); + assign m_axi_wstrb = {24'b0, s_axi_wstrb} << write_shift; + assign m_axi_wlast = s_axi_wlast; + assign m_axi_wvalid = s_axi_wvalid & write_active; + assign s_axi_wready = m_axi_wready & write_active; + + assign s_axi_bid = m_axi_bid; + assign s_axi_bresp = m_axi_bresp; + assign s_axi_bvalid = m_axi_bvalid; + assign m_axi_bready = s_axi_bready; + + assign m_axi_arid = s_axi_arid; + assign m_axi_araddr = s_axi_araddr[33:0]; + assign m_axi_arlen = s_axi_arlen; + assign m_axi_arsize = s_axi_arsize; + assign m_axi_arburst = s_axi_arburst; + assign m_axi_arlock = s_axi_arlock; + assign m_axi_arcache = s_axi_arcache; + assign m_axi_arprot = s_axi_arprot; + assign m_axi_arqos = s_axi_arqos; + assign m_axi_arregion = 4'b0; + assign m_axi_arvalid = s_axi_arvalid & ~read_active; + assign s_axi_arready = m_axi_arready & ~read_active; + + assign s_axi_rid = m_axi_rid; + assign s_axi_rdata = shifted_rdata[63:0]; + assign s_axi_rresp = m_axi_rresp; + assign s_axi_rlast = m_axi_rlast; + assign s_axi_rvalid = m_axi_rvalid & read_active; + assign m_axi_rready = s_axi_rready & read_active; + + function automatic [1:0] next_lane(input [1:0] lane, input [2:0] size, input [1:0] burst); + begin + // Both INCR and WRAP advance the transfer address on every beat. The + // NutShell cache-line port uses WRAP bursts, so keeping its lane fixed + // repeats lane zero after the first 64-bit beat on the 256-bit bus. + if ((burst == 2'b01 || burst == 2'b10) && size >= 3'd3) begin + next_lane = lane + (2'b01 << (size - 3'd3)); + end else begin + next_lane = lane; + end + end + endfunction + + always @(posedge clk) begin + if (!rstn) begin + write_active <= 1'b0; + write_resp_pending <= 1'b0; + write_lane <= 2'b0; + write_size <= 3'b0; + write_burst <= 2'b0; + end else begin + if (s_axi_awvalid && s_axi_awready) begin + write_active <= 1'b1; + write_resp_pending <= 1'b0; + write_lane <= s_axi_awaddr[4:3]; + write_size <= s_axi_awsize; + write_burst <= s_axi_awburst; + end else if (s_axi_wvalid && s_axi_wready) begin + if (s_axi_wlast) begin + write_active <= 1'b0; + write_resp_pending <= 1'b1; + end else begin + write_lane <= next_lane(write_lane, write_size, write_burst); + end + end + + if (s_axi_bvalid && s_axi_bready) begin + write_resp_pending <= 1'b0; + end + end + end + + always @(posedge clk) begin + if (!rstn) begin + read_active <= 1'b0; + read_lane <= 2'b0; + read_size <= 3'b0; + read_burst <= 2'b0; + end else begin + if (s_axi_arvalid && s_axi_arready) begin + read_active <= 1'b1; + read_lane <= s_axi_araddr[4:3]; + read_size <= s_axi_arsize; + read_burst <= s_axi_arburst; + end else if (s_axi_rvalid && s_axi_rready) begin + if (s_axi_rlast) begin + read_active <= 1'b0; + end else begin + read_lane <= next_lane(read_lane, read_size, read_burst); + end + end + end + end + +endmodule diff --git a/fpga_diff/src/rtl/common/uvhs_ddr4_wrapper.sv b/fpga_diff/src/rtl/common/uvhs_ddr4_wrapper.sv new file mode 100644 index 00000000..b0681b27 --- /dev/null +++ b/fpga_diff/src/rtl/common/uvhs_ddr4_wrapper.sv @@ -0,0 +1,306 @@ +`timescale 1ns/1ps + +module uvhs_ddr4_wrapper ( + input wire clk, + input wire rstn, + output wire calib_complete, + + input wire [17:0] s_axi_awid, +`ifdef CPU_NUTSHELL + input wire [32:0] s_axi_awaddr, +`else + input wire [39:0] s_axi_awaddr, +`endif + input wire [7:0] s_axi_awlen, + input wire [2:0] s_axi_awsize, + input wire [1:0] s_axi_awburst, + input wire s_axi_awlock, + input wire [3:0] s_axi_awcache, + input wire [2:0] s_axi_awprot, + input wire [3:0] s_axi_awqos, + input wire [3:0] s_axi_awregion, + input wire s_axi_awvalid, + output wire s_axi_awready, +`ifdef CPU_NUTSHELL + input wire [63:0] s_axi_wdata, + input wire [7:0] s_axi_wstrb, +`else + input wire [255:0] s_axi_wdata, + input wire [31:0] s_axi_wstrb, +`endif + input wire s_axi_wlast, + input wire s_axi_wvalid, + output wire s_axi_wready, + output wire [17:0] s_axi_bid, + output wire [1:0] s_axi_bresp, + output wire s_axi_bvalid, + input wire s_axi_bready, + + input wire [17:0] s_axi_arid, +`ifdef CPU_NUTSHELL + input wire [32:0] s_axi_araddr, +`else + input wire [39:0] s_axi_araddr, +`endif + input wire [7:0] s_axi_arlen, + input wire [2:0] s_axi_arsize, + input wire [1:0] s_axi_arburst, + input wire s_axi_arlock, + input wire [3:0] s_axi_arcache, + input wire [2:0] s_axi_arprot, + input wire [3:0] s_axi_arqos, + input wire [3:0] s_axi_arregion, + input wire s_axi_arvalid, + output wire s_axi_arready, + output wire [17:0] s_axi_rid, +`ifdef CPU_NUTSHELL + output wire [63:0] s_axi_rdata, +`else + output wire [255:0] s_axi_rdata, +`endif + output wire [1:0] s_axi_rresp, + output wire s_axi_rlast, + output wire s_axi_rvalid, + input wire s_axi_rready +); + + wire [13:0] ddr_awid; + wire [33:0] ddr_awaddr; + wire [7:0] ddr_awlen; + wire [2:0] ddr_awsize; + wire [1:0] ddr_awburst; + wire [0:0] ddr_awlock; + wire [3:0] ddr_awcache; + wire [2:0] ddr_awprot; + wire [3:0] ddr_awqos; + wire [3:0] ddr_awregion; + wire ddr_awvalid; + wire ddr_awready; + wire [255:0] ddr_wdata; + wire [31:0] ddr_wstrb; + wire ddr_wlast; + wire ddr_wvalid; + wire ddr_wready; + wire [13:0] ddr_bid; + wire [1:0] ddr_bresp; + wire ddr_bvalid; + wire ddr_bready; + wire [13:0] ddr_arid; + wire [33:0] ddr_araddr; + wire [7:0] ddr_arlen; + wire [2:0] ddr_arsize; + wire [1:0] ddr_arburst; + wire [0:0] ddr_arlock; + wire [3:0] ddr_arcache; + wire [2:0] ddr_arprot; + wire [3:0] ddr_arqos; + wire [3:0] ddr_arregion; + wire ddr_arvalid; + wire ddr_arready; + wire [255:0] ddr_rdata; + wire [13:0] ddr_rid; + wire [1:0] ddr_rresp; + wire ddr_rlast; + wire ddr_rvalid; + wire ddr_rready; + wire ddr_user_rst; + +`ifdef CPU_NUTSHELL + wire [13:0] s_axi_bid_64; + wire [13:0] s_axi_rid_64; + wire [63:0] s_axi_rdata_64; + + assign s_axi_bid = {4'b0, s_axi_bid_64}; + assign s_axi_rid = {4'b0, s_axi_rid_64}; + assign s_axi_rdata = s_axi_rdata_64; + + uvhs_axi64_to_axi256 width_adapter ( + .clk(clk), + .rstn(rstn), + .s_axi_awid(s_axi_awid[13:0]), + .s_axi_awaddr({7'b0, s_axi_awaddr}), + .s_axi_awlen(s_axi_awlen), + .s_axi_awsize(s_axi_awsize), + .s_axi_awburst(s_axi_awburst), + .s_axi_awlock(s_axi_awlock), + .s_axi_awcache(s_axi_awcache), + .s_axi_awprot(s_axi_awprot), + .s_axi_awqos(s_axi_awqos), + .s_axi_awvalid(s_axi_awvalid), + .s_axi_awready(s_axi_awready), + .s_axi_wdata(s_axi_wdata[63:0]), + .s_axi_wstrb(s_axi_wstrb[7:0]), + .s_axi_wlast(s_axi_wlast), + .s_axi_wvalid(s_axi_wvalid), + .s_axi_wready(s_axi_wready), + .s_axi_bid(s_axi_bid_64), + .s_axi_bresp(s_axi_bresp), + .s_axi_bvalid(s_axi_bvalid), + .s_axi_bready(s_axi_bready), + .s_axi_arid(s_axi_arid[13:0]), + .s_axi_araddr({7'b0, s_axi_araddr}), + .s_axi_arlen(s_axi_arlen), + .s_axi_arsize(s_axi_arsize), + .s_axi_arburst(s_axi_arburst), + .s_axi_arlock(s_axi_arlock), + .s_axi_arcache(s_axi_arcache), + .s_axi_arprot(s_axi_arprot), + .s_axi_arqos(s_axi_arqos), + .s_axi_arvalid(s_axi_arvalid), + .s_axi_arready(s_axi_arready), + .s_axi_rid(s_axi_rid_64), + .s_axi_rdata(s_axi_rdata_64), + .s_axi_rresp(s_axi_rresp), + .s_axi_rlast(s_axi_rlast), + .s_axi_rvalid(s_axi_rvalid), + .s_axi_rready(s_axi_rready), + .m_axi_awid(ddr_awid), + .m_axi_awaddr(ddr_awaddr), + .m_axi_awlen(ddr_awlen), + .m_axi_awsize(ddr_awsize), + .m_axi_awburst(ddr_awburst), + .m_axi_awlock(ddr_awlock), + .m_axi_awcache(ddr_awcache), + .m_axi_awprot(ddr_awprot), + .m_axi_awqos(ddr_awqos), + .m_axi_awregion(ddr_awregion), + .m_axi_awvalid(ddr_awvalid), + .m_axi_awready(ddr_awready), + .m_axi_wdata(ddr_wdata), + .m_axi_wstrb(ddr_wstrb), + .m_axi_wlast(ddr_wlast), + .m_axi_wvalid(ddr_wvalid), + .m_axi_wready(ddr_wready), + .m_axi_bid(ddr_bid), + .m_axi_bresp(ddr_bresp), + .m_axi_bvalid(ddr_bvalid), + .m_axi_bready(ddr_bready), + .m_axi_arid(ddr_arid), + .m_axi_araddr(ddr_araddr), + .m_axi_arlen(ddr_arlen), + .m_axi_arsize(ddr_arsize), + .m_axi_arburst(ddr_arburst), + .m_axi_arlock(ddr_arlock), + .m_axi_arcache(ddr_arcache), + .m_axi_arprot(ddr_arprot), + .m_axi_arqos(ddr_arqos), + .m_axi_arregion(ddr_arregion), + .m_axi_arvalid(ddr_arvalid), + .m_axi_arready(ddr_arready), + .m_axi_rid(ddr_rid), + .m_axi_rdata(ddr_rdata), + .m_axi_rresp(ddr_rresp), + .m_axi_rlast(ddr_rlast), + .m_axi_rvalid(ddr_rvalid), + .m_axi_rready(ddr_rready) + ); +`else + assign ddr_awid = s_axi_awid[13:0]; + assign ddr_awaddr = s_axi_awaddr[33:0]; + assign ddr_awlen = s_axi_awlen; + assign ddr_awsize = s_axi_awsize; + assign ddr_awburst = s_axi_awburst; + assign ddr_awlock = s_axi_awlock; + assign ddr_awcache = s_axi_awcache; + assign ddr_awprot = s_axi_awprot; + assign ddr_awqos = s_axi_awqos; + assign ddr_awregion = s_axi_awregion; + assign ddr_awvalid = s_axi_awvalid; + assign s_axi_awready = ddr_awready; + assign ddr_wdata = s_axi_wdata; + assign ddr_wstrb = s_axi_wstrb; + assign ddr_wlast = s_axi_wlast; + assign ddr_wvalid = s_axi_wvalid; + assign s_axi_wready = ddr_wready; + assign s_axi_bid = {4'b0, ddr_bid}; + assign s_axi_bresp = ddr_bresp; + assign s_axi_bvalid = ddr_bvalid; + assign ddr_bready = s_axi_bready; + assign ddr_arid = s_axi_arid[13:0]; + assign ddr_araddr = s_axi_araddr[33:0]; + assign ddr_arlen = s_axi_arlen; + assign ddr_arsize = s_axi_arsize; + assign ddr_arburst = s_axi_arburst; + assign ddr_arlock = s_axi_arlock; + assign ddr_arcache = s_axi_arcache; + assign ddr_arprot = s_axi_arprot; + assign ddr_arqos = s_axi_arqos; + assign ddr_arregion = s_axi_arregion; + assign ddr_arvalid = s_axi_arvalid; + assign s_axi_arready = ddr_arready; + assign s_axi_rid = {4'b0, ddr_rid}; + assign s_axi_rdata = ddr_rdata; + assign s_axi_rresp = ddr_rresp; + assign s_axi_rlast = ddr_rlast; + assign s_axi_rvalid = ddr_rvalid; + assign ddr_rready = s_axi_rready; +`endif + + assign calib_complete = rstn & ~ddr_user_rst; + + uvw_axi4_to_ddr4 ddr4_ip ( + .ddr4ip_dut_axi_aclk(clk), + .ddr4ip_dut_axi_aresetn(rstn), + .ddr4ip_dut_axi_awaddr(ddr_awaddr), + .ddr4ip_dut_axi_awburst(ddr_awburst), + .ddr4ip_dut_axi_awcache(ddr_awcache), + .ddr4ip_dut_axi_awid(ddr_awid), + .ddr4ip_dut_axi_awlen(ddr_awlen), + .ddr4ip_dut_axi_awlock(ddr_awlock), + .ddr4ip_dut_axi_awprot(ddr_awprot), + .ddr4ip_dut_axi_awqos(ddr_awqos), + .ddr4ip_dut_axi_awready(ddr_awready), + .ddr4ip_dut_axi_awregion(ddr_awregion), + .ddr4ip_dut_axi_awsize(ddr_awsize), + .ddr4ip_dut_axi_awvalid(ddr_awvalid), + .ddr4ip_dut_axi_wdata(ddr_wdata), + .ddr4ip_dut_axi_wlast(ddr_wlast), + .ddr4ip_dut_axi_wready(ddr_wready), + .ddr4ip_dut_axi_wstrb(ddr_wstrb), + .ddr4ip_dut_axi_wvalid(ddr_wvalid), + .ddr4ip_dut_axi_bid(ddr_bid), + .ddr4ip_dut_axi_bready(ddr_bready), + .ddr4ip_dut_axi_bresp(ddr_bresp), + .ddr4ip_dut_axi_bvalid(ddr_bvalid), + .ddr4ip_dut_axi_araddr(ddr_araddr), + .ddr4ip_dut_axi_arburst(ddr_arburst), + .ddr4ip_dut_axi_arcache(ddr_arcache), + .ddr4ip_dut_axi_arid(ddr_arid), + .ddr4ip_dut_axi_arlen(ddr_arlen), + .ddr4ip_dut_axi_arlock(ddr_arlock), + .ddr4ip_dut_axi_arprot(ddr_arprot), + .ddr4ip_dut_axi_arqos(ddr_arqos), + .ddr4ip_dut_axi_arready(ddr_arready), + .ddr4ip_dut_axi_arregion(ddr_arregion), + .ddr4ip_dut_axi_arsize(ddr_arsize), + .ddr4ip_dut_axi_arvalid(ddr_arvalid), + .ddr4ip_dut_axi_rdata(ddr_rdata), + .ddr4ip_dut_axi_rid(ddr_rid), + .ddr4ip_dut_axi_rlast(ddr_rlast), + .ddr4ip_dut_axi_rready(ddr_rready), + .ddr4ip_dut_axi_rresp(ddr_rresp), + .ddr4ip_dut_axi_rvalid(ddr_rvalid), + .ddr4ip_dut_axi_aclk_en(1'b1), + .ddr4ip_ddr4_user_clk(), + .ddr4ip_ddr4_user_rst(ddr_user_rst), + .sysbus_ghbd_i(256'b0), + .sysbus_ghbd_o(), + .FP_CLK_200M_P(), + .FP_CLK_200M_N(), + .DDR4_DIMM_ACT_N(), + .DDR4_DIMM_A(), + .DDR4_DIMM_BA(), + .DDR4_DIMM_BG(), + .DDR4_DIMM_CK_N(), + .DDR4_DIMM_CK_P(), + .DDR4_DIMM_CKE(), + .DDR4_DIMM_CS_N(), + .DDR4_DIMM_ODT(), + .DDR4_DIMM_RST_B(), + .DDR4_DIMM_DM(), + .DDR4_DIMM_DQ(), + .DDR4_DIMM_DQS_N(), + .DDR4_DIMM_DQS_P() + ); + +endmodule diff --git a/fpga_diff/src/tcl/common/AXI_bridge.tcl b/fpga_diff/src/tcl/common/AXI_bridge.tcl index c79b8654..f33eb947 100644 --- a/fpga_diff/src/tcl/common/AXI_bridge.tcl +++ b/fpga_diff/src/tcl/common/AXI_bridge.tcl @@ -249,12 +249,20 @@ proc create_root_design { parentCell } { set ACLK [ create_bd_port -dir I -type clk -freq_hz 25000000 ACLK ] set_property -dict [ list \ CONFIG.ASSOCIATED_BUSIF {rom_axi} \ - ] $ACLK + ] $ACLK set ARESETN [ create_bd_port -dir I -type rst ARESETN ] set SYS_INTER_CLK [ create_bd_port -dir I -type clk -freq_hz 25000000 SYS_INTER_CLK ] set_property -dict [ list \ CONFIG.ASSOCIATED_BUSIF {S00_AXI} \ - ] $SYS_INTER_CLK + ] $SYS_INTER_CLK + set uvhs_flow [expr {[info exists ::env(UVHS_FLOW)] && $::env(UVHS_FLOW) eq "1"}] + if {$uvhs_flow} { + set_property CONFIG.ASSOCIATED_RESET {ARESETN} $ACLK + set_property CONFIG.POLARITY {ACTIVE_LOW} $ARESETN + set_property CONFIG.ASSOCIATED_RESET {SYS_INTER_ARESETN} $SYS_INTER_CLK + set SYS_INTER_ARESETN [ create_bd_port -dir I -type rst SYS_INTER_ARESETN ] + set_property CONFIG.POLARITY {ACTIVE_LOW} $SYS_INTER_ARESETN + } set uart0_intc [ create_bd_port -dir O -type intr uart0_intc ] # Create instance: axi_apb_bridge_0, and set properties @@ -326,8 +334,26 @@ proc create_root_design { parentCell } { # Create port connections connect_bd_net -net ACLK_0_1 [get_bd_ports ACLK] [get_bd_pins axi_apb_bridge_0/s_axi_aclk] [get_bd_pins axi_interconnect_0/ACLK] [get_bd_pins axi_interconnect_0/M00_ACLK] [get_bd_pins axi_interconnect_0/M01_ACLK] [get_bd_pins axi_interconnect_0/M02_ACLK] [get_bd_pins axi_interconnect_0/M03_ACLK] [get_bd_pins axi_interconnect_0/S01_ACLK] [get_bd_pins axi_uart16550_0/s_axi_aclk] [get_bd_pins extllc_bram_ctrl/s_axi_aclk] [get_bd_pins jtag_axi_flash/aclk] - connect_bd_net -net ARESETN_0_1 [get_bd_ports ARESETN] [get_bd_pins axi_apb_bridge_0/s_axi_aresetn] [get_bd_pins axi_interconnect_0/ARESETN] [get_bd_pins axi_interconnect_0/M00_ARESETN] [get_bd_pins axi_interconnect_0/M01_ARESETN] [get_bd_pins axi_interconnect_0/M02_ARESETN] [get_bd_pins axi_interconnect_0/M03_ARESETN] [get_bd_pins axi_interconnect_0/S00_ARESETN] [get_bd_pins axi_interconnect_0/S01_ARESETN] [get_bd_pins axi_uart16550_0/s_axi_aresetn] [get_bd_pins extllc_bram_ctrl/s_axi_aresetn] [get_bd_pins jtag_axi_flash/aresetn] + set aresetn_pins [list \ + [get_bd_pins axi_apb_bridge_0/s_axi_aresetn] \ + [get_bd_pins axi_interconnect_0/ARESETN] \ + [get_bd_pins axi_interconnect_0/M00_ARESETN] \ + [get_bd_pins axi_interconnect_0/M01_ARESETN] \ + [get_bd_pins axi_interconnect_0/M02_ARESETN] \ + [get_bd_pins axi_interconnect_0/M03_ARESETN] \ + [get_bd_pins axi_interconnect_0/S01_ARESETN] \ + [get_bd_pins axi_uart16550_0/s_axi_aresetn] \ + [get_bd_pins extllc_bram_ctrl/s_axi_aresetn] \ + [get_bd_pins jtag_axi_flash/aresetn] \ + ] + if {!$uvhs_flow} { + lappend aresetn_pins [get_bd_pins axi_interconnect_0/S00_ARESETN] + } + connect_bd_net -net ARESETN_0_1 [get_bd_ports ARESETN] {*}$aresetn_pins connect_bd_net -net SYS_INTER_CLK_1 [get_bd_ports SYS_INTER_CLK] [get_bd_pins axi_interconnect_0/S00_ACLK] + if {$uvhs_flow} { + connect_bd_net -net SYS_INTER_ARESETN_1 [get_bd_ports SYS_INTER_ARESETN] [get_bd_pins axi_interconnect_0/S00_ARESETN] + } connect_bd_net -net axi_uart16550_0_ip2intc_irpt [get_bd_ports uart0_intc] [get_bd_pins axi_uart16550_0/ip2intc_irpt] connect_bd_net -net xlconstant_0_dout [get_bd_pins axi_uart16550_0/freeze] [get_bd_pins xlconstant_0/dout] diff --git a/fpga_diff/src/tcl/common/xdma_ep.tcl b/fpga_diff/src/tcl/common/xdma_ep.tcl index feee4ad8..d254ba7a 100644 --- a/fpga_diff/src/tcl/common/xdma_ep.tcl +++ b/fpga_diff/src/tcl/common/xdma_ep.tcl @@ -174,6 +174,18 @@ proc env_choice {name default allowed} { return $value } +proc env_positive_integer {name default} { + set value $default + if {[info exists ::env($name)] && [string trim $::env($name)] ne ""} { + set value [string trim $::env($name)] + } + if {![string is integer -strict $value] || $value <= 0} { + error "$name must be a positive integer, got '$value'" + } + puts "INFO: $name=$value" + return $value +} + if { $bCheckIPs == 1 } { common::send_gid_msg -ssname BD::TCL -id 2058 -severity "INFO" "Current scripts_vivado_version value: '$::vivado_version'" @@ -221,6 +233,13 @@ proc create_root_design { parentCell } { variable xdma_vlnv variable util_vlnv set xdma_link_width [env_choice XDMA_LINK_WIDTH X4 {X4 X8}] + set uvhs_flow [expr {[info exists ::env(UVHS_FLOW)] && $::env(UVHS_FLOW) eq "1"}] + if {$uvhs_flow} { + set xdma_enable_pf0_bar1 [env_choice XDMA_ENABLE_PF0_BAR1 1 {0 1}] + set xdma_axilite_master_scale [env_choice XDMA_AXILITE_MASTER_SCALE Kilobytes {Kilobytes Megabytes Gigabytes}] + set xdma_axilite_master_size [env_positive_integer XDMA_AXILITE_MASTER_SIZE 512] + set xdma_pf0_bar1_enabled [expr {$xdma_enable_pf0_bar1 eq "1" ? "true" : "false"}] + } set xdma_lane_count [string range $xdma_link_width 1 end] set xdma_lane_msb [expr {$xdma_lane_count - 1}] if {$xdma_link_width eq "X4"} { @@ -378,6 +397,16 @@ proc create_root_design { parentCell } { error "Unsupported XDMA IP version: $xdma_vlnv (only 4.1 or 4.2 supported)" } + if {$uvhs_flow} { + set_property -dict [list \ + CONFIG.axilite_master_scale $xdma_axilite_master_scale \ + CONFIG.axilite_master_size $xdma_axilite_master_size \ + CONFIG.pf0_bar1_enabled $xdma_pf0_bar1_enabled \ + CONFIG.pf0_bar1_scale {Kilobytes} \ + CONFIG.pf0_bar1_size {64} \ + ] $xdma_0 + } + puts "INFO: wiring XDMA ST interfaces directly on axi_aclk" # Create interface connections diff --git a/fpga_diff/user_script/.gitignore b/fpga_diff/user_script/.gitignore new file mode 100644 index 00000000..6ab2da6e --- /dev/null +++ b/fpga_diff/user_script/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!hw_run_download.tcl diff --git a/fpga_diff/user_script/hw_run_download.tcl b/fpga_diff/user_script/hw_run_download.tcl new file mode 100644 index 00000000..2572b454 --- /dev/null +++ b/fpga_diff/user_script/hw_run_download.tcl @@ -0,0 +1,67 @@ +# UVHS runtime download flow. A release database is sufficient for programming +# and reset release; host software loads the workload through H2C afterwards. + +query -user +query -fpgas -all +query -version + +# uv_shell runtime invocation does not guarantee the script directory as the +# current working directory. Prefer an explicit override, otherwise assume the +# staged hw.dat sits next to user_script/ in the runtime directory. +if {[info exists ::env(UVHS_DB_PATH)] && $::env(UVHS_DB_PATH) ne ""} { + set uvhs_db_path $::env(UVHS_DB_PATH) +} else { + set uvhs_script_dir [file dirname [file normalize [info script]]] + set uvhs_db_path [file normalize [file join $uvhs_script_dir .. hw.dat]] +} +puts "INFO: loading runtime database $uvhs_db_path" +load_db -db $uvhs_db_path + +config -connector +query -connector -type fmc +query -voltage + +# Some release databases carry replay clock values without UVHS sign-off +# frequencies. Configure defaults when available; otherwise retain the +# database replay clocks, as the x4 runtime template does. +if {[catch {query -clock -default} uvhs_clock_error]} { + puts "WARN: no sign-off default clock; retaining database replay clocks: $uvhs_clock_error" +} else { + config -clock -default + config -clock -commit + query -clock +} + +# Hold the top-level resets low across download, then release them in the +# same order used by the checked-in runtime scripts for this design. The host +# keeps CPU execution stopped later through HOST_IO_RESET while DDR is written. +reset -name rstn_sw6 -value 0 +reset -name rstn_sw5 -value 0 +reset -name rstn_sw4 -value 0 +query -reset + +download + +query -ipinfo +initialize +after 1000 + +reset -name rstn_sw6 -value 0 +reset -name rstn_sw5 -value 0 +reset -name rstn_sw4 -value 0 +after 1000 + +reset -name rstn_sw6 -value 1 +reset -name rstn_sw4 -value 1 +after 1000 + +reset -name rstn_sw5 -value 1 +after 1000 + +query -reset +query -fpgas -all + +# Keep the runtime attached after download. Terminate uv_shell when the board +# is no longer needed. +set ::uvhs_keepalive 0 +vwait ::uvhs_keepalive diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md new file mode 100644 index 00000000..0f49e6cd --- /dev/null +++ b/fpga_diff/uvhs/README.md @@ -0,0 +1,73 @@ +# UVHS FPGA-Diff Flow + +This directory contains the UVHS implementation flow for FPGA-Diff designs on +the U2.2 B0/F2 target. It is selected explicitly with `UVHS=1`; the top-level +Makefile otherwise retains the normal Vivado flow unchanged. + +## Environment + +Configure the runtime host shell before invoking `make`. The following values +are the validated Hejian runtime installation; `UVHS_TEMPLATE_DIR` and +`UVHS_UVW_AXI4_TO_DDR4_SRC` identify the locally installed base project and +vendor DDR IP and therefore remain site-specific. + +```sh +export UV_ROOT=/home/data/UVHS/2506p4_0210 +export UV_XILINX_VIVADO=/home/data/test/tools/vivado_2024/Vivado/2024.2 +export XILINX_HLS= +export UV_LICENSE=8273@localhost +export UVHS_TEMPLATE_DIR=/path/to/uvhs-template +export UVHS_UVW_AXI4_TO_DDR4_SRC=/path/to/uvw_axi4_to_ddr4 +``` + +`UVHS_TEMPLATE_DIR` supplies the board assembly skeleton. The source tree +regenerates its own Vivado DCPs and does not carry generated DCPs, bitstreams, +or machine paths. + +## Build + +```sh +make UVHS=1 uvhs_tools_check +make UVHS=1 uvhs_preflight CPU= +make UVHS=1 uvhs_frontend CPU= CORE_DIR=/path/to/generated/core SUFFIX= +make UVHS=1 uvhs_backend CPU= SUFFIX= +make UVHS=1 uvhs_package_bitstream CPU= SUFFIX= +``` + +`uvhs_frontend` creates `hw.dat`, imports the generated Vivado IP DCPs and the +vendor DDR DCP, elaborates the RTL, and records board/clock constraints. +`uvhs_backend` partitions and localizes that database, generates the vendor +implementation scripts, then runs placement, routing, timing signoff, and +bitstream generation. Thus frontend is close to synthesis/elaboration and +backend is close to physical implementation, but the boundary is UVHS's +database handoff rather than a direct Vivado `synth_design` boundary. + +`uvhs_all` runs frontend then backend. `UVHS_EXPORT_IP_FORCE=1` rebuilds the +source-generated Vivado DCPs; the default reuses an existing DCP in the chosen +work directory. `uvhs_clean` removes only the explicitly selected +`UVHS_WORK_DIR`. + +## Runtime + +Use `user_script/hw_run_download.tcl` with the completed `hw.dat` database. +It downloads the design and releases the software resets. The host-side +FPGA-Diff flow loads the workload through H2C after download; the runtime Tcl +does not contain workload, debug, or command-file hooks. + +## Files + +| File | Role | +| --- | --- | +| `uvhs.mk` | UVHS-only Make targets, prerequisites, DCP export, and stage invocation. | +| `export_vivado_ip.tcl` | Regenerates repository-owned Vivado IP/BD DCPs. | +| `frontend_run.tcl` | Creates the UVHS database, imports DCPs, reads RTL, and runs frontend. | +| `backend_run.tcl` | Applies implementation-stage clock/constraint compatibility patches and runs P&R. | +| `assemble_uvhs.tcl` | Adapts the template assembly to the selected B0/F2 board instance and DDR IP. | +| `assign_pin_u22_f2.tcl` | Assigns target-board clocks, PCIe, UART, and reset-visible top ports. | +| `timing_common.tcl`, `async_clocks.tcl` | Declare clocks and asynchronous clock-domain relationships. | +| `check_modules.sh`, `filelist.awk`, `check_flow_tools.sh` | Validate the generated RTL file list and checked-in flow sources. | +| `make_compat/` | Supplies the Bash-compatible commands required by UVHS-generated Makefiles and its `csh -fc limit` probe. | +| `patch_uvsyn_shell.sh` | Patches the generated worker Makefile to run the vendor `uv_shell` script through Bash. | +| `uvhs_axi64_to_axi256.sv` | Converts a 64-bit source AXI data path to the vendor DDR IP's 256-bit interface. | +| `uvhs_ddr4_wrapper.sv` | Isolates the vendor DDR AXI wiring from the common FPGA-Diff top-level RTL. | +| `../user_script/hw_run_download.tcl` | Downloads and initializes a completed UVHS database. | diff --git a/fpga_diff/uvhs/assemble_uvhs.tcl b/fpga_diff/uvhs/assemble_uvhs.tcl new file mode 100644 index 00000000..77568339 --- /dev/null +++ b/fpga_diff/uvhs/assemble_uvhs.tcl @@ -0,0 +1,229 @@ +################################################################################ +# UVHS-only board assembly overlay for fpga_diff. +################################################################################ + +proc uvhs_env_or_default {name default} { + if {[info exists ::env($name)] && $::env($name) ne ""} { + return $::env($name) + } + return $default +} + +proc uvhs_env_if_exists_or_default {name default} { + if {[info exists ::env($name)]} { + return $::env($name) + } + return $default +} + +set uvhs_base_assemble ./script/1B_4F_HGC_assemble.tcl +set uvhs_uvw_ddr4_mode [expr {[uvhs_env_or_default UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP 0] eq "1"}] +set uvhs_default_mem_dc [expr {$uvhs_uvw_ddr4_mode ? "none" : "UV_MEM_ARRAY_F"}] +set uvhs_mem_dc [uvhs_env_or_default UVHS_MEM_ARRAY_DC $uvhs_default_mem_dc] +set uvhs_mem_inst [uvhs_env_or_default UVHS_MEM_ARRAY_INST mem_array_inst0] +set uvhs_mem_connector [uvhs_env_or_default UVHS_MEM_ARRAY_CONNECTOR b0.F2_FMC1] +set uvhs_replace_inst [uvhs_env_or_default UVHS_MEM_ARRAY_REPLACE_INST pddr4dme_inst2] +set uvhs_replace_connector [uvhs_env_or_default UVHS_MEM_ARRAY_REPLACE_CONNECTOR b0.F2_FMC3] +set uvhs_aux_ddr_dc [uvhs_env_if_exists_or_default UVHS_AUX_DDR_DC UV_FMCH_PDDR4DME] +set uvhs_aux_ddr_inst [uvhs_env_or_default UVHS_AUX_DDR_INST pddr4dme_f2_aux_inst] +set uvhs_aux_ddr_connector [uvhs_env_or_default UVHS_AUX_DDR_CONNECTOR b0.F2_FMC2] +set uvhs_aux_swap_base_connector [uvhs_env_or_default UVHS_AUX_DDR_SWAP_BASE_CONNECTOR ""] +set uvhs_target_fpga [string tolower [uvhs_env_or_default UVHS_TARGET_FPGA_LOWER b0.f2]] +set uvhs_known_fpgas {b0.f0 b0.f1 b0.f2 b0.f3} +set uvhs_keep_fpgas {} +foreach uvhs_fpga [split [uvhs_env_or_default UVHS_KEEP_FPGAS $uvhs_target_fpga]] { + set uvhs_fpga [string tolower [string trim $uvhs_fpga]] + if {$uvhs_fpga ne "" && [lsearch -exact $uvhs_keep_fpgas $uvhs_fpga] < 0} { + lappend uvhs_keep_fpgas $uvhs_fpga + } +} +if {[lsearch -exact $uvhs_keep_fpgas $uvhs_target_fpga] < 0} { + lappend uvhs_keep_fpgas $uvhs_target_fpga +} +foreach uvhs_fpga $uvhs_keep_fpgas { + if {[lsearch -exact $uvhs_known_fpgas $uvhs_fpga] < 0} { + error "UVHS_KEEP_FPGAS contains unknown FPGA '$uvhs_fpga'" + } +} +# The deployed U2 exposes the B0 PLL clock bank directly and reports no +# external ClockHub at runtime. Keep the overlay opt-in for other systems. +set uvhs_enable_clock_hub [expr {[uvhs_env_or_default UVHS_ENABLE_CLOCK_HUB 0] eq "1"}] + +if {![file exists $uvhs_base_assemble]} { + error "missing base assembly file: $uvhs_base_assemble" +} + +set uvhs_fh [open $uvhs_base_assemble r] +set uvhs_base_data [read $uvhs_fh] +close $uvhs_fh + +set uvhs_remove_dc_instances {} +foreach uvhs_line [split $uvhs_base_data "\n"] { + set uvhs_trimmed_line [string trim $uvhs_line] + set uvhs_lower_line [string tolower $uvhs_trimmed_line] + if {[regexp {^config_hw[ \t]+-connect_daughter_card[ \t]+\{([^ \t]+)[ \t]+([^ \t]+)\.FMC\}} $uvhs_trimmed_line -> uvhs_connector uvhs_instance]} { + set uvhs_lower_connector [string tolower $uvhs_connector] + set uvhs_connector_fpga "" + foreach uvhs_fpga $uvhs_known_fpgas { + if {[string first $uvhs_fpga $uvhs_lower_connector] == 0} { + set uvhs_connector_fpga $uvhs_fpga + break + } + } + if {$uvhs_connector_fpga ne "" && [lsearch -exact $uvhs_keep_fpgas $uvhs_connector_fpga] < 0} { + lappend uvhs_remove_dc_instances $uvhs_instance + } + } +} + +if {$uvhs_mem_dc ne "" && $uvhs_mem_dc ne "none" && $uvhs_replace_inst ne "" && $uvhs_replace_inst ne "none"} { + set uvhs_remove_create "config_hw -create_daughter_card UV_FMCH_PDDR4DME -instance $uvhs_replace_inst" + set uvhs_remove_connect "config_hw -connect_daughter_card \\{$uvhs_replace_connector $uvhs_replace_inst.FMC\\}" + regsub -line -all "^$uvhs_remove_create\[ \t\]*\n" $uvhs_base_data "" uvhs_base_data + regsub -line -all "^$uvhs_remove_connect\[ \t\]*\n" $uvhs_base_data "" uvhs_base_data + puts "INFO: UVHS memory overlay: replace $uvhs_replace_inst on $uvhs_replace_connector" +} + +set uvhs_filtered_lines [list] +foreach uvhs_line [split $uvhs_base_data "\n"] { + set uvhs_trimmed_line [string trim $uvhs_line] + if {[regexp {^config_hw[ \t]+-create_(daughter_card|peripheral)[ \t]+[^ \t]+[ \t]+-instance[ \t]+([^ \t]+)} $uvhs_trimmed_line -> uvhs_create_type uvhs_instance] && + [lsearch -exact $uvhs_remove_dc_instances $uvhs_instance] >= 0} { + puts "INFO: UVHS selected-FPGA overlay: remove unused daughter-card instance: $uvhs_trimmed_line" + continue + } + if {[regexp {^config_hw[ \t]+-unplug_fpga[ \t]+([^ \t]+)} $uvhs_trimmed_line -> uvhs_unplug_fpga]} { + set uvhs_unplug_fpga [string tolower $uvhs_unplug_fpga] + if {[lsearch -exact $uvhs_keep_fpgas $uvhs_unplug_fpga] >= 0} { + puts "INFO: UVHS selected-FPGA overlay: ignore base unplug for kept FPGA $uvhs_unplug_fpga" + continue + } + } + if {[regexp {^config_hw[ \t]+-connect_daughter_card[ \t]+\{([^ \t]+)[ \t]+([^ \t]+)\.FMC\}} $uvhs_trimmed_line -> uvhs_connector uvhs_instance]} { + set uvhs_lower_connector [string tolower $uvhs_connector] + set uvhs_connector_fpga "" + foreach uvhs_fpga $uvhs_known_fpgas { + if {[string first $uvhs_fpga $uvhs_lower_connector] == 0} { + set uvhs_connector_fpga $uvhs_fpga + break + } + } + if {$uvhs_connector_fpga ne "" && [lsearch -exact $uvhs_keep_fpgas $uvhs_connector_fpga] < 0} { + puts "INFO: UVHS selected-FPGA overlay: remove unused daughter-card link: $uvhs_trimmed_line" + continue + } + } + if {[string match "config_hw -connect_fpga *" $uvhs_trimmed_line]} { + set uvhs_lower_line [string tolower $uvhs_trimmed_line] + set uvhs_touches_kept 0 + set uvhs_touches_unused 0 + foreach uvhs_fpga $uvhs_known_fpgas { + if {[string first $uvhs_fpga $uvhs_lower_line] >= 0} { + if {[lsearch -exact $uvhs_keep_fpgas $uvhs_fpga] >= 0} { + set uvhs_touches_kept 1 + } else { + set uvhs_touches_unused 1 + } + } + } + if {$uvhs_touches_unused || !$uvhs_touches_kept} { + puts "INFO: UVHS selected-FPGA overlay: remove unused FPGA link: $uvhs_trimmed_line" + continue + } + } + if {$uvhs_mem_dc ne "" && $uvhs_mem_dc ne "none" && + [string match "config_hw -connect_fpga *" $uvhs_trimmed_line] && + [string match "*$uvhs_mem_connector*" $uvhs_trimmed_line]} { + puts "INFO: UVHS memory overlay: remove connector conflict: $uvhs_trimmed_line" + continue + } + lappend uvhs_filtered_lines $uvhs_line +} +set uvhs_base_data [join $uvhs_filtered_lines "\n"] + +set uvhs_unplug_overlay "" +foreach uvhs_fpga $uvhs_known_fpgas { + if {[lsearch -exact $uvhs_keep_fpgas $uvhs_fpga] >= 0} { + append uvhs_unplug_overlay "#config_hw -unplug_fpga $uvhs_fpga\n" + } else { + append uvhs_unplug_overlay "puts \"INFO: UVHS selected-FPGA overlay: unplug $uvhs_fpga, keep $uvhs_keep_fpgas\"\n" + append uvhs_unplug_overlay "config_hw -unplug_fpga $uvhs_fpga\n" + } +} +set uvhs_create_board_replacements [regsub -line {^(config_hw[ \t]+-create_board_instance[ \t]+1[ \t]*)$} \ + $uvhs_base_data "\\1\n$uvhs_unplug_overlay" uvhs_base_data] +if {$uvhs_create_board_replacements != 1} { + puts "WARN: UVHS single-FPGA overlay: failed to insert unplug commands after create_board_instance; prepend overlay" + set uvhs_base_data "$uvhs_unplug_overlay\n$uvhs_base_data" +} + +set uvhs_late_overlay "" +if {$uvhs_enable_clock_hub && ![regexp -line {^config_hw[ \t]+-create_clock_hub(?:[ \t]|$)} $uvhs_base_data]} { + # U2 global clocks are driven through the external ClockHub. The stock + # 1B/4F assembly has no ClockHub connection, leaving single-FPGA DUT clocks + # assigned to unplugged inter-FPGA connectors with no physical source. + append uvhs_late_overlay { +puts "INFO: UVHS single-board overlay: create and connect U2 ClockHub" +config_hw -create_clock_hub +config_hw -connect_board_clk {b0.GLBOUT0 hub0_0.IN00} -cable NV_CLK_1000 +config_hw -connect_board_clk {b0.GLBOUT1 hub0_0.IN04} -cable NV_CLK_1000 +config_hw -connect_board_clk {b0.GLBOUT2 hub0_0.IN08} -cable NV_CLK_1000 +config_hw -connect_board_clk {b0.GLBOUT3 hub0_0.IN12} -cable NV_CLK_1000 +config_hw -connect_board_clk {hub0_0.OUT00_0 b0.GLBIN0} -cable NV_CLK_1000 +config_hw -connect_board_clk {hub0_0.OUT00_1 b0.GLBIN1} -cable NV_CLK_1000 +config_hw -connect_board_clk {hub0_0.OUT00_2 b0.GLBIN2} -cable NV_CLK_1000 +config_hw -connect_board_clk {hub0_0.OUT00_3 b0.GLBIN3} -cable NV_CLK_1000 +} +} +if {$uvhs_mem_dc ne "" && $uvhs_mem_dc ne "none"} { + append uvhs_late_overlay [format { +puts "INFO: UVHS memory overlay: create %s as %s" +config_hw -create_daughter_card %s -instance %s +puts "INFO: UVHS memory overlay: connect %s to %s.FMC" +config_hw -connect_daughter_card {%s %s.FMC} +} $uvhs_mem_dc $uvhs_mem_inst $uvhs_mem_dc $uvhs_mem_inst $uvhs_mem_connector $uvhs_mem_inst $uvhs_mem_connector $uvhs_mem_inst] +} + +set uvhs_patched_data $uvhs_base_data +if {$uvhs_aux_ddr_dc ne "" && $uvhs_aux_ddr_dc ne "none"} { + if {$uvhs_aux_swap_base_connector ne "" && $uvhs_aux_swap_base_connector ne "none"} { + set uvhs_base_connect_anchor "^config_hw -connect_daughter_card \\{$uvhs_replace_connector $uvhs_replace_inst.FMC\\}\[ \t\]*$" + set uvhs_base_connect_replacement "config_hw -connect_daughter_card {$uvhs_aux_swap_base_connector $uvhs_replace_inst.FMC}" + set uvhs_base_connect_replacements [regsub -line $uvhs_base_connect_anchor $uvhs_patched_data $uvhs_base_connect_replacement uvhs_patched_data] + if {$uvhs_base_connect_replacements != 1} { + error "failed to move $uvhs_replace_inst from $uvhs_replace_connector to $uvhs_aux_swap_base_connector" + } + puts "INFO: UVHS memory overlay: move $uvhs_replace_inst from $uvhs_replace_connector to $uvhs_aux_swap_base_connector" + } + + set uvhs_aux_overlay [format { +puts "INFO: UVHS memory overlay: create auxiliary DDR %s as %s" +config_hw -create_daughter_card %s -instance %s +puts "INFO: UVHS memory overlay: connect %s to %s.FMC" +config_hw -connect_daughter_card {%s %s.FMC} +} $uvhs_aux_ddr_dc $uvhs_aux_ddr_inst $uvhs_aux_ddr_dc $uvhs_aux_ddr_inst $uvhs_aux_ddr_connector $uvhs_aux_ddr_inst $uvhs_aux_ddr_connector $uvhs_aux_ddr_inst] + + # U2/VU19P_X4 mandates FMC3 for UHD. An auxiliary PDDR4DME can satisfy a + # second consumer, but declaration order cannot move UHD away from FMC3. + # Functional AXI2DDR builds must therefore disable UHD probe insertion. + # hw.dat/Log/binding.log is authoritative for the resulting assignment. + set uvhs_aux_anchor "^config_hw -create_daughter_card UV_FMCH_PDDR4DME -instance $uvhs_replace_inst\[ \t\]*$" + set uvhs_aux_replacements [regsub -line $uvhs_aux_anchor $uvhs_patched_data "$uvhs_aux_overlay\n&" uvhs_patched_data] + if {$uvhs_aux_replacements != 1} { + puts "WARN: UVHS memory overlay: failed to insert auxiliary DDR before $uvhs_replace_inst; append before assemble" + append uvhs_late_overlay $uvhs_aux_overlay + } +} + +set uvhs_replacements [regsub -line {^config_hw[ \t]+-assemble[ \t]*$} $uvhs_patched_data "$uvhs_late_overlay\nconfig_hw -assemble" uvhs_patched_data] +if {$uvhs_replacements != 1} { + error "failed to patch assembly file before config_hw -assemble: $uvhs_base_assemble" +} + +set uvhs_overlay_file [file join [pwd] script .uvhs_assemble_with_mem_array.tcl] +set uvhs_fh [open $uvhs_overlay_file w] +puts -nonewline $uvhs_fh $uvhs_patched_data +close $uvhs_fh + +puts "INFO: source UVHS assembly overlay $uvhs_overlay_file" +source $uvhs_overlay_file diff --git a/fpga_diff/uvhs/assign_pin_u22_f2.tcl b/fpga_diff/uvhs/assign_pin_u22_f2.tcl new file mode 100644 index 00000000..a4f4ca5c --- /dev/null +++ b/fpga_diff/uvhs/assign_pin_u22_f2.tcl @@ -0,0 +1,190 @@ +################################################################################ +# Pin assignment for NutShell fpga_diff on a single U2.2 VU19P FPGA (b0.f2). +# +# This file is intended for UVHS flow bring-up on the current lab machine. The +# reference flow keeps only b0.f2 plugged in, so all user-visible top ports must +# bind to b0.F2_* connectors instead of the original mixed F0/F1/F2 template. +################################################################################ + +proc assign_indexed_ports {prefix count connector indices} { + for {set i 0} {$i < $count} {incr i} { + set port [format {%s[%d]} $prefix $i] + assign_pin -port $port -connector $connector -index [lindex $indices $i] + } +} + +proc pin_name {top port} { + if {$top eq "" || $top eq "none"} { + return $port + } + return "${top}.${port}" +} + +set top [env_or_default UVHS_ASSIGN_PIN_TOP [env_or_default UVHS_TOP fpga_top_debug]] +set uvhs_mem_array_mode [expr {[env_or_default UVHS_MEM_ARRAY_DC none] eq "UV_MEM_ARRAY_F"}] +set uvhs_uvw_ddr4_mode [expr { + [env_or_default UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP 0] eq "1" + || [env_or_default UVHS_DDR_RTL_INST none] eq "${top}.core_def.U_UVHS_UVW_AXI4_TO_DDR4" +}] +set uvhs_mem_array_connector [env_or_default UVHS_MEM_ARRAY_CONNECTOR b0.F2_FMC1] +set uvhs_skip_pcie_pins [expr {[env_or_default UVHS_SKIP_PCIE_PINS 0] eq "1"}] +set xdma_link_width [string toupper [string trim [env_or_default XDMA_LINK_WIDTH X4]]] +if {$xdma_link_width ni {X4 X8}} { + error "XDMA_LINK_WIDTH must be one of X4/X8, got '$xdma_link_width'" +} +set xdma_lane_count [expr {$xdma_link_width eq "X8" ? 8 : 4}] + +set apc16_indices { + 101 102 104 105 114 115 117 57 + 81 82 84 85 94 95 97 98 + 61 62 64 65 74 75 77 78 + 118 58 54 55 44 45 41 42 +} + +proc apc16_pin {port slot} { + global apc16_indices + global top + assign_pin -port [pin_name $top $port] -connector b0.F2_APC16 -index [lindex $apc16_indices $slot] +} + +# Low-speed debug/control pins on the unused f2 APC16 connector. +# rstn_sw* are exported as UVHS global resets and must not also be assign_pin'd. +apc16_pin led0 3 +apc16_pin led2 4 +apc16_pin led3 5 + +# UART0 defaults to the F2 APC16 sideband connector. A two-FPGA build can +# route it through the F1 UV_FMCH_FLASH USB-UART with FMC indices 311/270. +set uvhs_uart0_connector [env_or_default UVHS_UART0_CONNECTOR b0.F2_APC16] +set uvhs_uart0_tx_index [env_or_default UVHS_UART0_TX_INDEX [lindex $apc16_indices 6]] +set uvhs_uart0_rx_index [env_or_default UVHS_UART0_RX_INDEX [lindex $apc16_indices 7]] +puts "INFO: UART0 pins: TX ${uvhs_uart0_connector}\[$uvhs_uart0_tx_index\], RX ${uvhs_uart0_connector}\[$uvhs_uart0_rx_index\]" +assign_pin -port [pin_name $top uart0_sout] -connector $uvhs_uart0_connector -index $uvhs_uart0_tx_index +assign_pin -port [pin_name $top uart0_sin] -connector $uvhs_uart0_connector -index $uvhs_uart0_rx_index +apc16_pin uart1_sout 8 +apc16_pin uart1_sin 9 +apc16_pin uart2_sout 10 +apc16_pin uart2_sin 11 + +apc16_pin JTAG_TCK 12 +apc16_pin JTAG_TMS 13 +apc16_pin JTAG_TDI 14 +apc16_pin JTAG_TDO 15 +apc16_pin JTAG_TRSTn 16 + +apc16_pin SD_CLK 17 +apc16_pin SD_CMD 18 +apc16_pin SD_DATA0 19 +apc16_pin SD_DATA1 20 +apc16_pin SD_DATA2 21 +apc16_pin SD_DATA3 22 +apc16_pin SD_DECT 23 + +# U2 ClockHub global clocks on F2. Keep the three unrelated frequencies in +# separate ClockHub groups: gclk0 (0..4), gclk5 (5..9), gclk10 (10..14). +# Package pins are the F2 GlobalClk pins declared by the U2.2 board file. +assign_pin -port [pin_name $top clk6_p] -fpga b0.f2 -pin CA39 +assign_pin -port [pin_name $top clk6_n] -fpga b0.f2 -pin CA40 +assign_pin -port [pin_name $top clk8_p] -fpga b0.f2 -pin G36 +assign_pin -port [pin_name $top clk8_n] -fpga b0.f2 -pin F36 +assign_pin -port [pin_name $top clk5_p] -fpga b0.f2 -pin AW17 +assign_pin -port [pin_name $top clk5_n] -fpga b0.f2 -pin AY17 +if {!$uvhs_mem_array_mode && !$uvhs_uvw_ddr4_mode} { + # clk7 is the Vivado DDR reference clock. UVHS direct DDR uses FP_CLK_200M + # on the same PDDR4DME pins, so do not assign both names to index 241/242. + assign_pin -port [pin_name $top clk7_p] -connector b0.F2_FMC3 -index 241 + assign_pin -port [pin_name $top clk7_n] -connector b0.F2_FMC3 -index 242 +} + +if {$uvhs_skip_pcie_pins} { + puts "INFO: skip PCIe/XDMA pin assignment because UVHS_SKIP_PCIE_PINS=1" +} else { + assign_pin -port [pin_name $top pcie_ep_lnk_up] -connector b0.F2_APC16 -index 58 + + # XDMA endpoint signals. X4 uses the HGC7 lane group from the Hejian + # official XDMA EP example; bind HGC6 only when X8 is explicitly selected. + puts "INFO: assign XDMA PCIe pins for $xdma_link_width" + assign_pin -port [pin_name $top pcie_ep_gt_ref_clk_p] -connector b0.F2_HGC7 -index 29 + assign_pin -port [pin_name $top pcie_ep_gt_ref_clk_n] -connector b0.F2_HGC7 -index 30 + assign_pin -port [pin_name $top pcie_ep_perstn] -connector b0.F2_APC16 -index 118 + + set xdma_rx_connectors {b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC6 b0.F2_HGC6 b0.F2_HGC6 b0.F2_HGC6} + set xdma_tx_connectors {b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC6 b0.F2_HGC6 b0.F2_HGC6 b0.F2_HGC6} + set xdma_rxp_indices {16 13 4 1 16 13 4 1} + set xdma_rxn_indices {17 14 5 2 17 14 5 2} + set xdma_txp_indices {35 32 23 20 35 32 23 20} + set xdma_txn_indices {36 33 24 21 36 33 24 21} + for {set i 0} {$i < $xdma_lane_count} {incr i} { + assign_pin -port [pin_name $top [format {pci_ep_rxp[%d]} $i]] -connector [lindex $xdma_rx_connectors $i] -index [lindex $xdma_rxp_indices $i] + assign_pin -port [pin_name $top [format {pci_ep_rxn[%d]} $i]] -connector [lindex $xdma_rx_connectors $i] -index [lindex $xdma_rxn_indices $i] + assign_pin -port [pin_name $top [format {pci_ep_txp[%d]} $i]] -connector [lindex $xdma_tx_connectors $i] -index [lindex $xdma_txp_indices $i] + assign_pin -port [pin_name $top [format {pci_ep_txn[%d]} $i]] -connector [lindex $xdma_tx_connectors $i] -index [lindex $xdma_txn_indices $i] + } +} + +# UVHS memory array connector. This is not a PDDR4DME pinout; only the TDM +# pins exposed by UV_MEM_ARRAY_F are legal on the daughter-card side. +if {$uvhs_mem_array_mode} { + assign_pin -port [pin_name $top uvw_mem_array_tdm_ref_clk_p] -connector $uvhs_mem_array_connector -index 241 + assign_pin -port [pin_name $top uvw_mem_array_tdm_ref_clk_n] -connector $uvhs_mem_array_connector -index 242 + assign_indexed_ports [pin_name $top uvw_mem_array_tdm_pin] 138 $uvhs_mem_array_connector { + 245 246 127 128 286 287 248 249 289 290 130 131 89 90 292 293 + 251 252 133 134 93 94 295 296 283 284 254 255 136 137 97 98 + 298 299 257 258 139 140 101 102 301 302 260 261 304 305 263 264 + 142 143 307 308 266 267 145 146 105 106 310 311 269 270 313 314 + 272 273 316 317 275 276 203 204 161 162 366 367 325 326 206 207 + 165 166 369 370 328 329 209 210 168 169 372 373 331 332 212 213 + 171 172 334 335 215 216 174 175 375 376 337 338 218 219 177 178 + 378 379 363 364 321 322 340 341 381 382 384 385 343 344 221 222 + 180 181 224 225 183 184 387 388 346 347 + } + return +} + +# The UVHS uvw_axi4_to_ddr4 IP declares: +# (* UV_HW_IP = "... toFPGA:" *) +# In that mode the UVHS daughter-card/IP binding owns the PDDR4DME DDR pins and +# emits the required *_pad_net_* constraints. Hand-assigning the naked +# FP_CLK_200M_* or DDR4_DIMM_* top ports here double-constrains the same pads +# and causes Vivado "pad already occupied" plus UCIO failures. +if {$uvhs_uvw_ddr4_mode} { + puts "INFO: skip manual PDDR4DME DDR pin assignment for UVHS uvw_axi4_to_ddr4 IP" + return +} + +# DDR4 PDDR4DME daughter card connected to b0.F2_FMC3 by 1B_4F_HGC_assemble.tcl. +assign_pin -port [pin_name $top FP_CLK_200M_P] -connector b0.F2_FMC3 -index 241 +assign_pin -port [pin_name $top FP_CLK_200M_N] -connector b0.F2_FMC3 -index 242 +assign_pin -port [pin_name $top {DDR4_DIMM_CK_P[0]}] -connector b0.F2_FMC3 -index 269 +assign_pin -port [pin_name $top {DDR4_DIMM_CK_P[1]}] -connector b0.F2_FMC3 -index 313 +assign_pin -port [pin_name $top {DDR4_DIMM_CK_N[0]}] -connector b0.F2_FMC3 -index 270 +assign_pin -port [pin_name $top {DDR4_DIMM_CK_N[1]}] -connector b0.F2_FMC3 -index 314 +assign_pin -port [pin_name $top DDR4_DIMM_RST_B] -connector b0.F2_FMC3 -index 227 -attribute {DRIVE:8} +assign_pin -port [pin_name $top {DDR4_DIMM_CKE[0]}] -connector b0.F2_FMC3 -index 169 +assign_pin -port [pin_name $top {DDR4_DIMM_CKE[1]}] -connector b0.F2_FMC3 -index 329 +assign_pin -port [pin_name $top {DDR4_DIMM_CS_N[0]}] -connector b0.F2_FMC3 -index 165 +assign_pin -port [pin_name $top {DDR4_DIMM_CS_N[1]}] -connector b0.F2_FMC3 -index 206 +assign_pin -port [pin_name $top {DDR4_DIMM_ODT[0]}] -connector b0.F2_FMC3 -index 325 +assign_pin -port [pin_name $top {DDR4_DIMM_ODT[1]}] -connector b0.F2_FMC3 -index 366 +assign_pin -port [pin_name $top DDR4_DIMM_ACT_N] -connector b0.F2_FMC3 -index 328 + +assign_indexed_ports [pin_name $top DDR4_DIMM_DQ] 72 b0.F2_FMC3 { + 263 101 301 305 304 102 302 264 + 307 105 267 310 311 106 308 266 + 257 136 254 258 298 137 255 299 + 181 225 388 387 180 346 347 224 + 177 178 338 375 337 379 378 376 + 216 334 213 212 215 335 332 331 + 292 295 94 251 296 293 93 252 + 286 289 127 131 290 287 130 128 + 344 343 341 340 385 384 321 322 +} +assign_indexed_ports [pin_name $top DDR4_DIMM_DM] 9 b0.F2_FMC3 {139 142 283 221 174 372 89 245 363} +assign_indexed_ports [pin_name $top DDR4_DIMM_DQS_P] 9 b0.F2_FMC3 {260 145 97 183 218 171 133 248 381} +assign_indexed_ports [pin_name $top DDR4_DIMM_DQS_N] 9 b0.F2_FMC3 {261 146 98 184 219 172 134 249 382} +assign_indexed_ports [pin_name $top DDR4_DIMM_A] 17 b0.F2_FMC3 { + 275 391 276 273 317 316 390 369 272 + 370 326 207 168 203 166 162 204 +} +assign_indexed_ports [pin_name $top DDR4_DIMM_BA] 2 b0.F2_FMC3 {161 367} +assign_indexed_ports [pin_name $top DDR4_DIMM_BG] 2 b0.F2_FMC3 {209 210} diff --git a/fpga_diff/uvhs/async_clocks.tcl b/fpga_diff/uvhs/async_clocks.tcl new file mode 100644 index 00000000..26fa30b2 --- /dev/null +++ b/fpga_diff/uvhs/async_clocks.tcl @@ -0,0 +1,14 @@ +################################################################################ +# UVHS asynchronous clock constraints. +# +# backend_run.tcl loads this after top-level and generated clocks are available. +################################################################################ + +set fpga_diff_async_groups [list] +foreach fpga_diff_clock {TMCLK ddr_ref_clk CPU_CLK_IN jtag_vclk pcie_ep_refclk} { + lappend fpga_diff_async_groups -group [get_clocks -include_generated_clocks $fpga_diff_clock] +} +if {[llength [get_clocks -quiet DEBUG_CLK_IN]] > 0} { + lappend fpga_diff_async_groups -group [get_clocks -include_generated_clocks DEBUG_CLK_IN] +} +eval [linsert $fpga_diff_async_groups 0 set_clock_groups -asynchronous] diff --git a/fpga_diff/uvhs/backend_run.tcl b/fpga_diff/uvhs/backend_run.tcl new file mode 100644 index 00000000..0bcab22c --- /dev/null +++ b/fpga_diff/uvhs/backend_run.tcl @@ -0,0 +1,1316 @@ +################################################################################ +# UVHS backend flow for fpga_diff. +################################################################################ + +set ::fpga_diff_uvhs_dir [file dirname [info script]] + +proc env_or_default {name default} { + if {[info exists ::env($name)] && $::env($name) ne ""} { + return $::env($name) + } + return $default +} + +proc source_if_exists {file} { + if {[file exists $file]} { + puts "INFO: source $file" + if {[catch {uplevel #0 [list source $file]} err]} { + puts "WARNING: source $file failed: $err" + } + } else { + puts "INFO: skip missing $file" + } +} + +proc run_or_warn {description command} { + puts "INFO: $description" + if {[catch {uplevel #0 $command} err]} { + puts "WARNING: $description failed: $err" + } +} + +proc uvhs_config_probe_group_resource {} { + set probe_group_resource [env_or_default UVHS_PROBE_GROUP_RESOURCE 35] + if {$probe_group_resource eq "none" || $probe_group_resource eq "0"} { + puts "INFO: skip Probe-Group resource override" + return + } + + run_or_warn "restore Probe-Group system resource to $probe_group_resource" \ + [list config_hw -set_resource $probe_group_resource -type Probe-Group] +} + +proc uvhs_cpu_clk_period_ns {} { + return [env_or_default UVHS_CPU_CLK_PERIOD_NS 40] +} + +proc uvhs_cpu_debug_clk {} { + return [expr {[env_or_default UVHS_CPU_DEBUG_CLK 1] eq "1"}] +} + +proc uvhs_xdma_link_width {} { + set link_width [string toupper [string trim [env_or_default XDMA_LINK_WIDTH X4]]] + if {$link_width ni {X4 X8}} { + error "XDMA_LINK_WIDTH must be one of X4/X8, got '$link_width'" + } + return $link_width +} + +proc uvhs_xdma_axi_clk_period_ns {} { + switch -- [uvhs_xdma_link_width] { + X4 { return 8.000 } + X8 { return 4.000 } + } +} + +proc uvhs_clean_stale_partition_runtime {} { + set partition_dir [file normalize hw.dat/Compile/Partition] + foreach stale_file { + partition_0bk.tcl + } { + set path [file join $partition_dir $stale_file] + if {[file exists $path]} { + file delete -force $path + puts "INFO: removed stale partition runtime file $path" + } + } +} + +proc uvhs_async_clock_patch_script {} { + set async_file [file normalize [file join $::fpga_diff_uvhs_dir async_clocks.tcl]] + return [format { +puts "INFO: UVHS patch: source async clock groups after Vivado clocks are available" +if {[file exists {%s}]} { + source {%s} +} else { + puts "WARNING: UVHS patch: missing async clock file %s" +} +} $async_file $async_file $async_file] +} + +proc uvhs_vivado_stage_hook_files {stage} { + switch -- $stage { + pre_opt { + set preferred_rel_paths { + user_pre_opt.tcl + } + set fallback_rel_paths { + user_pre_opt.tcl + user_stage_tcl/preOpt_pre_opt.tcl + user_stage_tcl/pre_opt.tcl + } + } + pre_place { + set preferred_rel_paths { + user_pre_place.tcl + } + set fallback_rel_paths { + user_pre_place.tcl + user_stage_tcl/prePlace_pre_place.tcl + user_stage_tcl/pre_place.tcl + } + } + default { + error "unsupported Vivado stage hook '$stage'" + } + } + + set files {} + foreach pnr_dir [glob -nocomplain hw.dat/Compile/PnR/*/*] { + set pnr_files {} + foreach rel_path $preferred_rel_paths { + set file [file join $pnr_dir $rel_path] + if {[file exists $file] && [lsearch -exact $pnr_files $file] < 0} { + lappend pnr_files $file + } + } + if {![llength $pnr_files]} { + foreach rel_path $fallback_rel_paths { + set file [file join $pnr_dir $rel_path] + if {[file exists $file] && [lsearch -exact $pnr_files $file] < 0} { + lappend pnr_files $file + } + } + } + foreach file $pnr_files { + if {[lsearch -exact $files $file] < 0} { + lappend files $file + } + } + } + return $files +} + +proc uvhs_xdma_gt_refclk_patch_script {stage} { + return [string map [list __UVHS_STAGE__ $stage] { +puts "INFO: UVHS patch: keep XDMA GT refclk direct to IBUFDS_GTE4 before __UVHS_STAGE__" +set uvhs_xdma_refclk_ports {} +foreach uvhs_refclk_pattern { + pcie_ep_gt_ref_clk_p_pad_net_* + pcie_ep_gt_ref_clk_n_pad_net_* + pcie_ep_gt_ref_clk_p + pcie_ep_gt_ref_clk_n +} { + foreach uvhs_port [get_ports -quiet $uvhs_refclk_pattern] { + if {[lsearch -exact $uvhs_xdma_refclk_ports $uvhs_port] < 0} { + lappend uvhs_xdma_refclk_ports $uvhs_port + } + } +} +if {[llength $uvhs_xdma_refclk_ports]} { + catch {set_property IO_BUFFER_TYPE NONE $uvhs_xdma_refclk_ports} uvhs_iobuf_msg + catch {set_property CLOCK_BUFFER_TYPE NONE $uvhs_xdma_refclk_ports} uvhs_clkbuf_msg + puts "INFO: UVHS patch: XDMA GT refclk ports before __UVHS_STAGE__: $uvhs_xdma_refclk_ports" +} else { + puts "WARNING: UVHS patch: XDMA GT refclk ports not found before __UVHS_STAGE__" +} + +proc ::uvhs_xdma_gt_refclk_net_segments {uvhs_net} { + set uvhs_segments {} + if {$uvhs_net ne ""} { + lappend uvhs_segments $uvhs_net + } + if {[catch {set uvhs_more_segments [get_nets -quiet -segments $uvhs_net]} uvhs_segment_msg]} { + puts "WARNING: UVHS patch: get net segments for $uvhs_net failed: $uvhs_segment_msg" + } else { + foreach uvhs_segment $uvhs_more_segments { + if {[lsearch -exact $uvhs_segments $uvhs_segment] < 0} { + lappend uvhs_segments $uvhs_segment + } + } + } + return $uvhs_segments +} + +proc ::uvhs_xdma_gt_refclk_input_pins {} { + set uvhs_pins {} + foreach uvhs_pattern { + */core_def/xdma_ep_i/*IBUFDS_GTE4*/I + */core_def/xdma_ep_i/*IBUFDS_GTE4_I/I + */core_def/xdma_ep_i/util_ds_buf_0/*/I + } { + foreach uvhs_pin [get_pins -hier -quiet $uvhs_pattern] { + if {[lsearch -exact $uvhs_pins $uvhs_pin] < 0} { + lappend uvhs_pins $uvhs_pin + } + } + } + foreach uvhs_pin [get_pins -hier -quiet -filter {REF_PIN_NAME == I && NAME =~ */core_def/xdma_ep_i/*IBUFDS_GTE4*}] { + if {[lsearch -exact $uvhs_pins $uvhs_pin] < 0} { + lappend uvhs_pins $uvhs_pin + } + } + return $uvhs_pins +} + +proc ::uvhs_xdma_gt_refclk_pin_is_driven_by_bufg {uvhs_pin uvhs_bufg} { + set uvhs_pin_net [lindex [get_nets -quiet -of_objects $uvhs_pin] 0] + if {$uvhs_pin_net eq ""} { + return 0 + } + foreach uvhs_segment [::uvhs_xdma_gt_refclk_net_segments $uvhs_pin_net] { + foreach uvhs_driver [get_pins -quiet -of_objects $uvhs_segment -filter {DIRECTION == OUT}] { + set uvhs_driver_cell [lindex [get_cells -quiet -of_objects $uvhs_driver] 0] + if {$uvhs_driver_cell eq $uvhs_bufg} { + return 1 + } + } + } + return 0 +} + +# UVHS/DLP can infer a BUFGCE on the PCIe GT reference clock after opt_design. +# Xilinx IBUFDS_GTE4 must be driven directly by a top port, so bypass only the +# generated XDMA refclk BUFGCE cells before place_design runs its DRC. +set uvhs_xdma_gt_input_pins [::uvhs_xdma_gt_refclk_input_pins] +if {[llength $uvhs_xdma_gt_input_pins]} { + puts "INFO: UVHS patch: XDMA IBUFDS_GTE4 input pins before __UVHS_STAGE__: $uvhs_xdma_gt_input_pins" +} else { + puts "WARNING: UVHS patch: no XDMA IBUFDS_GTE4 input pins found before __UVHS_STAGE__" +} +set uvhs_xdma_refclk_bufgs [get_cells -hier -quiet -filter {REF_NAME =~ BUFG* && NAME =~ *pcie_ep_gt_ref_clk*bufg*}] +if {[llength $uvhs_xdma_refclk_bufgs]} { + puts "INFO: UVHS patch: found XDMA GT refclk BUFG cells before __UVHS_STAGE__: $uvhs_xdma_refclk_bufgs" +} +foreach uvhs_bufg $uvhs_xdma_refclk_bufgs { + set uvhs_in_pins [get_pins -quiet ${uvhs_bufg}/I] + set uvhs_out_pins [get_pins -quiet ${uvhs_bufg}/O] + if {![llength $uvhs_in_pins] || ![llength $uvhs_out_pins]} { + puts "WARNING: UVHS patch: skip $uvhs_bufg, missing I/O pins" + continue + } + set uvhs_in_net [lindex [get_nets -quiet -of_objects [lindex $uvhs_in_pins 0]] 0] + set uvhs_out_net [lindex [get_nets -quiet -of_objects [lindex $uvhs_out_pins 0]] 0] + if {$uvhs_in_net eq "" || $uvhs_out_net eq ""} { + puts "WARNING: UVHS patch: skip $uvhs_bufg, missing I/O nets" + continue + } + + set uvhs_gt_loads {} + foreach uvhs_segment [::uvhs_xdma_gt_refclk_net_segments $uvhs_out_net] { + foreach uvhs_load [get_pins -quiet -of_objects $uvhs_segment -filter {DIRECTION == IN}] { + if {[string match *core_def/xdma_ep_i*IBUFDS_GTE4* $uvhs_load] || \ + [string match *core_def/xdma_ep_i/util_ds_buf_0* $uvhs_load]} { + if {[lsearch -exact $uvhs_gt_loads $uvhs_load] < 0} { + lappend uvhs_gt_loads $uvhs_load + } + } + } + } + foreach uvhs_gt_pin $uvhs_xdma_gt_input_pins { + if {[::uvhs_xdma_gt_refclk_pin_is_driven_by_bufg $uvhs_gt_pin $uvhs_bufg] && \ + [lsearch -exact $uvhs_gt_loads $uvhs_gt_pin] < 0} { + lappend uvhs_gt_loads $uvhs_gt_pin + } + } + if {![llength $uvhs_gt_loads]} { + puts "WARNING: UVHS patch: skip $uvhs_bufg, no XDMA IBUFDS_GTE4 loads on $uvhs_out_net" + foreach uvhs_segment [::uvhs_xdma_gt_refclk_net_segments $uvhs_out_net] { + puts "INFO: UVHS patch: pins on $uvhs_segment: [get_pins -quiet -of_objects $uvhs_segment]" + } + continue + } + + foreach uvhs_load $uvhs_gt_loads { + set uvhs_load_net [lindex [get_nets -quiet -of_objects $uvhs_load] 0] + if {$uvhs_load_net eq ""} { + puts "WARNING: UVHS patch: skip $uvhs_load, no connected net" + continue + } + if {[catch {disconnect_net -net $uvhs_load_net -objects $uvhs_load} uvhs_disconnect_msg]} { + puts "WARNING: UVHS patch: disconnect $uvhs_load_net -> $uvhs_load failed: $uvhs_disconnect_msg" + continue + } + if {[catch {connect_net -hier -net $uvhs_in_net -objects $uvhs_load} uvhs_connect_msg]} { + puts "WARNING: UVHS patch: connect $uvhs_in_net -> $uvhs_load failed: $uvhs_connect_msg" + } else { + puts "INFO: UVHS patch: rewired $uvhs_load from $uvhs_load_net to $uvhs_in_net" + } + } + + catch {disconnect_net -net $uvhs_in_net -objects [lindex $uvhs_in_pins 0]} uvhs_msg + catch {disconnect_net -net $uvhs_out_net -objects [lindex $uvhs_out_pins 0]} uvhs_msg + if {[info commands remove_cell] ne ""} { + catch {remove_cell $uvhs_bufg} uvhs_remove_msg + } elseif {[info commands delete_cells] ne ""} { + catch {delete_cells $uvhs_bufg} uvhs_remove_msg + } + puts "INFO: UVHS patch: bypassed XDMA GT refclk BUFG $uvhs_bufg" +} +}] +} + +proc uvhs_write_xdc_patch_script {} { + set async_file [file normalize [file join $::fpga_diff_uvhs_dir async_clocks.tcl]] + set script [format { +proc ::uvhs_create_ddr_ui_clock_patch {} { + if {[llength [get_clocks -quiet DDR_UI_CLK]] > 0} { + return + } + set uvhs_pins {} + foreach uvhs_pattern { + part_2/core_def/U_UVHS_UVW_AXI4_TO_DDR4/ddr4ip_ddr4_user_clk + */U_UVHS_UVW_AXI4_TO_DDR4/ddr4ip_ddr4_user_clk + } { + foreach uvhs_pin [get_pins -quiet $uvhs_pattern] { + if {[lsearch -exact $uvhs_pins $uvhs_pin] < 0} { + lappend uvhs_pins $uvhs_pin + } + } + foreach uvhs_pin [get_pins -hierarchical -quiet -filter "NAME =~ $uvhs_pattern"] { + if {[lsearch -exact $uvhs_pins $uvhs_pin] < 0} { + lappend uvhs_pins $uvhs_pin + } + } + } + if {[llength $uvhs_pins]} { + create_clock -period 5.000 -name DDR_UI_CLK -waveform {0.000 2.500} -add [lindex $uvhs_pins 0] + puts "INFO: UVHS patch: create DDR_UI_CLK on UVHS DDR user clock [lindex $uvhs_pins 0]" + } +} + +proc ::uvhs_patch_xdma_preopt_xdc {uvhs_xdc_file} { + if {![file exists $uvhs_xdc_file]} { + return + } + + set uvhs_fh [open $uvhs_xdc_file r] + set uvhs_data [read $uvhs_fh] + close $uvhs_fh + set uvhs_patched $uvhs_data + + if {[string match *pnr_physical_constraints_preopt.xdc $uvhs_xdc_file] || \ + [string match *pnr_timing_constraints_preopt.xdc $uvhs_xdc_file]} { + regsub -all {set_property CLKIN1_PERIOD [0-9]+(\.[0-9]*)? \[get_cells -hier -quiet -filter \{NAME =~ \*/core_def/xdma_ep_i/clk_wiz_0/inst/mmcme\*_adv_inst\}\]} \ + $uvhs_patched {set_property CLKIN1_PERIOD __UVHS_XDMA_AXI_CLK_PERIOD_NS__ [get_cells -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/inst/mmcme*_adv_inst}]} uvhs_patched + } + + if {[string match *pnr_timing_constraints_preopt.xdc $uvhs_xdc_file] || \ + [string match *pnr_timing_constraints.xdc $uvhs_xdc_file]} { + regsub -all {create_generated_clock[^\n]*-name[^\n]*core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer[^\n]*TO_DIFFTEST_PCIE_CLK[^\n]*} \ + $uvhs_patched {create_clock -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ -name XDMA_AXI_ACLK -waveform [list 0 [expr __UVHS_XDMA_AXI_CLK_PERIOD_NS__ / 2.0]] -add [get_pins part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK]} uvhs_patched + regsub -all {core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer} $uvhs_patched {XDMA_AXI_ACLK} uvhs_patched + regsub -all {create_generated_clock[^\n]*-name[^\n]*core_def_U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0_c0_ddr4_ui_clk_infer[^\n]*c0_ddr4_ui_clk[^\n]*} \ + $uvhs_patched {create_clock -period 5.000 -name core_def_U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0_c0_ddr4_ui_clk_infer -waveform {0.000 2.500} -add [get_pins part_2/core_def/U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0/c0_ddr4_ui_clk]} uvhs_patched + if {[string first {U_UVHS_UVW_AXI4_TO_DDR4} $uvhs_patched] >= 0 && \ + [string first {UVHS patch: create DDR_UI_CLK on UVHS DDR user clock} $uvhs_patched] < 0} { + append uvhs_patched "\n::uvhs_create_ddr_ui_clock_patch\n" + } + if {[string first {UVHS patch: source fpga_diff async clock constraints in final Vivado timing context} $uvhs_patched] < 0} { + append uvhs_patched "\n# UVHS patch: source fpga_diff async clock constraints in final Vivado timing context.\n" + append uvhs_patched "if {\[file exists {%s}\]} {\n source {%s}\n} else {\n puts \"WARNING: UVHS patch: missing async clock file %s\"\n}\n" + } + } + + if {$uvhs_patched ne $uvhs_data} { + set uvhs_fh [open $uvhs_xdc_file w] + puts -nonewline $uvhs_fh $uvhs_patched + close $uvhs_fh + puts "INFO: UVHS patch: patched generated preopt XDC $uvhs_xdc_file" + } +} + +if {[info commands ::uvhs_vivado_write_xdc] eq "" && [info commands ::write_xdc] ne ""} { + rename ::write_xdc ::uvhs_vivado_write_xdc + proc ::write_xdc {args} { + set uvhs_rc [catch {uplevel 1 [linsert $args 0 ::uvhs_vivado_write_xdc]} uvhs_result uvhs_options] + foreach uvhs_arg $args { + if {[string match *pnr_physical_constraints_preopt.xdc $uvhs_arg] || \ + [string match *pnr_timing_constraints_preopt.xdc $uvhs_arg] || \ + [string match *pnr_timing_constraints.xdc $uvhs_arg]} { + ::uvhs_patch_xdma_preopt_xdc $uvhs_arg + } + } + return -options $uvhs_options $uvhs_result + } + puts "INFO: UVHS patch: wrapped write_xdc to patch generated XDMA preopt constraints" +} +} $async_file $async_file $async_file] + return [string map [list __UVHS_XDMA_AXI_CLK_PERIOD_NS__ [uvhs_xdma_axi_clk_period_ns]] $script] +} + +proc create_clock_if_port_exists {name period port} { + if {[llength [get_clocks -quiet $name]] > 0} { + puts "INFO: skip create_clock $name, already exists" + return + } + set ports [get_ports -quiet $port] + if {[llength $ports] > 0} { + run_or_warn "create_clock $name on $port" [list create_clock -name $name -per $period $ports] + } else { + puts "INFO: skip create_clock $name, missing port $port" + } +} + +proc create_clock_if_pin_exists {name period pin} { + if {[llength [get_clocks -quiet $name]] > 0} { + puts "INFO: skip create_clock $name, already exists" + return + } + set pins [get_pins -quiet $pin] + if {[llength $pins] == 0} { + set pins [get_pins -hierarchical -quiet -filter "NAME =~ */$pin || NAME == $pin"] + } + if {[llength $pins] > 0} { + run_or_warn "create_clock $name on $pin" [list create_clock -name $name -per $period $pins] + } else { + puts "INFO: skip create_clock $name, missing pin $pin" + } +} + +proc create_blackbox_output_clock_if_pin_exists {name period pin} { + set pins [get_pins -quiet $pin] + if {[llength $pins] == 0} { + set pins [get_pins -hierarchical -quiet -filter "NAME =~ */$pin || NAME == $pin"] + } + if {[llength $pins] == 0} { + puts "INFO: skip create_clock $name, missing blackbox output pin $pin" + return + } + + set clocks [get_clocks -quiet -of_objects $pins] + if {[llength $clocks] > 0} { + puts "INFO: skip create_clock $name, blackbox output pin $pin already has clocks: $clocks" + return + } + + run_or_warn "create_clock $name on blackbox output $pin" \ + [list create_clock -name $name -per $period $pins] +} + +proc create_ddr_ui_clock_if_exists {} { + # The default Vivado flow uses jtag_ddr_subsys/c0_ddr4_ui_clk. The UVHS + # flow uses uvw_axi4_to_ddr4/ddr4ip_ddr4_user_clk. Both are 200 MHz user + # AXI domains; constrain whichever implementation is present. + set use_uvw_ddr [expr {[env_or_default UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP 0] eq "1"}] + if {$use_uvw_ddr} { + set pin_patterns { + core_def/U_UVHS_UVW_AXI4_TO_DDR4/ddr4ip_ddr4_user_clk + */U_UVHS_UVW_AXI4_TO_DDR4/ddr4ip_ddr4_user_clk + } + set clock_description "UVHS DDR ddr4ip_ddr4_user_clk" + } else { + set pin_patterns { + core_def/U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0/c0_ddr4_ui_clk + */U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0/c0_ddr4_ui_clk + */jtag_ddr_subsys_i_UVin_ddr4_0/c0_ddr4_ui_clk + */ddr4_0/c0_ddr4_ui_clk + } + set clock_description "Vivado DDR c0_ddr4_ui_clk" + } + set pins {} + foreach pin_pattern $pin_patterns { + foreach pin [get_pins -quiet $pin_pattern] { + if {[lsearch -exact $pins $pin] < 0} { + lappend pins $pin + } + } + foreach pin [get_pins -hierarchical -quiet -filter "NAME =~ $pin_pattern"] { + if {[lsearch -exact $pins $pin] < 0} { + lappend pins $pin + } + } + } + if {![llength $pins]} { + puts "INFO: skip create_clock DDR_UI_CLK, missing $clock_description pin" + return + } + + set pin [lindex $pins 0] + set clocks [get_clocks -quiet -of_objects $pin] + if {[llength $clocks]} { + puts "INFO: DDR UI pin $pin already has clocks: $clocks" + return + } + + run_or_warn "create_clock DDR_UI_CLK on $clock_description" \ + [list create_clock -name DDR_UI_CLK -per 5.000 $pin] +} + +proc create_generated_clock_if_bufgce_exists {name master_clock cell_patterns} { + if {[llength [get_clocks -quiet $name]] > 0} { + puts "INFO: skip create_generated_clock $name, already exists" + return + } + if {[llength [get_clocks -quiet $master_clock]] == 0} { + puts "WARNING: skip create_generated_clock $name, missing master clock $master_clock" + return + } + set cells {} + foreach cell_pattern $cell_patterns { + set matches [get_cells -hierarchical -quiet -filter "NAME =~ $cell_pattern"] + foreach match $matches { + if {[lsearch -exact $cells $match] < 0} { + lappend cells $match + } + } + } + if {[llength $cells] == 0} { + set bufgce_cells [get_cells -hierarchical -quiet -filter "REF_NAME =~ BUFGCE"] + puts "WARNING: skip create_generated_clock $name, missing BUFGCE cell patterns $cell_patterns; visible BUFGCE cells: $bufgce_cells" + return + } + if {[llength $cells] > 1} { + puts "WARNING: create_generated_clock $name matched multiple cells, using [lindex $cells 0]: $cells" + } + set cell [lindex $cells 0] + set in_pins [get_pins -quiet $cell/I] + set out_pins [get_pins -quiet $cell/O] + if {[llength $in_pins] == 0 || [llength $out_pins] == 0} { + puts "WARNING: skip create_generated_clock $name, missing I/O pins on $cell" + return + } + run_or_warn "create_generated_clock $name on $cell/O" \ + [list create_generated_clock -add -name $name -master_clock $master_clock -source $in_pins -divide_by 1 $out_pins] +} + +proc patch_vivado_wrappers {} { + set patterns { + hw.dat/Compile/PnR/*/*/vivado/Script/uv_vivado_wrapper.sh + hw.dat/Compile/PnR/*/*/vivado/Rundir/*/uv_vivado_wrapper.sh + } + foreach pattern $patterns { + foreach wrapper [glob -nocomplain $pattern] { + if {![file exists $wrapper]} { + continue + } + set fh [open $wrapper r] + set data [read $fh] + close $fh + if {[string match "#!/bin/sh*" $data]} { + regsub {^#!/bin/sh} $data {#!/bin/bash} data + set fh [open $wrapper w] + puts -nonewline $fh $data + close $fh + file attributes $wrapper -permissions u=rwx,g=rx,o=rx + puts "INFO: patched Vivado wrapper shell to bash: $wrapper" + } + } + } +} + +proc patch_vivado_pre_opt {} { + set write_xdc_patch_script [uvhs_write_xdc_patch_script] + set refclk_patch_script [uvhs_xdma_gt_refclk_patch_script "opt"] + set xdma_cdc_script { +puts "INFO: UVHS patch: source XDMA CDC attributes before opt_design" +set uvhs_xdma_cdc_script [file join $FILE_DIR xdma_cdc_attributes.tcl] +if {[file exists $uvhs_xdma_cdc_script]} { + source $uvhs_xdma_cdc_script +} else { + puts "WARNING: UVHS patch: missing XDMA CDC attribute script $uvhs_xdma_cdc_script" +} +} + set script [string map [list __UVHS_XDMA_AXI_CLK_PERIOD_NS__ [uvhs_xdma_axi_clk_period_ns]] { +puts "INFO: UVHS patch: constrain XDMA clk_wiz input period for Vivado MMCM DRC" +set uvhs_xdma_refclk_ports {} +foreach uvhs_refclk_pattern {pcie_ep_gt_ref_clk_p_pad_net_* pcie_ep_gt_ref_clk_n_pad_net_*} { + set uvhs_xdma_refclk_ports [concat $uvhs_xdma_refclk_ports [get_ports -quiet $uvhs_refclk_pattern]] +} +if {[llength $uvhs_xdma_refclk_ports]} { + set_property IO_BUFFER_TYPE NONE $uvhs_xdma_refclk_ports + set_property CLOCK_BUFFER_TYPE NONE $uvhs_xdma_refclk_ports + puts "INFO: UVHS patch: keep XDMA GT refclk pads unbuffered before opt: $uvhs_xdma_refclk_ports" +} else { + puts "WARNING: UVHS patch: XDMA GT refclk pad ports not found before opt" +} +set uvhs_xdma_clk_in [get_pins -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/clk_in1}] +if {[llength $uvhs_xdma_clk_in]} { + set uvhs_xdma_clk_in [lindex $uvhs_xdma_clk_in 0] + set uvhs_xdma_clocks [get_clocks -quiet -of_objects $uvhs_xdma_clk_in] + if {![llength $uvhs_xdma_clocks]} { + catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_clk_in} uvhs_create_clk_msg + puts "INFO: UVHS patch: XDMA_AXI_ACLK create_clock result: $uvhs_create_clk_msg" + } else { + puts "INFO: UVHS patch: XDMA clk_wiz input clocks: $uvhs_xdma_clocks" + if {[lsearch -exact $uvhs_xdma_clocks XDMA_AXI_ACLK] >= 0} { + puts "INFO: UVHS patch: XDMA_AXI_ACLK already exists" + } else { + catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_clk_in} uvhs_create_clk_msg + puts "INFO: UVHS patch: XDMA_AXI_ACLK override_clock result: $uvhs_create_clk_msg" + } + } +} else { + puts "INFO: UVHS patch: XDMA clk_wiz clk_in1 pin not found; current x4 DCP exposes TO_DIFFTEST_PCIE_CLK directly" +} +set uvhs_difftest_pcie_pin [get_pins -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK}] +if {[llength $uvhs_difftest_pcie_pin]} { + set uvhs_difftest_pcie_pin [lindex $uvhs_difftest_pcie_pin 0] + set uvhs_difftest_pcie_clocks [get_clocks -quiet -of_objects $uvhs_difftest_pcie_pin] + if {![llength $uvhs_difftest_pcie_clocks]} { + catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_difftest_pcie_pin} uvhs_create_xdma_pin_msg + puts "INFO: UVHS patch: XDMA_AXI_ACLK create_clock on TO_DIFFTEST_PCIE_CLK result: $uvhs_create_xdma_pin_msg" + } else { + puts "INFO: UVHS patch: TO_DIFFTEST_PCIE_CLK already has clocks: $uvhs_difftest_pcie_clocks" + } +} else { + puts "WARNING: UVHS patch: TO_DIFFTEST_PCIE_CLK pin not found" +} +set uvhs_xdma_mmcms [get_cells -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/inst/mmcme*_adv_inst}] +if {[llength $uvhs_xdma_mmcms]} { + set_property CLKIN1_PERIOD __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_mmcms + puts "INFO: UVHS patch: set CLKIN1_PERIOD=__UVHS_XDMA_AXI_CLK_PERIOD_NS__ on $uvhs_xdma_mmcms" +} else { + puts "INFO: UVHS patch: XDMA clk_wiz MMCM cell not found; current x4 DCP exposes TO_DIFFTEST_PCIE_CLK directly" +} +set uvhs_xdma_intclks [get_clocks -quiet */xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/diablo_gt.diablo_gt_phy_wrapper/phy_clk_i/bufg_gt_intclk/O] +set uvhs_pcie_refclks [get_clocks -quiet pcie_ep_refclk] +if {[llength $uvhs_xdma_intclks] && [llength $uvhs_pcie_refclks]} { + set_false_path -from $uvhs_xdma_intclks -to $uvhs_pcie_refclks + puts "INFO: UVHS patch: false path XDMA GT internal clock -> pcie_ep_refclk" +} +set uvhs_lnk_up_src [get_pins -hier -quiet -filter {NAME =~ */xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/user_lnk_up_reg/C}] +set uvhs_lnk_up_dsts [concat \ + [get_pins -hier -quiet -filter {NAME =~ */u_capt*/captured_signal_p1_reg*/D}] \ + [get_pins -hier -quiet -filter {NAME =~ */user_lnk_up*_trigger_pipeline*/D}]] +if {[llength $uvhs_lnk_up_src] && [llength $uvhs_lnk_up_dsts]} { + set_false_path -from $uvhs_lnk_up_src -to $uvhs_lnk_up_dsts + puts "INFO: UVHS patch: false path XDMA user_lnk_up debug trigger paths" +} +}] + append script "\n" $refclk_patch_script + append script [uvhs_async_clock_patch_script] + foreach pre_opt [uvhs_vivado_stage_hook_files pre_opt] { + set fh [open $pre_opt r] + set data [read $fh] + close $fh + if {[string first "UVHS patch: wrapped write_xdc to patch generated XDMA preopt constraints" $data] < 0} { + set fh [open $pre_opt a] + puts $fh "" + puts $fh $write_xdc_patch_script + close $fh + append data "\n" $write_xdc_patch_script + puts "INFO: patched Vivado pre-opt write_xdc wrapper: $pre_opt" + } + if {[string first "UVHS patch: source XDMA CDC attributes before opt_design" $data] < 0} { + set fh [open $pre_opt a] + puts $fh "" + puts $fh $xdma_cdc_script + close $fh + append data "\n" $xdma_cdc_script + puts "INFO: patched Vivado pre-opt XDMA CDC attributes: $pre_opt" + } + if {[string first "UVHS patch: constrain XDMA clk_wiz input period" $data] < 0} { + set fh [open $pre_opt a] + puts $fh "" + puts $fh $script + close $fh + puts "INFO: patched Vivado pre-opt XDMA clk_wiz input period: $pre_opt" + } + } +} + +proc patch_vivado_pre_place {} { + set refclk_patch_script [uvhs_xdma_gt_refclk_patch_script "place"] + set script [string map [list __UVHS_XDMA_AXI_CLK_PERIOD_NS__ [uvhs_xdma_axi_clk_period_ns]] { +puts "INFO: UVHS patch: re-apply XDMA clk_wiz input period before place/route DRC" +set uvhs_xdma_clk_in [get_pins -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/clk_in1}] +if {[llength $uvhs_xdma_clk_in]} { + set uvhs_xdma_clk_in [lindex $uvhs_xdma_clk_in 0] + set uvhs_xdma_clocks [get_clocks -quiet -of_objects $uvhs_xdma_clk_in] + if {![llength $uvhs_xdma_clocks]} { + catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_clk_in} uvhs_create_clk_msg + puts "INFO: UVHS patch: XDMA_AXI_ACLK create_clock before place result: $uvhs_create_clk_msg" + } else { + puts "INFO: UVHS patch: XDMA clk_wiz input clocks before place: $uvhs_xdma_clocks" + if {[lsearch -exact $uvhs_xdma_clocks XDMA_AXI_ACLK] >= 0} { + puts "INFO: UVHS patch: XDMA_AXI_ACLK already exists before place" + } else { + catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_clk_in} uvhs_create_clk_msg + puts "INFO: UVHS patch: XDMA_AXI_ACLK override_clock before place result: $uvhs_create_clk_msg" + } + } +} else { + puts "INFO: UVHS patch: XDMA clk_wiz clk_in1 pin not found before place; current x4 DCP exposes TO_DIFFTEST_PCIE_CLK directly" +} +set uvhs_difftest_pcie_pin [get_pins -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK}] +if {[llength $uvhs_difftest_pcie_pin]} { + set uvhs_difftest_pcie_pin [lindex $uvhs_difftest_pcie_pin 0] + set uvhs_difftest_pcie_clocks [get_clocks -quiet -of_objects $uvhs_difftest_pcie_pin] + if {![llength $uvhs_difftest_pcie_clocks]} { + catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_difftest_pcie_pin} uvhs_create_xdma_pin_msg + puts "INFO: UVHS patch: XDMA_AXI_ACLK create_clock on TO_DIFFTEST_PCIE_CLK before place result: $uvhs_create_xdma_pin_msg" + } else { + puts "INFO: UVHS patch: TO_DIFFTEST_PCIE_CLK clocks before place: $uvhs_difftest_pcie_clocks" + } +} else { + puts "WARNING: UVHS patch: TO_DIFFTEST_PCIE_CLK pin not found before place" +} +set uvhs_xdma_mmcms [get_cells -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/inst/mmcme*_adv_inst}] +if {[llength $uvhs_xdma_mmcms]} { + set_property CLKIN1_PERIOD __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_mmcms + puts "INFO: UVHS patch: set CLKIN1_PERIOD=__UVHS_XDMA_AXI_CLK_PERIOD_NS__ on $uvhs_xdma_mmcms before place" +} else { + puts "INFO: UVHS patch: XDMA clk_wiz MMCM cell not found before place; current x4 DCP exposes TO_DIFFTEST_PCIE_CLK directly" +} +puts "INFO: UVHS patch: rewire Vivado debug hub clock if it is attached to an undriven net" +if {[llength [get_debug_cores -quiet dbg_hub]]} { + set uvhs_dbg_clk [get_nets -quiet clk5_p_pad_net_7_bufg_n] + if {![llength $uvhs_dbg_clk]} { + set uvhs_dbg_clk [get_nets -quiet clk5_p_pad_net_6] + } + if {[llength $uvhs_dbg_clk]} { + catch {disconnect_debug_port dbg_hub/clk} + connect_debug_port dbg_hub/clk [lindex $uvhs_dbg_clk 0] + puts "INFO: UVHS patch: dbg_hub/clk -> [lindex $uvhs_dbg_clk 0]" + } else { + puts "WARNING: UVHS patch: no clk5 debug clock net found for dbg_hub" + } +} +puts "INFO: UVHS patch: fix known bring-up bitstream DRCs" +set uvhs_ila_rams [get_cells -hier -quiet -filter {NAME =~ *system_ila_0*trace_block_memory*ram/DEVICE_8SERIES*ram}] +if {[llength $uvhs_ila_rams]} { + set_property CLOCK_DOMAINS INDEPENDENT $uvhs_ila_rams + puts "INFO: UVHS patch: set CLOCK_DOMAINS INDEPENDENT on [llength $uvhs_ila_rams] system ILA RAM cells" +} +set uvhs_ddr_ck_ports {} +foreach uvhs_pat {DDR0_CK_C_pad_net_* DDR0_CK_T_pad_net_*} { + set uvhs_ddr_ck_ports [concat $uvhs_ddr_ck_ports [get_ports -quiet $uvhs_pat]] +} +if {[llength $uvhs_ddr_ck_ports]} { + set_property IOSTANDARD DIFF_SSTL12_DCI $uvhs_ddr_ck_ports + puts "INFO: UVHS patch: set differential IOSTANDARD on generated DDR CK pad ports: $uvhs_ddr_ck_ports" +} +}] + append script "\n" $refclk_patch_script + append script [uvhs_async_clock_patch_script] + foreach pre_place [uvhs_vivado_stage_hook_files pre_place] { + set fh [open $pre_place r] + set data [read $fh] + close $fh + if {[string first "UVHS patch: re-apply XDMA clk_wiz input period before place/route DRC" $data] < 0} { + set fh [open $pre_place a] + puts $fh "" + puts $fh $script + close $fh + puts "INFO: patched Vivado pre-place debug hub clock: $pre_place" + } + } +} + +proc patch_vivado_before_route {} { + set script [string map [list __UVHS_XDMA_AXI_CLK_PERIOD_NS__ [uvhs_xdma_axi_clk_period_ns]] { +puts "INFO: UVHS patch: re-apply XDMA clk_wiz input period before route DRC" +set uvhs_xdma_clk_in [get_pins -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/clk_in1}] +if {[llength $uvhs_xdma_clk_in]} { + set uvhs_xdma_clk_in [lindex $uvhs_xdma_clk_in 0] + set uvhs_xdma_clocks [get_clocks -quiet -of_objects $uvhs_xdma_clk_in] + if {![llength $uvhs_xdma_clocks]} { + catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_clk_in} uvhs_create_clk_msg + puts "INFO: UVHS patch: XDMA_AXI_ACLK create_clock before route result: $uvhs_create_clk_msg" + } else { + puts "INFO: UVHS patch: XDMA clk_wiz input clocks before route: $uvhs_xdma_clocks" + if {[lsearch -exact $uvhs_xdma_clocks XDMA_AXI_ACLK] >= 0} { + puts "INFO: UVHS patch: XDMA_AXI_ACLK already exists before route" + } else { + catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_clk_in} uvhs_create_clk_msg + puts "INFO: UVHS patch: XDMA_AXI_ACLK override_clock before route result: $uvhs_create_clk_msg" + } + } +} else { + puts "INFO: UVHS patch: XDMA clk_wiz clk_in1 pin not found before route; current x4 DCP exposes TO_DIFFTEST_PCIE_CLK directly" +} +set uvhs_difftest_pcie_pin [get_pins -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK}] +if {[llength $uvhs_difftest_pcie_pin]} { + set uvhs_difftest_pcie_pin [lindex $uvhs_difftest_pcie_pin 0] + set uvhs_difftest_pcie_clocks [get_clocks -quiet -of_objects $uvhs_difftest_pcie_pin] + if {![llength $uvhs_difftest_pcie_clocks]} { + catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_difftest_pcie_pin} uvhs_create_xdma_pin_msg + puts "INFO: UVHS patch: XDMA_AXI_ACLK create_clock on TO_DIFFTEST_PCIE_CLK before route result: $uvhs_create_xdma_pin_msg" + } else { + puts "INFO: UVHS patch: TO_DIFFTEST_PCIE_CLK clocks before route: $uvhs_difftest_pcie_clocks" + } +} else { + puts "WARNING: UVHS patch: TO_DIFFTEST_PCIE_CLK pin not found before route" +} +set uvhs_xdma_mmcms [get_cells -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/inst/mmcme*_adv_inst}] +if {[llength $uvhs_xdma_mmcms]} { + set_property CLKIN1_PERIOD __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_mmcms + puts "INFO: UVHS patch: set CLKIN1_PERIOD=__UVHS_XDMA_AXI_CLK_PERIOD_NS__ on $uvhs_xdma_mmcms before route" + catch {update_timing} uvhs_update_timing_msg + puts "INFO: UVHS patch: update_timing before route result: $uvhs_update_timing_msg" +} else { + puts "INFO: UVHS patch: XDMA clk_wiz MMCM cell not found before route; current x4 DCP exposes TO_DIFFTEST_PCIE_CLK directly" +} +}] + append script [uvhs_async_clock_patch_script] + foreach pnr_dir [glob -nocomplain hw.dat/Compile/PnR/*/*] { + set before_route [file join $pnr_dir before_route.tcl] + set data "" + if {[file exists $before_route]} { + set fh [open $before_route r] + set data [read $fh] + close $fh + } + if {[string first "UVHS patch: re-apply XDMA clk_wiz input period before route DRC" $data] < 0} { + set fh [open $before_route a] + puts $fh "" + puts $fh $script + close $fh + puts "INFO: patched Vivado before-route XDMA clk_wiz input period: $before_route" + } + } +} + +proc patch_timing_constraint_files {} { + set xdma_axi_clk_period [uvhs_xdma_axi_clk_period_ns] + set xdma_axi_clk_half_period [format %.3f [expr {$xdma_axi_clk_period / 2.0}]] + set xdma_clkin1_replacement "set_property CLKIN1_PERIOD $xdma_axi_clk_period \[get_cells -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/inst/mmcme*_adv_inst}\]" + set xdma_blackbox_clock_replacement [format { +create_clock -period %.3f -name XDMA_AXI_ACLK -waveform {0.000 %.3f} -add [get_pins part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK]} \ + $xdma_axi_clk_period $xdma_axi_clk_half_period] + set difftest_clock_token_pattern {(^|[^[:alnum:]_])DIFFTEST_PCIE_CLK([^[:alnum:]_]|$)} + set async_xdc_block [format { + +# UVHS patch: source fpga_diff async clock constraints in final Vivado timing context. +if {[file exists {%s}]} { + source {%s} +} else { + puts "WARNING: UVHS patch: missing async clock file %s" +} +} [file normalize [file join $::fpga_diff_uvhs_dir async_clocks.tcl]] \ + [file normalize [file join $::fpga_diff_uvhs_dir async_clocks.tcl]] \ + [file normalize [file join $::fpga_diff_uvhs_dir async_clocks.tcl]]] + + foreach file [glob -nocomplain hw.dat/Compile/PnR/*/*/timing_constraints.tcl] { + set fh [open $file r] + set data [read $fh] + close $fh + set patched $data + + # TO_DIFFTEST_PCIE_CLK exits the XDMA endpoint black-box boundary, but + # the BD drives it directly from xdma_0/axi_aclk. Keep its constraint + # aligned with the XDMA IP axisten_freq selected by XDMA_LINK_WIDTH. + set xdma_axi_primary_clock [format { +puts "WARNING: \[APS CSTR-1\] primary clock is defined on blackbox boundary which may cause inaccurate skew analysis." +create_clock -add -name XDMA_AXI_ACLK -period [expr $uvCstrRatio * %.3f + $uvCstrMargin] -waveform [list 0 [expr ($uvCstrRatio + $uvCstrMargin / %.3f) * %.3f]] [get_pins { part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK }] +variable XDMA_AXI_ACLK_name [get_property NAME [get_clocks XDMA_AXI_ACLK]] +} $xdma_axi_clk_period $xdma_axi_clk_period $xdma_axi_clk_half_period] + set difftest_generated_block {set DIFFTEST_PCIE_CLK_master [get_clocks -of_objects [get_pins { part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK }]] +set DIFFTEST_PCIE_CLK_source "" +if {$DIFFTEST_PCIE_CLK_master!=""} { + set DIFFTEST_PCIE_CLK_source [get_property SOURCE_PINS $DIFFTEST_PCIE_CLK_master] +} +if {[llength $DIFFTEST_PCIE_CLK_master] == 1 && [llength $DIFFTEST_PCIE_CLK_source] == 1} { + set DIFFTEST_PCIE_CLK_source [get_pins $DIFFTEST_PCIE_CLK_source] + if {$DIFFTEST_PCIE_CLK_source==""} { + set DIFFTEST_PCIE_CLK_source [get_ports [get_property SOURCE_PINS $DIFFTEST_PCIE_CLK_master]] + } + set driver [get_nets -top_net_of_hierarchical_group -segments -of_objects $DIFFTEST_PCIE_CLK_source] + if {[get_nets -top_net_of_hierarchical_group -segments -of_objects [get_pins { part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK }]]==$driver} { + variable DIFFTEST_PCIE_CLK_name [get_property NAME $DIFFTEST_PCIE_CLK_master] + dict set uvRenameClocks DIFFTEST_PCIE_CLK [get_pins { part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK }] + } else { + create_generated_clock -add -name DIFFTEST_PCIE_CLK -divide_by 1 -source $DIFFTEST_PCIE_CLK_source -master_clock $DIFFTEST_PCIE_CLK_master [get_pins { part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK }] + variable DIFFTEST_PCIE_CLK_name [get_property NAME [get_clocks DIFFTEST_PCIE_CLK]] + } +} else { + puts "WARNING: \[APS CSTR-1\] primary clock is defined on blackbox boundary which may cause inaccurate skew analysis." + create_clock -add -name DIFFTEST_PCIE_CLK -period [expr $uvCstrRatio * 10.00 + $uvCstrMargin] [get_pins { part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK }] +variable DIFFTEST_PCIE_CLK_name [get_property NAME [get_clocks DIFFTEST_PCIE_CLK]] +}} + if {[string first $difftest_generated_block $patched] >= 0} { + regsub [string map {\\ \\\\ \[ \\[ \] \\] \$ \\$ \( \\( \) \\) \{ \\{ \} \\} \. \\. \* \\* \+ \\+ \? \\? \^ \\^} $difftest_generated_block] \ + $patched $xdma_axi_primary_clock patched + } + regsub -all {create_clock[^\n]*-name[^\n]*DIFFTEST_PCIE_CLK[^\n]*TO_DIFFTEST_PCIE_CLK[^\n]*} \ + $patched $xdma_axi_primary_clock patched + regsub -all {create_generated_clock[^\n]*-name[^\n]*core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer[^\n]*TO_DIFFTEST_PCIE_CLK[^\n]*} \ + $patched $xdma_axi_primary_clock patched + regsub -all {core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer_name} $patched {XDMA_AXI_ACLK_name} patched + regsub -all {core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer} $patched {XDMA_AXI_ACLK} patched + regsub -all {DIFFTEST_PCIE_CLK_name} $patched {XDMA_AXI_ACLK_name} patched + regsub -all $difftest_clock_token_pattern $patched {\1XDMA_AXI_ACLK\2} patched + if {![env_or_default UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP 0]} { + regsub -all {create_generated_clock[^\n]*-name[^\n]*core_def_U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0_c0_ddr4_ui_clk_infer[^\n]*c0_ddr4_ui_clk[^\n]*} \ + $patched {create_clock -add -name core_def_U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0_c0_ddr4_ui_clk_infer -period [expr $uvCstrRatio * 5.000 + $uvCstrMargin] -waveform [list 0 [expr ($uvCstrRatio + $uvCstrMargin / 5.000) * 2.500]] [get_pins { part_2/core_def/U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0/c0_ddr4_ui_clk }]} patched + } + if {$patched ne $data} { + set fh [open $file w] + puts -nonewline $fh $patched + close $fh + puts "INFO: patched UVHS DIFFTEST PCIe / DDR UI clock timing constraints: $file" + } + } + + foreach file [concat \ + [glob -nocomplain hw.dat/Compile/PnR/*/*/vivado/Rundir/*/bitstream/pnr_timing_constraints_preopt.xdc] \ + [glob -nocomplain hw.dat/Compile/PnR/*/*/vivado/Rundir/*/bitstream/pnr_timing_constraints.xdc]] { + set fh [open $file r] + set data [read $fh] + close $fh + set patched $data + + regsub -all {create_clock[^\n]*-name[^\n]*DIFFTEST_PCIE_CLK[^\n]*TO_DIFFTEST_PCIE_CLK[^\n]*} \ + $patched $xdma_blackbox_clock_replacement patched + regsub -all {create_generated_clock[^\n]*-name[^\n]*core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer[^\n]*TO_DIFFTEST_PCIE_CLK[^\n]*} \ + $patched $xdma_blackbox_clock_replacement patched + regsub -all {core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer} $patched {XDMA_AXI_ACLK} patched + regsub -all $difftest_clock_token_pattern $patched {\1XDMA_AXI_ACLK\2} patched + if {![env_or_default UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP 0]} { + regsub -all {create_generated_clock[^\n]*-name[^\n]*core_def_U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0_c0_ddr4_ui_clk_infer[^\n]*c0_ddr4_ui_clk[^\n]*} \ + $patched {create_clock -period 5.000 -name core_def_U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0_c0_ddr4_ui_clk_infer -waveform {0.000 2.500} -add [get_pins part_2/core_def/U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0/c0_ddr4_ui_clk]} patched + } + regsub -all {set_property CLKIN1_PERIOD [0-9]+(\.[0-9]*)? \[get_cells -hier -quiet -filter \{NAME =~ \*/core_def/xdma_ep_i/clk_wiz_0/inst/mmcme\*_adv_inst\}\]} \ + $patched $xdma_clkin1_replacement patched + if {[string first "UVHS patch: source fpga_diff async clock constraints in final Vivado timing context" $patched] < 0} { + append patched $async_xdc_block + } + if {$patched ne $data} { + set fh [open $file w] + puts -nonewline $fh $patched + close $fh + puts "INFO: patched Vivado DIFFTEST PCIe / DDR UI clock timing constraints: $file" + } + } + + foreach file [glob -nocomplain hw.dat/Compile/PnR/*/*/vivado/Rundir/*/bitstream/pnr_physical_constraints_preopt.xdc] { + set fh [open $file r] + set data [read $fh] + close $fh + set patched $data + + regsub -all {set_property CLKIN1_PERIOD [0-9]+(\.[0-9]*)? \[get_cells -hier -quiet -filter \{NAME =~ \*/core_def/xdma_ep_i/clk_wiz_0/inst/mmcme\*_adv_inst\}\]} \ + $patched $xdma_clkin1_replacement patched + if {$patched ne $data} { + set fh [open $file w] + puts -nonewline $fh $patched + close $fh + puts "INFO: patched Vivado XDMA clk_wiz physical constraints: $file" + } + } +} + +proc patch_xdma_gt_refclk_pad_constraints {} { + foreach pnr_dir [glob -nocomplain hw.dat/Compile/PnR/*/*] { + set xdc [file join $pnr_dir xdma_gt_refclk_no_buffer.xdc] + if {[file exists $xdc]} { + file delete -force $xdc + puts "INFO: removed obsolete XDMA GT refclk XDC: $xdc" + } + + foreach hook_name {before_link.tcl pre_link.tcl} { + set hook [file join $pnr_dir $hook_name] + if {![file exists $hook]} { + continue + } + set fh [open $hook r] + set data [read $fh] + close $fh + set patched $data + + regsub -all {\nadd_file \$FILE_DIR/xdma_gt_refclk_no_buffer\.xdc} $patched "" patched + + if {$patched ne $data} { + set fh [open $hook w] + puts -nonewline $fh $patched + close $fh + puts "INFO: removed obsolete XDMA GT refclk XDC hook: $hook" + } + } + } + + foreach file [concat \ + [glob -nocomplain hw.dat/Compile/PnR/*/*/pin_assign.xdc] \ + [glob -nocomplain hw.dat/Compile/PnR/*/*/dlp.xdc]] { + set fh [open $file r] + set data [read $fh] + close $fh + if {[string first "UVHS patch: keep XDMA GT refclk pads unbuffered" $data] >= 0} { + continue + } + + set p_ports [regexp -inline -all {pcie_ep_gt_ref_clk_p_pad_net_[0-9]+} $data] + set n_ports [regexp -inline -all {pcie_ep_gt_ref_clk_n_pad_net_[0-9]+} $data] + set refclk_ports {} + foreach port [concat $p_ports $n_ports] { + if {[lsearch -exact $refclk_ports $port] < 0} { + lappend refclk_ports $port + } + } + if {![llength $refclk_ports]} { + continue + } + + set block "\n# UVHS patch: keep XDMA GT refclk pads unbuffered for IBUFDS_GTE in xdma_ep.\n" + foreach port $refclk_ports { + append block "set_property IO_BUFFER_TYPE NONE \[get_ports -quiet {$port}\]\n" + append block "set_property CLOCK_BUFFER_TYPE NONE \[get_ports -quiet {$port}\]\n" + } + set patched $data + if {[regexp {set_property PACKAGE_PIN [^\n]+pcie_ep_gt_ref_clk_[pn]_pad_net_[0-9]+[^\n]*} $patched first_refclk_line]} { + set idx [string first $first_refclk_line $patched] + set patched [string range $patched 0 [expr {$idx - 1}]] + append patched $block $first_refclk_line + append patched [string range $data [expr {$idx + [string length $first_refclk_line]}] end] + } else { + append patched $block + } + set fh [open $file w] + puts -nonewline $fh $patched + close $fh + puts "INFO: patched XDMA GT refclk pad constraints: $file" + } +} + +proc patch_xdma_cdc_attribute_constraints {} { + foreach pnr_dir [glob -nocomplain hw.dat/Compile/PnR/*/*] { + set script [file join $pnr_dir xdma_cdc_attributes.tcl] + set fh [open $script w] + puts $fh "# UVHS patch: annotate known XDMA IP CDC synchronizer registers." + puts $fh "# This does not change clock definitions; it only preserves and classifies" + puts $fh "# Xilinx XDMA reset/clock-converter synchronization chains after link_design." + puts $fh "proc ::uvhs_xdma_mark_cdc_cells {uvhs_label uvhs_patterns} {" + puts $fh " set uvhs_cells {}" + puts $fh " foreach uvhs_pattern \$uvhs_patterns {" + puts $fh " foreach uvhs_cell \[get_cells -hier -quiet -filter \"IS_SEQUENTIAL && NAME =~ \$uvhs_pattern\"\] {" + puts $fh " if {\[lsearch -exact \$uvhs_cells \$uvhs_cell\] < 0} {" + puts $fh " lappend uvhs_cells \$uvhs_cell" + puts $fh " }" + puts $fh " }" + puts $fh " }" + puts $fh " if {\[llength \$uvhs_cells\]} {" + puts $fh " set_property ASYNC_REG TRUE \$uvhs_cells" + puts $fh " }" + puts $fh " puts \"INFO: UVHS patch: XDMA CDC category \$uvhs_label ASYNC_REG count=\[llength \$uvhs_cells\]\"" + puts $fh " return \$uvhs_cells" + puts $fh "}" + puts $fh "set uvhs_xdma_cdc_cells {}" + puts $fh "foreach uvhs_xdma_cdc_cell \[::uvhs_xdma_mark_cdc_cells auto_cc_clock_conv_lite {" + puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/inst/gen_clock_conv.gen_async_lite_conv*/clock_conv_lite_*/*_reg*" + puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/inst/gen_clock_conv.gen_async_lite_conv*/clock_conv_lite_*/handshake/*_reg*" + puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*clock_conv_lite*/*_reg*" + puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*handshake*/*_reg*" + puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*cdc*/*_reg*" + puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*sync*/*_reg*" + puts $fh "}\] {" + puts $fh " if {\[lsearch -exact \$uvhs_xdma_cdc_cells \$uvhs_xdma_cdc_cell\] < 0} {" + puts $fh " lappend uvhs_xdma_cdc_cells \$uvhs_xdma_cdc_cell" + puts $fh " }" + puts $fh "}" + puts $fh "foreach uvhs_xdma_cdc_cell \[::uvhs_xdma_mark_cdc_cells auto_cc_xpm_cdc {" + puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/inst/*xpm_cdc*/*_reg*" + puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/inst/*xpm_cdc*/inst/*_reg*" + puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*xpm_cdc*/*_reg*" + puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*xpm_cdc*/inst/*_reg*" + puts $fh "}\] {" + puts $fh " if {\[lsearch -exact \$uvhs_xdma_cdc_cells \$uvhs_xdma_cdc_cell\] < 0} {" + puts $fh " lappend uvhs_xdma_cdc_cells \$uvhs_xdma_cdc_cell" + puts $fh " }" + puts $fh "}" + puts $fh "foreach uvhs_xdma_cdc_cell \[::uvhs_xdma_mark_cdc_cells xdma_reset_and_link {" + puts $fh " */core_def/xdma_ep_i/xdma_0/inst/*/*cdc*/*_reg*" + puts $fh " */core_def/xdma_ep_i/xdma_0/inst/*/*cdc*/inst/*_reg*" + puts $fh " */core_def/xdma_ep_i/xdma_0/inst/*/xpm_cdc*/*_reg*" + puts $fh " */core_def/xdma_ep_i/xdma_0/inst/*/xpm_cdc*/inst/*_reg*" + puts $fh " */core_def/xdma_ep_i/xdma_0/inst/*/arststages_ff_reg*" + puts $fh " */core_def/xdma_ep_i/xdma_0/inst/*/*user_rst*_reg*" + puts $fh " */core_def/xdma_ep_i/xdma_0/inst/udma_wrapper/dma_top/user_rst*_reg*" + puts $fh " */core_def/xdma_ep_i/xdma_0/inst/udma_wrapper/dma_top/*user_rst*_reg*" + puts $fh " */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*cdc*/*_reg*" + puts $fh " */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*cdc*/inst/*_reg*" + puts $fh " */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*sync*/*_reg*" + puts $fh " */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*sync*/inst/*_reg*" + puts $fh " */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*rst*sync*reg*" + puts $fh " */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*reset*sync*reg*" + puts $fh "}\] {" + puts $fh " if {\[lsearch -exact \$uvhs_xdma_cdc_cells \$uvhs_xdma_cdc_cell\] < 0} {" + puts $fh " lappend uvhs_xdma_cdc_cells \$uvhs_xdma_cdc_cell" + puts $fh " }" + puts $fh "}" + puts $fh "if {\[llength \$uvhs_xdma_cdc_cells\]} {" + puts $fh " set_property ASYNC_REG TRUE \$uvhs_xdma_cdc_cells" + puts $fh " puts \"INFO: UVHS patch: marked XDMA CDC cells ASYNC_REG count=\[llength \$uvhs_xdma_cdc_cells\]\"" + puts $fh "} else {" + puts $fh " puts \"INFO: UVHS patch: no XDMA CDC cells matched for ASYNC_REG annotation\"" + puts $fh "}" + close $fh + puts "INFO: wrote XDMA CDC attribute script: $script" + + foreach hook_name {before_link.tcl pre_link.tcl} { + set hook [file join $pnr_dir $hook_name] + if {![file exists $hook]} { + continue + } + set fh [open $hook r] + set data [read $fh] + close $fh + set patched $data + regsub -all {\nadd_file \$FILE_DIR/xdma_cdc_attributes\.xdc} $patched "" patched + regsub -all {\nsource \$FILE_DIR/xdma_cdc_attributes\.tcl} $patched "" patched + if {$patched ne $data} { + set fh [open $hook w] + puts -nonewline $fh $patched + close $fh + puts "INFO: removed pre-link XDMA CDC attribute hook: $hook" + } + } + } +} + +proc patch_vivado_makefiles {} { + if {[info exists ::env(UV_SHELL)] && $::env(UV_SHELL) ne ""} { + set uv_shell $::env(UV_SHELL) + } elseif {[info exists ::env(UV_ROOT)] && $::env(UV_ROOT) ne ""} { + set uv_shell [file join $::env(UV_ROOT) bin uv_shell] + } else { + set uv_shell uv_shell + } + set replacement "bash $uv_shell" + foreach makefile [glob -nocomplain hw.dat/Compile/PnR/*/*/vivado/Rundir/*/Makefile] { + set fh [open $makefile r] + set data [read $fh] + close $fh + set patched $data + regsub -all {(^|[[:space:]&;])uv_shell([[:space:]])} \ + $patched "\\1$replacement\\2" patched + regsub -all {(^|[[:space:]&;])(/[^[:space:]]+/uv_shell)([[:space:]])} \ + $patched "\\1$replacement\\3" patched + regsub -all {(^|[[:space:]&;(@])(bash[[:space:]]+)+(/[^[:space:]]+/uv_shell)} \ + $patched "\\1$replacement" patched + regsub -all {(^|[[:space:]])@uv_shell([[:space:]])} \ + $patched "\\1@$replacement\\2" patched + if {$patched ne $data} { + set fh [open $makefile w] + puts -nonewline $fh $patched + close $fh + puts "INFO: patched UVHS Makefile uv_shell invocation: $makefile" + } + } +} + +set_working_space hw.dat + +set fpga_threads [env_or_default UVHS_FPGA_THREADS 8] +set fpga_processes [env_or_default UVHS_FPGA_PROCESSES 16] +if {[env_or_default UVHS_USE_LSF 1]} { + set_parallel_option -max_threads $fpga_threads -max_processes $fpga_processes -submit_command {bsub -R "rusage[mem=80000]"} -terminate_command bkill -label fpga +} else { + set_parallel_option -max_threads $fpga_threads -max_processes $fpga_processes -label fpga +} + +set_option time.auto_clock_config true +set_option clock.transform_clock.multi_iteration true +set_option clock.glitch.force_transform true +set_option clock.async_control.force_accept true +set_option time.enable_sign_off true +set_option time.incremental_sign_off true +set uvhs_time_group_io_logic [env_or_default UVHS_TIME_GROUP_IO_LOGIC default] +if {$uvhs_time_group_io_logic ne "default"} { + if {$uvhs_time_group_io_logic ni {0 1 false true}} { + error "UVHS_TIME_GROUP_IO_LOGIC must be one of default/0/1/false/true, got '$uvhs_time_group_io_logic'" + } + puts "INFO: set time.group_io_logic=$uvhs_time_group_io_logic" + set_option time.group_io_logic $uvhs_time_group_io_logic +} + +set design_name [env_or_default UVHS_DESIGN_NAME VU19P_X4] +set platform [env_or_default PLATFORM U2.2] +create_system_design -name $design_name -platform $platform +set assemble_file [env_or_default UVHS_ASSEMBLE_FILE ./script/1B_4F_HGC_assemble.tcl] +if {$assemble_file eq "none"} { + puts "INFO: skip board assembly" +} else { + source_if_exists $assemble_file +} +set skip_board_constraints [env_or_default UVHS_SKIP_BOARD_CONSTRAINTS 0] +if {$skip_board_constraints} { + puts "INFO: skip board pin constraints" +} else { + set assign_pin_file [env_or_default UVHS_ASSIGN_PIN_FILE ./script/assign_pin.tcl] + if {[file exists $assign_pin_file]} { + set ::env(UVHS_ASSIGN_PIN_TOP) none + source_if_exists $assign_pin_file + unset -nocomplain ::env(UVHS_ASSIGN_PIN_TOP) + } else { + puts "INFO: skip missing $assign_pin_file" + } + source_if_exists [env_or_default UVHS_PIN_OVERRIDE_FILE none] +} + +create_design -name test +uvhs_clean_stale_partition_runtime +read_netlist +link_design +report_resource -depth 4 + +instrument_design +sanitize_design +if {$skip_board_constraints} { + run_or_warn "check_design" {check_design} +} else { + check_design +} +init_runtime_data +trigger_probe -check +sweep_design + +create_clock_if_port_exists TMCLK 1000 clk8_p +create_clock_if_port_exists ddr_ref_clk 12.5 clk7_p +if {[uvhs_cpu_debug_clk]} { + create_clock_if_port_exists CPU_CLK_IN [uvhs_cpu_clk_period_ns] clk5_p +} else { + create_clock_if_port_exists CPU_CLK_IN [uvhs_cpu_clk_period_ns] clk6_p + create_clock_if_port_exists DEBUG_CLK_IN 40 clk5_p +} +create_clock_if_port_exists jtag_vclk 83.333 JTAG_TCK +create_clock_if_port_exists pcie_ep_refclk 10 pcie_ep_gt_ref_clk_p +create_generated_clock_if_bufgce_exists SOC_GATED_CLK CPU_CLK_IN { + *SOC_CLK_CTRL*u_bufgce + *inter_soc_clk* +} +create_generated_clock_if_bufgce_exists RTC_GATED_CLK TMCLK { + *RTC_CLK_CTRL*u_bufgce + *inter_rtc_clk* +} +create_blackbox_output_clock_if_pin_exists XDMA_AXI_ACLK [uvhs_xdma_axi_clk_period_ns] core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK +create_ddr_ui_clock_if_exists +create_clock_if_pin_exists XDMA_AXI_ACLK [uvhs_xdma_axi_clk_period_ns] core_def/xdma_ep_i/clk_wiz_0/clk_in1 +run_or_warn "infer_clock" {infer_clock} +run_or_warn "report_clock -inferred" {report_clock -inferred} +source_if_exists [file normalize [file join [file dirname [info script]] async_clocks.tcl]] +run_or_warn "transform_clock" {transform_clock} +source_if_exists [file normalize [file join [file dirname [info script]] async_clocks.tcl]] +trigger_probe -group +uvhs_config_probe_group_resource +sweep_design -remap +report_clock + +if {$skip_board_constraints} { + run_or_warn "check_design" {check_design} +} else { + check_design +} +report_resource -depth 4 +report_system_resource +list_partition_constraints -all +if {$skip_board_constraints} { + run_or_warn "partition_design" {partition_design -tdc -tdss true} +} else { + partition_design -tdc -tdss true +} +report_resource -depth 4 + +instrument_design +localize_design -replicate_cell -clock -self_check +sweep_design -keep_feedthrough +localize_design -data +route_design +check_timing -verbose +report_system_performance -show_clock_relation -verbose +report_path -normalize -exception -tdr -net -rtl -max_path 100 -sort_by fmax + +insert_tdm +reopt_design -verbose +bind_system +save_runtime_data + +set_option compile.resourceUsageLimit [env_or_default UVHS_RESOURCE_USAGE_LIMIT 100] +set strategy_num_retry [env_or_default UVHS_STRATEGY_NUM_RETRY none] +if {$strategy_num_retry eq "none" || $strategy_num_retry eq "0"} { + puts "INFO: skip compile.strategyNumRetry" +} else { + run_or_warn "set_option compile.strategyNumRetry" \ + [list set_option compile.strategyNumRetry $strategy_num_retry] +} + +set compile_strategy_num [env_or_default UVHS_COMPILE_STRATEGY_NUM 1] +if {![string is integer -strict $compile_strategy_num] || $compile_strategy_num < 1} { + error "UVHS_COMPILE_STRATEGY_NUM must be a positive integer, got '$compile_strategy_num'" +} +set_option compile.strategyNum $compile_strategy_num +set default_compile_strategies { + uv_high_fanout_explore + uv_placer_balance_slrs + uv_placer_extra_timing_opt +} +for {set i 0} {$i < $compile_strategy_num} {incr i} { + set default_strategy "" + if {$i < [llength $default_compile_strategies]} { + set default_strategy [lindex $default_compile_strategies $i] + } + set strategy [env_or_default [format {UVHS_COMPILE_STRATEGY%d} $i] $default_strategy] + if {$strategy eq "" || $strategy eq "none"} { + error "missing compile strategy $i; set UVHS_COMPILE_STRATEGY$i" + } + puts "INFO: UVHS compile.strategy$i=$strategy" + set_option [format {compile.strategy%d} $i] $strategy +} +set_option compile.stage.preOpt ./script/pre_opt.tcl +set_option compile.stage.prePlace ./script/pre_place.tcl + +compile_fpga -parallel_option fpga -genScriptOnly -explore +patch_timing_constraint_files +patch_xdma_gt_refclk_pad_constraints +patch_xdma_cdc_attribute_constraints +patch_vivado_wrappers +patch_vivado_makefiles +patch_vivado_pre_opt +patch_vivado_pre_place +patch_vivado_before_route +compile_fpga -parallel_option fpga -runOnly -explore + +report_path -max_path 100 +report_system_performance +commit_runtime_data +exit diff --git a/fpga_diff/uvhs/check_flow_tools.sh b/fpga_diff/uvhs/check_flow_tools.sh new file mode 100644 index 00000000..1d554861 --- /dev/null +++ b/fpga_diff/uvhs/check_flow_tools.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +root_dir="$(cd "$script_dir/.." && pwd)" + +required=( + Makefile + uvhs/uvhs.mk + uvhs/README.md + uvhs/frontend_run.tcl + uvhs/backend_run.tcl + uvhs/assemble_uvhs.tcl + uvhs/assign_pin_u22_f2.tcl + uvhs/async_clocks.tcl + uvhs/timing_common.tcl + uvhs/export_vivado_ip.tcl + uvhs/check_modules.sh + uvhs/filelist.awk + uvhs/make_compat/make + uvhs/make_compat/csh + uvhs/patch_uvsyn_shell.sh + user_script/hw_run_download.tcl + src/rtl/common/uvhs_axi64_to_axi256.sv + src/rtl/common/uvhs_ddr4_wrapper.sv + src/tcl/common/AXI_bridge.tcl + src/tcl/common/xdma_ep.tcl +) + +for path in "${required[@]}"; do + test -f "$root_dir/$path" || { + echo "ERROR: missing required UVHS flow file: $path" >&2 + exit 1 + } +done + +bash -n "$root_dir/uvhs/check_modules.sh" +bash -n "$root_dir/uvhs/check_flow_tools.sh" +bash -n "$root_dir/uvhs/make_compat/make" +bash -n "$root_dir/uvhs/make_compat/csh" +bash -n "$root_dir/uvhs/patch_uvsyn_shell.sh" + +if command -v tclsh >/dev/null 2>&1; then + while IFS= read -r -d '' path; do + tclsh /dev/stdin "$path" <<'TCL' +set fh [open [lindex $argv 0] r] +set source [read $fh] +close $fh +if {![info complete $source]} { exit 1 } +TCL + done < <(find "$root_dir/uvhs" "$root_dir/user_script" -type f -name '*.tcl' -print0) +fi + +if grep -R -n -E '/home/|setenv\.local|NUTSHELL_LEGACY_DIFFTEST_HOSTIF|UVHS_XDMA_ST_LOOPBACK_SMOKE|UVHS_CPU_LIVENESS_GBD' \ + --include='*.mk' --include='*.sh' --include='*.tcl' --include='*.sv' \ + --exclude='check_flow_tools.sh' "$root_dir/uvhs" "$root_dir/user_script"; then + echo "ERROR: removed local paths or legacy/debug controls remain in UVHS sources" >&2 + exit 1 +fi + +echo "OK: UVHS flow source checks passed" diff --git a/fpga_diff/uvhs/check_modules.sh b/fpga_diff/uvhs/check_modules.sh new file mode 100755 index 00000000..357ef4a5 --- /dev/null +++ b/fpga_diff/uvhs/check_modules.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail + +filelist=${1:-} +required_modules=${2:-} + +if [[ -z "$filelist" || ! -f "$filelist" ]]; then + echo "Verilog filelist not found: $filelist" >&2 + exit 2 +fi + +if [[ -z "$required_modules" ]]; then + echo "No required modules configured; skip module check." + exit 0 +fi + +tmp_sources=$(mktemp) +trap 'rm -f "$tmp_sources"' EXIT + +awk 'NF && $0 !~ /^\+/ { print }' "$filelist" > "$tmp_sources" + +missing=0 +for module_name in $required_modules; do + found=0 + while IFS= read -r source_file; do + [[ -f "$source_file" ]] || continue + if grep -Eq "^[[:space:]]*module[[:space:]]+$module_name([[:space:]#(]|$)" "$source_file"; then + found=1 + break + fi + done < "$tmp_sources" + + if [[ "$found" == 1 ]]; then + echo "Found required module: $module_name" + else + echo "Missing required module: $module_name" >&2 + missing=1 + fi +done + +if [[ "$missing" != 0 ]]; then + echo "Required module check failed for $filelist" >&2 + exit 1 +fi diff --git a/fpga_diff/uvhs/export_vivado_ip.tcl b/fpga_diff/uvhs/export_vivado_ip.tcl new file mode 100644 index 00000000..6e09ccd7 --- /dev/null +++ b/fpga_diff/uvhs/export_vivado_ip.tcl @@ -0,0 +1,386 @@ +################################################################################ +# Export Vivado IP/BD checkpoints for UVHS blackbox import. +################################################################################ + +set origin_dir "." +set out_dir "./uvhs_ip" +set vivado_version "" +set force 0 +set jobs 8 +set cpu "kmh" +set core_dir "" +set only "" +set skip_exports [list] + +proc print_help {} { + puts "Usage:" + puts " vivado -mode batch -source uvhs/export_vivado_ip.tcl -tclargs \\" + puts " --origin_dir --out_dir \[--vivado_version \] \[--cpu \] \[--core_dir \] \[--only \] \[--skip \] \[--force\] \[--jobs N\]" + exit 0 +} + +for {set i 0} {$i < $::argc} {incr i} { + set option [lindex $::argv $i] + switch -- $option { + "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } + "--out_dir" { incr i; set out_dir [lindex $::argv $i] } + "--vivado_version" { incr i; set vivado_version [lindex $::argv $i] } + "--cpu" { incr i; set cpu [lindex $::argv $i] } + "--core_dir" { incr i; set core_dir [lindex $::argv $i] } + "--only" { incr i; set only [lindex $::argv $i] } + "--skip" { incr i; lappend skip_exports [lindex $::argv $i] } + "--force" { set force 1 } + "--jobs" { incr i; set jobs [lindex $::argv $i] } + "--help" { print_help } + default { + puts "ERROR: unknown option $option" + print_help + } + } +} + +set origin_dir [file normalize $origin_dir] +set out_dir [file normalize $out_dir] +if {$core_dir ne ""} { + set core_dir [file normalize $core_dir] +} +set tcl_dir [file join $origin_dir src tcl common] +set export_project_dir [file join $out_dir vivado_ip_export] +set export_project [file join $export_project_dir vivado_ip_export.xpr] + +if {$vivado_version eq ""} { + set vivado_version [version -short] +} +set ::vivado_version $vivado_version +set ::cpu $cpu +set ::core_dir $core_dir + +if {$force && [file exists $export_project_dir]} { + file delete -force $export_project_dir +} + +file mkdir $out_dir +file mkdir [file join $out_dir rtl soc] +file mkdir [file join $out_dir rtl device pcie] +file mkdir $export_project_dir + +if {[file exists $export_project]} { + open_project $export_project +} else { + create_project vivado_ip_export $export_project_dir -part xcvu19p-fsva3824-2-e + set_property target_language Verilog [current_project] + set_property simulator_language Mixed [current_project] +} + +proc add_core_generated_headers {core_dir} { + if {$core_dir eq "" || ![file isdirectory $core_dir]} { + return + } + + set header_candidates [list \ + [file join $core_dir build generated-src DifftestMacros.svh] \ + [file join $core_dir generated-src DifftestMacros.svh] \ + [file join $core_dir build rtl DifftestMacros.svh] \ + [file join $core_dir rtl DifftestMacros.svh] \ + ] + foreach hdr $header_candidates { + if {![file exists $hdr]} { + continue + } + set hdr [file normalize $hdr] + if {[llength [get_files -quiet $hdr]] == 0} { + add_files -norecurse $hdr + } + set hdr_file [get_files -quiet $hdr] + if {[llength $hdr_file] > 0} { + set_property file_type {Verilog Header} $hdr_file + } + puts "INFO: added core generated header $hdr" + return + } + puts "WARNING: DifftestMacros.svh not found under core_dir $core_dir" +} + +add_core_generated_headers $core_dir + +proc source_ip_tcl {script} { + if {![file exists $script]} { + puts "WARNING: missing IP script $script" + return 0 + } + puts "INFO: source $script" + set rc [catch {uplevel #0 [list source $script]} err opts] + if {$rc != 0} { + puts "ERROR: failed to source $script" + puts $err + return -options $opts $err + } + return 1 +} + +proc run_and_copy_dcp {run_name out_file jobs force} { + if {[file exists $out_file] && !$force} { + puts "INFO: reuse existing $out_file" + return + } + + set run [get_runs -quiet $run_name] + if {[llength $run] == 0} { + error "run $run_name not found" + } + + reset_run $run + clear_auto_incremental_imports $run_name + launch_runs $run -jobs $jobs + wait_on_run $run + + set status [get_property STATUS $run] + puts "INFO: $run_name status: $status" + + set run_dir [get_property DIRECTORY $run] + set dcps [glob -nocomplain [file join $run_dir *.dcp]] + if {[llength $dcps] == 0} { + if {![string match "*Complete*" $status]} { + error "$run_name did not complete: $status" + } + error "no DCP generated in $run_dir" + } + + file mkdir [file dirname $out_file] + file copy -force [lindex $dcps 0] $out_file + puts "INFO: exported $out_file" +} + +proc run_and_write_opened_dcp {run_name out_file jobs force} { + if {[file exists $out_file] && !$force} { + puts "INFO: reuse existing $out_file" + return + } + + set run [get_runs -quiet $run_name] + if {[llength $run] == 0} { + error "run $run_name not found" + } + + reset_run $run + clear_auto_incremental_imports $run_name + launch_runs $run -jobs $jobs + wait_on_run $run + + set status [get_property STATUS $run] + puts "INFO: $run_name status: $status" + if {![string match "*Complete*" $status]} { + error "$run_name did not complete: $status" + } + + catch {close_design} + open_run $run_name + file mkdir [file dirname $out_file] + write_checkpoint -force $out_file + puts "INFO: exported stitched checkpoint $out_file" +} + +proc copy_generated_stub {kind name out_file} { + global export_project_dir out_dir + + if {$kind eq "xci"} { + set candidates [concat \ + [glob -nocomplain [file join $export_project_dir *.srcs sources_1 ip $name ${name}_stub.v]] \ + [glob -nocomplain [file join $export_project_dir *.gen sources_1 ip $name ${name}_stub.v]]] + } else { + set candidates [glob -nocomplain [file join $export_project_dir *.gen sources_1 bd $name ${name}_bmstub.v]] + } + if {[llength $candidates] != 1} { + error "cannot find generated $kind stub for $name" + } + + set stub [file join $out_dir rtl stubs ${name}.v] + file mkdir [file dirname $stub] + file copy -force [lindex $candidates 0] $stub + puts "INFO: exported generated stub $stub" +} + +proc clear_auto_incremental_imports {run_name} { + global export_project_dir + + set run [get_runs -quiet $run_name] + if {[llength $run] > 0} { + set props [list_property $run] + foreach {prop value} { + AUTO_INCREMENTAL_CHECKPOINT 0 + INCREMENTAL_CHECKPOINT {} + STEPS.SYNTH_DESIGN.ARGS.INCREMENTAL_MODE off + } { + if {[lsearch -exact $props $prop] >= 0} { + set rc [catch {set_property $prop $value $run} err] + if {$rc == 0} { + puts "INFO: cleared auto-incremental property $prop on run $run_name" + } else { + puts "WARNING: failed to clear auto-incremental property $prop on run $run_name: $err" + } + } + } + } + + foreach imports_dir [glob -nocomplain [file join $export_project_dir *.srcs utils_1 imports $run_name]] { + file delete -force $imports_dir + puts "INFO: removed stale auto-incremental checkpoint imports for $run_name: $imports_dir" + } +} + +proc verify_checkpoint {label dcp} { + open_checkpoint $dcp + set cell_count [llength [get_cells -hier -quiet]] + if {$cell_count == 0} { + close_design + error "$label synthesized to an empty design" + } + set blackbox_cells [get_cells -hier -quiet -filter {IS_BLACKBOX == 1}] + set blackbox_names [list] + if {[llength $blackbox_cells] > 0} { + set blackbox_names [get_property NAME $blackbox_cells] + } + close_design + set unexpected_blackboxes [list] + foreach blackbox $blackbox_names { + if {$blackbox eq "dbg_hub"} { + puts "INFO: $label keeps Vivado debug hub blackbox $blackbox" + } else { + lappend unexpected_blackboxes $blackbox + } + } + if {[llength $unexpected_blackboxes] > 0} { + error "$label still has blackbox cells after checkpoint export: $unexpected_blackboxes" + } +} + +proc launch_run_list {run_list jobs} { + if {[llength $run_list] == 0} { + return + } + + foreach run $run_list { + reset_run $run + } + launch_runs $run_list -jobs $jobs + foreach run $run_list { + wait_on_run $run + } + + foreach run $run_list { + set status [get_property STATUS $run] + puts "INFO: $run status: $status" + if {![string match "*Complete*" $status] && ![string match "*cached IP results*" $status]} { + error "IP run $run did not complete: $status" + } + } +} + +proc create_and_launch_bd_ip_runs {bd jobs} { + catch {create_ip_run $bd} + set bd_name [file rootname [file tail $bd]] + set run_list [get_runs -quiet ${bd_name}_*_synth_1] + launch_run_list $run_list $jobs + return $run_list +} + +proc export_xci_ip {name script out_file jobs force} { + if {[llength [get_ips -quiet $name]] == 0} { + source_ip_tcl $script + } + + set ip [get_ips -quiet $name] + if {[llength $ip] == 0} { + error "IP $name was not created by $script" + } + + set ip_file [get_property IP_FILE $ip] + if {$ip_file ne ""} { + set ip_file_obj [get_files -quiet $ip_file] + if {[llength $ip_file_obj] > 0} { + set_property GENERATE_SYNTH_CHECKPOINT true $ip_file_obj + } + } + generate_target all $ip + catch {create_ip_run $ip} + run_and_copy_dcp ${name}_synth_1 $out_file $jobs $force + copy_generated_stub xci $name $out_file + verify_checkpoint "IP $name" $out_file +} + +proc export_bd_ip {name script out_file jobs force} { + if {[llength [get_files -quiet ${name}.bd]] == 0} { + source_ip_tcl $script + } + + set bd [get_files -quiet ${name}.bd] + if {[llength $bd] == 0} { + error "BD $name was not created by $script" + } + + open_bd_design $bd + current_bd_design $name + validate_bd_design + save_bd_design + generate_target all $bd + catch {make_wrapper -files $bd -top} + copy_generated_stub bd $name $out_file + + if {[file exists $out_file] && !$force} { + puts "INFO: reuse existing $out_file" + return + } + + # Build child IP OOC runs first, then synthesize the BD top as one + # checkpoint. This keeps the exported artifact as a single DCP while + # letting Vivado handle encrypted or packaged IP internals through their + # generated runs instead of compiling raw shared sources. + create_and_launch_bd_ip_runs $bd $jobs + set_property top $name [current_fileset] + update_compile_order -fileset sources_1 + run_and_write_opened_dcp synth_1 $out_file $jobs $force + verify_checkpoint "BD $name" $out_file +} + +set exports [list \ + [list xci blk_mem_gen_0 [file join $tcl_dir blk_mem_gen_0.tcl] [file join $out_dir rtl soc blk_mem_gen_0.dcp]] \ + [list bd AXI_bridge [file join $tcl_dir AXI_bridge.tcl] [file join $out_dir rtl soc AXI_bridge.dcp]] \ + [list bd data_bridge [file join $tcl_dir data_bridge.tcl] [file join $out_dir rtl soc data_bridge.dcp]] \ + [list xci vio_0 [file join $tcl_dir vio_0.tcl] [file join $out_dir rtl soc vio_0.dcp]] \ + [list bd xdma_ep [file join $tcl_dir xdma_ep.tcl] [file join $out_dir rtl device pcie xdma_ep.dcp]] \ + [list bd jtag_ddr_subsys [file join $tcl_dir jtag_ddr_subsys.tcl] [file join $out_dir rtl soc jtag_ddr_subsys.dcp]] \ +] + +set failed_exports [list] +foreach item $exports { + lassign $item kind name script out_file + if {$only ne "" && $name ne $only} { + puts "INFO: skip $name because --only $only is set" + continue + } + if {[lsearch -exact $skip_exports $name] >= 0} { + puts "INFO: skip $name because --skip requested" + continue + } + puts "INFO: exporting $kind $name" + set rc [catch { + if {$kind eq "xci"} { + export_xci_ip $name $script $out_file $jobs $force + } else { + export_bd_ip $name $script $out_file $jobs $force + } + } err opts] + if {$rc != 0} { + catch {close_design} + lappend failed_exports $name + puts "ERROR: failed to export $name" + puts "ERROR: $err" + } +} + +if {[llength $failed_exports] > 0} { + error "Vivado IP/BD DCP export failed for: $failed_exports" +} + +close_project +puts "INFO: Vivado IP export finished." diff --git a/fpga_diff/uvhs/filelist.awk b/fpga_diff/uvhs/filelist.awk new file mode 100644 index 00000000..6d7c9e2e --- /dev/null +++ b/fpga_diff/uvhs/filelist.awk @@ -0,0 +1,5 @@ +/^[[:space:]]*$/ { next } + +{ + print $0 +} diff --git a/fpga_diff/uvhs/frontend_run.tcl b/fpga_diff/uvhs/frontend_run.tcl new file mode 100644 index 00000000..9ffac1a9 --- /dev/null +++ b/fpga_diff/uvhs/frontend_run.tcl @@ -0,0 +1,238 @@ +################################################################################ +# UVHS frontend flow for fpga_diff. +################################################################################ + +proc env_or_default {name default} { + if {[info exists ::env($name)] && $::env($name) ne ""} { + return $::env($name) + } + return $default +} + +proc split_words {value} { + set out [list] + foreach item $value { + if {$item ne ""} { + lappend out $item + } + } + return $out +} + +set required_dcp_modules [split_words [env_or_default UVHS_REQUIRED_DCP_MODULES {blk_mem_gen_0 AXI_bridge data_bridge xdma_ep uvw_axi4_to_ddr4}]] + +proc dcp_module_is_required {module} { + return [expr {[lsearch -exact $::required_dcp_modules $module] >= 0}] +} + +proc source_if_exists {file} { + if {$file eq "none"} { + puts "INFO: skip $file" + return + } + if {[file exists $file]} { + puts "INFO: source $file" + if {[catch {uplevel #0 [list source $file]} err]} { + puts "WARNING: source $file failed: $err" + } + } else { + puts "INFO: skip missing $file" + } +} + +proc set_blackbox_if_exists {module dcp args} { + if {![dcp_module_is_required $module]} { + puts "INFO: skip blackbox $module because it is not listed in UVHS_REQUIRED_DCP_MODULES" + return + } + if {[file exists $dcp]} { + puts "INFO: set_blackbox $module $dcp" + set command [list set_blackbox -module $module -source_file $dcp] + if {[llength $args] > 0} { + set command [concat $command $args] + } + uplevel #0 $command + } else { + error "required blackbox DCP missing for $module: $dcp" + } +} + +proc set_ip_if_exists {module dcp stub args} { + if {![dcp_module_is_required $module]} { + puts "INFO: skip set_ip $module because it is not listed in UVHS_REQUIRED_DCP_MODULES" + return + } + if {![file exists $dcp]} { + error "required IP DCP missing for $module: $dcp" + } + if {![file exists $stub]} { + error "required IP stub missing for $module: $stub" + } + + puts "INFO: set_ip $module $dcp" + set command [list set_ip -module $module -source_file $dcp] + if {[llength $args] > 0} { + set command [concat $command $args] + } + uplevel #0 $command + set read_stub [env_or_default [string toupper UVHS_${module}_READ_STUB] 1] + if {$read_stub eq "0"} { + puts "INFO: skip read_verilog $stub because UVHS_[string toupper ${module}]_READ_STUB=0" + } else { + puts "INFO: read_verilog $stub" + uplevel #0 [list read_verilog $stub] + } +} + +proc require_file_for_uvhs_ip {description file} { + if {![file exists $file] || [file size $file] == 0} { + error "required UVHS DDR IP $description missing or empty: $file" + } + puts "INFO: found UVHS DDR IP $description: $file" +} + +proc run_or_warn {description command} { + puts "INFO: $description" + if {[catch {uplevel #0 $command} err]} { + puts "WARNING: $description failed: $err" + } +} + +proc append_line_if_missing {file line} { + if {$file eq "" || $line eq ""} { + return + } + set existing "" + if {[file exists $file]} { + set fh [open $file r] + set existing [read $fh] + close $fh + foreach entry [split $existing "\n"] { + if {[string trim $entry] eq $line} { + puts "INFO: keep existing option line in $file: $line" + return + } + } + } + set fh [open $file a] + if {$existing ne "" && ![string match *\n $existing]} { + puts $fh "" + } + puts $fh $line + close $fh + puts "INFO: appended option line to $file: $line" +} + +proc patch_option_add_rtl_inst {working_space inst_path} { + if {$inst_path eq "" || $inst_path eq "none"} { + puts "INFO: skip option.add_rtl_inst patch" + return + } + set option_dir [file join $working_space DB Options] + file mkdir $option_dir + set add_inst_line "add_rtl_inst -inst_name $inst_path" + append_line_if_missing [file join $option_dir option.add_rtl_inst.txt] $add_inst_line + append_line_if_missing [file join $option_dir option.txt] $add_inst_line +} + +# UVHS generates this Makefile after elaboration. Its stock recipe invokes +# uv_shell through /bin/sh even though the vendor script requires Bash. +proc start_uvsyn_shell_patch_watcher {} { + set module_makefile [file join [pwd] hw.dat Synthesis Uvsyn Script module.makefile] + set patch_script [file normalize [file join [file dirname [info script]] patch_uvsyn_shell.sh]] + if {![file exists $patch_script]} { + error "missing UVHS worker shell compatibility helper: $patch_script" + } + exec bash $patch_script $module_makefile & + puts "INFO: started UVHS worker shell compatibility helper" +} + +create_working_space hw.dat +set_option syn.computeFeCheckSum true + +set frontend_threads [env_or_default UVHS_FRONTEND_THREADS 16] +set frontend_processes [env_or_default UVHS_FRONTEND_PROCESSES 64] +set fpga_threads [env_or_default UVHS_FPGA_THREADS 8] +set fpga_processes [env_or_default UVHS_FPGA_PROCESSES 32] + +if {[env_or_default UVHS_USE_LSF 1]} { + set_parallel_option -max_threads $frontend_threads -max_processes $frontend_processes -submit_command bsub -terminate_command bkill -label frontend + set_parallel_option -max_threads $fpga_threads -max_processes $fpga_processes -submit_command {bsub -R "rusage[mem=80000]"} -terminate_command bkill -label fpga +} else { + set_parallel_option -max_threads $frontend_threads -max_processes $frontend_processes -label frontend + set_parallel_option -max_threads $fpga_threads -max_processes $fpga_processes -label fpga +} + +set_option global.log.label MEMORY +set_option syn.checkMultiDriver false +set_option syn.multipleDriverConflict WOR +set_option time.auto_clock_config true +set_option clock.transform_clock.multi_iteration true +set_option clock.glitch.force_transform true +set_option clock.async_control.force_accept true +set_option time.enable_sign_off true +set_option time.incremental_sign_off true +set_option signal.uhd.sampling_clock.allow_local_clock true +set_option syn.logicFillingRateThreshold 0.001 + +set design_name [env_or_default UVHS_DESIGN_NAME VU19P_X4] +set platform [env_or_default PLATFORM U2.2] +set design_top [env_or_default UVHS_TOP fpga_top_debug] +set ddr_inst_path [env_or_default UVHS_DDR_RTL_INST ${design_top}.core_def.U_JTAG_DDR_SUBSYS] +set reset_ports [split_words [env_or_default UVHS_RESET_PORTS {rstn_sw6 rstn_sw5 rstn_sw4}]] +create_system_design -name $design_name -platform $platform + +set assemble_file [env_or_default UVHS_ASSEMBLE_FILE ./script/1B_4F_HGC_assemble.tcl] +if {$assemble_file eq "none"} { + puts "INFO: skip board assembly" +} else { + source_if_exists $assemble_file +} +set skip_board_constraints [env_or_default UVHS_SKIP_BOARD_CONSTRAINTS 0] + +if {$skip_board_constraints} { + puts "INFO: skip board probe/pin/timing/partition constraints" +} else { + source_if_exists [env_or_default UVHS_PROBE_FILE ./script/probe.tcl] + source_if_exists [env_or_default UVHS_ASSIGN_PIN_FILE ./script/assign_pin.tcl] + set timing_file [env_or_default UVHS_TIMING_FILE none] + if {$timing_file eq "none"} { + puts "INFO: skip timing constraints" + } else { + run_or_warn "set_constraint_files" [list set_constraint_files $timing_file] + } + set partition_file [env_or_default UVHS_PARTITION_FILE ./script/partition.tcl] + if {$partition_file eq "none"} { + puts "INFO: skip partition constraints" + } else { + run_or_warn "set_partition_constraint_file" [list set_partition_constraint_file $partition_file] + } + foreach reset_port $reset_ports { + set reset_net ${design_top}.${reset_port} + run_or_warn "create_reset $reset_net" [list create_reset -port $reset_net -active 0] + } +} + +set_blackbox_if_exists blk_mem_gen_0 ./rtl/soc/blk_mem_gen_0.dcp +set_blackbox_if_exists AXI_bridge ./rtl/soc/AXI_bridge.dcp +set_blackbox_if_exists data_bridge ./rtl/soc/data_bridge.dcp +set_blackbox_if_exists xdma_ep ./rtl/device/pcie/xdma_ep.dcp +require_file_for_uvhs_ip DCP ./rtl/soc/uvw_axi4_to_ddr4.dcp +require_file_for_uvhs_ip stub ./rtl/soc/uvw_axi4_to_ddr4_Stub.v +require_file_for_uvhs_ip pblock ./script/uvw_axi4_to_ddr4_pblock.tcl +set_ip_if_exists uvw_axi4_to_ddr4 ./rtl/soc/uvw_axi4_to_ddr4.dcp \ + ./rtl/soc/uvw_axi4_to_ddr4_Stub.v \ + -clock_enable_pairs {ddr4ip_dut_axi_aclk ddr4ip_dut_axi_aclk_en 1} \ + -script_file {prePlace ./script/uvw_axi4_to_ddr4_pblock.tcl} + +set filelist [env_or_default UVHS_FILELIST ./rtl/filelist.f] +puts "INFO: read_verilog -f $filelist" +read_verilog -f $filelist -mfcu + +puts "INFO: elaborate_design $design_top" +elaborate_design $design_top +start_uvsyn_shell_patch_watcher +synthesize_design -parallel_option frontend +save_working_space +patch_option_add_rtl_inst hw.dat $ddr_inst_path +exit diff --git a/fpga_diff/uvhs/make_compat/csh b/fpga_diff/uvhs/make_compat/csh new file mode 100755 index 00000000..cbbc567c --- /dev/null +++ b/fpga_diff/uvhs/make_compat/csh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -ge 2 && ( "$1" == "-fc" || "$1" == "-c" ) && "$2" == "limit" ]]; then + ulimit -a + exit 0 +fi + +exec /bin/bash "$@" diff --git a/fpga_diff/uvhs/make_compat/make b/fpga_diff/uvhs/make_compat/make new file mode 100755 index 00000000..2e930fbd --- /dev/null +++ b/fpga_diff/uvhs/make_compat/make @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec /usr/bin/make SHELL=/bin/bash "$@" diff --git a/fpga_diff/uvhs/patch_uvsyn_shell.sh b/fpga_diff/uvhs/patch_uvsyn_shell.sh new file mode 100755 index 00000000..97069cb5 --- /dev/null +++ b/fpga_diff/uvhs/patch_uvsyn_shell.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail + +module_makefile=${1:?usage: $0 /path/to/module.makefile} + +for _ in $(seq 1 12000); do + if [[ -f "$module_makefile" ]]; then + if grep -Eq 'bash[[:space:]]+([^[:space:]]*/)?uv_shell[[:space:]]' "$module_makefile"; then + printf 'INFO: UVHS module worker already invokes uv_shell through bash: %s\n' "$module_makefile" + exit 0 + fi + sed -E -i \ + -e 's/until[[:space:]]+sh[[:space:]]+-c/until bash -c/' \ + -e 's#(^|[[:space:]])(/[^[:space:]]*/bin/uv_shell)([[:space:]])#\1bash \2\3#g' \ + -e 's#(^|[[:space:]])(uv_shell)([[:space:]])#\1bash \2\3#g' \ + "$module_makefile" + if grep -Eq 'bash[[:space:]]+([^[:space:]]*/)?uv_shell[[:space:]]' "$module_makefile"; then + printf 'INFO: patched UVHS module worker uv_shell invocation: %s\n' "$module_makefile" + exit 0 + fi + echo "ERROR: module.makefile appeared but uv_shell invocation was not patched: $module_makefile" >&2 + exit 1 + fi + sleep 0.05 +done + +echo "ERROR: timed out waiting for UVHS module makefile: $module_makefile" >&2 +exit 1 diff --git a/fpga_diff/uvhs/timing_common.tcl b/fpga_diff/uvhs/timing_common.tcl new file mode 100644 index 00000000..f52e65b2 --- /dev/null +++ b/fpga_diff/uvhs/timing_common.tcl @@ -0,0 +1,32 @@ +################################################################################ +# Shared UVHS timing constraints for fpga_diff. +# UVHS records constraints before RTL elaboration, so protected ports need the +# elaborated top-level scope. +################################################################################ + +set fpga_diff_top fpga_top_debug +if {[info exists ::env(UVHS_TOP)] && $::env(UVHS_TOP) ne ""} { + set fpga_diff_top $::env(UVHS_TOP) +} +proc fpga_diff_top_port {name} { + return "${::fpga_diff_top}.${name}" +} + +create_clock -name TMCLK -period 1000 [get_ports [fpga_diff_top_port clk8_p]] +create_clock -name ddr_ref_clk -period 12.5 [get_ports [fpga_diff_top_port clk7_p]] +set fpga_diff_cpu_clk_period_ns 40 +if {[info exists ::env(UVHS_CPU_CLK_PERIOD_NS)] && $::env(UVHS_CPU_CLK_PERIOD_NS) ne ""} { + set fpga_diff_cpu_clk_period_ns $::env(UVHS_CPU_CLK_PERIOD_NS) +} +set fpga_diff_cpu_debug_clk 1 +if {[info exists ::env(UVHS_CPU_DEBUG_CLK)] && $::env(UVHS_CPU_DEBUG_CLK) ne ""} { + set fpga_diff_cpu_debug_clk [expr {$::env(UVHS_CPU_DEBUG_CLK) eq "1"}] +} +if {$fpga_diff_cpu_debug_clk} { + create_clock -name CPU_CLK_IN -period $fpga_diff_cpu_clk_period_ns [get_ports [fpga_diff_top_port clk5_p]] +} else { + create_clock -name CPU_CLK_IN -period $fpga_diff_cpu_clk_period_ns [get_ports [fpga_diff_top_port clk6_p]] + create_clock -name DEBUG_CLK_IN -period 40 [get_ports [fpga_diff_top_port clk5_p]] +} +create_clock -name jtag_vclk -period 83.333 [get_ports [fpga_diff_top_port JTAG_TCK]] +create_clock -name pcie_ep_refclk -period 10 [get_ports [fpga_diff_top_port pcie_ep_gt_ref_clk_p]] diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk new file mode 100644 index 00000000..4db35e00 --- /dev/null +++ b/fpga_diff/uvhs/uvhs.mk @@ -0,0 +1,224 @@ +UVHS_ROOT_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))/..) + +PLATFORM ?= U2.2 +UVHS_TEMPLATE_DIR ?= +UVHS_UVW_AXI4_TO_DDR4_SRC ?= +UVHS_UVW_AXI4_TO_DDR4_EXPECTED_MD5 ?= +UVHS_WORK_DIR ?= $(ENV_SCRIPTS_HOME)/fpga_diff_uvhs_$(CPU)$(if $(strip $(SUFFIX)),-$(strip $(SUFFIX)),) +UVHS_TOP ?= fpga_top_debug +UVHS_FILELIST ?= $(UVHS_WORK_DIR)/rtl/filelist.f + +UVHS_EXPORT_IP_FORCE ?= 0 +UVHS_EXPORT_IP_JOBS ?= 8 +UVHS_EXPORT_IP_VIVADO_VERSION ?= +UVHS_EXPORT_IP_ONLY ?= +UVHS_SKIP_VIVADO_EXPORT ?= vio_0 jtag_ddr_subsys + +UVHS_DESIGN_NAME ?= VU19P_X4 +UVHS_TARGET_PACK ?= B0 +UVHS_TARGET_FPGA ?= F2 +UVHS_TARGET_FPGA_LOWER ?= b0.f2 +UVHS_KEEP_FPGAS ?= $(UVHS_TARGET_FPGA_LOWER) +UVHS_ASSIGN_PIN_FILE ?= $(UVHS_ROOT_DIR)/uvhs/assign_pin_u22_f2.tcl +UVHS_TIMING_FILE ?= $(UVHS_ROOT_DIR)/uvhs/timing_common.tcl +UVHS_ASSEMBLE_FILE ?= $(UVHS_ROOT_DIR)/uvhs/assemble_uvhs.tcl +UVHS_CPU_CLK_PERIOD_NS ?= 40 +UVHS_CPU_DEBUG_CLK ?= 1 +UVHS_USE_LSF ?= 0 +UVHS_FRONTEND_THREADS ?= 4 +UVHS_FRONTEND_PROCESSES ?= 16 +UVHS_FPGA_THREADS ?= 4 +UVHS_FPGA_PROCESSES ?= 8 +UVHS_PNR_STRATEGY ?= Strategy_uv_high_fanout_explore +UVHS_COMPILE_STRATEGY_NUM ?= 1 +UVHS_COMPILE_STRATEGY0 ?= uv_high_fanout_explore + +XDMA_LINK_WIDTH ?= X4 +XDMA_ENABLE_PF0_BAR1 ?= 1 +XDMA_AXILITE_MASTER_SCALE ?= Kilobytes +XDMA_AXILITE_MASTER_SIZE ?= 512 + +UVHS_UVW_AXI4_TO_DDR4_FILES := \ + rtl/soc/uvw_axi4_to_ddr4.dcp \ + rtl/soc/uvw_axi4_to_ddr4_Stub.v \ + script/uvw_axi4_to_ddr4_pblock.tcl \ + script/custom_parts_ddr4_KSM26SES8_2666.csv +UVHS_UVW_AXI4_TO_DDR4_REQUIRED_FILES := \ + rtl/soc/uvw_axi4_to_ddr4.dcp \ + rtl/soc/uvw_axi4_to_ddr4_Stub.v \ + script/uvw_axi4_to_ddr4_pblock.tcl +UVHS_REQUIRED_DCP_MODULES := blk_mem_gen_0 AXI_bridge data_bridge xdma_ep uvw_axi4_to_ddr4 +UVHS_REQUIRED_MODULES ?= $(if $(filter nanhu,$(CPU)),XlnFpgaTop,$(if $(filter kmh nutshell,$(CPU)),SimTop,)) +UVHS_DDR_RTL_INST := $(UVHS_TOP).core_def.U_UVHS_UVW_AXI4_TO_DDR4 +UVHS_RUNTIME_LIB_DIR ?= $(UVHS_WORK_DIR)/.uvhs-runtime-lib + +UVHS_FLOW_ENV = \ + PATH="$(UVHS_ROOT_DIR)/uvhs/make_compat:$$UV_ROOT/bin:$$UV_ROOT/lib/venv3.8/bin:$$UV_ROOT/lib/gcc10.3/bin:$$PATH" \ + LD_LIBRARY_PATH="$(UVHS_RUNTIME_LIB_DIR):$${LD_LIBRARY_PATH:-}" \ + UVHS_FLOW=1 \ + PLATFORM="$(PLATFORM)" \ + XDMA_LINK_WIDTH="$(XDMA_LINK_WIDTH)" \ + XDMA_ENABLE_PF0_BAR1="$(XDMA_ENABLE_PF0_BAR1)" \ + XDMA_AXILITE_MASTER_SCALE="$(XDMA_AXILITE_MASTER_SCALE)" \ + XDMA_AXILITE_MASTER_SIZE="$(XDMA_AXILITE_MASTER_SIZE)" \ + UVHS_DESIGN_NAME="$(UVHS_DESIGN_NAME)" \ + UVHS_TARGET_PACK="$(UVHS_TARGET_PACK)" \ + UVHS_TARGET_FPGA="$(UVHS_TARGET_FPGA)" \ + UVHS_TARGET_FPGA_LOWER="$(UVHS_TARGET_FPGA_LOWER)" \ + UVHS_KEEP_FPGAS="$(UVHS_KEEP_FPGAS)" \ + UVHS_CPU_CLK_PERIOD_NS="$(UVHS_CPU_CLK_PERIOD_NS)" \ + UVHS_CPU_DEBUG_CLK="$(UVHS_CPU_DEBUG_CLK)" \ + UVHS_PNR_STRATEGY="$(UVHS_PNR_STRATEGY)" \ + UVHS_COMPILE_STRATEGY_NUM="$(UVHS_COMPILE_STRATEGY_NUM)" \ + UVHS_COMPILE_STRATEGY0="$(UVHS_COMPILE_STRATEGY0)" + +UVHS_PNR_DIR ?= $(UVHS_WORK_DIR)/hw.dat/Compile/PnR/$(UVHS_TARGET_PACK)/$(UVHS_TARGET_FPGA)/vivado/Rundir/$(UVHS_PNR_STRATEGY) +UVHS_BITSTREAM_DIR ?= $(UVHS_PNR_DIR)/bitstream +UVHS_BIT_HOME ?= $(UVHS_WORK_DIR)/ready-to-program + +.PHONY: uvhs_preflight uvhs_prepare uvhs_export_vivado_ip \ + uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist uvhs_check_modules \ + uvhs_frontend uvhs_backend uvhs_all uvhs_check_timing \ + uvhs_package_bitstream uvhs_tools_check uvhs_clean + +uvhs_preflight: + test -n "$$UV_ROOT" + test -x "$$UV_ROOT/bin/uv_shell" + test -n "$$UV_XILINX_VIVADO" + test -x "$$UV_XILINX_VIVADO/bin/vivado" + test -n "$$UV_LICENSE" + test -d "$(UVHS_TEMPLATE_DIR)/script" + test -f "$(UVHS_TEMPLATE_DIR)/Makefile" + test -f "$(UVHS_TEMPLATE_DIR)/script/1B_4F_HGC_assemble.tcl" + test -d "$(UVHS_UVW_AXI4_TO_DDR4_SRC)" + mkdir -p "$(UVHS_RUNTIME_LIB_DIR)" + bash -c 'set -euo pipefail; \ + ffi="$$(ldconfig -p | awk '\''/libffi[.]so[.]6 / { print $$NF; exit } /libffi[.]so[.]8 / { fallback = $$NF } END { if (fallback != "") print fallback }'\'')"; \ + test -n "$$ffi"; \ + ln -sfn "$$ffi" "$(UVHS_RUNTIME_LIB_DIR)/libffi.so.6"' + +uvhs_tools_check: + bash "$(UVHS_ROOT_DIR)/uvhs/check_flow_tools.sh" + +uvhs_prepare: uvhs_preflight + test -n "$(UVHS_WORK_DIR)" + rm -rf "$(UVHS_WORK_DIR)/script" + mkdir -p "$(UVHS_WORK_DIR)" + cp -a "$(UVHS_TEMPLATE_DIR)/script" "$(UVHS_WORK_DIR)/" + cp -f "$(UVHS_TEMPLATE_DIR)/Makefile" "$(UVHS_WORK_DIR)/Makefile" + mkdir -p "$(UVHS_WORK_DIR)/rtl/soc" "$(UVHS_WORK_DIR)/rtl/device/pcie" + +uvhs_export_vivado_ip: uvhs_prepare + bash -c 'set -euo pipefail; \ + export VIVADO_HOME="$$UV_XILINX_VIVADO" XILINX_VIVADO="$$UV_XILINX_VIVADO"; \ + version="$(UVHS_EXPORT_IP_VIVADO_VERSION)"; \ + if [ -z "$$version" ]; then version="$$("$$UV_XILINX_VIVADO/bin/vivado" -version | sed -n "s/^Vivado v\\([^ ]*\\).*/\\1/p" | head -n 1)"; fi; \ + $(UVHS_FLOW_ENV) "$$UV_XILINX_VIVADO/bin/vivado" -mode batch \ + -source "$(UVHS_ROOT_DIR)/uvhs/export_vivado_ip.tcl" -tclargs \ + --origin_dir "$(UVHS_ROOT_DIR)" --out_dir "$(UVHS_WORK_DIR)" \ + --vivado_version "$$version" --cpu "$(CPU)" --core_dir "$(CORE_DIR)" \ + --jobs "$(UVHS_EXPORT_IP_JOBS)" \ + $(if $(strip $(UVHS_EXPORT_IP_ONLY)),--only "$(UVHS_EXPORT_IP_ONLY)",) \ + $(foreach ip,$(UVHS_SKIP_VIVADO_EXPORT),--skip "$(ip)") \ + $(if $(filter 1,$(UVHS_EXPORT_IP_FORCE)),--force,)' + +uvhs_sync_uvw_axi4_to_ddr4: uvhs_prepare + bash -c 'set -euo pipefail; \ + src="$(UVHS_UVW_AXI4_TO_DDR4_SRC)"; work="$(UVHS_WORK_DIR)"; \ + for rel in $(UVHS_UVW_AXI4_TO_DDR4_FILES); do \ + base="$${rel##*/}"; dst="$$work/$$rel"; found=""; \ + for candidate in "$$src/$$rel" "$$src/$$base"; do \ + if [ -f "$$candidate" ]; then found="$$candidate"; break; fi; \ + done; \ + if [ -z "$$found" ]; then found="$$(find "$$src" -type f -name "$$base" -size +0c -print -quit)"; fi; \ + if [ -n "$$found" ]; then mkdir -p "$$(dirname "$$dst")"; cp -f "$$found" "$$dst"; fi; \ + done; \ + for rel in $(UVHS_UVW_AXI4_TO_DDR4_REQUIRED_FILES); do test -s "$$work/$$rel"; done; \ + if [ -n "$(UVHS_UVW_AXI4_TO_DDR4_EXPECTED_MD5)" ]; then \ + echo "$(UVHS_UVW_AXI4_TO_DDR4_EXPECTED_MD5) $$work/rtl/soc/uvw_axi4_to_ddr4.dcp" | md5sum -c -; \ + fi' + +uvhs_filelist: + mkdir -p "$(dir $(UVHS_FILELIST))" + { \ + printf '+define+SYNTHESIS\n+define+XIANGSHAN_FPGA\n'; \ + printf '+define+RANDOMIZE_GARBAGE_ASSIGN\n+define+RANDOMIZE_REG_INIT\n'; \ + printf '+define+RANDOMIZE_MEM_INIT\n+define+RANDOMIZE_DELAY=1\n'; \ + printf '+define+UVHS_SOC_ADAPT\n+define+UVHS_UVW_AXI4_TO_DDR4\n'; \ + printf '+define+DDR4_16G_X8\n+define+DQ64\n+define+DDR4_2400\n'; \ + printf '+define+DQ=64\n+define+MICRON_DDR\n+define+DDR4_16Gbx8\n'; \ + printf '+define+DDR4\n+define+SRAM_SYN\n+define+DATA_VERSION=0\n'; \ + if [ "$(CPU)" = nutshell ]; then printf '+define+CPU_NUTSHELL\n'; fi; \ + if [ "$(UVHS_CPU_DEBUG_CLK)" = 1 ]; then printf '+define+UVHS_CPU_DEBUG_CLK\n'; fi; \ + if [ -n "$(CHI_DIR)" ]; then printf '+define+MSI_MODE\n+define+CONFIG_USE_XSCORE_CHI\n'; \ + else printf '+define+CONFIG_USE_XSCORE_AXI\n'; fi; \ + if [ -d "$(CORE_DIR)/build" ]; then printf '+incdir+%s/build\n' "$(CORE_DIR)"; fi; \ + if [ -d "$(CORE_DIR)/build/rtl" ]; then printf '+incdir+%s/build/rtl\n' "$(CORE_DIR)"; fi; \ + if [ -d "$(CORE_DIR)/build/generated-src" ]; then printf '+incdir+%s/build/generated-src\n' "$(CORE_DIR)"; fi; \ + printf '+incdir+%s/src/rtl/common\n' "$(UVHS_ROOT_DIR)"; \ + find "$(UVHS_ROOT_DIR)/src/rtl/common" -type f \ + \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ + ! -name 'u0_xdma.v' -print | sort; \ + test ! -d "$(UVHS_WORK_DIR)/rtl/stubs" || \ + find "$(UVHS_WORK_DIR)/rtl/stubs" -type f -name '*.v' -print | sort; \ + test ! -d "$(UVHS_ROOT_DIR)/src/rtl/$(CPU)" || \ + find "$(UVHS_ROOT_DIR)/src/rtl/$(CPU)" -type f \ + \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ + if [ -d "$(CORE_DIR)/build/rtl" ]; then \ + find "$(CORE_DIR)/build/rtl" -type f \ + \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ + elif [ -n "$(CORE_DIR)" ] && [ -d "$(CORE_DIR)" ]; then \ + find "$(CORE_DIR)" \( -path '*/rtl/verification' -o -path '*/out' \) -prune -o \ + -type f \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ + fi; \ + test ! -f "$(CORE_DIR)/difftest/src/test/vsrc/common/DifftestClockGate.v" || \ + printf '%s\n' "$(CORE_DIR)/difftest/src/test/vsrc/common/DifftestClockGate.v"; \ + if [ -n "$(CHI_DIR)" ] && [ -d "$(CHI_DIR)" ]; then \ + find "$(CHI_DIR)" -type f \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ + fi; \ + for item in $(RTL_INCLUDE); do \ + if [ -d "$$item" ]; then find "$$item" -type f \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ + elif [ -f "$$item" ]; then case "$$item" in *.f|*.flist|*.list) cat "$$item";; *) printf '%s\n' "$$item";; esac; fi; \ + done; \ + } | awk -f "$(UVHS_ROOT_DIR)/uvhs/filelist.awk" > "$(UVHS_FILELIST)" + +uvhs_check_modules: uvhs_filelist + bash "$(UVHS_ROOT_DIR)/uvhs/check_modules.sh" "$(UVHS_FILELIST)" "$(UVHS_REQUIRED_MODULES)" + +uvhs_frontend: uvhs_export_vivado_ip uvhs_sync_uvw_axi4_to_ddr4 uvhs_check_modules + bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ + $(UVHS_FLOW_ENV) UVHS_TOP="$(UVHS_TOP)" UVHS_FILELIST=./rtl/filelist.f \ + UVHS_REQUIRED_DCP_MODULES="$(UVHS_REQUIRED_DCP_MODULES)" \ + UVHS_DDR_RTL_INST="$(UVHS_DDR_RTL_INST)" UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP=1 \ + UVHS_ASSIGN_PIN_FILE="$(UVHS_ASSIGN_PIN_FILE)" UVHS_TIMING_FILE="$(UVHS_TIMING_FILE)" \ + UVHS_PARTITION_FILE=none UVHS_PROBE_FILE=none UVHS_ASSEMBLE_FILE="$(UVHS_ASSEMBLE_FILE)" \ + UVHS_MEM_ARRAY_DC=none UVHS_AUX_DDR_DC=none UVHS_USE_LSF="$(UVHS_USE_LSF)" \ + UVHS_FRONTEND_THREADS="$(UVHS_FRONTEND_THREADS)" UVHS_FRONTEND_PROCESSES="$(UVHS_FRONTEND_PROCESSES)" \ + UVHS_FPGA_THREADS="$(UVHS_FPGA_THREADS)" UVHS_FPGA_PROCESSES="$(UVHS_FPGA_PROCESSES)" \ + bash "$$UV_ROOT/bin/uv_shell" -bypass_vivado_version_check \ + -s "$(UVHS_ROOT_DIR)/uvhs/frontend_run.tcl" |& tee frontend_run.log' + +uvhs_backend: + bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ + $(UVHS_FLOW_ENV) UVHS_TOP="$(UVHS_TOP)" UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP=1 \ + UVHS_ASSIGN_PIN_FILE="$(UVHS_ASSIGN_PIN_FILE)" UVHS_ASSEMBLE_FILE="$(UVHS_ASSEMBLE_FILE)" \ + UVHS_MEM_ARRAY_DC=none UVHS_AUX_DDR_DC=none UVHS_USE_LSF="$(UVHS_USE_LSF)" \ + UVHS_FPGA_THREADS="$(UVHS_FPGA_THREADS)" UVHS_FPGA_PROCESSES="$(UVHS_FPGA_PROCESSES)" \ + bash "$$UV_ROOT/bin/uv_shell" -bypass_vivado_version_check \ + -s "$(UVHS_ROOT_DIR)/uvhs/backend_run.tcl" |& tee backend_run.log' + +uvhs_all: uvhs_frontend uvhs_backend + +uvhs_check_timing: + test -f "$(UVHS_BITSTREAM_DIR)/after_xtalk_fix_timing_summary.txt" + ! grep -q 'Timing constraints are not met' "$(UVHS_BITSTREAM_DIR)/after_xtalk_fix_timing_summary.txt" + +uvhs_package_bitstream: uvhs_check_timing + test -f "$(UVHS_BITSTREAM_DIR)/pnr.bit" + mkdir -p "$(UVHS_BIT_HOME)" + ln -sf "$(UVHS_BITSTREAM_DIR)/pnr.bit" "$(UVHS_BIT_HOME)/fpga_top_debug.bit" + @echo "FPGA_BIT_HOME=$(UVHS_BIT_HOME)" + +uvhs_clean: + test -n "$(UVHS_WORK_DIR)" + rm -rf "$(UVHS_WORK_DIR)" From ef6619c6567869fe4e0cbead3f684b35d2b62eef Mon Sep 17 00:00:00 2001 From: klin02 Date: Wed, 29 Jul 2026 12:31:24 +0800 Subject: [PATCH 02/62] fix(fpga_diff): synchronize interconnect reset Synchronize the CPU reset into the interconnect clock domain before driving the AXI bridge reset input. Co-authored-by: Kamimiao --- fpga_diff/src/rtl/common/core_def_xdma.sv | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fpga_diff/src/rtl/common/core_def_xdma.sv b/fpga_diff/src/rtl/common/core_def_xdma.sv index ab5338a3..04aa2663 100755 --- a/fpga_diff/src/rtl/common/core_def_xdma.sv +++ b/fpga_diff/src/rtl/common/core_def_xdma.sv @@ -1159,6 +1159,7 @@ wire [0:0] br2cfg_wvalid; wire difftest_from_host_axis_tlast; wire difftest_clock_enable; wire inter_soc_clk; + wire inter_soc_sync_rstn; wire inter_rtc_clk; wire io_host_reset; @@ -1268,6 +1269,16 @@ wire [0:0] br2cfg_wvalid; .Q (inter_soc_clk) ); + RST_SYNC #( + .SYNC_STAGES(3), + .PIPELINE_STAGES(1), + .INIT(1'b0) + ) inter_soc_rstn_sync ( + .clk (inter_soc_clk), + .async_in (cpu_rstn_io), + .sync_out (inter_soc_sync_rstn) + ); + DifftestClockGate RTC_CLK_CTRL( .CK (tmclk), .E (difftest_clock_enable || ~io_host_diff_enable || ~sys_rstn_io || ~cpu_rstn_io ), From 7019f7c252048f9cdd9980d30341a8bb93929a00 Mon Sep 17 00:00:00 2001 From: klin02 Date: Wed, 29 Jul 2026 12:50:47 +0800 Subject: [PATCH 03/62] feat(fpga_diff): support XiangShan in UVHS flow Align the kmh wrapper with current XiangShan AXI widths and isolate unused SystemJTAG and RTC crossings in the UVHS image. Detect DMA-capable SimTop builds and apply XiangShan-specific placement, routing, and generated-clock settings. Co-authored-by: Kamimiao --- fpga_diff/src/rtl/kmh/SimTop_wrapper.sv | 31 ++++++++++---- fpga_diff/uvhs/README.md | 13 ++++++ fpga_diff/uvhs/backend_run.tcl | 54 +++++++++++++++++++++++-- fpga_diff/uvhs/uvhs.mk | 19 ++++++++- 4 files changed, 106 insertions(+), 11 deletions(-) diff --git a/fpga_diff/src/rtl/kmh/SimTop_wrapper.sv b/fpga_diff/src/rtl/kmh/SimTop_wrapper.sv index 8e7c5f93..aced6cf2 100755 --- a/fpga_diff/src/rtl/kmh/SimTop_wrapper.sv +++ b/fpga_diff/src/rtl/kmh/SimTop_wrapper.sv @@ -250,6 +250,11 @@ wire [149:0] trace_iaddr; wire [11:0] trace_itype; wire [20:0] trace_iretire; wire [2:0] trace_ilastsize; +wire [47:0] difftest_mem_awaddr_int; +wire [47:0] difftest_mem_araddr_int; + +assign mem_core_awaddr = difftest_mem_awaddr_int[35:0]; +assign mem_core_araddr = difftest_mem_araddr_int[35:0]; `ifndef CONFIG_SIMTOP_HAS_DMA assign dma_core_awready = 1'b0; @@ -275,7 +280,7 @@ SimTop u_XSTop( .peripheral_awready (peri_awready ), .peripheral_awvalid (peri_awvalid ), .peripheral_awid (peri_awid ), - .peripheral_awaddr ({16'd0, peri_awaddr}), + .peripheral_awaddr (peri_awaddr ), .peripheral_awlen (peri_awlen ), .peripheral_awsize (peri_awsize ), .peripheral_awburst (peri_awburst ), @@ -295,7 +300,7 @@ SimTop u_XSTop( .peripheral_arready (peri_arready ), .peripheral_arvalid (peri_arvalid ), .peripheral_arid (peri_arid ), - .peripheral_araddr ({16'd0, peri_araddr}), + .peripheral_araddr (peri_araddr ), .peripheral_arlen (peri_arlen ), .peripheral_arsize (peri_arsize ), .peripheral_arburst (peri_arburst ), @@ -313,7 +318,7 @@ SimTop u_XSTop( .dma_awready (dma_core_awready ), .dma_awvalid (dma_core_awvalid ), .dma_awid (dma_core_awid ), - .dma_awaddr (dma_core_awaddr[35:0] ), + .dma_awaddr ({12'b0, dma_core_awaddr}), .dma_awlen (dma_core_awlen ), .dma_awsize (dma_core_awsize ), .dma_awburst (dma_core_awburst ), @@ -333,7 +338,7 @@ SimTop u_XSTop( .dma_arready (dma_core_arready ), .dma_arvalid (dma_core_arvalid ), .dma_arid (dma_core_arid ), - .dma_araddr (dma_core_araddr[35:0] ), + .dma_araddr ({12'b0, dma_core_araddr}), .dma_arlen (dma_core_arlen ), .dma_arsize (dma_core_arsize ), .dma_arburst (dma_core_arburst ), @@ -348,9 +353,16 @@ SimTop u_XSTop( .dma_rresp (dma_core_rresp ), .dma_rlast (dma_core_rlast ), `endif +`ifdef UVHS_SOC_ADAPT + // UVHS does not expose XiangShan's SystemJTAG pins. + .io_systemjtag_jtag_TCK (1'b0), + .io_systemjtag_jtag_TMS (1'b1), + .io_systemjtag_jtag_TDI (1'b0), +`else .io_systemjtag_jtag_TCK (io_systemjtag_jtag_TCK), .io_systemjtag_jtag_TMS (io_systemjtag_jtag_TMS), .io_systemjtag_jtag_TDI (io_systemjtag_jtag_TDI), +`endif .io_systemjtag_jtag_TDO_data (io_systemjtag_jtag_TDO_data), .io_systemjtag_jtag_TDO_driven (io_systemjtag_jtag_TDO_driven), .io_systemjtag_reset (io_systemjtag_reset), @@ -369,8 +381,13 @@ SimTop u_XSTop( .io_pll0_ctrl_4 (io_pll0_ctrl_4), .io_pll0_ctrl_5 (io_pll0_ctrl_5), .io_extIntrs (io_extIntrs ), +`ifdef UVHS_SOC_ADAPT + // Keep SYSCNT in the SoC domain and avoid the FPGA-only TimeAsync CDC. + .io_rtc_clock (inter_soc_clk), +`else .io_rtc_clock (tmclk), - .io_riscv_rst_vec_0 (38'h10000000), +`endif + .io_riscv_rst_vec_0 (48'h0000_1000_0000), //difftest @@ -413,7 +430,7 @@ SimTop u_XSTop( .difftest_mem_awvalid (mem_core_awvalid ), .difftest_mem_awid (mem_core_awid ), .difftest_mem_awuser (), - .difftest_mem_awaddr ({12'd0, mem_core_awaddr}), + .difftest_mem_awaddr (difftest_mem_awaddr_int), .difftest_mem_awlen (mem_core_awlen ), .difftest_mem_awsize (mem_core_awsize ), .difftest_mem_awburst (mem_core_awburst ), @@ -435,7 +452,7 @@ SimTop u_XSTop( .difftest_mem_arvalid (mem_core_arvalid ), .difftest_mem_arid (mem_core_arid ), .difftest_mem_aruser (), - .difftest_mem_araddr ({12'd0, mem_core_araddr}), + .difftest_mem_araddr (difftest_mem_araddr_int), .difftest_mem_arlen (mem_core_arlen ), .difftest_mem_arsize (mem_core_arsize ), .difftest_mem_arburst (mem_core_arburst ), diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 0f49e6cd..bc6f122a 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -47,6 +47,19 @@ source-generated Vivado DCPs; the default reuses an existing DCP in the chosen work directory. `uvhs_clean` removes only the explicitly selected `UVHS_WORK_DIR`. +### XiangShan + +Use the same entry points with `CPU=kmh` and an AXI-based XiangShan RTL tree: + +```sh +make UVHS=1 uvhs_all CPU=kmh CORE_DIR=/path/to/XiangShan SUFFIX= +``` + +The file-list step detects whether `SimTop` exposes DMA and enables the H2C +path accordingly. XiangShan keeps the B0/F2, x4, and 25 MHz defaults, while +using 80% LUT and 30% LUT6 fill limits and disabling the hold-expansion route +bailout. Each value remains independently overrideable on the command line. + ## Runtime Use `user_script/hw_run_download.tcl` with the completed `hw.dat` database. diff --git a/fpga_diff/uvhs/backend_run.tcl b/fpga_diff/uvhs/backend_run.tcl index 0bcab22c..bfb8d9ec 100644 --- a/fpga_diff/uvhs/backend_run.tcl +++ b/fpga_diff/uvhs/backend_run.tcl @@ -40,6 +40,30 @@ proc uvhs_config_probe_group_resource {} { [list config_hw -set_resource $probe_group_resource -type Probe-Group] } +proc uvhs_config_fill_rates {} { + set lut_fill_rate [env_or_default UVHS_LUT_FILL_RATE none] + set lut6_fill_rate [env_or_default UVHS_LUT6_FILL_RATE none] + set args {} + + foreach {option value} [list -lut $lut_fill_rate -lut6 $lut6_fill_rate] { + if {$value eq "none" || $value eq ""} { + continue + } + if {![string is double -strict $value] || $value <= 0 || $value > 100} { + error "$option fill rate must be in (0, 100], got '$value'" + } + lappend args $option $value + } + + if {![llength $args]} { + puts "INFO: keep platform default LUT fill rates" + return + } + + puts "INFO: set UVHS fill rates: $args" + set_fill_rate {*}$args +} + proc uvhs_cpu_clk_period_ns {} { return [env_or_default UVHS_CPU_CLK_PERIOD_NS 40] } @@ -347,6 +371,21 @@ proc ::uvhs_patch_xdma_preopt_xdc {uvhs_xdc_file} { if {[string match *pnr_timing_constraints_preopt.xdc $uvhs_xdc_file] || \ [string match *pnr_timing_constraints.xdc $uvhs_xdc_file]} { + # localize_design can serialize a replicated high-fanout clock as an + # unrelated primary clock. Restore its original CPU_CLK_IN relation. + set uvhs_lines {} + foreach uvhs_line [split $uvhs_patched "\n"] { + if {[string first {-name SOC_GATED_CLK} $uvhs_line] >= 0 && \ + [regexp {^create_clock[^\n]*\[get_pins[[:space:]]+([^]]+)/O\]} \ + $uvhs_line -> uvhs_soc_bufg]} { + set uvhs_line [format {create_generated_clock -name SOC_GATED_CLK -source [get_pins %%s/I] -divide_by 1 -add -master_clock [get_clocks CPU_CLK_IN] [get_pins %%s/O]} \ + $uvhs_soc_bufg $uvhs_soc_bufg] + puts "INFO: UVHS patch: restore replicated SOC_GATED_CLK as CPU_CLK_IN generated clock on $uvhs_soc_bufg" + } + lappend uvhs_lines $uvhs_line + } + set uvhs_patched [join $uvhs_lines "\n"] + regsub -all {create_generated_clock[^\n]*-name[^\n]*core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer[^\n]*TO_DIFFTEST_PCIE_CLK[^\n]*} \ $uvhs_patched {create_clock -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ -name XDMA_AXI_ACLK -waveform [list 0 [expr __UVHS_XDMA_AXI_CLK_PERIOD_NS__ / 2.0]] -add [get_pins part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK]} uvhs_patched regsub -all {core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer} $uvhs_patched {XDMA_AXI_ACLK} uvhs_patched @@ -793,6 +832,14 @@ if {[llength $uvhs_xdma_mmcms]} { puts "INFO: UVHS patch: XDMA clk_wiz MMCM cell not found before route; current x4 DCP exposes TO_DIFFTEST_PCIE_CLK directly" } }] + set hold_expn_bailout [env_or_default UVHS_ROUTE_ENABLE_HOLD_EXPN_BAILOUT ""] + if {$hold_expn_bailout ne ""} { + if {$hold_expn_bailout ni {0 1}} { + error "UVHS_ROUTE_ENABLE_HOLD_EXPN_BAILOUT must be empty, 0, or 1; got '$hold_expn_bailout'" + } + append script "\nputs \"INFO: UVHS patch: set route.enableHoldExpnBailout=$hold_expn_bailout before route\"\n" + append script "set_param route.enableHoldExpnBailout $hold_expn_bailout\n" + } append script [uvhs_async_clock_patch_script] foreach pnr_dir [glob -nocomplain hw.dat/Compile/PnR/*/*] { set before_route [file join $pnr_dir before_route.tcl] @@ -1216,11 +1263,11 @@ if {[uvhs_cpu_debug_clk]} { create_clock_if_port_exists jtag_vclk 83.333 JTAG_TCK create_clock_if_port_exists pcie_ep_refclk 10 pcie_ep_gt_ref_clk_p create_generated_clock_if_bufgce_exists SOC_GATED_CLK CPU_CLK_IN { - *SOC_CLK_CTRL*u_bufgce + *SOC_CLK_CTRL*bufgce* *inter_soc_clk* } create_generated_clock_if_bufgce_exists RTC_GATED_CLK TMCLK { - *RTC_CLK_CTRL*u_bufgce + *RTC_CLK_CTRL*bufgce* *inter_rtc_clk* } create_blackbox_output_clock_if_pin_exists XDMA_AXI_ACLK [uvhs_xdma_axi_clk_period_ns] core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK @@ -1231,8 +1278,9 @@ run_or_warn "report_clock -inferred" {report_clock -inferred} source_if_exists [file normalize [file join [file dirname [info script]] async_clocks.tcl]] run_or_warn "transform_clock" {transform_clock} source_if_exists [file normalize [file join [file dirname [info script]] async_clocks.tcl]] -trigger_probe -group +uvhs_config_fill_rates uvhs_config_probe_group_resource +trigger_probe -group sweep_design -remap report_clock diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 4db35e00..c769e494 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -32,6 +32,9 @@ UVHS_FPGA_PROCESSES ?= 8 UVHS_PNR_STRATEGY ?= Strategy_uv_high_fanout_explore UVHS_COMPILE_STRATEGY_NUM ?= 1 UVHS_COMPILE_STRATEGY0 ?= uv_high_fanout_explore +UVHS_LUT_FILL_RATE ?= $(if $(filter kmh,$(CPU)),80,) +UVHS_LUT6_FILL_RATE ?= $(if $(filter kmh,$(CPU)),30,) +UVHS_ROUTE_ENABLE_HOLD_EXPN_BAILOUT ?= $(if $(filter kmh,$(CPU)),0,) XDMA_LINK_WIDTH ?= X4 XDMA_ENABLE_PF0_BAR1 ?= 1 @@ -70,7 +73,10 @@ UVHS_FLOW_ENV = \ UVHS_CPU_DEBUG_CLK="$(UVHS_CPU_DEBUG_CLK)" \ UVHS_PNR_STRATEGY="$(UVHS_PNR_STRATEGY)" \ UVHS_COMPILE_STRATEGY_NUM="$(UVHS_COMPILE_STRATEGY_NUM)" \ - UVHS_COMPILE_STRATEGY0="$(UVHS_COMPILE_STRATEGY0)" + UVHS_COMPILE_STRATEGY0="$(UVHS_COMPILE_STRATEGY0)" \ + UVHS_LUT_FILL_RATE="$(UVHS_LUT_FILL_RATE)" \ + UVHS_LUT6_FILL_RATE="$(UVHS_LUT6_FILL_RATE)" \ + UVHS_ROUTE_ENABLE_HOLD_EXPN_BAILOUT="$(UVHS_ROUTE_ENABLE_HOLD_EXPN_BAILOUT)" UVHS_PNR_DIR ?= $(UVHS_WORK_DIR)/hw.dat/Compile/PnR/$(UVHS_TARGET_PACK)/$(UVHS_TARGET_FPGA)/vivado/Rundir/$(UVHS_PNR_STRATEGY) UVHS_BITSTREAM_DIR ?= $(UVHS_PNR_DIR)/bitstream @@ -149,6 +155,17 @@ uvhs_filelist: printf '+define+DQ=64\n+define+MICRON_DDR\n+define+DDR4_16Gbx8\n'; \ printf '+define+DDR4\n+define+SRAM_SYN\n+define+DATA_VERSION=0\n'; \ if [ "$(CPU)" = nutshell ]; then printf '+define+CPU_NUTSHELL\n'; fi; \ + if [ "$(CPU)" = kmh ]; then \ + simtop=""; \ + for candidate in "$(CORE_DIR)/build/rtl/SimTop.sv" \ + "$(CORE_DIR)/rtl/SimTop.sv" "$(CORE_DIR)/SimTop.sv"; do \ + if [ -f "$$candidate" ]; then simtop="$$candidate"; break; fi; \ + done; \ + if [ -n "$$simtop" ] && \ + grep -Eq '^[[:space:]]*(input|output)[[:space:]].*dma_awready' "$$simtop"; then \ + printf '+define+CONFIG_SIMTOP_HAS_DMA\n'; \ + fi; \ + fi; \ if [ "$(UVHS_CPU_DEBUG_CLK)" = 1 ]; then printf '+define+UVHS_CPU_DEBUG_CLK\n'; fi; \ if [ -n "$(CHI_DIR)" ]; then printf '+define+MSI_MODE\n+define+CONFIG_USE_XSCORE_CHI\n'; \ else printf '+define+CONFIG_USE_XSCORE_AXI\n'; fi; \ From cfb9521ed6bf910feea714cbfc8d922d0fcd049e Mon Sep 17 00:00:00 2001 From: klin02 Date: Wed, 29 Jul 2026 22:28:33 +0800 Subject: [PATCH 04/62] refactor(fpga_diff): simplify UVHS build and runtime Use native-width vendor DDR DCPs and remove the NutShell AXI width adapter. Consolidate UVHS-only RTL selection while retaining the normal Vivado target behavior. Add attached runtime commands for download, reset, and DDR backdoor writes, together with tool compatibility checks and updated flow documentation. Co-authored-by: Kamimiao --- fpga_diff/Makefile | 51 ++-- fpga_diff/src/rtl/common/core_def_xdma.sv | 6 +- fpga_diff/src/rtl/common/fpga_top_debug.sv | 100 +++---- .../src/rtl/common/uvhs_axi64_to_axi256.sv | 211 --------------- fpga_diff/src/rtl/common/uvhs_ddr4_wrapper.sv | 246 ++++-------------- fpga_diff/src/rtl/kmh/SimTop_wrapper.sv | 7 +- fpga_diff/user_script/hw_run_download.tcl | 35 ++- fpga_diff/uvhs/README.md | 64 ++++- fpga_diff/uvhs/async_clocks.tcl | 3 - fpga_diff/uvhs/backend_run.tcl | 11 +- fpga_diff/uvhs/check_flow_tools.sh | 6 +- fpga_diff/uvhs/enqueue_runtime_command.sh | 53 ++++ fpga_diff/uvhs/runtime_command.tcl | 112 ++++++++ fpga_diff/uvhs/timing_common.tcl | 11 +- fpga_diff/uvhs/uv_shell_exec_compat.sh | 14 + fpga_diff/uvhs/uvhs.mk | 89 ++++++- 16 files changed, 463 insertions(+), 556 deletions(-) delete mode 100644 fpga_diff/src/rtl/common/uvhs_axi64_to_axi256.sv create mode 100755 fpga_diff/uvhs/enqueue_runtime_command.sh create mode 100644 fpga_diff/uvhs/runtime_command.tcl create mode 100755 fpga_diff/uvhs/uv_shell_exec_compat.sh diff --git a/fpga_diff/Makefile b/fpga_diff/Makefile index 7afa5eb4..db95ff96 100755 --- a/fpga_diff/Makefile +++ b/fpga_diff/Makefile @@ -23,7 +23,20 @@ PRJ_NAME = fpga_$(CPU)$(if $(strip $(SUFFIX)),-$(strip $(SUFFIX)),) PRJ_DIR ?= $(ENV_SCRIPTS_HOME)/$(PRJ_NAME) PRJ ?= $(PRJ_DIR)/$(PRJ_NAME).xpr -.PHONY: bitstream vivado dump_ila write_jtag_flash update_core_flist +FPGA_WRITE_BITSTREAM_IMPL ?= vivado_write_bitstream +FPGA_HALT_SOC_IMPL ?= vivado_halt_soc +FPGA_WRITE_DDR_IMPL ?= vivado_write_jtag_ddr +FPGA_WRITE_FLASH_IMPL ?= vivado_write_jtag_flash +FPGA_RESET_CPU_IMPL ?= vivado_reset_cpu + +ifeq ($(UVHS),1) +include uvhs/uvhs.mk +endif + +.PHONY: bitstream vivado dump_ila update_core_flist \ + write_bitstream halt_soc write_jtag_ddr write_jtag_flash reset_cpu \ + vivado_write_bitstream vivado_halt_soc vivado_write_jtag_ddr \ + vivado_write_jtag_flash vivado_reset_cpu # Get Vivado version VIVADO_VERSION := $(shell vivado -version 2>/dev/null | head -1 | grep -o '[0-9]\{4\}\.[0-9]' || echo "unknown") @@ -51,28 +64,38 @@ vivado: check_vivado_version check_version: vivado -mode batch -source src/tcl/common/check_version.tcl -tclargs --vivado_version $(VIVADO_VERSION) --cpu $(CPU) --project_name $(PRJ_NAME) -# Write bitstream to FPGA via PCIe -write_bitstream: +# Program the selected FPGA backend. +write_bitstream: $(FPGA_WRITE_BITSTREAM_IMPL) + +vivado_write_bitstream: sh tools/pcie-remove.sh vivado -mode tcl -source tools/write_bitstream.tcl -tclargs $(FPGA_BIT_HOME) sh tools/pcie-rescan.sh vivado -mode tcl -source tools/reset_ddr.tcl -tclargs $(FPGA_BIT_HOME)/fpga_top_debug.ltx - $(MAKE) reset_cpu + $(MAKE) vivado_reset_cpu + +# Halt the FPGA SoC before loading memory. +halt_soc: $(FPGA_HALT_SOC_IMPL) -# Halt the FPGA SoC (for Write Jtag DDR) -halt_soc: +vivado_halt_soc: vivado -mode tcl -source tools/halt_soc.tcl -tclargs $(FPGA_BIT_HOME)/fpga_top_debug.ltx -# Write workload to FPGA DDR via JTAG -write_jtag_ddr: +# Load a workload into FPGA DDR. +write_jtag_ddr: $(FPGA_WRITE_DDR_IMPL) + +vivado_write_jtag_ddr: vivado -mode tcl -source tools/jtag_write_ddr.tcl -tclargs $(WORKLOAD) $(AXI_WIDTH) -# Write a raw binary image to the BRAM-backed flash via the flash-only JTAG AXI -write_jtag_flash: +# Load a raw binary image into the BRAM-backed flash. +write_jtag_flash: $(FPGA_WRITE_FLASH_IMPL) + +vivado_write_jtag_flash: vivado -mode tcl -source tools/jtag_write_flash.tcl -tclargs $(WORKLOAD) -# Reset CPU on FPGA -reset_cpu: +# Reset the CPU on the selected FPGA backend. +reset_cpu: $(FPGA_RESET_CPU_IMPL) + +vivado_reset_cpu: vivado -mode tcl -source tools/reset_cpu.tcl -tclargs $(FPGA_BIT_HOME)/fpga_top_debug.ltx ILA_OUT ?= $(ENV_SCRIPTS_HOME)/ila-dump @@ -99,7 +122,3 @@ get_synth_log: all: $(MAKE) update_core_flist CORE_DIR="$(CORE_DIR)" RTL_INCLUDE="$(RTL_INCLUDE)" $(MAKE) vivado CPU=$(CPU) SUFFIX="$(SUFFIX)" - -ifeq ($(UVHS),1) -include uvhs/uvhs.mk -endif diff --git a/fpga_diff/src/rtl/common/core_def_xdma.sv b/fpga_diff/src/rtl/common/core_def_xdma.sv index 04aa2663..1ec1cfe6 100755 --- a/fpga_diff/src/rtl/common/core_def_xdma.sv +++ b/fpga_diff/src/rtl/common/core_def_xdma.sv @@ -54,7 +54,7 @@ module core_def ( output [1:0] uhs1_drv_sth , output uhs1_swvolt_en , output sd_led_control , -`ifndef UVHS_UVW_AXI4_TO_DDR4 +`ifndef UVHS output [`CONFIG_RANK_WIDTH-1:0] DDR_CK_T , output [`CONFIG_RANK_WIDTH-1:0] DDR_CK_C , output [`CONFIG_RANK_WIDTH-1:0] DDR_CKE , @@ -1334,7 +1334,7 @@ mode_ctrl U_MODE_CTRL( .scan_mode ( ) ); -`ifdef UVHS_UVW_AXI4_TO_DDR4 +`ifdef UVHS uvhs_ddr4_wrapper U_UVHS_UVW_AXI4_TO_DDR4 ( .clk (inter_soc_clk), .rstn (rstn_sw4), @@ -1695,7 +1695,7 @@ assign hpm_dig_result = 0; AXI_bridge CFG_AXI_bridge_i (.SYS_INTER_CLK (inter_soc_clk), -`ifdef UVHS_SOC_ADAPT +`ifdef UVHS .SYS_INTER_ARESETN (inter_soc_sync_rstn), `endif .ACLK (sys_clk_i), diff --git a/fpga_diff/src/rtl/common/fpga_top_debug.sv b/fpga_diff/src/rtl/common/fpga_top_debug.sv index c984065d..3b1d03a3 100755 --- a/fpga_diff/src/rtl/common/fpga_top_debug.sv +++ b/fpga_diff/src/rtl/common/fpga_top_debug.sv @@ -35,7 +35,7 @@ module fpga_top_debug input uart2_sin, `endif //PCIE -`ifndef UVHS_SOC_ADAPT +`ifndef UVHS input refclk_p, // pcie 100MHz input refclk_n, output PERST_N, @@ -55,7 +55,7 @@ module fpga_top_debug input pcie_ep_perstn, `endif //DDR -`ifndef UVHS_UVW_AXI4_TO_DDR4 +`ifndef UVHS output [`CONFIG_RANK_WIDTH-1:0] DDR0_CK_T, output [`CONFIG_RANK_WIDTH-1:0] DDR0_CK_C, output [`CONFIG_RANK_WIDTH-1:0] DDR0_CKE, @@ -119,7 +119,7 @@ wire pcie_rstn; (*mark_debug = "true"*) wire cpu_setn_rflag; (*mark_debug = "true"*) reg cpu_rstn; -`ifdef UVHS_SOC_ADAPT +`ifdef UVHS assign sys_rstn = rstn_sw6; assign cpu_setn_buf = rstn_sw5; assign sys_rstn_to_core = rstn_sw6; @@ -152,16 +152,18 @@ assign cpu_rstn_to_core = cpu_rstn; assign ddr_rstn_to_core = rstn_sw4 && vio_sw4; `endif +`ifdef XS_GMAC // Suppose PHY_RESET_B active high. // Although 88E1116R pin10 resetn is active low. // But this pin is on connector, which might not have current by default? -assign PHY_RESET_B = cpu_rstn; +assign PHY_RESET_B = cpu_rstn_to_core; +`endif wire tmclk_buf; wire cqetmclk_buf; wire dbg_clk_buf; -`ifdef UVHS_SOC_ADAPT +`ifdef UVHS assign tmclk_buf = clk8_p; assign cqetmclk_buf = clk6_p; assign dbg_clk_buf = clk5_p; @@ -208,7 +210,7 @@ BUFG bufg_dbgclk ); `endif -`ifndef UVHS_SOC_ADAPT +`ifndef UVHS wire pcie_sysclk_gt; wire pcie_sysclk; @@ -230,20 +232,10 @@ IBUFDS_GTE4 refclk2_ibuf ( ); `endif -`ifdef UVHS_SOC_ADAPT -`ifdef UVHS_CPU_DEBUG_CLK -assign sys_clk_i = dbg_clk_buf; -assign dev_clk_i = dbg_clk_buf; -`else -assign sys_clk_i = cqetmclk_buf; -assign dev_clk_i = cqetmclk_buf; -`endif -`else assign sys_clk_i = dbg_clk_buf; assign dev_clk_i = dbg_clk_buf; -`endif -`ifndef UVHS_SOC_ADAPT +`ifndef UVHS vio_0 u_vio( .clk (dbg_clk_buf), @@ -420,31 +412,8 @@ core_def core_def // .qspi_mi2(qspi_mi2), // .qspi_mi3(qspi_mi3), - // sdmmc - .sd_card_clk_out (sdmmc_cclk_card), - .sd_cmd_out (sdmmc_sd_cmd_out), - .sd_cmd_out_oe (sdmmc_sd_cmd_out_en), - .sd_dat_out (sdmmc_sd_dat_out), - .sd_dat_out_oe (sdmmc_sd_dat_out_en), - .uhs1_drv_sth (sdmmc_uhs1_drv_sth), - .uhs1_swvolt_en (sdmmc_uhs1_swvolt_en), - .sd_vdd1_on (sdmmc_sd_vdd1_on), - .sd_vdd1_sel (sdmmc_sd_vdd1_sel), - .sd_card_det_in (sdmmc_card_detect_n), - .sd_card_wp_in (sdmmc_card_write_prot), - .sd_cmd_in (sdmmc_sd_cmd_in), - .sd_dat_in (sdmmc_sd_dat_in), - .sd_led_control ( ) `ifdef XS_GMAC - , -`else -`ifndef UVHS_UVW_AXI4_TO_DDR4 - , -`endif -`endif - - `ifdef XS_GMAC - // gmac + // GMAC .io_gmac_mdo_oe ( io_gmac_mdo_oe ), .io_gmac_mdo ( io_gmac_mdo ), .io_gmac_mck_out ( io_gmac_mck_out ), @@ -454,14 +423,11 @@ core_def core_def .io_gmac_rx_clk ( io_gmac_rx_clk ), .io_gmac_rxd_vld ( io_gmac_rxd_vld ), .io_gmac_rxd ( io_gmac_rxd ), - .io_gmac_txd ( io_gmac_txd ) -`ifndef UVHS_UVW_AXI4_TO_DDR4 - , -`endif + .io_gmac_txd ( io_gmac_txd ), `endif - // ddr -`ifndef UVHS_UVW_AXI4_TO_DDR4 +`ifndef UVHS + // DDR .DDR_CK_T (DDR0_CK_T ), .DDR_CK_C (DDR0_CK_C ), .DDR_CKE (DDR0_CKE ), @@ -475,32 +441,24 @@ core_def core_def .DDR_DM_N (DDR0_DM ), .DDR_DQ (DDR0_DQ ), .DDR_DQS_T (DDR0_DQS_T ), - .DDR_DQS_C (DDR0_DQS_C )/*, - .DDR_ZQ (DDR0_ZQ), - .gmac_gmii_mdc_o(gmac_gmii_mdc_o), - .gmac_gmii_mdo_o(gmac_gmii_mdo_o), - .gmac_gmii_mdo_o_e(gmac_gmii_mdo_o_e), - .gmac_clk_tx_o(gmac_clk_tx_o), - .gmac_phy_txd(gmac_phy_txd), - .gmac_phy_txen(gmac_phy_txen), - .gmac_gmii_mdi_i(gmac_gmii_mdi_i), - .gmac_clk_rx_i(gmac_clk_rx_i), - .gmac_phy_rxd(gmac_phy_rxd), - .gmac_phy_rxdv(gmac_phy_rxdv), - - .gpio_porta_ddr(gpio_porta_ddr), - .gpio_porta_dr(gpio_porta_dr), - .gpio_ext_porta(gpio_ext_porta), - - .jtag_tck(jtag_tck), - .jtag_tdi(jtag_tdi), - .jtag_tms(jtag_tms), - .jtag_trstn(jtag_trstn), - .jtag_tdo(jtag_tdo), - - */ + .DDR_DQS_C (DDR0_DQS_C ), `endif + // SDMMC + .sd_card_clk_out (sdmmc_cclk_card), + .sd_cmd_out (sdmmc_sd_cmd_out), + .sd_cmd_out_oe (sdmmc_sd_cmd_out_en), + .sd_dat_out (sdmmc_sd_dat_out), + .sd_dat_out_oe (sdmmc_sd_dat_out_en), + .uhs1_drv_sth (sdmmc_uhs1_drv_sth), + .uhs1_swvolt_en (sdmmc_uhs1_swvolt_en), + .sd_vdd1_on (sdmmc_sd_vdd1_on), + .sd_vdd1_sel (sdmmc_sd_vdd1_sel), + .sd_card_det_in (sdmmc_card_detect_n), + .sd_card_wp_in (sdmmc_card_write_prot), + .sd_cmd_in (sdmmc_sd_cmd_in), + .sd_dat_in (sdmmc_sd_dat_in), + .sd_led_control () ); //--- diff --git a/fpga_diff/src/rtl/common/uvhs_axi64_to_axi256.sv b/fpga_diff/src/rtl/common/uvhs_axi64_to_axi256.sv deleted file mode 100644 index 23eaac51..00000000 --- a/fpga_diff/src/rtl/common/uvhs_axi64_to_axi256.sv +++ /dev/null @@ -1,211 +0,0 @@ -`timescale 1ns/1ps - -module uvhs_axi64_to_axi256 ( - input wire clk, - input wire rstn, - - input wire [13:0] s_axi_awid, - input wire [39:0] s_axi_awaddr, - input wire [7:0] s_axi_awlen, - input wire [2:0] s_axi_awsize, - input wire [1:0] s_axi_awburst, - input wire s_axi_awlock, - input wire [3:0] s_axi_awcache, - input wire [2:0] s_axi_awprot, - input wire [3:0] s_axi_awqos, - input wire s_axi_awvalid, - output wire s_axi_awready, - input wire [63:0] s_axi_wdata, - input wire [7:0] s_axi_wstrb, - input wire s_axi_wlast, - input wire s_axi_wvalid, - output wire s_axi_wready, - output wire [13:0] s_axi_bid, - output wire [1:0] s_axi_bresp, - output wire s_axi_bvalid, - input wire s_axi_bready, - - input wire [13:0] s_axi_arid, - input wire [39:0] s_axi_araddr, - input wire [7:0] s_axi_arlen, - input wire [2:0] s_axi_arsize, - input wire [1:0] s_axi_arburst, - input wire s_axi_arlock, - input wire [3:0] s_axi_arcache, - input wire [2:0] s_axi_arprot, - input wire [3:0] s_axi_arqos, - input wire s_axi_arvalid, - output wire s_axi_arready, - output wire [13:0] s_axi_rid, - output wire [63:0] s_axi_rdata, - output wire [1:0] s_axi_rresp, - output wire s_axi_rlast, - output wire s_axi_rvalid, - input wire s_axi_rready, - - output wire [13:0] m_axi_awid, - output wire [33:0] m_axi_awaddr, - output wire [7:0] m_axi_awlen, - output wire [2:0] m_axi_awsize, - output wire [1:0] m_axi_awburst, - output wire [0:0] m_axi_awlock, - output wire [3:0] m_axi_awcache, - output wire [2:0] m_axi_awprot, - output wire [3:0] m_axi_awqos, - output wire [3:0] m_axi_awregion, - output wire m_axi_awvalid, - input wire m_axi_awready, - output wire [255:0] m_axi_wdata, - output wire [31:0] m_axi_wstrb, - output wire m_axi_wlast, - output wire m_axi_wvalid, - input wire m_axi_wready, - input wire [13:0] m_axi_bid, - input wire [1:0] m_axi_bresp, - input wire m_axi_bvalid, - output wire m_axi_bready, - - output wire [13:0] m_axi_arid, - output wire [33:0] m_axi_araddr, - output wire [7:0] m_axi_arlen, - output wire [2:0] m_axi_arsize, - output wire [1:0] m_axi_arburst, - output wire [0:0] m_axi_arlock, - output wire [3:0] m_axi_arcache, - output wire [2:0] m_axi_arprot, - output wire [3:0] m_axi_arqos, - output wire [3:0] m_axi_arregion, - output wire m_axi_arvalid, - input wire m_axi_arready, - input wire [13:0] m_axi_rid, - input wire [255:0] m_axi_rdata, - input wire [1:0] m_axi_rresp, - input wire m_axi_rlast, - input wire m_axi_rvalid, - output wire m_axi_rready -); - - reg write_active; - reg write_resp_pending; - reg [1:0] write_lane; - reg [2:0] write_size; - reg [1:0] write_burst; - - reg read_active; - reg [1:0] read_lane; - reg [2:0] read_size; - reg [1:0] read_burst; - - wire [4:0] write_shift = {write_lane, 3'b000}; - wire [4:0] read_shift = {read_lane, 3'b000}; - wire [255:0] shifted_rdata = m_axi_rdata >> (read_shift * 8); - - assign m_axi_awid = s_axi_awid; - assign m_axi_awaddr = s_axi_awaddr[33:0]; - assign m_axi_awlen = s_axi_awlen; - assign m_axi_awsize = s_axi_awsize; - assign m_axi_awburst = s_axi_awburst; - assign m_axi_awlock = s_axi_awlock; - assign m_axi_awcache = s_axi_awcache; - assign m_axi_awprot = s_axi_awprot; - assign m_axi_awqos = s_axi_awqos; - assign m_axi_awregion = 4'b0; - assign m_axi_awvalid = s_axi_awvalid & ~write_active & ~write_resp_pending; - assign s_axi_awready = m_axi_awready & ~write_active & ~write_resp_pending; - - assign m_axi_wdata = {192'b0, s_axi_wdata} << (write_shift * 8); - assign m_axi_wstrb = {24'b0, s_axi_wstrb} << write_shift; - assign m_axi_wlast = s_axi_wlast; - assign m_axi_wvalid = s_axi_wvalid & write_active; - assign s_axi_wready = m_axi_wready & write_active; - - assign s_axi_bid = m_axi_bid; - assign s_axi_bresp = m_axi_bresp; - assign s_axi_bvalid = m_axi_bvalid; - assign m_axi_bready = s_axi_bready; - - assign m_axi_arid = s_axi_arid; - assign m_axi_araddr = s_axi_araddr[33:0]; - assign m_axi_arlen = s_axi_arlen; - assign m_axi_arsize = s_axi_arsize; - assign m_axi_arburst = s_axi_arburst; - assign m_axi_arlock = s_axi_arlock; - assign m_axi_arcache = s_axi_arcache; - assign m_axi_arprot = s_axi_arprot; - assign m_axi_arqos = s_axi_arqos; - assign m_axi_arregion = 4'b0; - assign m_axi_arvalid = s_axi_arvalid & ~read_active; - assign s_axi_arready = m_axi_arready & ~read_active; - - assign s_axi_rid = m_axi_rid; - assign s_axi_rdata = shifted_rdata[63:0]; - assign s_axi_rresp = m_axi_rresp; - assign s_axi_rlast = m_axi_rlast; - assign s_axi_rvalid = m_axi_rvalid & read_active; - assign m_axi_rready = s_axi_rready & read_active; - - function automatic [1:0] next_lane(input [1:0] lane, input [2:0] size, input [1:0] burst); - begin - // Both INCR and WRAP advance the transfer address on every beat. The - // NutShell cache-line port uses WRAP bursts, so keeping its lane fixed - // repeats lane zero after the first 64-bit beat on the 256-bit bus. - if ((burst == 2'b01 || burst == 2'b10) && size >= 3'd3) begin - next_lane = lane + (2'b01 << (size - 3'd3)); - end else begin - next_lane = lane; - end - end - endfunction - - always @(posedge clk) begin - if (!rstn) begin - write_active <= 1'b0; - write_resp_pending <= 1'b0; - write_lane <= 2'b0; - write_size <= 3'b0; - write_burst <= 2'b0; - end else begin - if (s_axi_awvalid && s_axi_awready) begin - write_active <= 1'b1; - write_resp_pending <= 1'b0; - write_lane <= s_axi_awaddr[4:3]; - write_size <= s_axi_awsize; - write_burst <= s_axi_awburst; - end else if (s_axi_wvalid && s_axi_wready) begin - if (s_axi_wlast) begin - write_active <= 1'b0; - write_resp_pending <= 1'b1; - end else begin - write_lane <= next_lane(write_lane, write_size, write_burst); - end - end - - if (s_axi_bvalid && s_axi_bready) begin - write_resp_pending <= 1'b0; - end - end - end - - always @(posedge clk) begin - if (!rstn) begin - read_active <= 1'b0; - read_lane <= 2'b0; - read_size <= 3'b0; - read_burst <= 2'b0; - end else begin - if (s_axi_arvalid && s_axi_arready) begin - read_active <= 1'b1; - read_lane <= s_axi_araddr[4:3]; - read_size <= s_axi_arsize; - read_burst <= s_axi_arburst; - end else if (s_axi_rvalid && s_axi_rready) begin - if (s_axi_rlast) begin - read_active <= 1'b0; - end else begin - read_lane <= next_lane(read_lane, read_size, read_burst); - end - end - end - end - -endmodule diff --git a/fpga_diff/src/rtl/common/uvhs_ddr4_wrapper.sv b/fpga_diff/src/rtl/common/uvhs_ddr4_wrapper.sv index b0681b27..780ed09f 100644 --- a/fpga_diff/src/rtl/common/uvhs_ddr4_wrapper.sv +++ b/fpga_diff/src/rtl/common/uvhs_ddr4_wrapper.sv @@ -64,222 +64,68 @@ module uvhs_ddr4_wrapper ( input wire s_axi_rready ); - wire [13:0] ddr_awid; - wire [33:0] ddr_awaddr; - wire [7:0] ddr_awlen; - wire [2:0] ddr_awsize; - wire [1:0] ddr_awburst; - wire [0:0] ddr_awlock; - wire [3:0] ddr_awcache; - wire [2:0] ddr_awprot; - wire [3:0] ddr_awqos; - wire [3:0] ddr_awregion; - wire ddr_awvalid; - wire ddr_awready; - wire [255:0] ddr_wdata; - wire [31:0] ddr_wstrb; - wire ddr_wlast; - wire ddr_wvalid; - wire ddr_wready; - wire [13:0] ddr_bid; - wire [1:0] ddr_bresp; - wire ddr_bvalid; - wire ddr_bready; - wire [13:0] ddr_arid; - wire [33:0] ddr_araddr; - wire [7:0] ddr_arlen; - wire [2:0] ddr_arsize; - wire [1:0] ddr_arburst; - wire [0:0] ddr_arlock; - wire [3:0] ddr_arcache; - wire [2:0] ddr_arprot; - wire [3:0] ddr_arqos; - wire [3:0] ddr_arregion; - wire ddr_arvalid; - wire ddr_arready; - wire [255:0] ddr_rdata; - wire [13:0] ddr_rid; - wire [1:0] ddr_rresp; - wire ddr_rlast; - wire ddr_rvalid; - wire ddr_rready; - wire ddr_user_rst; + wire [33:0] ddr_awaddr; + wire [33:0] ddr_araddr; + wire [13:0] ddr_bid; + wire [13:0] ddr_rid; + wire ddr_user_rst; `ifdef CPU_NUTSHELL - wire [13:0] s_axi_bid_64; - wire [13:0] s_axi_rid_64; - wire [63:0] s_axi_rdata_64; - - assign s_axi_bid = {4'b0, s_axi_bid_64}; - assign s_axi_rid = {4'b0, s_axi_rid_64}; - assign s_axi_rdata = s_axi_rdata_64; - - uvhs_axi64_to_axi256 width_adapter ( - .clk(clk), - .rstn(rstn), - .s_axi_awid(s_axi_awid[13:0]), - .s_axi_awaddr({7'b0, s_axi_awaddr}), - .s_axi_awlen(s_axi_awlen), - .s_axi_awsize(s_axi_awsize), - .s_axi_awburst(s_axi_awburst), - .s_axi_awlock(s_axi_awlock), - .s_axi_awcache(s_axi_awcache), - .s_axi_awprot(s_axi_awprot), - .s_axi_awqos(s_axi_awqos), - .s_axi_awvalid(s_axi_awvalid), - .s_axi_awready(s_axi_awready), - .s_axi_wdata(s_axi_wdata[63:0]), - .s_axi_wstrb(s_axi_wstrb[7:0]), - .s_axi_wlast(s_axi_wlast), - .s_axi_wvalid(s_axi_wvalid), - .s_axi_wready(s_axi_wready), - .s_axi_bid(s_axi_bid_64), - .s_axi_bresp(s_axi_bresp), - .s_axi_bvalid(s_axi_bvalid), - .s_axi_bready(s_axi_bready), - .s_axi_arid(s_axi_arid[13:0]), - .s_axi_araddr({7'b0, s_axi_araddr}), - .s_axi_arlen(s_axi_arlen), - .s_axi_arsize(s_axi_arsize), - .s_axi_arburst(s_axi_arburst), - .s_axi_arlock(s_axi_arlock), - .s_axi_arcache(s_axi_arcache), - .s_axi_arprot(s_axi_arprot), - .s_axi_arqos(s_axi_arqos), - .s_axi_arvalid(s_axi_arvalid), - .s_axi_arready(s_axi_arready), - .s_axi_rid(s_axi_rid_64), - .s_axi_rdata(s_axi_rdata_64), - .s_axi_rresp(s_axi_rresp), - .s_axi_rlast(s_axi_rlast), - .s_axi_rvalid(s_axi_rvalid), - .s_axi_rready(s_axi_rready), - .m_axi_awid(ddr_awid), - .m_axi_awaddr(ddr_awaddr), - .m_axi_awlen(ddr_awlen), - .m_axi_awsize(ddr_awsize), - .m_axi_awburst(ddr_awburst), - .m_axi_awlock(ddr_awlock), - .m_axi_awcache(ddr_awcache), - .m_axi_awprot(ddr_awprot), - .m_axi_awqos(ddr_awqos), - .m_axi_awregion(ddr_awregion), - .m_axi_awvalid(ddr_awvalid), - .m_axi_awready(ddr_awready), - .m_axi_wdata(ddr_wdata), - .m_axi_wstrb(ddr_wstrb), - .m_axi_wlast(ddr_wlast), - .m_axi_wvalid(ddr_wvalid), - .m_axi_wready(ddr_wready), - .m_axi_bid(ddr_bid), - .m_axi_bresp(ddr_bresp), - .m_axi_bvalid(ddr_bvalid), - .m_axi_bready(ddr_bready), - .m_axi_arid(ddr_arid), - .m_axi_araddr(ddr_araddr), - .m_axi_arlen(ddr_arlen), - .m_axi_arsize(ddr_arsize), - .m_axi_arburst(ddr_arburst), - .m_axi_arlock(ddr_arlock), - .m_axi_arcache(ddr_arcache), - .m_axi_arprot(ddr_arprot), - .m_axi_arqos(ddr_arqos), - .m_axi_arregion(ddr_arregion), - .m_axi_arvalid(ddr_arvalid), - .m_axi_arready(ddr_arready), - .m_axi_rid(ddr_rid), - .m_axi_rdata(ddr_rdata), - .m_axi_rresp(ddr_rresp), - .m_axi_rlast(ddr_rlast), - .m_axi_rvalid(ddr_rvalid), - .m_axi_rready(ddr_rready) - ); + assign ddr_awaddr = {1'b0, s_axi_awaddr}; + assign ddr_araddr = {1'b0, s_axi_araddr}; `else - assign ddr_awid = s_axi_awid[13:0]; assign ddr_awaddr = s_axi_awaddr[33:0]; - assign ddr_awlen = s_axi_awlen; - assign ddr_awsize = s_axi_awsize; - assign ddr_awburst = s_axi_awburst; - assign ddr_awlock = s_axi_awlock; - assign ddr_awcache = s_axi_awcache; - assign ddr_awprot = s_axi_awprot; - assign ddr_awqos = s_axi_awqos; - assign ddr_awregion = s_axi_awregion; - assign ddr_awvalid = s_axi_awvalid; - assign s_axi_awready = ddr_awready; - assign ddr_wdata = s_axi_wdata; - assign ddr_wstrb = s_axi_wstrb; - assign ddr_wlast = s_axi_wlast; - assign ddr_wvalid = s_axi_wvalid; - assign s_axi_wready = ddr_wready; - assign s_axi_bid = {4'b0, ddr_bid}; - assign s_axi_bresp = ddr_bresp; - assign s_axi_bvalid = ddr_bvalid; - assign ddr_bready = s_axi_bready; - assign ddr_arid = s_axi_arid[13:0]; assign ddr_araddr = s_axi_araddr[33:0]; - assign ddr_arlen = s_axi_arlen; - assign ddr_arsize = s_axi_arsize; - assign ddr_arburst = s_axi_arburst; - assign ddr_arlock = s_axi_arlock; - assign ddr_arcache = s_axi_arcache; - assign ddr_arprot = s_axi_arprot; - assign ddr_arqos = s_axi_arqos; - assign ddr_arregion = s_axi_arregion; - assign ddr_arvalid = s_axi_arvalid; - assign s_axi_arready = ddr_arready; - assign s_axi_rid = {4'b0, ddr_rid}; - assign s_axi_rdata = ddr_rdata; - assign s_axi_rresp = ddr_rresp; - assign s_axi_rlast = ddr_rlast; - assign s_axi_rvalid = ddr_rvalid; - assign ddr_rready = s_axi_rready; `endif + assign s_axi_bid = {4'b0, ddr_bid}; + assign s_axi_rid = {4'b0, ddr_rid}; assign calib_complete = rstn & ~ddr_user_rst; + // The selected vendor DCP must match the source AXI data width: NutShell + // uses a native 64-bit DCP while the XiangShan path uses a 256-bit DCP. uvw_axi4_to_ddr4 ddr4_ip ( .ddr4ip_dut_axi_aclk(clk), .ddr4ip_dut_axi_aresetn(rstn), .ddr4ip_dut_axi_awaddr(ddr_awaddr), - .ddr4ip_dut_axi_awburst(ddr_awburst), - .ddr4ip_dut_axi_awcache(ddr_awcache), - .ddr4ip_dut_axi_awid(ddr_awid), - .ddr4ip_dut_axi_awlen(ddr_awlen), - .ddr4ip_dut_axi_awlock(ddr_awlock), - .ddr4ip_dut_axi_awprot(ddr_awprot), - .ddr4ip_dut_axi_awqos(ddr_awqos), - .ddr4ip_dut_axi_awready(ddr_awready), - .ddr4ip_dut_axi_awregion(ddr_awregion), - .ddr4ip_dut_axi_awsize(ddr_awsize), - .ddr4ip_dut_axi_awvalid(ddr_awvalid), - .ddr4ip_dut_axi_wdata(ddr_wdata), - .ddr4ip_dut_axi_wlast(ddr_wlast), - .ddr4ip_dut_axi_wready(ddr_wready), - .ddr4ip_dut_axi_wstrb(ddr_wstrb), - .ddr4ip_dut_axi_wvalid(ddr_wvalid), + .ddr4ip_dut_axi_awburst(s_axi_awburst), + .ddr4ip_dut_axi_awcache(s_axi_awcache), + .ddr4ip_dut_axi_awid(s_axi_awid[13:0]), + .ddr4ip_dut_axi_awlen(s_axi_awlen), + .ddr4ip_dut_axi_awlock(s_axi_awlock), + .ddr4ip_dut_axi_awprot(s_axi_awprot), + .ddr4ip_dut_axi_awqos(s_axi_awqos), + .ddr4ip_dut_axi_awready(s_axi_awready), + .ddr4ip_dut_axi_awregion(s_axi_awregion), + .ddr4ip_dut_axi_awsize(s_axi_awsize), + .ddr4ip_dut_axi_awvalid(s_axi_awvalid), + .ddr4ip_dut_axi_wdata(s_axi_wdata), + .ddr4ip_dut_axi_wlast(s_axi_wlast), + .ddr4ip_dut_axi_wready(s_axi_wready), + .ddr4ip_dut_axi_wstrb(s_axi_wstrb), + .ddr4ip_dut_axi_wvalid(s_axi_wvalid), .ddr4ip_dut_axi_bid(ddr_bid), - .ddr4ip_dut_axi_bready(ddr_bready), - .ddr4ip_dut_axi_bresp(ddr_bresp), - .ddr4ip_dut_axi_bvalid(ddr_bvalid), + .ddr4ip_dut_axi_bready(s_axi_bready), + .ddr4ip_dut_axi_bresp(s_axi_bresp), + .ddr4ip_dut_axi_bvalid(s_axi_bvalid), .ddr4ip_dut_axi_araddr(ddr_araddr), - .ddr4ip_dut_axi_arburst(ddr_arburst), - .ddr4ip_dut_axi_arcache(ddr_arcache), - .ddr4ip_dut_axi_arid(ddr_arid), - .ddr4ip_dut_axi_arlen(ddr_arlen), - .ddr4ip_dut_axi_arlock(ddr_arlock), - .ddr4ip_dut_axi_arprot(ddr_arprot), - .ddr4ip_dut_axi_arqos(ddr_arqos), - .ddr4ip_dut_axi_arready(ddr_arready), - .ddr4ip_dut_axi_arregion(ddr_arregion), - .ddr4ip_dut_axi_arsize(ddr_arsize), - .ddr4ip_dut_axi_arvalid(ddr_arvalid), - .ddr4ip_dut_axi_rdata(ddr_rdata), + .ddr4ip_dut_axi_arburst(s_axi_arburst), + .ddr4ip_dut_axi_arcache(s_axi_arcache), + .ddr4ip_dut_axi_arid(s_axi_arid[13:0]), + .ddr4ip_dut_axi_arlen(s_axi_arlen), + .ddr4ip_dut_axi_arlock(s_axi_arlock), + .ddr4ip_dut_axi_arprot(s_axi_arprot), + .ddr4ip_dut_axi_arqos(s_axi_arqos), + .ddr4ip_dut_axi_arready(s_axi_arready), + .ddr4ip_dut_axi_arregion(s_axi_arregion), + .ddr4ip_dut_axi_arsize(s_axi_arsize), + .ddr4ip_dut_axi_arvalid(s_axi_arvalid), + .ddr4ip_dut_axi_rdata(s_axi_rdata), .ddr4ip_dut_axi_rid(ddr_rid), - .ddr4ip_dut_axi_rlast(ddr_rlast), - .ddr4ip_dut_axi_rready(ddr_rready), - .ddr4ip_dut_axi_rresp(ddr_rresp), - .ddr4ip_dut_axi_rvalid(ddr_rvalid), + .ddr4ip_dut_axi_rlast(s_axi_rlast), + .ddr4ip_dut_axi_rready(s_axi_rready), + .ddr4ip_dut_axi_rresp(s_axi_rresp), + .ddr4ip_dut_axi_rvalid(s_axi_rvalid), .ddr4ip_dut_axi_aclk_en(1'b1), .ddr4ip_ddr4_user_clk(), .ddr4ip_ddr4_user_rst(ddr_user_rst), diff --git a/fpga_diff/src/rtl/kmh/SimTop_wrapper.sv b/fpga_diff/src/rtl/kmh/SimTop_wrapper.sv index aced6cf2..d909dc4c 100755 --- a/fpga_diff/src/rtl/kmh/SimTop_wrapper.sv +++ b/fpga_diff/src/rtl/kmh/SimTop_wrapper.sv @@ -353,7 +353,7 @@ SimTop u_XSTop( .dma_rresp (dma_core_rresp ), .dma_rlast (dma_core_rlast ), `endif -`ifdef UVHS_SOC_ADAPT +`ifdef UVHS // UVHS does not expose XiangShan's SystemJTAG pins. .io_systemjtag_jtag_TCK (1'b0), .io_systemjtag_jtag_TMS (1'b1), @@ -381,12 +381,7 @@ SimTop u_XSTop( .io_pll0_ctrl_4 (io_pll0_ctrl_4), .io_pll0_ctrl_5 (io_pll0_ctrl_5), .io_extIntrs (io_extIntrs ), -`ifdef UVHS_SOC_ADAPT - // Keep SYSCNT in the SoC domain and avoid the FPGA-only TimeAsync CDC. - .io_rtc_clock (inter_soc_clk), -`else .io_rtc_clock (tmclk), -`endif .io_riscv_rst_vec_0 (48'h0000_1000_0000), diff --git a/fpga_diff/user_script/hw_run_download.tcl b/fpga_diff/user_script/hw_run_download.tcl index 2572b454..2b4665db 100644 --- a/fpga_diff/user_script/hw_run_download.tcl +++ b/fpga_diff/user_script/hw_run_download.tcl @@ -1,5 +1,6 @@ -# UVHS runtime download flow. A release database is sufficient for programming -# and reset release; host software loads the workload through H2C afterwards. +# UVHS runtime download flow. A release database is sufficient for programming, +# reset control, and runtime memory operations. H2C remains available to the +# host flow after download. query -user query -fpgas -all @@ -33,8 +34,8 @@ if {[catch {query -clock -default} uvhs_clock_error]} { } # Hold the top-level resets low across download, then release them in the -# same order used by the checked-in runtime scripts for this design. The host -# keeps CPU execution stopped later through HOST_IO_RESET while DDR is written. +# same order used by the checked-in runtime scripts for this design. Runtime +# memory commands hold rstn_sw5 low while DDR is written. reset -name rstn_sw6 -value 0 reset -name rstn_sw5 -value 0 reset -name rstn_sw4 -value 0 @@ -61,7 +62,29 @@ after 1000 query -reset query -fpgas -all -# Keep the runtime attached after download. Terminate uv_shell when the board -# is no longer needed. +proc uvhs_poll_command_file {} { + if {![info exists ::env(UVHS_COMMAND_FILE)] || $::env(UVHS_COMMAND_FILE) eq ""} { + after 500 uvhs_poll_command_file + return + } + + set command_file $::env(UVHS_COMMAND_FILE) + if {[file exists $command_file]} { + set running_file "${command_file}.running" + if {[catch { + file rename -force $command_file $running_file + puts "INFO: sourcing UVHS runtime command: $running_file" + source $running_file + } command_error]} { + puts stderr "ERROR: UVHS runtime command failed: $command_error" + } + catch {file delete -force $running_file} + } + after 500 uvhs_poll_command_file +} + +# Keep the runtime attached after download. Other Make targets enqueue commands +# through UVHS_COMMAND_FILE; uvhs_runtime_stop ends this session cleanly. set ::uvhs_keepalive 0 +uvhs_poll_command_file vwait ::uvhs_keepalive diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index bc6f122a..8e2accf6 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -20,9 +20,19 @@ export UVHS_TEMPLATE_DIR=/path/to/uvhs-template export UVHS_UVW_AXI4_TO_DDR4_SRC=/path/to/uvw_axi4_to_ddr4 ``` -`UVHS_TEMPLATE_DIR` supplies the board assembly skeleton. The source tree -regenerates its own Vivado DCPs and does not carry generated DCPs, bitstreams, -or machine paths. +Complete UVHS installations resolve their own runtime libraries. If a shared +installation reports a missing `libpcre.so.1`, point +`UVHS_COMPAT_PCRE_LIB` at a compatible copy supplied with another installation; +the preflight stages it in the selected work directory without modifying the +shared tool tree. + +`UVHS_TEMPLATE_DIR` supplies the board assembly skeleton. The flow regenerates +the repository-owned Vivado IP DCPs and consumes the vendor DDR DCP separately; +the source tree does not carry generated DCPs, bitstreams, or machine paths. +`UVHS_UVW_AXI4_TO_DDR4_SRC` must select a vendor DDR DCP whose AXI width matches +the design. The default is 64 bits for `CPU=nutshell` and 256 bits for the other +designs; `uvhs_sync_uvw_axi4_to_ddr4` checks the copied stub before frontend +starts. ## Build @@ -41,6 +51,8 @@ implementation scripts, then runs placement, routing, timing signoff, and bitstream generation. Thus frontend is close to synthesis/elaboration and backend is close to physical implementation, but the boundary is UVHS's database handoff rather than a direct Vivado `synth_design` boundary. +All designs use the B0/F2 `clk5_p` 25 MHz input as the CPU clock; its default +timing period is 40 ns. `uvhs_all` runs frontend then backend. `UVHS_EXPORT_IP_FORCE=1` rebuilds the source-generated Vivado DCPs; the default reuses an existing DCP in the chosen @@ -56,16 +68,43 @@ make UVHS=1 uvhs_all CPU=kmh CORE_DIR=/path/to/XiangShan SUFFIX= ``` The file-list step detects whether `SimTop` exposes DMA and enables the H2C -path accordingly. XiangShan keeps the B0/F2, x4, and 25 MHz defaults, while -using 80% LUT and 30% LUT6 fill limits and disabling the hold-expansion route -bailout. Each value remains independently overrideable on the command line. +path accordingly. XiangShan keeps the B0/F2 and x4 defaults, while using 80% +LUT and 30% LUT6 fill limits and disabling the hold-expansion route bailout. ## Runtime -Use `user_script/hw_run_download.tcl` with the completed `hw.dat` database. -It downloads the design and releases the software resets. The host-side -FPGA-Diff flow loads the workload through H2C after download; the runtime Tcl -does not contain workload, debug, or command-file hooks. +The public programming targets retain the same names in both flows. With +`UVHS=1`, Make selects the UVHS runtime Tcl instead of Vivado LabTools: + +```sh +# Keep this foreground process attached to the board. +make UVHS=1 CPU= SUFFIX= write_bitstream + +# Run these from another shell with the same CPU/SUFFIX or UVHS_WORK_DIR. +make UVHS=1 CPU= SUFFIX= halt_soc +make UVHS=1 CPU= SUFFIX= write_jtag_ddr WORKLOAD=/path/to/image.txt +make UVHS=1 CPU= SUFFIX= reset_cpu +make UVHS=1 CPU= SUFFIX= uvhs_runtime_stop +``` + +`write_bitstream` loads the completed `hw.dat`, configures the connector and +clocks, holds `rstn_sw6/rstn_sw5/rstn_sw4` low across `download`, calls +`initialize`, then releases system/DDR reset before CPU reset. The process +polls an atomic command file while it owns the runtime session. `halt_soc` and +`reset_cpu` control `rstn_sw5`; the other two reset names remain reserved for +the system and external DDR IP. + +`write_jtag_ddr` keeps the legacy target name but uses UVHS `writemem` in this +flow. It accepts the same address/data-pair text file as the Vivado Tcl, +converts each segment to the selected DCP word width, and writes the DDR IP +through its runtime backdoor. H2C remains available for the normal FPGA-Diff +host workflow and is independent of this loader. + +The current runtime database exposes only the vendor DDR IP in +`query -memory`; the BRAM-backed flash DCP is not a runtime memory object. +Therefore `write_jtag_flash` is unsupported with `UVHS=1` and fails explicitly. +The normal Vivado flow continues to write that flash through its dedicated +32-bit JTAG AXI without any interface change. ## Files @@ -81,6 +120,7 @@ does not contain workload, debug, or command-file hooks. | `check_modules.sh`, `filelist.awk`, `check_flow_tools.sh` | Validate the generated RTL file list and checked-in flow sources. | | `make_compat/` | Supplies the Bash-compatible commands required by UVHS-generated Makefiles and its `csh -fc limit` probe. | | `patch_uvsyn_shell.sh` | Patches the generated worker Makefile to run the vendor `uv_shell` script through Bash. | -| `uvhs_axi64_to_axi256.sv` | Converts a 64-bit source AXI data path to the vendor DDR IP's 256-bit interface. | +| `enqueue_runtime_command.sh`, `runtime_command.tcl` | Atomically submit reset and memory operations to the attached runtime process. | +| `uv_shell_exec_compat.sh` | Restores staged compatibility libraries after the vendor launcher sanitizes `LD_LIBRARY_PATH`. | | `uvhs_ddr4_wrapper.sv` | Isolates the vendor DDR AXI wiring from the common FPGA-Diff top-level RTL. | -| `../user_script/hw_run_download.tcl` | Downloads and initializes a completed UVHS database. | +| `../user_script/hw_run_download.tcl` | Downloads and initializes a completed UVHS database, then services runtime commands. | diff --git a/fpga_diff/uvhs/async_clocks.tcl b/fpga_diff/uvhs/async_clocks.tcl index 26fa30b2..8bbce9f7 100644 --- a/fpga_diff/uvhs/async_clocks.tcl +++ b/fpga_diff/uvhs/async_clocks.tcl @@ -8,7 +8,4 @@ set fpga_diff_async_groups [list] foreach fpga_diff_clock {TMCLK ddr_ref_clk CPU_CLK_IN jtag_vclk pcie_ep_refclk} { lappend fpga_diff_async_groups -group [get_clocks -include_generated_clocks $fpga_diff_clock] } -if {[llength [get_clocks -quiet DEBUG_CLK_IN]] > 0} { - lappend fpga_diff_async_groups -group [get_clocks -include_generated_clocks DEBUG_CLK_IN] -} eval [linsert $fpga_diff_async_groups 0 set_clock_groups -asynchronous] diff --git a/fpga_diff/uvhs/backend_run.tcl b/fpga_diff/uvhs/backend_run.tcl index bfb8d9ec..0a4be30c 100644 --- a/fpga_diff/uvhs/backend_run.tcl +++ b/fpga_diff/uvhs/backend_run.tcl @@ -68,10 +68,6 @@ proc uvhs_cpu_clk_period_ns {} { return [env_or_default UVHS_CPU_CLK_PERIOD_NS 40] } -proc uvhs_cpu_debug_clk {} { - return [expr {[env_or_default UVHS_CPU_DEBUG_CLK 1] eq "1"}] -} - proc uvhs_xdma_link_width {} { set link_width [string toupper [string trim [env_or_default XDMA_LINK_WIDTH X4]]] if {$link_width ni {X4 X8}} { @@ -1254,12 +1250,7 @@ sweep_design create_clock_if_port_exists TMCLK 1000 clk8_p create_clock_if_port_exists ddr_ref_clk 12.5 clk7_p -if {[uvhs_cpu_debug_clk]} { - create_clock_if_port_exists CPU_CLK_IN [uvhs_cpu_clk_period_ns] clk5_p -} else { - create_clock_if_port_exists CPU_CLK_IN [uvhs_cpu_clk_period_ns] clk6_p - create_clock_if_port_exists DEBUG_CLK_IN 40 clk5_p -} +create_clock_if_port_exists CPU_CLK_IN [uvhs_cpu_clk_period_ns] clk5_p create_clock_if_port_exists jtag_vclk 83.333 JTAG_TCK create_clock_if_port_exists pcie_ep_refclk 10 pcie_ep_gt_ref_clk_p create_generated_clock_if_bufgce_exists SOC_GATED_CLK CPU_CLK_IN { diff --git a/fpga_diff/uvhs/check_flow_tools.sh b/fpga_diff/uvhs/check_flow_tools.sh index 1d554861..6730732b 100644 --- a/fpga_diff/uvhs/check_flow_tools.sh +++ b/fpga_diff/uvhs/check_flow_tools.sh @@ -20,8 +20,10 @@ required=( uvhs/make_compat/make uvhs/make_compat/csh uvhs/patch_uvsyn_shell.sh + uvhs/enqueue_runtime_command.sh + uvhs/uv_shell_exec_compat.sh + uvhs/runtime_command.tcl user_script/hw_run_download.tcl - src/rtl/common/uvhs_axi64_to_axi256.sv src/rtl/common/uvhs_ddr4_wrapper.sv src/tcl/common/AXI_bridge.tcl src/tcl/common/xdma_ep.tcl @@ -39,6 +41,8 @@ bash -n "$root_dir/uvhs/check_flow_tools.sh" bash -n "$root_dir/uvhs/make_compat/make" bash -n "$root_dir/uvhs/make_compat/csh" bash -n "$root_dir/uvhs/patch_uvsyn_shell.sh" +bash -n "$root_dir/uvhs/enqueue_runtime_command.sh" +bash -n "$root_dir/uvhs/uv_shell_exec_compat.sh" if command -v tclsh >/dev/null 2>&1; then while IFS= read -r -d '' path; do diff --git a/fpga_diff/uvhs/enqueue_runtime_command.sh b/fpga_diff/uvhs/enqueue_runtime_command.sh new file mode 100755 index 00000000..9b706437 --- /dev/null +++ b/fpga_diff/uvhs/enqueue_runtime_command.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -euo pipefail + +if (( $# < 2 )); then + echo "usage: $0 [argument ...]" >&2 + exit 64 +fi + +command_file=$1 +tcl_script=$2 +shift 2 + +if [[ ! -f $tcl_script ]]; then + echo "ERROR: runtime Tcl script not found: $tcl_script" >&2 + exit 2 +fi +if [[ -e $command_file || -e $command_file.running ]]; then + echo "ERROR: a UVHS runtime command is already pending" >&2 + exit 3 +fi + +tcl_quote() { + local value=$1 + value=${value//\\/\\\\} + value=${value//\"/\\\"} + value=${value//\$/\\\$} + value=${value//\[/\\[} + value=${value//\]/\\]} + printf '"%s"' "$value" +} + +mkdir -p "$(dirname "$command_file")" +tmp_file="${command_file}.tmp.$$" +trap 'rm -f "$tmp_file"' EXIT + +{ + printf 'set argv [list' + for argument in "$@"; do + printf ' ' + tcl_quote "$argument" + done + printf ']\nsource ' + tcl_quote "$tcl_script" + printf '\n' +} >"$tmp_file" + +mv -n "$tmp_file" "$command_file" +if [[ -e $tmp_file ]]; then + echo "ERROR: command file appeared while enqueueing: $command_file" >&2 + exit 4 +fi +trap - EXIT +echo "INFO: enqueued UVHS runtime command: $command_file" diff --git a/fpga_diff/uvhs/runtime_command.tcl b/fpga_diff/uvhs/runtime_command.tcl new file mode 100644 index 00000000..b209e161 --- /dev/null +++ b/fpga_diff/uvhs/runtime_command.tcl @@ -0,0 +1,112 @@ +proc uvhs_temp_dir {} { + if {[info exists ::env(UVHS_RUNTIME_TMP_DIR)] && $::env(UVHS_RUNTIME_TMP_DIR) ne ""} { + set path $::env(UVHS_RUNTIME_TMP_DIR) + } else { + set path [pwd] + } + file mkdir $path + return $path +} + +proc uvhs_write_ddr_pairs {input_file rtl_path data_width} { + if {![file exists $input_file]} { + error "DDR workload not found: $input_file" + } + if {![string is integer -strict $data_width] || $data_width ni {64 256}} { + error "unsupported DDR AXI data width: $data_width" + } + + set beat_bytes [expr {$data_width / 8}] + set beat_chars [expr {$data_width / 4}] + set input [open $input_file r] + set segment 0 + set line_number 0 + + while {[gets $input address_text] >= 0} { + incr line_number + if {[gets $input data_text] < 0} { + close $input + error "missing data line after line $line_number" + } + incr line_number + set address_text [string trim $address_text] + set data_text [string trim $data_text] + if {![regexp {^[0-9a-fA-F]+$} $address_text]} { + close $input + error "invalid DDR address on line [expr {$line_number - 1}]: $address_text" + } + if {![regexp {^[0-9a-fA-F]+$} $data_text]} { + close $input + error "invalid DDR data on line $line_number" + } + if {[expr {[string length $data_text] % $beat_chars}] != 0} { + close $input + error "DDR data on line $line_number is not aligned to $data_width bits" + } + if {[scan $address_text %llx byte_address] != 1 || [expr {$byte_address % $beat_bytes}] != 0} { + close $input + error "DDR address is not aligned to $beat_bytes bytes: $address_text" + } + + set beat_count [expr {[string length $data_text] / $beat_chars}] + set start_word [expr {$byte_address / $beat_bytes}] + set end_word [expr {$start_word + $beat_count - 1}] + set temp_file [file join [uvhs_temp_dir] [format "ddr-%d-%d.hex" [pid] $segment]] + incr segment + + set output [open $temp_file w] + for {set beat 0} {$beat < $beat_count} {incr beat} { + set first [expr {[string length $data_text] - ($beat + 1) * $beat_chars}] + puts $output [string range $data_text $first [expr {$first + $beat_chars - 1}]] + } + close $output + + puts [format "INFO: DDR backdoor write %s words 0x%llx..0x%llx" \ + $beat_count $start_word $end_word] + set status [catch { + writemem -rtl $rtl_path -start $start_word -end $end_word -file $temp_file -hex + } message options] + file delete -force $temp_file + if {$status != 0} { + close $input + return -options $options $message + } + } + close $input + puts "INFO: DDR backdoor write completed: $input_file" +} + +if {[llength $argv] == 0} { + error "missing UVHS runtime command" +} + +set uvhs_command [lindex $argv 0] +puts "INFO: executing UVHS runtime command: $uvhs_command" +switch -- $uvhs_command { + halt_soc { + reset -name rstn_sw5 -value 0 + query -reset + } + reset_cpu { + reset -name rstn_sw5 -value 0 + after 500 + reset -name rstn_sw5 -value 1 + after 500 + query -reset + } + write_ddr { + if {[llength $argv] < 4} { + error "write_ddr expects 3 arguments" + } + reset -name rstn_sw5 -value 0 + after 100 + uvhs_write_ddr_pairs [lindex $argv 1] [lindex $argv 2] [lindex $argv 3] + } + stop { + set ::uvhs_keepalive 1 + } + default { + error "unknown UVHS runtime command: $uvhs_command" + } +} +puts "INFO: completed UVHS runtime command: $uvhs_command" diff --git a/fpga_diff/uvhs/timing_common.tcl b/fpga_diff/uvhs/timing_common.tcl index f52e65b2..eada4e05 100644 --- a/fpga_diff/uvhs/timing_common.tcl +++ b/fpga_diff/uvhs/timing_common.tcl @@ -18,15 +18,6 @@ set fpga_diff_cpu_clk_period_ns 40 if {[info exists ::env(UVHS_CPU_CLK_PERIOD_NS)] && $::env(UVHS_CPU_CLK_PERIOD_NS) ne ""} { set fpga_diff_cpu_clk_period_ns $::env(UVHS_CPU_CLK_PERIOD_NS) } -set fpga_diff_cpu_debug_clk 1 -if {[info exists ::env(UVHS_CPU_DEBUG_CLK)] && $::env(UVHS_CPU_DEBUG_CLK) ne ""} { - set fpga_diff_cpu_debug_clk [expr {$::env(UVHS_CPU_DEBUG_CLK) eq "1"}] -} -if {$fpga_diff_cpu_debug_clk} { - create_clock -name CPU_CLK_IN -period $fpga_diff_cpu_clk_period_ns [get_ports [fpga_diff_top_port clk5_p]] -} else { - create_clock -name CPU_CLK_IN -period $fpga_diff_cpu_clk_period_ns [get_ports [fpga_diff_top_port clk6_p]] - create_clock -name DEBUG_CLK_IN -period 40 [get_ports [fpga_diff_top_port clk5_p]] -} +create_clock -name CPU_CLK_IN -period $fpga_diff_cpu_clk_period_ns [get_ports [fpga_diff_top_port clk5_p]] create_clock -name jtag_vclk -period 83.333 [get_ports [fpga_diff_top_port JTAG_TCK]] create_clock -name pcie_ep_refclk -period 10 [get_ports [fpga_diff_top_port pcie_ep_gt_ref_clk_p]] diff --git a/fpga_diff/uvhs/uv_shell_exec_compat.sh b/fpga_diff/uvhs/uv_shell_exec_compat.sh new file mode 100755 index 00000000..43eca7d0 --- /dev/null +++ b/fpga_diff/uvhs/uv_shell_exec_compat.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +: "${UV_ROOT:?UV_ROOT is not set}" + +runtime_library_path=${UVHS_RUNTIME_LIB_DIR:-} +if [[ -n ${UMI_LD_LIBRARY_PATH:-} ]]; then + runtime_library_path=${runtime_library_path:+$runtime_library_path:}$UMI_LD_LIBRARY_PATH +fi +if [[ -n $runtime_library_path ]]; then + export LD_LIBRARY_PATH=$runtime_library_path +fi + +exec "$UV_ROOT/bin/uv_shell_exec" "$@" diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index c769e494..f3701f13 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -4,6 +4,7 @@ PLATFORM ?= U2.2 UVHS_TEMPLATE_DIR ?= UVHS_UVW_AXI4_TO_DDR4_SRC ?= UVHS_UVW_AXI4_TO_DDR4_EXPECTED_MD5 ?= +UVHS_DDR_AXI_WIDTH ?= $(if $(filter nutshell,$(CPU)),64,256) UVHS_WORK_DIR ?= $(ENV_SCRIPTS_HOME)/fpga_diff_uvhs_$(CPU)$(if $(strip $(SUFFIX)),-$(strip $(SUFFIX)),) UVHS_TOP ?= fpga_top_debug UVHS_FILELIST ?= $(UVHS_WORK_DIR)/rtl/filelist.f @@ -23,7 +24,6 @@ UVHS_ASSIGN_PIN_FILE ?= $(UVHS_ROOT_DIR)/uvhs/assign_pin_u22_f2.tcl UVHS_TIMING_FILE ?= $(UVHS_ROOT_DIR)/uvhs/timing_common.tcl UVHS_ASSEMBLE_FILE ?= $(UVHS_ROOT_DIR)/uvhs/assemble_uvhs.tcl UVHS_CPU_CLK_PERIOD_NS ?= 40 -UVHS_CPU_DEBUG_CLK ?= 1 UVHS_USE_LSF ?= 0 UVHS_FRONTEND_THREADS ?= 4 UVHS_FRONTEND_PROCESSES ?= 16 @@ -54,10 +54,30 @@ UVHS_REQUIRED_DCP_MODULES := blk_mem_gen_0 AXI_bridge data_bridge xdma_ep uvw_ax UVHS_REQUIRED_MODULES ?= $(if $(filter nanhu,$(CPU)),XlnFpgaTop,$(if $(filter kmh nutshell,$(CPU)),SimTop,)) UVHS_DDR_RTL_INST := $(UVHS_TOP).core_def.U_UVHS_UVW_AXI4_TO_DDR4 UVHS_RUNTIME_LIB_DIR ?= $(UVHS_WORK_DIR)/.uvhs-runtime-lib +UVHS_RUNTIME_DB ?= $(UVHS_WORK_DIR)/hw.dat +UVHS_RUNTIME_WORK_DIR ?= $(UVHS_WORK_DIR)/runtime-work +UVHS_RUNTIME_COMMAND_FILE ?= $(UVHS_RUNTIME_WORK_DIR)/command.tcl +UVHS_RUNTIME_TMP_DIR ?= $(UVHS_RUNTIME_WORK_DIR)/tmp +UVHS_RUNTIME_DOWNLOAD_SCRIPT ?= $(UVHS_ROOT_DIR)/user_script/hw_run_download.tcl +UVHS_RUNTIME_COMMAND_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/runtime_command.tcl +UVHS_RUNTIME_DDR_RTL ?= $(UVHS_DDR_RTL_INST).ddr4_ip +UVHS_COMPAT_PCRE_LIB ?= +UVHS_SHELL_EXEC_WRAPPER ?= $(UVHS_ROOT_DIR)/uvhs/uv_shell_exec_compat.sh -UVHS_FLOW_ENV = \ +FPGA_WRITE_BITSTREAM_IMPL := uvhs_download +FPGA_HALT_SOC_IMPL := uvhs_halt_soc +FPGA_WRITE_DDR_IMPL := uvhs_write_ddr +FPGA_WRITE_FLASH_IMPL := uvhs_write_flash +FPGA_RESET_CPU_IMPL := uvhs_reset_cpu + +UVHS_TOOL_ENV = \ PATH="$(UVHS_ROOT_DIR)/uvhs/make_compat:$$UV_ROOT/bin:$$UV_ROOT/lib/venv3.8/bin:$$UV_ROOT/lib/gcc10.3/bin:$$PATH" \ LD_LIBRARY_PATH="$(UVHS_RUNTIME_LIB_DIR):$${LD_LIBRARY_PATH:-}" \ + UVHS_RUNTIME_LIB_DIR="$(UVHS_RUNTIME_LIB_DIR)" \ + UVSHELL_EXEC_NAME="$(UVHS_SHELL_EXEC_WRAPPER)" + +UVHS_FLOW_ENV = \ + $(UVHS_TOOL_ENV) \ UVHS_FLOW=1 \ PLATFORM="$(PLATFORM)" \ XDMA_LINK_WIDTH="$(XDMA_LINK_WIDTH)" \ @@ -70,7 +90,6 @@ UVHS_FLOW_ENV = \ UVHS_TARGET_FPGA_LOWER="$(UVHS_TARGET_FPGA_LOWER)" \ UVHS_KEEP_FPGAS="$(UVHS_KEEP_FPGAS)" \ UVHS_CPU_CLK_PERIOD_NS="$(UVHS_CPU_CLK_PERIOD_NS)" \ - UVHS_CPU_DEBUG_CLK="$(UVHS_CPU_DEBUG_CLK)" \ UVHS_PNR_STRATEGY="$(UVHS_PNR_STRATEGY)" \ UVHS_COMPILE_STRATEGY_NUM="$(UVHS_COMPILE_STRATEGY_NUM)" \ UVHS_COMPILE_STRATEGY0="$(UVHS_COMPILE_STRATEGY0)" \ @@ -85,7 +104,9 @@ UVHS_BIT_HOME ?= $(UVHS_WORK_DIR)/ready-to-program .PHONY: uvhs_preflight uvhs_prepare uvhs_export_vivado_ip \ uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist uvhs_check_modules \ uvhs_frontend uvhs_backend uvhs_all uvhs_check_timing \ - uvhs_package_bitstream uvhs_tools_check uvhs_clean + uvhs_package_bitstream uvhs_tools_check uvhs_clean uvhs_download \ + uvhs_halt_soc uvhs_reset_cpu uvhs_write_ddr uvhs_write_flash \ + uvhs_runtime_stop uvhs_preflight: test -n "$$UV_ROOT" @@ -93,6 +114,8 @@ uvhs_preflight: test -n "$$UV_XILINX_VIVADO" test -x "$$UV_XILINX_VIVADO/bin/vivado" test -n "$$UV_LICENSE" + test -x "$$UV_ROOT/bin/uv_shell_exec" + test -x "$(UVHS_SHELL_EXEC_WRAPPER)" test -d "$(UVHS_TEMPLATE_DIR)/script" test -f "$(UVHS_TEMPLATE_DIR)/Makefile" test -f "$(UVHS_TEMPLATE_DIR)/script/1B_4F_HGC_assemble.tcl" @@ -101,7 +124,18 @@ uvhs_preflight: bash -c 'set -euo pipefail; \ ffi="$$(ldconfig -p | awk '\''/libffi[.]so[.]6 / { print $$NF; exit } /libffi[.]so[.]8 / { fallback = $$NF } END { if (fallback != "") print fallback }'\'')"; \ test -n "$$ffi"; \ - ln -sfn "$$ffi" "$(UVHS_RUNTIME_LIB_DIR)/libffi.so.6"' + ln -sfn "$$ffi" "$(UVHS_RUNTIME_LIB_DIR)/libffi.so.6"; \ + pcre="$(UVHS_COMPAT_PCRE_LIB)"; \ + if [ -z "$$pcre" ] && ldd "$$UV_ROOT/bin/uv_shell_exec" 2>/dev/null | grep -q "libpcre[.]so[.]1 => not found"; then \ + for candidate in "$$UV_ROOT/shlib_install/libpcre.so.1" "$$UV_ROOT/shlib/libpcre.so.1"; do \ + if [ -f "$$candidate" ]; then pcre="$$candidate"; break; fi; \ + done; \ + if [ -z "$$pcre" ]; then \ + echo "ERROR: uv_shell_exec needs libpcre.so.1; set UVHS_COMPAT_PCRE_LIB" >&2; \ + exit 1; \ + fi; \ + fi; \ + if [ -n "$$pcre" ]; then test -f "$$pcre"; ln -sfn "$$pcre" "$(UVHS_RUNTIME_LIB_DIR)/libpcre.so.1"; fi' uvhs_tools_check: bash "$(UVHS_ROOT_DIR)/uvhs/check_flow_tools.sh" @@ -140,6 +174,11 @@ uvhs_sync_uvw_axi4_to_ddr4: uvhs_prepare if [ -n "$$found" ]; then mkdir -p "$$(dirname "$$dst")"; cp -f "$$found" "$$dst"; fi; \ done; \ for rel in $(UVHS_UVW_AXI4_TO_DDR4_REQUIRED_FILES); do test -s "$$work/$$rel"; done; \ + expected_width="$(UVHS_DDR_AXI_WIDTH)"; last_bit="$$((expected_width - 1))"; \ + stub="$$work/rtl/soc/uvw_axi4_to_ddr4_Stub.v"; \ + grep -Eq "input[[:space:]]+\\[$$last_bit:0\\][[:space:]]*ddr4ip_dut_axi_wdata" "$$stub"; \ + grep -Eq "output[[:space:]]+\\[$$last_bit:0\\][[:space:]]*ddr4ip_dut_axi_rdata" "$$stub"; \ + echo "INFO: verified UVHS DDR DCP AXI data width: $$expected_width"; \ if [ -n "$(UVHS_UVW_AXI4_TO_DDR4_EXPECTED_MD5)" ]; then \ echo "$(UVHS_UVW_AXI4_TO_DDR4_EXPECTED_MD5) $$work/rtl/soc/uvw_axi4_to_ddr4.dcp" | md5sum -c -; \ fi' @@ -150,7 +189,7 @@ uvhs_filelist: printf '+define+SYNTHESIS\n+define+XIANGSHAN_FPGA\n'; \ printf '+define+RANDOMIZE_GARBAGE_ASSIGN\n+define+RANDOMIZE_REG_INIT\n'; \ printf '+define+RANDOMIZE_MEM_INIT\n+define+RANDOMIZE_DELAY=1\n'; \ - printf '+define+UVHS_SOC_ADAPT\n+define+UVHS_UVW_AXI4_TO_DDR4\n'; \ + printf '+define+UVHS\n'; \ printf '+define+DDR4_16G_X8\n+define+DQ64\n+define+DDR4_2400\n'; \ printf '+define+DQ=64\n+define+MICRON_DDR\n+define+DDR4_16Gbx8\n'; \ printf '+define+DDR4\n+define+SRAM_SYN\n+define+DATA_VERSION=0\n'; \ @@ -166,7 +205,6 @@ uvhs_filelist: printf '+define+CONFIG_SIMTOP_HAS_DMA\n'; \ fi; \ fi; \ - if [ "$(UVHS_CPU_DEBUG_CLK)" = 1 ]; then printf '+define+UVHS_CPU_DEBUG_CLK\n'; fi; \ if [ -n "$(CHI_DIR)" ]; then printf '+define+MSI_MODE\n+define+CONFIG_USE_XSCORE_CHI\n'; \ else printf '+define+CONFIG_USE_XSCORE_AXI\n'; fi; \ if [ -d "$(CORE_DIR)/build" ]; then printf '+incdir+%s/build\n' "$(CORE_DIR)"; fi; \ @@ -236,6 +274,43 @@ uvhs_package_bitstream: uvhs_check_timing ln -sf "$(UVHS_BITSTREAM_DIR)/pnr.bit" "$(UVHS_BIT_HOME)/fpga_top_debug.bit" @echo "FPGA_BIT_HOME=$(UVHS_BIT_HOME)" +# Runtime stays in the foreground because uv_shell owns the board session. +# Use another shell for the command targets below while this target is active. +uvhs_download: + test -d "$(UVHS_RUNTIME_DB)" + test -f "$(UVHS_RUNTIME_DOWNLOAD_SCRIPT)" + test ! -e "$(UVHS_RUNTIME_COMMAND_FILE)" + test ! -e "$(UVHS_RUNTIME_COMMAND_FILE).running" + mkdir -p "$(UVHS_RUNTIME_WORK_DIR)" "$(UVHS_RUNTIME_TMP_DIR)" + $(UVHS_TOOL_ENV) UVHS_DB_PATH="$(UVHS_RUNTIME_DB)" \ + UVHS_COMMAND_FILE="$(UVHS_RUNTIME_COMMAND_FILE)" \ + UVHS_RUNTIME_TMP_DIR="$(UVHS_RUNTIME_TMP_DIR)" \ + bash "$$UV_ROOT/bin/uv_shell" -rt_shell \ + -workdir "$(UVHS_RUNTIME_WORK_DIR)" \ + -script "$(UVHS_RUNTIME_DOWNLOAD_SCRIPT)" + +uvhs_halt_soc: + bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ + "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" halt_soc + +uvhs_reset_cpu: + bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ + "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" reset_cpu + +uvhs_write_ddr: + test -f "$(WORKLOAD)" + bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ + "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" \ + write_ddr "$(WORKLOAD)" "$(UVHS_RUNTIME_DDR_RTL)" "$(UVHS_DDR_AXI_WIDTH)" + +uvhs_write_flash: + @echo "ERROR: the current UVHS runtime DB does not expose flash as a writable memory" >&2 + @exit 2 + +uvhs_runtime_stop: + bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ + "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" stop + uvhs_clean: test -n "$(UVHS_WORK_DIR)" rm -rf "$(UVHS_WORK_DIR)" From e47a6101d31b505fa6982c30e61e698a11c0ee48 Mon Sep 17 00:00:00 2001 From: klin02 Date: Wed, 29 Jul 2026 23:56:24 +0800 Subject: [PATCH 05/62] feat(fpga_diff): add UVHS flash programming Connect a 64-bit UVHS generalBus to the existing BRAM-backed flash through AXI_bridge and verify each raw image with a full readback. Expose standalone uvhs_* build and runtime targets while keeping the normal Vivado and JTAG commands unchanged. Make attached runtime commands report completion and propagate failures. Co-authored-by: Kamimiao --- fpga_diff/Makefile | 50 +++------ fpga_diff/README.md | 9 +- fpga_diff/src/rtl/common/core_def_xdma.sv | 128 ++++++++++++++++++++++ fpga_diff/src/tcl/common/AXI_bridge.tcl | 73 +++++++++++- fpga_diff/user_script/hw_run_download.tcl | 19 +++- fpga_diff/uvhs/README.md | 71 ++++++------ fpga_diff/uvhs/enqueue_runtime_command.sh | 32 +++++- fpga_diff/uvhs/frontend_run.tcl | 5 +- fpga_diff/uvhs/runtime_command.tcl | 91 +++++++++++++++ fpga_diff/uvhs/uvhs.mk | 97 +++++++++++++--- 10 files changed, 483 insertions(+), 92 deletions(-) diff --git a/fpga_diff/Makefile b/fpga_diff/Makefile index db95ff96..200789b8 100755 --- a/fpga_diff/Makefile +++ b/fpga_diff/Makefile @@ -23,20 +23,8 @@ PRJ_NAME = fpga_$(CPU)$(if $(strip $(SUFFIX)),-$(strip $(SUFFIX)),) PRJ_DIR ?= $(ENV_SCRIPTS_HOME)/$(PRJ_NAME) PRJ ?= $(PRJ_DIR)/$(PRJ_NAME).xpr -FPGA_WRITE_BITSTREAM_IMPL ?= vivado_write_bitstream -FPGA_HALT_SOC_IMPL ?= vivado_halt_soc -FPGA_WRITE_DDR_IMPL ?= vivado_write_jtag_ddr -FPGA_WRITE_FLASH_IMPL ?= vivado_write_jtag_flash -FPGA_RESET_CPU_IMPL ?= vivado_reset_cpu - -ifeq ($(UVHS),1) -include uvhs/uvhs.mk -endif - .PHONY: bitstream vivado dump_ila update_core_flist \ - write_bitstream halt_soc write_jtag_ddr write_jtag_flash reset_cpu \ - vivado_write_bitstream vivado_halt_soc vivado_write_jtag_ddr \ - vivado_write_jtag_flash vivado_reset_cpu + write_bitstream halt_soc write_jtag_ddr write_jtag_flash reset_cpu # Get Vivado version VIVADO_VERSION := $(shell vivado -version 2>/dev/null | head -1 | grep -o '[0-9]\{4\}\.[0-9]' || echo "unknown") @@ -64,38 +52,28 @@ vivado: check_vivado_version check_version: vivado -mode batch -source src/tcl/common/check_version.tcl -tclargs --vivado_version $(VIVADO_VERSION) --cpu $(CPU) --project_name $(PRJ_NAME) -# Program the selected FPGA backend. -write_bitstream: $(FPGA_WRITE_BITSTREAM_IMPL) - -vivado_write_bitstream: +# Write bitstream to FPGA via PCIe +write_bitstream: sh tools/pcie-remove.sh vivado -mode tcl -source tools/write_bitstream.tcl -tclargs $(FPGA_BIT_HOME) sh tools/pcie-rescan.sh vivado -mode tcl -source tools/reset_ddr.tcl -tclargs $(FPGA_BIT_HOME)/fpga_top_debug.ltx - $(MAKE) vivado_reset_cpu - -# Halt the FPGA SoC before loading memory. -halt_soc: $(FPGA_HALT_SOC_IMPL) + $(MAKE) reset_cpu -vivado_halt_soc: +# Halt the FPGA SoC (for Write Jtag DDR) +halt_soc: vivado -mode tcl -source tools/halt_soc.tcl -tclargs $(FPGA_BIT_HOME)/fpga_top_debug.ltx -# Load a workload into FPGA DDR. -write_jtag_ddr: $(FPGA_WRITE_DDR_IMPL) - -vivado_write_jtag_ddr: +# Write workload to FPGA DDR via JTAG +write_jtag_ddr: vivado -mode tcl -source tools/jtag_write_ddr.tcl -tclargs $(WORKLOAD) $(AXI_WIDTH) -# Load a raw binary image into the BRAM-backed flash. -write_jtag_flash: $(FPGA_WRITE_FLASH_IMPL) - -vivado_write_jtag_flash: +# Write a raw binary image to the BRAM-backed flash via the flash-only JTAG AXI +write_jtag_flash: vivado -mode tcl -source tools/jtag_write_flash.tcl -tclargs $(WORKLOAD) -# Reset the CPU on the selected FPGA backend. -reset_cpu: $(FPGA_RESET_CPU_IMPL) - -vivado_reset_cpu: +# Reset CPU on FPGA +reset_cpu: vivado -mode tcl -source tools/reset_cpu.tcl -tclargs $(FPGA_BIT_HOME)/fpga_top_debug.ltx ILA_OUT ?= $(ENV_SCRIPTS_HOME)/ila-dump @@ -122,3 +100,7 @@ get_synth_log: all: $(MAKE) update_core_flist CORE_DIR="$(CORE_DIR)" RTL_INCLUDE="$(RTL_INCLUDE)" $(MAKE) vivado CPU=$(CPU) SUFFIX="$(SUFFIX)" + +# UVHS targets use an explicit uvhs_* namespace and do not replace the normal +# Vivado/JTAG targets above. +include uvhs/uvhs.mk diff --git a/fpga_diff/README.md b/fpga_diff/README.md index 8023ad79..1811b8c5 100755 --- a/fpga_diff/README.md +++ b/fpga_diff/README.md @@ -51,12 +51,13 @@ FPGA_DDR_LOAD_CMD="bash -lc ' \ UVHS Flow ========= -The Hejian UVHS flow is opt-in and leaves the targets above unchanged. Configure -the UVHS tool environment in the runtime host shell, then invoke: +The Hejian UVHS flow uses separate `uvhs_*` targets and leaves the targets above +unchanged. Configure the UVHS tool environment in the runtime host shell, then +invoke: ```shell -make UVHS=1 uvhs_preflight CPU= -make UVHS=1 uvhs_all CPU= CORE_DIR=/path/to/generated/core SUFFIX= +make uvhs_preflight CPU= +make uvhs_all CPU= CORE_DIR=/path/to/generated/core SUFFIX= ``` See [`uvhs/README.md`](uvhs/README.md) for the required environment variables, diff --git a/fpga_diff/src/rtl/common/core_def_xdma.sv b/fpga_diff/src/rtl/common/core_def_xdma.sv index 1ec1cfe6..64cd4c05 100755 --- a/fpga_diff/src/rtl/common/core_def_xdma.sv +++ b/fpga_diff/src/rtl/common/core_def_xdma.sv @@ -1000,6 +1000,93 @@ wire [1 : 0] rom_axi_rresp ; (*mark_debug = "true"*) wire rom_axi_rvalid ; (*mark_debug = "true"*) wire rom_axi_rlast ; (*mark_debug = "true"*) wire rom_axi_rready ; + +`ifdef UVHS +wire [7:0] uvhs_flash_axi_awid; +wire [31:0] uvhs_flash_axi_awaddr; +wire [3:0] uvhs_flash_axi_awlen; +wire [2:0] uvhs_flash_axi_awsize; +wire [1:0] uvhs_flash_axi_awburst; +wire [1:0] uvhs_flash_axi_awlock; +wire [3:0] uvhs_flash_axi_awcache; +wire [2:0] uvhs_flash_axi_awprot; +wire [3:0] uvhs_flash_axi_awqos; +wire uvhs_flash_axi_awvalid; +wire uvhs_flash_axi_awready; +wire [7:0] uvhs_flash_axi_wid; +wire [63:0] uvhs_flash_axi_wdata; +wire [7:0] uvhs_flash_axi_wstrb; +wire uvhs_flash_axi_wlast; +wire uvhs_flash_axi_wvalid; +wire uvhs_flash_axi_wready; +wire [7:0] uvhs_flash_axi_bid; +wire [1:0] uvhs_flash_axi_bresp; +wire uvhs_flash_axi_bvalid; +wire uvhs_flash_axi_bready; +wire [7:0] uvhs_flash_axi_arid; +wire [31:0] uvhs_flash_axi_araddr; +wire [3:0] uvhs_flash_axi_arlen; +wire [2:0] uvhs_flash_axi_arsize; +wire [1:0] uvhs_flash_axi_arburst; +wire [1:0] uvhs_flash_axi_arlock; +wire [3:0] uvhs_flash_axi_arcache; +wire [2:0] uvhs_flash_axi_arprot; +wire [3:0] uvhs_flash_axi_arqos; +wire uvhs_flash_axi_arvalid; +wire uvhs_flash_axi_arready; +wire [7:0] uvhs_flash_axi_rid; +wire [63:0] uvhs_flash_axi_rdata; +wire [1:0] uvhs_flash_axi_rresp; +wire uvhs_flash_axi_rlast; +wire uvhs_flash_axi_rvalid; +wire uvhs_flash_axi_rready; + +uvw_general_bus U_UVHS_FLASH_GBUS ( + .dut_axi_aclk (sys_clk_i), + .dut_axi_aclk_en (1'b1), + .dut_axi_aresetn (axi_bclk_sync_rstn), + .dut_axi_awid (uvhs_flash_axi_awid), + .dut_axi_awaddr (uvhs_flash_axi_awaddr), + .dut_axi_awlen (uvhs_flash_axi_awlen), + .dut_axi_awsize (uvhs_flash_axi_awsize), + .dut_axi_awburst (uvhs_flash_axi_awburst), + .dut_axi_awlock (uvhs_flash_axi_awlock), + .dut_axi_awcache (uvhs_flash_axi_awcache), + .dut_axi_awprot (uvhs_flash_axi_awprot), + .dut_axi_awqos (uvhs_flash_axi_awqos), + .dut_axi_awvalid (uvhs_flash_axi_awvalid), + .dut_axi_awready (uvhs_flash_axi_awready), + .dut_axi_wid (uvhs_flash_axi_wid), + .dut_axi_wdata (uvhs_flash_axi_wdata), + .dut_axi_wstrb (uvhs_flash_axi_wstrb), + .dut_axi_wlast (uvhs_flash_axi_wlast), + .dut_axi_wvalid (uvhs_flash_axi_wvalid), + .dut_axi_wready (uvhs_flash_axi_wready), + .dut_axi_bid (uvhs_flash_axi_bid), + .dut_axi_bresp (uvhs_flash_axi_bresp), + .dut_axi_bvalid (uvhs_flash_axi_bvalid), + .dut_axi_bready (uvhs_flash_axi_bready), + .dut_axi_arid (uvhs_flash_axi_arid), + .dut_axi_araddr (uvhs_flash_axi_araddr), + .dut_axi_arlen (uvhs_flash_axi_arlen), + .dut_axi_arsize (uvhs_flash_axi_arsize), + .dut_axi_arburst (uvhs_flash_axi_arburst), + .dut_axi_arlock (uvhs_flash_axi_arlock), + .dut_axi_arcache (uvhs_flash_axi_arcache), + .dut_axi_arprot (uvhs_flash_axi_arprot), + .dut_axi_arqos (uvhs_flash_axi_arqos), + .dut_axi_arvalid (uvhs_flash_axi_arvalid), + .dut_axi_arready (uvhs_flash_axi_arready), + .dut_axi_rid (uvhs_flash_axi_rid), + .dut_axi_rdata (uvhs_flash_axi_rdata), + .dut_axi_rresp (uvhs_flash_axi_rresp), + .dut_axi_rlast (uvhs_flash_axi_rlast), + .dut_axi_rvalid (uvhs_flash_axi_rvalid), + .dut_axi_rready (uvhs_flash_axi_rready), + .sysbus_ghbd_o (), + .sysbus_ghbd_i () +); +`endif `endif `ifdef XS_QSPI2ROM @@ -1739,6 +1826,47 @@ AXI_bridge CFG_AXI_bridge_i .S00_AXI_wstrb (cpu2cfg_m2s_wstrb), .S00_AXI_wvalid (cpu2cfg_m2s_wvalid), +`ifdef UVHS + .UVHS_FLASH_AXI_araddr (uvhs_flash_axi_araddr), + .UVHS_FLASH_AXI_arburst (uvhs_flash_axi_arburst), + .UVHS_FLASH_AXI_arcache (uvhs_flash_axi_arcache), + .UVHS_FLASH_AXI_arid (uvhs_flash_axi_arid), + .UVHS_FLASH_AXI_arlen (uvhs_flash_axi_arlen), + .UVHS_FLASH_AXI_arlock (uvhs_flash_axi_arlock), + .UVHS_FLASH_AXI_arprot (uvhs_flash_axi_arprot), + .UVHS_FLASH_AXI_arqos (uvhs_flash_axi_arqos), + .UVHS_FLASH_AXI_arready (uvhs_flash_axi_arready), + .UVHS_FLASH_AXI_arsize (uvhs_flash_axi_arsize), + .UVHS_FLASH_AXI_arvalid (uvhs_flash_axi_arvalid), + .UVHS_FLASH_AXI_awaddr (uvhs_flash_axi_awaddr), + .UVHS_FLASH_AXI_awburst (uvhs_flash_axi_awburst), + .UVHS_FLASH_AXI_awcache (uvhs_flash_axi_awcache), + .UVHS_FLASH_AXI_awid (uvhs_flash_axi_awid), + .UVHS_FLASH_AXI_awlen (uvhs_flash_axi_awlen), + .UVHS_FLASH_AXI_awlock (uvhs_flash_axi_awlock), + .UVHS_FLASH_AXI_awprot (uvhs_flash_axi_awprot), + .UVHS_FLASH_AXI_awqos (uvhs_flash_axi_awqos), + .UVHS_FLASH_AXI_awready (uvhs_flash_axi_awready), + .UVHS_FLASH_AXI_awsize (uvhs_flash_axi_awsize), + .UVHS_FLASH_AXI_awvalid (uvhs_flash_axi_awvalid), + .UVHS_FLASH_AXI_bid (uvhs_flash_axi_bid), + .UVHS_FLASH_AXI_bready (uvhs_flash_axi_bready), + .UVHS_FLASH_AXI_bresp (uvhs_flash_axi_bresp), + .UVHS_FLASH_AXI_bvalid (uvhs_flash_axi_bvalid), + .UVHS_FLASH_AXI_rdata (uvhs_flash_axi_rdata), + .UVHS_FLASH_AXI_rid (uvhs_flash_axi_rid), + .UVHS_FLASH_AXI_rlast (uvhs_flash_axi_rlast), + .UVHS_FLASH_AXI_rready (uvhs_flash_axi_rready), + .UVHS_FLASH_AXI_rresp (uvhs_flash_axi_rresp), + .UVHS_FLASH_AXI_rvalid (uvhs_flash_axi_rvalid), + .UVHS_FLASH_AXI_wdata (uvhs_flash_axi_wdata), + .UVHS_FLASH_AXI_wid (uvhs_flash_axi_wid), + .UVHS_FLASH_AXI_wlast (uvhs_flash_axi_wlast), + .UVHS_FLASH_AXI_wready (uvhs_flash_axi_wready), + .UVHS_FLASH_AXI_wstrb (uvhs_flash_axi_wstrb), + .UVHS_FLASH_AXI_wvalid (uvhs_flash_axi_wvalid), +`endif + .SYS_CFG_APB_paddr (syscfg_paddr_mix), .SYS_CFG_APB_penable (syscfg_penable), .SYS_CFG_APB_prdata (syscfg_prdata), diff --git a/fpga_diff/src/tcl/common/AXI_bridge.tcl b/fpga_diff/src/tcl/common/AXI_bridge.tcl index f33eb947..59b5783d 100644 --- a/fpga_diff/src/tcl/common/AXI_bridge.tcl +++ b/fpga_diff/src/tcl/common/AXI_bridge.tcl @@ -190,6 +190,7 @@ proc create_root_design { parentCell } { # Set parent object as current current_bd_instance $parentObj + set uvhs_flow [expr {[info exists ::env(UVHS_FLOW)] && $::env(UVHS_FLOW) eq "1"}] # Create interface ports set S00_AXI [ create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S00_AXI ] @@ -224,6 +225,40 @@ proc create_root_design { parentCell } { CONFIG.WUSER_WIDTH {0} \ ] $S00_AXI + if {$uvhs_flow} { + set UVHS_FLASH_AXI [ create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 UVHS_FLASH_AXI ] + set_property -dict [ list \ + CONFIG.ADDR_WIDTH {32} \ + CONFIG.ARUSER_WIDTH {0} \ + CONFIG.AWUSER_WIDTH {0} \ + CONFIG.BUSER_WIDTH {0} \ + CONFIG.DATA_WIDTH {64} \ + CONFIG.FREQ_HZ {25000000} \ + CONFIG.HAS_BRESP {1} \ + CONFIG.HAS_BURST {1} \ + CONFIG.HAS_CACHE {1} \ + CONFIG.HAS_LOCK {1} \ + CONFIG.HAS_PROT {1} \ + CONFIG.HAS_QOS {1} \ + CONFIG.HAS_REGION {0} \ + CONFIG.HAS_RRESP {1} \ + CONFIG.HAS_WSTRB {1} \ + CONFIG.ID_WIDTH {8} \ + CONFIG.MAX_BURST_LENGTH {16} \ + CONFIG.NUM_READ_OUTSTANDING {2} \ + CONFIG.NUM_READ_THREADS {1} \ + CONFIG.NUM_WRITE_OUTSTANDING {2} \ + CONFIG.NUM_WRITE_THREADS {1} \ + CONFIG.PROTOCOL {AXI3} \ + CONFIG.READ_WRITE_MODE {READ_WRITE} \ + CONFIG.RUSER_BITS_PER_BYTE {0} \ + CONFIG.RUSER_WIDTH {0} \ + CONFIG.SUPPORTS_NARROW_BURST {1} \ + CONFIG.WUSER_BITS_PER_BYTE {0} \ + CONFIG.WUSER_WIDTH {0} \ + ] $UVHS_FLASH_AXI + } + set SYS_CFG_APB [ create_bd_intf_port -mode Master -vlnv xilinx.com:interface:apb_rtl:1.0 SYS_CFG_APB ] set UART_0 [ create_bd_intf_port -mode Master -vlnv xilinx.com:interface:uart_rtl:1.0 UART_0 ] @@ -247,15 +282,18 @@ proc create_root_design { parentCell } { # Create ports set ACLK [ create_bd_port -dir I -type clk -freq_hz 25000000 ACLK ] + set aclk_busif rom_axi + if {$uvhs_flow} { + append aclk_busif :UVHS_FLASH_AXI + } set_property -dict [ list \ - CONFIG.ASSOCIATED_BUSIF {rom_axi} \ + CONFIG.ASSOCIATED_BUSIF $aclk_busif \ ] $ACLK set ARESETN [ create_bd_port -dir I -type rst ARESETN ] set SYS_INTER_CLK [ create_bd_port -dir I -type clk -freq_hz 25000000 SYS_INTER_CLK ] set_property -dict [ list \ CONFIG.ASSOCIATED_BUSIF {S00_AXI} \ ] $SYS_INTER_CLK - set uvhs_flow [expr {[info exists ::env(UVHS_FLOW)] && $::env(UVHS_FLOW) eq "1"}] if {$uvhs_flow} { set_property CONFIG.ASSOCIATED_RESET {ARESETN} $ACLK set_property CONFIG.POLARITY {ACTIVE_LOW} $ARESETN @@ -274,9 +312,10 @@ proc create_root_design { parentCell } { # Create instance: axi_interconnect_0, and set properties set axi_interconnect_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 axi_interconnect_0 ] + set axi_slave_count [expr {$uvhs_flow ? 3 : 2}] set_property -dict [ list \ CONFIG.NUM_MI {4} \ - CONFIG.NUM_SI {2} \ + CONFIG.NUM_SI $axi_slave_count \ ] $axi_interconnect_0 # Create instance: extllc_bram_ctrl, and set properties @@ -330,10 +369,28 @@ proc create_root_design { parentCell } { connect_bd_intf_net -intf_net axi_interconnect_0_M03_AXI [get_bd_intf_pins axi_interconnect_0/M03_AXI] [get_bd_intf_pins extllc_bram_ctrl/S_AXI] connect_bd_intf_net -intf_net extllc_bram_ctrl_BRAM_PORTA [get_bd_intf_pins extllc_bram_ctrl/BRAM_PORTA] [get_bd_intf_pins extllc_bram/BRAM_PORTA] connect_bd_intf_net -intf_net jtag_axi_flash_M_AXI [get_bd_intf_pins axi_interconnect_0/S01_AXI] [get_bd_intf_pins jtag_axi_flash/M_AXI] + if {$uvhs_flow} { + connect_bd_intf_net -intf_net UVHS_FLASH_AXI_0_1 [get_bd_intf_ports UVHS_FLASH_AXI] [get_bd_intf_pins axi_interconnect_0/S02_AXI] + } connect_bd_intf_net -intf_net axi_uart16550_0_UART [get_bd_intf_ports UART_0] [get_bd_intf_pins axi_uart16550_0/UART] # Create port connections - connect_bd_net -net ACLK_0_1 [get_bd_ports ACLK] [get_bd_pins axi_apb_bridge_0/s_axi_aclk] [get_bd_pins axi_interconnect_0/ACLK] [get_bd_pins axi_interconnect_0/M00_ACLK] [get_bd_pins axi_interconnect_0/M01_ACLK] [get_bd_pins axi_interconnect_0/M02_ACLK] [get_bd_pins axi_interconnect_0/M03_ACLK] [get_bd_pins axi_interconnect_0/S01_ACLK] [get_bd_pins axi_uart16550_0/s_axi_aclk] [get_bd_pins extllc_bram_ctrl/s_axi_aclk] [get_bd_pins jtag_axi_flash/aclk] + set aclk_pins [list \ + [get_bd_pins axi_apb_bridge_0/s_axi_aclk] \ + [get_bd_pins axi_interconnect_0/ACLK] \ + [get_bd_pins axi_interconnect_0/M00_ACLK] \ + [get_bd_pins axi_interconnect_0/M01_ACLK] \ + [get_bd_pins axi_interconnect_0/M02_ACLK] \ + [get_bd_pins axi_interconnect_0/M03_ACLK] \ + [get_bd_pins axi_interconnect_0/S01_ACLK] \ + [get_bd_pins axi_uart16550_0/s_axi_aclk] \ + [get_bd_pins extllc_bram_ctrl/s_axi_aclk] \ + [get_bd_pins jtag_axi_flash/aclk] \ + ] + if {$uvhs_flow} { + lappend aclk_pins [get_bd_pins axi_interconnect_0/S02_ACLK] + } + connect_bd_net -net ACLK_0_1 [get_bd_ports ACLK] {*}$aclk_pins set aresetn_pins [list \ [get_bd_pins axi_apb_bridge_0/s_axi_aresetn] \ [get_bd_pins axi_interconnect_0/ARESETN] \ @@ -348,6 +405,8 @@ proc create_root_design { parentCell } { ] if {!$uvhs_flow} { lappend aresetn_pins [get_bd_pins axi_interconnect_0/S00_ARESETN] + } else { + lappend aresetn_pins [get_bd_pins axi_interconnect_0/S02_ARESETN] } connect_bd_net -net ARESETN_0_1 [get_bd_ports ARESETN] {*}$aresetn_pins connect_bd_net -net SYS_INTER_CLK_1 [get_bd_ports SYS_INTER_CLK] [get_bd_pins axi_interconnect_0/S00_ACLK] @@ -366,6 +425,12 @@ proc create_root_design { parentCell } { exclude_bd_addr_seg -target_address_space [get_bd_addr_spaces jtag_axi_flash/Data] [get_bd_addr_segs SYS_CFG_APB/Reg] exclude_bd_addr_seg -target_address_space [get_bd_addr_spaces jtag_axi_flash/Data] [get_bd_addr_segs axi_uart16550_0/S_AXI/Reg] exclude_bd_addr_seg -target_address_space [get_bd_addr_spaces jtag_axi_flash/Data] [get_bd_addr_segs extllc_bram_ctrl/S_AXI/Mem0] + if {$uvhs_flow} { + assign_bd_address -offset 0x10000000 -range 0x00100000 -target_address_space [get_bd_addr_spaces UVHS_FLASH_AXI] [get_bd_addr_segs rom_axi/Reg] -force + exclude_bd_addr_seg -target_address_space [get_bd_addr_spaces UVHS_FLASH_AXI] [get_bd_addr_segs SYS_CFG_APB/Reg] + exclude_bd_addr_seg -target_address_space [get_bd_addr_spaces UVHS_FLASH_AXI] [get_bd_addr_segs axi_uart16550_0/S_AXI/Reg] + exclude_bd_addr_seg -target_address_space [get_bd_addr_spaces UVHS_FLASH_AXI] [get_bd_addr_segs extllc_bram_ctrl/S_AXI/Mem0] + } # Restore current instance diff --git a/fpga_diff/user_script/hw_run_download.tcl b/fpga_diff/user_script/hw_run_download.tcl index 2b4665db..bf30a595 100644 --- a/fpga_diff/user_script/hw_run_download.tcl +++ b/fpga_diff/user_script/hw_run_download.tcl @@ -71,14 +71,27 @@ proc uvhs_poll_command_file {} { set command_file $::env(UVHS_COMMAND_FILE) if {[file exists $command_file]} { set running_file "${command_file}.running" - if {[catch { + set uvhs_result_file "" + set command_status [catch { file rename -force $command_file $running_file puts "INFO: sourcing UVHS runtime command: $running_file" source $running_file - } command_error]} { - puts stderr "ERROR: UVHS runtime command failed: $command_error" + } command_message] + if {$command_status != 0} { + set command_message "UVHS runtime command failed: $command_message" } catch {file delete -force $running_file} + if {$uvhs_result_file ne ""} { + set result_tmp "${uvhs_result_file}.tmp.[pid]" + set result [open $result_tmp w] + puts $result $command_status + puts -nonewline $result $command_message + close $result + file rename -force $result_tmp $uvhs_result_file + } + if {$command_status != 0} { + puts stderr "ERROR: $command_message" + } } after 500 uvhs_poll_command_file } diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 8e2accf6..ce9daeb0 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -1,13 +1,14 @@ # UVHS FPGA-Diff Flow This directory contains the UVHS implementation flow for FPGA-Diff designs on -the U2.2 B0/F2 target. It is selected explicitly with `UVHS=1`; the top-level -Makefile otherwise retains the normal Vivado flow unchanged. +the U2.2 B0/F2 target. Its targets use the `uvhs_*` prefix; the normal Vivado, +PCIe, and JTAG targets retain their original names and recipes. ## Environment -Configure the runtime host shell before invoking `make`. The following values -are the validated Hejian runtime installation; `UVHS_TEMPLATE_DIR` and +Configure the runtime host shell before invoking `make`, for example directly +in `.bashrc`. The following values are the validated Hejian runtime +installation; `UVHS_TEMPLATE_DIR` and `UVHS_UVW_AXI4_TO_DDR4_SRC` identify the locally installed base project and vendor DDR IP and therefore remain site-specific. @@ -37,11 +38,11 @@ starts. ## Build ```sh -make UVHS=1 uvhs_tools_check -make UVHS=1 uvhs_preflight CPU= -make UVHS=1 uvhs_frontend CPU= CORE_DIR=/path/to/generated/core SUFFIX= -make UVHS=1 uvhs_backend CPU= SUFFIX= -make UVHS=1 uvhs_package_bitstream CPU= SUFFIX= +make uvhs_tools_check +make uvhs_preflight CPU= +make uvhs_frontend CPU= CORE_DIR=/path/to/generated/core SUFFIX= +make uvhs_backend CPU= SUFFIX= +make uvhs_package_bitstream CPU= SUFFIX= ``` `uvhs_frontend` creates `hw.dat`, imports the generated Vivado IP DCPs and the @@ -64,7 +65,7 @@ work directory. `uvhs_clean` removes only the explicitly selected Use the same entry points with `CPU=kmh` and an AXI-based XiangShan RTL tree: ```sh -make UVHS=1 uvhs_all CPU=kmh CORE_DIR=/path/to/XiangShan SUFFIX= +make uvhs_all CPU=kmh CORE_DIR=/path/to/XiangShan SUFFIX= ``` The file-list step detects whether `SimTop` exposes DMA and enables the H2C @@ -73,45 +74,51 @@ LUT and 30% LUT6 fill limits and disabling the hold-expansion route bailout. ## Runtime -The public programming targets retain the same names in both flows. With -`UVHS=1`, Make selects the UVHS runtime Tcl instead of Vivado LabTools: +UVHS runtime targets are separate from the normal Vivado LabTools targets: ```sh # Keep this foreground process attached to the board. -make UVHS=1 CPU= SUFFIX= write_bitstream +make uvhs_write_bitstream CPU= SUFFIX= # Run these from another shell with the same CPU/SUFFIX or UVHS_WORK_DIR. -make UVHS=1 CPU= SUFFIX= halt_soc -make UVHS=1 CPU= SUFFIX= write_jtag_ddr WORKLOAD=/path/to/image.txt -make UVHS=1 CPU= SUFFIX= reset_cpu -make UVHS=1 CPU= SUFFIX= uvhs_runtime_stop +make uvhs_halt_soc CPU= SUFFIX= +make uvhs_write_ddr CPU= SUFFIX= WORKLOAD=/path/to/image.txt +make uvhs_write_flash CPU= SUFFIX= WORKLOAD=/path/to/image.bin +make uvhs_reset_cpu CPU= SUFFIX= +make uvhs_runtime_stop CPU= SUFFIX= ``` -`write_bitstream` loads the completed `hw.dat`, configures the connector and +`uvhs_write_bitstream` loads the completed `hw.dat`, configures the connector and clocks, holds `rstn_sw6/rstn_sw5/rstn_sw4` low across `download`, calls `initialize`, then releases system/DDR reset before CPU reset. The process -polls an atomic command file while it owns the runtime session. `halt_soc` and -`reset_cpu` control `rstn_sw5`; the other two reset names remain reserved for -the system and external DDR IP. +polls an atomic command file while it owns the runtime session. The other +runtime targets wait for command completion and propagate errors to Make. +`uvhs_halt_soc` and `uvhs_reset_cpu` control `rstn_sw5`; the other two reset +names remain reserved for the system and external DDR IP. -`write_jtag_ddr` keeps the legacy target name but uses UVHS `writemem` in this -flow. It accepts the same address/data-pair text file as the Vivado Tcl, +`uvhs_write_ddr` accepts the same address/data-pair text file as the Vivado Tcl, converts each segment to the selected DCP word width, and writes the DDR IP -through its runtime backdoor. H2C remains available for the normal FPGA-Diff -host workflow and is independent of this loader. - -The current runtime database exposes only the vendor DDR IP in -`query -memory`; the BRAM-backed flash DCP is not a runtime memory object. -Therefore `write_jtag_flash` is unsupported with `UVHS=1` and fails explicitly. -The normal Vivado flow continues to write that flash through its dedicated -32-bit JTAG AXI without any interface change. +through the UVHS `writemem` runtime backdoor. It holds CPU reset low after the +write; run `uvhs_reset_cpu` when the image is ready. H2C remains available for +the normal FPGA-Diff host workflow and is independent of this loader. + +The BRAM-backed flash is inside an imported Vivado DCP and is not exposed as a +UVHS runtime memory. The flow therefore generates a 64-bit UVHS generalBus IP +and connects it to the existing 32-bit flash path through `AXI_bridge`'s width +converter. `uvhs_write_flash` holds CPU reset, pads the raw binary to the +generalBus 8-byte transfer alignment, writes at `0x10000000`, reads the entire +transfer back, and releases CPU reset only after a byte-for-byte match. The +maximum image size is the flash BRAM capacity, 32 KiB. The normal +`write_jtag_flash` target continues to use its dedicated 32-bit JTAG AXI. A +database built before this generalBus path was added cannot use +`uvhs_write_flash` and must be rebuilt. ## Files | File | Role | | --- | --- | | `uvhs.mk` | UVHS-only Make targets, prerequisites, DCP export, and stage invocation. | -| `export_vivado_ip.tcl` | Regenerates repository-owned Vivado IP/BD DCPs. | +| `export_vivado_ip.tcl` | Regenerates repository-owned Vivado IP/BD DCPs; `uvhs.mk` separately invokes the vendor generalBus generator. | | `frontend_run.tcl` | Creates the UVHS database, imports DCPs, reads RTL, and runs frontend. | | `backend_run.tcl` | Applies implementation-stage clock/constraint compatibility patches and runs P&R. | | `assemble_uvhs.tcl` | Adapts the template assembly to the selected B0/F2 board instance and DDR IP. | diff --git a/fpga_diff/uvhs/enqueue_runtime_command.sh b/fpga_diff/uvhs/enqueue_runtime_command.sh index 9b706437..6c672bbb 100755 --- a/fpga_diff/uvhs/enqueue_runtime_command.sh +++ b/fpga_diff/uvhs/enqueue_runtime_command.sh @@ -19,6 +19,13 @@ if [[ -e $command_file || -e $command_file.running ]]; then exit 3 fi +timeout=${UVHS_RUNTIME_COMMAND_TIMEOUT:-600} +if [[ ! $timeout =~ ^[1-9][0-9]*$ ]]; then + echo "ERROR: UVHS_RUNTIME_COMMAND_TIMEOUT must be a positive integer" >&2 + exit 64 +fi +result_file="${command_file}.result.$$" + tcl_quote() { local value=$1 value=${value//\\/\\\\} @@ -31,9 +38,12 @@ tcl_quote() { mkdir -p "$(dirname "$command_file")" tmp_file="${command_file}.tmp.$$" -trap 'rm -f "$tmp_file"' EXIT +trap 'rm -f "$tmp_file" "$result_file"' EXIT { + printf 'set uvhs_result_file ' + tcl_quote "$result_file" + printf '\n' printf 'set argv [list' for argument in "$@"; do printf ' ' @@ -51,3 +61,23 @@ if [[ -e $tmp_file ]]; then fi trap - EXIT echo "INFO: enqueued UVHS runtime command: $command_file" + +deadline=$((SECONDS + timeout)) +while [[ ! -f $result_file ]]; do + if (( SECONDS >= deadline )); then + echo "ERROR: timed out waiting for UVHS runtime command after ${timeout}s" >&2 + exit 5 + fi + sleep 0.2 +done + +status=$(sed -n '1p' "$result_file") +message=$(sed -n '2,$p' "$result_file") +rm -f "$result_file" +if [[ $status != 0 ]]; then + echo "ERROR: UVHS runtime command failed: $message" >&2 + exit 6 +fi +if [[ -n $message ]]; then + echo "INFO: $message" +fi diff --git a/fpga_diff/uvhs/frontend_run.tcl b/fpga_diff/uvhs/frontend_run.tcl index 9ffac1a9..17a4f71f 100644 --- a/fpga_diff/uvhs/frontend_run.tcl +++ b/fpga_diff/uvhs/frontend_run.tcl @@ -19,7 +19,7 @@ proc split_words {value} { return $out } -set required_dcp_modules [split_words [env_or_default UVHS_REQUIRED_DCP_MODULES {blk_mem_gen_0 AXI_bridge data_bridge xdma_ep uvw_axi4_to_ddr4}]] +set required_dcp_modules [split_words [env_or_default UVHS_REQUIRED_DCP_MODULES {blk_mem_gen_0 AXI_bridge data_bridge xdma_ep uvw_axi4_to_ddr4 uvw_general_bus}]] proc dcp_module_is_required {module} { return [expr {[lsearch -exact $::required_dcp_modules $module] >= 0}] @@ -217,6 +217,9 @@ set_blackbox_if_exists blk_mem_gen_0 ./rtl/soc/blk_mem_gen_0.dcp set_blackbox_if_exists AXI_bridge ./rtl/soc/AXI_bridge.dcp set_blackbox_if_exists data_bridge ./rtl/soc/data_bridge.dcp set_blackbox_if_exists xdma_ep ./rtl/device/pcie/xdma_ep.dcp +set_blackbox_if_exists uvw_general_bus \ + ./rtl/soc/uvw_general_bus/uvw_general_bus.dcp \ + -clock_enable_pairs {dut_axi_aclk dut_axi_aclk_en 1} require_file_for_uvhs_ip DCP ./rtl/soc/uvw_axi4_to_ddr4.dcp require_file_for_uvhs_ip stub ./rtl/soc/uvw_axi4_to_ddr4_Stub.v require_file_for_uvhs_ip pblock ./script/uvw_axi4_to_ddr4_pblock.tcl diff --git a/fpga_diff/uvhs/runtime_command.tcl b/fpga_diff/uvhs/runtime_command.tcl index b209e161..d0e956ce 100644 --- a/fpga_diff/uvhs/runtime_command.tcl +++ b/fpga_diff/uvhs/runtime_command.tcl @@ -8,6 +8,86 @@ proc uvhs_temp_dir {} { return $path } +proc uvhs_parse_integer {name value} { + if {![string is wideinteger -strict $value]} { + error "$name is not an integer: $value" + } + return [expr {$value + 0}] +} + +proc uvhs_read_binary {path} { + set input [open $path rb] + fconfigure $input -translation binary -encoding binary + set data [read $input] + close $input + return $data +} + +proc uvhs_write_binary {path data} { + set output [open $path wb] + fconfigure $output -translation binary -encoding binary + puts -nonewline $output $data + close $output +} + +proc uvhs_write_flash_gbus {input_file board fpga port channel base capacity} { + if {![file exists $input_file]} { + error "flash image not found: $input_file" + } + + if {[regexp -nocase {^b([0-9]+)$} $board -> board_index]} { + set board $board_index + } + if {![string is integer -strict $board]} { + error "generalBus board must be an index or B: $board" + } + if {![regexp -nocase {^f([0-9]+)$} $fpga -> fpga_index]} { + error "generalBus FPGA must be F: $fpga" + } + set fpga f$fpga_index + set port [uvhs_parse_integer "generalBus port" $port] + set channel [uvhs_parse_integer "generalBus channel" $channel] + set base [uvhs_parse_integer "flash base" $base] + set capacity [uvhs_parse_integer "flash capacity" $capacity] + set payload [uvhs_read_binary $input_file] + set payload_size [string length $payload] + if {$payload_size == 0} { + error "flash image is empty: $input_file" + } + if {$payload_size > $capacity} { + error "flash image is $payload_size bytes, capacity is $capacity bytes" + } + + set transfer_size [expr {($payload_size + 7) & ~7}] + if {$transfer_size > $capacity} { + error "8-byte-aligned flash transfer exceeds capacity: $transfer_size > $capacity" + } + append payload [string repeat "\x00" [expr {$transfer_size - $payload_size}]] + + set temp_dir [uvhs_temp_dir] + set write_file [file join $temp_dir [format "flash-write-%d.bin" [pid]]] + set read_file [file join $temp_dir [format "flash-read-%d.bin" [pid]]] + uvhs_write_binary $write_file $payload + file delete -force $read_file + + puts [format "INFO: generalBus flash write 0x%llx, %d bytes" $base $transfer_size] + set status [catch { + gbus_dma_write -board $board -fpga $fpga -port $port \ + -addr $base -size $transfer_size -channel $channel -file $write_file + gbus_dma_read -board $board -fpga $fpga -port $port \ + -addr $base -size $transfer_size -channel $channel -file $read_file + set readback [uvhs_read_binary $read_file] + if {![string equal $payload $readback]} { + error "generalBus flash readback mismatch" + } + } message options] + file delete -force $write_file $read_file + if {$status != 0} { + return -options $options $message + } + puts "INFO: generalBus flash full readback passed: $input_file" +} + proc uvhs_write_ddr_pairs {input_file rtl_path data_width} { if {![file exists $input_file]} { error "DDR workload not found: $input_file" @@ -102,6 +182,17 @@ switch -- $uvhs_command { after 100 uvhs_write_ddr_pairs [lindex $argv 1] [lindex $argv 2] [lindex $argv 3] } + write_flash { + if {[llength $argv] < 8} { + error "write_flash expects 7 arguments" + } + reset -name rstn_sw5 -value 0 + after 100 + uvhs_write_flash_gbus {*}[lrange $argv 1 7] + reset -name rstn_sw5 -value 1 + after 500 + query -reset + } stop { set ::uvhs_keepalive 1 } diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index f3701f13..0b1b8a39 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -14,6 +14,10 @@ UVHS_EXPORT_IP_JOBS ?= 8 UVHS_EXPORT_IP_VIVADO_VERSION ?= UVHS_EXPORT_IP_ONLY ?= UVHS_SKIP_VIVADO_EXPORT ?= vio_0 jtag_ddr_subsys +UVHS_GBUS_IP_DIR ?= $(UV_ROOT)/platform/$(PLATFORM)/Prototype/ips/uvw_gbus.3.1 +UVHS_GBUS_GENERATOR ?= $(UVHS_GBUS_IP_DIR)/gen_generalbus_ip.py +UVHS_GBUS_JSON ?= $(UVHS_GBUS_IP_DIR)/uvw_axi3_generalbus.json +UVHS_GBUS_GEN_DIR ?= $(UVHS_WORK_DIR)/ip-gen/generalbus UVHS_DESIGN_NAME ?= VU19P_X4 UVHS_TARGET_PACK ?= B0 @@ -50,7 +54,8 @@ UVHS_UVW_AXI4_TO_DDR4_REQUIRED_FILES := \ rtl/soc/uvw_axi4_to_ddr4.dcp \ rtl/soc/uvw_axi4_to_ddr4_Stub.v \ script/uvw_axi4_to_ddr4_pblock.tcl -UVHS_REQUIRED_DCP_MODULES := blk_mem_gen_0 AXI_bridge data_bridge xdma_ep uvw_axi4_to_ddr4 +UVHS_REQUIRED_DCP_MODULES := blk_mem_gen_0 AXI_bridge data_bridge xdma_ep \ + uvw_axi4_to_ddr4 uvw_general_bus UVHS_REQUIRED_MODULES ?= $(if $(filter nanhu,$(CPU)),XlnFpgaTop,$(if $(filter kmh nutshell,$(CPU)),SimTop,)) UVHS_DDR_RTL_INST := $(UVHS_TOP).core_def.U_UVHS_UVW_AXI4_TO_DDR4 UVHS_RUNTIME_LIB_DIR ?= $(UVHS_WORK_DIR)/.uvhs-runtime-lib @@ -61,15 +66,16 @@ UVHS_RUNTIME_TMP_DIR ?= $(UVHS_RUNTIME_WORK_DIR)/tmp UVHS_RUNTIME_DOWNLOAD_SCRIPT ?= $(UVHS_ROOT_DIR)/user_script/hw_run_download.tcl UVHS_RUNTIME_COMMAND_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/runtime_command.tcl UVHS_RUNTIME_DDR_RTL ?= $(UVHS_DDR_RTL_INST).ddr4_ip +UVHS_RUNTIME_COMMAND_TIMEOUT ?= 600 +UVHS_GBUS_BOARD ?= $(UVHS_TARGET_PACK) +UVHS_GBUS_FPGA ?= $(UVHS_TARGET_FPGA) +UVHS_GBUS_PORT ?= 0 +UVHS_GBUS_CHANNEL ?= 0 +UVHS_FLASH_BASE ?= 0x10000000 +UVHS_FLASH_SIZE ?= 0x8000 UVHS_COMPAT_PCRE_LIB ?= UVHS_SHELL_EXEC_WRAPPER ?= $(UVHS_ROOT_DIR)/uvhs/uv_shell_exec_compat.sh -FPGA_WRITE_BITSTREAM_IMPL := uvhs_download -FPGA_HALT_SOC_IMPL := uvhs_halt_soc -FPGA_WRITE_DDR_IMPL := uvhs_write_ddr -FPGA_WRITE_FLASH_IMPL := uvhs_write_flash -FPGA_RESET_CPU_IMPL := uvhs_reset_cpu - UVHS_TOOL_ENV = \ PATH="$(UVHS_ROOT_DIR)/uvhs/make_compat:$$UV_ROOT/bin:$$UV_ROOT/lib/venv3.8/bin:$$UV_ROOT/lib/gcc10.3/bin:$$PATH" \ LD_LIBRARY_PATH="$(UVHS_RUNTIME_LIB_DIR):$${LD_LIBRARY_PATH:-}" \ @@ -102,9 +108,10 @@ UVHS_BITSTREAM_DIR ?= $(UVHS_PNR_DIR)/bitstream UVHS_BIT_HOME ?= $(UVHS_WORK_DIR)/ready-to-program .PHONY: uvhs_preflight uvhs_prepare uvhs_export_vivado_ip \ + uvhs_export_generalbus \ uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist uvhs_check_modules \ uvhs_frontend uvhs_backend uvhs_all uvhs_check_timing \ - uvhs_package_bitstream uvhs_tools_check uvhs_clean uvhs_download \ + uvhs_package_bitstream uvhs_tools_check uvhs_clean uvhs_write_bitstream \ uvhs_halt_soc uvhs_reset_cpu uvhs_write_ddr uvhs_write_flash \ uvhs_runtime_stop @@ -116,6 +123,10 @@ uvhs_preflight: test -n "$$UV_LICENSE" test -x "$$UV_ROOT/bin/uv_shell_exec" test -x "$(UVHS_SHELL_EXEC_WRAPPER)" + test -f "$(UVHS_GBUS_GENERATOR)" + test -f "$(UVHS_GBUS_JSON)" + command -v python3 >/dev/null + command -v gzip >/dev/null test -d "$(UVHS_TEMPLATE_DIR)/script" test -f "$(UVHS_TEMPLATE_DIR)/Makefile" test -f "$(UVHS_TEMPLATE_DIR)/script/1B_4F_HGC_assemble.tcl" @@ -162,6 +173,52 @@ uvhs_export_vivado_ip: uvhs_prepare $(foreach ip,$(UVHS_SKIP_VIVADO_EXPORT),--skip "$(ip)") \ $(if $(filter 1,$(UVHS_EXPORT_IP_FORCE)),--force,)' +# The vendor generator assumes tcsh and starts an asynchronous DCP copy before +# deleting its project. Patch only the private work-directory copy. +uvhs_export_generalbus: uvhs_prepare + bash -c 'set -euo pipefail; \ + source_ip_dir="$(UVHS_GBUS_IP_DIR)"; generator="$(UVHS_GBUS_GENERATOR)"; \ + gen_dir="$(UVHS_GBUS_GEN_DIR)"; release="$$gen_dir/uvw_general_bus"; \ + test -f "$$generator"; test -f "$(UVHS_GBUS_JSON)"; \ + if [ "$(UVHS_EXPORT_IP_FORCE)" = 1 ] || \ + [ ! -s "$$release/uvw_general_bus.dcp" ] || \ + [ ! -s "$$release/uvw_general_bus_Stub.v" ] || \ + ! grep -Eq "output[[:space:]]+\\[63:0\\][[:space:]]*dut_axi_wdata" \ + "$$release/uvw_general_bus_Stub.v" || \ + ! grep -Eq "input[[:space:]]+\\[63:0\\][[:space:]]*dut_axi_rdata" \ + "$$release/uvw_general_bus_Stub.v"; then \ + rm -rf "$$gen_dir"; mkdir -p "$$gen_dir"; \ + ip_dir="$$gen_dir/ip-src"; \ + cp -a "$$source_ip_dir" "$$ip_dir"; \ + gen_script="$$ip_dir/gen_generalbus_ip.py"; \ + sed -i "s|#!/bin/tcsh|#!/usr/bin/env bash|" "$$gen_script"; \ + sed -i "/os[.]popen.*f_dcp_in.*f_dcp_out/c\\ shutil.copy2(f_dcp_in, f_dcp_out)" \ + "$$gen_script"; \ + grep -Fq "#!/usr/bin/env bash" "$$gen_script"; \ + grep -Fq "shutil.copy2(f_dcp_in, f_dcp_out)" "$$gen_script"; \ + json="$$gen_dir/uvw_axi3_generalbus.json"; \ + cp -f "$(UVHS_GBUS_JSON)" "$$json"; \ + sed -i -E \ + "s|(\"IP_LOCATION\"[[:space:]]*:[[:space:]]*)\"[^\"]*\"|\1\"$$ip_dir\"|; \ + s|(\"DATA_WIDTH\"[[:space:]]*:[[:space:]]*)\"[^\"]*\"|\1\"64\"|" \ + "$$json"; \ + export VIVADO_HOME="$$UV_XILINX_VIVADO" XILINX_VIVADO="$$UV_XILINX_VIVADO"; \ + cd "$$gen_dir"; \ + PATH="$$UV_XILINX_VIVADO/bin:$$PATH" python3 "$$gen_script" -j "$$json"; \ + fi; \ + test -s "$$release/uvw_general_bus.dcp"; \ + test -s "$$release/uvw_general_bus_Stub.v"; \ + rm -rf "$(UVHS_WORK_DIR)/rtl/soc/uvw_general_bus"; \ + mkdir -p "$(UVHS_WORK_DIR)/rtl/soc" "$(UVHS_WORK_DIR)/rtl/stubs"; \ + cp -a "$$release" "$(UVHS_WORK_DIR)/rtl/soc/uvw_general_bus"; \ + cp -f "$$release/uvw_general_bus_Stub.v" \ + "$(UVHS_WORK_DIR)/rtl/stubs/uvw_general_bus.v"; \ + grep -Eq "output[[:space:]]+\\[63:0\\][[:space:]]*dut_axi_wdata" \ + "$(UVHS_WORK_DIR)/rtl/stubs/uvw_general_bus.v"; \ + grep -Eq "input[[:space:]]+\\[63:0\\][[:space:]]*dut_axi_rdata" \ + "$(UVHS_WORK_DIR)/rtl/stubs/uvw_general_bus.v"; \ + echo "INFO: prepared 64-bit UVHS generalBus DCP"' + uvhs_sync_uvw_axi4_to_ddr4: uvhs_prepare bash -c 'set -euo pipefail; \ src="$(UVHS_UVW_AXI4_TO_DDR4_SRC)"; work="$(UVHS_WORK_DIR)"; \ @@ -176,6 +233,10 @@ uvhs_sync_uvw_axi4_to_ddr4: uvhs_prepare for rel in $(UVHS_UVW_AXI4_TO_DDR4_REQUIRED_FILES); do test -s "$$work/$$rel"; done; \ expected_width="$(UVHS_DDR_AXI_WIDTH)"; last_bit="$$((expected_width - 1))"; \ stub="$$work/rtl/soc/uvw_axi4_to_ddr4_Stub.v"; \ + if gzip -t "$$stub" 2>/dev/null; then \ + gzip -dc "$$stub" > "$$stub.decompressed"; \ + mv -f "$$stub.decompressed" "$$stub"; \ + fi; \ grep -Eq "input[[:space:]]+\\[$$last_bit:0\\][[:space:]]*ddr4ip_dut_axi_wdata" "$$stub"; \ grep -Eq "output[[:space:]]+\\[$$last_bit:0\\][[:space:]]*ddr4ip_dut_axi_rdata" "$$stub"; \ echo "INFO: verified UVHS DDR DCP AXI data width: $$expected_width"; \ @@ -183,7 +244,7 @@ uvhs_sync_uvw_axi4_to_ddr4: uvhs_prepare echo "$(UVHS_UVW_AXI4_TO_DDR4_EXPECTED_MD5) $$work/rtl/soc/uvw_axi4_to_ddr4.dcp" | md5sum -c -; \ fi' -uvhs_filelist: +uvhs_filelist: uvhs_export_generalbus mkdir -p "$(dir $(UVHS_FILELIST))" { \ printf '+define+SYNTHESIS\n+define+XIANGSHAN_FPGA\n'; \ @@ -240,7 +301,8 @@ uvhs_filelist: uvhs_check_modules: uvhs_filelist bash "$(UVHS_ROOT_DIR)/uvhs/check_modules.sh" "$(UVHS_FILELIST)" "$(UVHS_REQUIRED_MODULES)" -uvhs_frontend: uvhs_export_vivado_ip uvhs_sync_uvw_axi4_to_ddr4 uvhs_check_modules +uvhs_frontend: uvhs_export_vivado_ip uvhs_export_generalbus \ + uvhs_sync_uvw_axi4_to_ddr4 uvhs_check_modules bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ $(UVHS_FLOW_ENV) UVHS_TOP="$(UVHS_TOP)" UVHS_FILELIST=./rtl/filelist.f \ UVHS_REQUIRED_DCP_MODULES="$(UVHS_REQUIRED_DCP_MODULES)" \ @@ -276,7 +338,7 @@ uvhs_package_bitstream: uvhs_check_timing # Runtime stays in the foreground because uv_shell owns the board session. # Use another shell for the command targets below while this target is active. -uvhs_download: +uvhs_write_bitstream: test -d "$(UVHS_RUNTIME_DB)" test -f "$(UVHS_RUNTIME_DOWNLOAD_SCRIPT)" test ! -e "$(UVHS_RUNTIME_COMMAND_FILE)" @@ -290,24 +352,33 @@ uvhs_download: -script "$(UVHS_RUNTIME_DOWNLOAD_SCRIPT)" uvhs_halt_soc: + UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_COMMAND_TIMEOUT)" \ bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" halt_soc uvhs_reset_cpu: + UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_COMMAND_TIMEOUT)" \ bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" reset_cpu uvhs_write_ddr: test -f "$(WORKLOAD)" + UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_COMMAND_TIMEOUT)" \ bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" \ write_ddr "$(WORKLOAD)" "$(UVHS_RUNTIME_DDR_RTL)" "$(UVHS_DDR_AXI_WIDTH)" uvhs_write_flash: - @echo "ERROR: the current UVHS runtime DB does not expose flash as a writable memory" >&2 - @exit 2 + test -f "$(WORKLOAD)" + UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_COMMAND_TIMEOUT)" \ + bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ + "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" \ + write_flash "$(WORKLOAD)" "$(UVHS_GBUS_BOARD)" "$(UVHS_GBUS_FPGA)" \ + "$(UVHS_GBUS_PORT)" "$(UVHS_GBUS_CHANNEL)" \ + "$(UVHS_FLASH_BASE)" "$(UVHS_FLASH_SIZE)" uvhs_runtime_stop: + UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_COMMAND_TIMEOUT)" \ bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" stop From 82e8508de25269daaa51ea3ede7655f8292d705b Mon Sep 17 00:00:00 2001 From: klin02 Date: Thu, 30 Jul 2026 09:58:14 +0800 Subject: [PATCH 06/62] refactor(fpga_diff): remove obsolete UVHS adapters Instantiate the width-matched vendor DDR IP directly and keep only the address and ID adaptations required by its AXI interface. Update the runtime writemem path for the direct instance. Remove unused memory-array, auxiliary-DDR, ClockHub, and manual DDR pin branches. Inline the trivial file-list filter and document the reduced flow. Co-authored-by: Kamimiao --- fpga_diff/src/rtl/common/core_def_xdma.sv | 125 +++++++++----- fpga_diff/src/rtl/common/uvhs_ddr4_wrapper.sv | 152 ------------------ fpga_diff/uvhs/README.md | 8 +- fpga_diff/uvhs/assemble_uvhs.tcl | 127 ++------------- fpga_diff/uvhs/assign_pin_u22_f2.tcl | 145 ++++------------- fpga_diff/uvhs/check_flow_tools.sh | 2 - fpga_diff/uvhs/filelist.awk | 5 - fpga_diff/uvhs/uvhs.mk | 8 +- 8 files changed, 132 insertions(+), 440 deletions(-) delete mode 100644 fpga_diff/src/rtl/common/uvhs_ddr4_wrapper.sv delete mode 100644 fpga_diff/uvhs/filelist.awk diff --git a/fpga_diff/src/rtl/common/core_def_xdma.sv b/fpga_diff/src/rtl/common/core_def_xdma.sv index 64cd4c05..36f1d62b 100755 --- a/fpga_diff/src/rtl/common/core_def_xdma.sv +++ b/fpga_diff/src/rtl/common/core_def_xdma.sv @@ -1422,49 +1422,88 @@ mode_ctrl U_MODE_CTRL( ); `ifdef UVHS -uvhs_ddr4_wrapper U_UVHS_UVW_AXI4_TO_DDR4 ( - .clk (inter_soc_clk), - .rstn (rstn_sw4), - .calib_complete (init_calib_complete), - .s_axi_awid (cpu2ddr_m2s_awid_mix), - .s_axi_awaddr (cpu2ddr_m2s_awaddr_mix), - .s_axi_awlen (cpu2ddr_m2s_awlen), - .s_axi_awsize (cpu2ddr_m2s_awsize), - .s_axi_awburst (cpu2ddr_m2s_awburst), - .s_axi_awlock (cpu2ddr_m2s_awlock), - .s_axi_awcache (cpu2ddr_m2s_awcache), - .s_axi_awprot (cpu2ddr_m2s_awprot), - .s_axi_awqos (cpu2ddr_m2s_awqos), - .s_axi_awregion (cpu2ddr_m2s_awregion), - .s_axi_awvalid (cpu2ddr_m2s_awvalid), - .s_axi_awready (cpu2ddr_s2m_awready), - .s_axi_wdata (cpu2ddr_m2s_wdata), - .s_axi_wstrb (cpu2ddr_m2s_wstrb), - .s_axi_wlast (cpu2ddr_m2s_wlast), - .s_axi_wvalid (cpu2ddr_m2s_wvalid), - .s_axi_wready (cpu2ddr_s2m_wready), - .s_axi_bid (cpu2ddr_s2m_bid), - .s_axi_bresp (cpu2ddr_s2m_bresp), - .s_axi_bvalid (cpu2ddr_s2m_bvalid), - .s_axi_bready (cpu2ddr_m2s_bready), - .s_axi_arid (cpu2ddr_m2s_arid_mix), - .s_axi_araddr (cpu2ddr_m2s_araddr_mix), - .s_axi_arlen (cpu2ddr_m2s_arlen), - .s_axi_arsize (cpu2ddr_m2s_arsize), - .s_axi_arburst (cpu2ddr_m2s_arburst), - .s_axi_arlock (cpu2ddr_m2s_arlock), - .s_axi_arcache (cpu2ddr_m2s_arcache), - .s_axi_arprot (cpu2ddr_m2s_arprot), - .s_axi_arqos (cpu2ddr_m2s_arqos), - .s_axi_arregion (cpu2ddr_m2s_arregion), - .s_axi_arvalid (cpu2ddr_m2s_arvalid), - .s_axi_arready (cpu2ddr_s2m_arready), - .s_axi_rid (cpu2ddr_s2m_rid), - .s_axi_rdata (cpu2ddr_s2m_rdata), - .s_axi_rresp (cpu2ddr_s2m_rresp), - .s_axi_rlast (cpu2ddr_s2m_rlast), - .s_axi_rvalid (cpu2ddr_s2m_rvalid), - .s_axi_rready (cpu2ddr_m2s_rready) +// The vendor DDR IP uses 34-bit addresses and 14-bit IDs. Keep those narrow +// adaptations local while preserving the common fpga_diff AXI interface. +wire [33:0] uvhs_ddr_awaddr; +wire [33:0] uvhs_ddr_araddr; +wire [13:0] uvhs_ddr_bid; +wire [13:0] uvhs_ddr_rid; +wire uvhs_ddr_user_rst; + +`ifdef CPU_NUTSHELL +assign uvhs_ddr_awaddr = {1'b0, cpu2ddr_m2s_awaddr_mix}; +assign uvhs_ddr_araddr = {1'b0, cpu2ddr_m2s_araddr_mix}; +`else +assign uvhs_ddr_awaddr = cpu2ddr_m2s_awaddr_mix[33:0]; +assign uvhs_ddr_araddr = cpu2ddr_m2s_araddr_mix[33:0]; +`endif +assign cpu2ddr_s2m_bid = {4'b0, uvhs_ddr_bid}; +assign cpu2ddr_s2m_rid = {4'b0, uvhs_ddr_rid}; +assign init_calib_complete = rstn_sw4 & ~uvhs_ddr_user_rst; + +uvw_axi4_to_ddr4 U_UVHS_UVW_AXI4_TO_DDR4 ( + .ddr4ip_dut_axi_aclk (inter_soc_clk), + .ddr4ip_dut_axi_aresetn (rstn_sw4), + .ddr4ip_dut_axi_awaddr (uvhs_ddr_awaddr), + .ddr4ip_dut_axi_awburst (cpu2ddr_m2s_awburst), + .ddr4ip_dut_axi_awcache (cpu2ddr_m2s_awcache), + .ddr4ip_dut_axi_awid (cpu2ddr_m2s_awid_mix[13:0]), + .ddr4ip_dut_axi_awlen (cpu2ddr_m2s_awlen), + .ddr4ip_dut_axi_awlock (cpu2ddr_m2s_awlock), + .ddr4ip_dut_axi_awprot (cpu2ddr_m2s_awprot), + .ddr4ip_dut_axi_awqos (cpu2ddr_m2s_awqos), + .ddr4ip_dut_axi_awready (cpu2ddr_s2m_awready), + .ddr4ip_dut_axi_awregion (cpu2ddr_m2s_awregion), + .ddr4ip_dut_axi_awsize (cpu2ddr_m2s_awsize), + .ddr4ip_dut_axi_awvalid (cpu2ddr_m2s_awvalid), + .ddr4ip_dut_axi_wdata (cpu2ddr_m2s_wdata), + .ddr4ip_dut_axi_wlast (cpu2ddr_m2s_wlast), + .ddr4ip_dut_axi_wready (cpu2ddr_s2m_wready), + .ddr4ip_dut_axi_wstrb (cpu2ddr_m2s_wstrb), + .ddr4ip_dut_axi_wvalid (cpu2ddr_m2s_wvalid), + .ddr4ip_dut_axi_bid (uvhs_ddr_bid), + .ddr4ip_dut_axi_bready (cpu2ddr_m2s_bready), + .ddr4ip_dut_axi_bresp (cpu2ddr_s2m_bresp), + .ddr4ip_dut_axi_bvalid (cpu2ddr_s2m_bvalid), + .ddr4ip_dut_axi_araddr (uvhs_ddr_araddr), + .ddr4ip_dut_axi_arburst (cpu2ddr_m2s_arburst), + .ddr4ip_dut_axi_arcache (cpu2ddr_m2s_arcache), + .ddr4ip_dut_axi_arid (cpu2ddr_m2s_arid_mix[13:0]), + .ddr4ip_dut_axi_arlen (cpu2ddr_m2s_arlen), + .ddr4ip_dut_axi_arlock (cpu2ddr_m2s_arlock), + .ddr4ip_dut_axi_arprot (cpu2ddr_m2s_arprot), + .ddr4ip_dut_axi_arqos (cpu2ddr_m2s_arqos), + .ddr4ip_dut_axi_arready (cpu2ddr_s2m_arready), + .ddr4ip_dut_axi_arregion (cpu2ddr_m2s_arregion), + .ddr4ip_dut_axi_arsize (cpu2ddr_m2s_arsize), + .ddr4ip_dut_axi_arvalid (cpu2ddr_m2s_arvalid), + .ddr4ip_dut_axi_rdata (cpu2ddr_s2m_rdata), + .ddr4ip_dut_axi_rid (uvhs_ddr_rid), + .ddr4ip_dut_axi_rlast (cpu2ddr_s2m_rlast), + .ddr4ip_dut_axi_rready (cpu2ddr_m2s_rready), + .ddr4ip_dut_axi_rresp (cpu2ddr_s2m_rresp), + .ddr4ip_dut_axi_rvalid (cpu2ddr_s2m_rvalid), + .ddr4ip_dut_axi_aclk_en (1'b1), + .ddr4ip_ddr4_user_clk (), + .ddr4ip_ddr4_user_rst (uvhs_ddr_user_rst), + .sysbus_ghbd_i (256'b0), + .sysbus_ghbd_o (), + .FP_CLK_200M_P (), + .FP_CLK_200M_N (), + .DDR4_DIMM_ACT_N (), + .DDR4_DIMM_A (), + .DDR4_DIMM_BA (), + .DDR4_DIMM_BG (), + .DDR4_DIMM_CK_N (), + .DDR4_DIMM_CK_P (), + .DDR4_DIMM_CKE (), + .DDR4_DIMM_CS_N (), + .DDR4_DIMM_ODT (), + .DDR4_DIMM_RST_B (), + .DDR4_DIMM_DM (), + .DDR4_DIMM_DQ (), + .DDR4_DIMM_DQS_N (), + .DDR4_DIMM_DQS_P () ); `else jtag_ddr_subsys_wrapper U_JTAG_DDR_SUBSYS( diff --git a/fpga_diff/src/rtl/common/uvhs_ddr4_wrapper.sv b/fpga_diff/src/rtl/common/uvhs_ddr4_wrapper.sv deleted file mode 100644 index 780ed09f..00000000 --- a/fpga_diff/src/rtl/common/uvhs_ddr4_wrapper.sv +++ /dev/null @@ -1,152 +0,0 @@ -`timescale 1ns/1ps - -module uvhs_ddr4_wrapper ( - input wire clk, - input wire rstn, - output wire calib_complete, - - input wire [17:0] s_axi_awid, -`ifdef CPU_NUTSHELL - input wire [32:0] s_axi_awaddr, -`else - input wire [39:0] s_axi_awaddr, -`endif - input wire [7:0] s_axi_awlen, - input wire [2:0] s_axi_awsize, - input wire [1:0] s_axi_awburst, - input wire s_axi_awlock, - input wire [3:0] s_axi_awcache, - input wire [2:0] s_axi_awprot, - input wire [3:0] s_axi_awqos, - input wire [3:0] s_axi_awregion, - input wire s_axi_awvalid, - output wire s_axi_awready, -`ifdef CPU_NUTSHELL - input wire [63:0] s_axi_wdata, - input wire [7:0] s_axi_wstrb, -`else - input wire [255:0] s_axi_wdata, - input wire [31:0] s_axi_wstrb, -`endif - input wire s_axi_wlast, - input wire s_axi_wvalid, - output wire s_axi_wready, - output wire [17:0] s_axi_bid, - output wire [1:0] s_axi_bresp, - output wire s_axi_bvalid, - input wire s_axi_bready, - - input wire [17:0] s_axi_arid, -`ifdef CPU_NUTSHELL - input wire [32:0] s_axi_araddr, -`else - input wire [39:0] s_axi_araddr, -`endif - input wire [7:0] s_axi_arlen, - input wire [2:0] s_axi_arsize, - input wire [1:0] s_axi_arburst, - input wire s_axi_arlock, - input wire [3:0] s_axi_arcache, - input wire [2:0] s_axi_arprot, - input wire [3:0] s_axi_arqos, - input wire [3:0] s_axi_arregion, - input wire s_axi_arvalid, - output wire s_axi_arready, - output wire [17:0] s_axi_rid, -`ifdef CPU_NUTSHELL - output wire [63:0] s_axi_rdata, -`else - output wire [255:0] s_axi_rdata, -`endif - output wire [1:0] s_axi_rresp, - output wire s_axi_rlast, - output wire s_axi_rvalid, - input wire s_axi_rready -); - - wire [33:0] ddr_awaddr; - wire [33:0] ddr_araddr; - wire [13:0] ddr_bid; - wire [13:0] ddr_rid; - wire ddr_user_rst; - -`ifdef CPU_NUTSHELL - assign ddr_awaddr = {1'b0, s_axi_awaddr}; - assign ddr_araddr = {1'b0, s_axi_araddr}; -`else - assign ddr_awaddr = s_axi_awaddr[33:0]; - assign ddr_araddr = s_axi_araddr[33:0]; -`endif - - assign s_axi_bid = {4'b0, ddr_bid}; - assign s_axi_rid = {4'b0, ddr_rid}; - assign calib_complete = rstn & ~ddr_user_rst; - - // The selected vendor DCP must match the source AXI data width: NutShell - // uses a native 64-bit DCP while the XiangShan path uses a 256-bit DCP. - uvw_axi4_to_ddr4 ddr4_ip ( - .ddr4ip_dut_axi_aclk(clk), - .ddr4ip_dut_axi_aresetn(rstn), - .ddr4ip_dut_axi_awaddr(ddr_awaddr), - .ddr4ip_dut_axi_awburst(s_axi_awburst), - .ddr4ip_dut_axi_awcache(s_axi_awcache), - .ddr4ip_dut_axi_awid(s_axi_awid[13:0]), - .ddr4ip_dut_axi_awlen(s_axi_awlen), - .ddr4ip_dut_axi_awlock(s_axi_awlock), - .ddr4ip_dut_axi_awprot(s_axi_awprot), - .ddr4ip_dut_axi_awqos(s_axi_awqos), - .ddr4ip_dut_axi_awready(s_axi_awready), - .ddr4ip_dut_axi_awregion(s_axi_awregion), - .ddr4ip_dut_axi_awsize(s_axi_awsize), - .ddr4ip_dut_axi_awvalid(s_axi_awvalid), - .ddr4ip_dut_axi_wdata(s_axi_wdata), - .ddr4ip_dut_axi_wlast(s_axi_wlast), - .ddr4ip_dut_axi_wready(s_axi_wready), - .ddr4ip_dut_axi_wstrb(s_axi_wstrb), - .ddr4ip_dut_axi_wvalid(s_axi_wvalid), - .ddr4ip_dut_axi_bid(ddr_bid), - .ddr4ip_dut_axi_bready(s_axi_bready), - .ddr4ip_dut_axi_bresp(s_axi_bresp), - .ddr4ip_dut_axi_bvalid(s_axi_bvalid), - .ddr4ip_dut_axi_araddr(ddr_araddr), - .ddr4ip_dut_axi_arburst(s_axi_arburst), - .ddr4ip_dut_axi_arcache(s_axi_arcache), - .ddr4ip_dut_axi_arid(s_axi_arid[13:0]), - .ddr4ip_dut_axi_arlen(s_axi_arlen), - .ddr4ip_dut_axi_arlock(s_axi_arlock), - .ddr4ip_dut_axi_arprot(s_axi_arprot), - .ddr4ip_dut_axi_arqos(s_axi_arqos), - .ddr4ip_dut_axi_arready(s_axi_arready), - .ddr4ip_dut_axi_arregion(s_axi_arregion), - .ddr4ip_dut_axi_arsize(s_axi_arsize), - .ddr4ip_dut_axi_arvalid(s_axi_arvalid), - .ddr4ip_dut_axi_rdata(s_axi_rdata), - .ddr4ip_dut_axi_rid(ddr_rid), - .ddr4ip_dut_axi_rlast(s_axi_rlast), - .ddr4ip_dut_axi_rready(s_axi_rready), - .ddr4ip_dut_axi_rresp(s_axi_rresp), - .ddr4ip_dut_axi_rvalid(s_axi_rvalid), - .ddr4ip_dut_axi_aclk_en(1'b1), - .ddr4ip_ddr4_user_clk(), - .ddr4ip_ddr4_user_rst(ddr_user_rst), - .sysbus_ghbd_i(256'b0), - .sysbus_ghbd_o(), - .FP_CLK_200M_P(), - .FP_CLK_200M_N(), - .DDR4_DIMM_ACT_N(), - .DDR4_DIMM_A(), - .DDR4_DIMM_BA(), - .DDR4_DIMM_BG(), - .DDR4_DIMM_CK_N(), - .DDR4_DIMM_CK_P(), - .DDR4_DIMM_CKE(), - .DDR4_DIMM_CS_N(), - .DDR4_DIMM_ODT(), - .DDR4_DIMM_RST_B(), - .DDR4_DIMM_DM(), - .DDR4_DIMM_DQ(), - .DDR4_DIMM_DQS_N(), - .DDR4_DIMM_DQS_P() - ); - -endmodule diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index ce9daeb0..94c3a7ca 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -121,13 +121,13 @@ database built before this generalBus path was added cannot use | `export_vivado_ip.tcl` | Regenerates repository-owned Vivado IP/BD DCPs; `uvhs.mk` separately invokes the vendor generalBus generator. | | `frontend_run.tcl` | Creates the UVHS database, imports DCPs, reads RTL, and runs frontend. | | `backend_run.tcl` | Applies implementation-stage clock/constraint compatibility patches and runs P&R. | -| `assemble_uvhs.tcl` | Adapts the template assembly to the selected B0/F2 board instance and DDR IP. | -| `assign_pin_u22_f2.tcl` | Assigns target-board clocks, PCIe, UART, and reset-visible top ports. | +| `assemble_uvhs.tcl` | Reduces the four-FPGA vendor template to the selected FPGA and its daughter cards. | +| `assign_pin_u22_f2.tcl` | Assigns target-board clocks, PCIe, UART, and low-speed I/O; DDR pins remain owned by the vendor IP. | | `timing_common.tcl`, `async_clocks.tcl` | Declare clocks and asynchronous clock-domain relationships. | -| `check_modules.sh`, `filelist.awk`, `check_flow_tools.sh` | Validate the generated RTL file list and checked-in flow sources. | +| `check_modules.sh`, `check_flow_tools.sh` | Validate the generated RTL file list and checked-in flow sources. | | `make_compat/` | Supplies the Bash-compatible commands required by UVHS-generated Makefiles and its `csh -fc limit` probe. | | `patch_uvsyn_shell.sh` | Patches the generated worker Makefile to run the vendor `uv_shell` script through Bash. | | `enqueue_runtime_command.sh`, `runtime_command.tcl` | Atomically submit reset and memory operations to the attached runtime process. | | `uv_shell_exec_compat.sh` | Restores staged compatibility libraries after the vendor launcher sanitizes `LD_LIBRARY_PATH`. | -| `uvhs_ddr4_wrapper.sv` | Isolates the vendor DDR AXI wiring from the common FPGA-Diff top-level RTL. | +| `../src/rtl/common/core_def_xdma.sv` | Instantiates the width-matched vendor DDR IP directly for UVHS builds. | | `../user_script/hw_run_download.tcl` | Downloads and initializes a completed UVHS database, then services runtime commands. | diff --git a/fpga_diff/uvhs/assemble_uvhs.tcl b/fpga_diff/uvhs/assemble_uvhs.tcl index 77568339..a3925be8 100644 --- a/fpga_diff/uvhs/assemble_uvhs.tcl +++ b/fpga_diff/uvhs/assemble_uvhs.tcl @@ -1,5 +1,5 @@ ################################################################################ -# UVHS-only board assembly overlay for fpga_diff. +# Reduce the vendor four-FPGA assembly template to the selected UVHS FPGA. ################################################################################ proc uvhs_env_or_default {name default} { @@ -9,25 +9,7 @@ proc uvhs_env_or_default {name default} { return $default } -proc uvhs_env_if_exists_or_default {name default} { - if {[info exists ::env($name)]} { - return $::env($name) - } - return $default -} - set uvhs_base_assemble ./script/1B_4F_HGC_assemble.tcl -set uvhs_uvw_ddr4_mode [expr {[uvhs_env_or_default UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP 0] eq "1"}] -set uvhs_default_mem_dc [expr {$uvhs_uvw_ddr4_mode ? "none" : "UV_MEM_ARRAY_F"}] -set uvhs_mem_dc [uvhs_env_or_default UVHS_MEM_ARRAY_DC $uvhs_default_mem_dc] -set uvhs_mem_inst [uvhs_env_or_default UVHS_MEM_ARRAY_INST mem_array_inst0] -set uvhs_mem_connector [uvhs_env_or_default UVHS_MEM_ARRAY_CONNECTOR b0.F2_FMC1] -set uvhs_replace_inst [uvhs_env_or_default UVHS_MEM_ARRAY_REPLACE_INST pddr4dme_inst2] -set uvhs_replace_connector [uvhs_env_or_default UVHS_MEM_ARRAY_REPLACE_CONNECTOR b0.F2_FMC3] -set uvhs_aux_ddr_dc [uvhs_env_if_exists_or_default UVHS_AUX_DDR_DC UV_FMCH_PDDR4DME] -set uvhs_aux_ddr_inst [uvhs_env_or_default UVHS_AUX_DDR_INST pddr4dme_f2_aux_inst] -set uvhs_aux_ddr_connector [uvhs_env_or_default UVHS_AUX_DDR_CONNECTOR b0.F2_FMC2] -set uvhs_aux_swap_base_connector [uvhs_env_or_default UVHS_AUX_DDR_SWAP_BASE_CONNECTOR ""] set uvhs_target_fpga [string tolower [uvhs_env_or_default UVHS_TARGET_FPGA_LOWER b0.f2]] set uvhs_known_fpgas {b0.f0 b0.f1 b0.f2 b0.f3} set uvhs_keep_fpgas {} @@ -45,9 +27,6 @@ foreach uvhs_fpga $uvhs_keep_fpgas { error "UVHS_KEEP_FPGAS contains unknown FPGA '$uvhs_fpga'" } } -# The deployed U2 exposes the B0 PLL clock bank directly and reports no -# external ClockHub at runtime. Keep the overlay opt-in for other systems. -set uvhs_enable_clock_hub [expr {[uvhs_env_or_default UVHS_ENABLE_CLOCK_HUB 0] eq "1"}] if {![file exists $uvhs_base_assemble]} { error "missing base assembly file: $uvhs_base_assemble" @@ -57,33 +36,23 @@ set uvhs_fh [open $uvhs_base_assemble r] set uvhs_base_data [read $uvhs_fh] close $uvhs_fh +# Record daughter cards attached only to FPGAs that will be unplugged. Their +# create commands must be removed together with their connector commands. set uvhs_remove_dc_instances {} foreach uvhs_line [split $uvhs_base_data "\n"] { set uvhs_trimmed_line [string trim $uvhs_line] - set uvhs_lower_line [string tolower $uvhs_trimmed_line] if {[regexp {^config_hw[ \t]+-connect_daughter_card[ \t]+\{([^ \t]+)[ \t]+([^ \t]+)\.FMC\}} $uvhs_trimmed_line -> uvhs_connector uvhs_instance]} { set uvhs_lower_connector [string tolower $uvhs_connector] - set uvhs_connector_fpga "" foreach uvhs_fpga $uvhs_known_fpgas { - if {[string first $uvhs_fpga $uvhs_lower_connector] == 0} { - set uvhs_connector_fpga $uvhs_fpga + if {[string first $uvhs_fpga $uvhs_lower_connector] == 0 && + [lsearch -exact $uvhs_keep_fpgas $uvhs_fpga] < 0} { + lappend uvhs_remove_dc_instances $uvhs_instance break } } - if {$uvhs_connector_fpga ne "" && [lsearch -exact $uvhs_keep_fpgas $uvhs_connector_fpga] < 0} { - lappend uvhs_remove_dc_instances $uvhs_instance - } } } -if {$uvhs_mem_dc ne "" && $uvhs_mem_dc ne "none" && $uvhs_replace_inst ne "" && $uvhs_replace_inst ne "none"} { - set uvhs_remove_create "config_hw -create_daughter_card UV_FMCH_PDDR4DME -instance $uvhs_replace_inst" - set uvhs_remove_connect "config_hw -connect_daughter_card \\{$uvhs_replace_connector $uvhs_replace_inst.FMC\\}" - regsub -line -all "^$uvhs_remove_create\[ \t\]*\n" $uvhs_base_data "" uvhs_base_data - regsub -line -all "^$uvhs_remove_connect\[ \t\]*\n" $uvhs_base_data "" uvhs_base_data - puts "INFO: UVHS memory overlay: replace $uvhs_replace_inst on $uvhs_replace_connector" -} - set uvhs_filtered_lines [list] foreach uvhs_line [split $uvhs_base_data "\n"] { set uvhs_trimmed_line [string trim $uvhs_line] @@ -101,14 +70,15 @@ foreach uvhs_line [split $uvhs_base_data "\n"] { } if {[regexp {^config_hw[ \t]+-connect_daughter_card[ \t]+\{([^ \t]+)[ \t]+([^ \t]+)\.FMC\}} $uvhs_trimmed_line -> uvhs_connector uvhs_instance]} { set uvhs_lower_connector [string tolower $uvhs_connector] - set uvhs_connector_fpga "" + set uvhs_remove_link 0 foreach uvhs_fpga $uvhs_known_fpgas { - if {[string first $uvhs_fpga $uvhs_lower_connector] == 0} { - set uvhs_connector_fpga $uvhs_fpga + if {[string first $uvhs_fpga $uvhs_lower_connector] == 0 && + [lsearch -exact $uvhs_keep_fpgas $uvhs_fpga] < 0} { + set uvhs_remove_link 1 break } } - if {$uvhs_connector_fpga ne "" && [lsearch -exact $uvhs_keep_fpgas $uvhs_connector_fpga] < 0} { + if {$uvhs_remove_link} { puts "INFO: UVHS selected-FPGA overlay: remove unused daughter-card link: $uvhs_trimmed_line" continue } @@ -131,12 +101,6 @@ foreach uvhs_line [split $uvhs_base_data "\n"] { continue } } - if {$uvhs_mem_dc ne "" && $uvhs_mem_dc ne "none" && - [string match "config_hw -connect_fpga *" $uvhs_trimmed_line] && - [string match "*$uvhs_mem_connector*" $uvhs_trimmed_line]} { - puts "INFO: UVHS memory overlay: remove connector conflict: $uvhs_trimmed_line" - continue - } lappend uvhs_filtered_lines $uvhs_line } set uvhs_base_data [join $uvhs_filtered_lines "\n"] @@ -153,76 +117,13 @@ foreach uvhs_fpga $uvhs_known_fpgas { set uvhs_create_board_replacements [regsub -line {^(config_hw[ \t]+-create_board_instance[ \t]+1[ \t]*)$} \ $uvhs_base_data "\\1\n$uvhs_unplug_overlay" uvhs_base_data] if {$uvhs_create_board_replacements != 1} { - puts "WARN: UVHS single-FPGA overlay: failed to insert unplug commands after create_board_instance; prepend overlay" + puts "WARN: UVHS selected-FPGA overlay: failed to insert unplug commands after create_board_instance; prepend overlay" set uvhs_base_data "$uvhs_unplug_overlay\n$uvhs_base_data" } -set uvhs_late_overlay "" -if {$uvhs_enable_clock_hub && ![regexp -line {^config_hw[ \t]+-create_clock_hub(?:[ \t]|$)} $uvhs_base_data]} { - # U2 global clocks are driven through the external ClockHub. The stock - # 1B/4F assembly has no ClockHub connection, leaving single-FPGA DUT clocks - # assigned to unplugged inter-FPGA connectors with no physical source. - append uvhs_late_overlay { -puts "INFO: UVHS single-board overlay: create and connect U2 ClockHub" -config_hw -create_clock_hub -config_hw -connect_board_clk {b0.GLBOUT0 hub0_0.IN00} -cable NV_CLK_1000 -config_hw -connect_board_clk {b0.GLBOUT1 hub0_0.IN04} -cable NV_CLK_1000 -config_hw -connect_board_clk {b0.GLBOUT2 hub0_0.IN08} -cable NV_CLK_1000 -config_hw -connect_board_clk {b0.GLBOUT3 hub0_0.IN12} -cable NV_CLK_1000 -config_hw -connect_board_clk {hub0_0.OUT00_0 b0.GLBIN0} -cable NV_CLK_1000 -config_hw -connect_board_clk {hub0_0.OUT00_1 b0.GLBIN1} -cable NV_CLK_1000 -config_hw -connect_board_clk {hub0_0.OUT00_2 b0.GLBIN2} -cable NV_CLK_1000 -config_hw -connect_board_clk {hub0_0.OUT00_3 b0.GLBIN3} -cable NV_CLK_1000 -} -} -if {$uvhs_mem_dc ne "" && $uvhs_mem_dc ne "none"} { - append uvhs_late_overlay [format { -puts "INFO: UVHS memory overlay: create %s as %s" -config_hw -create_daughter_card %s -instance %s -puts "INFO: UVHS memory overlay: connect %s to %s.FMC" -config_hw -connect_daughter_card {%s %s.FMC} -} $uvhs_mem_dc $uvhs_mem_inst $uvhs_mem_dc $uvhs_mem_inst $uvhs_mem_connector $uvhs_mem_inst $uvhs_mem_connector $uvhs_mem_inst] -} - -set uvhs_patched_data $uvhs_base_data -if {$uvhs_aux_ddr_dc ne "" && $uvhs_aux_ddr_dc ne "none"} { - if {$uvhs_aux_swap_base_connector ne "" && $uvhs_aux_swap_base_connector ne "none"} { - set uvhs_base_connect_anchor "^config_hw -connect_daughter_card \\{$uvhs_replace_connector $uvhs_replace_inst.FMC\\}\[ \t\]*$" - set uvhs_base_connect_replacement "config_hw -connect_daughter_card {$uvhs_aux_swap_base_connector $uvhs_replace_inst.FMC}" - set uvhs_base_connect_replacements [regsub -line $uvhs_base_connect_anchor $uvhs_patched_data $uvhs_base_connect_replacement uvhs_patched_data] - if {$uvhs_base_connect_replacements != 1} { - error "failed to move $uvhs_replace_inst from $uvhs_replace_connector to $uvhs_aux_swap_base_connector" - } - puts "INFO: UVHS memory overlay: move $uvhs_replace_inst from $uvhs_replace_connector to $uvhs_aux_swap_base_connector" - } - - set uvhs_aux_overlay [format { -puts "INFO: UVHS memory overlay: create auxiliary DDR %s as %s" -config_hw -create_daughter_card %s -instance %s -puts "INFO: UVHS memory overlay: connect %s to %s.FMC" -config_hw -connect_daughter_card {%s %s.FMC} -} $uvhs_aux_ddr_dc $uvhs_aux_ddr_inst $uvhs_aux_ddr_dc $uvhs_aux_ddr_inst $uvhs_aux_ddr_connector $uvhs_aux_ddr_inst $uvhs_aux_ddr_connector $uvhs_aux_ddr_inst] - - # U2/VU19P_X4 mandates FMC3 for UHD. An auxiliary PDDR4DME can satisfy a - # second consumer, but declaration order cannot move UHD away from FMC3. - # Functional AXI2DDR builds must therefore disable UHD probe insertion. - # hw.dat/Log/binding.log is authoritative for the resulting assignment. - set uvhs_aux_anchor "^config_hw -create_daughter_card UV_FMCH_PDDR4DME -instance $uvhs_replace_inst\[ \t\]*$" - set uvhs_aux_replacements [regsub -line $uvhs_aux_anchor $uvhs_patched_data "$uvhs_aux_overlay\n&" uvhs_patched_data] - if {$uvhs_aux_replacements != 1} { - puts "WARN: UVHS memory overlay: failed to insert auxiliary DDR before $uvhs_replace_inst; append before assemble" - append uvhs_late_overlay $uvhs_aux_overlay - } -} - -set uvhs_replacements [regsub -line {^config_hw[ \t]+-assemble[ \t]*$} $uvhs_patched_data "$uvhs_late_overlay\nconfig_hw -assemble" uvhs_patched_data] -if {$uvhs_replacements != 1} { - error "failed to patch assembly file before config_hw -assemble: $uvhs_base_assemble" -} - -set uvhs_overlay_file [file join [pwd] script .uvhs_assemble_with_mem_array.tcl] +set uvhs_overlay_file [file join [pwd] script .uvhs_assemble.tcl] set uvhs_fh [open $uvhs_overlay_file w] -puts -nonewline $uvhs_fh $uvhs_patched_data +puts -nonewline $uvhs_fh $uvhs_base_data close $uvhs_fh puts "INFO: source UVHS assembly overlay $uvhs_overlay_file" diff --git a/fpga_diff/uvhs/assign_pin_u22_f2.tcl b/fpga_diff/uvhs/assign_pin_u22_f2.tcl index a4f4ca5c..2d0a6fe7 100644 --- a/fpga_diff/uvhs/assign_pin_u22_f2.tcl +++ b/fpga_diff/uvhs/assign_pin_u22_f2.tcl @@ -1,18 +1,10 @@ ################################################################################ -# Pin assignment for NutShell fpga_diff on a single U2.2 VU19P FPGA (b0.f2). +# Pin assignment for fpga_diff on a single U2.2 VU19P FPGA (b0.f2). # -# This file is intended for UVHS flow bring-up on the current lab machine. The -# reference flow keeps only b0.f2 plugged in, so all user-visible top ports must -# bind to b0.F2_* connectors instead of the original mixed F0/F1/F2 template. +# This file targets the single-FPGA b0.f2 configuration. All user-visible top +# ports bind to b0.F2_* connectors instead of the mixed F0/F1/F2 template. ################################################################################ -proc assign_indexed_ports {prefix count connector indices} { - for {set i 0} {$i < $count} {incr i} { - set port [format {%s[%d]} $prefix $i] - assign_pin -port $port -connector $connector -index [lindex $indices $i] - } -} - proc pin_name {top port} { if {$top eq "" || $top eq "none"} { return $port @@ -21,13 +13,6 @@ proc pin_name {top port} { } set top [env_or_default UVHS_ASSIGN_PIN_TOP [env_or_default UVHS_TOP fpga_top_debug]] -set uvhs_mem_array_mode [expr {[env_or_default UVHS_MEM_ARRAY_DC none] eq "UV_MEM_ARRAY_F"}] -set uvhs_uvw_ddr4_mode [expr { - [env_or_default UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP 0] eq "1" - || [env_or_default UVHS_DDR_RTL_INST none] eq "${top}.core_def.U_UVHS_UVW_AXI4_TO_DDR4" -}] -set uvhs_mem_array_connector [env_or_default UVHS_MEM_ARRAY_CONNECTOR b0.F2_FMC1] -set uvhs_skip_pcie_pins [expr {[env_or_default UVHS_SKIP_PCIE_PINS 0] eq "1"}] set xdma_link_width [string toupper [string trim [env_or_default XDMA_LINK_WIDTH X4]]] if {$xdma_link_width ni {X4 X8}} { error "XDMA_LINK_WIDTH must be one of X4/X8, got '$xdma_link_width'" @@ -80,111 +65,37 @@ apc16_pin SD_DATA2 21 apc16_pin SD_DATA3 22 apc16_pin SD_DECT 23 -# U2 ClockHub global clocks on F2. Keep the three unrelated frequencies in -# separate ClockHub groups: gclk0 (0..4), gclk5 (5..9), gclk10 (10..14). -# Package pins are the F2 GlobalClk pins declared by the U2.2 board file. +# U2 global clocks on F2 use the package pins declared by the board file. assign_pin -port [pin_name $top clk6_p] -fpga b0.f2 -pin CA39 assign_pin -port [pin_name $top clk6_n] -fpga b0.f2 -pin CA40 assign_pin -port [pin_name $top clk8_p] -fpga b0.f2 -pin G36 assign_pin -port [pin_name $top clk8_n] -fpga b0.f2 -pin F36 assign_pin -port [pin_name $top clk5_p] -fpga b0.f2 -pin AW17 assign_pin -port [pin_name $top clk5_n] -fpga b0.f2 -pin AY17 -if {!$uvhs_mem_array_mode && !$uvhs_uvw_ddr4_mode} { - # clk7 is the Vivado DDR reference clock. UVHS direct DDR uses FP_CLK_200M - # on the same PDDR4DME pins, so do not assign both names to index 241/242. - assign_pin -port [pin_name $top clk7_p] -connector b0.F2_FMC3 -index 241 - assign_pin -port [pin_name $top clk7_n] -connector b0.F2_FMC3 -index 242 -} -if {$uvhs_skip_pcie_pins} { - puts "INFO: skip PCIe/XDMA pin assignment because UVHS_SKIP_PCIE_PINS=1" -} else { - assign_pin -port [pin_name $top pcie_ep_lnk_up] -connector b0.F2_APC16 -index 58 - - # XDMA endpoint signals. X4 uses the HGC7 lane group from the Hejian - # official XDMA EP example; bind HGC6 only when X8 is explicitly selected. - puts "INFO: assign XDMA PCIe pins for $xdma_link_width" - assign_pin -port [pin_name $top pcie_ep_gt_ref_clk_p] -connector b0.F2_HGC7 -index 29 - assign_pin -port [pin_name $top pcie_ep_gt_ref_clk_n] -connector b0.F2_HGC7 -index 30 - assign_pin -port [pin_name $top pcie_ep_perstn] -connector b0.F2_APC16 -index 118 - - set xdma_rx_connectors {b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC6 b0.F2_HGC6 b0.F2_HGC6 b0.F2_HGC6} - set xdma_tx_connectors {b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC6 b0.F2_HGC6 b0.F2_HGC6 b0.F2_HGC6} - set xdma_rxp_indices {16 13 4 1 16 13 4 1} - set xdma_rxn_indices {17 14 5 2 17 14 5 2} - set xdma_txp_indices {35 32 23 20 35 32 23 20} - set xdma_txn_indices {36 33 24 21 36 33 24 21} - for {set i 0} {$i < $xdma_lane_count} {incr i} { - assign_pin -port [pin_name $top [format {pci_ep_rxp[%d]} $i]] -connector [lindex $xdma_rx_connectors $i] -index [lindex $xdma_rxp_indices $i] - assign_pin -port [pin_name $top [format {pci_ep_rxn[%d]} $i]] -connector [lindex $xdma_rx_connectors $i] -index [lindex $xdma_rxn_indices $i] - assign_pin -port [pin_name $top [format {pci_ep_txp[%d]} $i]] -connector [lindex $xdma_tx_connectors $i] -index [lindex $xdma_txp_indices $i] - assign_pin -port [pin_name $top [format {pci_ep_txn[%d]} $i]] -connector [lindex $xdma_tx_connectors $i] -index [lindex $xdma_txn_indices $i] - } +assign_pin -port [pin_name $top pcie_ep_lnk_up] -connector b0.F2_APC16 -index 58 + +# XDMA endpoint signals. X4 uses the HGC7 lane group from the Hejian official +# XDMA EP example; bind HGC6 only when X8 is explicitly selected. +puts "INFO: assign XDMA PCIe pins for $xdma_link_width" +assign_pin -port [pin_name $top pcie_ep_gt_ref_clk_p] -connector b0.F2_HGC7 -index 29 +assign_pin -port [pin_name $top pcie_ep_gt_ref_clk_n] -connector b0.F2_HGC7 -index 30 +assign_pin -port [pin_name $top pcie_ep_perstn] -connector b0.F2_APC16 -index 118 + +set xdma_rx_connectors {b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC6 b0.F2_HGC6 b0.F2_HGC6 b0.F2_HGC6} +set xdma_tx_connectors {b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC7 b0.F2_HGC6 b0.F2_HGC6 b0.F2_HGC6 b0.F2_HGC6} +set xdma_rxp_indices {16 13 4 1 16 13 4 1} +set xdma_rxn_indices {17 14 5 2 17 14 5 2} +set xdma_txp_indices {35 32 23 20 35 32 23 20} +set xdma_txn_indices {36 33 24 21 36 33 24 21} +for {set i 0} {$i < $xdma_lane_count} {incr i} { + assign_pin -port [pin_name $top [format {pci_ep_rxp[%d]} $i]] -connector [lindex $xdma_rx_connectors $i] -index [lindex $xdma_rxp_indices $i] + assign_pin -port [pin_name $top [format {pci_ep_rxn[%d]} $i]] -connector [lindex $xdma_rx_connectors $i] -index [lindex $xdma_rxn_indices $i] + assign_pin -port [pin_name $top [format {pci_ep_txp[%d]} $i]] -connector [lindex $xdma_tx_connectors $i] -index [lindex $xdma_txp_indices $i] + assign_pin -port [pin_name $top [format {pci_ep_txn[%d]} $i]] -connector [lindex $xdma_tx_connectors $i] -index [lindex $xdma_txn_indices $i] } -# UVHS memory array connector. This is not a PDDR4DME pinout; only the TDM -# pins exposed by UV_MEM_ARRAY_F are legal on the daughter-card side. -if {$uvhs_mem_array_mode} { - assign_pin -port [pin_name $top uvw_mem_array_tdm_ref_clk_p] -connector $uvhs_mem_array_connector -index 241 - assign_pin -port [pin_name $top uvw_mem_array_tdm_ref_clk_n] -connector $uvhs_mem_array_connector -index 242 - assign_indexed_ports [pin_name $top uvw_mem_array_tdm_pin] 138 $uvhs_mem_array_connector { - 245 246 127 128 286 287 248 249 289 290 130 131 89 90 292 293 - 251 252 133 134 93 94 295 296 283 284 254 255 136 137 97 98 - 298 299 257 258 139 140 101 102 301 302 260 261 304 305 263 264 - 142 143 307 308 266 267 145 146 105 106 310 311 269 270 313 314 - 272 273 316 317 275 276 203 204 161 162 366 367 325 326 206 207 - 165 166 369 370 328 329 209 210 168 169 372 373 331 332 212 213 - 171 172 334 335 215 216 174 175 375 376 337 338 218 219 177 178 - 378 379 363 364 321 322 340 341 381 382 384 385 343 344 221 222 - 180 181 224 225 183 184 387 388 346 347 - } - return -} - -# The UVHS uvw_axi4_to_ddr4 IP declares: -# (* UV_HW_IP = "... toFPGA:" *) -# In that mode the UVHS daughter-card/IP binding owns the PDDR4DME DDR pins and -# emits the required *_pad_net_* constraints. Hand-assigning the naked -# FP_CLK_200M_* or DDR4_DIMM_* top ports here double-constrains the same pads -# and causes Vivado "pad already occupied" plus UCIO failures. -if {$uvhs_uvw_ddr4_mode} { - puts "INFO: skip manual PDDR4DME DDR pin assignment for UVHS uvw_axi4_to_ddr4 IP" - return -} - -# DDR4 PDDR4DME daughter card connected to b0.F2_FMC3 by 1B_4F_HGC_assemble.tcl. -assign_pin -port [pin_name $top FP_CLK_200M_P] -connector b0.F2_FMC3 -index 241 -assign_pin -port [pin_name $top FP_CLK_200M_N] -connector b0.F2_FMC3 -index 242 -assign_pin -port [pin_name $top {DDR4_DIMM_CK_P[0]}] -connector b0.F2_FMC3 -index 269 -assign_pin -port [pin_name $top {DDR4_DIMM_CK_P[1]}] -connector b0.F2_FMC3 -index 313 -assign_pin -port [pin_name $top {DDR4_DIMM_CK_N[0]}] -connector b0.F2_FMC3 -index 270 -assign_pin -port [pin_name $top {DDR4_DIMM_CK_N[1]}] -connector b0.F2_FMC3 -index 314 -assign_pin -port [pin_name $top DDR4_DIMM_RST_B] -connector b0.F2_FMC3 -index 227 -attribute {DRIVE:8} -assign_pin -port [pin_name $top {DDR4_DIMM_CKE[0]}] -connector b0.F2_FMC3 -index 169 -assign_pin -port [pin_name $top {DDR4_DIMM_CKE[1]}] -connector b0.F2_FMC3 -index 329 -assign_pin -port [pin_name $top {DDR4_DIMM_CS_N[0]}] -connector b0.F2_FMC3 -index 165 -assign_pin -port [pin_name $top {DDR4_DIMM_CS_N[1]}] -connector b0.F2_FMC3 -index 206 -assign_pin -port [pin_name $top {DDR4_DIMM_ODT[0]}] -connector b0.F2_FMC3 -index 325 -assign_pin -port [pin_name $top {DDR4_DIMM_ODT[1]}] -connector b0.F2_FMC3 -index 366 -assign_pin -port [pin_name $top DDR4_DIMM_ACT_N] -connector b0.F2_FMC3 -index 328 - -assign_indexed_ports [pin_name $top DDR4_DIMM_DQ] 72 b0.F2_FMC3 { - 263 101 301 305 304 102 302 264 - 307 105 267 310 311 106 308 266 - 257 136 254 258 298 137 255 299 - 181 225 388 387 180 346 347 224 - 177 178 338 375 337 379 378 376 - 216 334 213 212 215 335 332 331 - 292 295 94 251 296 293 93 252 - 286 289 127 131 290 287 130 128 - 344 343 341 340 385 384 321 322 -} -assign_indexed_ports [pin_name $top DDR4_DIMM_DM] 9 b0.F2_FMC3 {139 142 283 221 174 372 89 245 363} -assign_indexed_ports [pin_name $top DDR4_DIMM_DQS_P] 9 b0.F2_FMC3 {260 145 97 183 218 171 133 248 381} -assign_indexed_ports [pin_name $top DDR4_DIMM_DQS_N] 9 b0.F2_FMC3 {261 146 98 184 219 172 134 249 382} -assign_indexed_ports [pin_name $top DDR4_DIMM_A] 17 b0.F2_FMC3 { - 275 391 276 273 317 316 390 369 272 - 370 326 207 168 203 166 162 204 -} -assign_indexed_ports [pin_name $top DDR4_DIMM_BA] 2 b0.F2_FMC3 {161 367} -assign_indexed_ports [pin_name $top DDR4_DIMM_BG] 2 b0.F2_FMC3 {209 210} +# The vendor DDR DCP declares its PDDR4DME binding through UV_HW_IP metadata. +# UVHS owns those physical pins; assigning clk7 or DDR4_DIMM ports here would +# double-constrain the same daughter-card pads. +puts "INFO: vendor uvw_axi4_to_ddr4 IP owns the PDDR4DME DDR pin assignment" diff --git a/fpga_diff/uvhs/check_flow_tools.sh b/fpga_diff/uvhs/check_flow_tools.sh index 6730732b..7fb018fd 100644 --- a/fpga_diff/uvhs/check_flow_tools.sh +++ b/fpga_diff/uvhs/check_flow_tools.sh @@ -16,7 +16,6 @@ required=( uvhs/timing_common.tcl uvhs/export_vivado_ip.tcl uvhs/check_modules.sh - uvhs/filelist.awk uvhs/make_compat/make uvhs/make_compat/csh uvhs/patch_uvsyn_shell.sh @@ -24,7 +23,6 @@ required=( uvhs/uv_shell_exec_compat.sh uvhs/runtime_command.tcl user_script/hw_run_download.tcl - src/rtl/common/uvhs_ddr4_wrapper.sv src/tcl/common/AXI_bridge.tcl src/tcl/common/xdma_ep.tcl ) diff --git a/fpga_diff/uvhs/filelist.awk b/fpga_diff/uvhs/filelist.awk deleted file mode 100644 index 6d7c9e2e..00000000 --- a/fpga_diff/uvhs/filelist.awk +++ /dev/null @@ -1,5 +0,0 @@ -/^[[:space:]]*$/ { next } - -{ - print $0 -} diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 0b1b8a39..c7b917d7 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -65,7 +65,7 @@ UVHS_RUNTIME_COMMAND_FILE ?= $(UVHS_RUNTIME_WORK_DIR)/command.tcl UVHS_RUNTIME_TMP_DIR ?= $(UVHS_RUNTIME_WORK_DIR)/tmp UVHS_RUNTIME_DOWNLOAD_SCRIPT ?= $(UVHS_ROOT_DIR)/user_script/hw_run_download.tcl UVHS_RUNTIME_COMMAND_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/runtime_command.tcl -UVHS_RUNTIME_DDR_RTL ?= $(UVHS_DDR_RTL_INST).ddr4_ip +UVHS_RUNTIME_DDR_RTL ?= $(UVHS_DDR_RTL_INST) UVHS_RUNTIME_COMMAND_TIMEOUT ?= 600 UVHS_GBUS_BOARD ?= $(UVHS_TARGET_PACK) UVHS_GBUS_FPGA ?= $(UVHS_TARGET_FPGA) @@ -296,7 +296,7 @@ uvhs_filelist: uvhs_export_generalbus if [ -d "$$item" ]; then find "$$item" -type f \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ elif [ -f "$$item" ]; then case "$$item" in *.f|*.flist|*.list) cat "$$item";; *) printf '%s\n' "$$item";; esac; fi; \ done; \ - } | awk -f "$(UVHS_ROOT_DIR)/uvhs/filelist.awk" > "$(UVHS_FILELIST)" + } | awk 'NF' > "$(UVHS_FILELIST)" uvhs_check_modules: uvhs_filelist bash "$(UVHS_ROOT_DIR)/uvhs/check_modules.sh" "$(UVHS_FILELIST)" "$(UVHS_REQUIRED_MODULES)" @@ -309,7 +309,7 @@ uvhs_frontend: uvhs_export_vivado_ip uvhs_export_generalbus \ UVHS_DDR_RTL_INST="$(UVHS_DDR_RTL_INST)" UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP=1 \ UVHS_ASSIGN_PIN_FILE="$(UVHS_ASSIGN_PIN_FILE)" UVHS_TIMING_FILE="$(UVHS_TIMING_FILE)" \ UVHS_PARTITION_FILE=none UVHS_PROBE_FILE=none UVHS_ASSEMBLE_FILE="$(UVHS_ASSEMBLE_FILE)" \ - UVHS_MEM_ARRAY_DC=none UVHS_AUX_DDR_DC=none UVHS_USE_LSF="$(UVHS_USE_LSF)" \ + UVHS_USE_LSF="$(UVHS_USE_LSF)" \ UVHS_FRONTEND_THREADS="$(UVHS_FRONTEND_THREADS)" UVHS_FRONTEND_PROCESSES="$(UVHS_FRONTEND_PROCESSES)" \ UVHS_FPGA_THREADS="$(UVHS_FPGA_THREADS)" UVHS_FPGA_PROCESSES="$(UVHS_FPGA_PROCESSES)" \ bash "$$UV_ROOT/bin/uv_shell" -bypass_vivado_version_check \ @@ -319,7 +319,7 @@ uvhs_backend: bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ $(UVHS_FLOW_ENV) UVHS_TOP="$(UVHS_TOP)" UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP=1 \ UVHS_ASSIGN_PIN_FILE="$(UVHS_ASSIGN_PIN_FILE)" UVHS_ASSEMBLE_FILE="$(UVHS_ASSEMBLE_FILE)" \ - UVHS_MEM_ARRAY_DC=none UVHS_AUX_DDR_DC=none UVHS_USE_LSF="$(UVHS_USE_LSF)" \ + UVHS_USE_LSF="$(UVHS_USE_LSF)" \ UVHS_FPGA_THREADS="$(UVHS_FPGA_THREADS)" UVHS_FPGA_PROCESSES="$(UVHS_FPGA_PROCESSES)" \ bash "$$UV_ROOT/bin/uv_shell" -bypass_vivado_version_check \ -s "$(UVHS_ROOT_DIR)/uvhs/backend_run.tcl" |& tee backend_run.log' From 6dc0d10693405b013c413d232823a4dcd8aeb8cd Mon Sep 17 00:00:00 2001 From: klin02 Date: Thu, 30 Jul 2026 10:24:42 +0800 Subject: [PATCH 07/62] refactor(fpga_diff): detach UVHS runtime session Run uv_shell as a tracked background session so uvhs_write_bitstream returns after programming while later reset and memory commands retain the database connection. Move reset sequencing and command polling out of hw_run_download.tcl into shared runtime control procedures. Reject commands without a ready session and preserve the validated reset order. Co-authored-by: Kamimiao --- fpga_diff/user_script/hw_run_download.tcl | 80 +++-------- fpga_diff/uvhs/README.md | 21 ++- fpga_diff/uvhs/check_flow_tools.sh | 3 + fpga_diff/uvhs/runtime_command.tcl | 24 ++-- fpga_diff/uvhs/runtime_control.tcl | 110 +++++++++++++++ fpga_diff/uvhs/runtime_session.sh | 160 ++++++++++++++++++++++ fpga_diff/uvhs/uvhs.mk | 47 +++++-- 7 files changed, 353 insertions(+), 92 deletions(-) create mode 100644 fpga_diff/uvhs/runtime_control.tcl create mode 100755 fpga_diff/uvhs/runtime_session.sh diff --git a/fpga_diff/user_script/hw_run_download.tcl b/fpga_diff/user_script/hw_run_download.tcl index bf30a595..84ab410a 100644 --- a/fpga_diff/user_script/hw_run_download.tcl +++ b/fpga_diff/user_script/hw_run_download.tcl @@ -2,6 +2,19 @@ # reset control, and runtime memory operations. H2C remains available to the # host flow after download. +set uvhs_script_dir [file dirname [file normalize [info script]]] +if {[info exists ::env(UVHS_RUNTIME_CONTROL_SCRIPT)] && + $::env(UVHS_RUNTIME_CONTROL_SCRIPT) ne ""} { + set uvhs_control_script $::env(UVHS_RUNTIME_CONTROL_SCRIPT) +} else { + set uvhs_control_script \ + [file normalize [file join $uvhs_script_dir .. uvhs runtime_control.tcl]] +} +if {![file exists $uvhs_control_script]} { + error "UVHS runtime control script not found: $uvhs_control_script" +} +source $uvhs_control_script + query -user query -fpgas -all query -version @@ -12,7 +25,6 @@ query -version if {[info exists ::env(UVHS_DB_PATH)] && $::env(UVHS_DB_PATH) ne ""} { set uvhs_db_path $::env(UVHS_DB_PATH) } else { - set uvhs_script_dir [file dirname [file normalize [info script]]] set uvhs_db_path [file normalize [file join $uvhs_script_dir .. hw.dat]] } puts "INFO: loading runtime database $uvhs_db_path" @@ -33,13 +45,9 @@ if {[catch {query -clock -default} uvhs_clock_error]} { query -clock } -# Hold the top-level resets low across download, then release them in the -# same order used by the checked-in runtime scripts for this design. Runtime -# memory commands hold rstn_sw5 low while DDR is written. -reset -name rstn_sw6 -value 0 -reset -name rstn_sw5 -value 0 -reset -name rstn_sw4 -value 0 -query -reset +# Keep all reset sequencing in runtime_control.tcl so download and standalone +# reset commands use the same named operations. +uvhs_hold_soc_for_download download @@ -47,57 +55,9 @@ query -ipinfo initialize after 1000 -reset -name rstn_sw6 -value 0 -reset -name rstn_sw5 -value 0 -reset -name rstn_sw4 -value 0 -after 1000 - -reset -name rstn_sw6 -value 1 -reset -name rstn_sw4 -value 1 -after 1000 - -reset -name rstn_sw5 -value 1 -after 1000 - -query -reset +uvhs_release_soc_after_download query -fpgas -all -proc uvhs_poll_command_file {} { - if {![info exists ::env(UVHS_COMMAND_FILE)] || $::env(UVHS_COMMAND_FILE) eq ""} { - after 500 uvhs_poll_command_file - return - } - - set command_file $::env(UVHS_COMMAND_FILE) - if {[file exists $command_file]} { - set running_file "${command_file}.running" - set uvhs_result_file "" - set command_status [catch { - file rename -force $command_file $running_file - puts "INFO: sourcing UVHS runtime command: $running_file" - source $running_file - } command_message] - if {$command_status != 0} { - set command_message "UVHS runtime command failed: $command_message" - } - catch {file delete -force $running_file} - if {$uvhs_result_file ne ""} { - set result_tmp "${uvhs_result_file}.tmp.[pid]" - set result [open $result_tmp w] - puts $result $command_status - puts -nonewline $result $command_message - close $result - file rename -force $result_tmp $uvhs_result_file - } - if {$command_status != 0} { - puts stderr "ERROR: $command_message" - } - } - after 500 uvhs_poll_command_file -} - -# Keep the runtime attached after download. Other Make targets enqueue commands -# through UVHS_COMMAND_FILE; uvhs_runtime_stop ends this session cleanly. -set ::uvhs_keepalive 0 -uvhs_poll_command_file -vwait ::uvhs_keepalive +# The launcher detaches this service after programming. Runtime commands still +# execute in the same UVHS session that owns the downloaded database. +uvhs_serve_runtime_commands diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 94c3a7ca..0a81657d 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -77,10 +77,11 @@ LUT and 30% LUT6 fill limits and disabling the hold-expansion route bailout. UVHS runtime targets are separate from the normal Vivado LabTools targets: ```sh -# Keep this foreground process attached to the board. +# Program the FPGA and return after the detached runtime is ready. make uvhs_write_bitstream CPU= SUFFIX= -# Run these from another shell with the same CPU/SUFFIX or UVHS_WORK_DIR. +# Use the same CPU/SUFFIX or UVHS_WORK_DIR for later commands. +make uvhs_runtime_status CPU= SUFFIX= make uvhs_halt_soc CPU= SUFFIX= make uvhs_write_ddr CPU= SUFFIX= WORKLOAD=/path/to/image.txt make uvhs_write_flash CPU= SUFFIX= WORKLOAD=/path/to/image.bin @@ -90,11 +91,15 @@ make uvhs_runtime_stop CPU= SUFFIX= `uvhs_write_bitstream` loads the completed `hw.dat`, configures the connector and clocks, holds `rstn_sw6/rstn_sw5/rstn_sw4` low across `download`, calls -`initialize`, then releases system/DDR reset before CPU reset. The process -polls an atomic command file while it owns the runtime session. The other -runtime targets wait for command completion and propagate errors to Make. +`initialize`, then releases system/DDR reset before CPU reset. It leaves the +required UVHS runtime session detached, waits until its command service is +ready, and then returns. Session state and `uv_shell.log` live under +`runtime-work`; `uvhs_runtime_status` checks the PID and ready marker. The other +runtime targets fail immediately without a live session, wait for command +completion, and propagate errors to Make. Run `uvhs_runtime_stop` when finished. `uvhs_halt_soc` and `uvhs_reset_cpu` control `rstn_sw5`; the other two reset -names remain reserved for the system and external DDR IP. +names remain reserved for the system and external DDR IP. Download and runtime +commands share the reset sequences defined in `runtime_control.tcl`. `uvhs_write_ddr` accepts the same address/data-pair text file as the Vivado Tcl, converts each segment to the selected DCP word width, and writes the DDR IP @@ -127,7 +132,9 @@ database built before this generalBus path was added cannot use | `check_modules.sh`, `check_flow_tools.sh` | Validate the generated RTL file list and checked-in flow sources. | | `make_compat/` | Supplies the Bash-compatible commands required by UVHS-generated Makefiles and its `csh -fc limit` probe. | | `patch_uvsyn_shell.sh` | Patches the generated worker Makefile to run the vendor `uv_shell` script through Bash. | -| `enqueue_runtime_command.sh`, `runtime_command.tcl` | Atomically submit reset and memory operations to the attached runtime process. | +| `runtime_session.sh` | Starts, checks, and stops the detached UVHS runtime session. | +| `runtime_control.tcl` | Owns reset sequencing, readiness, and command servicing. | +| `enqueue_runtime_command.sh`, `runtime_command.tcl` | Atomically submit reset and memory operations to the runtime session. | | `uv_shell_exec_compat.sh` | Restores staged compatibility libraries after the vendor launcher sanitizes `LD_LIBRARY_PATH`. | | `../src/rtl/common/core_def_xdma.sv` | Instantiates the width-matched vendor DDR IP directly for UVHS builds. | | `../user_script/hw_run_download.tcl` | Downloads and initializes a completed UVHS database, then services runtime commands. | diff --git a/fpga_diff/uvhs/check_flow_tools.sh b/fpga_diff/uvhs/check_flow_tools.sh index 7fb018fd..401862c2 100644 --- a/fpga_diff/uvhs/check_flow_tools.sh +++ b/fpga_diff/uvhs/check_flow_tools.sh @@ -20,7 +20,9 @@ required=( uvhs/make_compat/csh uvhs/patch_uvsyn_shell.sh uvhs/enqueue_runtime_command.sh + uvhs/runtime_session.sh uvhs/uv_shell_exec_compat.sh + uvhs/runtime_control.tcl uvhs/runtime_command.tcl user_script/hw_run_download.tcl src/tcl/common/AXI_bridge.tcl @@ -40,6 +42,7 @@ bash -n "$root_dir/uvhs/make_compat/make" bash -n "$root_dir/uvhs/make_compat/csh" bash -n "$root_dir/uvhs/patch_uvsyn_shell.sh" bash -n "$root_dir/uvhs/enqueue_runtime_command.sh" +bash -n "$root_dir/uvhs/runtime_session.sh" bash -n "$root_dir/uvhs/uv_shell_exec_compat.sh" if command -v tclsh >/dev/null 2>&1; then diff --git a/fpga_diff/uvhs/runtime_command.tcl b/fpga_diff/uvhs/runtime_command.tcl index d0e956ce..c46e85c3 100644 --- a/fpga_diff/uvhs/runtime_command.tcl +++ b/fpga_diff/uvhs/runtime_command.tcl @@ -1,3 +1,8 @@ +if {[llength [info commands uvhs_reset_cpu]] == 0} { + set uvhs_script_dir [file dirname [file normalize [info script]]] + source [file join $uvhs_script_dir runtime_control.tcl] +} + proc uvhs_temp_dir {} { if {[info exists ::env(UVHS_RUNTIME_TMP_DIR)] && $::env(UVHS_RUNTIME_TMP_DIR) ne ""} { set path $::env(UVHS_RUNTIME_TMP_DIR) @@ -164,34 +169,25 @@ set uvhs_command [lindex $argv 0] puts "INFO: executing UVHS runtime command: $uvhs_command" switch -- $uvhs_command { halt_soc { - reset -name rstn_sw5 -value 0 - query -reset + uvhs_halt_soc } reset_cpu { - reset -name rstn_sw5 -value 0 - after 500 - reset -name rstn_sw5 -value 1 - after 500 - query -reset + uvhs_reset_cpu } write_ddr { if {[llength $argv] < 4} { error "write_ddr expects 3 arguments" } - reset -name rstn_sw5 -value 0 - after 100 + uvhs_hold_cpu_for_memory uvhs_write_ddr_pairs [lindex $argv 1] [lindex $argv 2] [lindex $argv 3] } write_flash { if {[llength $argv] < 8} { error "write_flash expects 7 arguments" } - reset -name rstn_sw5 -value 0 - after 100 + uvhs_hold_cpu_for_memory uvhs_write_flash_gbus {*}[lrange $argv 1 7] - reset -name rstn_sw5 -value 1 - after 500 - query -reset + uvhs_release_cpu_after_memory } stop { set ::uvhs_keepalive 1 diff --git a/fpga_diff/uvhs/runtime_control.tcl b/fpga_diff/uvhs/runtime_control.tcl new file mode 100644 index 00000000..e2a67364 --- /dev/null +++ b/fpga_diff/uvhs/runtime_control.tcl @@ -0,0 +1,110 @@ +proc uvhs_hold_soc_for_download {} { + reset -name rstn_sw6 -value 0 + reset -name rstn_sw5 -value 0 + reset -name rstn_sw4 -value 0 + query -reset +} + +proc uvhs_release_soc_after_download {} { + reset -name rstn_sw6 -value 0 + reset -name rstn_sw5 -value 0 + reset -name rstn_sw4 -value 0 + after 1000 + + reset -name rstn_sw6 -value 1 + reset -name rstn_sw4 -value 1 + after 1000 + + reset -name rstn_sw5 -value 1 + after 1000 + query -reset +} + +proc uvhs_halt_soc {} { + reset -name rstn_sw5 -value 0 + query -reset +} + +proc uvhs_reset_cpu {} { + reset -name rstn_sw5 -value 0 + after 500 + reset -name rstn_sw5 -value 1 + after 500 + query -reset +} + +proc uvhs_hold_cpu_for_memory {} { + reset -name rstn_sw5 -value 0 + after 100 +} + +proc uvhs_release_cpu_after_memory {} { + reset -name rstn_sw5 -value 1 + after 500 + query -reset +} + +proc uvhs_signal_runtime_ready {} { + if {![info exists ::env(UVHS_RUNTIME_READY_FILE)] || + $::env(UVHS_RUNTIME_READY_FILE) eq ""} { + return + } + + set ready_file $::env(UVHS_RUNTIME_READY_FILE) + file mkdir [file dirname $ready_file] + set temp_file "${ready_file}.tmp.[pid]" + set output [open $temp_file w] + puts $output [pid] + close $output + file rename -force $temp_file $ready_file + puts "INFO: UVHS runtime command service is ready" +} + +proc uvhs_clear_runtime_ready {} { + if {[info exists ::env(UVHS_RUNTIME_READY_FILE)] && + $::env(UVHS_RUNTIME_READY_FILE) ne ""} { + file delete -force $::env(UVHS_RUNTIME_READY_FILE) + } +} + +proc uvhs_poll_command_file {} { + if {![info exists ::env(UVHS_COMMAND_FILE)] || $::env(UVHS_COMMAND_FILE) eq ""} { + after 500 uvhs_poll_command_file + return + } + + set command_file $::env(UVHS_COMMAND_FILE) + if {[file exists $command_file]} { + set running_file "${command_file}.running" + set uvhs_result_file "" + set command_status [catch { + file rename -force $command_file $running_file + puts "INFO: sourcing UVHS runtime command: $running_file" + source $running_file + } command_message] + if {$command_status != 0} { + set command_message "UVHS runtime command failed: $command_message" + } + catch {file delete -force $running_file} + if {$uvhs_result_file ne ""} { + set result_tmp "${uvhs_result_file}.tmp.[pid]" + set result [open $result_tmp w] + puts $result $command_status + puts -nonewline $result $command_message + close $result + file rename -force $result_tmp $uvhs_result_file + } + if {$command_status != 0} { + puts stderr "ERROR: $command_message" + } + } + after 500 uvhs_poll_command_file +} + +proc uvhs_serve_runtime_commands {} { + set ::uvhs_keepalive 0 + uvhs_signal_runtime_ready + uvhs_poll_command_file + vwait ::uvhs_keepalive + uvhs_clear_runtime_ready +} diff --git a/fpga_diff/uvhs/runtime_session.sh b/fpga_diff/uvhs/runtime_session.sh new file mode 100755 index 00000000..05f6abf1 --- /dev/null +++ b/fpga_diff/uvhs/runtime_session.sh @@ -0,0 +1,160 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat >&2 <<'EOF' +usage: + runtime_session.sh start \ + [argument ...] + runtime_session.sh active + runtime_session.sh check + runtime_session.sh wait +EOF + exit 64 +} + +read_pid() { + local pid_file=$1 + local pid + [[ -f $pid_file ]] || return 1 + IFS= read -r pid <"$pid_file" || return 1 + [[ $pid =~ ^[1-9][0-9]*$ ]] || return 1 + printf '%s\n' "$pid" +} + +process_is_alive() { + kill -0 "$1" 2>/dev/null +} + +validate_timeout() { + [[ $1 =~ ^[1-9][0-9]*$ ]] || { + echo "ERROR: UVHS runtime timeout must be a positive integer" >&2 + exit 64 + } +} + +show_log_tail() { + local log_file=$1 + if [[ -f $log_file ]]; then + echo "----- UVHS runtime log tail: $log_file -----" >&2 + tail -40 "$log_file" >&2 + fi +} + +action=${1:-} +[[ -n $action ]] || usage +shift + +case $action in + start) + (( $# >= 6 )) || usage + pid_file=$1 + ready_file=$2 + log_file=$3 + command_file=$4 + timeout=$5 + shift 5 + validate_timeout "$timeout" + + if pid=$(read_pid "$pid_file") && process_is_alive "$pid"; then + echo "ERROR: UVHS runtime is already active with PID $pid" >&2 + echo "Run make uvhs_runtime_stop before programming again." >&2 + exit 2 + fi + + mkdir -p "$(dirname "$pid_file")" "$(dirname "$ready_file")" \ + "$(dirname "$log_file")" "$(dirname "$command_file")" + rm -f "$pid_file" "$ready_file" "$command_file" "${command_file}.running" + + nohup "$@" "$log_file" 2>&1 & + pid=$! + pid_temp="${pid_file}.tmp.$$" + printf '%s\n' "$pid" >"$pid_temp" + mv -f "$pid_temp" "$pid_file" + + deadline=$((SECONDS + timeout)) + while [[ ! -f $ready_file ]]; do + if ! process_is_alive "$pid"; then + set +e + wait "$pid" + status=$? + set -e + rm -f "$pid_file" "$ready_file" + show_log_tail "$log_file" + echo "ERROR: UVHS runtime exited before it became ready (status $status)" >&2 + exit 3 + fi + if (( SECONDS >= deadline )); then + kill "$pid" 2>/dev/null || true + wait "$pid" 2>/dev/null || true + rm -f "$pid_file" "$ready_file" + show_log_tail "$log_file" + echo "ERROR: timed out waiting for UVHS runtime after ${timeout}s" >&2 + exit 4 + fi + sleep 0.2 + done + + if ! runtime_pid=$(read_pid "$ready_file") || ! process_is_alive "$runtime_pid"; then + rm -f "$pid_file" "$ready_file" + show_log_tail "$log_file" + echo "ERROR: UVHS runtime published an invalid ready PID" >&2 + exit 5 + fi + pid_temp="${pid_file}.tmp.$$" + printf '%s\n' "$runtime_pid" >"$pid_temp" + mv -f "$pid_temp" "$pid_file" + echo "INFO: UVHS runtime ready (PID $runtime_pid); log: $log_file" + ;; + active) + (( $# == 1 )) || usage + pid_file=$1 + if pid=$(read_pid "$pid_file") && process_is_alive "$pid"; then + echo "INFO: UVHS runtime process is active (PID $pid)" + exit 0 + fi + rm -f "$pid_file" + exit 1 + ;; + check) + (( $# == 2 )) || usage + pid_file=$1 + ready_file=$2 + if ! pid=$(read_pid "$pid_file") || ! process_is_alive "$pid"; then + rm -f "$pid_file" "$ready_file" + echo "ERROR: UVHS runtime is not active; run make uvhs_write_bitstream first" >&2 + exit 6 + fi + if ! ready_pid=$(read_pid "$ready_file") || [[ $ready_pid != "$pid" ]]; then + echo "ERROR: UVHS runtime PID $pid has no matching ready marker" >&2 + exit 7 + fi + echo "INFO: UVHS runtime is ready (PID $pid)" + ;; + wait) + (( $# == 4 )) || usage + pid_file=$1 + ready_file=$2 + command_file=$3 + timeout=$4 + validate_timeout "$timeout" + + if ! pid=$(read_pid "$pid_file"); then + rm -f "$ready_file" "$command_file" "${command_file}.running" + exit 0 + fi + deadline=$((SECONDS + timeout)) + while process_is_alive "$pid"; do + if (( SECONDS >= deadline )); then + echo "ERROR: timed out waiting for UVHS runtime PID $pid to stop" >&2 + exit 8 + fi + sleep 0.2 + done + rm -f "$pid_file" "$ready_file" "$command_file" "${command_file}.running" + echo "INFO: UVHS runtime stopped" + ;; + *) + usage + ;; +esac diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index c7b917d7..3f39e317 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -63,9 +63,15 @@ UVHS_RUNTIME_DB ?= $(UVHS_WORK_DIR)/hw.dat UVHS_RUNTIME_WORK_DIR ?= $(UVHS_WORK_DIR)/runtime-work UVHS_RUNTIME_COMMAND_FILE ?= $(UVHS_RUNTIME_WORK_DIR)/command.tcl UVHS_RUNTIME_TMP_DIR ?= $(UVHS_RUNTIME_WORK_DIR)/tmp +UVHS_RUNTIME_PID_FILE ?= $(UVHS_RUNTIME_WORK_DIR)/uv_shell.pid +UVHS_RUNTIME_READY_FILE ?= $(UVHS_RUNTIME_WORK_DIR)/uv_shell.ready +UVHS_RUNTIME_LOG ?= $(UVHS_RUNTIME_WORK_DIR)/uv_shell.log UVHS_RUNTIME_DOWNLOAD_SCRIPT ?= $(UVHS_ROOT_DIR)/user_script/hw_run_download.tcl +UVHS_RUNTIME_CONTROL_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/runtime_control.tcl UVHS_RUNTIME_COMMAND_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/runtime_command.tcl +UVHS_RUNTIME_SESSION_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/runtime_session.sh UVHS_RUNTIME_DDR_RTL ?= $(UVHS_DDR_RTL_INST) +UVHS_RUNTIME_START_TIMEOUT ?= 600 UVHS_RUNTIME_COMMAND_TIMEOUT ?= 600 UVHS_GBUS_BOARD ?= $(UVHS_TARGET_PACK) UVHS_GBUS_FPGA ?= $(UVHS_TARGET_FPGA) @@ -113,7 +119,7 @@ UVHS_BIT_HOME ?= $(UVHS_WORK_DIR)/ready-to-program uvhs_frontend uvhs_backend uvhs_all uvhs_check_timing \ uvhs_package_bitstream uvhs_tools_check uvhs_clean uvhs_write_bitstream \ uvhs_halt_soc uvhs_reset_cpu uvhs_write_ddr uvhs_write_flash \ - uvhs_runtime_stop + uvhs_runtime_status uvhs_runtime_check uvhs_runtime_stop uvhs_preflight: test -n "$$UV_ROOT" @@ -336,39 +342,52 @@ uvhs_package_bitstream: uvhs_check_timing ln -sf "$(UVHS_BITSTREAM_DIR)/pnr.bit" "$(UVHS_BIT_HOME)/fpga_top_debug.bit" @echo "FPGA_BIT_HOME=$(UVHS_BIT_HOME)" -# Runtime stays in the foreground because uv_shell owns the board session. -# Use another shell for the command targets below while this target is active. +# The UVHS API requires one session to retain ownership of the downloaded +# database. Detach that session after programming and track it in runtime-work. uvhs_write_bitstream: test -d "$(UVHS_RUNTIME_DB)" test -f "$(UVHS_RUNTIME_DOWNLOAD_SCRIPT)" - test ! -e "$(UVHS_RUNTIME_COMMAND_FILE)" - test ! -e "$(UVHS_RUNTIME_COMMAND_FILE).running" + test -f "$(UVHS_RUNTIME_CONTROL_SCRIPT)" + test -x "$(UVHS_RUNTIME_SESSION_SCRIPT)" mkdir -p "$(UVHS_RUNTIME_WORK_DIR)" "$(UVHS_RUNTIME_TMP_DIR)" $(UVHS_TOOL_ENV) UVHS_DB_PATH="$(UVHS_RUNTIME_DB)" \ UVHS_COMMAND_FILE="$(UVHS_RUNTIME_COMMAND_FILE)" \ + UVHS_RUNTIME_READY_FILE="$(UVHS_RUNTIME_READY_FILE)" \ UVHS_RUNTIME_TMP_DIR="$(UVHS_RUNTIME_TMP_DIR)" \ - bash "$$UV_ROOT/bin/uv_shell" -rt_shell \ + UVHS_RUNTIME_CONTROL_SCRIPT="$(UVHS_RUNTIME_CONTROL_SCRIPT)" \ + bash "$(UVHS_RUNTIME_SESSION_SCRIPT)" start \ + "$(UVHS_RUNTIME_PID_FILE)" "$(UVHS_RUNTIME_READY_FILE)" \ + "$(UVHS_RUNTIME_LOG)" "$(UVHS_RUNTIME_COMMAND_FILE)" \ + "$(UVHS_RUNTIME_START_TIMEOUT)" \ + bash "$$UV_ROOT/bin/uv_shell" -rt_shell \ -workdir "$(UVHS_RUNTIME_WORK_DIR)" \ -script "$(UVHS_RUNTIME_DOWNLOAD_SCRIPT)" -uvhs_halt_soc: +uvhs_runtime_check: + bash "$(UVHS_RUNTIME_SESSION_SCRIPT)" check \ + "$(UVHS_RUNTIME_PID_FILE)" "$(UVHS_RUNTIME_READY_FILE)" + +uvhs_runtime_status: uvhs_runtime_check + @echo "UVHS_RUNTIME_LOG=$(UVHS_RUNTIME_LOG)" + +uvhs_halt_soc: uvhs_runtime_check UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_COMMAND_TIMEOUT)" \ bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" halt_soc -uvhs_reset_cpu: +uvhs_reset_cpu: uvhs_runtime_check UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_COMMAND_TIMEOUT)" \ bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" reset_cpu -uvhs_write_ddr: +uvhs_write_ddr: uvhs_runtime_check test -f "$(WORKLOAD)" UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_COMMAND_TIMEOUT)" \ bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" \ write_ddr "$(WORKLOAD)" "$(UVHS_RUNTIME_DDR_RTL)" "$(UVHS_DDR_AXI_WIDTH)" -uvhs_write_flash: +uvhs_write_flash: uvhs_runtime_check test -f "$(WORKLOAD)" UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_COMMAND_TIMEOUT)" \ bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ @@ -377,11 +396,17 @@ uvhs_write_flash: "$(UVHS_GBUS_PORT)" "$(UVHS_GBUS_CHANNEL)" \ "$(UVHS_FLASH_BASE)" "$(UVHS_FLASH_SIZE)" -uvhs_runtime_stop: +uvhs_runtime_stop: uvhs_runtime_check UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_COMMAND_TIMEOUT)" \ bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" stop + bash "$(UVHS_RUNTIME_SESSION_SCRIPT)" wait \ + "$(UVHS_RUNTIME_PID_FILE)" "$(UVHS_RUNTIME_READY_FILE)" \ + "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_TIMEOUT)" uvhs_clean: + @! bash "$(UVHS_RUNTIME_SESSION_SCRIPT)" active \ + "$(UVHS_RUNTIME_PID_FILE)" >/dev/null 2>&1 || \ + { echo "ERROR: stop the UVHS runtime before cleaning" >&2; exit 1; } test -n "$(UVHS_WORK_DIR)" rm -rf "$(UVHS_WORK_DIR)" From 1ffe1740d2ab81a921e22fc89e62b9348e1812d5 Mon Sep 17 00:00:00 2001 From: klin02 Date: Sun, 2 Aug 2026 15:53:07 +0800 Subject: [PATCH 08/62] fix(fpga_diff): align UVHS flash address mapping Map the UVHS GeneralBus master address space to the flash target at offset zero and issue runtime DMA transfers from the same base. Keep CPU and JTAG flash mappings at 0x10000000. This matches the validated 64-bit GeneralBus path and restores full-image readback. Co-authored-by: Kamimiao --- fpga_diff/src/tcl/common/AXI_bridge.tcl | 2 +- fpga_diff/uvhs/uvhs.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fpga_diff/src/tcl/common/AXI_bridge.tcl b/fpga_diff/src/tcl/common/AXI_bridge.tcl index 59b5783d..ce08a588 100644 --- a/fpga_diff/src/tcl/common/AXI_bridge.tcl +++ b/fpga_diff/src/tcl/common/AXI_bridge.tcl @@ -426,7 +426,7 @@ proc create_root_design { parentCell } { exclude_bd_addr_seg -target_address_space [get_bd_addr_spaces jtag_axi_flash/Data] [get_bd_addr_segs axi_uart16550_0/S_AXI/Reg] exclude_bd_addr_seg -target_address_space [get_bd_addr_spaces jtag_axi_flash/Data] [get_bd_addr_segs extllc_bram_ctrl/S_AXI/Mem0] if {$uvhs_flow} { - assign_bd_address -offset 0x10000000 -range 0x00100000 -target_address_space [get_bd_addr_spaces UVHS_FLASH_AXI] [get_bd_addr_segs rom_axi/Reg] -force + assign_bd_address -offset 0x00000000 -range 0x00100000 -target_address_space [get_bd_addr_spaces UVHS_FLASH_AXI] [get_bd_addr_segs rom_axi/Reg] -force exclude_bd_addr_seg -target_address_space [get_bd_addr_spaces UVHS_FLASH_AXI] [get_bd_addr_segs SYS_CFG_APB/Reg] exclude_bd_addr_seg -target_address_space [get_bd_addr_spaces UVHS_FLASH_AXI] [get_bd_addr_segs axi_uart16550_0/S_AXI/Reg] exclude_bd_addr_seg -target_address_space [get_bd_addr_spaces UVHS_FLASH_AXI] [get_bd_addr_segs extllc_bram_ctrl/S_AXI/Mem0] diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 3f39e317..18ce2a8e 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -77,7 +77,7 @@ UVHS_GBUS_BOARD ?= $(UVHS_TARGET_PACK) UVHS_GBUS_FPGA ?= $(UVHS_TARGET_FPGA) UVHS_GBUS_PORT ?= 0 UVHS_GBUS_CHANNEL ?= 0 -UVHS_FLASH_BASE ?= 0x10000000 +UVHS_FLASH_BASE ?= 0x0 UVHS_FLASH_SIZE ?= 0x8000 UVHS_COMPAT_PCRE_LIB ?= UVHS_SHELL_EXEC_WRAPPER ?= $(UVHS_ROOT_DIR)/uvhs/uv_shell_exec_compat.sh From 5ee5d28242ad40b725723efdfef14361ca6e9301 Mon Sep 17 00:00:00 2001 From: klin02 Date: Sun, 2 Aug 2026 17:44:33 +0800 Subject: [PATCH 09/62] refactor(fpga_diff): simplify UVHS flow scripts Replace generated Vivado Tcl and XDC rewrites with one explicit pre-opt stage for the required XDMA refclock and CDC constraints. Keep only the Bash and runtime-library compatibility required by the validated installation. Build XiangShan from fpga-release RTL, normalize external file lists, and move the download entry point under uvhs/. Co-authored-by: Kamimiao --- fpga_diff/tools/update_core_flist.sh | 98 +- fpga_diff/user_script/.gitignore | 3 - fpga_diff/user_script/hw_run_download.tcl | 63 - fpga_diff/uvhs/README.md | 182 +-- fpga_diff/uvhs/backend_run.tcl | 1325 +-------------------- fpga_diff/uvhs/check_flow_tools.sh | 11 +- fpga_diff/uvhs/frontend_run.tcl | 247 ++-- fpga_diff/uvhs/hw_run_download.tcl | 51 + fpga_diff/uvhs/patch_uvsyn_shell.sh | 28 - fpga_diff/uvhs/shell_compat.sh | 80 ++ fpga_diff/uvhs/uvhs.mk | 111 +- fpga_diff/uvhs/vivado_pre_opt.tcl | 89 ++ 12 files changed, 609 insertions(+), 1679 deletions(-) delete mode 100644 fpga_diff/user_script/.gitignore delete mode 100644 fpga_diff/user_script/hw_run_download.tcl create mode 100644 fpga_diff/uvhs/hw_run_download.tcl delete mode 100755 fpga_diff/uvhs/patch_uvsyn_shell.sh create mode 100755 fpga_diff/uvhs/shell_compat.sh create mode 100644 fpga_diff/uvhs/vivado_pre_opt.tcl diff --git a/fpga_diff/tools/update_core_flist.sh b/fpga_diff/tools/update_core_flist.sh index 47a0100f..4166d048 100755 --- a/fpga_diff/tools/update_core_flist.sh +++ b/fpga_diff/tools/update_core_flist.sh @@ -8,7 +8,7 @@ fail() { } usage() { - echo "Usage: $0 CORE_DIR [--] [RTL_INCLUDE ...]" >&2 + echo "Usage: $0 CORE_DIR [--external-only] [--output-filelist FILE] [--] [RTL_INCLUDE ...]" >&2 exit 2 } @@ -16,15 +16,39 @@ usage() { core_dir=$1 shift -if [[ ${1:-} == -- ]]; then - shift -fi - -[[ -d $core_dir ]] || fail "CORE_DIR is not a directory: $core_dir" fpga_diff_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd) awk_script="$fpga_diff_dir/core_flist.awk" output_tcl="$fpga_diff_dir/src/tcl/cpu_files.tcl" +output_filelist="" +external_only=0 + +while (($#)); do + case $1 in + --external-only) + external_only=1 + shift + ;; + --output-filelist) + [[ $# -ge 2 ]] || usage + output_filelist=$2 + shift 2 + ;; + --) + shift + break + ;; + *) + break + ;; + esac +done + +[[ -d $core_dir ]] || fail "CORE_DIR is not a directory: $core_dir" +if [[ $external_only == 1 && -z $output_filelist ]]; then + fail "--external-only requires --output-filelist" +fi + tmp_dir=$(mktemp -d) trap 'rm -rf "$tmp_dir"' EXIT @@ -178,26 +202,48 @@ for rtl_include in "$@"; do fi done -core_dir=$(realpath -e -- "$core_dir") -find "$core_dir" -path "$core_dir/rtl/verification" -prune -o \ - -type f \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ - -print | LC_ALL=C sort > "$tmp_dir/cpu_files" -: > "$tmp_dir/rtl_files" -: > "$tmp_dir/rtl_include_dirs" -if ((${#rtl_files[@]})); then - printf '%s\n' "${rtl_files[@]}" > "$tmp_dir/rtl_files" -fi -if ((${#rtl_include_dirs[@]})); then - printf '%s\n' "${rtl_include_dirs[@]}" > "$tmp_dir/rtl_include_dirs" +if [[ $external_only == 0 ]]; then + core_dir=$(realpath -e -- "$core_dir") + find "$core_dir" -path "$core_dir/rtl/verification" -prune -o \ + -type f \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ + -print | LC_ALL=C sort > "$tmp_dir/cpu_files" + : > "$tmp_dir/rtl_files" + : > "$tmp_dir/rtl_include_dirs" + if ((${#rtl_files[@]})); then + printf '%s\n' "${rtl_files[@]}" > "$tmp_dir/rtl_files" + fi + if ((${#rtl_include_dirs[@]})); then + printf '%s\n' "${rtl_include_dirs[@]}" > "$tmp_dir/rtl_include_dirs" + fi + + tmp_output="$tmp_dir/cpu_files.tcl" + awk -v var=cpu_files -v detect_simtop_dma=1 -f "$awk_script" \ + "$tmp_dir/cpu_files" > "$tmp_output" + awk -v var=rtl_include_files -f "$awk_script" \ + "$tmp_dir/rtl_files" >> "$tmp_output" + awk -v var=rtl_include_dirs -f "$awk_script" \ + "$tmp_dir/rtl_include_dirs" >> "$tmp_output" + mkdir -p "$(dirname -- "$output_tcl")" + mv -- "$tmp_output" "$output_tcl" fi -tmp_output="$tmp_dir/cpu_files.tcl" -awk -v var=cpu_files -v detect_simtop_dma=1 -f "$awk_script" \ - "$tmp_dir/cpu_files" > "$tmp_output" -awk -v var=rtl_include_files -f "$awk_script" \ - "$tmp_dir/rtl_files" >> "$tmp_output" -awk -v var=rtl_include_dirs -f "$awk_script" \ - "$tmp_dir/rtl_include_dirs" >> "$tmp_output" -mv -- "$tmp_output" "$output_tcl" +if [[ -n $output_filelist ]]; then + tmp_output="$tmp_dir/rtl_include.f" + { + if ((${#rtl_include_dirs[@]})); then + printf '+incdir+%s\n' "${rtl_include_dirs[@]}" + fi + if ((${#rtl_files[@]})); then + printf '%s\n' "${rtl_files[@]}" + fi + } > "$tmp_output" + mkdir -p "$(dirname -- "$output_filelist")" + mv -- "$tmp_output" "$output_filelist" +fi -echo "INFO: generated $output_tcl with ${#rtl_files[@]} external RTL files" +if [[ $external_only == 0 ]]; then + echo "INFO: generated $output_tcl with ${#rtl_files[@]} external RTL files" +fi +if [[ -n $output_filelist ]]; then + echo "INFO: generated $output_filelist with ${#rtl_files[@]} external RTL files" +fi diff --git a/fpga_diff/user_script/.gitignore b/fpga_diff/user_script/.gitignore deleted file mode 100644 index 6ab2da6e..00000000 --- a/fpga_diff/user_script/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -* -!.gitignore -!hw_run_download.tcl diff --git a/fpga_diff/user_script/hw_run_download.tcl b/fpga_diff/user_script/hw_run_download.tcl deleted file mode 100644 index 84ab410a..00000000 --- a/fpga_diff/user_script/hw_run_download.tcl +++ /dev/null @@ -1,63 +0,0 @@ -# UVHS runtime download flow. A release database is sufficient for programming, -# reset control, and runtime memory operations. H2C remains available to the -# host flow after download. - -set uvhs_script_dir [file dirname [file normalize [info script]]] -if {[info exists ::env(UVHS_RUNTIME_CONTROL_SCRIPT)] && - $::env(UVHS_RUNTIME_CONTROL_SCRIPT) ne ""} { - set uvhs_control_script $::env(UVHS_RUNTIME_CONTROL_SCRIPT) -} else { - set uvhs_control_script \ - [file normalize [file join $uvhs_script_dir .. uvhs runtime_control.tcl]] -} -if {![file exists $uvhs_control_script]} { - error "UVHS runtime control script not found: $uvhs_control_script" -} -source $uvhs_control_script - -query -user -query -fpgas -all -query -version - -# uv_shell runtime invocation does not guarantee the script directory as the -# current working directory. Prefer an explicit override, otherwise assume the -# staged hw.dat sits next to user_script/ in the runtime directory. -if {[info exists ::env(UVHS_DB_PATH)] && $::env(UVHS_DB_PATH) ne ""} { - set uvhs_db_path $::env(UVHS_DB_PATH) -} else { - set uvhs_db_path [file normalize [file join $uvhs_script_dir .. hw.dat]] -} -puts "INFO: loading runtime database $uvhs_db_path" -load_db -db $uvhs_db_path - -config -connector -query -connector -type fmc -query -voltage - -# Some release databases carry replay clock values without UVHS sign-off -# frequencies. Configure defaults when available; otherwise retain the -# database replay clocks, as the x4 runtime template does. -if {[catch {query -clock -default} uvhs_clock_error]} { - puts "WARN: no sign-off default clock; retaining database replay clocks: $uvhs_clock_error" -} else { - config -clock -default - config -clock -commit - query -clock -} - -# Keep all reset sequencing in runtime_control.tcl so download and standalone -# reset commands use the same named operations. -uvhs_hold_soc_for_download - -download - -query -ipinfo -initialize -after 1000 - -uvhs_release_soc_after_download -query -fpgas -all - -# The launcher detaches this service after programming. Runtime commands still -# execute in the same UVHS session that owns the downloaded database. -uvhs_serve_runtime_commands diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 0a81657d..d1815734 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -1,16 +1,12 @@ # UVHS FPGA-Diff Flow -This directory contains the UVHS implementation flow for FPGA-Diff designs on -the U2.2 B0/F2 target. Its targets use the `uvhs_*` prefix; the normal Vivado, -PCIe, and JTAG targets retain their original names and recipes. +This directory contains the UVHS build and runtime flow for FPGA-Diff on the +U2.2 B0/F2 target. UVHS targets use the `uvhs_*` prefix; the existing Vivado, +PCIe, and JTAG targets keep their original behavior. ## Environment -Configure the runtime host shell before invoking `make`, for example directly -in `.bashrc`. The following values are the validated Hejian runtime -installation; `UVHS_TEMPLATE_DIR` and -`UVHS_UVW_AXI4_TO_DDR4_SRC` identify the locally installed base project and -vendor DDR IP and therefore remain site-specific. +Configure the runtime host shell directly, for example in `.bashrc`: ```sh export UV_ROOT=/home/data/UVHS/2506p4_0210 @@ -21,66 +17,67 @@ export UVHS_TEMPLATE_DIR=/path/to/uvhs-template export UVHS_UVW_AXI4_TO_DDR4_SRC=/path/to/uvw_axi4_to_ddr4 ``` -Complete UVHS installations resolve their own runtime libraries. If a shared -installation reports a missing `libpcre.so.1`, point -`UVHS_COMPAT_PCRE_LIB` at a compatible copy supplied with another installation; -the preflight stages it in the selected work directory without modifying the -shared tool tree. +`UVHS_TEMPLATE_DIR` provides the U2.2 board assembly files. The flow regenerates +the repository-owned Vivado IP and imports the vendor DDR DCP selected by +`UVHS_UVW_AXI4_TO_DDR4_SRC`. That DCP must expose a 64-bit AXI interface for +`CPU=nutshell` and a 256-bit interface for other designs; the stub is checked +before frontend starts. -`UVHS_TEMPLATE_DIR` supplies the board assembly skeleton. The flow regenerates -the repository-owned Vivado IP DCPs and consumes the vendor DDR DCP separately; -the source tree does not carry generated DCPs, bitstreams, or machine paths. -`UVHS_UVW_AXI4_TO_DDR4_SRC` must select a vendor DDR DCP whose AXI width matches -the design. The default is 64 bits for `CPU=nutshell` and 256 bits for the other -designs; `uvhs_sync_uvw_axi4_to_ddr4` checks the copied stub before frontend -starts. +Some shared UVHS installations need a local `libpcre.so.1`. Set +`UVHS_COMPAT_PCRE_LIB` to a compatible library when preflight reports that +dependency. The flow stages the library in its work directory and does not +modify the shared installation. ## Build ```sh make uvhs_tools_check make uvhs_preflight CPU= -make uvhs_frontend CPU= CORE_DIR=/path/to/generated/core SUFFIX= +make uvhs_frontend CPU= CORE_DIR=/path/to/core SUFFIX= make uvhs_backend CPU= SUFFIX= make uvhs_package_bitstream CPU= SUFFIX= ``` -`uvhs_frontend` creates `hw.dat`, imports the generated Vivado IP DCPs and the -vendor DDR DCP, elaborates the RTL, and records board/clock constraints. -`uvhs_backend` partitions and localizes that database, generates the vendor -implementation scripts, then runs placement, routing, timing signoff, and -bitstream generation. Thus frontend is close to synthesis/elaboration and -backend is close to physical implementation, but the boundary is UVHS's -database handoff rather than a direct Vivado `synth_design` boundary. -All designs use the B0/F2 `clk5_p` 25 MHz input as the CPU clock; its default -timing period is 40 ns. +`uvhs_frontend` creates `hw.dat`, applies board and timing constraints, imports +the fixed IP DCPs, elaborates the RTL, and runs UVHS synthesis. It also records +the DDR instance used by runtime `writemem`. -`uvhs_all` runs frontend then backend. `UVHS_EXPORT_IP_FORCE=1` rebuilds the -source-generated Vivado DCPs; the default reuses an existing DCP in the chosen -work directory. `uvhs_clean` removes only the explicitly selected -`UVHS_WORK_DIR`. +`uvhs_backend` reads that database and runs clock inference, remap, partition, +localization, system routing, FPGA placement/routing, timing signoff, and +bitstream generation. Its implementation sequence follows the vendor reference +flow. The only custom Vivado stage is `vivado_pre_opt.tcl`, which preserves the +XDMA GT reference-clock input and marks the known XDMA synchronizer registers. -### XiangShan +`uvhs_all` runs both stages. `UVHS_EXPORT_IP_FORCE=1` regenerates Vivado and +generalBus DCPs even when the selected work directory already contains them. +`uvhs_clean` removes only the selected `UVHS_WORK_DIR` and refuses to run while +its runtime session is active. -Use the same entry points with `CPU=kmh` and an AXI-based XiangShan RTL tree: +### XiangShan And External RTL + +For `CPU=kmh`, `uvhs_prepare_core_rtl` runs the upstream `difftest` +`fpga-release` target and synthesizes the extracted release instead of the raw +`build/rtl`. This keeps the normal FPGA clock-gate replacement, +`DifftestClockGate.v`, and generated RAM-style conversion. + +`RTL_INCLUDE` accepts RTL files, directories, and nested `.f`, `.flist`, or +`.list` files. `tools/update_core_flist.sh` resolves every relative entry +against its containing file list before writing the UVHS input list. For +example: ```sh -make uvhs_all CPU=kmh CORE_DIR=/path/to/XiangShan SUFFIX= +make uvhs_all CPU=kmh CORE_DIR=/path/to/XiangShan \ + RTL_INCLUDE=/path/to/external_llc.f SUFFIX= ``` -The file-list step detects whether `SimTop` exposes DMA and enables the H2C -path accordingly. XiangShan keeps the B0/F2 and x4 defaults, while using 80% -LUT and 30% LUT6 fill limits and disabling the hold-expansion route bailout. +The default XiangShan partition limits are 80% LUT and 30% LUT6. They remain +overridable through `UVHS_LUT_FILL_RATE` and `UVHS_LUT6_FILL_RATE`; changing +them is a placement experiment, not a functional requirement. ## Runtime -UVHS runtime targets are separate from the normal Vivado LabTools targets: - ```sh -# Program the FPGA and return after the detached runtime is ready. make uvhs_write_bitstream CPU= SUFFIX= - -# Use the same CPU/SUFFIX or UVHS_WORK_DIR for later commands. make uvhs_runtime_status CPU= SUFFIX= make uvhs_halt_soc CPU= SUFFIX= make uvhs_write_ddr CPU= SUFFIX= WORKLOAD=/path/to/image.txt @@ -89,52 +86,59 @@ make uvhs_reset_cpu CPU= SUFFIX= make uvhs_runtime_stop CPU= SUFFIX= ``` -`uvhs_write_bitstream` loads the completed `hw.dat`, configures the connector and -clocks, holds `rstn_sw6/rstn_sw5/rstn_sw4` low across `download`, calls -`initialize`, then releases system/DDR reset before CPU reset. It leaves the -required UVHS runtime session detached, waits until its command service is -ready, and then returns. Session state and `uv_shell.log` live under -`runtime-work`; `uvhs_runtime_status` checks the PID and ready marker. The other -runtime targets fail immediately without a live session, wait for command -completion, and propagate errors to Make. Run `uvhs_runtime_stop` when finished. -`uvhs_halt_soc` and `uvhs_reset_cpu` control `rstn_sw5`; the other two reset -names remain reserved for the system and external DDR IP. Download and runtime -commands share the reset sequences defined in `runtime_control.tcl`. - -`uvhs_write_ddr` accepts the same address/data-pair text file as the Vivado Tcl, -converts each segment to the selected DCP word width, and writes the DDR IP -through the UVHS `writemem` runtime backdoor. It holds CPU reset low after the -write; run `uvhs_reset_cpu` when the image is ready. H2C remains available for -the normal FPGA-Diff host workflow and is independent of this loader. - -The BRAM-backed flash is inside an imported Vivado DCP and is not exposed as a -UVHS runtime memory. The flow therefore generates a 64-bit UVHS generalBus IP -and connects it to the existing 32-bit flash path through `AXI_bridge`'s width -converter. `uvhs_write_flash` holds CPU reset, pads the raw binary to the -generalBus 8-byte transfer alignment, writes at `0x10000000`, reads the entire -transfer back, and releases CPU reset only after a byte-for-byte match. The -maximum image size is the flash BRAM capacity, 32 KiB. The normal -`write_jtag_flash` target continues to use its dedicated 32-bit JTAG AXI. A -database built before this generalBus path was added cannot use -`uvhs_write_flash` and must be rebuilt. +`uvhs_write_bitstream` loads the completed database, configures the connector +and clocks, holds the three named resets across `download`, initializes the +hardware, and releases the resets in system/DDR/CPU order. It then detaches the +session because later UVHS memory operations must use the process that owns the +downloaded database. Runtime PID, readiness, commands, and logs are under +`runtime-work`. + +`uvhs_write_ddr` converts the address/data-pair format used by the Vivado DDR +loader to the selected 64-bit or 256-bit DCP word width, then calls UVHS +`writemem -rtl`. It leaves the CPU halted; call `uvhs_reset_cpu` after loading. + +`uvhs_write_flash` uses the 64-bit UVHS generalBus master and the existing +32-bit `AXI_bridge` flash path. GeneralBus sees the flash at offset `0x0`; the +CPU and the normal JTAG path retain their `0x10000000` mapping. The command pads +the binary to an 8-byte transfer, writes at offset zero, and requires a complete +readback match before releasing the CPU. The maximum image is 32 KiB. + +## Compatibility Boundary + +Only compatibility workarounds observed as necessary on the validated UVHS +installation remain: + +- `make_compat/` supplies Bash-backed `make` and the limited `csh -fc limit` + query emitted by UVHS. The host does not provide `csh` or `tcsh`. +- `shell_compat.sh` selects Bash in generated synthesis and PnR launchers. Those + launchers use Bash syntax but are generated with `/bin/sh` invocation paths. +- `uv_shell_exec_compat.sh` restores staged runtime libraries after the vendor + launcher sanitizes `LD_LIBRARY_PATH`. +- The private generalBus generator copy replaces its asynchronous DCP copy with + `shutil.copy2`; otherwise it can delete the project before the copy finishes. + +No generated clock, timing XDC, VIO/ILA, DDR pin, or hierarchy-version text +patching remains in the backend flow. ## Files | File | Role | | --- | --- | -| `uvhs.mk` | UVHS-only Make targets, prerequisites, DCP export, and stage invocation. | -| `export_vivado_ip.tcl` | Regenerates repository-owned Vivado IP/BD DCPs; `uvhs.mk` separately invokes the vendor generalBus generator. | -| `frontend_run.tcl` | Creates the UVHS database, imports DCPs, reads RTL, and runs frontend. | -| `backend_run.tcl` | Applies implementation-stage clock/constraint compatibility patches and runs P&R. | -| `assemble_uvhs.tcl` | Reduces the four-FPGA vendor template to the selected FPGA and its daughter cards. | -| `assign_pin_u22_f2.tcl` | Assigns target-board clocks, PCIe, UART, and low-speed I/O; DDR pins remain owned by the vendor IP. | -| `timing_common.tcl`, `async_clocks.tcl` | Declare clocks and asynchronous clock-domain relationships. | -| `check_modules.sh`, `check_flow_tools.sh` | Validate the generated RTL file list and checked-in flow sources. | -| `make_compat/` | Supplies the Bash-compatible commands required by UVHS-generated Makefiles and its `csh -fc limit` probe. | -| `patch_uvsyn_shell.sh` | Patches the generated worker Makefile to run the vendor `uv_shell` script through Bash. | -| `runtime_session.sh` | Starts, checks, and stops the detached UVHS runtime session. | -| `runtime_control.tcl` | Owns reset sequencing, readiness, and command servicing. | -| `enqueue_runtime_command.sh`, `runtime_command.tcl` | Atomically submit reset and memory operations to the runtime session. | -| `uv_shell_exec_compat.sh` | Restores staged compatibility libraries after the vendor launcher sanitizes `LD_LIBRARY_PATH`. | -| `../src/rtl/common/core_def_xdma.sv` | Instantiates the width-matched vendor DDR IP directly for UVHS builds. | -| `../user_script/hw_run_download.tcl` | Downloads and initializes a completed UVHS database, then services runtime commands. | +| `uvhs.mk` | UVHS targets, inputs, stage invocation, packaging, and runtime commands. | +| `frontend_run.tcl` | Builds the synthesized UVHS database from RTL and imported DCPs. | +| `backend_run.tcl` | Runs the standard partition, localization, PnR, and commit sequence. | +| `vivado_pre_opt.tcl` | Applies the two required XDMA physical/CDC constraints. | +| `assemble_uvhs.tcl` | Reduces the vendor four-FPGA assembly to the selected FPGA set. | +| `assign_pin_u22_f2.tcl` | Assigns B0/F2 clocks, PCIe, UART, JTAG, SD, and low-speed pins. | +| `timing_common.tcl` | Declares the external clocks consumed by frontend. | +| `async_clocks.tcl` | Declares asynchronous relationships after clocks are available. | +| `export_vivado_ip.tcl` | Regenerates repository-owned XCI and block-design DCPs. | +| `check_modules.sh` | Confirms required RTL modules exist in the final file list. | +| `check_flow_tools.sh` | Performs source, shell, Tcl, and local-path checks. | +| `shell_compat.sh`, `make_compat/` | Contain the generated-launcher Bash compatibility. | +| `uv_shell_exec_compat.sh` | Supplies the staged runtime library path to `uv_shell_exec`. | +| `hw_run_download.tcl` | Downloads the database and starts its runtime command service. | +| `runtime_control.tcl` | Defines reset sequencing and command polling. | +| `runtime_command.tcl` | Implements reset, DDR, and flash operations. | +| `runtime_session.sh` | Starts, checks, waits for, and stops the detached session. | +| `enqueue_runtime_command.sh` | Submits one command and returns its completion status. | diff --git a/fpga_diff/uvhs/backend_run.tcl b/fpga_diff/uvhs/backend_run.tcl index 0a4be30c..c1256ff8 100644 --- a/fpga_diff/uvhs/backend_run.tcl +++ b/fpga_diff/uvhs/backend_run.tcl @@ -2,8 +2,6 @@ # UVHS backend flow for fpga_diff. ################################################################################ -set ::fpga_diff_uvhs_dir [file dirname [info script]] - proc env_or_default {name default} { if {[info exists ::env($name)] && $::env($name) ne ""} { return $::env($name) @@ -11,1174 +9,32 @@ proc env_or_default {name default} { return $default } -proc source_if_exists {file} { - if {[file exists $file]} { - puts "INFO: source $file" - if {[catch {uplevel #0 [list source $file]} err]} { - puts "WARNING: source $file failed: $err" - } - } else { - puts "INFO: skip missing $file" - } -} - -proc run_or_warn {description command} { - puts "INFO: $description" - if {[catch {uplevel #0 $command} err]} { - puts "WARNING: $description failed: $err" +proc source_required {file} { + if {![file exists $file]} { + error "required UVHS flow file not found: $file" } + puts "INFO: source $file" + uplevel #0 [list source $file] } -proc uvhs_config_probe_group_resource {} { - set probe_group_resource [env_or_default UVHS_PROBE_GROUP_RESOURCE 35] - if {$probe_group_resource eq "none" || $probe_group_resource eq "0"} { - puts "INFO: skip Probe-Group resource override" - return - } - - run_or_warn "restore Probe-Group system resource to $probe_group_resource" \ - [list config_hw -set_resource $probe_group_resource -type Probe-Group] -} - -proc uvhs_config_fill_rates {} { - set lut_fill_rate [env_or_default UVHS_LUT_FILL_RATE none] - set lut6_fill_rate [env_or_default UVHS_LUT6_FILL_RATE none] +proc configure_fill_rates {} { set args {} - - foreach {option value} [list -lut $lut_fill_rate -lut6 $lut6_fill_rate] { - if {$value eq "none" || $value eq ""} { + foreach {option variable} { + -lut UVHS_LUT_FILL_RATE + -lut6 UVHS_LUT6_FILL_RATE + } { + set value [env_or_default $variable ""] + if {$value eq ""} { continue } if {![string is double -strict $value] || $value <= 0 || $value > 100} { - error "$option fill rate must be in (0, 100], got '$value'" + error "$variable must be in (0, 100], got '$value'" } lappend args $option $value } - - if {![llength $args]} { - puts "INFO: keep platform default LUT fill rates" - return - } - - puts "INFO: set UVHS fill rates: $args" - set_fill_rate {*}$args -} - -proc uvhs_cpu_clk_period_ns {} { - return [env_or_default UVHS_CPU_CLK_PERIOD_NS 40] -} - -proc uvhs_xdma_link_width {} { - set link_width [string toupper [string trim [env_or_default XDMA_LINK_WIDTH X4]]] - if {$link_width ni {X4 X8}} { - error "XDMA_LINK_WIDTH must be one of X4/X8, got '$link_width'" - } - return $link_width -} - -proc uvhs_xdma_axi_clk_period_ns {} { - switch -- [uvhs_xdma_link_width] { - X4 { return 8.000 } - X8 { return 4.000 } - } -} - -proc uvhs_clean_stale_partition_runtime {} { - set partition_dir [file normalize hw.dat/Compile/Partition] - foreach stale_file { - partition_0bk.tcl - } { - set path [file join $partition_dir $stale_file] - if {[file exists $path]} { - file delete -force $path - puts "INFO: removed stale partition runtime file $path" - } - } -} - -proc uvhs_async_clock_patch_script {} { - set async_file [file normalize [file join $::fpga_diff_uvhs_dir async_clocks.tcl]] - return [format { -puts "INFO: UVHS patch: source async clock groups after Vivado clocks are available" -if {[file exists {%s}]} { - source {%s} -} else { - puts "WARNING: UVHS patch: missing async clock file %s" -} -} $async_file $async_file $async_file] -} - -proc uvhs_vivado_stage_hook_files {stage} { - switch -- $stage { - pre_opt { - set preferred_rel_paths { - user_pre_opt.tcl - } - set fallback_rel_paths { - user_pre_opt.tcl - user_stage_tcl/preOpt_pre_opt.tcl - user_stage_tcl/pre_opt.tcl - } - } - pre_place { - set preferred_rel_paths { - user_pre_place.tcl - } - set fallback_rel_paths { - user_pre_place.tcl - user_stage_tcl/prePlace_pre_place.tcl - user_stage_tcl/pre_place.tcl - } - } - default { - error "unsupported Vivado stage hook '$stage'" - } - } - - set files {} - foreach pnr_dir [glob -nocomplain hw.dat/Compile/PnR/*/*] { - set pnr_files {} - foreach rel_path $preferred_rel_paths { - set file [file join $pnr_dir $rel_path] - if {[file exists $file] && [lsearch -exact $pnr_files $file] < 0} { - lappend pnr_files $file - } - } - if {![llength $pnr_files]} { - foreach rel_path $fallback_rel_paths { - set file [file join $pnr_dir $rel_path] - if {[file exists $file] && [lsearch -exact $pnr_files $file] < 0} { - lappend pnr_files $file - } - } - } - foreach file $pnr_files { - if {[lsearch -exact $files $file] < 0} { - lappend files $file - } - } - } - return $files -} - -proc uvhs_xdma_gt_refclk_patch_script {stage} { - return [string map [list __UVHS_STAGE__ $stage] { -puts "INFO: UVHS patch: keep XDMA GT refclk direct to IBUFDS_GTE4 before __UVHS_STAGE__" -set uvhs_xdma_refclk_ports {} -foreach uvhs_refclk_pattern { - pcie_ep_gt_ref_clk_p_pad_net_* - pcie_ep_gt_ref_clk_n_pad_net_* - pcie_ep_gt_ref_clk_p - pcie_ep_gt_ref_clk_n -} { - foreach uvhs_port [get_ports -quiet $uvhs_refclk_pattern] { - if {[lsearch -exact $uvhs_xdma_refclk_ports $uvhs_port] < 0} { - lappend uvhs_xdma_refclk_ports $uvhs_port - } - } -} -if {[llength $uvhs_xdma_refclk_ports]} { - catch {set_property IO_BUFFER_TYPE NONE $uvhs_xdma_refclk_ports} uvhs_iobuf_msg - catch {set_property CLOCK_BUFFER_TYPE NONE $uvhs_xdma_refclk_ports} uvhs_clkbuf_msg - puts "INFO: UVHS patch: XDMA GT refclk ports before __UVHS_STAGE__: $uvhs_xdma_refclk_ports" -} else { - puts "WARNING: UVHS patch: XDMA GT refclk ports not found before __UVHS_STAGE__" -} - -proc ::uvhs_xdma_gt_refclk_net_segments {uvhs_net} { - set uvhs_segments {} - if {$uvhs_net ne ""} { - lappend uvhs_segments $uvhs_net - } - if {[catch {set uvhs_more_segments [get_nets -quiet -segments $uvhs_net]} uvhs_segment_msg]} { - puts "WARNING: UVHS patch: get net segments for $uvhs_net failed: $uvhs_segment_msg" - } else { - foreach uvhs_segment $uvhs_more_segments { - if {[lsearch -exact $uvhs_segments $uvhs_segment] < 0} { - lappend uvhs_segments $uvhs_segment - } - } - } - return $uvhs_segments -} - -proc ::uvhs_xdma_gt_refclk_input_pins {} { - set uvhs_pins {} - foreach uvhs_pattern { - */core_def/xdma_ep_i/*IBUFDS_GTE4*/I - */core_def/xdma_ep_i/*IBUFDS_GTE4_I/I - */core_def/xdma_ep_i/util_ds_buf_0/*/I - } { - foreach uvhs_pin [get_pins -hier -quiet $uvhs_pattern] { - if {[lsearch -exact $uvhs_pins $uvhs_pin] < 0} { - lappend uvhs_pins $uvhs_pin - } - } - } - foreach uvhs_pin [get_pins -hier -quiet -filter {REF_PIN_NAME == I && NAME =~ */core_def/xdma_ep_i/*IBUFDS_GTE4*}] { - if {[lsearch -exact $uvhs_pins $uvhs_pin] < 0} { - lappend uvhs_pins $uvhs_pin - } - } - return $uvhs_pins -} - -proc ::uvhs_xdma_gt_refclk_pin_is_driven_by_bufg {uvhs_pin uvhs_bufg} { - set uvhs_pin_net [lindex [get_nets -quiet -of_objects $uvhs_pin] 0] - if {$uvhs_pin_net eq ""} { - return 0 - } - foreach uvhs_segment [::uvhs_xdma_gt_refclk_net_segments $uvhs_pin_net] { - foreach uvhs_driver [get_pins -quiet -of_objects $uvhs_segment -filter {DIRECTION == OUT}] { - set uvhs_driver_cell [lindex [get_cells -quiet -of_objects $uvhs_driver] 0] - if {$uvhs_driver_cell eq $uvhs_bufg} { - return 1 - } - } - } - return 0 -} - -# UVHS/DLP can infer a BUFGCE on the PCIe GT reference clock after opt_design. -# Xilinx IBUFDS_GTE4 must be driven directly by a top port, so bypass only the -# generated XDMA refclk BUFGCE cells before place_design runs its DRC. -set uvhs_xdma_gt_input_pins [::uvhs_xdma_gt_refclk_input_pins] -if {[llength $uvhs_xdma_gt_input_pins]} { - puts "INFO: UVHS patch: XDMA IBUFDS_GTE4 input pins before __UVHS_STAGE__: $uvhs_xdma_gt_input_pins" -} else { - puts "WARNING: UVHS patch: no XDMA IBUFDS_GTE4 input pins found before __UVHS_STAGE__" -} -set uvhs_xdma_refclk_bufgs [get_cells -hier -quiet -filter {REF_NAME =~ BUFG* && NAME =~ *pcie_ep_gt_ref_clk*bufg*}] -if {[llength $uvhs_xdma_refclk_bufgs]} { - puts "INFO: UVHS patch: found XDMA GT refclk BUFG cells before __UVHS_STAGE__: $uvhs_xdma_refclk_bufgs" -} -foreach uvhs_bufg $uvhs_xdma_refclk_bufgs { - set uvhs_in_pins [get_pins -quiet ${uvhs_bufg}/I] - set uvhs_out_pins [get_pins -quiet ${uvhs_bufg}/O] - if {![llength $uvhs_in_pins] || ![llength $uvhs_out_pins]} { - puts "WARNING: UVHS patch: skip $uvhs_bufg, missing I/O pins" - continue - } - set uvhs_in_net [lindex [get_nets -quiet -of_objects [lindex $uvhs_in_pins 0]] 0] - set uvhs_out_net [lindex [get_nets -quiet -of_objects [lindex $uvhs_out_pins 0]] 0] - if {$uvhs_in_net eq "" || $uvhs_out_net eq ""} { - puts "WARNING: UVHS patch: skip $uvhs_bufg, missing I/O nets" - continue - } - - set uvhs_gt_loads {} - foreach uvhs_segment [::uvhs_xdma_gt_refclk_net_segments $uvhs_out_net] { - foreach uvhs_load [get_pins -quiet -of_objects $uvhs_segment -filter {DIRECTION == IN}] { - if {[string match *core_def/xdma_ep_i*IBUFDS_GTE4* $uvhs_load] || \ - [string match *core_def/xdma_ep_i/util_ds_buf_0* $uvhs_load]} { - if {[lsearch -exact $uvhs_gt_loads $uvhs_load] < 0} { - lappend uvhs_gt_loads $uvhs_load - } - } - } - } - foreach uvhs_gt_pin $uvhs_xdma_gt_input_pins { - if {[::uvhs_xdma_gt_refclk_pin_is_driven_by_bufg $uvhs_gt_pin $uvhs_bufg] && \ - [lsearch -exact $uvhs_gt_loads $uvhs_gt_pin] < 0} { - lappend uvhs_gt_loads $uvhs_gt_pin - } - } - if {![llength $uvhs_gt_loads]} { - puts "WARNING: UVHS patch: skip $uvhs_bufg, no XDMA IBUFDS_GTE4 loads on $uvhs_out_net" - foreach uvhs_segment [::uvhs_xdma_gt_refclk_net_segments $uvhs_out_net] { - puts "INFO: UVHS patch: pins on $uvhs_segment: [get_pins -quiet -of_objects $uvhs_segment]" - } - continue - } - - foreach uvhs_load $uvhs_gt_loads { - set uvhs_load_net [lindex [get_nets -quiet -of_objects $uvhs_load] 0] - if {$uvhs_load_net eq ""} { - puts "WARNING: UVHS patch: skip $uvhs_load, no connected net" - continue - } - if {[catch {disconnect_net -net $uvhs_load_net -objects $uvhs_load} uvhs_disconnect_msg]} { - puts "WARNING: UVHS patch: disconnect $uvhs_load_net -> $uvhs_load failed: $uvhs_disconnect_msg" - continue - } - if {[catch {connect_net -hier -net $uvhs_in_net -objects $uvhs_load} uvhs_connect_msg]} { - puts "WARNING: UVHS patch: connect $uvhs_in_net -> $uvhs_load failed: $uvhs_connect_msg" - } else { - puts "INFO: UVHS patch: rewired $uvhs_load from $uvhs_load_net to $uvhs_in_net" - } - } - - catch {disconnect_net -net $uvhs_in_net -objects [lindex $uvhs_in_pins 0]} uvhs_msg - catch {disconnect_net -net $uvhs_out_net -objects [lindex $uvhs_out_pins 0]} uvhs_msg - if {[info commands remove_cell] ne ""} { - catch {remove_cell $uvhs_bufg} uvhs_remove_msg - } elseif {[info commands delete_cells] ne ""} { - catch {delete_cells $uvhs_bufg} uvhs_remove_msg - } - puts "INFO: UVHS patch: bypassed XDMA GT refclk BUFG $uvhs_bufg" -} -}] -} - -proc uvhs_write_xdc_patch_script {} { - set async_file [file normalize [file join $::fpga_diff_uvhs_dir async_clocks.tcl]] - set script [format { -proc ::uvhs_create_ddr_ui_clock_patch {} { - if {[llength [get_clocks -quiet DDR_UI_CLK]] > 0} { - return - } - set uvhs_pins {} - foreach uvhs_pattern { - part_2/core_def/U_UVHS_UVW_AXI4_TO_DDR4/ddr4ip_ddr4_user_clk - */U_UVHS_UVW_AXI4_TO_DDR4/ddr4ip_ddr4_user_clk - } { - foreach uvhs_pin [get_pins -quiet $uvhs_pattern] { - if {[lsearch -exact $uvhs_pins $uvhs_pin] < 0} { - lappend uvhs_pins $uvhs_pin - } - } - foreach uvhs_pin [get_pins -hierarchical -quiet -filter "NAME =~ $uvhs_pattern"] { - if {[lsearch -exact $uvhs_pins $uvhs_pin] < 0} { - lappend uvhs_pins $uvhs_pin - } - } - } - if {[llength $uvhs_pins]} { - create_clock -period 5.000 -name DDR_UI_CLK -waveform {0.000 2.500} -add [lindex $uvhs_pins 0] - puts "INFO: UVHS patch: create DDR_UI_CLK on UVHS DDR user clock [lindex $uvhs_pins 0]" - } -} - -proc ::uvhs_patch_xdma_preopt_xdc {uvhs_xdc_file} { - if {![file exists $uvhs_xdc_file]} { - return - } - - set uvhs_fh [open $uvhs_xdc_file r] - set uvhs_data [read $uvhs_fh] - close $uvhs_fh - set uvhs_patched $uvhs_data - - if {[string match *pnr_physical_constraints_preopt.xdc $uvhs_xdc_file] || \ - [string match *pnr_timing_constraints_preopt.xdc $uvhs_xdc_file]} { - regsub -all {set_property CLKIN1_PERIOD [0-9]+(\.[0-9]*)? \[get_cells -hier -quiet -filter \{NAME =~ \*/core_def/xdma_ep_i/clk_wiz_0/inst/mmcme\*_adv_inst\}\]} \ - $uvhs_patched {set_property CLKIN1_PERIOD __UVHS_XDMA_AXI_CLK_PERIOD_NS__ [get_cells -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/inst/mmcme*_adv_inst}]} uvhs_patched - } - - if {[string match *pnr_timing_constraints_preopt.xdc $uvhs_xdc_file] || \ - [string match *pnr_timing_constraints.xdc $uvhs_xdc_file]} { - # localize_design can serialize a replicated high-fanout clock as an - # unrelated primary clock. Restore its original CPU_CLK_IN relation. - set uvhs_lines {} - foreach uvhs_line [split $uvhs_patched "\n"] { - if {[string first {-name SOC_GATED_CLK} $uvhs_line] >= 0 && \ - [regexp {^create_clock[^\n]*\[get_pins[[:space:]]+([^]]+)/O\]} \ - $uvhs_line -> uvhs_soc_bufg]} { - set uvhs_line [format {create_generated_clock -name SOC_GATED_CLK -source [get_pins %%s/I] -divide_by 1 -add -master_clock [get_clocks CPU_CLK_IN] [get_pins %%s/O]} \ - $uvhs_soc_bufg $uvhs_soc_bufg] - puts "INFO: UVHS patch: restore replicated SOC_GATED_CLK as CPU_CLK_IN generated clock on $uvhs_soc_bufg" - } - lappend uvhs_lines $uvhs_line - } - set uvhs_patched [join $uvhs_lines "\n"] - - regsub -all {create_generated_clock[^\n]*-name[^\n]*core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer[^\n]*TO_DIFFTEST_PCIE_CLK[^\n]*} \ - $uvhs_patched {create_clock -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ -name XDMA_AXI_ACLK -waveform [list 0 [expr __UVHS_XDMA_AXI_CLK_PERIOD_NS__ / 2.0]] -add [get_pins part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK]} uvhs_patched - regsub -all {core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer} $uvhs_patched {XDMA_AXI_ACLK} uvhs_patched - regsub -all {create_generated_clock[^\n]*-name[^\n]*core_def_U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0_c0_ddr4_ui_clk_infer[^\n]*c0_ddr4_ui_clk[^\n]*} \ - $uvhs_patched {create_clock -period 5.000 -name core_def_U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0_c0_ddr4_ui_clk_infer -waveform {0.000 2.500} -add [get_pins part_2/core_def/U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0/c0_ddr4_ui_clk]} uvhs_patched - if {[string first {U_UVHS_UVW_AXI4_TO_DDR4} $uvhs_patched] >= 0 && \ - [string first {UVHS patch: create DDR_UI_CLK on UVHS DDR user clock} $uvhs_patched] < 0} { - append uvhs_patched "\n::uvhs_create_ddr_ui_clock_patch\n" - } - if {[string first {UVHS patch: source fpga_diff async clock constraints in final Vivado timing context} $uvhs_patched] < 0} { - append uvhs_patched "\n# UVHS patch: source fpga_diff async clock constraints in final Vivado timing context.\n" - append uvhs_patched "if {\[file exists {%s}\]} {\n source {%s}\n} else {\n puts \"WARNING: UVHS patch: missing async clock file %s\"\n}\n" - } - } - - if {$uvhs_patched ne $uvhs_data} { - set uvhs_fh [open $uvhs_xdc_file w] - puts -nonewline $uvhs_fh $uvhs_patched - close $uvhs_fh - puts "INFO: UVHS patch: patched generated preopt XDC $uvhs_xdc_file" - } -} - -if {[info commands ::uvhs_vivado_write_xdc] eq "" && [info commands ::write_xdc] ne ""} { - rename ::write_xdc ::uvhs_vivado_write_xdc - proc ::write_xdc {args} { - set uvhs_rc [catch {uplevel 1 [linsert $args 0 ::uvhs_vivado_write_xdc]} uvhs_result uvhs_options] - foreach uvhs_arg $args { - if {[string match *pnr_physical_constraints_preopt.xdc $uvhs_arg] || \ - [string match *pnr_timing_constraints_preopt.xdc $uvhs_arg] || \ - [string match *pnr_timing_constraints.xdc $uvhs_arg]} { - ::uvhs_patch_xdma_preopt_xdc $uvhs_arg - } - } - return -options $uvhs_options $uvhs_result - } - puts "INFO: UVHS patch: wrapped write_xdc to patch generated XDMA preopt constraints" -} -} $async_file $async_file $async_file] - return [string map [list __UVHS_XDMA_AXI_CLK_PERIOD_NS__ [uvhs_xdma_axi_clk_period_ns]] $script] -} - -proc create_clock_if_port_exists {name period port} { - if {[llength [get_clocks -quiet $name]] > 0} { - puts "INFO: skip create_clock $name, already exists" - return - } - set ports [get_ports -quiet $port] - if {[llength $ports] > 0} { - run_or_warn "create_clock $name on $port" [list create_clock -name $name -per $period $ports] - } else { - puts "INFO: skip create_clock $name, missing port $port" - } -} - -proc create_clock_if_pin_exists {name period pin} { - if {[llength [get_clocks -quiet $name]] > 0} { - puts "INFO: skip create_clock $name, already exists" - return - } - set pins [get_pins -quiet $pin] - if {[llength $pins] == 0} { - set pins [get_pins -hierarchical -quiet -filter "NAME =~ */$pin || NAME == $pin"] - } - if {[llength $pins] > 0} { - run_or_warn "create_clock $name on $pin" [list create_clock -name $name -per $period $pins] - } else { - puts "INFO: skip create_clock $name, missing pin $pin" - } -} - -proc create_blackbox_output_clock_if_pin_exists {name period pin} { - set pins [get_pins -quiet $pin] - if {[llength $pins] == 0} { - set pins [get_pins -hierarchical -quiet -filter "NAME =~ */$pin || NAME == $pin"] - } - if {[llength $pins] == 0} { - puts "INFO: skip create_clock $name, missing blackbox output pin $pin" - return - } - - set clocks [get_clocks -quiet -of_objects $pins] - if {[llength $clocks] > 0} { - puts "INFO: skip create_clock $name, blackbox output pin $pin already has clocks: $clocks" - return - } - - run_or_warn "create_clock $name on blackbox output $pin" \ - [list create_clock -name $name -per $period $pins] -} - -proc create_ddr_ui_clock_if_exists {} { - # The default Vivado flow uses jtag_ddr_subsys/c0_ddr4_ui_clk. The UVHS - # flow uses uvw_axi4_to_ddr4/ddr4ip_ddr4_user_clk. Both are 200 MHz user - # AXI domains; constrain whichever implementation is present. - set use_uvw_ddr [expr {[env_or_default UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP 0] eq "1"}] - if {$use_uvw_ddr} { - set pin_patterns { - core_def/U_UVHS_UVW_AXI4_TO_DDR4/ddr4ip_ddr4_user_clk - */U_UVHS_UVW_AXI4_TO_DDR4/ddr4ip_ddr4_user_clk - } - set clock_description "UVHS DDR ddr4ip_ddr4_user_clk" - } else { - set pin_patterns { - core_def/U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0/c0_ddr4_ui_clk - */U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0/c0_ddr4_ui_clk - */jtag_ddr_subsys_i_UVin_ddr4_0/c0_ddr4_ui_clk - */ddr4_0/c0_ddr4_ui_clk - } - set clock_description "Vivado DDR c0_ddr4_ui_clk" - } - set pins {} - foreach pin_pattern $pin_patterns { - foreach pin [get_pins -quiet $pin_pattern] { - if {[lsearch -exact $pins $pin] < 0} { - lappend pins $pin - } - } - foreach pin [get_pins -hierarchical -quiet -filter "NAME =~ $pin_pattern"] { - if {[lsearch -exact $pins $pin] < 0} { - lappend pins $pin - } - } - } - if {![llength $pins]} { - puts "INFO: skip create_clock DDR_UI_CLK, missing $clock_description pin" - return - } - - set pin [lindex $pins 0] - set clocks [get_clocks -quiet -of_objects $pin] - if {[llength $clocks]} { - puts "INFO: DDR UI pin $pin already has clocks: $clocks" - return - } - - run_or_warn "create_clock DDR_UI_CLK on $clock_description" \ - [list create_clock -name DDR_UI_CLK -per 5.000 $pin] -} - -proc create_generated_clock_if_bufgce_exists {name master_clock cell_patterns} { - if {[llength [get_clocks -quiet $name]] > 0} { - puts "INFO: skip create_generated_clock $name, already exists" - return - } - if {[llength [get_clocks -quiet $master_clock]] == 0} { - puts "WARNING: skip create_generated_clock $name, missing master clock $master_clock" - return - } - set cells {} - foreach cell_pattern $cell_patterns { - set matches [get_cells -hierarchical -quiet -filter "NAME =~ $cell_pattern"] - foreach match $matches { - if {[lsearch -exact $cells $match] < 0} { - lappend cells $match - } - } - } - if {[llength $cells] == 0} { - set bufgce_cells [get_cells -hierarchical -quiet -filter "REF_NAME =~ BUFGCE"] - puts "WARNING: skip create_generated_clock $name, missing BUFGCE cell patterns $cell_patterns; visible BUFGCE cells: $bufgce_cells" - return - } - if {[llength $cells] > 1} { - puts "WARNING: create_generated_clock $name matched multiple cells, using [lindex $cells 0]: $cells" - } - set cell [lindex $cells 0] - set in_pins [get_pins -quiet $cell/I] - set out_pins [get_pins -quiet $cell/O] - if {[llength $in_pins] == 0 || [llength $out_pins] == 0} { - puts "WARNING: skip create_generated_clock $name, missing I/O pins on $cell" - return - } - run_or_warn "create_generated_clock $name on $cell/O" \ - [list create_generated_clock -add -name $name -master_clock $master_clock -source $in_pins -divide_by 1 $out_pins] -} - -proc patch_vivado_wrappers {} { - set patterns { - hw.dat/Compile/PnR/*/*/vivado/Script/uv_vivado_wrapper.sh - hw.dat/Compile/PnR/*/*/vivado/Rundir/*/uv_vivado_wrapper.sh - } - foreach pattern $patterns { - foreach wrapper [glob -nocomplain $pattern] { - if {![file exists $wrapper]} { - continue - } - set fh [open $wrapper r] - set data [read $fh] - close $fh - if {[string match "#!/bin/sh*" $data]} { - regsub {^#!/bin/sh} $data {#!/bin/bash} data - set fh [open $wrapper w] - puts -nonewline $fh $data - close $fh - file attributes $wrapper -permissions u=rwx,g=rx,o=rx - puts "INFO: patched Vivado wrapper shell to bash: $wrapper" - } - } - } -} - -proc patch_vivado_pre_opt {} { - set write_xdc_patch_script [uvhs_write_xdc_patch_script] - set refclk_patch_script [uvhs_xdma_gt_refclk_patch_script "opt"] - set xdma_cdc_script { -puts "INFO: UVHS patch: source XDMA CDC attributes before opt_design" -set uvhs_xdma_cdc_script [file join $FILE_DIR xdma_cdc_attributes.tcl] -if {[file exists $uvhs_xdma_cdc_script]} { - source $uvhs_xdma_cdc_script -} else { - puts "WARNING: UVHS patch: missing XDMA CDC attribute script $uvhs_xdma_cdc_script" -} -} - set script [string map [list __UVHS_XDMA_AXI_CLK_PERIOD_NS__ [uvhs_xdma_axi_clk_period_ns]] { -puts "INFO: UVHS patch: constrain XDMA clk_wiz input period for Vivado MMCM DRC" -set uvhs_xdma_refclk_ports {} -foreach uvhs_refclk_pattern {pcie_ep_gt_ref_clk_p_pad_net_* pcie_ep_gt_ref_clk_n_pad_net_*} { - set uvhs_xdma_refclk_ports [concat $uvhs_xdma_refclk_ports [get_ports -quiet $uvhs_refclk_pattern]] -} -if {[llength $uvhs_xdma_refclk_ports]} { - set_property IO_BUFFER_TYPE NONE $uvhs_xdma_refclk_ports - set_property CLOCK_BUFFER_TYPE NONE $uvhs_xdma_refclk_ports - puts "INFO: UVHS patch: keep XDMA GT refclk pads unbuffered before opt: $uvhs_xdma_refclk_ports" -} else { - puts "WARNING: UVHS patch: XDMA GT refclk pad ports not found before opt" -} -set uvhs_xdma_clk_in [get_pins -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/clk_in1}] -if {[llength $uvhs_xdma_clk_in]} { - set uvhs_xdma_clk_in [lindex $uvhs_xdma_clk_in 0] - set uvhs_xdma_clocks [get_clocks -quiet -of_objects $uvhs_xdma_clk_in] - if {![llength $uvhs_xdma_clocks]} { - catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_clk_in} uvhs_create_clk_msg - puts "INFO: UVHS patch: XDMA_AXI_ACLK create_clock result: $uvhs_create_clk_msg" - } else { - puts "INFO: UVHS patch: XDMA clk_wiz input clocks: $uvhs_xdma_clocks" - if {[lsearch -exact $uvhs_xdma_clocks XDMA_AXI_ACLK] >= 0} { - puts "INFO: UVHS patch: XDMA_AXI_ACLK already exists" - } else { - catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_clk_in} uvhs_create_clk_msg - puts "INFO: UVHS patch: XDMA_AXI_ACLK override_clock result: $uvhs_create_clk_msg" - } - } -} else { - puts "INFO: UVHS patch: XDMA clk_wiz clk_in1 pin not found; current x4 DCP exposes TO_DIFFTEST_PCIE_CLK directly" -} -set uvhs_difftest_pcie_pin [get_pins -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK}] -if {[llength $uvhs_difftest_pcie_pin]} { - set uvhs_difftest_pcie_pin [lindex $uvhs_difftest_pcie_pin 0] - set uvhs_difftest_pcie_clocks [get_clocks -quiet -of_objects $uvhs_difftest_pcie_pin] - if {![llength $uvhs_difftest_pcie_clocks]} { - catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_difftest_pcie_pin} uvhs_create_xdma_pin_msg - puts "INFO: UVHS patch: XDMA_AXI_ACLK create_clock on TO_DIFFTEST_PCIE_CLK result: $uvhs_create_xdma_pin_msg" - } else { - puts "INFO: UVHS patch: TO_DIFFTEST_PCIE_CLK already has clocks: $uvhs_difftest_pcie_clocks" - } -} else { - puts "WARNING: UVHS patch: TO_DIFFTEST_PCIE_CLK pin not found" -} -set uvhs_xdma_mmcms [get_cells -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/inst/mmcme*_adv_inst}] -if {[llength $uvhs_xdma_mmcms]} { - set_property CLKIN1_PERIOD __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_mmcms - puts "INFO: UVHS patch: set CLKIN1_PERIOD=__UVHS_XDMA_AXI_CLK_PERIOD_NS__ on $uvhs_xdma_mmcms" -} else { - puts "INFO: UVHS patch: XDMA clk_wiz MMCM cell not found; current x4 DCP exposes TO_DIFFTEST_PCIE_CLK directly" -} -set uvhs_xdma_intclks [get_clocks -quiet */xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/diablo_gt.diablo_gt_phy_wrapper/phy_clk_i/bufg_gt_intclk/O] -set uvhs_pcie_refclks [get_clocks -quiet pcie_ep_refclk] -if {[llength $uvhs_xdma_intclks] && [llength $uvhs_pcie_refclks]} { - set_false_path -from $uvhs_xdma_intclks -to $uvhs_pcie_refclks - puts "INFO: UVHS patch: false path XDMA GT internal clock -> pcie_ep_refclk" -} -set uvhs_lnk_up_src [get_pins -hier -quiet -filter {NAME =~ */xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/user_lnk_up_reg/C}] -set uvhs_lnk_up_dsts [concat \ - [get_pins -hier -quiet -filter {NAME =~ */u_capt*/captured_signal_p1_reg*/D}] \ - [get_pins -hier -quiet -filter {NAME =~ */user_lnk_up*_trigger_pipeline*/D}]] -if {[llength $uvhs_lnk_up_src] && [llength $uvhs_lnk_up_dsts]} { - set_false_path -from $uvhs_lnk_up_src -to $uvhs_lnk_up_dsts - puts "INFO: UVHS patch: false path XDMA user_lnk_up debug trigger paths" -} -}] - append script "\n" $refclk_patch_script - append script [uvhs_async_clock_patch_script] - foreach pre_opt [uvhs_vivado_stage_hook_files pre_opt] { - set fh [open $pre_opt r] - set data [read $fh] - close $fh - if {[string first "UVHS patch: wrapped write_xdc to patch generated XDMA preopt constraints" $data] < 0} { - set fh [open $pre_opt a] - puts $fh "" - puts $fh $write_xdc_patch_script - close $fh - append data "\n" $write_xdc_patch_script - puts "INFO: patched Vivado pre-opt write_xdc wrapper: $pre_opt" - } - if {[string first "UVHS patch: source XDMA CDC attributes before opt_design" $data] < 0} { - set fh [open $pre_opt a] - puts $fh "" - puts $fh $xdma_cdc_script - close $fh - append data "\n" $xdma_cdc_script - puts "INFO: patched Vivado pre-opt XDMA CDC attributes: $pre_opt" - } - if {[string first "UVHS patch: constrain XDMA clk_wiz input period" $data] < 0} { - set fh [open $pre_opt a] - puts $fh "" - puts $fh $script - close $fh - puts "INFO: patched Vivado pre-opt XDMA clk_wiz input period: $pre_opt" - } - } -} - -proc patch_vivado_pre_place {} { - set refclk_patch_script [uvhs_xdma_gt_refclk_patch_script "place"] - set script [string map [list __UVHS_XDMA_AXI_CLK_PERIOD_NS__ [uvhs_xdma_axi_clk_period_ns]] { -puts "INFO: UVHS patch: re-apply XDMA clk_wiz input period before place/route DRC" -set uvhs_xdma_clk_in [get_pins -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/clk_in1}] -if {[llength $uvhs_xdma_clk_in]} { - set uvhs_xdma_clk_in [lindex $uvhs_xdma_clk_in 0] - set uvhs_xdma_clocks [get_clocks -quiet -of_objects $uvhs_xdma_clk_in] - if {![llength $uvhs_xdma_clocks]} { - catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_clk_in} uvhs_create_clk_msg - puts "INFO: UVHS patch: XDMA_AXI_ACLK create_clock before place result: $uvhs_create_clk_msg" - } else { - puts "INFO: UVHS patch: XDMA clk_wiz input clocks before place: $uvhs_xdma_clocks" - if {[lsearch -exact $uvhs_xdma_clocks XDMA_AXI_ACLK] >= 0} { - puts "INFO: UVHS patch: XDMA_AXI_ACLK already exists before place" - } else { - catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_clk_in} uvhs_create_clk_msg - puts "INFO: UVHS patch: XDMA_AXI_ACLK override_clock before place result: $uvhs_create_clk_msg" - } - } -} else { - puts "INFO: UVHS patch: XDMA clk_wiz clk_in1 pin not found before place; current x4 DCP exposes TO_DIFFTEST_PCIE_CLK directly" -} -set uvhs_difftest_pcie_pin [get_pins -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK}] -if {[llength $uvhs_difftest_pcie_pin]} { - set uvhs_difftest_pcie_pin [lindex $uvhs_difftest_pcie_pin 0] - set uvhs_difftest_pcie_clocks [get_clocks -quiet -of_objects $uvhs_difftest_pcie_pin] - if {![llength $uvhs_difftest_pcie_clocks]} { - catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_difftest_pcie_pin} uvhs_create_xdma_pin_msg - puts "INFO: UVHS patch: XDMA_AXI_ACLK create_clock on TO_DIFFTEST_PCIE_CLK before place result: $uvhs_create_xdma_pin_msg" - } else { - puts "INFO: UVHS patch: TO_DIFFTEST_PCIE_CLK clocks before place: $uvhs_difftest_pcie_clocks" - } -} else { - puts "WARNING: UVHS patch: TO_DIFFTEST_PCIE_CLK pin not found before place" -} -set uvhs_xdma_mmcms [get_cells -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/inst/mmcme*_adv_inst}] -if {[llength $uvhs_xdma_mmcms]} { - set_property CLKIN1_PERIOD __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_mmcms - puts "INFO: UVHS patch: set CLKIN1_PERIOD=__UVHS_XDMA_AXI_CLK_PERIOD_NS__ on $uvhs_xdma_mmcms before place" -} else { - puts "INFO: UVHS patch: XDMA clk_wiz MMCM cell not found before place; current x4 DCP exposes TO_DIFFTEST_PCIE_CLK directly" -} -puts "INFO: UVHS patch: rewire Vivado debug hub clock if it is attached to an undriven net" -if {[llength [get_debug_cores -quiet dbg_hub]]} { - set uvhs_dbg_clk [get_nets -quiet clk5_p_pad_net_7_bufg_n] - if {![llength $uvhs_dbg_clk]} { - set uvhs_dbg_clk [get_nets -quiet clk5_p_pad_net_6] - } - if {[llength $uvhs_dbg_clk]} { - catch {disconnect_debug_port dbg_hub/clk} - connect_debug_port dbg_hub/clk [lindex $uvhs_dbg_clk 0] - puts "INFO: UVHS patch: dbg_hub/clk -> [lindex $uvhs_dbg_clk 0]" - } else { - puts "WARNING: UVHS patch: no clk5 debug clock net found for dbg_hub" - } -} -puts "INFO: UVHS patch: fix known bring-up bitstream DRCs" -set uvhs_ila_rams [get_cells -hier -quiet -filter {NAME =~ *system_ila_0*trace_block_memory*ram/DEVICE_8SERIES*ram}] -if {[llength $uvhs_ila_rams]} { - set_property CLOCK_DOMAINS INDEPENDENT $uvhs_ila_rams - puts "INFO: UVHS patch: set CLOCK_DOMAINS INDEPENDENT on [llength $uvhs_ila_rams] system ILA RAM cells" -} -set uvhs_ddr_ck_ports {} -foreach uvhs_pat {DDR0_CK_C_pad_net_* DDR0_CK_T_pad_net_*} { - set uvhs_ddr_ck_ports [concat $uvhs_ddr_ck_ports [get_ports -quiet $uvhs_pat]] -} -if {[llength $uvhs_ddr_ck_ports]} { - set_property IOSTANDARD DIFF_SSTL12_DCI $uvhs_ddr_ck_ports - puts "INFO: UVHS patch: set differential IOSTANDARD on generated DDR CK pad ports: $uvhs_ddr_ck_ports" -} -}] - append script "\n" $refclk_patch_script - append script [uvhs_async_clock_patch_script] - foreach pre_place [uvhs_vivado_stage_hook_files pre_place] { - set fh [open $pre_place r] - set data [read $fh] - close $fh - if {[string first "UVHS patch: re-apply XDMA clk_wiz input period before place/route DRC" $data] < 0} { - set fh [open $pre_place a] - puts $fh "" - puts $fh $script - close $fh - puts "INFO: patched Vivado pre-place debug hub clock: $pre_place" - } - } -} - -proc patch_vivado_before_route {} { - set script [string map [list __UVHS_XDMA_AXI_CLK_PERIOD_NS__ [uvhs_xdma_axi_clk_period_ns]] { -puts "INFO: UVHS patch: re-apply XDMA clk_wiz input period before route DRC" -set uvhs_xdma_clk_in [get_pins -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/clk_in1}] -if {[llength $uvhs_xdma_clk_in]} { - set uvhs_xdma_clk_in [lindex $uvhs_xdma_clk_in 0] - set uvhs_xdma_clocks [get_clocks -quiet -of_objects $uvhs_xdma_clk_in] - if {![llength $uvhs_xdma_clocks]} { - catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_clk_in} uvhs_create_clk_msg - puts "INFO: UVHS patch: XDMA_AXI_ACLK create_clock before route result: $uvhs_create_clk_msg" - } else { - puts "INFO: UVHS patch: XDMA clk_wiz input clocks before route: $uvhs_xdma_clocks" - if {[lsearch -exact $uvhs_xdma_clocks XDMA_AXI_ACLK] >= 0} { - puts "INFO: UVHS patch: XDMA_AXI_ACLK already exists before route" - } else { - catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_clk_in} uvhs_create_clk_msg - puts "INFO: UVHS patch: XDMA_AXI_ACLK override_clock before route result: $uvhs_create_clk_msg" - } - } -} else { - puts "INFO: UVHS patch: XDMA clk_wiz clk_in1 pin not found before route; current x4 DCP exposes TO_DIFFTEST_PCIE_CLK directly" -} -set uvhs_difftest_pcie_pin [get_pins -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK}] -if {[llength $uvhs_difftest_pcie_pin]} { - set uvhs_difftest_pcie_pin [lindex $uvhs_difftest_pcie_pin 0] - set uvhs_difftest_pcie_clocks [get_clocks -quiet -of_objects $uvhs_difftest_pcie_pin] - if {![llength $uvhs_difftest_pcie_clocks]} { - catch {create_clock -name XDMA_AXI_ACLK -period __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_difftest_pcie_pin} uvhs_create_xdma_pin_msg - puts "INFO: UVHS patch: XDMA_AXI_ACLK create_clock on TO_DIFFTEST_PCIE_CLK before route result: $uvhs_create_xdma_pin_msg" - } else { - puts "INFO: UVHS patch: TO_DIFFTEST_PCIE_CLK clocks before route: $uvhs_difftest_pcie_clocks" - } -} else { - puts "WARNING: UVHS patch: TO_DIFFTEST_PCIE_CLK pin not found before route" -} -set uvhs_xdma_mmcms [get_cells -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/inst/mmcme*_adv_inst}] -if {[llength $uvhs_xdma_mmcms]} { - set_property CLKIN1_PERIOD __UVHS_XDMA_AXI_CLK_PERIOD_NS__ $uvhs_xdma_mmcms - puts "INFO: UVHS patch: set CLKIN1_PERIOD=__UVHS_XDMA_AXI_CLK_PERIOD_NS__ on $uvhs_xdma_mmcms before route" - catch {update_timing} uvhs_update_timing_msg - puts "INFO: UVHS patch: update_timing before route result: $uvhs_update_timing_msg" -} else { - puts "INFO: UVHS patch: XDMA clk_wiz MMCM cell not found before route; current x4 DCP exposes TO_DIFFTEST_PCIE_CLK directly" -} -}] - set hold_expn_bailout [env_or_default UVHS_ROUTE_ENABLE_HOLD_EXPN_BAILOUT ""] - if {$hold_expn_bailout ne ""} { - if {$hold_expn_bailout ni {0 1}} { - error "UVHS_ROUTE_ENABLE_HOLD_EXPN_BAILOUT must be empty, 0, or 1; got '$hold_expn_bailout'" - } - append script "\nputs \"INFO: UVHS patch: set route.enableHoldExpnBailout=$hold_expn_bailout before route\"\n" - append script "set_param route.enableHoldExpnBailout $hold_expn_bailout\n" - } - append script [uvhs_async_clock_patch_script] - foreach pnr_dir [glob -nocomplain hw.dat/Compile/PnR/*/*] { - set before_route [file join $pnr_dir before_route.tcl] - set data "" - if {[file exists $before_route]} { - set fh [open $before_route r] - set data [read $fh] - close $fh - } - if {[string first "UVHS patch: re-apply XDMA clk_wiz input period before route DRC" $data] < 0} { - set fh [open $before_route a] - puts $fh "" - puts $fh $script - close $fh - puts "INFO: patched Vivado before-route XDMA clk_wiz input period: $before_route" - } - } -} - -proc patch_timing_constraint_files {} { - set xdma_axi_clk_period [uvhs_xdma_axi_clk_period_ns] - set xdma_axi_clk_half_period [format %.3f [expr {$xdma_axi_clk_period / 2.0}]] - set xdma_clkin1_replacement "set_property CLKIN1_PERIOD $xdma_axi_clk_period \[get_cells -hier -quiet -filter {NAME =~ */core_def/xdma_ep_i/clk_wiz_0/inst/mmcme*_adv_inst}\]" - set xdma_blackbox_clock_replacement [format { -create_clock -period %.3f -name XDMA_AXI_ACLK -waveform {0.000 %.3f} -add [get_pins part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK]} \ - $xdma_axi_clk_period $xdma_axi_clk_half_period] - set difftest_clock_token_pattern {(^|[^[:alnum:]_])DIFFTEST_PCIE_CLK([^[:alnum:]_]|$)} - set async_xdc_block [format { - -# UVHS patch: source fpga_diff async clock constraints in final Vivado timing context. -if {[file exists {%s}]} { - source {%s} -} else { - puts "WARNING: UVHS patch: missing async clock file %s" -} -} [file normalize [file join $::fpga_diff_uvhs_dir async_clocks.tcl]] \ - [file normalize [file join $::fpga_diff_uvhs_dir async_clocks.tcl]] \ - [file normalize [file join $::fpga_diff_uvhs_dir async_clocks.tcl]]] - - foreach file [glob -nocomplain hw.dat/Compile/PnR/*/*/timing_constraints.tcl] { - set fh [open $file r] - set data [read $fh] - close $fh - set patched $data - - # TO_DIFFTEST_PCIE_CLK exits the XDMA endpoint black-box boundary, but - # the BD drives it directly from xdma_0/axi_aclk. Keep its constraint - # aligned with the XDMA IP axisten_freq selected by XDMA_LINK_WIDTH. - set xdma_axi_primary_clock [format { -puts "WARNING: \[APS CSTR-1\] primary clock is defined on blackbox boundary which may cause inaccurate skew analysis." -create_clock -add -name XDMA_AXI_ACLK -period [expr $uvCstrRatio * %.3f + $uvCstrMargin] -waveform [list 0 [expr ($uvCstrRatio + $uvCstrMargin / %.3f) * %.3f]] [get_pins { part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK }] -variable XDMA_AXI_ACLK_name [get_property NAME [get_clocks XDMA_AXI_ACLK]] -} $xdma_axi_clk_period $xdma_axi_clk_period $xdma_axi_clk_half_period] - set difftest_generated_block {set DIFFTEST_PCIE_CLK_master [get_clocks -of_objects [get_pins { part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK }]] -set DIFFTEST_PCIE_CLK_source "" -if {$DIFFTEST_PCIE_CLK_master!=""} { - set DIFFTEST_PCIE_CLK_source [get_property SOURCE_PINS $DIFFTEST_PCIE_CLK_master] -} -if {[llength $DIFFTEST_PCIE_CLK_master] == 1 && [llength $DIFFTEST_PCIE_CLK_source] == 1} { - set DIFFTEST_PCIE_CLK_source [get_pins $DIFFTEST_PCIE_CLK_source] - if {$DIFFTEST_PCIE_CLK_source==""} { - set DIFFTEST_PCIE_CLK_source [get_ports [get_property SOURCE_PINS $DIFFTEST_PCIE_CLK_master]] - } - set driver [get_nets -top_net_of_hierarchical_group -segments -of_objects $DIFFTEST_PCIE_CLK_source] - if {[get_nets -top_net_of_hierarchical_group -segments -of_objects [get_pins { part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK }]]==$driver} { - variable DIFFTEST_PCIE_CLK_name [get_property NAME $DIFFTEST_PCIE_CLK_master] - dict set uvRenameClocks DIFFTEST_PCIE_CLK [get_pins { part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK }] - } else { - create_generated_clock -add -name DIFFTEST_PCIE_CLK -divide_by 1 -source $DIFFTEST_PCIE_CLK_source -master_clock $DIFFTEST_PCIE_CLK_master [get_pins { part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK }] - variable DIFFTEST_PCIE_CLK_name [get_property NAME [get_clocks DIFFTEST_PCIE_CLK]] - } -} else { - puts "WARNING: \[APS CSTR-1\] primary clock is defined on blackbox boundary which may cause inaccurate skew analysis." - create_clock -add -name DIFFTEST_PCIE_CLK -period [expr $uvCstrRatio * 10.00 + $uvCstrMargin] [get_pins { part_2/core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK }] -variable DIFFTEST_PCIE_CLK_name [get_property NAME [get_clocks DIFFTEST_PCIE_CLK]] -}} - if {[string first $difftest_generated_block $patched] >= 0} { - regsub [string map {\\ \\\\ \[ \\[ \] \\] \$ \\$ \( \\( \) \\) \{ \\{ \} \\} \. \\. \* \\* \+ \\+ \? \\? \^ \\^} $difftest_generated_block] \ - $patched $xdma_axi_primary_clock patched - } - regsub -all {create_clock[^\n]*-name[^\n]*DIFFTEST_PCIE_CLK[^\n]*TO_DIFFTEST_PCIE_CLK[^\n]*} \ - $patched $xdma_axi_primary_clock patched - regsub -all {create_generated_clock[^\n]*-name[^\n]*core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer[^\n]*TO_DIFFTEST_PCIE_CLK[^\n]*} \ - $patched $xdma_axi_primary_clock patched - regsub -all {core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer_name} $patched {XDMA_AXI_ACLK_name} patched - regsub -all {core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer} $patched {XDMA_AXI_ACLK} patched - regsub -all {DIFFTEST_PCIE_CLK_name} $patched {XDMA_AXI_ACLK_name} patched - regsub -all $difftest_clock_token_pattern $patched {\1XDMA_AXI_ACLK\2} patched - if {![env_or_default UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP 0]} { - regsub -all {create_generated_clock[^\n]*-name[^\n]*core_def_U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0_c0_ddr4_ui_clk_infer[^\n]*c0_ddr4_ui_clk[^\n]*} \ - $patched {create_clock -add -name core_def_U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0_c0_ddr4_ui_clk_infer -period [expr $uvCstrRatio * 5.000 + $uvCstrMargin] -waveform [list 0 [expr ($uvCstrRatio + $uvCstrMargin / 5.000) * 2.500]] [get_pins { part_2/core_def/U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0/c0_ddr4_ui_clk }]} patched - } - if {$patched ne $data} { - set fh [open $file w] - puts -nonewline $fh $patched - close $fh - puts "INFO: patched UVHS DIFFTEST PCIe / DDR UI clock timing constraints: $file" - } - } - - foreach file [concat \ - [glob -nocomplain hw.dat/Compile/PnR/*/*/vivado/Rundir/*/bitstream/pnr_timing_constraints_preopt.xdc] \ - [glob -nocomplain hw.dat/Compile/PnR/*/*/vivado/Rundir/*/bitstream/pnr_timing_constraints.xdc]] { - set fh [open $file r] - set data [read $fh] - close $fh - set patched $data - - regsub -all {create_clock[^\n]*-name[^\n]*DIFFTEST_PCIE_CLK[^\n]*TO_DIFFTEST_PCIE_CLK[^\n]*} \ - $patched $xdma_blackbox_clock_replacement patched - regsub -all {create_generated_clock[^\n]*-name[^\n]*core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer[^\n]*TO_DIFFTEST_PCIE_CLK[^\n]*} \ - $patched $xdma_blackbox_clock_replacement patched - regsub -all {core_def_xdma_ep_i_TO_DIFFTEST_PCIE_CLK_infer} $patched {XDMA_AXI_ACLK} patched - regsub -all $difftest_clock_token_pattern $patched {\1XDMA_AXI_ACLK\2} patched - if {![env_or_default UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP 0]} { - regsub -all {create_generated_clock[^\n]*-name[^\n]*core_def_U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0_c0_ddr4_ui_clk_infer[^\n]*c0_ddr4_ui_clk[^\n]*} \ - $patched {create_clock -period 5.000 -name core_def_U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0_c0_ddr4_ui_clk_infer -waveform {0.000 2.500} -add [get_pins part_2/core_def/U_JTAG_DDR_SUBSYS_UVin_jtag_ddr_subsys_i_UVin_ddr4_0/c0_ddr4_ui_clk]} patched - } - regsub -all {set_property CLKIN1_PERIOD [0-9]+(\.[0-9]*)? \[get_cells -hier -quiet -filter \{NAME =~ \*/core_def/xdma_ep_i/clk_wiz_0/inst/mmcme\*_adv_inst\}\]} \ - $patched $xdma_clkin1_replacement patched - if {[string first "UVHS patch: source fpga_diff async clock constraints in final Vivado timing context" $patched] < 0} { - append patched $async_xdc_block - } - if {$patched ne $data} { - set fh [open $file w] - puts -nonewline $fh $patched - close $fh - puts "INFO: patched Vivado DIFFTEST PCIe / DDR UI clock timing constraints: $file" - } - } - - foreach file [glob -nocomplain hw.dat/Compile/PnR/*/*/vivado/Rundir/*/bitstream/pnr_physical_constraints_preopt.xdc] { - set fh [open $file r] - set data [read $fh] - close $fh - set patched $data - - regsub -all {set_property CLKIN1_PERIOD [0-9]+(\.[0-9]*)? \[get_cells -hier -quiet -filter \{NAME =~ \*/core_def/xdma_ep_i/clk_wiz_0/inst/mmcme\*_adv_inst\}\]} \ - $patched $xdma_clkin1_replacement patched - if {$patched ne $data} { - set fh [open $file w] - puts -nonewline $fh $patched - close $fh - puts "INFO: patched Vivado XDMA clk_wiz physical constraints: $file" - } - } -} - -proc patch_xdma_gt_refclk_pad_constraints {} { - foreach pnr_dir [glob -nocomplain hw.dat/Compile/PnR/*/*] { - set xdc [file join $pnr_dir xdma_gt_refclk_no_buffer.xdc] - if {[file exists $xdc]} { - file delete -force $xdc - puts "INFO: removed obsolete XDMA GT refclk XDC: $xdc" - } - - foreach hook_name {before_link.tcl pre_link.tcl} { - set hook [file join $pnr_dir $hook_name] - if {![file exists $hook]} { - continue - } - set fh [open $hook r] - set data [read $fh] - close $fh - set patched $data - - regsub -all {\nadd_file \$FILE_DIR/xdma_gt_refclk_no_buffer\.xdc} $patched "" patched - - if {$patched ne $data} { - set fh [open $hook w] - puts -nonewline $fh $patched - close $fh - puts "INFO: removed obsolete XDMA GT refclk XDC hook: $hook" - } - } - } - - foreach file [concat \ - [glob -nocomplain hw.dat/Compile/PnR/*/*/pin_assign.xdc] \ - [glob -nocomplain hw.dat/Compile/PnR/*/*/dlp.xdc]] { - set fh [open $file r] - set data [read $fh] - close $fh - if {[string first "UVHS patch: keep XDMA GT refclk pads unbuffered" $data] >= 0} { - continue - } - - set p_ports [regexp -inline -all {pcie_ep_gt_ref_clk_p_pad_net_[0-9]+} $data] - set n_ports [regexp -inline -all {pcie_ep_gt_ref_clk_n_pad_net_[0-9]+} $data] - set refclk_ports {} - foreach port [concat $p_ports $n_ports] { - if {[lsearch -exact $refclk_ports $port] < 0} { - lappend refclk_ports $port - } - } - if {![llength $refclk_ports]} { - continue - } - - set block "\n# UVHS patch: keep XDMA GT refclk pads unbuffered for IBUFDS_GTE in xdma_ep.\n" - foreach port $refclk_ports { - append block "set_property IO_BUFFER_TYPE NONE \[get_ports -quiet {$port}\]\n" - append block "set_property CLOCK_BUFFER_TYPE NONE \[get_ports -quiet {$port}\]\n" - } - set patched $data - if {[regexp {set_property PACKAGE_PIN [^\n]+pcie_ep_gt_ref_clk_[pn]_pad_net_[0-9]+[^\n]*} $patched first_refclk_line]} { - set idx [string first $first_refclk_line $patched] - set patched [string range $patched 0 [expr {$idx - 1}]] - append patched $block $first_refclk_line - append patched [string range $data [expr {$idx + [string length $first_refclk_line]}] end] - } else { - append patched $block - } - set fh [open $file w] - puts -nonewline $fh $patched - close $fh - puts "INFO: patched XDMA GT refclk pad constraints: $file" - } -} - -proc patch_xdma_cdc_attribute_constraints {} { - foreach pnr_dir [glob -nocomplain hw.dat/Compile/PnR/*/*] { - set script [file join $pnr_dir xdma_cdc_attributes.tcl] - set fh [open $script w] - puts $fh "# UVHS patch: annotate known XDMA IP CDC synchronizer registers." - puts $fh "# This does not change clock definitions; it only preserves and classifies" - puts $fh "# Xilinx XDMA reset/clock-converter synchronization chains after link_design." - puts $fh "proc ::uvhs_xdma_mark_cdc_cells {uvhs_label uvhs_patterns} {" - puts $fh " set uvhs_cells {}" - puts $fh " foreach uvhs_pattern \$uvhs_patterns {" - puts $fh " foreach uvhs_cell \[get_cells -hier -quiet -filter \"IS_SEQUENTIAL && NAME =~ \$uvhs_pattern\"\] {" - puts $fh " if {\[lsearch -exact \$uvhs_cells \$uvhs_cell\] < 0} {" - puts $fh " lappend uvhs_cells \$uvhs_cell" - puts $fh " }" - puts $fh " }" - puts $fh " }" - puts $fh " if {\[llength \$uvhs_cells\]} {" - puts $fh " set_property ASYNC_REG TRUE \$uvhs_cells" - puts $fh " }" - puts $fh " puts \"INFO: UVHS patch: XDMA CDC category \$uvhs_label ASYNC_REG count=\[llength \$uvhs_cells\]\"" - puts $fh " return \$uvhs_cells" - puts $fh "}" - puts $fh "set uvhs_xdma_cdc_cells {}" - puts $fh "foreach uvhs_xdma_cdc_cell \[::uvhs_xdma_mark_cdc_cells auto_cc_clock_conv_lite {" - puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/inst/gen_clock_conv.gen_async_lite_conv*/clock_conv_lite_*/*_reg*" - puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/inst/gen_clock_conv.gen_async_lite_conv*/clock_conv_lite_*/handshake/*_reg*" - puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*clock_conv_lite*/*_reg*" - puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*handshake*/*_reg*" - puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*cdc*/*_reg*" - puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*sync*/*_reg*" - puts $fh "}\] {" - puts $fh " if {\[lsearch -exact \$uvhs_xdma_cdc_cells \$uvhs_xdma_cdc_cell\] < 0} {" - puts $fh " lappend uvhs_xdma_cdc_cells \$uvhs_xdma_cdc_cell" - puts $fh " }" - puts $fh "}" - puts $fh "foreach uvhs_xdma_cdc_cell \[::uvhs_xdma_mark_cdc_cells auto_cc_xpm_cdc {" - puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/inst/*xpm_cdc*/*_reg*" - puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/inst/*xpm_cdc*/inst/*_reg*" - puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*xpm_cdc*/*_reg*" - puts $fh " */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*xpm_cdc*/inst/*_reg*" - puts $fh "}\] {" - puts $fh " if {\[lsearch -exact \$uvhs_xdma_cdc_cells \$uvhs_xdma_cdc_cell\] < 0} {" - puts $fh " lappend uvhs_xdma_cdc_cells \$uvhs_xdma_cdc_cell" - puts $fh " }" - puts $fh "}" - puts $fh "foreach uvhs_xdma_cdc_cell \[::uvhs_xdma_mark_cdc_cells xdma_reset_and_link {" - puts $fh " */core_def/xdma_ep_i/xdma_0/inst/*/*cdc*/*_reg*" - puts $fh " */core_def/xdma_ep_i/xdma_0/inst/*/*cdc*/inst/*_reg*" - puts $fh " */core_def/xdma_ep_i/xdma_0/inst/*/xpm_cdc*/*_reg*" - puts $fh " */core_def/xdma_ep_i/xdma_0/inst/*/xpm_cdc*/inst/*_reg*" - puts $fh " */core_def/xdma_ep_i/xdma_0/inst/*/arststages_ff_reg*" - puts $fh " */core_def/xdma_ep_i/xdma_0/inst/*/*user_rst*_reg*" - puts $fh " */core_def/xdma_ep_i/xdma_0/inst/udma_wrapper/dma_top/user_rst*_reg*" - puts $fh " */core_def/xdma_ep_i/xdma_0/inst/udma_wrapper/dma_top/*user_rst*_reg*" - puts $fh " */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*cdc*/*_reg*" - puts $fh " */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*cdc*/inst/*_reg*" - puts $fh " */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*sync*/*_reg*" - puts $fh " */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*sync*/inst/*_reg*" - puts $fh " */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*rst*sync*reg*" - puts $fh " */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*reset*sync*reg*" - puts $fh "}\] {" - puts $fh " if {\[lsearch -exact \$uvhs_xdma_cdc_cells \$uvhs_xdma_cdc_cell\] < 0} {" - puts $fh " lappend uvhs_xdma_cdc_cells \$uvhs_xdma_cdc_cell" - puts $fh " }" - puts $fh "}" - puts $fh "if {\[llength \$uvhs_xdma_cdc_cells\]} {" - puts $fh " set_property ASYNC_REG TRUE \$uvhs_xdma_cdc_cells" - puts $fh " puts \"INFO: UVHS patch: marked XDMA CDC cells ASYNC_REG count=\[llength \$uvhs_xdma_cdc_cells\]\"" - puts $fh "} else {" - puts $fh " puts \"INFO: UVHS patch: no XDMA CDC cells matched for ASYNC_REG annotation\"" - puts $fh "}" - close $fh - puts "INFO: wrote XDMA CDC attribute script: $script" - - foreach hook_name {before_link.tcl pre_link.tcl} { - set hook [file join $pnr_dir $hook_name] - if {![file exists $hook]} { - continue - } - set fh [open $hook r] - set data [read $fh] - close $fh - set patched $data - regsub -all {\nadd_file \$FILE_DIR/xdma_cdc_attributes\.xdc} $patched "" patched - regsub -all {\nsource \$FILE_DIR/xdma_cdc_attributes\.tcl} $patched "" patched - if {$patched ne $data} { - set fh [open $hook w] - puts -nonewline $fh $patched - close $fh - puts "INFO: removed pre-link XDMA CDC attribute hook: $hook" - } - } - } -} - -proc patch_vivado_makefiles {} { - if {[info exists ::env(UV_SHELL)] && $::env(UV_SHELL) ne ""} { - set uv_shell $::env(UV_SHELL) - } elseif {[info exists ::env(UV_ROOT)] && $::env(UV_ROOT) ne ""} { - set uv_shell [file join $::env(UV_ROOT) bin uv_shell] - } else { - set uv_shell uv_shell - } - set replacement "bash $uv_shell" - foreach makefile [glob -nocomplain hw.dat/Compile/PnR/*/*/vivado/Rundir/*/Makefile] { - set fh [open $makefile r] - set data [read $fh] - close $fh - set patched $data - regsub -all {(^|[[:space:]&;])uv_shell([[:space:]])} \ - $patched "\\1$replacement\\2" patched - regsub -all {(^|[[:space:]&;])(/[^[:space:]]+/uv_shell)([[:space:]])} \ - $patched "\\1$replacement\\3" patched - regsub -all {(^|[[:space:]&;(@])(bash[[:space:]]+)+(/[^[:space:]]+/uv_shell)} \ - $patched "\\1$replacement" patched - regsub -all {(^|[[:space:]])@uv_shell([[:space:]])} \ - $patched "\\1@$replacement\\2" patched - if {$patched ne $data} { - set fh [open $makefile w] - puts -nonewline $fh $patched - close $fh - puts "INFO: patched UVHS Makefile uv_shell invocation: $makefile" - } + if {[llength $args]} { + puts "INFO: set UVHS fill rates: $args" + set_fill_rate {*}$args } } @@ -1186,10 +42,14 @@ set_working_space hw.dat set fpga_threads [env_or_default UVHS_FPGA_THREADS 8] set fpga_processes [env_or_default UVHS_FPGA_PROCESSES 16] -if {[env_or_default UVHS_USE_LSF 1]} { - set_parallel_option -max_threads $fpga_threads -max_processes $fpga_processes -submit_command {bsub -R "rusage[mem=80000]"} -terminate_command bkill -label fpga +if {[env_or_default UVHS_USE_LSF 0]} { + set_parallel_option -max_threads $fpga_threads \ + -max_processes $fpga_processes \ + -submit_command {bsub -R "rusage[mem=80000]"} \ + -terminate_command bkill -label fpga } else { - set_parallel_option -max_threads $fpga_threads -max_processes $fpga_processes -label fpga + set_parallel_option -max_threads $fpga_threads \ + -max_processes $fpga_processes -label fpga } set_option time.auto_clock_config true @@ -1198,96 +58,43 @@ set_option clock.glitch.force_transform true set_option clock.async_control.force_accept true set_option time.enable_sign_off true set_option time.incremental_sign_off true -set uvhs_time_group_io_logic [env_or_default UVHS_TIME_GROUP_IO_LOGIC default] -if {$uvhs_time_group_io_logic ne "default"} { - if {$uvhs_time_group_io_logic ni {0 1 false true}} { - error "UVHS_TIME_GROUP_IO_LOGIC must be one of default/0/1/false/true, got '$uvhs_time_group_io_logic'" - } - puts "INFO: set time.group_io_logic=$uvhs_time_group_io_logic" - set_option time.group_io_logic $uvhs_time_group_io_logic -} set design_name [env_or_default UVHS_DESIGN_NAME VU19P_X4] set platform [env_or_default PLATFORM U2.2] create_system_design -name $design_name -platform $platform -set assemble_file [env_or_default UVHS_ASSEMBLE_FILE ./script/1B_4F_HGC_assemble.tcl] -if {$assemble_file eq "none"} { - puts "INFO: skip board assembly" -} else { - source_if_exists $assemble_file -} -set skip_board_constraints [env_or_default UVHS_SKIP_BOARD_CONSTRAINTS 0] -if {$skip_board_constraints} { - puts "INFO: skip board pin constraints" -} else { - set assign_pin_file [env_or_default UVHS_ASSIGN_PIN_FILE ./script/assign_pin.tcl] - if {[file exists $assign_pin_file]} { - set ::env(UVHS_ASSIGN_PIN_TOP) none - source_if_exists $assign_pin_file - unset -nocomplain ::env(UVHS_ASSIGN_PIN_TOP) - } else { - puts "INFO: skip missing $assign_pin_file" - } - source_if_exists [env_or_default UVHS_PIN_OVERRIDE_FILE none] -} +source_required [env_or_default UVHS_ASSEMBLE_FILE ./script/1B_4F_HGC_assemble.tcl] + +set assign_pin_file [env_or_default UVHS_ASSIGN_PIN_FILE ./script/assign_pin.tcl] +set ::env(UVHS_ASSIGN_PIN_TOP) none +source_required $assign_pin_file +unset ::env(UVHS_ASSIGN_PIN_TOP) create_design -name test -uvhs_clean_stale_partition_runtime read_netlist link_design report_resource -depth 4 instrument_design sanitize_design -if {$skip_board_constraints} { - run_or_warn "check_design" {check_design} -} else { - check_design -} +check_design init_runtime_data trigger_probe -check sweep_design -create_clock_if_port_exists TMCLK 1000 clk8_p -create_clock_if_port_exists ddr_ref_clk 12.5 clk7_p -create_clock_if_port_exists CPU_CLK_IN [uvhs_cpu_clk_period_ns] clk5_p -create_clock_if_port_exists jtag_vclk 83.333 JTAG_TCK -create_clock_if_port_exists pcie_ep_refclk 10 pcie_ep_gt_ref_clk_p -create_generated_clock_if_bufgce_exists SOC_GATED_CLK CPU_CLK_IN { - *SOC_CLK_CTRL*bufgce* - *inter_soc_clk* -} -create_generated_clock_if_bufgce_exists RTC_GATED_CLK TMCLK { - *RTC_CLK_CTRL*bufgce* - *inter_rtc_clk* -} -create_blackbox_output_clock_if_pin_exists XDMA_AXI_ACLK [uvhs_xdma_axi_clk_period_ns] core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK -create_ddr_ui_clock_if_exists -create_clock_if_pin_exists XDMA_AXI_ACLK [uvhs_xdma_axi_clk_period_ns] core_def/xdma_ep_i/clk_wiz_0/clk_in1 -run_or_warn "infer_clock" {infer_clock} -run_or_warn "report_clock -inferred" {report_clock -inferred} -source_if_exists [file normalize [file join [file dirname [info script]] async_clocks.tcl]] -run_or_warn "transform_clock" {transform_clock} -source_if_exists [file normalize [file join [file dirname [info script]] async_clocks.tcl]] -uvhs_config_fill_rates -uvhs_config_probe_group_resource +infer_clock +report_clock -inferred +transform_clock +source_required [env_or_default UVHS_ASYNC_CLOCK_FILE ./script/fpga_diff_async_clocks.tcl] +configure_fill_rates trigger_probe -group sweep_design -remap report_clock -if {$skip_board_constraints} { - run_or_warn "check_design" {check_design} -} else { - check_design -} +check_design report_resource -depth 4 report_system_resource list_partition_constraints -all -if {$skip_board_constraints} { - run_or_warn "partition_design" {partition_design -tdc -tdss true} -} else { - partition_design -tdc -tdss true -} +partition_design -tdc -tdss true report_resource -depth 4 instrument_design @@ -1297,59 +104,35 @@ localize_design -data route_design check_timing -verbose report_system_performance -show_clock_relation -verbose -report_path -normalize -exception -tdr -net -rtl -max_path 100 -sort_by fmax +report_path -normalize -exception -tdr -net -rtl \ + -max_path 100 -sort_by fmax insert_tdm reopt_design -verbose bind_system save_runtime_data -set_option compile.resourceUsageLimit [env_or_default UVHS_RESOURCE_USAGE_LIMIT 100] -set strategy_num_retry [env_or_default UVHS_STRATEGY_NUM_RETRY none] -if {$strategy_num_retry eq "none" || $strategy_num_retry eq "0"} { - puts "INFO: skip compile.strategyNumRetry" -} else { - run_or_warn "set_option compile.strategyNumRetry" \ - [list set_option compile.strategyNumRetry $strategy_num_retry] -} +set_option compile.resourceUsageLimit 100 +set_option compile.strategyNum 1 +set_option compile.strategy0 \ + [env_or_default UVHS_COMPILE_STRATEGY uv_high_fanout_explore] +set_option compile.stage.preOpt \ + [env_or_default UVHS_VIVADO_PRE_OPT_FILE ./script/vivado_pre_opt.tcl] -set compile_strategy_num [env_or_default UVHS_COMPILE_STRATEGY_NUM 1] -if {![string is integer -strict $compile_strategy_num] || $compile_strategy_num < 1} { - error "UVHS_COMPILE_STRATEGY_NUM must be a positive integer, got '$compile_strategy_num'" +compile_fpga -parallel_option fpga -genScriptOnly -explore +set shell_helper [env_or_default UVHS_SHELL_COMPAT_SCRIPT ""] +if {$shell_helper eq ""} { + error "UVHS_SHELL_COMPAT_SCRIPT is not set" } -set_option compile.strategyNum $compile_strategy_num -set default_compile_strategies { - uv_high_fanout_explore - uv_placer_balance_slrs - uv_placer_extra_timing_opt +set shell_helper [file normalize $shell_helper] +if {![file isfile $shell_helper]} { + error "UVHS shell compatibility helper not found: $shell_helper" } -for {set i 0} {$i < $compile_strategy_num} {incr i} { - set default_strategy "" - if {$i < [llength $default_compile_strategies]} { - set default_strategy [lindex $default_compile_strategies $i] - } - set strategy [env_or_default [format {UVHS_COMPILE_STRATEGY%d} $i] $default_strategy] - if {$strategy eq "" || $strategy eq "none"} { - error "missing compile strategy $i; set UVHS_COMPILE_STRATEGY$i" - } - puts "INFO: UVHS compile.strategy$i=$strategy" - set_option [format {compile.strategy%d} $i] $strategy -} -set_option compile.stage.preOpt ./script/pre_opt.tcl -set_option compile.stage.prePlace ./script/pre_place.tcl - -compile_fpga -parallel_option fpga -genScriptOnly -explore -patch_timing_constraint_files -patch_xdma_gt_refclk_pad_constraints -patch_xdma_cdc_attribute_constraints -patch_vivado_wrappers -patch_vivado_makefiles -patch_vivado_pre_opt -patch_vivado_pre_place -patch_vivado_before_route +exec bash $shell_helper patch-pnr hw.dat/Compile/PnR compile_fpga -parallel_option fpga -runOnly -explore report_path -max_path 100 report_system_performance commit_runtime_data +puts "UVHS_BACKEND_SUCCESS" exit diff --git a/fpga_diff/uvhs/check_flow_tools.sh b/fpga_diff/uvhs/check_flow_tools.sh index 401862c2..45af496c 100644 --- a/fpga_diff/uvhs/check_flow_tools.sh +++ b/fpga_diff/uvhs/check_flow_tools.sh @@ -14,17 +14,18 @@ required=( uvhs/assign_pin_u22_f2.tcl uvhs/async_clocks.tcl uvhs/timing_common.tcl + uvhs/vivado_pre_opt.tcl uvhs/export_vivado_ip.tcl uvhs/check_modules.sh uvhs/make_compat/make uvhs/make_compat/csh - uvhs/patch_uvsyn_shell.sh + uvhs/shell_compat.sh uvhs/enqueue_runtime_command.sh uvhs/runtime_session.sh uvhs/uv_shell_exec_compat.sh + uvhs/hw_run_download.tcl uvhs/runtime_control.tcl uvhs/runtime_command.tcl - user_script/hw_run_download.tcl src/tcl/common/AXI_bridge.tcl src/tcl/common/xdma_ep.tcl ) @@ -40,7 +41,7 @@ bash -n "$root_dir/uvhs/check_modules.sh" bash -n "$root_dir/uvhs/check_flow_tools.sh" bash -n "$root_dir/uvhs/make_compat/make" bash -n "$root_dir/uvhs/make_compat/csh" -bash -n "$root_dir/uvhs/patch_uvsyn_shell.sh" +bash -n "$root_dir/uvhs/shell_compat.sh" bash -n "$root_dir/uvhs/enqueue_runtime_command.sh" bash -n "$root_dir/uvhs/runtime_session.sh" bash -n "$root_dir/uvhs/uv_shell_exec_compat.sh" @@ -53,12 +54,12 @@ set source [read $fh] close $fh if {![info complete $source]} { exit 1 } TCL - done < <(find "$root_dir/uvhs" "$root_dir/user_script" -type f -name '*.tcl' -print0) + done < <(find "$root_dir/uvhs" -type f -name '*.tcl' -print0) fi if grep -R -n -E '/home/|setenv\.local|NUTSHELL_LEGACY_DIFFTEST_HOSTIF|UVHS_XDMA_ST_LOOPBACK_SMOKE|UVHS_CPU_LIVENESS_GBD' \ --include='*.mk' --include='*.sh' --include='*.tcl' --include='*.sv' \ - --exclude='check_flow_tools.sh' "$root_dir/uvhs" "$root_dir/user_script"; then + --exclude='check_flow_tools.sh' "$root_dir/uvhs"; then echo "ERROR: removed local paths or legacy/debug controls remain in UVHS sources" >&2 exit 1 fi diff --git a/fpga_diff/uvhs/frontend_run.tcl b/fpga_diff/uvhs/frontend_run.tcl index 17a4f71f..466eb59a 100644 --- a/fpga_diff/uvhs/frontend_run.tcl +++ b/fpga_diff/uvhs/frontend_run.tcl @@ -10,141 +10,92 @@ proc env_or_default {name default} { } proc split_words {value} { - set out [list] - foreach item $value { - if {$item ne ""} { - lappend out $item + set words {} + foreach word $value { + if {$word ne ""} { + lappend words $word } } - return $out + return $words } -set required_dcp_modules [split_words [env_or_default UVHS_REQUIRED_DCP_MODULES {blk_mem_gen_0 AXI_bridge data_bridge xdma_ep uvw_axi4_to_ddr4 uvw_general_bus}]] - -proc dcp_module_is_required {module} { - return [expr {[lsearch -exact $::required_dcp_modules $module] >= 0}] -} - -proc source_if_exists {file} { - if {$file eq "none"} { - puts "INFO: skip $file" - return - } - if {[file exists $file]} { - puts "INFO: source $file" - if {[catch {uplevel #0 [list source $file]} err]} { - puts "WARNING: source $file failed: $err" - } - } else { - puts "INFO: skip missing $file" - } -} - -proc set_blackbox_if_exists {module dcp args} { - if {![dcp_module_is_required $module]} { - puts "INFO: skip blackbox $module because it is not listed in UVHS_REQUIRED_DCP_MODULES" - return - } - if {[file exists $dcp]} { - puts "INFO: set_blackbox $module $dcp" - set command [list set_blackbox -module $module -source_file $dcp] - if {[llength $args] > 0} { - set command [concat $command $args] - } - uplevel #0 $command - } else { - error "required blackbox DCP missing for $module: $dcp" +proc source_required {file} { + if {![file exists $file]} { + error "required UVHS flow file not found: $file" } + puts "INFO: source $file" + uplevel #0 [list source $file] } -proc set_ip_if_exists {module dcp stub args} { - if {![dcp_module_is_required $module]} { - puts "INFO: skip set_ip $module because it is not listed in UVHS_REQUIRED_DCP_MODULES" - return - } - if {![file exists $dcp]} { - error "required IP DCP missing for $module: $dcp" - } - if {![file exists $stub]} { - error "required IP stub missing for $module: $stub" +proc import_blackbox {module dcp args} { + if {![file exists $dcp] || [file size $dcp] == 0} { + error "required blackbox DCP missing or empty for $module: $dcp" } - puts "INFO: set_ip $module $dcp" - set command [list set_ip -module $module -source_file $dcp] - if {[llength $args] > 0} { - set command [concat $command $args] - } - uplevel #0 $command - set read_stub [env_or_default [string toupper UVHS_${module}_READ_STUB] 1] - if {$read_stub eq "0"} { - puts "INFO: skip read_verilog $stub because UVHS_[string toupper ${module}]_READ_STUB=0" - } else { - puts "INFO: read_verilog $stub" - uplevel #0 [list read_verilog $stub] - } + puts "INFO: set_blackbox $module $dcp" + uplevel #0 [concat [list set_blackbox -module $module -source_file $dcp] $args] } -proc require_file_for_uvhs_ip {description file} { - if {![file exists $file] || [file size $file] == 0} { - error "required UVHS DDR IP $description missing or empty: $file" +proc import_ip {module dcp stub args} { + foreach {kind file} [list DCP $dcp stub $stub] { + if {![file exists $file] || [file size $file] == 0} { + error "required $module $kind missing or empty: $file" + } } - puts "INFO: found UVHS DDR IP $description: $file" -} -proc run_or_warn {description command} { - puts "INFO: $description" - if {[catch {uplevel #0 $command} err]} { - puts "WARNING: $description failed: $err" - } + puts "INFO: set_ip $module $dcp" + uplevel #0 [concat [list set_ip -module $module -source_file $dcp] $args] + puts "INFO: read_verilog $stub" + read_verilog $stub } -proc append_line_if_missing {file line} { - if {$file eq "" || $line eq ""} { - return - } - set existing "" +proc append_option_once {file line} { + set data "" if {[file exists $file]} { - set fh [open $file r] - set existing [read $fh] - close $fh - foreach entry [split $existing "\n"] { - if {[string trim $entry] eq $line} { - puts "INFO: keep existing option line in $file: $line" + set input [open $file r] + set data [read $input] + close $input + foreach existing [split $data "\n"] { + if {[string trim $existing] eq $line} { return } } } - set fh [open $file a] - if {$existing ne "" && ![string match *\n $existing]} { - puts $fh "" + + set output [open $file a] + if {$data ne "" && ![string match *\n $data]} { + puts $output "" } - puts $fh $line - close $fh - puts "INFO: appended option line to $file: $line" + puts $output $line + close $output } -proc patch_option_add_rtl_inst {working_space inst_path} { +# UVHS runtime writemem discovers backdoor instances from these database files; +# the installed release does not expose an equivalent frontend Tcl command. +proc register_runtime_memory {working_space inst_path} { if {$inst_path eq "" || $inst_path eq "none"} { - puts "INFO: skip option.add_rtl_inst patch" return } set option_dir [file join $working_space DB Options] file mkdir $option_dir - set add_inst_line "add_rtl_inst -inst_name $inst_path" - append_line_if_missing [file join $option_dir option.add_rtl_inst.txt] $add_inst_line - append_line_if_missing [file join $option_dir option.txt] $add_inst_line + set option "add_rtl_inst -inst_name $inst_path" + append_option_once [file join $option_dir option.add_rtl_inst.txt] $option + append_option_once [file join $option_dir option.txt] $option + puts "INFO: registered UVHS runtime memory instance $inst_path" } -# UVHS generates this Makefile after elaboration. Its stock recipe invokes -# uv_shell through /bin/sh even though the vendor script requires Bash. -proc start_uvsyn_shell_patch_watcher {} { - set module_makefile [file join [pwd] hw.dat Synthesis Uvsyn Script module.makefile] - set patch_script [file normalize [file join [file dirname [info script]] patch_uvsyn_shell.sh]] - if {![file exists $patch_script]} { - error "missing UVHS worker shell compatibility helper: $patch_script" +proc start_frontend_shell_compat {} { + set helper [env_or_default UVHS_SHELL_COMPAT_SCRIPT ""] + if {$helper eq ""} { + error "UVHS_SHELL_COMPAT_SCRIPT is not set" + } + set helper [file normalize $helper] + if {![file isfile $helper]} { + error "UVHS shell compatibility helper not found: $helper" } - exec bash $patch_script $module_makefile & - puts "INFO: started UVHS worker shell compatibility helper" + set module_makefile [file join [pwd] hw.dat Synthesis Uvsyn Script module.makefile] + exec bash $helper wait-module $module_makefile & + puts "INFO: started UVHS frontend shell compatibility helper" } create_working_space hw.dat @@ -154,18 +105,25 @@ set frontend_threads [env_or_default UVHS_FRONTEND_THREADS 16] set frontend_processes [env_or_default UVHS_FRONTEND_PROCESSES 64] set fpga_threads [env_or_default UVHS_FPGA_THREADS 8] set fpga_processes [env_or_default UVHS_FPGA_PROCESSES 32] - -if {[env_or_default UVHS_USE_LSF 1]} { - set_parallel_option -max_threads $frontend_threads -max_processes $frontend_processes -submit_command bsub -terminate_command bkill -label frontend - set_parallel_option -max_threads $fpga_threads -max_processes $fpga_processes -submit_command {bsub -R "rusage[mem=80000]"} -terminate_command bkill -label fpga +if {[env_or_default UVHS_USE_LSF 0]} { + set_parallel_option -max_threads $frontend_threads \ + -max_processes $frontend_processes -submit_command bsub \ + -terminate_command bkill -label frontend + set_parallel_option -max_threads $fpga_threads \ + -max_processes $fpga_processes \ + -submit_command {bsub -R "rusage[mem=80000]"} \ + -terminate_command bkill -label fpga } else { - set_parallel_option -max_threads $frontend_threads -max_processes $frontend_processes -label frontend - set_parallel_option -max_threads $fpga_threads -max_processes $fpga_processes -label fpga + set_parallel_option -max_threads $frontend_threads \ + -max_processes $frontend_processes -label frontend + set_parallel_option -max_threads $fpga_threads \ + -max_processes $fpga_processes -label fpga } set_option global.log.label MEMORY set_option syn.checkMultiDriver false set_option syn.multipleDriverConflict WOR +set_option syn.logicFillingRateThreshold 0.001 set_option time.auto_clock_config true set_option clock.transform_clock.multi_iteration true set_option clock.glitch.force_transform true @@ -173,69 +131,48 @@ set_option clock.async_control.force_accept true set_option time.enable_sign_off true set_option time.incremental_sign_off true set_option signal.uhd.sampling_clock.allow_local_clock true -set_option syn.logicFillingRateThreshold 0.001 set design_name [env_or_default UVHS_DESIGN_NAME VU19P_X4] set platform [env_or_default PLATFORM U2.2] set design_top [env_or_default UVHS_TOP fpga_top_debug] -set ddr_inst_path [env_or_default UVHS_DDR_RTL_INST ${design_top}.core_def.U_JTAG_DDR_SUBSYS] -set reset_ports [split_words [env_or_default UVHS_RESET_PORTS {rstn_sw6 rstn_sw5 rstn_sw4}]] +set ddr_inst_path [env_or_default UVHS_DDR_RTL_INST \ + ${design_top}.core_def.U_UVHS_UVW_AXI4_TO_DDR4] create_system_design -name $design_name -platform $platform -set assemble_file [env_or_default UVHS_ASSEMBLE_FILE ./script/1B_4F_HGC_assemble.tcl] -if {$assemble_file eq "none"} { - puts "INFO: skip board assembly" -} else { - source_if_exists $assemble_file +source_required [env_or_default UVHS_ASSEMBLE_FILE ./script/1B_4F_HGC_assemble.tcl] +source_required [env_or_default UVHS_ASSIGN_PIN_FILE ./script/assign_pin.tcl] +set timing_file [env_or_default UVHS_TIMING_FILE ./script/timing.tcl] +if {![file exists $timing_file]} { + error "required UVHS timing constraints not found: $timing_file" } -set skip_board_constraints [env_or_default UVHS_SKIP_BOARD_CONSTRAINTS 0] - -if {$skip_board_constraints} { - puts "INFO: skip board probe/pin/timing/partition constraints" -} else { - source_if_exists [env_or_default UVHS_PROBE_FILE ./script/probe.tcl] - source_if_exists [env_or_default UVHS_ASSIGN_PIN_FILE ./script/assign_pin.tcl] - set timing_file [env_or_default UVHS_TIMING_FILE none] - if {$timing_file eq "none"} { - puts "INFO: skip timing constraints" - } else { - run_or_warn "set_constraint_files" [list set_constraint_files $timing_file] - } - set partition_file [env_or_default UVHS_PARTITION_FILE ./script/partition.tcl] - if {$partition_file eq "none"} { - puts "INFO: skip partition constraints" - } else { - run_or_warn "set_partition_constraint_file" [list set_partition_constraint_file $partition_file] - } - foreach reset_port $reset_ports { - set reset_net ${design_top}.${reset_port} - run_or_warn "create_reset $reset_net" [list create_reset -port $reset_net -active 0] - } +set_constraint_files $timing_file +foreach reset_port [split_words [env_or_default UVHS_RESET_PORTS { + rstn_sw6 rstn_sw5 rstn_sw4 +}]] { + create_reset -port ${design_top}.${reset_port} -active 0 } -set_blackbox_if_exists blk_mem_gen_0 ./rtl/soc/blk_mem_gen_0.dcp -set_blackbox_if_exists AXI_bridge ./rtl/soc/AXI_bridge.dcp -set_blackbox_if_exists data_bridge ./rtl/soc/data_bridge.dcp -set_blackbox_if_exists xdma_ep ./rtl/device/pcie/xdma_ep.dcp -set_blackbox_if_exists uvw_general_bus \ +import_blackbox blk_mem_gen_0 ./rtl/soc/blk_mem_gen_0.dcp +import_blackbox AXI_bridge ./rtl/soc/AXI_bridge.dcp +import_blackbox data_bridge ./rtl/soc/data_bridge.dcp +import_blackbox xdma_ep ./rtl/device/pcie/xdma_ep.dcp +import_blackbox uvw_general_bus \ ./rtl/soc/uvw_general_bus/uvw_general_bus.dcp \ -clock_enable_pairs {dut_axi_aclk dut_axi_aclk_en 1} -require_file_for_uvhs_ip DCP ./rtl/soc/uvw_axi4_to_ddr4.dcp -require_file_for_uvhs_ip stub ./rtl/soc/uvw_axi4_to_ddr4_Stub.v -require_file_for_uvhs_ip pblock ./script/uvw_axi4_to_ddr4_pblock.tcl -set_ip_if_exists uvw_axi4_to_ddr4 ./rtl/soc/uvw_axi4_to_ddr4.dcp \ +import_ip uvw_axi4_to_ddr4 ./rtl/soc/uvw_axi4_to_ddr4.dcp \ ./rtl/soc/uvw_axi4_to_ddr4_Stub.v \ -clock_enable_pairs {ddr4ip_dut_axi_aclk ddr4ip_dut_axi_aclk_en 1} \ -script_file {prePlace ./script/uvw_axi4_to_ddr4_pblock.tcl} set filelist [env_or_default UVHS_FILELIST ./rtl/filelist.f] -puts "INFO: read_verilog -f $filelist" +if {![file exists $filelist]} { + error "required UVHS RTL file list not found: $filelist" +} read_verilog -f $filelist -mfcu - -puts "INFO: elaborate_design $design_top" elaborate_design $design_top -start_uvsyn_shell_patch_watcher +start_frontend_shell_compat synthesize_design -parallel_option frontend save_working_space -patch_option_add_rtl_inst hw.dat $ddr_inst_path +register_runtime_memory hw.dat $ddr_inst_path +puts "UVHS_FRONTEND_SUCCESS" exit diff --git a/fpga_diff/uvhs/hw_run_download.tcl b/fpga_diff/uvhs/hw_run_download.tcl new file mode 100644 index 00000000..0e8a0f4c --- /dev/null +++ b/fpga_diff/uvhs/hw_run_download.tcl @@ -0,0 +1,51 @@ +# Download a completed UVHS database and retain the owning runtime session for +# reset and memory commands. + +set uvhs_script_dir [file dirname [file normalize [info script]]] +if {[info exists ::env(UVHS_RUNTIME_CONTROL_SCRIPT)] && + $::env(UVHS_RUNTIME_CONTROL_SCRIPT) ne ""} { + set uvhs_control_script $::env(UVHS_RUNTIME_CONTROL_SCRIPT) +} else { + set uvhs_control_script [file join $uvhs_script_dir runtime_control.tcl] +} +if {![file exists $uvhs_control_script]} { + error "UVHS runtime control script not found: $uvhs_control_script" +} +source $uvhs_control_script + +query -user +query -fpgas -all +query -version + +if {[info exists ::env(UVHS_DB_PATH)] && $::env(UVHS_DB_PATH) ne ""} { + set uvhs_db_path $::env(UVHS_DB_PATH) +} else { + set uvhs_db_path [file normalize [file join [pwd] .. hw.dat]] +} +puts "INFO: loading runtime database $uvhs_db_path" +load_db -db $uvhs_db_path + +config -connector +query -connector -type fmc +query -voltage + +# A release database can lack sign-off defaults. In that case the replay clock +# values already stored in the database remain active. +if {[catch {query -clock -default} uvhs_clock_error]} { + puts "WARN: retaining database replay clocks: $uvhs_clock_error" +} else { + config -clock -default + config -clock -commit + query -clock +} + +uvhs_hold_soc_for_download +download +query -ipinfo +initialize +after 1000 +uvhs_release_soc_after_download +query -fpgas -all + +# Later commands must execute in the session that owns the downloaded database. +uvhs_serve_runtime_commands diff --git a/fpga_diff/uvhs/patch_uvsyn_shell.sh b/fpga_diff/uvhs/patch_uvsyn_shell.sh deleted file mode 100755 index 97069cb5..00000000 --- a/fpga_diff/uvhs/patch_uvsyn_shell.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -module_makefile=${1:?usage: $0 /path/to/module.makefile} - -for _ in $(seq 1 12000); do - if [[ -f "$module_makefile" ]]; then - if grep -Eq 'bash[[:space:]]+([^[:space:]]*/)?uv_shell[[:space:]]' "$module_makefile"; then - printf 'INFO: UVHS module worker already invokes uv_shell through bash: %s\n' "$module_makefile" - exit 0 - fi - sed -E -i \ - -e 's/until[[:space:]]+sh[[:space:]]+-c/until bash -c/' \ - -e 's#(^|[[:space:]])(/[^[:space:]]*/bin/uv_shell)([[:space:]])#\1bash \2\3#g' \ - -e 's#(^|[[:space:]])(uv_shell)([[:space:]])#\1bash \2\3#g' \ - "$module_makefile" - if grep -Eq 'bash[[:space:]]+([^[:space:]]*/)?uv_shell[[:space:]]' "$module_makefile"; then - printf 'INFO: patched UVHS module worker uv_shell invocation: %s\n' "$module_makefile" - exit 0 - fi - echo "ERROR: module.makefile appeared but uv_shell invocation was not patched: $module_makefile" >&2 - exit 1 - fi - sleep 0.05 -done - -echo "ERROR: timed out waiting for UVHS module makefile: $module_makefile" >&2 -exit 1 diff --git a/fpga_diff/uvhs/shell_compat.sh b/fpga_diff/uvhs/shell_compat.sh new file mode 100755 index 00000000..754676d8 --- /dev/null +++ b/fpga_diff/uvhs/shell_compat.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + echo "Usage: $0 wait-module MODULE_MAKEFILE | patch-pnr PNR_DIR" >&2 + exit 2 +} + +patch_makefile() { + local makefile=$1 + + sed -E -i \ + -e 's/until[[:space:]]+sh[[:space:]]+-c/until bash -c/' \ + -e 's#(^|[[:space:]&;@])(/[^[:space:]]*/bin/uv_shell)([[:space:]])#\1bash \2\3#g' \ + -e 's#(^|[[:space:]&;@])(uv_shell)([[:space:]])#\1bash \2\3#g' \ + -e 's#(^|[[:space:]&;(@])(bash[[:space:]]+)+(/[^[:space:]]*/bin/uv_shell)#\1bash \3#g' \ + -e 's#(^|[[:space:]&;(@])(bash[[:space:]]+)+(uv_shell)#\1bash \3#g' \ + "$makefile" +} + +wait_for_module_makefile() { + local module_makefile=$1 + + for ((attempt = 0; attempt < 12000; attempt++)); do + if [[ -f $module_makefile ]]; then + patch_makefile "$module_makefile" + grep -Eq 'bash[[:space:]]+([^[:space:]]*/)?uv_shell[[:space:]]' \ + "$module_makefile" || { + echo "ERROR: failed to select Bash for $module_makefile" >&2 + exit 1 + } + echo "INFO: selected Bash for UVHS frontend workers: $module_makefile" + return + fi + sleep 0.05 + done + echo "ERROR: timed out waiting for $module_makefile" >&2 + exit 1 +} + +patch_pnr_scripts() { + local pnr_dir=$1 + local wrapper_count=0 + local makefile_count=0 + + [[ -d $pnr_dir ]] || { + echo "ERROR: PnR script directory not found: $pnr_dir" >&2 + exit 1 + } + while IFS= read -r -d '' wrapper; do + sed -i '1s|^#!/bin/sh$|#!/bin/bash|' "$wrapper" + head -n 1 "$wrapper" | grep -Fxq '#!/bin/bash' || { + echo "ERROR: unsupported generated wrapper shell: $wrapper" >&2 + exit 1 + } + chmod 755 "$wrapper" + ((wrapper_count += 1)) + done < <(find "$pnr_dir" -type f -name uv_vivado_wrapper.sh -print0) + while IFS= read -r -d '' makefile; do + patch_makefile "$makefile" + ((makefile_count += 1)) + done < <(find "$pnr_dir" -type f -name Makefile -print0) + + ((wrapper_count > 0)) || { + echo "ERROR: no generated Vivado wrapper found under $pnr_dir" >&2 + exit 1 + } + ((makefile_count > 0)) || { + echo "ERROR: no generated PnR Makefile found under $pnr_dir" >&2 + exit 1 + } + echo "INFO: selected Bash in $wrapper_count wrappers and $makefile_count PnR Makefiles" +} + +[[ $# -eq 2 ]] || usage +case $1 in + wait-module) wait_for_module_makefile "$2" ;; + patch-pnr) patch_pnr_scripts "$2" ;; + *) usage ;; +esac diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 18ce2a8e..b0467594 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -8,6 +8,14 @@ UVHS_DDR_AXI_WIDTH ?= $(if $(filter nutshell,$(CPU)),64,256) UVHS_WORK_DIR ?= $(ENV_SCRIPTS_HOME)/fpga_diff_uvhs_$(CPU)$(if $(strip $(SUFFIX)),-$(strip $(SUFFIX)),) UVHS_TOP ?= fpga_top_debug UVHS_FILELIST ?= $(UVHS_WORK_DIR)/rtl/filelist.f +UVHS_RTL_INCLUDE_FILELIST ?= $(UVHS_WORK_DIR)/rtl/rtl_include.f +UVHS_CORE_RELEASE_DIR ?= $(UVHS_WORK_DIR)/core-release +UVHS_CORE_RELEASE_PACKAGE_DIR ?= $(UVHS_WORK_DIR)/core-release-package +UVHS_CORE_RELEASE_SUFFIX ?= uvhs$(if $(strip $(SUFFIX)),-$(strip $(SUFFIX)),) +UVHS_USE_FPGA_RELEASE ?= $(if $(filter kmh,$(CPU)),1,0) +UVHS_CORE_BUILD_DIR ?= $(if $(filter 1,$(UVHS_USE_FPGA_RELEASE)),$(UVHS_CORE_RELEASE_DIR)/build,$(CORE_DIR)/build) +UVHS_CORE_RTL_DIR ?= $(UVHS_CORE_BUILD_DIR)/rtl +UVHS_CORE_GENERATED_SRC_DIR ?= $(UVHS_CORE_BUILD_DIR)/generated-src UVHS_EXPORT_IP_FORCE ?= 0 UVHS_EXPORT_IP_JOBS ?= 8 @@ -34,11 +42,12 @@ UVHS_FRONTEND_PROCESSES ?= 16 UVHS_FPGA_THREADS ?= 4 UVHS_FPGA_PROCESSES ?= 8 UVHS_PNR_STRATEGY ?= Strategy_uv_high_fanout_explore -UVHS_COMPILE_STRATEGY_NUM ?= 1 -UVHS_COMPILE_STRATEGY0 ?= uv_high_fanout_explore +UVHS_COMPILE_STRATEGY ?= uv_high_fanout_explore UVHS_LUT_FILL_RATE ?= $(if $(filter kmh,$(CPU)),80,) UVHS_LUT6_FILL_RATE ?= $(if $(filter kmh,$(CPU)),30,) -UVHS_ROUTE_ENABLE_HOLD_EXPN_BAILOUT ?= $(if $(filter kmh,$(CPU)),0,) +UVHS_VIVADO_PRE_OPT_FILE ?= $(UVHS_ROOT_DIR)/uvhs/vivado_pre_opt.tcl +UVHS_ASYNC_CLOCK_FILE ?= $(UVHS_WORK_DIR)/script/fpga_diff_async_clocks.tcl +UVHS_SHELL_COMPAT_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/shell_compat.sh XDMA_LINK_WIDTH ?= X4 XDMA_ENABLE_PF0_BAR1 ?= 1 @@ -54,8 +63,6 @@ UVHS_UVW_AXI4_TO_DDR4_REQUIRED_FILES := \ rtl/soc/uvw_axi4_to_ddr4.dcp \ rtl/soc/uvw_axi4_to_ddr4_Stub.v \ script/uvw_axi4_to_ddr4_pblock.tcl -UVHS_REQUIRED_DCP_MODULES := blk_mem_gen_0 AXI_bridge data_bridge xdma_ep \ - uvw_axi4_to_ddr4 uvw_general_bus UVHS_REQUIRED_MODULES ?= $(if $(filter nanhu,$(CPU)),XlnFpgaTop,$(if $(filter kmh nutshell,$(CPU)),SimTop,)) UVHS_DDR_RTL_INST := $(UVHS_TOP).core_def.U_UVHS_UVW_AXI4_TO_DDR4 UVHS_RUNTIME_LIB_DIR ?= $(UVHS_WORK_DIR)/.uvhs-runtime-lib @@ -66,7 +73,7 @@ UVHS_RUNTIME_TMP_DIR ?= $(UVHS_RUNTIME_WORK_DIR)/tmp UVHS_RUNTIME_PID_FILE ?= $(UVHS_RUNTIME_WORK_DIR)/uv_shell.pid UVHS_RUNTIME_READY_FILE ?= $(UVHS_RUNTIME_WORK_DIR)/uv_shell.ready UVHS_RUNTIME_LOG ?= $(UVHS_RUNTIME_WORK_DIR)/uv_shell.log -UVHS_RUNTIME_DOWNLOAD_SCRIPT ?= $(UVHS_ROOT_DIR)/user_script/hw_run_download.tcl +UVHS_RUNTIME_DOWNLOAD_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/hw_run_download.tcl UVHS_RUNTIME_CONTROL_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/runtime_control.tcl UVHS_RUNTIME_COMMAND_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/runtime_command.tcl UVHS_RUNTIME_SESSION_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/runtime_session.sh @@ -103,18 +110,19 @@ UVHS_FLOW_ENV = \ UVHS_KEEP_FPGAS="$(UVHS_KEEP_FPGAS)" \ UVHS_CPU_CLK_PERIOD_NS="$(UVHS_CPU_CLK_PERIOD_NS)" \ UVHS_PNR_STRATEGY="$(UVHS_PNR_STRATEGY)" \ - UVHS_COMPILE_STRATEGY_NUM="$(UVHS_COMPILE_STRATEGY_NUM)" \ - UVHS_COMPILE_STRATEGY0="$(UVHS_COMPILE_STRATEGY0)" \ + UVHS_COMPILE_STRATEGY="$(UVHS_COMPILE_STRATEGY)" \ UVHS_LUT_FILL_RATE="$(UVHS_LUT_FILL_RATE)" \ UVHS_LUT6_FILL_RATE="$(UVHS_LUT6_FILL_RATE)" \ - UVHS_ROUTE_ENABLE_HOLD_EXPN_BAILOUT="$(UVHS_ROUTE_ENABLE_HOLD_EXPN_BAILOUT)" + UVHS_VIVADO_PRE_OPT_FILE="$(UVHS_VIVADO_PRE_OPT_FILE)" \ + UVHS_ASYNC_CLOCK_FILE="$(UVHS_ASYNC_CLOCK_FILE)" \ + UVHS_SHELL_COMPAT_SCRIPT="$(UVHS_SHELL_COMPAT_SCRIPT)" UVHS_PNR_DIR ?= $(UVHS_WORK_DIR)/hw.dat/Compile/PnR/$(UVHS_TARGET_PACK)/$(UVHS_TARGET_FPGA)/vivado/Rundir/$(UVHS_PNR_STRATEGY) UVHS_BITSTREAM_DIR ?= $(UVHS_PNR_DIR)/bitstream UVHS_BIT_HOME ?= $(UVHS_WORK_DIR)/ready-to-program -.PHONY: uvhs_preflight uvhs_prepare uvhs_export_vivado_ip \ - uvhs_export_generalbus \ +.PHONY: uvhs_preflight uvhs_prepare uvhs_prepare_core_rtl \ + uvhs_export_vivado_ip uvhs_export_generalbus uvhs_normalize_rtl_include \ uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist uvhs_check_modules \ uvhs_frontend uvhs_backend uvhs_all uvhs_check_timing \ uvhs_package_bitstream uvhs_tools_check uvhs_clean uvhs_write_bitstream \ @@ -129,6 +137,8 @@ uvhs_preflight: test -n "$$UV_LICENSE" test -x "$$UV_ROOT/bin/uv_shell_exec" test -x "$(UVHS_SHELL_EXEC_WRAPPER)" + test -x "$(UVHS_SHELL_COMPAT_SCRIPT)" + test -f "$(UVHS_VIVADO_PRE_OPT_FILE)" test -f "$(UVHS_GBUS_GENERATOR)" test -f "$(UVHS_GBUS_JSON)" command -v python3 >/dev/null @@ -163,8 +173,34 @@ uvhs_prepare: uvhs_preflight mkdir -p "$(UVHS_WORK_DIR)" cp -a "$(UVHS_TEMPLATE_DIR)/script" "$(UVHS_WORK_DIR)/" cp -f "$(UVHS_TEMPLATE_DIR)/Makefile" "$(UVHS_WORK_DIR)/Makefile" + cp -f "$(UVHS_ROOT_DIR)/uvhs/async_clocks.tcl" "$(UVHS_ASYNC_CLOCK_FILE)" mkdir -p "$(UVHS_WORK_DIR)/rtl/soc" "$(UVHS_WORK_DIR)/rtl/device/pcie" +# XiangShan's upstream release step removes FPGA clock gates and assigns large +# generated arrays to URAM. Synthesize that released RTL rather than build/rtl. +uvhs_prepare_core_rtl: +ifeq ($(filter 1,$(UVHS_USE_FPGA_RELEASE)),1) + bash -c 'set -euo pipefail; \ + core="$(CORE_DIR)"; package="$(UVHS_CORE_RELEASE_PACKAGE_DIR)"; release="$(UVHS_CORE_RELEASE_DIR)"; \ + test -f "$$core/build/rtl/SimTop.sv"; \ + test -f "$$core/build/generated-src/difftest_profile.json"; \ + test -f "$$core/difftest/scripts/fpga/release.sh"; \ + rm -rf "$$package" "$$release"; \ + mkdir -p "$$package" "$$release"; \ + $(MAKE) -C "$$core/difftest" fpga-release NOOP_HOME="$$core" \ + RELEASE_DIR="$$package" RELEASE_SUFFIX="$(UVHS_CORE_RELEASE_SUFFIX)"; \ + archive="$$(find "$$package" -maxdepth 1 -type f -name "*.tar.gz" -print -quit)"; \ + test -n "$$archive"; \ + tar -xzf "$$archive" -C "$$release" --strip-components=1; \ + test -f "$$release/build/rtl/SimTop.sv"; \ + test -f "$$release/build/rtl/DifftestClockGate.v"; \ + grep -Fq "assign Q = CK;" "$$release/build/rtl/ClockGate.sv"; \ + grep -Fq "ram_style = \"ultra\"" "$$release/build/rtl"/array_*.v; \ + echo "INFO: prepared XiangShan FPGA release RTL at $$release/build/rtl"' +else + test -d "$(UVHS_CORE_RTL_DIR)" +endif + uvhs_export_vivado_ip: uvhs_prepare bash -c 'set -euo pipefail; \ export VIVADO_HOME="$$UV_XILINX_VIVADO" XILINX_VIVADO="$$UV_XILINX_VIVADO"; \ @@ -179,8 +215,8 @@ uvhs_export_vivado_ip: uvhs_prepare $(foreach ip,$(UVHS_SKIP_VIVADO_EXPORT),--skip "$(ip)") \ $(if $(filter 1,$(UVHS_EXPORT_IP_FORCE)),--force,)' -# The vendor generator assumes tcsh and starts an asynchronous DCP copy before -# deleting its project. Patch only the private work-directory copy. +# The vendor generator starts an asynchronous DCP copy before deleting its +# project. Make that copy synchronous in the private work-directory copy. uvhs_export_generalbus: uvhs_prepare bash -c 'set -euo pipefail; \ source_ip_dir="$(UVHS_GBUS_IP_DIR)"; generator="$(UVHS_GBUS_GENERATOR)"; \ @@ -197,10 +233,8 @@ uvhs_export_generalbus: uvhs_prepare ip_dir="$$gen_dir/ip-src"; \ cp -a "$$source_ip_dir" "$$ip_dir"; \ gen_script="$$ip_dir/gen_generalbus_ip.py"; \ - sed -i "s|#!/bin/tcsh|#!/usr/bin/env bash|" "$$gen_script"; \ sed -i "/os[.]popen.*f_dcp_in.*f_dcp_out/c\\ shutil.copy2(f_dcp_in, f_dcp_out)" \ "$$gen_script"; \ - grep -Fq "#!/usr/bin/env bash" "$$gen_script"; \ grep -Fq "shutil.copy2(f_dcp_in, f_dcp_out)" "$$gen_script"; \ json="$$gen_dir/uvw_axi3_generalbus.json"; \ cp -f "$(UVHS_GBUS_JSON)" "$$json"; \ @@ -225,6 +259,12 @@ uvhs_export_generalbus: uvhs_prepare "$(UVHS_WORK_DIR)/rtl/stubs/uvw_general_bus.v"; \ echo "INFO: prepared 64-bit UVHS generalBus DCP"' +uvhs_normalize_rtl_include: uvhs_prepare + mkdir -p "$(dir $(UVHS_RTL_INCLUDE_FILELIST))" + bash "$(UVHS_ROOT_DIR)/tools/update_core_flist.sh" "$(CORE_DIR)" \ + --external-only --output-filelist "$(UVHS_RTL_INCLUDE_FILELIST)" \ + -- $(RTL_INCLUDE) + uvhs_sync_uvw_axi4_to_ddr4: uvhs_prepare bash -c 'set -euo pipefail; \ src="$(UVHS_UVW_AXI4_TO_DDR4_SRC)"; work="$(UVHS_WORK_DIR)"; \ @@ -250,12 +290,11 @@ uvhs_sync_uvw_axi4_to_ddr4: uvhs_prepare echo "$(UVHS_UVW_AXI4_TO_DDR4_EXPECTED_MD5) $$work/rtl/soc/uvw_axi4_to_ddr4.dcp" | md5sum -c -; \ fi' -uvhs_filelist: uvhs_export_generalbus +uvhs_filelist: uvhs_export_generalbus uvhs_normalize_rtl_include \ + uvhs_prepare_core_rtl mkdir -p "$(dir $(UVHS_FILELIST))" { \ printf '+define+SYNTHESIS\n+define+XIANGSHAN_FPGA\n'; \ - printf '+define+RANDOMIZE_GARBAGE_ASSIGN\n+define+RANDOMIZE_REG_INIT\n'; \ - printf '+define+RANDOMIZE_MEM_INIT\n+define+RANDOMIZE_DELAY=1\n'; \ printf '+define+UVHS\n'; \ printf '+define+DDR4_16G_X8\n+define+DQ64\n+define+DDR4_2400\n'; \ printf '+define+DQ=64\n+define+MICRON_DDR\n+define+DDR4_16Gbx8\n'; \ @@ -263,7 +302,7 @@ uvhs_filelist: uvhs_export_generalbus if [ "$(CPU)" = nutshell ]; then printf '+define+CPU_NUTSHELL\n'; fi; \ if [ "$(CPU)" = kmh ]; then \ simtop=""; \ - for candidate in "$(CORE_DIR)/build/rtl/SimTop.sv" \ + for candidate in "$(UVHS_CORE_RTL_DIR)/SimTop.sv" \ "$(CORE_DIR)/rtl/SimTop.sv" "$(CORE_DIR)/SimTop.sv"; do \ if [ -f "$$candidate" ]; then simtop="$$candidate"; break; fi; \ done; \ @@ -272,11 +311,9 @@ uvhs_filelist: uvhs_export_generalbus printf '+define+CONFIG_SIMTOP_HAS_DMA\n'; \ fi; \ fi; \ - if [ -n "$(CHI_DIR)" ]; then printf '+define+MSI_MODE\n+define+CONFIG_USE_XSCORE_CHI\n'; \ - else printf '+define+CONFIG_USE_XSCORE_AXI\n'; fi; \ - if [ -d "$(CORE_DIR)/build" ]; then printf '+incdir+%s/build\n' "$(CORE_DIR)"; fi; \ - if [ -d "$(CORE_DIR)/build/rtl" ]; then printf '+incdir+%s/build/rtl\n' "$(CORE_DIR)"; fi; \ - if [ -d "$(CORE_DIR)/build/generated-src" ]; then printf '+incdir+%s/build/generated-src\n' "$(CORE_DIR)"; fi; \ + if [ -d "$(UVHS_CORE_BUILD_DIR)" ]; then printf '+incdir+%s\n' "$(UVHS_CORE_BUILD_DIR)"; fi; \ + if [ -d "$(UVHS_CORE_RTL_DIR)" ]; then printf '+incdir+%s\n' "$(UVHS_CORE_RTL_DIR)"; fi; \ + if [ -d "$(UVHS_CORE_GENERATED_SRC_DIR)" ]; then printf '+incdir+%s\n' "$(UVHS_CORE_GENERATED_SRC_DIR)"; fi; \ printf '+incdir+%s/src/rtl/common\n' "$(UVHS_ROOT_DIR)"; \ find "$(UVHS_ROOT_DIR)/src/rtl/common" -type f \ \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ @@ -286,22 +323,17 @@ uvhs_filelist: uvhs_export_generalbus test ! -d "$(UVHS_ROOT_DIR)/src/rtl/$(CPU)" || \ find "$(UVHS_ROOT_DIR)/src/rtl/$(CPU)" -type f \ \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ - if [ -d "$(CORE_DIR)/build/rtl" ]; then \ - find "$(CORE_DIR)/build/rtl" -type f \ + if [ -d "$(UVHS_CORE_RTL_DIR)" ]; then \ + find "$(UVHS_CORE_RTL_DIR)" -type f \ \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ elif [ -n "$(CORE_DIR)" ] && [ -d "$(CORE_DIR)" ]; then \ find "$(CORE_DIR)" \( -path '*/rtl/verification' -o -path '*/out' \) -prune -o \ -type f \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ fi; \ - test ! -f "$(CORE_DIR)/difftest/src/test/vsrc/common/DifftestClockGate.v" || \ + if [ "$(CPU)" != kmh ]; then test ! -f "$(CORE_DIR)/difftest/src/test/vsrc/common/DifftestClockGate.v" || \ printf '%s\n' "$(CORE_DIR)/difftest/src/test/vsrc/common/DifftestClockGate.v"; \ - if [ -n "$(CHI_DIR)" ] && [ -d "$(CHI_DIR)" ]; then \ - find "$(CHI_DIR)" -type f \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ fi; \ - for item in $(RTL_INCLUDE); do \ - if [ -d "$$item" ]; then find "$$item" -type f \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ - elif [ -f "$$item" ]; then case "$$item" in *.f|*.flist|*.list) cat "$$item";; *) printf '%s\n' "$$item";; esac; fi; \ - done; \ + test ! -f "$(UVHS_RTL_INCLUDE_FILELIST)" || cat "$(UVHS_RTL_INCLUDE_FILELIST)"; \ } | awk 'NF' > "$(UVHS_FILELIST)" uvhs_check_modules: uvhs_filelist @@ -311,24 +343,25 @@ uvhs_frontend: uvhs_export_vivado_ip uvhs_export_generalbus \ uvhs_sync_uvw_axi4_to_ddr4 uvhs_check_modules bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ $(UVHS_FLOW_ENV) UVHS_TOP="$(UVHS_TOP)" UVHS_FILELIST=./rtl/filelist.f \ - UVHS_REQUIRED_DCP_MODULES="$(UVHS_REQUIRED_DCP_MODULES)" \ - UVHS_DDR_RTL_INST="$(UVHS_DDR_RTL_INST)" UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP=1 \ + UVHS_DDR_RTL_INST="$(UVHS_DDR_RTL_INST)" \ UVHS_ASSIGN_PIN_FILE="$(UVHS_ASSIGN_PIN_FILE)" UVHS_TIMING_FILE="$(UVHS_TIMING_FILE)" \ - UVHS_PARTITION_FILE=none UVHS_PROBE_FILE=none UVHS_ASSEMBLE_FILE="$(UVHS_ASSEMBLE_FILE)" \ + UVHS_ASSEMBLE_FILE="$(UVHS_ASSEMBLE_FILE)" \ UVHS_USE_LSF="$(UVHS_USE_LSF)" \ UVHS_FRONTEND_THREADS="$(UVHS_FRONTEND_THREADS)" UVHS_FRONTEND_PROCESSES="$(UVHS_FRONTEND_PROCESSES)" \ UVHS_FPGA_THREADS="$(UVHS_FPGA_THREADS)" UVHS_FPGA_PROCESSES="$(UVHS_FPGA_PROCESSES)" \ bash "$$UV_ROOT/bin/uv_shell" -bypass_vivado_version_check \ - -s "$(UVHS_ROOT_DIR)/uvhs/frontend_run.tcl" |& tee frontend_run.log' + -s "$(UVHS_ROOT_DIR)/uvhs/frontend_run.tcl" |& tee frontend_run.log; \ + grep -Fxq UVHS_FRONTEND_SUCCESS frontend_run.log' uvhs_backend: bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ - $(UVHS_FLOW_ENV) UVHS_TOP="$(UVHS_TOP)" UVHS_UVW_AXI4_TO_DDR4_USE_SET_IP=1 \ + $(UVHS_FLOW_ENV) UVHS_TOP="$(UVHS_TOP)" \ UVHS_ASSIGN_PIN_FILE="$(UVHS_ASSIGN_PIN_FILE)" UVHS_ASSEMBLE_FILE="$(UVHS_ASSEMBLE_FILE)" \ UVHS_USE_LSF="$(UVHS_USE_LSF)" \ UVHS_FPGA_THREADS="$(UVHS_FPGA_THREADS)" UVHS_FPGA_PROCESSES="$(UVHS_FPGA_PROCESSES)" \ bash "$$UV_ROOT/bin/uv_shell" -bypass_vivado_version_check \ - -s "$(UVHS_ROOT_DIR)/uvhs/backend_run.tcl" |& tee backend_run.log' + -s "$(UVHS_ROOT_DIR)/uvhs/backend_run.tcl" |& tee backend_run.log; \ + grep -Fxq UVHS_BACKEND_SUCCESS backend_run.log' uvhs_all: uvhs_frontend uvhs_backend diff --git a/fpga_diff/uvhs/vivado_pre_opt.tcl b/fpga_diff/uvhs/vivado_pre_opt.tcl new file mode 100644 index 00000000..c092753e --- /dev/null +++ b/fpga_diff/uvhs/vivado_pre_opt.tcl @@ -0,0 +1,89 @@ +################################################################################ +# Vivado constraints that must be applied after the UVHS netlist is linked. +################################################################################ + +set fpga_diff_refclk_ports {} +foreach pattern { + pcie_ep_gt_ref_clk_p_pad_net_* + pcie_ep_gt_ref_clk_n_pad_net_* + pcie_ep_gt_ref_clk_p + pcie_ep_gt_ref_clk_n +} { + foreach port [get_ports -quiet $pattern] { + if {[lsearch -exact $fpga_diff_refclk_ports $port] < 0} { + lappend fpga_diff_refclk_ports $port + } + } +} +if {[llength $fpga_diff_refclk_ports]} { + # The imported XDMA IP owns the IBUFDS_GTE4. Prevent Vivado from inserting + # a fabric input/clock buffer in front of that primitive. + set_property IO_BUFFER_TYPE NONE $fpga_diff_refclk_ports + set_property CLOCK_BUFFER_TYPE NONE $fpga_diff_refclk_ports + puts "INFO: kept XDMA GT refclk pads unbuffered: $fpga_diff_refclk_ports" +} + +proc fpga_diff_mark_async_regs {label patterns} { + set cells {} + foreach pattern $patterns { + foreach cell [get_cells -hier -quiet \ + -filter "IS_SEQUENTIAL && NAME =~ $pattern"] { + if {[lsearch -exact $cells $cell] < 0} { + lappend cells $cell + } + } + } + if {[llength $cells]} { + set_property ASYNC_REG TRUE $cells + } + puts "INFO: XDMA CDC $label ASYNC_REG count=[llength $cells]" + return $cells +} + +set fpga_diff_xdma_cdc_cells {} +foreach {label patterns} { + axi_clock_converter { + */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/inst/gen_clock_conv.gen_async_lite_conv*/clock_conv_lite_*/*_reg* + */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/inst/gen_clock_conv.gen_async_lite_conv*/clock_conv_lite_*/handshake/*_reg* + */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*clock_conv_lite*/*_reg* + */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*handshake*/*_reg* + */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*cdc*/*_reg* + */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*sync*/*_reg* + } + axi_xpm_cdc { + */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/inst/*xpm_cdc*/*_reg* + */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/inst/*xpm_cdc*/inst/*_reg* + */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*xpm_cdc*/*_reg* + */core_def/xdma_ep_i/axi_interconnect_0/*/auto_cc/*xpm_cdc*/inst/*_reg* + } + xdma_reset_and_link { + */core_def/xdma_ep_i/xdma_0/inst/*/*cdc*/*_reg* + */core_def/xdma_ep_i/xdma_0/inst/*/*cdc*/inst/*_reg* + */core_def/xdma_ep_i/xdma_0/inst/*/xpm_cdc*/*_reg* + */core_def/xdma_ep_i/xdma_0/inst/*/xpm_cdc*/inst/*_reg* + */core_def/xdma_ep_i/xdma_0/inst/*/arststages_ff_reg* + */core_def/xdma_ep_i/xdma_0/inst/*/*user_rst*_reg* + */core_def/xdma_ep_i/xdma_0/inst/udma_wrapper/dma_top/user_rst*_reg* + */core_def/xdma_ep_i/xdma_0/inst/udma_wrapper/dma_top/*user_rst*_reg* + */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*cdc*/*_reg* + */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*cdc*/inst/*_reg* + */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*sync*/*_reg* + */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*sync*/inst/*_reg* + */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*rst*sync*reg* + */core_def/xdma_ep_i/xdma_0/inst/pcie4c_ip_i/inst/*/*reset*sync*reg* + } +} { + foreach cell [fpga_diff_mark_async_regs $label $patterns] { + if {[lsearch -exact $fpga_diff_xdma_cdc_cells $cell] < 0} { + lappend fpga_diff_xdma_cdc_cells $cell + } + } +} +puts "INFO: XDMA CDC total ASYNC_REG count=[llength $fpga_diff_xdma_cdc_cells]" + +if {![info exists ::env(UVHS_ASYNC_CLOCK_FILE)] || + $::env(UVHS_ASYNC_CLOCK_FILE) eq "" || + ![file exists $::env(UVHS_ASYNC_CLOCK_FILE)]} { + error "UVHS_ASYNC_CLOCK_FILE is missing in Vivado pre-opt" +} +source $::env(UVHS_ASYNC_CLOCK_FILE) From eb8972beeef07bee92279883c9f5168087d794ea Mon Sep 17 00:00:00 2001 From: klin02 Date: Sun, 2 Aug 2026 19:26:51 +0800 Subject: [PATCH 10/62] refactor(fpga_diff): streamline UVHS flow inputs Use the FPGA release build as the sole core input and collapse external file-list generation to one output mode. Drop unused IP exports, RANDOMIZE defines, and path-forwarding knobs. Replace make/csh wrappers with inherited Bash Make flags, keep only observed shell and runtime compatibility, and document the reduced flow. Co-authored-by: Kamimiao --- fpga_diff/src/tcl/common/defines.tcl | 4 - fpga_diff/tools/update_core_flist.sh | 14 +- fpga_diff/uvhs/README.md | 171 +++++++++----------- fpga_diff/uvhs/assemble_uvhs.tcl | 4 +- fpga_diff/uvhs/assign_pin_u22_f2.tcl | 2 +- fpga_diff/uvhs/async_clocks.tcl | 3 +- fpga_diff/uvhs/backend_run.tcl | 30 ++-- fpga_diff/uvhs/check_flow_tools.sh | 4 - fpga_diff/uvhs/export_vivado_ip.tcl | 38 +---- fpga_diff/uvhs/frontend_run.tcl | 63 ++------ fpga_diff/uvhs/hw_run_download.tcl | 7 +- fpga_diff/uvhs/make_compat/csh | 9 -- fpga_diff/uvhs/make_compat/make | 2 - fpga_diff/uvhs/timing_common.tcl | 3 - fpga_diff/uvhs/uvhs.mk | 228 ++++++++------------------- fpga_diff/uvhs/vivado_pre_opt.tcl | 7 +- 16 files changed, 180 insertions(+), 409 deletions(-) delete mode 100755 fpga_diff/uvhs/make_compat/csh delete mode 100755 fpga_diff/uvhs/make_compat/make diff --git a/fpga_diff/src/tcl/common/defines.tcl b/fpga_diff/src/tcl/common/defines.tcl index a2ee1721..5e3a1a6b 100755 --- a/fpga_diff/src/tcl/common/defines.tcl +++ b/fpga_diff/src/tcl/common/defines.tcl @@ -1,9 +1,5 @@ set defines [list \ XIANGSHAN_FPGA \ - RANDOMIZE_GARBAGE_ASSIGN \ - RANDOMIZE_REG_INIT \ - RANDOMIZE_MEM_INIT \ - RANDOMIZE_DELAY=1 \ DDR4_16G_X8 \ DQ64 \ DDR4_2400 \ diff --git a/fpga_diff/tools/update_core_flist.sh b/fpga_diff/tools/update_core_flist.sh index 4166d048..b0d4bc63 100755 --- a/fpga_diff/tools/update_core_flist.sh +++ b/fpga_diff/tools/update_core_flist.sh @@ -8,7 +8,7 @@ fail() { } usage() { - echo "Usage: $0 CORE_DIR [--external-only] [--output-filelist FILE] [--] [RTL_INCLUDE ...]" >&2 + echo "Usage: $0 CORE_DIR [--output-filelist FILE] [--] [RTL_INCLUDE ...]" >&2 exit 2 } @@ -21,14 +21,9 @@ fpga_diff_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd) awk_script="$fpga_diff_dir/core_flist.awk" output_tcl="$fpga_diff_dir/src/tcl/cpu_files.tcl" output_filelist="" -external_only=0 while (($#)); do case $1 in - --external-only) - external_only=1 - shift - ;; --output-filelist) [[ $# -ge 2 ]] || usage output_filelist=$2 @@ -45,9 +40,6 @@ while (($#)); do done [[ -d $core_dir ]] || fail "CORE_DIR is not a directory: $core_dir" -if [[ $external_only == 1 && -z $output_filelist ]]; then - fail "--external-only requires --output-filelist" -fi tmp_dir=$(mktemp -d) trap 'rm -rf "$tmp_dir"' EXIT @@ -202,7 +194,7 @@ for rtl_include in "$@"; do fi done -if [[ $external_only == 0 ]]; then +if [[ -z $output_filelist ]]; then core_dir=$(realpath -e -- "$core_dir") find "$core_dir" -path "$core_dir/rtl/verification" -prune -o \ -type f \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ @@ -241,7 +233,7 @@ if [[ -n $output_filelist ]]; then mv -- "$tmp_output" "$output_filelist" fi -if [[ $external_only == 0 ]]; then +if [[ -z $output_filelist ]]; then echo "INFO: generated $output_tcl with ${#rtl_files[@]} external RTL files" fi if [[ -n $output_filelist ]]; then diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index d1815734..80ad22b0 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -1,78 +1,57 @@ # UVHS FPGA-Diff Flow -This directory contains the UVHS build and runtime flow for FPGA-Diff on the -U2.2 B0/F2 target. UVHS targets use the `uvhs_*` prefix; the existing Vivado, -PCIe, and JTAG targets keep their original behavior. +This directory contains the UVHS build and runtime flow for FPGA-Diff. UVHS +commands use the `uvhs_*` prefix and do not replace the existing Vivado, PCIe, +or JTAG commands. -## Environment +## RTL Input -Configure the runtime host shell directly, for example in `.bashrc`: +Generate an FPGA release before entering `env-scripts`. `CORE_DIR` is the +release `build` directory, not the design source checkout: -```sh -export UV_ROOT=/home/data/UVHS/2506p4_0210 -export UV_XILINX_VIVADO=/home/data/test/tools/vivado_2024/Vivado/2024.2 -export XILINX_HLS= -export UV_LICENSE=8273@localhost -export UVHS_TEMPLATE_DIR=/path/to/uvhs-template -export UVHS_UVW_AXI4_TO_DDR4_SRC=/path/to/uvw_axi4_to_ddr4 +```text +design RTL -> difftest fpga-release -> /build -> env-scripts ``` -`UVHS_TEMPLATE_DIR` provides the U2.2 board assembly files. The flow regenerates -the repository-owned Vivado IP and imports the vendor DDR DCP selected by -`UVHS_UVW_AXI4_TO_DDR4_SRC`. That DCP must expose a 64-bit AXI interface for -`CPU=nutshell` and a 256-bit interface for other designs; the stub is checked -before frontend starts. +The release step owns FPGA clock-gate replacement and generated RAM-style +conversion. The UVHS flow only consumes that result. -Some shared UVHS installations need a local `libpcre.so.1`. Set -`UVHS_COMPAT_PCRE_LIB` to a compatible library when preflight reports that -dependency. The flow stages the library in its work directory and does not -modify the shared installation. +`RTL_INCLUDE` accepts RTL files, directories, and nested `.f`, `.flist`, or +`.list` files. Relative entries are resolved from the file list that contains +them. The common `tools/update_core_flist.sh` parser writes an absolute flat +file list for UVHS while the normal Vivado flow continues to generate +`cpu_files.tcl`. ## Build ```sh make uvhs_tools_check -make uvhs_preflight CPU= -make uvhs_frontend CPU= CORE_DIR=/path/to/core SUFFIX= +make uvhs_frontend CPU= CORE_DIR=/path/to/release/build \ + RTL_INCLUDE=/path/to/extra.f SUFFIX= make uvhs_backend CPU= SUFFIX= make uvhs_package_bitstream CPU= SUFFIX= ``` -`uvhs_frontend` creates `hw.dat`, applies board and timing constraints, imports -the fixed IP DCPs, elaborates the RTL, and runs UVHS synthesis. It also records -the DDR instance used by runtime `writemem`. - -`uvhs_backend` reads that database and runs clock inference, remap, partition, -localization, system routing, FPGA placement/routing, timing signoff, and -bitstream generation. Its implementation sequence follows the vendor reference -flow. The only custom Vivado stage is `vivado_pre_opt.tcl`, which preserves the -XDMA GT reference-clock input and marks the known XDMA synchronizer registers. - -`uvhs_all` runs both stages. `UVHS_EXPORT_IP_FORCE=1` regenerates Vivado and -generalBus DCPs even when the selected work directory already contains them. -`uvhs_clean` removes only the selected `UVHS_WORK_DIR` and refuses to run while -its runtime session is active. +`RTL_INCLUDE` is optional. `uvhs_all` runs frontend and backend in sequence. -### XiangShan And External RTL +`uvhs_frontend` performs these steps: -For `CPU=kmh`, `uvhs_prepare_core_rtl` runs the upstream `difftest` -`fpga-release` target and synthesizes the extracted release instead of the raw -`build/rtl`. This keeps the normal FPGA clock-gate replacement, -`DifftestClockGate.v`, and generated RAM-style conversion. +1. Copies the vendor board template into an isolated work directory. +2. Prepares repository-owned Vivado IP and the 64-bit generalBus DCP. +3. Imports the selected DDR DCP and validates its AXI width. +4. Builds the complete RTL file list and checks the expected design module. +5. Elaborates and synthesizes the design with uvsyn. +6. Registers the DDR instance used by runtime `writemem`. -`RTL_INCLUDE` accepts RTL files, directories, and nested `.f`, `.flist`, or -`.list` files. `tools/update_core_flist.sh` resolves every relative entry -against its containing file list before writing the UVHS input list. For -example: - -```sh -make uvhs_all CPU=kmh CORE_DIR=/path/to/XiangShan \ - RTL_INCLUDE=/path/to/external_llc.f SUFFIX= -``` +`uvhs_backend` follows the vendor implementation sequence: clock inference and +transformation, remap, partition, localization, system routing, FPGA PnR, +timing signoff, bitstream generation, and runtime database commit. -The default XiangShan partition limits are 80% LUT and 30% LUT6. They remain -overridable through `UVHS_LUT_FILL_RATE` and `UVHS_LUT6_FILL_RATE`; changing -them is a placement experiment, not a functional requirement. +The default XiangShan partition limits are 80% LUT and 30% LUT6. They can be +changed with `UVHS_LUT_FILL_RATE` and `UVHS_LUT6_FILL_RATE` for placement +experiments. `UVHS_EXPORT_IP_FORCE=1` regenerates cached Vivado and generalBus +IP. `uvhs_clean` removes only the selected work directory and refuses to run +while its runtime session is active. ## Runtime @@ -86,59 +65,55 @@ make uvhs_reset_cpu CPU= SUFFIX= make uvhs_runtime_stop CPU= SUFFIX= ``` -`uvhs_write_bitstream` loads the completed database, configures the connector -and clocks, holds the three named resets across `download`, initializes the -hardware, and releases the resets in system/DDR/CPU order. It then detaches the -session because later UVHS memory operations must use the process that owns the -downloaded database. Runtime PID, readiness, commands, and logs are under -`runtime-work`. +`uvhs_write_bitstream` downloads the completed runtime database, initializes +the hardware, and keeps a detached UVHS session alive. Later reset and memory +commands must use that same session. Its PID, command files, and log are stored +under `runtime-work` in the selected build directory. -`uvhs_write_ddr` converts the address/data-pair format used by the Vivado DDR -loader to the selected 64-bit or 256-bit DCP word width, then calls UVHS -`writemem -rtl`. It leaves the CPU halted; call `uvhs_reset_cpu` after loading. +`uvhs_write_ddr` converts the Vivado address/data-pair format to the DDR DCP +word width and calls `writemem -rtl`. It leaves the CPU halted until +`uvhs_reset_cpu` is issued. -`uvhs_write_flash` uses the 64-bit UVHS generalBus master and the existing -32-bit `AXI_bridge` flash path. GeneralBus sees the flash at offset `0x0`; the -CPU and the normal JTAG path retain their `0x10000000` mapping. The command pads -the binary to an 8-byte transfer, writes at offset zero, and requires a complete -readback match before releasing the CPU. The maximum image is 32 KiB. +`uvhs_write_flash` writes through the 64-bit generalBus and the existing +32-bit AXI flash bridge. The generalBus view starts at offset zero; the CPU and +normal JTAG address map are unchanged. A complete readback match is required +before the command succeeds. ## Compatibility Boundary -Only compatibility workarounds observed as necessary on the validated UVHS -installation remain: +The retained compatibility code is limited to observed tool behavior: -- `make_compat/` supplies Bash-backed `make` and the limited `csh -fc limit` - query emitted by UVHS. The host does not provide `csh` or `tcsh`. -- `shell_compat.sh` selects Bash in generated synthesis and PnR launchers. Those - launchers use Bash syntax but are generated with `/bin/sh` invocation paths. -- `uv_shell_exec_compat.sh` restores staged runtime libraries after the vendor - launcher sanitizes `LD_LIBRARY_PATH`. -- The private generalBus generator copy replaces its asynchronous DCP copy with - `shutil.copy2`; otherwise it can delete the project before the copy finishes. +- `shell_compat.sh` selects Bash in generated synthesis and PnR launchers that + contain Bash syntax. +- `uv_shell_exec_compat.sh` restores runtime libraries after the vendor launcher + sanitizes `LD_LIBRARY_PATH`. +- The generalBus export uses a private generator copy and makes its DCP copy + synchronous so the project is not removed before the copy finishes. +- `vivado_pre_opt.tcl` preserves the XDMA GT reference clock and marks the + validated XDMA CDC registers. -No generated clock, timing XDC, VIO/ILA, DDR pin, or hierarchy-version text -patching remains in the backend flow. +The flow does not patch generated timing XDC, hierarchy names, VIO/ILA logic, +or DDR pins. ## Files | File | Role | | --- | --- | -| `uvhs.mk` | UVHS targets, inputs, stage invocation, packaging, and runtime commands. | -| `frontend_run.tcl` | Builds the synthesized UVHS database from RTL and imported DCPs. | -| `backend_run.tcl` | Runs the standard partition, localization, PnR, and commit sequence. | -| `vivado_pre_opt.tcl` | Applies the two required XDMA physical/CDC constraints. | -| `assemble_uvhs.tcl` | Reduces the vendor four-FPGA assembly to the selected FPGA set. | -| `assign_pin_u22_f2.tcl` | Assigns B0/F2 clocks, PCIe, UART, JTAG, SD, and low-speed pins. | -| `timing_common.tcl` | Declares the external clocks consumed by frontend. | -| `async_clocks.tcl` | Declares asynchronous relationships after clocks are available. | -| `export_vivado_ip.tcl` | Regenerates repository-owned XCI and block-design DCPs. | -| `check_modules.sh` | Confirms required RTL modules exist in the final file list. | -| `check_flow_tools.sh` | Performs source, shell, Tcl, and local-path checks. | -| `shell_compat.sh`, `make_compat/` | Contain the generated-launcher Bash compatibility. | -| `uv_shell_exec_compat.sh` | Supplies the staged runtime library path to `uv_shell_exec`. | -| `hw_run_download.tcl` | Downloads the database and starts its runtime command service. | -| `runtime_control.tcl` | Defines reset sequencing and command polling. | -| `runtime_command.tcl` | Implements reset, DDR, and flash operations. | -| `runtime_session.sh` | Starts, checks, waits for, and stops the detached session. | -| `enqueue_runtime_command.sh` | Submits one command and returns its completion status. | +| `uvhs.mk` | Build, packaging, and runtime targets. | +| `frontend_run.tcl` | RTL/IP import, elaboration, and uvsyn frontend. | +| `backend_run.tcl` | Partition, routing, FPGA PnR, and runtime database commit. | +| `assemble_uvhs.tcl` | Selects the FPGA set from the vendor board assembly. | +| `assign_pin_u22_f2.tcl` | B0/F2 clock, PCIe, UART, JTAG, SD, and control pins. | +| `timing_common.tcl` | External clock constraints. | +| `async_clocks.tcl` | Asynchronous clock groups used by backend and Vivado PnR. | +| `vivado_pre_opt.tcl` | XDMA refclock and CDC constraints. | +| `export_vivado_ip.tcl` | Repository-owned Vivado IP export. | +| `check_modules.sh` | Final RTL module check. | +| `check_flow_tools.sh` | Shell/Tcl/source validation. | +| `shell_compat.sh` | Generated launcher shell correction. | +| `uv_shell_exec_compat.sh` | Runtime library wrapper. | +| `hw_run_download.tcl` | Download and command-service entry point. | +| `runtime_control.tcl` | Reset sequencing and command polling. | +| `runtime_command.tcl` | Reset, DDR, and flash operations. | +| `runtime_session.sh` | Detached runtime session lifecycle. | +| `enqueue_runtime_command.sh` | Runtime command submission and status. | diff --git a/fpga_diff/uvhs/assemble_uvhs.tcl b/fpga_diff/uvhs/assemble_uvhs.tcl index a3925be8..f074ebbc 100644 --- a/fpga_diff/uvhs/assemble_uvhs.tcl +++ b/fpga_diff/uvhs/assemble_uvhs.tcl @@ -10,7 +10,9 @@ proc uvhs_env_or_default {name default} { } set uvhs_base_assemble ./script/1B_4F_HGC_assemble.tcl -set uvhs_target_fpga [string tolower [uvhs_env_or_default UVHS_TARGET_FPGA_LOWER b0.f2]] +set uvhs_target_pack [uvhs_env_or_default UVHS_TARGET_PACK B0] +set uvhs_target_name [uvhs_env_or_default UVHS_TARGET_FPGA F2] +set uvhs_target_fpga [string tolower "$uvhs_target_pack.$uvhs_target_name"] set uvhs_known_fpgas {b0.f0 b0.f1 b0.f2 b0.f3} set uvhs_keep_fpgas {} foreach uvhs_fpga [split [uvhs_env_or_default UVHS_KEEP_FPGAS $uvhs_target_fpga]] { diff --git a/fpga_diff/uvhs/assign_pin_u22_f2.tcl b/fpga_diff/uvhs/assign_pin_u22_f2.tcl index 2d0a6fe7..49c5f152 100644 --- a/fpga_diff/uvhs/assign_pin_u22_f2.tcl +++ b/fpga_diff/uvhs/assign_pin_u22_f2.tcl @@ -12,7 +12,7 @@ proc pin_name {top port} { return "${top}.${port}" } -set top [env_or_default UVHS_ASSIGN_PIN_TOP [env_or_default UVHS_TOP fpga_top_debug]] +set top [env_or_default UVHS_ASSIGN_PIN_TOP fpga_top_debug] set xdma_link_width [string toupper [string trim [env_or_default XDMA_LINK_WIDTH X4]]] if {$xdma_link_width ni {X4 X8}} { error "XDMA_LINK_WIDTH must be one of X4/X8, got '$xdma_link_width'" diff --git a/fpga_diff/uvhs/async_clocks.tcl b/fpga_diff/uvhs/async_clocks.tcl index 8bbce9f7..ff0fc1b1 100644 --- a/fpga_diff/uvhs/async_clocks.tcl +++ b/fpga_diff/uvhs/async_clocks.tcl @@ -1,7 +1,8 @@ ################################################################################ # UVHS asynchronous clock constraints. # -# backend_run.tcl loads this after top-level and generated clocks are available. +# backend_run.tcl and the Vivado pre-opt stage load this after generated clocks +# are available. ################################################################################ set fpga_diff_async_groups [list] diff --git a/fpga_diff/uvhs/backend_run.tcl b/fpga_diff/uvhs/backend_run.tcl index c1256ff8..ee0fe42c 100644 --- a/fpga_diff/uvhs/backend_run.tcl +++ b/fpga_diff/uvhs/backend_run.tcl @@ -38,19 +38,13 @@ proc configure_fill_rates {} { } } +set uvhs_script_dir [file dirname [file normalize [info script]]] set_working_space hw.dat set fpga_threads [env_or_default UVHS_FPGA_THREADS 8] set fpga_processes [env_or_default UVHS_FPGA_PROCESSES 16] -if {[env_or_default UVHS_USE_LSF 0]} { - set_parallel_option -max_threads $fpga_threads \ - -max_processes $fpga_processes \ - -submit_command {bsub -R "rusage[mem=80000]"} \ - -terminate_command bkill -label fpga -} else { - set_parallel_option -max_threads $fpga_threads \ - -max_processes $fpga_processes -label fpga -} +set_parallel_option -max_threads $fpga_threads \ + -max_processes $fpga_processes -label fpga set_option time.auto_clock_config true set_option clock.transform_clock.multi_iteration true @@ -59,14 +53,12 @@ set_option clock.async_control.force_accept true set_option time.enable_sign_off true set_option time.incremental_sign_off true -set design_name [env_or_default UVHS_DESIGN_NAME VU19P_X4] set platform [env_or_default PLATFORM U2.2] -create_system_design -name $design_name -platform $platform -source_required [env_or_default UVHS_ASSEMBLE_FILE ./script/1B_4F_HGC_assemble.tcl] +create_system_design -name VU19P_X4 -platform $platform +source_required [file join $uvhs_script_dir assemble_uvhs.tcl] -set assign_pin_file [env_or_default UVHS_ASSIGN_PIN_FILE ./script/assign_pin.tcl] set ::env(UVHS_ASSIGN_PIN_TOP) none -source_required $assign_pin_file +source_required [file join $uvhs_script_dir assign_pin_u22_f2.tcl] unset ::env(UVHS_ASSIGN_PIN_TOP) create_design -name test @@ -84,7 +76,7 @@ sweep_design infer_clock report_clock -inferred transform_clock -source_required [env_or_default UVHS_ASYNC_CLOCK_FILE ./script/fpga_diff_async_clocks.tcl] +source_required [file join $uvhs_script_dir async_clocks.tcl] configure_fill_rates trigger_probe -group sweep_design -remap @@ -117,14 +109,10 @@ set_option compile.strategyNum 1 set_option compile.strategy0 \ [env_or_default UVHS_COMPILE_STRATEGY uv_high_fanout_explore] set_option compile.stage.preOpt \ - [env_or_default UVHS_VIVADO_PRE_OPT_FILE ./script/vivado_pre_opt.tcl] + [file join $uvhs_script_dir vivado_pre_opt.tcl] compile_fpga -parallel_option fpga -genScriptOnly -explore -set shell_helper [env_or_default UVHS_SHELL_COMPAT_SCRIPT ""] -if {$shell_helper eq ""} { - error "UVHS_SHELL_COMPAT_SCRIPT is not set" -} -set shell_helper [file normalize $shell_helper] +set shell_helper [file join $uvhs_script_dir shell_compat.sh] if {![file isfile $shell_helper]} { error "UVHS shell compatibility helper not found: $shell_helper" } diff --git a/fpga_diff/uvhs/check_flow_tools.sh b/fpga_diff/uvhs/check_flow_tools.sh index 45af496c..48acea16 100644 --- a/fpga_diff/uvhs/check_flow_tools.sh +++ b/fpga_diff/uvhs/check_flow_tools.sh @@ -17,8 +17,6 @@ required=( uvhs/vivado_pre_opt.tcl uvhs/export_vivado_ip.tcl uvhs/check_modules.sh - uvhs/make_compat/make - uvhs/make_compat/csh uvhs/shell_compat.sh uvhs/enqueue_runtime_command.sh uvhs/runtime_session.sh @@ -39,8 +37,6 @@ done bash -n "$root_dir/uvhs/check_modules.sh" bash -n "$root_dir/uvhs/check_flow_tools.sh" -bash -n "$root_dir/uvhs/make_compat/make" -bash -n "$root_dir/uvhs/make_compat/csh" bash -n "$root_dir/uvhs/shell_compat.sh" bash -n "$root_dir/uvhs/enqueue_runtime_command.sh" bash -n "$root_dir/uvhs/runtime_session.sh" diff --git a/fpga_diff/uvhs/export_vivado_ip.tcl b/fpga_diff/uvhs/export_vivado_ip.tcl index 6e09ccd7..3ff8174e 100644 --- a/fpga_diff/uvhs/export_vivado_ip.tcl +++ b/fpga_diff/uvhs/export_vivado_ip.tcl @@ -7,15 +7,12 @@ set out_dir "./uvhs_ip" set vivado_version "" set force 0 set jobs 8 -set cpu "kmh" set core_dir "" -set only "" -set skip_exports [list] proc print_help {} { puts "Usage:" puts " vivado -mode batch -source uvhs/export_vivado_ip.tcl -tclargs \\" - puts " --origin_dir --out_dir \[--vivado_version \] \[--cpu \] \[--core_dir \] \[--only \] \[--skip \] \[--force\] \[--jobs N\]" + puts " --origin_dir --out_dir \[--vivado_version \] \[--core_dir \] \[--force\] \[--jobs N\]" exit 0 } @@ -25,10 +22,7 @@ for {set i 0} {$i < $::argc} {incr i} { "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } "--out_dir" { incr i; set out_dir [lindex $::argv $i] } "--vivado_version" { incr i; set vivado_version [lindex $::argv $i] } - "--cpu" { incr i; set cpu [lindex $::argv $i] } "--core_dir" { incr i; set core_dir [lindex $::argv $i] } - "--only" { incr i; set only [lindex $::argv $i] } - "--skip" { incr i; lappend skip_exports [lindex $::argv $i] } "--force" { set force 1 } "--jobs" { incr i; set jobs [lindex $::argv $i] } "--help" { print_help } @@ -52,7 +46,6 @@ if {$vivado_version eq ""} { set vivado_version [version -short] } set ::vivado_version $vivado_version -set ::cpu $cpu set ::core_dir $core_dir if {$force && [file exists $export_project_dir]} { @@ -78,9 +71,7 @@ proc add_core_generated_headers {core_dir} { } set header_candidates [list \ - [file join $core_dir build generated-src DifftestMacros.svh] \ [file join $core_dir generated-src DifftestMacros.svh] \ - [file join $core_dir build rtl DifftestMacros.svh] \ [file join $core_dir rtl DifftestMacros.svh] \ ] foreach hdr $header_candidates { @@ -105,17 +96,10 @@ add_core_generated_headers $core_dir proc source_ip_tcl {script} { if {![file exists $script]} { - puts "WARNING: missing IP script $script" - return 0 + error "missing IP script $script" } puts "INFO: source $script" - set rc [catch {uplevel #0 [list source $script]} err opts] - if {$rc != 0} { - puts "ERROR: failed to source $script" - puts $err - return -options $opts $err - } - return 1 + uplevel #0 [list source $script] } proc run_and_copy_dcp {run_name out_file jobs force} { @@ -180,7 +164,7 @@ proc run_and_write_opened_dcp {run_name out_file jobs force} { puts "INFO: exported stitched checkpoint $out_file" } -proc copy_generated_stub {kind name out_file} { +proc copy_generated_stub {kind name} { global export_project_dir out_dir if {$kind eq "xci"} { @@ -304,7 +288,7 @@ proc export_xci_ip {name script out_file jobs force} { generate_target all $ip catch {create_ip_run $ip} run_and_copy_dcp ${name}_synth_1 $out_file $jobs $force - copy_generated_stub xci $name $out_file + copy_generated_stub xci $name verify_checkpoint "IP $name" $out_file } @@ -324,7 +308,7 @@ proc export_bd_ip {name script out_file jobs force} { save_bd_design generate_target all $bd catch {make_wrapper -files $bd -top} - copy_generated_stub bd $name $out_file + copy_generated_stub bd $name if {[file exists $out_file] && !$force} { puts "INFO: reuse existing $out_file" @@ -346,22 +330,12 @@ set exports [list \ [list xci blk_mem_gen_0 [file join $tcl_dir blk_mem_gen_0.tcl] [file join $out_dir rtl soc blk_mem_gen_0.dcp]] \ [list bd AXI_bridge [file join $tcl_dir AXI_bridge.tcl] [file join $out_dir rtl soc AXI_bridge.dcp]] \ [list bd data_bridge [file join $tcl_dir data_bridge.tcl] [file join $out_dir rtl soc data_bridge.dcp]] \ - [list xci vio_0 [file join $tcl_dir vio_0.tcl] [file join $out_dir rtl soc vio_0.dcp]] \ [list bd xdma_ep [file join $tcl_dir xdma_ep.tcl] [file join $out_dir rtl device pcie xdma_ep.dcp]] \ - [list bd jtag_ddr_subsys [file join $tcl_dir jtag_ddr_subsys.tcl] [file join $out_dir rtl soc jtag_ddr_subsys.dcp]] \ ] set failed_exports [list] foreach item $exports { lassign $item kind name script out_file - if {$only ne "" && $name ne $only} { - puts "INFO: skip $name because --only $only is set" - continue - } - if {[lsearch -exact $skip_exports $name] >= 0} { - puts "INFO: skip $name because --skip requested" - continue - } puts "INFO: exporting $kind $name" set rc [catch { if {$kind eq "xci"} { diff --git a/fpga_diff/uvhs/frontend_run.tcl b/fpga_diff/uvhs/frontend_run.tcl index 466eb59a..fe1fc8bd 100644 --- a/fpga_diff/uvhs/frontend_run.tcl +++ b/fpga_diff/uvhs/frontend_run.tcl @@ -9,16 +9,6 @@ proc env_or_default {name default} { return $default } -proc split_words {value} { - set words {} - foreach word $value { - if {$word ne ""} { - lappend words $word - } - } - return $words -} - proc source_required {file} { if {![file exists $file]} { error "required UVHS flow file not found: $file" @@ -85,11 +75,7 @@ proc register_runtime_memory {working_space inst_path} { } proc start_frontend_shell_compat {} { - set helper [env_or_default UVHS_SHELL_COMPAT_SCRIPT ""] - if {$helper eq ""} { - error "UVHS_SHELL_COMPAT_SCRIPT is not set" - } - set helper [file normalize $helper] + set helper [file join $::uvhs_script_dir shell_compat.sh] if {![file isfile $helper]} { error "UVHS shell compatibility helper not found: $helper" } @@ -98,32 +84,19 @@ proc start_frontend_shell_compat {} { puts "INFO: started UVHS frontend shell compatibility helper" } +set ::uvhs_script_dir [file dirname [file normalize [info script]]] create_working_space hw.dat set_option syn.computeFeCheckSum true set frontend_threads [env_or_default UVHS_FRONTEND_THREADS 16] set frontend_processes [env_or_default UVHS_FRONTEND_PROCESSES 64] -set fpga_threads [env_or_default UVHS_FPGA_THREADS 8] -set fpga_processes [env_or_default UVHS_FPGA_PROCESSES 32] -if {[env_or_default UVHS_USE_LSF 0]} { - set_parallel_option -max_threads $frontend_threads \ - -max_processes $frontend_processes -submit_command bsub \ - -terminate_command bkill -label frontend - set_parallel_option -max_threads $fpga_threads \ - -max_processes $fpga_processes \ - -submit_command {bsub -R "rusage[mem=80000]"} \ - -terminate_command bkill -label fpga -} else { - set_parallel_option -max_threads $frontend_threads \ - -max_processes $frontend_processes -label frontend - set_parallel_option -max_threads $fpga_threads \ - -max_processes $fpga_processes -label fpga -} +set_parallel_option -max_threads $frontend_threads \ + -max_processes $frontend_processes -label frontend set_option global.log.label MEMORY set_option syn.checkMultiDriver false set_option syn.multipleDriverConflict WOR -set_option syn.logicFillingRateThreshold 0.001 +set_option syn.engine uvsyn set_option time.auto_clock_config true set_option clock.transform_clock.multi_iteration true set_option clock.glitch.force_transform true @@ -132,23 +105,15 @@ set_option time.enable_sign_off true set_option time.incremental_sign_off true set_option signal.uhd.sampling_clock.allow_local_clock true -set design_name [env_or_default UVHS_DESIGN_NAME VU19P_X4] set platform [env_or_default PLATFORM U2.2] -set design_top [env_or_default UVHS_TOP fpga_top_debug] -set ddr_inst_path [env_or_default UVHS_DDR_RTL_INST \ - ${design_top}.core_def.U_UVHS_UVW_AXI4_TO_DDR4] -create_system_design -name $design_name -platform $platform - -source_required [env_or_default UVHS_ASSEMBLE_FILE ./script/1B_4F_HGC_assemble.tcl] -source_required [env_or_default UVHS_ASSIGN_PIN_FILE ./script/assign_pin.tcl] -set timing_file [env_or_default UVHS_TIMING_FILE ./script/timing.tcl] -if {![file exists $timing_file]} { - error "required UVHS timing constraints not found: $timing_file" -} -set_constraint_files $timing_file -foreach reset_port [split_words [env_or_default UVHS_RESET_PORTS { - rstn_sw6 rstn_sw5 rstn_sw4 -}]] { +set design_top fpga_top_debug +set ddr_inst_path ${design_top}.core_def.U_UVHS_UVW_AXI4_TO_DDR4 +create_system_design -name VU19P_X4 -platform $platform + +source_required [file join $::uvhs_script_dir assemble_uvhs.tcl] +source_required [file join $::uvhs_script_dir assign_pin_u22_f2.tcl] +set_constraint_files [file join $::uvhs_script_dir timing_common.tcl] +foreach reset_port {rstn_sw6 rstn_sw5 rstn_sw4} { create_reset -port ${design_top}.${reset_port} -active 0 } @@ -164,7 +129,7 @@ import_ip uvw_axi4_to_ddr4 ./rtl/soc/uvw_axi4_to_ddr4.dcp \ -clock_enable_pairs {ddr4ip_dut_axi_aclk ddr4ip_dut_axi_aclk_en 1} \ -script_file {prePlace ./script/uvw_axi4_to_ddr4_pblock.tcl} -set filelist [env_or_default UVHS_FILELIST ./rtl/filelist.f] +set filelist ./rtl/filelist.f if {![file exists $filelist]} { error "required UVHS RTL file list not found: $filelist" } diff --git a/fpga_diff/uvhs/hw_run_download.tcl b/fpga_diff/uvhs/hw_run_download.tcl index 0e8a0f4c..e6cf1949 100644 --- a/fpga_diff/uvhs/hw_run_download.tcl +++ b/fpga_diff/uvhs/hw_run_download.tcl @@ -2,12 +2,7 @@ # reset and memory commands. set uvhs_script_dir [file dirname [file normalize [info script]]] -if {[info exists ::env(UVHS_RUNTIME_CONTROL_SCRIPT)] && - $::env(UVHS_RUNTIME_CONTROL_SCRIPT) ne ""} { - set uvhs_control_script $::env(UVHS_RUNTIME_CONTROL_SCRIPT) -} else { - set uvhs_control_script [file join $uvhs_script_dir runtime_control.tcl] -} +set uvhs_control_script [file join $uvhs_script_dir runtime_control.tcl] if {![file exists $uvhs_control_script]} { error "UVHS runtime control script not found: $uvhs_control_script" } diff --git a/fpga_diff/uvhs/make_compat/csh b/fpga_diff/uvhs/make_compat/csh deleted file mode 100755 index cbbc567c..00000000 --- a/fpga_diff/uvhs/make_compat/csh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -if [[ $# -ge 2 && ( "$1" == "-fc" || "$1" == "-c" ) && "$2" == "limit" ]]; then - ulimit -a - exit 0 -fi - -exec /bin/bash "$@" diff --git a/fpga_diff/uvhs/make_compat/make b/fpga_diff/uvhs/make_compat/make deleted file mode 100755 index 2e930fbd..00000000 --- a/fpga_diff/uvhs/make_compat/make +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -exec /usr/bin/make SHELL=/bin/bash "$@" diff --git a/fpga_diff/uvhs/timing_common.tcl b/fpga_diff/uvhs/timing_common.tcl index eada4e05..464d1785 100644 --- a/fpga_diff/uvhs/timing_common.tcl +++ b/fpga_diff/uvhs/timing_common.tcl @@ -5,9 +5,6 @@ ################################################################################ set fpga_diff_top fpga_top_debug -if {[info exists ::env(UVHS_TOP)] && $::env(UVHS_TOP) ne ""} { - set fpga_diff_top $::env(UVHS_TOP) -} proc fpga_diff_top_port {name} { return "${::fpga_diff_top}.${name}" } diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index b0467594..636d58c6 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -3,51 +3,31 @@ UVHS_ROOT_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))/..) PLATFORM ?= U2.2 UVHS_TEMPLATE_DIR ?= UVHS_UVW_AXI4_TO_DDR4_SRC ?= -UVHS_UVW_AXI4_TO_DDR4_EXPECTED_MD5 ?= -UVHS_DDR_AXI_WIDTH ?= $(if $(filter nutshell,$(CPU)),64,256) +UVHS_DDR_AXI_WIDTH := $(if $(filter nutshell,$(CPU)),64,256) UVHS_WORK_DIR ?= $(ENV_SCRIPTS_HOME)/fpga_diff_uvhs_$(CPU)$(if $(strip $(SUFFIX)),-$(strip $(SUFFIX)),) -UVHS_TOP ?= fpga_top_debug -UVHS_FILELIST ?= $(UVHS_WORK_DIR)/rtl/filelist.f -UVHS_RTL_INCLUDE_FILELIST ?= $(UVHS_WORK_DIR)/rtl/rtl_include.f -UVHS_CORE_RELEASE_DIR ?= $(UVHS_WORK_DIR)/core-release -UVHS_CORE_RELEASE_PACKAGE_DIR ?= $(UVHS_WORK_DIR)/core-release-package -UVHS_CORE_RELEASE_SUFFIX ?= uvhs$(if $(strip $(SUFFIX)),-$(strip $(SUFFIX)),) -UVHS_USE_FPGA_RELEASE ?= $(if $(filter kmh,$(CPU)),1,0) -UVHS_CORE_BUILD_DIR ?= $(if $(filter 1,$(UVHS_USE_FPGA_RELEASE)),$(UVHS_CORE_RELEASE_DIR)/build,$(CORE_DIR)/build) -UVHS_CORE_RTL_DIR ?= $(UVHS_CORE_BUILD_DIR)/rtl -UVHS_CORE_GENERATED_SRC_DIR ?= $(UVHS_CORE_BUILD_DIR)/generated-src +UVHS_FILELIST := $(UVHS_WORK_DIR)/rtl/filelist.f +UVHS_RTL_INCLUDE_FILELIST := $(UVHS_WORK_DIR)/rtl/rtl_include.f +UVHS_CORE_RTL_DIR := $(CORE_DIR)/rtl +UVHS_CORE_GENERATED_SRC_DIR := $(CORE_DIR)/generated-src UVHS_EXPORT_IP_FORCE ?= 0 -UVHS_EXPORT_IP_JOBS ?= 8 -UVHS_EXPORT_IP_VIVADO_VERSION ?= -UVHS_EXPORT_IP_ONLY ?= -UVHS_SKIP_VIVADO_EXPORT ?= vio_0 jtag_ddr_subsys -UVHS_GBUS_IP_DIR ?= $(UV_ROOT)/platform/$(PLATFORM)/Prototype/ips/uvw_gbus.3.1 -UVHS_GBUS_GENERATOR ?= $(UVHS_GBUS_IP_DIR)/gen_generalbus_ip.py -UVHS_GBUS_JSON ?= $(UVHS_GBUS_IP_DIR)/uvw_axi3_generalbus.json -UVHS_GBUS_GEN_DIR ?= $(UVHS_WORK_DIR)/ip-gen/generalbus - -UVHS_DESIGN_NAME ?= VU19P_X4 +UVHS_EXPORT_IP_JOBS := $(if $(strip $(VIVADO_JOBS)),$(VIVADO_JOBS),8) +UVHS_GBUS_IP_DIR := $(UV_ROOT)/platform/$(PLATFORM)/Prototype/ips/uvw_gbus.3.1 +UVHS_GBUS_GENERATOR := $(UVHS_GBUS_IP_DIR)/gen_generalbus_ip.py +UVHS_GBUS_JSON := $(UVHS_GBUS_IP_DIR)/uvw_axi3_generalbus.json +UVHS_GBUS_GEN_DIR := $(UVHS_WORK_DIR)/ip-gen/generalbus + UVHS_TARGET_PACK ?= B0 UVHS_TARGET_FPGA ?= F2 -UVHS_TARGET_FPGA_LOWER ?= b0.f2 -UVHS_KEEP_FPGAS ?= $(UVHS_TARGET_FPGA_LOWER) -UVHS_ASSIGN_PIN_FILE ?= $(UVHS_ROOT_DIR)/uvhs/assign_pin_u22_f2.tcl -UVHS_TIMING_FILE ?= $(UVHS_ROOT_DIR)/uvhs/timing_common.tcl -UVHS_ASSEMBLE_FILE ?= $(UVHS_ROOT_DIR)/uvhs/assemble_uvhs.tcl +UVHS_KEEP_FPGAS ?= UVHS_CPU_CLK_PERIOD_NS ?= 40 -UVHS_USE_LSF ?= 0 UVHS_FRONTEND_THREADS ?= 4 UVHS_FRONTEND_PROCESSES ?= 16 UVHS_FPGA_THREADS ?= 4 UVHS_FPGA_PROCESSES ?= 8 -UVHS_PNR_STRATEGY ?= Strategy_uv_high_fanout_explore UVHS_COMPILE_STRATEGY ?= uv_high_fanout_explore UVHS_LUT_FILL_RATE ?= $(if $(filter kmh,$(CPU)),80,) UVHS_LUT6_FILL_RATE ?= $(if $(filter kmh,$(CPU)),30,) -UVHS_VIVADO_PRE_OPT_FILE ?= $(UVHS_ROOT_DIR)/uvhs/vivado_pre_opt.tcl -UVHS_ASYNC_CLOCK_FILE ?= $(UVHS_WORK_DIR)/script/fpga_diff_async_clocks.tcl -UVHS_SHELL_COMPAT_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/shell_compat.sh XDMA_LINK_WIDTH ?= X4 XDMA_ENABLE_PF0_BAR1 ?= 1 @@ -63,37 +43,25 @@ UVHS_UVW_AXI4_TO_DDR4_REQUIRED_FILES := \ rtl/soc/uvw_axi4_to_ddr4.dcp \ rtl/soc/uvw_axi4_to_ddr4_Stub.v \ script/uvw_axi4_to_ddr4_pblock.tcl -UVHS_REQUIRED_MODULES ?= $(if $(filter nanhu,$(CPU)),XlnFpgaTop,$(if $(filter kmh nutshell,$(CPU)),SimTop,)) -UVHS_DDR_RTL_INST := $(UVHS_TOP).core_def.U_UVHS_UVW_AXI4_TO_DDR4 -UVHS_RUNTIME_LIB_DIR ?= $(UVHS_WORK_DIR)/.uvhs-runtime-lib -UVHS_RUNTIME_DB ?= $(UVHS_WORK_DIR)/hw.dat -UVHS_RUNTIME_WORK_DIR ?= $(UVHS_WORK_DIR)/runtime-work -UVHS_RUNTIME_COMMAND_FILE ?= $(UVHS_RUNTIME_WORK_DIR)/command.tcl -UVHS_RUNTIME_TMP_DIR ?= $(UVHS_RUNTIME_WORK_DIR)/tmp -UVHS_RUNTIME_PID_FILE ?= $(UVHS_RUNTIME_WORK_DIR)/uv_shell.pid -UVHS_RUNTIME_READY_FILE ?= $(UVHS_RUNTIME_WORK_DIR)/uv_shell.ready -UVHS_RUNTIME_LOG ?= $(UVHS_RUNTIME_WORK_DIR)/uv_shell.log -UVHS_RUNTIME_DOWNLOAD_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/hw_run_download.tcl -UVHS_RUNTIME_CONTROL_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/runtime_control.tcl -UVHS_RUNTIME_COMMAND_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/runtime_command.tcl -UVHS_RUNTIME_SESSION_SCRIPT ?= $(UVHS_ROOT_DIR)/uvhs/runtime_session.sh -UVHS_RUNTIME_DDR_RTL ?= $(UVHS_DDR_RTL_INST) -UVHS_RUNTIME_START_TIMEOUT ?= 600 -UVHS_RUNTIME_COMMAND_TIMEOUT ?= 600 -UVHS_GBUS_BOARD ?= $(UVHS_TARGET_PACK) -UVHS_GBUS_FPGA ?= $(UVHS_TARGET_FPGA) -UVHS_GBUS_PORT ?= 0 -UVHS_GBUS_CHANNEL ?= 0 -UVHS_FLASH_BASE ?= 0x0 -UVHS_FLASH_SIZE ?= 0x8000 +UVHS_REQUIRED_MODULES := $(if $(filter nanhu,$(CPU)),XlnFpgaTop,$(if $(filter kmh nutshell,$(CPU)),SimTop,)) +UVHS_DDR_RTL_INST := fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4 +UVHS_RUNTIME_LIB_DIR := $(UVHS_WORK_DIR)/.uvhs-runtime-lib +UVHS_RUNTIME_DB := $(UVHS_WORK_DIR)/hw.dat +UVHS_RUNTIME_WORK_DIR := $(UVHS_WORK_DIR)/runtime-work +UVHS_RUNTIME_COMMAND_FILE := $(UVHS_RUNTIME_WORK_DIR)/command.tcl +UVHS_RUNTIME_TMP_DIR := $(UVHS_RUNTIME_WORK_DIR)/tmp +UVHS_RUNTIME_PID_FILE := $(UVHS_RUNTIME_WORK_DIR)/uv_shell.pid +UVHS_RUNTIME_READY_FILE := $(UVHS_RUNTIME_WORK_DIR)/uv_shell.ready +UVHS_RUNTIME_LOG := $(UVHS_RUNTIME_WORK_DIR)/uv_shell.log +UVHS_RUNTIME_TIMEOUT ?= 600 UVHS_COMPAT_PCRE_LIB ?= -UVHS_SHELL_EXEC_WRAPPER ?= $(UVHS_ROOT_DIR)/uvhs/uv_shell_exec_compat.sh UVHS_TOOL_ENV = \ - PATH="$(UVHS_ROOT_DIR)/uvhs/make_compat:$$UV_ROOT/bin:$$UV_ROOT/lib/venv3.8/bin:$$UV_ROOT/lib/gcc10.3/bin:$$PATH" \ + PATH="$$UV_ROOT/bin:$$UV_ROOT/lib/venv3.8/bin:$$UV_ROOT/lib/gcc10.3/bin:$$PATH" \ + MAKEFLAGS="$${MAKEFLAGS:+$$MAKEFLAGS }SHELL=/bin/bash" \ LD_LIBRARY_PATH="$(UVHS_RUNTIME_LIB_DIR):$${LD_LIBRARY_PATH:-}" \ UVHS_RUNTIME_LIB_DIR="$(UVHS_RUNTIME_LIB_DIR)" \ - UVSHELL_EXEC_NAME="$(UVHS_SHELL_EXEC_WRAPPER)" + UVSHELL_EXEC_NAME="$(UVHS_ROOT_DIR)/uvhs/uv_shell_exec_compat.sh" UVHS_FLOW_ENV = \ $(UVHS_TOOL_ENV) \ @@ -103,25 +71,19 @@ UVHS_FLOW_ENV = \ XDMA_ENABLE_PF0_BAR1="$(XDMA_ENABLE_PF0_BAR1)" \ XDMA_AXILITE_MASTER_SCALE="$(XDMA_AXILITE_MASTER_SCALE)" \ XDMA_AXILITE_MASTER_SIZE="$(XDMA_AXILITE_MASTER_SIZE)" \ - UVHS_DESIGN_NAME="$(UVHS_DESIGN_NAME)" \ UVHS_TARGET_PACK="$(UVHS_TARGET_PACK)" \ UVHS_TARGET_FPGA="$(UVHS_TARGET_FPGA)" \ - UVHS_TARGET_FPGA_LOWER="$(UVHS_TARGET_FPGA_LOWER)" \ UVHS_KEEP_FPGAS="$(UVHS_KEEP_FPGAS)" \ UVHS_CPU_CLK_PERIOD_NS="$(UVHS_CPU_CLK_PERIOD_NS)" \ - UVHS_PNR_STRATEGY="$(UVHS_PNR_STRATEGY)" \ UVHS_COMPILE_STRATEGY="$(UVHS_COMPILE_STRATEGY)" \ UVHS_LUT_FILL_RATE="$(UVHS_LUT_FILL_RATE)" \ - UVHS_LUT6_FILL_RATE="$(UVHS_LUT6_FILL_RATE)" \ - UVHS_VIVADO_PRE_OPT_FILE="$(UVHS_VIVADO_PRE_OPT_FILE)" \ - UVHS_ASYNC_CLOCK_FILE="$(UVHS_ASYNC_CLOCK_FILE)" \ - UVHS_SHELL_COMPAT_SCRIPT="$(UVHS_SHELL_COMPAT_SCRIPT)" + UVHS_LUT6_FILL_RATE="$(UVHS_LUT6_FILL_RATE)" -UVHS_PNR_DIR ?= $(UVHS_WORK_DIR)/hw.dat/Compile/PnR/$(UVHS_TARGET_PACK)/$(UVHS_TARGET_FPGA)/vivado/Rundir/$(UVHS_PNR_STRATEGY) -UVHS_BITSTREAM_DIR ?= $(UVHS_PNR_DIR)/bitstream +UVHS_PNR_DIR := $(UVHS_WORK_DIR)/hw.dat/Compile/PnR/$(UVHS_TARGET_PACK)/$(UVHS_TARGET_FPGA)/vivado/Rundir/Strategy_$(UVHS_COMPILE_STRATEGY) +UVHS_BITSTREAM_DIR := $(UVHS_PNR_DIR)/bitstream UVHS_BIT_HOME ?= $(UVHS_WORK_DIR)/ready-to-program -.PHONY: uvhs_preflight uvhs_prepare uvhs_prepare_core_rtl \ +.PHONY: uvhs_preflight uvhs_prepare \ uvhs_export_vivado_ip uvhs_export_generalbus uvhs_normalize_rtl_include \ uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist uvhs_check_modules \ uvhs_frontend uvhs_backend uvhs_all uvhs_check_timing \ @@ -136,9 +98,9 @@ uvhs_preflight: test -x "$$UV_XILINX_VIVADO/bin/vivado" test -n "$$UV_LICENSE" test -x "$$UV_ROOT/bin/uv_shell_exec" - test -x "$(UVHS_SHELL_EXEC_WRAPPER)" - test -x "$(UVHS_SHELL_COMPAT_SCRIPT)" - test -f "$(UVHS_VIVADO_PRE_OPT_FILE)" + test -x "$(UVHS_ROOT_DIR)/uvhs/uv_shell_exec_compat.sh" + test -x "$(UVHS_ROOT_DIR)/uvhs/shell_compat.sh" + test -f "$(UVHS_ROOT_DIR)/uvhs/vivado_pre_opt.tcl" test -f "$(UVHS_GBUS_GENERATOR)" test -f "$(UVHS_GBUS_JSON)" command -v python3 >/dev/null @@ -173,46 +135,18 @@ uvhs_prepare: uvhs_preflight mkdir -p "$(UVHS_WORK_DIR)" cp -a "$(UVHS_TEMPLATE_DIR)/script" "$(UVHS_WORK_DIR)/" cp -f "$(UVHS_TEMPLATE_DIR)/Makefile" "$(UVHS_WORK_DIR)/Makefile" - cp -f "$(UVHS_ROOT_DIR)/uvhs/async_clocks.tcl" "$(UVHS_ASYNC_CLOCK_FILE)" mkdir -p "$(UVHS_WORK_DIR)/rtl/soc" "$(UVHS_WORK_DIR)/rtl/device/pcie" -# XiangShan's upstream release step removes FPGA clock gates and assigns large -# generated arrays to URAM. Synthesize that released RTL rather than build/rtl. -uvhs_prepare_core_rtl: -ifeq ($(filter 1,$(UVHS_USE_FPGA_RELEASE)),1) - bash -c 'set -euo pipefail; \ - core="$(CORE_DIR)"; package="$(UVHS_CORE_RELEASE_PACKAGE_DIR)"; release="$(UVHS_CORE_RELEASE_DIR)"; \ - test -f "$$core/build/rtl/SimTop.sv"; \ - test -f "$$core/build/generated-src/difftest_profile.json"; \ - test -f "$$core/difftest/scripts/fpga/release.sh"; \ - rm -rf "$$package" "$$release"; \ - mkdir -p "$$package" "$$release"; \ - $(MAKE) -C "$$core/difftest" fpga-release NOOP_HOME="$$core" \ - RELEASE_DIR="$$package" RELEASE_SUFFIX="$(UVHS_CORE_RELEASE_SUFFIX)"; \ - archive="$$(find "$$package" -maxdepth 1 -type f -name "*.tar.gz" -print -quit)"; \ - test -n "$$archive"; \ - tar -xzf "$$archive" -C "$$release" --strip-components=1; \ - test -f "$$release/build/rtl/SimTop.sv"; \ - test -f "$$release/build/rtl/DifftestClockGate.v"; \ - grep -Fq "assign Q = CK;" "$$release/build/rtl/ClockGate.sv"; \ - grep -Fq "ram_style = \"ultra\"" "$$release/build/rtl"/array_*.v; \ - echo "INFO: prepared XiangShan FPGA release RTL at $$release/build/rtl"' -else - test -d "$(UVHS_CORE_RTL_DIR)" -endif - uvhs_export_vivado_ip: uvhs_prepare bash -c 'set -euo pipefail; \ export VIVADO_HOME="$$UV_XILINX_VIVADO" XILINX_VIVADO="$$UV_XILINX_VIVADO"; \ - version="$(UVHS_EXPORT_IP_VIVADO_VERSION)"; \ - if [ -z "$$version" ]; then version="$$("$$UV_XILINX_VIVADO/bin/vivado" -version | sed -n "s/^Vivado v\\([^ ]*\\).*/\\1/p" | head -n 1)"; fi; \ + version="$$("$$UV_XILINX_VIVADO/bin/vivado" -version | sed -n "s/^Vivado v\\([^ ]*\\).*/\\1/p" | head -n 1)"; \ + test -n "$$version"; \ $(UVHS_FLOW_ENV) "$$UV_XILINX_VIVADO/bin/vivado" -mode batch \ -source "$(UVHS_ROOT_DIR)/uvhs/export_vivado_ip.tcl" -tclargs \ --origin_dir "$(UVHS_ROOT_DIR)" --out_dir "$(UVHS_WORK_DIR)" \ - --vivado_version "$$version" --cpu "$(CPU)" --core_dir "$(CORE_DIR)" \ + --vivado_version "$$version" --core_dir "$(CORE_DIR)" \ --jobs "$(UVHS_EXPORT_IP_JOBS)" \ - $(if $(strip $(UVHS_EXPORT_IP_ONLY)),--only "$(UVHS_EXPORT_IP_ONLY)",) \ - $(foreach ip,$(UVHS_SKIP_VIVADO_EXPORT),--skip "$(ip)") \ $(if $(filter 1,$(UVHS_EXPORT_IP_FORCE)),--force,)' # The vendor generator starts an asynchronous DCP copy before deleting its @@ -262,7 +196,7 @@ uvhs_export_generalbus: uvhs_prepare uvhs_normalize_rtl_include: uvhs_prepare mkdir -p "$(dir $(UVHS_RTL_INCLUDE_FILELIST))" bash "$(UVHS_ROOT_DIR)/tools/update_core_flist.sh" "$(CORE_DIR)" \ - --external-only --output-filelist "$(UVHS_RTL_INCLUDE_FILELIST)" \ + --output-filelist "$(UVHS_RTL_INCLUDE_FILELIST)" \ -- $(RTL_INCLUDE) uvhs_sync_uvw_axi4_to_ddr4: uvhs_prepare @@ -285,13 +219,10 @@ uvhs_sync_uvw_axi4_to_ddr4: uvhs_prepare fi; \ grep -Eq "input[[:space:]]+\\[$$last_bit:0\\][[:space:]]*ddr4ip_dut_axi_wdata" "$$stub"; \ grep -Eq "output[[:space:]]+\\[$$last_bit:0\\][[:space:]]*ddr4ip_dut_axi_rdata" "$$stub"; \ - echo "INFO: verified UVHS DDR DCP AXI data width: $$expected_width"; \ - if [ -n "$(UVHS_UVW_AXI4_TO_DDR4_EXPECTED_MD5)" ]; then \ - echo "$(UVHS_UVW_AXI4_TO_DDR4_EXPECTED_MD5) $$work/rtl/soc/uvw_axi4_to_ddr4.dcp" | md5sum -c -; \ - fi' + echo "INFO: verified UVHS DDR DCP AXI data width: $$expected_width"' -uvhs_filelist: uvhs_export_generalbus uvhs_normalize_rtl_include \ - uvhs_prepare_core_rtl +uvhs_filelist: uvhs_export_generalbus uvhs_normalize_rtl_include + test -d "$(UVHS_CORE_RTL_DIR)" mkdir -p "$(dir $(UVHS_FILELIST))" { \ printf '+define+SYNTHESIS\n+define+XIANGSHAN_FPGA\n'; \ @@ -302,8 +233,7 @@ uvhs_filelist: uvhs_export_generalbus uvhs_normalize_rtl_include \ if [ "$(CPU)" = nutshell ]; then printf '+define+CPU_NUTSHELL\n'; fi; \ if [ "$(CPU)" = kmh ]; then \ simtop=""; \ - for candidate in "$(UVHS_CORE_RTL_DIR)/SimTop.sv" \ - "$(CORE_DIR)/rtl/SimTop.sv" "$(CORE_DIR)/SimTop.sv"; do \ + for candidate in "$(UVHS_CORE_RTL_DIR)/SimTop.sv"; do \ if [ -f "$$candidate" ]; then simtop="$$candidate"; break; fi; \ done; \ if [ -n "$$simtop" ] && \ @@ -311,7 +241,7 @@ uvhs_filelist: uvhs_export_generalbus uvhs_normalize_rtl_include \ printf '+define+CONFIG_SIMTOP_HAS_DMA\n'; \ fi; \ fi; \ - if [ -d "$(UVHS_CORE_BUILD_DIR)" ]; then printf '+incdir+%s\n' "$(UVHS_CORE_BUILD_DIR)"; fi; \ + printf '+incdir+%s\n' "$(CORE_DIR)"; \ if [ -d "$(UVHS_CORE_RTL_DIR)" ]; then printf '+incdir+%s\n' "$(UVHS_CORE_RTL_DIR)"; fi; \ if [ -d "$(UVHS_CORE_GENERATED_SRC_DIR)" ]; then printf '+incdir+%s\n' "$(UVHS_CORE_GENERATED_SRC_DIR)"; fi; \ printf '+incdir+%s/src/rtl/common\n' "$(UVHS_ROOT_DIR)"; \ @@ -323,16 +253,8 @@ uvhs_filelist: uvhs_export_generalbus uvhs_normalize_rtl_include \ test ! -d "$(UVHS_ROOT_DIR)/src/rtl/$(CPU)" || \ find "$(UVHS_ROOT_DIR)/src/rtl/$(CPU)" -type f \ \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ - if [ -d "$(UVHS_CORE_RTL_DIR)" ]; then \ - find "$(UVHS_CORE_RTL_DIR)" -type f \ - \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ - elif [ -n "$(CORE_DIR)" ] && [ -d "$(CORE_DIR)" ]; then \ - find "$(CORE_DIR)" \( -path '*/rtl/verification' -o -path '*/out' \) -prune -o \ - -type f \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ - fi; \ - if [ "$(CPU)" != kmh ]; then test ! -f "$(CORE_DIR)/difftest/src/test/vsrc/common/DifftestClockGate.v" || \ - printf '%s\n' "$(CORE_DIR)/difftest/src/test/vsrc/common/DifftestClockGate.v"; \ - fi; \ + find "$(UVHS_CORE_RTL_DIR)" -type f \ + \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ test ! -f "$(UVHS_RTL_INCLUDE_FILELIST)" || cat "$(UVHS_RTL_INCLUDE_FILELIST)"; \ } | awk 'NF' > "$(UVHS_FILELIST)" @@ -342,22 +264,15 @@ uvhs_check_modules: uvhs_filelist uvhs_frontend: uvhs_export_vivado_ip uvhs_export_generalbus \ uvhs_sync_uvw_axi4_to_ddr4 uvhs_check_modules bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ - $(UVHS_FLOW_ENV) UVHS_TOP="$(UVHS_TOP)" UVHS_FILELIST=./rtl/filelist.f \ - UVHS_DDR_RTL_INST="$(UVHS_DDR_RTL_INST)" \ - UVHS_ASSIGN_PIN_FILE="$(UVHS_ASSIGN_PIN_FILE)" UVHS_TIMING_FILE="$(UVHS_TIMING_FILE)" \ - UVHS_ASSEMBLE_FILE="$(UVHS_ASSEMBLE_FILE)" \ - UVHS_USE_LSF="$(UVHS_USE_LSF)" \ + $(UVHS_FLOW_ENV) \ UVHS_FRONTEND_THREADS="$(UVHS_FRONTEND_THREADS)" UVHS_FRONTEND_PROCESSES="$(UVHS_FRONTEND_PROCESSES)" \ - UVHS_FPGA_THREADS="$(UVHS_FPGA_THREADS)" UVHS_FPGA_PROCESSES="$(UVHS_FPGA_PROCESSES)" \ bash "$$UV_ROOT/bin/uv_shell" -bypass_vivado_version_check \ -s "$(UVHS_ROOT_DIR)/uvhs/frontend_run.tcl" |& tee frontend_run.log; \ grep -Fxq UVHS_FRONTEND_SUCCESS frontend_run.log' uvhs_backend: bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ - $(UVHS_FLOW_ENV) UVHS_TOP="$(UVHS_TOP)" \ - UVHS_ASSIGN_PIN_FILE="$(UVHS_ASSIGN_PIN_FILE)" UVHS_ASSEMBLE_FILE="$(UVHS_ASSEMBLE_FILE)" \ - UVHS_USE_LSF="$(UVHS_USE_LSF)" \ + $(UVHS_FLOW_ENV) \ UVHS_FPGA_THREADS="$(UVHS_FPGA_THREADS)" UVHS_FPGA_PROCESSES="$(UVHS_FPGA_PROCESSES)" \ bash "$$UV_ROOT/bin/uv_shell" -bypass_vivado_version_check \ -s "$(UVHS_ROOT_DIR)/uvhs/backend_run.tcl" |& tee backend_run.log; \ @@ -379,66 +294,57 @@ uvhs_package_bitstream: uvhs_check_timing # database. Detach that session after programming and track it in runtime-work. uvhs_write_bitstream: test -d "$(UVHS_RUNTIME_DB)" - test -f "$(UVHS_RUNTIME_DOWNLOAD_SCRIPT)" - test -f "$(UVHS_RUNTIME_CONTROL_SCRIPT)" - test -x "$(UVHS_RUNTIME_SESSION_SCRIPT)" + test -f "$(UVHS_ROOT_DIR)/uvhs/hw_run_download.tcl" + test -f "$(UVHS_ROOT_DIR)/uvhs/runtime_control.tcl" + test -x "$(UVHS_ROOT_DIR)/uvhs/runtime_session.sh" mkdir -p "$(UVHS_RUNTIME_WORK_DIR)" "$(UVHS_RUNTIME_TMP_DIR)" $(UVHS_TOOL_ENV) UVHS_DB_PATH="$(UVHS_RUNTIME_DB)" \ UVHS_COMMAND_FILE="$(UVHS_RUNTIME_COMMAND_FILE)" \ UVHS_RUNTIME_READY_FILE="$(UVHS_RUNTIME_READY_FILE)" \ UVHS_RUNTIME_TMP_DIR="$(UVHS_RUNTIME_TMP_DIR)" \ - UVHS_RUNTIME_CONTROL_SCRIPT="$(UVHS_RUNTIME_CONTROL_SCRIPT)" \ - bash "$(UVHS_RUNTIME_SESSION_SCRIPT)" start \ + bash "$(UVHS_ROOT_DIR)/uvhs/runtime_session.sh" start \ "$(UVHS_RUNTIME_PID_FILE)" "$(UVHS_RUNTIME_READY_FILE)" \ "$(UVHS_RUNTIME_LOG)" "$(UVHS_RUNTIME_COMMAND_FILE)" \ - "$(UVHS_RUNTIME_START_TIMEOUT)" \ + "$(UVHS_RUNTIME_TIMEOUT)" \ bash "$$UV_ROOT/bin/uv_shell" -rt_shell \ -workdir "$(UVHS_RUNTIME_WORK_DIR)" \ - -script "$(UVHS_RUNTIME_DOWNLOAD_SCRIPT)" + -script "$(UVHS_ROOT_DIR)/uvhs/hw_run_download.tcl" uvhs_runtime_check: - bash "$(UVHS_RUNTIME_SESSION_SCRIPT)" check \ + bash "$(UVHS_ROOT_DIR)/uvhs/runtime_session.sh" check \ "$(UVHS_RUNTIME_PID_FILE)" "$(UVHS_RUNTIME_READY_FILE)" uvhs_runtime_status: uvhs_runtime_check @echo "UVHS_RUNTIME_LOG=$(UVHS_RUNTIME_LOG)" -uvhs_halt_soc: uvhs_runtime_check - UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_COMMAND_TIMEOUT)" \ +define uvhs_runtime_command + UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_TIMEOUT)" \ bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ - "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" halt_soc + "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_ROOT_DIR)/uvhs/runtime_command.tcl" $(1) +endef + +uvhs_halt_soc: uvhs_runtime_check + $(call uvhs_runtime_command,halt_soc) uvhs_reset_cpu: uvhs_runtime_check - UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_COMMAND_TIMEOUT)" \ - bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ - "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" reset_cpu + $(call uvhs_runtime_command,reset_cpu) uvhs_write_ddr: uvhs_runtime_check test -f "$(WORKLOAD)" - UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_COMMAND_TIMEOUT)" \ - bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ - "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" \ - write_ddr "$(WORKLOAD)" "$(UVHS_RUNTIME_DDR_RTL)" "$(UVHS_DDR_AXI_WIDTH)" + $(call uvhs_runtime_command,write_ddr "$(WORKLOAD)" "$(UVHS_DDR_RTL_INST)" "$(UVHS_DDR_AXI_WIDTH)") uvhs_write_flash: uvhs_runtime_check test -f "$(WORKLOAD)" - UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_COMMAND_TIMEOUT)" \ - bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ - "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" \ - write_flash "$(WORKLOAD)" "$(UVHS_GBUS_BOARD)" "$(UVHS_GBUS_FPGA)" \ - "$(UVHS_GBUS_PORT)" "$(UVHS_GBUS_CHANNEL)" \ - "$(UVHS_FLASH_BASE)" "$(UVHS_FLASH_SIZE)" + $(call uvhs_runtime_command,write_flash "$(WORKLOAD)" "$(UVHS_TARGET_PACK)" "$(UVHS_TARGET_FPGA)" 0 0 0x0 0x8000) uvhs_runtime_stop: uvhs_runtime_check - UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_COMMAND_TIMEOUT)" \ - bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ - "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_SCRIPT)" stop - bash "$(UVHS_RUNTIME_SESSION_SCRIPT)" wait \ + $(call uvhs_runtime_command,stop) + bash "$(UVHS_ROOT_DIR)/uvhs/runtime_session.sh" wait \ "$(UVHS_RUNTIME_PID_FILE)" "$(UVHS_RUNTIME_READY_FILE)" \ - "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_COMMAND_TIMEOUT)" + "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_TIMEOUT)" uvhs_clean: - @! bash "$(UVHS_RUNTIME_SESSION_SCRIPT)" active \ + @! bash "$(UVHS_ROOT_DIR)/uvhs/runtime_session.sh" active \ "$(UVHS_RUNTIME_PID_FILE)" >/dev/null 2>&1 || \ { echo "ERROR: stop the UVHS runtime before cleaning" >&2; exit 1; } test -n "$(UVHS_WORK_DIR)" diff --git a/fpga_diff/uvhs/vivado_pre_opt.tcl b/fpga_diff/uvhs/vivado_pre_opt.tcl index c092753e..8e0ccb01 100644 --- a/fpga_diff/uvhs/vivado_pre_opt.tcl +++ b/fpga_diff/uvhs/vivado_pre_opt.tcl @@ -81,9 +81,4 @@ foreach {label patterns} { } puts "INFO: XDMA CDC total ASYNC_REG count=[llength $fpga_diff_xdma_cdc_cells]" -if {![info exists ::env(UVHS_ASYNC_CLOCK_FILE)] || - $::env(UVHS_ASYNC_CLOCK_FILE) eq "" || - ![file exists $::env(UVHS_ASYNC_CLOCK_FILE)]} { - error "UVHS_ASYNC_CLOCK_FILE is missing in Vivado pre-opt" -} -source $::env(UVHS_ASYNC_CLOCK_FILE) +source [file join [file dirname [file normalize [info script]]] async_clocks.tcl] From 2c5cf21d93676ed3ab0476db75589d22ab8b197c Mon Sep 17 00:00:00 2001 From: klin02 Date: Sun, 2 Aug 2026 20:00:06 +0800 Subject: [PATCH 11/62] refactor(fpga_diff): separate UVHS flow stages Share RTL_INCLUDE parsing between the Vivado and UVHS file-list generators while keeping each output contract independent. Generate and validate the complete UVHS input in one step. Move common Tcl helpers and automatic partitioning out of the frontend and backend drivers. Make selected-FPGA assembly state explicit and order file-list generation after all stub exports. Co-authored-by: Kamimiao --- fpga_diff/tools/rtl_filelist_lib.sh | 168 ++++++++++++++++++ fpga_diff/tools/update_core_flist.sh | 254 ++++----------------------- fpga_diff/uvhs/README.md | 15 +- fpga_diff/uvhs/assemble_uvhs.tcl | 25 +-- fpga_diff/uvhs/backend_run.tcl | 66 ++----- fpga_diff/uvhs/check_flow_tools.sh | 8 +- fpga_diff/uvhs/check_modules.sh | 44 ----- fpga_diff/uvhs/flow_common.tcl | 24 +++ fpga_diff/uvhs/frontend_run.tcl | 56 +++--- fpga_diff/uvhs/generate_filelist.sh | 96 ++++++++++ fpga_diff/uvhs/partition.tcl | 31 ++++ fpga_diff/uvhs/uvhs.mk | 60 +------ 12 files changed, 415 insertions(+), 432 deletions(-) create mode 100644 fpga_diff/tools/rtl_filelist_lib.sh delete mode 100755 fpga_diff/uvhs/check_modules.sh create mode 100644 fpga_diff/uvhs/flow_common.tcl create mode 100755 fpga_diff/uvhs/generate_filelist.sh create mode 100644 fpga_diff/uvhs/partition.tcl diff --git a/fpga_diff/tools/rtl_filelist_lib.sh b/fpga_diff/tools/rtl_filelist_lib.sh new file mode 100644 index 00000000..1ff7ca46 --- /dev/null +++ b/fpga_diff/tools/rtl_filelist_lib.sh @@ -0,0 +1,168 @@ +#!/usr/bin/env bash + +# Shared RTL_INCLUDE parser. Call rtl_flist_parse_inputs BASE_DIR INPUT... +# after sourcing this file, then consume rtl_flist_files and +# rtl_flist_include_dirs. + +declare -a rtl_flist_files=() +declare -a rtl_flist_include_dirs=() +declare -A rtl_flist_seen_files=() +declare -A rtl_flist_seen_dirs=() +declare -A rtl_flist_active_lists=() + +rtl_flist_fail() { + echo "ERROR: $*" >&2 + exit 1 +} + +rtl_flist_resolve_path() { + local base_dir=$1 + local path=$2 + + if [[ $path != /* ]]; then + path="$base_dir/$path" + fi + realpath -e -- "$path" +} + +rtl_flist_add_include_dir() { + local base_dir=$1 + local path=$2 + local resolved + + resolved=$(rtl_flist_resolve_path "$base_dir" "$path") || + rtl_flist_fail "RTL include directory not found: $path" + [[ -d $resolved ]] || rtl_flist_fail "RTL include path is not a directory: $path" + if [[ -z ${rtl_flist_seen_dirs[$resolved]+x} ]]; then + rtl_flist_seen_dirs[$resolved]=1 + rtl_flist_include_dirs+=("$resolved") + fi +} + +rtl_flist_add_file() { + local base_dir=$1 + local path=$2 + local resolved + + resolved=$(rtl_flist_resolve_path "$base_dir" "$path") || + rtl_flist_fail "RTL source not found: $path" + [[ -f $resolved ]] || rtl_flist_fail "RTL source is not a file: $path" + case $resolved in + *.v|*.sv|*.vh|*.svh) ;; + *) rtl_flist_fail "unsupported RTL source: $path" ;; + esac + + if [[ -z ${rtl_flist_seen_files[$resolved]+x} ]]; then + rtl_flist_seen_files[$resolved]=1 + rtl_flist_files+=("$resolved") + fi + rtl_flist_add_include_dir / "$(dirname -- "$resolved")" +} + +rtl_flist_add_dir() { + local base_dir=$1 + local path=$2 + local recursive=$3 + local resolved + local -a find_depth=() + + resolved=$(rtl_flist_resolve_path "$base_dir" "$path") || + rtl_flist_fail "RTL directory not found: $path" + [[ -d $resolved ]] || rtl_flist_fail "RTL path is not a directory: $path" + rtl_flist_add_include_dir / "$resolved" + if [[ $recursive == 0 ]]; then + find_depth=(-maxdepth 1) + fi + while IFS= read -r -d '' rtl_file; do + rtl_flist_add_file / "$rtl_file" + done < <( + find "$resolved" "${find_depth[@]}" -type f \ + \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ + -print0 | LC_ALL=C sort -z + ) +} + +rtl_flist_parse_filelist() { + local caller_dir=$1 + local path=$2 + local filelist + local filelist_dir + local line + local token + local pending="" + local value + local -a tokens=() + local -a values=() + + filelist=$(rtl_flist_resolve_path "$caller_dir" "$path") || + rtl_flist_fail "RTL file list not found: $path" + [[ -f $filelist ]] || rtl_flist_fail "RTL file list is not a file: $path" + if [[ -n ${rtl_flist_active_lists[$filelist]+x} ]]; then + rtl_flist_fail "recursive RTL file list: $filelist" + fi + + rtl_flist_active_lists[$filelist]=1 + filelist_dir=$(dirname -- "$filelist") + while IFS= read -r line || [[ -n $line ]]; do + line=${line%$'\r'} + line=${line%%//*} + line=${line%%#*} + read -r -a tokens <<< "$line" + for token in "${tokens[@]}"; do + if [[ -n $pending ]]; then + case $pending in + filelist) rtl_flist_parse_filelist "$filelist_dir" "$token" ;; + library) rtl_flist_add_dir "$filelist_dir" "$token" 0 ;; + source) rtl_flist_add_file "$filelist_dir" "$token" ;; + include) rtl_flist_add_include_dir "$filelist_dir" "$token" ;; + esac + pending="" + continue + fi + + case $token in + -f|-F) pending=filelist ;; + -y) pending=library ;; + -v) pending=source ;; + -I) pending=include ;; + -f*|-F*) rtl_flist_parse_filelist "$filelist_dir" "${token:2}" ;; + -y*) rtl_flist_add_dir "$filelist_dir" "${token:2}" 0 ;; + -v*) rtl_flist_add_file "$filelist_dir" "${token:2}" ;; + -I*) rtl_flist_add_include_dir "$filelist_dir" "${token:2}" ;; + +incdir+*) + IFS=+ read -r -a values <<< "${token#+incdir+}" + for value in "${values[@]}"; do + [[ -n $value ]] && rtl_flist_add_include_dir "$filelist_dir" "$value" + done + ;; + +libext+*) ;; + *.v|*.sv|*.vh|*.svh) rtl_flist_add_file "$filelist_dir" "$token" ;; + *) rtl_flist_fail "unsupported option in $filelist: $token" ;; + esac + done + done < "$filelist" + [[ -z $pending ]] || rtl_flist_fail "missing argument after file-list option in $filelist" + unset 'rtl_flist_active_lists[$filelist]' +} + +rtl_flist_parse_inputs() { + local base_dir=$1 + local input + local resolved + shift + + for input in "$@"; do + resolved=$(rtl_flist_resolve_path "$base_dir" "$input") || + rtl_flist_fail "RTL_INCLUDE path not found: $input" + if [[ -d $resolved ]]; then + rtl_flist_add_dir / "$resolved" 1 + elif [[ -f $resolved ]]; then + case $input in + *.f|*.flist|*.list) rtl_flist_parse_filelist / "$resolved" ;; + *) rtl_flist_add_file / "$resolved" ;; + esac + else + rtl_flist_fail "RTL_INCLUDE path not found: $input" + fi + done +} diff --git a/fpga_diff/tools/update_core_flist.sh b/fpga_diff/tools/update_core_flist.sh index b0d4bc63..0c241f48 100755 --- a/fpga_diff/tools/update_core_flist.sh +++ b/fpga_diff/tools/update_core_flist.sh @@ -2,240 +2,52 @@ set -euo pipefail -fail() { - echo "ERROR: $*" >&2 - exit 1 -} - usage() { - echo "Usage: $0 CORE_DIR [--output-filelist FILE] [--] [RTL_INCLUDE ...]" >&2 + echo "Usage: $0 CORE_DIR [--] [RTL_INCLUDE ...]" >&2 exit 2 } [[ $# -ge 1 ]] || usage - core_dir=$1 shift +if [[ ${1:-} == -- ]]; then + shift +fi +[[ -d $core_dir ]] || { + echo "ERROR: CORE_DIR is not a directory: $core_dir" >&2 + exit 1 +} fpga_diff_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd) -awk_script="$fpga_diff_dir/core_flist.awk" -output_tcl="$fpga_diff_dir/src/tcl/cpu_files.tcl" -output_filelist="" - -while (($#)); do - case $1 in - --output-filelist) - [[ $# -ge 2 ]] || usage - output_filelist=$2 - shift 2 - ;; - --) - shift - break - ;; - *) - break - ;; - esac -done - -[[ -d $core_dir ]] || fail "CORE_DIR is not a directory: $core_dir" +source "$fpga_diff_dir/tools/rtl_filelist_lib.sh" +rtl_flist_parse_inputs "$PWD" "$@" +core_dir=$(realpath -e -- "$core_dir") tmp_dir=$(mktemp -d) trap 'rm -rf "$tmp_dir"' EXIT -declare -a rtl_files=() -declare -a rtl_include_dirs=() -declare -A seen_files=() -declare -A seen_dirs=() -declare -A active_filelists=() - -resolve_path() { - local base_dir=$1 - local path=$2 - - if [[ $path != /* ]]; then - path="$base_dir/$path" - fi - realpath -e -- "$path" -} - -add_include_dir() { - local base_dir=$1 - local path=$2 - local resolved - - resolved=$(resolve_path "$base_dir" "$path") || - fail "RTL include directory not found: $path" - [[ -d $resolved ]] || fail "RTL include path is not a directory: $path" - if [[ -z ${seen_dirs[$resolved]+x} ]]; then - seen_dirs[$resolved]=1 - rtl_include_dirs+=("$resolved") - fi -} - -add_rtl_file() { - local base_dir=$1 - local path=$2 - local resolved - - resolved=$(resolve_path "$base_dir" "$path") || fail "RTL source not found: $path" - [[ -f $resolved ]] || fail "RTL source is not a file: $path" - case $resolved in - *.v|*.sv|*.vh|*.svh) ;; - *) - fail "unsupported RTL source: $path" - ;; - esac - - if [[ -z ${seen_files[$resolved]+x} ]]; then - seen_files[$resolved]=1 - rtl_files+=("$resolved") - fi - add_include_dir / "$(dirname -- "$resolved")" -} - -add_rtl_dir() { - local base_dir=$1 - local path=$2 - local recursive=$3 - local resolved - local -a find_depth=() - - resolved=$(resolve_path "$base_dir" "$path") || fail "RTL directory not found: $path" - [[ -d $resolved ]] || fail "RTL path is not a directory: $path" - add_include_dir / "$resolved" - if [[ $recursive == 0 ]]; then - find_depth=(-maxdepth 1) - fi - while IFS= read -r -d '' rtl_file; do - add_rtl_file / "$rtl_file" - done < <( - find "$resolved" "${find_depth[@]}" -type f \ - \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ - -print0 | LC_ALL=C sort -z - ) -} - -parse_filelist() { - local caller_dir=$1 - local path=$2 - local filelist - local filelist_dir - local line - local token - local pending="" - local value - local -a tokens=() - local -a values=() - - filelist=$(resolve_path "$caller_dir" "$path") || - fail "RTL file list not found: $path" - [[ -f $filelist ]] || fail "RTL file list is not a file: $path" - if [[ -n ${active_filelists[$filelist]+x} ]]; then - fail "recursive RTL file list: $filelist" - fi - - active_filelists[$filelist]=1 - filelist_dir=$(dirname -- "$filelist") - # Match -F semantics: relative entries belong to the containing file list. - while IFS= read -r line || [[ -n $line ]]; do - line=${line%$'\r'} - line=${line%%//*} - line=${line%%#*} - read -r -a tokens <<< "$line" - for token in "${tokens[@]}"; do - if [[ -n $pending ]]; then - case $pending in - filelist) parse_filelist "$filelist_dir" "$token" ;; - library) add_rtl_dir "$filelist_dir" "$token" 0 ;; - source) add_rtl_file "$filelist_dir" "$token" ;; - include) add_include_dir "$filelist_dir" "$token" ;; - esac - pending="" - continue - fi - - case $token in - -f|-F) pending=filelist ;; - -y) pending=library ;; - -v) pending=source ;; - -I) pending=include ;; - -f*|-F*) parse_filelist "$filelist_dir" "${token:2}" ;; - -y*) add_rtl_dir "$filelist_dir" "${token:2}" 0 ;; - -v*) add_rtl_file "$filelist_dir" "${token:2}" ;; - -I*) add_include_dir "$filelist_dir" "${token:2}" ;; - +incdir+*) - IFS=+ read -r -a values <<< "${token#+incdir+}" - for value in "${values[@]}"; do - [[ -n $value ]] && add_include_dir "$filelist_dir" "$value" - done - ;; - +libext+*) ;; - *.v|*.sv|*.vh|*.svh) add_rtl_file "$filelist_dir" "$token" ;; - *) fail "unsupported option in $filelist: $token" ;; - esac - done - done < "$filelist" - [[ -z $pending ]] || fail "missing argument after file-list option in $filelist" - unset 'active_filelists[$filelist]' -} - -for rtl_include in "$@"; do - if [[ -d $rtl_include ]]; then - add_rtl_dir "$PWD" "$rtl_include" 1 - elif [[ -f $rtl_include ]]; then - case $rtl_include in - *.f|*.flist|*.list) parse_filelist "$PWD" "$rtl_include" ;; - *) add_rtl_file "$PWD" "$rtl_include" ;; - esac - else - fail "RTL_INCLUDE path not found: $rtl_include" - fi -done - -if [[ -z $output_filelist ]]; then - core_dir=$(realpath -e -- "$core_dir") - find "$core_dir" -path "$core_dir/rtl/verification" -prune -o \ - -type f \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ - -print | LC_ALL=C sort > "$tmp_dir/cpu_files" - : > "$tmp_dir/rtl_files" - : > "$tmp_dir/rtl_include_dirs" - if ((${#rtl_files[@]})); then - printf '%s\n' "${rtl_files[@]}" > "$tmp_dir/rtl_files" - fi - if ((${#rtl_include_dirs[@]})); then - printf '%s\n' "${rtl_include_dirs[@]}" > "$tmp_dir/rtl_include_dirs" - fi - - tmp_output="$tmp_dir/cpu_files.tcl" - awk -v var=cpu_files -v detect_simtop_dma=1 -f "$awk_script" \ - "$tmp_dir/cpu_files" > "$tmp_output" - awk -v var=rtl_include_files -f "$awk_script" \ - "$tmp_dir/rtl_files" >> "$tmp_output" - awk -v var=rtl_include_dirs -f "$awk_script" \ - "$tmp_dir/rtl_include_dirs" >> "$tmp_output" - mkdir -p "$(dirname -- "$output_tcl")" - mv -- "$tmp_output" "$output_tcl" +find "$core_dir" -path "$core_dir/rtl/verification" -prune -o \ + -type f \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ + -print | LC_ALL=C sort > "$tmp_dir/cpu_files" +: > "$tmp_dir/rtl_files" +: > "$tmp_dir/rtl_include_dirs" +if ((${#rtl_flist_files[@]})); then + printf '%s\n' "${rtl_flist_files[@]}" > "$tmp_dir/rtl_files" fi - -if [[ -n $output_filelist ]]; then - tmp_output="$tmp_dir/rtl_include.f" - { - if ((${#rtl_include_dirs[@]})); then - printf '+incdir+%s\n' "${rtl_include_dirs[@]}" - fi - if ((${#rtl_files[@]})); then - printf '%s\n' "${rtl_files[@]}" - fi - } > "$tmp_output" - mkdir -p "$(dirname -- "$output_filelist")" - mv -- "$tmp_output" "$output_filelist" +if ((${#rtl_flist_include_dirs[@]})); then + printf '%s\n' "${rtl_flist_include_dirs[@]}" > "$tmp_dir/rtl_include_dirs" fi -if [[ -z $output_filelist ]]; then - echo "INFO: generated $output_tcl with ${#rtl_files[@]} external RTL files" -fi -if [[ -n $output_filelist ]]; then - echo "INFO: generated $output_filelist with ${#rtl_files[@]} external RTL files" -fi +awk_script="$fpga_diff_dir/core_flist.awk" +output_tcl="$fpga_diff_dir/src/tcl/cpu_files.tcl" +tmp_output="$tmp_dir/cpu_files.tcl" +awk -v var=cpu_files -v detect_simtop_dma=1 -f "$awk_script" \ + "$tmp_dir/cpu_files" > "$tmp_output" +awk -v var=rtl_include_files -f "$awk_script" \ + "$tmp_dir/rtl_files" >> "$tmp_output" +awk -v var=rtl_include_dirs -f "$awk_script" \ + "$tmp_dir/rtl_include_dirs" >> "$tmp_output" +mkdir -p "$(dirname -- "$output_tcl")" +mv -- "$tmp_output" "$output_tcl" + +echo "INFO: generated $output_tcl with ${#rtl_flist_files[@]} external RTL files" diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 80ad22b0..f8070896 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -18,9 +18,9 @@ conversion. The UVHS flow only consumes that result. `RTL_INCLUDE` accepts RTL files, directories, and nested `.f`, `.flist`, or `.list` files. Relative entries are resolved from the file list that contains -them. The common `tools/update_core_flist.sh` parser writes an absolute flat -file list for UVHS while the normal Vivado flow continues to generate -`cpu_files.tcl`. +them. Both build flows use `tools/rtl_filelist_lib.sh` for that parsing. The +normal Vivado wrapper generates `cpu_files.tcl`; the UVHS generator combines +the parsed additions with release RTL and FPGA-Diff wrappers in `filelist.f`. ## Build @@ -39,13 +39,14 @@ make uvhs_package_bitstream CPU= SUFFIX= 1. Copies the vendor board template into an isolated work directory. 2. Prepares repository-owned Vivado IP and the 64-bit generalBus DCP. 3. Imports the selected DDR DCP and validates its AXI width. -4. Builds the complete RTL file list and checks the expected design module. +4. Builds the complete RTL file list and checks the expected top module. 5. Elaborates and synthesizes the design with uvsyn. 6. Registers the DDR instance used by runtime `writemem`. `uvhs_backend` follows the vendor implementation sequence: clock inference and transformation, remap, partition, localization, system routing, FPGA PnR, -timing signoff, bitstream generation, and runtime database commit. +timing signoff, bitstream generation, and runtime database commit. Fill-rate +configuration and automatic partitioning are isolated in `partition.tcl`. The default XiangShan partition limits are 80% LUT and 30% LUT6. They can be changed with `UVHS_LUT_FILL_RATE` and `UVHS_LUT6_FILL_RATE` for placement @@ -100,15 +101,17 @@ or DDR pins. | File | Role | | --- | --- | | `uvhs.mk` | Build, packaging, and runtime targets. | +| `generate_filelist.sh` | Complete UVHS RTL file list generation and top check. | +| `flow_common.tcl` | Shared UVHS path, environment, and source helpers. | | `frontend_run.tcl` | RTL/IP import, elaboration, and uvsyn frontend. | | `backend_run.tcl` | Partition, routing, FPGA PnR, and runtime database commit. | +| `partition.tcl` | Fill-rate validation and automatic partitioning. | | `assemble_uvhs.tcl` | Selects the FPGA set from the vendor board assembly. | | `assign_pin_u22_f2.tcl` | B0/F2 clock, PCIe, UART, JTAG, SD, and control pins. | | `timing_common.tcl` | External clock constraints. | | `async_clocks.tcl` | Asynchronous clock groups used by backend and Vivado PnR. | | `vivado_pre_opt.tcl` | XDMA refclock and CDC constraints. | | `export_vivado_ip.tcl` | Repository-owned Vivado IP export. | -| `check_modules.sh` | Final RTL module check. | | `check_flow_tools.sh` | Shell/Tcl/source validation. | | `shell_compat.sh` | Generated launcher shell correction. | | `uv_shell_exec_compat.sh` | Runtime library wrapper. | diff --git a/fpga_diff/uvhs/assemble_uvhs.tcl b/fpga_diff/uvhs/assemble_uvhs.tcl index f074ebbc..59f47066 100644 --- a/fpga_diff/uvhs/assemble_uvhs.tcl +++ b/fpga_diff/uvhs/assemble_uvhs.tcl @@ -2,20 +2,13 @@ # Reduce the vendor four-FPGA assembly template to the selected UVHS FPGA. ################################################################################ -proc uvhs_env_or_default {name default} { - if {[info exists ::env($name)] && $::env($name) ne ""} { - return $::env($name) - } - return $default -} - set uvhs_base_assemble ./script/1B_4F_HGC_assemble.tcl -set uvhs_target_pack [uvhs_env_or_default UVHS_TARGET_PACK B0] -set uvhs_target_name [uvhs_env_or_default UVHS_TARGET_FPGA F2] +set uvhs_target_pack [uvhs::env_or_default UVHS_TARGET_PACK B0] +set uvhs_target_name [uvhs::env_or_default UVHS_TARGET_FPGA F2] set uvhs_target_fpga [string tolower "$uvhs_target_pack.$uvhs_target_name"] set uvhs_known_fpgas {b0.f0 b0.f1 b0.f2 b0.f3} set uvhs_keep_fpgas {} -foreach uvhs_fpga [split [uvhs_env_or_default UVHS_KEEP_FPGAS $uvhs_target_fpga]] { +foreach uvhs_fpga [split [uvhs::env_or_default UVHS_KEEP_FPGAS $uvhs_target_fpga]] { set uvhs_fpga [string tolower [string trim $uvhs_fpga]] if {$uvhs_fpga ne "" && [lsearch -exact $uvhs_keep_fpgas $uvhs_fpga] < 0} { lappend uvhs_keep_fpgas $uvhs_fpga @@ -63,12 +56,9 @@ foreach uvhs_line [split $uvhs_base_data "\n"] { puts "INFO: UVHS selected-FPGA overlay: remove unused daughter-card instance: $uvhs_trimmed_line" continue } - if {[regexp {^config_hw[ \t]+-unplug_fpga[ \t]+([^ \t]+)} $uvhs_trimmed_line -> uvhs_unplug_fpga]} { - set uvhs_unplug_fpga [string tolower $uvhs_unplug_fpga] - if {[lsearch -exact $uvhs_keep_fpgas $uvhs_unplug_fpga] >= 0} { - puts "INFO: UVHS selected-FPGA overlay: ignore base unplug for kept FPGA $uvhs_unplug_fpga" - continue - } + if {[regexp {^config_hw[ \t]+-unplug_fpga[ \t]+} $uvhs_trimmed_line]} { + puts "INFO: UVHS selected-FPGA overlay: replace base unplug: $uvhs_trimmed_line" + continue } if {[regexp {^config_hw[ \t]+-connect_daughter_card[ \t]+\{([^ \t]+)[ \t]+([^ \t]+)\.FMC\}} $uvhs_trimmed_line -> uvhs_connector uvhs_instance]} { set uvhs_lower_connector [string tolower $uvhs_connector] @@ -119,8 +109,7 @@ foreach uvhs_fpga $uvhs_known_fpgas { set uvhs_create_board_replacements [regsub -line {^(config_hw[ \t]+-create_board_instance[ \t]+1[ \t]*)$} \ $uvhs_base_data "\\1\n$uvhs_unplug_overlay" uvhs_base_data] if {$uvhs_create_board_replacements != 1} { - puts "WARN: UVHS selected-FPGA overlay: failed to insert unplug commands after create_board_instance; prepend overlay" - set uvhs_base_data "$uvhs_unplug_overlay\n$uvhs_base_data" + error "unexpected UVHS assembly template: create_board_instance marker not found" } set uvhs_overlay_file [file join [pwd] script .uvhs_assemble.tcl] diff --git a/fpga_diff/uvhs/backend_run.tcl b/fpga_diff/uvhs/backend_run.tcl index ee0fe42c..34bc6b3c 100644 --- a/fpga_diff/uvhs/backend_run.tcl +++ b/fpga_diff/uvhs/backend_run.tcl @@ -2,47 +2,11 @@ # UVHS backend flow for fpga_diff. ################################################################################ -proc env_or_default {name default} { - if {[info exists ::env($name)] && $::env($name) ne ""} { - return $::env($name) - } - return $default -} - -proc source_required {file} { - if {![file exists $file]} { - error "required UVHS flow file not found: $file" - } - puts "INFO: source $file" - uplevel #0 [list source $file] -} - -proc configure_fill_rates {} { - set args {} - foreach {option variable} { - -lut UVHS_LUT_FILL_RATE - -lut6 UVHS_LUT6_FILL_RATE - } { - set value [env_or_default $variable ""] - if {$value eq ""} { - continue - } - if {![string is double -strict $value] || $value <= 0 || $value > 100} { - error "$variable must be in (0, 100], got '$value'" - } - lappend args $option $value - } - if {[llength $args]} { - puts "INFO: set UVHS fill rates: $args" - set_fill_rate {*}$args - } -} - -set uvhs_script_dir [file dirname [file normalize [info script]]] +source [file join [file dirname [file normalize [info script]]] flow_common.tcl] set_working_space hw.dat -set fpga_threads [env_or_default UVHS_FPGA_THREADS 8] -set fpga_processes [env_or_default UVHS_FPGA_PROCESSES 16] +set fpga_threads [uvhs::env_or_default UVHS_FPGA_THREADS 8] +set fpga_processes [uvhs::env_or_default UVHS_FPGA_PROCESSES 16] set_parallel_option -max_threads $fpga_threads \ -max_processes $fpga_processes -label fpga @@ -53,12 +17,12 @@ set_option clock.async_control.force_accept true set_option time.enable_sign_off true set_option time.incremental_sign_off true -set platform [env_or_default PLATFORM U2.2] +set platform [uvhs::env_or_default PLATFORM U2.2] create_system_design -name VU19P_X4 -platform $platform -source_required [file join $uvhs_script_dir assemble_uvhs.tcl] +uvhs::source_required assemble_uvhs.tcl set ::env(UVHS_ASSIGN_PIN_TOP) none -source_required [file join $uvhs_script_dir assign_pin_u22_f2.tcl] +uvhs::source_required assign_pin_u22_f2.tcl unset ::env(UVHS_ASSIGN_PIN_TOP) create_design -name test @@ -76,18 +40,14 @@ sweep_design infer_clock report_clock -inferred transform_clock -source_required [file join $uvhs_script_dir async_clocks.tcl] -configure_fill_rates +uvhs::source_required async_clocks.tcl +uvhs::source_required partition.tcl +uvhs::configure_fill_rates trigger_probe -group sweep_design -remap report_clock -check_design -report_resource -depth 4 -report_system_resource -list_partition_constraints -all -partition_design -tdc -tdss true -report_resource -depth 4 +uvhs::run_partition instrument_design localize_design -replicate_cell -clock -self_check @@ -107,12 +67,12 @@ save_runtime_data set_option compile.resourceUsageLimit 100 set_option compile.strategyNum 1 set_option compile.strategy0 \ - [env_or_default UVHS_COMPILE_STRATEGY uv_high_fanout_explore] + [uvhs::env_or_default UVHS_COMPILE_STRATEGY uv_high_fanout_explore] set_option compile.stage.preOpt \ - [file join $uvhs_script_dir vivado_pre_opt.tcl] + [uvhs::path vivado_pre_opt.tcl] compile_fpga -parallel_option fpga -genScriptOnly -explore -set shell_helper [file join $uvhs_script_dir shell_compat.sh] +set shell_helper [uvhs::path shell_compat.sh] if {![file isfile $shell_helper]} { error "UVHS shell compatibility helper not found: $shell_helper" } diff --git a/fpga_diff/uvhs/check_flow_tools.sh b/fpga_diff/uvhs/check_flow_tools.sh index 48acea16..ba29282f 100644 --- a/fpga_diff/uvhs/check_flow_tools.sh +++ b/fpga_diff/uvhs/check_flow_tools.sh @@ -6,17 +6,20 @@ root_dir="$(cd "$script_dir/.." && pwd)" required=( Makefile + tools/rtl_filelist_lib.sh uvhs/uvhs.mk uvhs/README.md + uvhs/flow_common.tcl uvhs/frontend_run.tcl uvhs/backend_run.tcl + uvhs/partition.tcl uvhs/assemble_uvhs.tcl uvhs/assign_pin_u22_f2.tcl uvhs/async_clocks.tcl uvhs/timing_common.tcl uvhs/vivado_pre_opt.tcl uvhs/export_vivado_ip.tcl - uvhs/check_modules.sh + uvhs/generate_filelist.sh uvhs/shell_compat.sh uvhs/enqueue_runtime_command.sh uvhs/runtime_session.sh @@ -35,8 +38,9 @@ for path in "${required[@]}"; do } done -bash -n "$root_dir/uvhs/check_modules.sh" bash -n "$root_dir/uvhs/check_flow_tools.sh" +bash -n "$root_dir/tools/rtl_filelist_lib.sh" +bash -n "$root_dir/uvhs/generate_filelist.sh" bash -n "$root_dir/uvhs/shell_compat.sh" bash -n "$root_dir/uvhs/enqueue_runtime_command.sh" bash -n "$root_dir/uvhs/runtime_session.sh" diff --git a/fpga_diff/uvhs/check_modules.sh b/fpga_diff/uvhs/check_modules.sh deleted file mode 100755 index 357ef4a5..00000000 --- a/fpga_diff/uvhs/check_modules.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -filelist=${1:-} -required_modules=${2:-} - -if [[ -z "$filelist" || ! -f "$filelist" ]]; then - echo "Verilog filelist not found: $filelist" >&2 - exit 2 -fi - -if [[ -z "$required_modules" ]]; then - echo "No required modules configured; skip module check." - exit 0 -fi - -tmp_sources=$(mktemp) -trap 'rm -f "$tmp_sources"' EXIT - -awk 'NF && $0 !~ /^\+/ { print }' "$filelist" > "$tmp_sources" - -missing=0 -for module_name in $required_modules; do - found=0 - while IFS= read -r source_file; do - [[ -f "$source_file" ]] || continue - if grep -Eq "^[[:space:]]*module[[:space:]]+$module_name([[:space:]#(]|$)" "$source_file"; then - found=1 - break - fi - done < "$tmp_sources" - - if [[ "$found" == 1 ]]; then - echo "Found required module: $module_name" - else - echo "Missing required module: $module_name" >&2 - missing=1 - fi -done - -if [[ "$missing" != 0 ]]; then - echo "Required module check failed for $filelist" >&2 - exit 1 -fi diff --git a/fpga_diff/uvhs/flow_common.tcl b/fpga_diff/uvhs/flow_common.tcl new file mode 100644 index 00000000..79ab6748 --- /dev/null +++ b/fpga_diff/uvhs/flow_common.tcl @@ -0,0 +1,24 @@ +namespace eval uvhs { + variable script_dir [file dirname [file normalize [info script]]] + + proc path {name} { + variable script_dir + return [file join $script_dir $name] + } + + proc env_or_default {name default} { + if {[info exists ::env($name)] && $::env($name) ne ""} { + return $::env($name) + } + return $default + } + + proc source_required {name} { + set file [path $name] + if {![file exists $file]} { + error "required UVHS flow file not found: $file" + } + puts "INFO: source $file" + uplevel #0 [list source $file] + } +} diff --git a/fpga_diff/uvhs/frontend_run.tcl b/fpga_diff/uvhs/frontend_run.tcl index fe1fc8bd..a072bb6f 100644 --- a/fpga_diff/uvhs/frontend_run.tcl +++ b/fpga_diff/uvhs/frontend_run.tcl @@ -2,22 +2,9 @@ # UVHS frontend flow for fpga_diff. ################################################################################ -proc env_or_default {name default} { - if {[info exists ::env($name)] && $::env($name) ne ""} { - return $::env($name) - } - return $default -} - -proc source_required {file} { - if {![file exists $file]} { - error "required UVHS flow file not found: $file" - } - puts "INFO: source $file" - uplevel #0 [list source $file] -} +source [file join [file dirname [file normalize [info script]]] flow_common.tcl] -proc import_blackbox {module dcp args} { +proc uvhs::import_blackbox {module dcp args} { if {![file exists $dcp] || [file size $dcp] == 0} { error "required blackbox DCP missing or empty for $module: $dcp" } @@ -26,7 +13,7 @@ proc import_blackbox {module dcp args} { uplevel #0 [concat [list set_blackbox -module $module -source_file $dcp] $args] } -proc import_ip {module dcp stub args} { +proc uvhs::import_ip {module dcp stub args} { foreach {kind file} [list DCP $dcp stub $stub] { if {![file exists $file] || [file size $file] == 0} { error "required $module $kind missing or empty: $file" @@ -39,7 +26,7 @@ proc import_ip {module dcp stub args} { read_verilog $stub } -proc append_option_once {file line} { +proc uvhs::append_option_once {file line} { set data "" if {[file exists $file]} { set input [open $file r] @@ -62,7 +49,7 @@ proc append_option_once {file line} { # UVHS runtime writemem discovers backdoor instances from these database files; # the installed release does not expose an equivalent frontend Tcl command. -proc register_runtime_memory {working_space inst_path} { +proc uvhs::register_runtime_memory {working_space inst_path} { if {$inst_path eq "" || $inst_path eq "none"} { return } @@ -74,8 +61,8 @@ proc register_runtime_memory {working_space inst_path} { puts "INFO: registered UVHS runtime memory instance $inst_path" } -proc start_frontend_shell_compat {} { - set helper [file join $::uvhs_script_dir shell_compat.sh] +proc uvhs::start_frontend_shell_compat {} { + set helper [uvhs::path shell_compat.sh] if {![file isfile $helper]} { error "UVHS shell compatibility helper not found: $helper" } @@ -84,12 +71,11 @@ proc start_frontend_shell_compat {} { puts "INFO: started UVHS frontend shell compatibility helper" } -set ::uvhs_script_dir [file dirname [file normalize [info script]]] create_working_space hw.dat set_option syn.computeFeCheckSum true -set frontend_threads [env_or_default UVHS_FRONTEND_THREADS 16] -set frontend_processes [env_or_default UVHS_FRONTEND_PROCESSES 64] +set frontend_threads [uvhs::env_or_default UVHS_FRONTEND_THREADS 16] +set frontend_processes [uvhs::env_or_default UVHS_FRONTEND_PROCESSES 64] set_parallel_option -max_threads $frontend_threads \ -max_processes $frontend_processes -label frontend @@ -105,26 +91,26 @@ set_option time.enable_sign_off true set_option time.incremental_sign_off true set_option signal.uhd.sampling_clock.allow_local_clock true -set platform [env_or_default PLATFORM U2.2] +set platform [uvhs::env_or_default PLATFORM U2.2] set design_top fpga_top_debug set ddr_inst_path ${design_top}.core_def.U_UVHS_UVW_AXI4_TO_DDR4 create_system_design -name VU19P_X4 -platform $platform -source_required [file join $::uvhs_script_dir assemble_uvhs.tcl] -source_required [file join $::uvhs_script_dir assign_pin_u22_f2.tcl] -set_constraint_files [file join $::uvhs_script_dir timing_common.tcl] +uvhs::source_required assemble_uvhs.tcl +uvhs::source_required assign_pin_u22_f2.tcl +set_constraint_files [uvhs::path timing_common.tcl] foreach reset_port {rstn_sw6 rstn_sw5 rstn_sw4} { create_reset -port ${design_top}.${reset_port} -active 0 } -import_blackbox blk_mem_gen_0 ./rtl/soc/blk_mem_gen_0.dcp -import_blackbox AXI_bridge ./rtl/soc/AXI_bridge.dcp -import_blackbox data_bridge ./rtl/soc/data_bridge.dcp -import_blackbox xdma_ep ./rtl/device/pcie/xdma_ep.dcp -import_blackbox uvw_general_bus \ +uvhs::import_blackbox blk_mem_gen_0 ./rtl/soc/blk_mem_gen_0.dcp +uvhs::import_blackbox AXI_bridge ./rtl/soc/AXI_bridge.dcp +uvhs::import_blackbox data_bridge ./rtl/soc/data_bridge.dcp +uvhs::import_blackbox xdma_ep ./rtl/device/pcie/xdma_ep.dcp +uvhs::import_blackbox uvw_general_bus \ ./rtl/soc/uvw_general_bus/uvw_general_bus.dcp \ -clock_enable_pairs {dut_axi_aclk dut_axi_aclk_en 1} -import_ip uvw_axi4_to_ddr4 ./rtl/soc/uvw_axi4_to_ddr4.dcp \ +uvhs::import_ip uvw_axi4_to_ddr4 ./rtl/soc/uvw_axi4_to_ddr4.dcp \ ./rtl/soc/uvw_axi4_to_ddr4_Stub.v \ -clock_enable_pairs {ddr4ip_dut_axi_aclk ddr4ip_dut_axi_aclk_en 1} \ -script_file {prePlace ./script/uvw_axi4_to_ddr4_pblock.tcl} @@ -135,9 +121,9 @@ if {![file exists $filelist]} { } read_verilog -f $filelist -mfcu elaborate_design $design_top -start_frontend_shell_compat +uvhs::start_frontend_shell_compat synthesize_design -parallel_option frontend save_working_space -register_runtime_memory hw.dat $ddr_inst_path +uvhs::register_runtime_memory hw.dat $ddr_inst_path puts "UVHS_FRONTEND_SUCCESS" exit diff --git a/fpga_diff/uvhs/generate_filelist.sh b/fpga_diff/uvhs/generate_filelist.sh new file mode 100755 index 00000000..2d25a919 --- /dev/null +++ b/fpga_diff/uvhs/generate_filelist.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +set -euo pipefail + +usage() { + echo "Usage: $0 CORE_BUILD_DIR UVHS_WORK_DIR CPU OUTPUT [--] [RTL_INCLUDE ...]" >&2 + exit 2 +} + +[[ $# -ge 4 ]] || usage +core_dir=$(realpath -e -- "$1") +work_dir=$(realpath -e -- "$2") +cpu=$3 +output=$4 +shift 4 +if [[ ${1:-} == -- ]]; then + shift +fi + +script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) +fpga_diff_dir=$(cd -- "$script_dir/.." && pwd) +source "$fpga_diff_dir/tools/rtl_filelist_lib.sh" +rtl_flist_parse_inputs "$PWD" "$@" + +core_rtl_dir="$core_dir/rtl" +core_generated_dir="$core_dir/generated-src" +[[ -d $core_rtl_dir ]] || rtl_flist_fail "FPGA release RTL not found: $core_rtl_dir" + +mkdir -p "$(dirname -- "$output")" +tmp_dir=$(mktemp -d) +trap 'rm -rf "$tmp_dir"' EXIT +tmp_output="$tmp_dir/filelist.f" + +{ + printf '+define+SYNTHESIS\n+define+XIANGSHAN_FPGA\n+define+UVHS\n' + printf '+define+DDR4_16G_X8\n+define+DQ64\n+define+DDR4_2400\n' + printf '+define+DQ=64\n+define+MICRON_DDR\n+define+DDR4_16Gbx8\n' + printf '+define+DDR4\n+define+SRAM_SYN\n+define+DATA_VERSION=0\n' + if [[ $cpu == nutshell ]]; then + printf '+define+CPU_NUTSHELL\n' + fi + if [[ $cpu == kmh ]] && + grep -Eq '^[[:space:]]*(input|output)[[:space:]].*dma_awready' "$core_rtl_dir/SimTop.sv"; then + printf '+define+CONFIG_SIMTOP_HAS_DMA\n' + fi + + printf '+incdir+%s\n' "$core_dir" "$core_rtl_dir" + if [[ -d $core_generated_dir ]]; then + printf '+incdir+%s\n' "$core_generated_dir" + fi + printf '+incdir+%s/src/rtl/common\n' "$fpga_diff_dir" + + find "$fpga_diff_dir/src/rtl/common" -type f \ + \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ + ! -name 'u0_xdma.v' -print | LC_ALL=C sort + if [[ -d $work_dir/rtl/stubs ]]; then + find "$work_dir/rtl/stubs" -type f -name '*.v' -print | LC_ALL=C sort + fi + if [[ -d $fpga_diff_dir/src/rtl/$cpu ]]; then + find "$fpga_diff_dir/src/rtl/$cpu" -type f \ + \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ + -print | LC_ALL=C sort + fi + find "$core_rtl_dir" -type f \ + \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ + -print | LC_ALL=C sort + if ((${#rtl_flist_include_dirs[@]})); then + printf '+incdir+%s\n' "${rtl_flist_include_dirs[@]}" + fi + if ((${#rtl_flist_files[@]})); then + printf '%s\n' "${rtl_flist_files[@]}" + fi +} > "$tmp_output" + +mv -- "$tmp_output" "$output" + +case $cpu in + kmh|nutshell) required_modules=(SimTop) ;; + nanhu) required_modules=(XlnFpgaTop) ;; + *) required_modules=() ;; +esac + +for module_name in "${required_modules[@]}"; do + found=0 + while IFS= read -r source_file; do + [[ $source_file != +* && -f $source_file ]] || continue + if grep -Eq "^[[:space:]]*module[[:space:]]+$module_name([[:space:]#(]|$)" "$source_file"; then + found=1 + break + fi + done < "$output" + [[ $found == 1 ]] || rtl_flist_fail "required module not found: $module_name" + echo "INFO: found required module: $module_name" +done + +echo "INFO: generated UVHS file list $output" diff --git a/fpga_diff/uvhs/partition.tcl b/fpga_diff/uvhs/partition.tcl new file mode 100644 index 00000000..a18c2d37 --- /dev/null +++ b/fpga_diff/uvhs/partition.tcl @@ -0,0 +1,31 @@ +namespace eval uvhs { + proc configure_fill_rates {} { + set args {} + foreach {option variable} { + -lut UVHS_LUT_FILL_RATE + -lut6 UVHS_LUT6_FILL_RATE + } { + set value [env_or_default $variable ""] + if {$value eq ""} { + continue + } + if {![string is double -strict $value] || $value <= 0 || $value > 100} { + error "$variable must be in (0, 100], got '$value'" + } + lappend args $option $value + } + if {[llength $args]} { + puts "INFO: set UVHS fill rates: $args" + set_fill_rate {*}$args + } + } + + proc run_partition {} { + check_design + report_resource -depth 4 + report_system_resource + list_partition_constraints -all + partition_design -tdc -tdss true + report_resource -depth 4 + } +} diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 636d58c6..21588b0d 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -6,9 +6,6 @@ UVHS_UVW_AXI4_TO_DDR4_SRC ?= UVHS_DDR_AXI_WIDTH := $(if $(filter nutshell,$(CPU)),64,256) UVHS_WORK_DIR ?= $(ENV_SCRIPTS_HOME)/fpga_diff_uvhs_$(CPU)$(if $(strip $(SUFFIX)),-$(strip $(SUFFIX)),) UVHS_FILELIST := $(UVHS_WORK_DIR)/rtl/filelist.f -UVHS_RTL_INCLUDE_FILELIST := $(UVHS_WORK_DIR)/rtl/rtl_include.f -UVHS_CORE_RTL_DIR := $(CORE_DIR)/rtl -UVHS_CORE_GENERATED_SRC_DIR := $(CORE_DIR)/generated-src UVHS_EXPORT_IP_FORCE ?= 0 UVHS_EXPORT_IP_JOBS := $(if $(strip $(VIVADO_JOBS)),$(VIVADO_JOBS),8) @@ -43,7 +40,6 @@ UVHS_UVW_AXI4_TO_DDR4_REQUIRED_FILES := \ rtl/soc/uvw_axi4_to_ddr4.dcp \ rtl/soc/uvw_axi4_to_ddr4_Stub.v \ script/uvw_axi4_to_ddr4_pblock.tcl -UVHS_REQUIRED_MODULES := $(if $(filter nanhu,$(CPU)),XlnFpgaTop,$(if $(filter kmh nutshell,$(CPU)),SimTop,)) UVHS_DDR_RTL_INST := fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4 UVHS_RUNTIME_LIB_DIR := $(UVHS_WORK_DIR)/.uvhs-runtime-lib UVHS_RUNTIME_DB := $(UVHS_WORK_DIR)/hw.dat @@ -84,8 +80,8 @@ UVHS_BITSTREAM_DIR := $(UVHS_PNR_DIR)/bitstream UVHS_BIT_HOME ?= $(UVHS_WORK_DIR)/ready-to-program .PHONY: uvhs_preflight uvhs_prepare \ - uvhs_export_vivado_ip uvhs_export_generalbus uvhs_normalize_rtl_include \ - uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist uvhs_check_modules \ + uvhs_export_vivado_ip uvhs_export_generalbus \ + uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist \ uvhs_frontend uvhs_backend uvhs_all uvhs_check_timing \ uvhs_package_bitstream uvhs_tools_check uvhs_clean uvhs_write_bitstream \ uvhs_halt_soc uvhs_reset_cpu uvhs_write_ddr uvhs_write_flash \ @@ -193,12 +189,6 @@ uvhs_export_generalbus: uvhs_prepare "$(UVHS_WORK_DIR)/rtl/stubs/uvw_general_bus.v"; \ echo "INFO: prepared 64-bit UVHS generalBus DCP"' -uvhs_normalize_rtl_include: uvhs_prepare - mkdir -p "$(dir $(UVHS_RTL_INCLUDE_FILELIST))" - bash "$(UVHS_ROOT_DIR)/tools/update_core_flist.sh" "$(CORE_DIR)" \ - --output-filelist "$(UVHS_RTL_INCLUDE_FILELIST)" \ - -- $(RTL_INCLUDE) - uvhs_sync_uvw_axi4_to_ddr4: uvhs_prepare bash -c 'set -euo pipefail; \ src="$(UVHS_UVW_AXI4_TO_DDR4_SRC)"; work="$(UVHS_WORK_DIR)"; \ @@ -221,48 +211,12 @@ uvhs_sync_uvw_axi4_to_ddr4: uvhs_prepare grep -Eq "output[[:space:]]+\\[$$last_bit:0\\][[:space:]]*ddr4ip_dut_axi_rdata" "$$stub"; \ echo "INFO: verified UVHS DDR DCP AXI data width: $$expected_width"' -uvhs_filelist: uvhs_export_generalbus uvhs_normalize_rtl_include - test -d "$(UVHS_CORE_RTL_DIR)" - mkdir -p "$(dir $(UVHS_FILELIST))" - { \ - printf '+define+SYNTHESIS\n+define+XIANGSHAN_FPGA\n'; \ - printf '+define+UVHS\n'; \ - printf '+define+DDR4_16G_X8\n+define+DQ64\n+define+DDR4_2400\n'; \ - printf '+define+DQ=64\n+define+MICRON_DDR\n+define+DDR4_16Gbx8\n'; \ - printf '+define+DDR4\n+define+SRAM_SYN\n+define+DATA_VERSION=0\n'; \ - if [ "$(CPU)" = nutshell ]; then printf '+define+CPU_NUTSHELL\n'; fi; \ - if [ "$(CPU)" = kmh ]; then \ - simtop=""; \ - for candidate in "$(UVHS_CORE_RTL_DIR)/SimTop.sv"; do \ - if [ -f "$$candidate" ]; then simtop="$$candidate"; break; fi; \ - done; \ - if [ -n "$$simtop" ] && \ - grep -Eq '^[[:space:]]*(input|output)[[:space:]].*dma_awready' "$$simtop"; then \ - printf '+define+CONFIG_SIMTOP_HAS_DMA\n'; \ - fi; \ - fi; \ - printf '+incdir+%s\n' "$(CORE_DIR)"; \ - if [ -d "$(UVHS_CORE_RTL_DIR)" ]; then printf '+incdir+%s\n' "$(UVHS_CORE_RTL_DIR)"; fi; \ - if [ -d "$(UVHS_CORE_GENERATED_SRC_DIR)" ]; then printf '+incdir+%s\n' "$(UVHS_CORE_GENERATED_SRC_DIR)"; fi; \ - printf '+incdir+%s/src/rtl/common\n' "$(UVHS_ROOT_DIR)"; \ - find "$(UVHS_ROOT_DIR)/src/rtl/common" -type f \ - \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ - ! -name 'u0_xdma.v' -print | sort; \ - test ! -d "$(UVHS_WORK_DIR)/rtl/stubs" || \ - find "$(UVHS_WORK_DIR)/rtl/stubs" -type f -name '*.v' -print | sort; \ - test ! -d "$(UVHS_ROOT_DIR)/src/rtl/$(CPU)" || \ - find "$(UVHS_ROOT_DIR)/src/rtl/$(CPU)" -type f \ - \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ - find "$(UVHS_CORE_RTL_DIR)" -type f \ - \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) -print | sort; \ - test ! -f "$(UVHS_RTL_INCLUDE_FILELIST)" || cat "$(UVHS_RTL_INCLUDE_FILELIST)"; \ - } | awk 'NF' > "$(UVHS_FILELIST)" - -uvhs_check_modules: uvhs_filelist - bash "$(UVHS_ROOT_DIR)/uvhs/check_modules.sh" "$(UVHS_FILELIST)" "$(UVHS_REQUIRED_MODULES)" +uvhs_filelist: uvhs_export_vivado_ip uvhs_export_generalbus + bash "$(UVHS_ROOT_DIR)/uvhs/generate_filelist.sh" \ + "$(CORE_DIR)" "$(UVHS_WORK_DIR)" "$(CPU)" "$(UVHS_FILELIST)" \ + -- $(RTL_INCLUDE) -uvhs_frontend: uvhs_export_vivado_ip uvhs_export_generalbus \ - uvhs_sync_uvw_axi4_to_ddr4 uvhs_check_modules +uvhs_frontend: uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ $(UVHS_FLOW_ENV) \ UVHS_FRONTEND_THREADS="$(UVHS_FRONTEND_THREADS)" UVHS_FRONTEND_PROCESSES="$(UVHS_FRONTEND_PROCESSES)" \ From 7a1d68e96bf4251cbfe48d92c02e74c2d8107ffc Mon Sep 17 00:00:00 2001 From: klin02 Date: Sun, 2 Aug 2026 20:15:23 +0800 Subject: [PATCH 12/62] refactor(fpga_diff): expose stable UVHS targets Add uvhs and uvhs_bitstream as the stable build entry points so upper-level callers can mirror the normal project and bitstream sequence. Keep detailed stages available for reuse and serialize the compatibility pipeline under parallel make. Document how shared RTL_INCLUDE parsing feeds the different Vivado Tcl and UVHS flat-file consumers. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 19 +++++++++++++++---- fpga_diff/uvhs/uvhs.mk | 13 +++++++++++-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index f8070896..1956b1ff 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -22,17 +22,28 @@ them. Both build flows use `tools/rtl_filelist_lib.sh` for that parsing. The normal Vivado wrapper generates `cpu_files.tcl`; the UVHS generator combines the parsed additions with release RTL and FPGA-Diff wrappers in `filelist.f`. +| File-list stage | Vivado | UVHS | +| --- | --- | --- | +| Shared input | `CORE_DIR` and optional `RTL_INCLUDE` | `CORE_DIR` and optional `RTL_INCLUDE` | +| Core files | Scans the complete release build, excluding `rtl/verification` | Reads release `rtl/` and optional `generated-src/` headers | +| Board wrappers and IP | Added later by `xs_uart.tcl` from Tcl lists | Written directly into the complete UVHS `filelist.f` | +| Output | Tcl variables in `src/tcl/cpu_files.tcl` | Flat uvsyn input in `/rtl/filelist.f` | +| Consumer | Vivado project creation | UVHS `read_verilog -f` | + ## Build ```sh make uvhs_tools_check -make uvhs_frontend CPU= CORE_DIR=/path/to/release/build \ +make uvhs CPU= CORE_DIR=/path/to/release/build \ RTL_INCLUDE=/path/to/extra.f SUFFIX= -make uvhs_backend CPU= SUFFIX= -make uvhs_package_bitstream CPU= SUFFIX= +make uvhs_bitstream CPU= SUFFIX= ``` -`RTL_INCLUDE` is optional. `uvhs_all` runs frontend and backend in sequence. +`RTL_INCLUDE` is optional. These are the two stable build entry points intended +for an upper-level build system: `uvhs` prepares and synthesizes the UVHS +database, while `uvhs_bitstream` runs backend implementation, checks timing, +and publishes `fpga_top_debug.bit`. The lower-level `uvhs_frontend` and +`uvhs_backend` targets remain available for stage reuse and debugging. `uvhs_frontend` performs these steps: diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 21588b0d..07ee8e19 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -79,7 +79,7 @@ UVHS_PNR_DIR := $(UVHS_WORK_DIR)/hw.dat/Compile/PnR/$(UVHS_TARGET_PACK)/$(UVHS_T UVHS_BITSTREAM_DIR := $(UVHS_PNR_DIR)/bitstream UVHS_BIT_HOME ?= $(UVHS_WORK_DIR)/ready-to-program -.PHONY: uvhs_preflight uvhs_prepare \ +.PHONY: uvhs uvhs_bitstream uvhs_preflight uvhs_prepare \ uvhs_export_vivado_ip uvhs_export_generalbus \ uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist \ uvhs_frontend uvhs_backend uvhs_all uvhs_check_timing \ @@ -224,6 +224,9 @@ uvhs_frontend: uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist -s "$(UVHS_ROOT_DIR)/uvhs/frontend_run.tcl" |& tee frontend_run.log; \ grep -Fxq UVHS_FRONTEND_SUCCESS frontend_run.log' +# Stable frontend entry point, analogous to the normal `all` project setup. +uvhs: uvhs_frontend + uvhs_backend: bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ $(UVHS_FLOW_ENV) \ @@ -232,7 +235,9 @@ uvhs_backend: -s "$(UVHS_ROOT_DIR)/uvhs/backend_run.tcl" |& tee backend_run.log; \ grep -Fxq UVHS_BACKEND_SUCCESS backend_run.log' -uvhs_all: uvhs_frontend uvhs_backend +# Keep the compatibility target serial even when the caller enables make -j. +uvhs_all: uvhs + $(MAKE) uvhs_backend uvhs_check_timing: test -f "$(UVHS_BITSTREAM_DIR)/after_xtalk_fix_timing_summary.txt" @@ -244,6 +249,10 @@ uvhs_package_bitstream: uvhs_check_timing ln -sf "$(UVHS_BITSTREAM_DIR)/pnr.bit" "$(UVHS_BIT_HOME)/fpga_top_debug.bit" @echo "FPGA_BIT_HOME=$(UVHS_BIT_HOME)" +# Stable implementation entry point, analogous to the normal `bitstream` target. +uvhs_bitstream: uvhs_backend + $(MAKE) uvhs_package_bitstream + # The UVHS API requires one session to retain ownership of the downloaded # database. Detach that session after programming and track it in runtime-work. uvhs_write_bitstream: From 23d49699c93526b483eef93f70b4a5a2965ded29 Mon Sep 17 00:00:00 2001 From: klin02 Date: Sun, 2 Aug 2026 22:00:51 +0800 Subject: [PATCH 13/62] refactor(fpga_diff): consolidate UVHS scripts Unify Vivado and UVHS file-list generation while preserving their output contracts. Fold partition setup into the backend driver and runtime command submission into the session manager. Rename board setup around topology and pin assignment, remove the redundant source-check target, and reduce UVHS tuning inputs to the validated flow controls. Co-authored-by: Kamimiao --- fpga_diff/Makefile | 2 +- fpga_diff/README.md | 8 +- fpga_diff/tools/generate_rtl_filelist.sh | 165 ++++++++++++++++++ fpga_diff/tools/update_core_flist.sh | 53 ------ fpga_diff/uvhs/README.md | 28 ++- .../{assign_pin_u22_f2.tcl => assign_pin.tcl} | 2 +- fpga_diff/uvhs/backend_run.tcl | 39 +++-- fpga_diff/uvhs/check_flow_tools.sh | 67 ------- fpga_diff/uvhs/enqueue_runtime_command.sh | 83 --------- fpga_diff/uvhs/frontend_run.tcl | 9 +- fpga_diff/uvhs/generate_filelist.sh | 96 ---------- fpga_diff/uvhs/hw_run_download.tcl | 110 +++++++++++- fpga_diff/uvhs/partition.tcl | 31 ---- fpga_diff/uvhs/runtime_command.tcl | 5 - fpga_diff/uvhs/runtime_control.tcl | 110 ------------ fpga_diff/uvhs/runtime_session.sh | 67 +++++++ fpga_diff/uvhs/timing_common.tcl | 6 +- .../uvhs/{assemble_uvhs.tcl => topology.tcl} | 6 +- fpga_diff/uvhs/uvhs.mk | 64 ++----- 19 files changed, 406 insertions(+), 545 deletions(-) create mode 100755 fpga_diff/tools/generate_rtl_filelist.sh delete mode 100755 fpga_diff/tools/update_core_flist.sh rename fpga_diff/uvhs/{assign_pin_u22_f2.tcl => assign_pin.tcl} (98%) delete mode 100644 fpga_diff/uvhs/check_flow_tools.sh delete mode 100755 fpga_diff/uvhs/enqueue_runtime_command.sh delete mode 100755 fpga_diff/uvhs/generate_filelist.sh delete mode 100644 fpga_diff/uvhs/partition.tcl delete mode 100644 fpga_diff/uvhs/runtime_control.tcl rename fpga_diff/uvhs/{assemble_uvhs.tcl => topology.tcl} (94%) diff --git a/fpga_diff/Makefile b/fpga_diff/Makefile index 200789b8..a819cac4 100755 --- a/fpga_diff/Makefile +++ b/fpga_diff/Makefile @@ -42,7 +42,7 @@ bitstream: # RTL_INCLUDE accepts RTL files, directories, and .f/.flist/.list file lists. update_core_flist: - @./tools/update_core_flist.sh "$(CORE_DIR)" -- $(RTL_INCLUDE) + @./tools/generate_rtl_filelist.sh vivado "$(CORE_DIR)" -- $(RTL_INCLUDE) # Launch Vivado with FPGA project configuration vivado: check_vivado_version diff --git a/fpga_diff/README.md b/fpga_diff/README.md index 1811b8c5..38077e2a 100755 --- a/fpga_diff/README.md +++ b/fpga_diff/README.md @@ -56,9 +56,9 @@ unchanged. Configure the UVHS tool environment in the runtime host shell, then invoke: ```shell -make uvhs_preflight CPU= -make uvhs_all CPU= CORE_DIR=/path/to/generated/core SUFFIX= +make uvhs CPU= CORE_DIR=/path/to/release/build SUFFIX= +make uvhs_bitstream CPU= SUFFIX= ``` -See [`uvhs/README.md`](uvhs/README.md) for the required environment variables, -board template and vendor DDR IP inputs, stages, and runtime script. +See [`uvhs/README.md`](uvhs/README.md) for the board-template and vendor-DDR +inputs, build stages, and runtime commands. diff --git a/fpga_diff/tools/generate_rtl_filelist.sh b/fpga_diff/tools/generate_rtl_filelist.sh new file mode 100755 index 00000000..5b930a9d --- /dev/null +++ b/fpga_diff/tools/generate_rtl_filelist.sh @@ -0,0 +1,165 @@ +#!/usr/bin/env bash + +set -euo pipefail + +usage() { + cat >&2 <<'EOF' +Usage: + generate_rtl_filelist.sh vivado CORE_DIR [--] [RTL_INCLUDE ...] + generate_rtl_filelist.sh uvhs CORE_DIR WORK_DIR CPU OUTPUT [--] [RTL_INCLUDE ...] +EOF + exit 2 +} + +script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) +fpga_diff_dir=$(cd -- "$script_dir/.." && pwd) +source "$script_dir/rtl_filelist_lib.sh" + +generate_vivado_filelist() { + local core_dir=$1 + local output=$fpga_diff_dir/src/tcl/cpu_files.tcl + local tmp_dir + local tmp_output + shift + + [[ -d $core_dir ]] || rtl_flist_fail "CORE_DIR is not a directory: $core_dir" + core_dir=$(realpath -e -- "$core_dir") + rtl_flist_parse_inputs "$PWD" "$@" + + tmp_dir=$(mktemp -d) + trap 'rm -rf "$tmp_dir"' RETURN + find "$core_dir" -path "$core_dir/rtl/verification" -prune -o \ + -type f \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ + -print | LC_ALL=C sort > "$tmp_dir/cpu_files" + : > "$tmp_dir/rtl_files" + : > "$tmp_dir/rtl_include_dirs" + if ((${#rtl_flist_files[@]})); then + printf '%s\n' "${rtl_flist_files[@]}" > "$tmp_dir/rtl_files" + fi + if ((${#rtl_flist_include_dirs[@]})); then + printf '%s\n' "${rtl_flist_include_dirs[@]}" > "$tmp_dir/rtl_include_dirs" + fi + + tmp_output=$tmp_dir/cpu_files.tcl + awk -v var=cpu_files -v detect_simtop_dma=1 -f "$fpga_diff_dir/core_flist.awk" \ + "$tmp_dir/cpu_files" > "$tmp_output" + awk -v var=rtl_include_files -f "$fpga_diff_dir/core_flist.awk" \ + "$tmp_dir/rtl_files" >> "$tmp_output" + awk -v var=rtl_include_dirs -f "$fpga_diff_dir/core_flist.awk" \ + "$tmp_dir/rtl_include_dirs" >> "$tmp_output" + mkdir -p "$(dirname -- "$output")" + mv -- "$tmp_output" "$output" + echo "INFO: generated $output with ${#rtl_flist_files[@]} external RTL files" +} + +generate_uvhs_filelist() { + local core_dir=$1 + local work_dir=$2 + local cpu=$3 + local output=$4 + local core_rtl_dir + local core_generated_dir + local module_name + local source_file + local found + local tmp_dir + local tmp_output + local -a required_modules=() + shift 4 + + core_dir=$(realpath -e -- "$core_dir") + work_dir=$(realpath -e -- "$work_dir") + core_rtl_dir=$core_dir/rtl + core_generated_dir=$core_dir/generated-src + [[ -d $core_rtl_dir ]] || rtl_flist_fail "FPGA release RTL not found: $core_rtl_dir" + rtl_flist_parse_inputs "$PWD" "$@" + + mkdir -p "$(dirname -- "$output")" + tmp_dir=$(mktemp -d) + trap 'rm -rf "$tmp_dir"' RETURN + tmp_output=$tmp_dir/filelist.f + + { + printf '+define+SYNTHESIS\n+define+XIANGSHAN_FPGA\n+define+UVHS\n' + printf '+define+DDR4_16G_X8\n+define+DQ64\n+define+DDR4_2400\n' + printf '+define+DQ=64\n+define+MICRON_DDR\n+define+DDR4_16Gbx8\n' + printf '+define+DDR4\n+define+SRAM_SYN\n+define+DATA_VERSION=0\n' + if [[ $cpu == nutshell ]]; then + printf '+define+CPU_NUTSHELL\n' + fi + if [[ $cpu == kmh ]] && + grep -Eq '^[[:space:]]*(input|output)[[:space:]].*dma_awready' "$core_rtl_dir/SimTop.sv"; then + printf '+define+CONFIG_SIMTOP_HAS_DMA\n' + fi + + printf '+incdir+%s\n' "$core_dir" "$core_rtl_dir" + if [[ -d $core_generated_dir ]]; then + printf '+incdir+%s\n' "$core_generated_dir" + fi + printf '+incdir+%s/src/rtl/common\n' "$fpga_diff_dir" + + find "$fpga_diff_dir/src/rtl/common" -type f \ + \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ + ! -name 'u0_xdma.v' -print | LC_ALL=C sort + if [[ -d $work_dir/rtl/stubs ]]; then + find "$work_dir/rtl/stubs" -type f -name '*.v' -print | LC_ALL=C sort + fi + if [[ -d $fpga_diff_dir/src/rtl/$cpu ]]; then + find "$fpga_diff_dir/src/rtl/$cpu" -type f \ + \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ + -print | LC_ALL=C sort + fi + find "$core_rtl_dir" -type f \ + \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ + -print | LC_ALL=C sort + if ((${#rtl_flist_include_dirs[@]})); then + printf '+incdir+%s\n' "${rtl_flist_include_dirs[@]}" + fi + if ((${#rtl_flist_files[@]})); then + printf '%s\n' "${rtl_flist_files[@]}" + fi + } > "$tmp_output" + + mv -- "$tmp_output" "$output" + case $cpu in + kmh|nutshell) required_modules=(SimTop) ;; + nanhu) required_modules=(XlnFpgaTop) ;; + esac + for module_name in "${required_modules[@]}"; do + found=0 + while IFS= read -r source_file; do + [[ $source_file != +* && -f $source_file ]] || continue + if grep -Eq "^[[:space:]]*module[[:space:]]+$module_name([[:space:]#(]|$)" "$source_file"; then + found=1 + break + fi + done < "$output" + [[ $found == 1 ]] || rtl_flist_fail "required module not found: $module_name" + echo "INFO: found required module: $module_name" + done + echo "INFO: generated UVHS file list $output" +} + +mode=${1:-} +[[ -n $mode ]] || usage +shift +case $mode in + vivado) + [[ $# -ge 1 ]] || usage + core_dir=$1 + shift + [[ ${1:-} != -- ]] || shift + generate_vivado_filelist "$core_dir" "$@" + ;; + uvhs) + [[ $# -ge 4 ]] || usage + core_dir=$1 + work_dir=$2 + cpu=$3 + output=$4 + shift 4 + [[ ${1:-} != -- ]] || shift + generate_uvhs_filelist "$core_dir" "$work_dir" "$cpu" "$output" "$@" + ;; + *) usage ;; +esac diff --git a/fpga_diff/tools/update_core_flist.sh b/fpga_diff/tools/update_core_flist.sh deleted file mode 100755 index 0c241f48..00000000 --- a/fpga_diff/tools/update_core_flist.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -usage() { - echo "Usage: $0 CORE_DIR [--] [RTL_INCLUDE ...]" >&2 - exit 2 -} - -[[ $# -ge 1 ]] || usage -core_dir=$1 -shift -if [[ ${1:-} == -- ]]; then - shift -fi -[[ -d $core_dir ]] || { - echo "ERROR: CORE_DIR is not a directory: $core_dir" >&2 - exit 1 -} - -fpga_diff_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd) -source "$fpga_diff_dir/tools/rtl_filelist_lib.sh" -rtl_flist_parse_inputs "$PWD" "$@" - -core_dir=$(realpath -e -- "$core_dir") -tmp_dir=$(mktemp -d) -trap 'rm -rf "$tmp_dir"' EXIT - -find "$core_dir" -path "$core_dir/rtl/verification" -prune -o \ - -type f \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ - -print | LC_ALL=C sort > "$tmp_dir/cpu_files" -: > "$tmp_dir/rtl_files" -: > "$tmp_dir/rtl_include_dirs" -if ((${#rtl_flist_files[@]})); then - printf '%s\n' "${rtl_flist_files[@]}" > "$tmp_dir/rtl_files" -fi -if ((${#rtl_flist_include_dirs[@]})); then - printf '%s\n' "${rtl_flist_include_dirs[@]}" > "$tmp_dir/rtl_include_dirs" -fi - -awk_script="$fpga_diff_dir/core_flist.awk" -output_tcl="$fpga_diff_dir/src/tcl/cpu_files.tcl" -tmp_output="$tmp_dir/cpu_files.tcl" -awk -v var=cpu_files -v detect_simtop_dma=1 -f "$awk_script" \ - "$tmp_dir/cpu_files" > "$tmp_output" -awk -v var=rtl_include_files -f "$awk_script" \ - "$tmp_dir/rtl_files" >> "$tmp_output" -awk -v var=rtl_include_dirs -f "$awk_script" \ - "$tmp_dir/rtl_include_dirs" >> "$tmp_output" -mkdir -p "$(dirname -- "$output_tcl")" -mv -- "$tmp_output" "$output_tcl" - -echo "INFO: generated $output_tcl with ${#rtl_flist_files[@]} external RTL files" diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 1956b1ff..fa6015d6 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -18,9 +18,10 @@ conversion. The UVHS flow only consumes that result. `RTL_INCLUDE` accepts RTL files, directories, and nested `.f`, `.flist`, or `.list` files. Relative entries are resolved from the file list that contains -them. Both build flows use `tools/rtl_filelist_lib.sh` for that parsing. The -normal Vivado wrapper generates `cpu_files.tcl`; the UVHS generator combines -the parsed additions with release RTL and FPGA-Diff wrappers in `filelist.f`. +them. Both build flows call `tools/generate_rtl_filelist.sh`, which uses +`tools/rtl_filelist_lib.sh` for parsing. Vivado mode generates +`cpu_files.tcl`; UVHS mode combines the parsed additions with release RTL and +FPGA-Diff wrappers in `filelist.f`. | File-list stage | Vivado | UVHS | | --- | --- | --- | @@ -33,7 +34,6 @@ the parsed additions with release RTL and FPGA-Diff wrappers in `filelist.f`. ## Build ```sh -make uvhs_tools_check make uvhs CPU= CORE_DIR=/path/to/release/build \ RTL_INCLUDE=/path/to/extra.f SUFFIX= make uvhs_bitstream CPU= SUFFIX= @@ -57,7 +57,8 @@ and publishes `fpga_top_debug.bit`. The lower-level `uvhs_frontend` and `uvhs_backend` follows the vendor implementation sequence: clock inference and transformation, remap, partition, localization, system routing, FPGA PnR, timing signoff, bitstream generation, and runtime database commit. Fill-rate -configuration and automatic partitioning are isolated in `partition.tcl`. +validation and automatic partitioning are kept next to that sequence in +`backend_run.tcl`. The default XiangShan partition limits are 80% LUT and 30% LUT6. They can be changed with `UVHS_LUT_FILL_RATE` and `UVHS_LUT6_FILL_RATE` for placement @@ -112,22 +113,19 @@ or DDR pins. | File | Role | | --- | --- | | `uvhs.mk` | Build, packaging, and runtime targets. | -| `generate_filelist.sh` | Complete UVHS RTL file list generation and top check. | +| `../tools/generate_rtl_filelist.sh` | Shared Vivado/UVHS RTL file-list entry point. | +| `../tools/rtl_filelist_lib.sh` | Nested file-list parsing and path resolution. | | `flow_common.tcl` | Shared UVHS path, environment, and source helpers. | | `frontend_run.tcl` | RTL/IP import, elaboration, and uvsyn frontend. | -| `backend_run.tcl` | Partition, routing, FPGA PnR, and runtime database commit. | -| `partition.tcl` | Fill-rate validation and automatic partitioning. | -| `assemble_uvhs.tcl` | Selects the FPGA set from the vendor board assembly. | -| `assign_pin_u22_f2.tcl` | B0/F2 clock, PCIe, UART, JTAG, SD, and control pins. | +| `backend_run.tcl` | Fill-rate setup, partition, routing, PnR, and database commit. | +| `topology.tcl` | Selects the FPGA set from the vendor board assembly. | +| `assign_pin.tcl` | B0/F2 clock, PCIe, UART, JTAG, SD, and control pins. | | `timing_common.tcl` | External clock constraints. | | `async_clocks.tcl` | Asynchronous clock groups used by backend and Vivado PnR. | | `vivado_pre_opt.tcl` | XDMA refclock and CDC constraints. | | `export_vivado_ip.tcl` | Repository-owned Vivado IP export. | -| `check_flow_tools.sh` | Shell/Tcl/source validation. | | `shell_compat.sh` | Generated launcher shell correction. | | `uv_shell_exec_compat.sh` | Runtime library wrapper. | -| `hw_run_download.tcl` | Download and command-service entry point. | -| `runtime_control.tcl` | Reset sequencing and command polling. | +| `hw_run_download.tcl` | Download, reset sequencing, and command service. | | `runtime_command.tcl` | Reset, DDR, and flash operations. | -| `runtime_session.sh` | Detached runtime session lifecycle. | -| `enqueue_runtime_command.sh` | Runtime command submission and status. | +| `runtime_session.sh` | Runtime lifecycle, command submission, and status. | diff --git a/fpga_diff/uvhs/assign_pin_u22_f2.tcl b/fpga_diff/uvhs/assign_pin.tcl similarity index 98% rename from fpga_diff/uvhs/assign_pin_u22_f2.tcl rename to fpga_diff/uvhs/assign_pin.tcl index 49c5f152..0453358b 100644 --- a/fpga_diff/uvhs/assign_pin_u22_f2.tcl +++ b/fpga_diff/uvhs/assign_pin.tcl @@ -1,5 +1,5 @@ ################################################################################ -# Pin assignment for fpga_diff on a single U2.2 VU19P FPGA (b0.f2). +# Pin assignment for fpga_diff on a U2.2 VU19P FPGA (b0.f2). # # This file targets the single-FPGA b0.f2 configuration. All user-visible top # ports bind to b0.F2_* connectors instead of the mixed F0/F1/F2 template. diff --git a/fpga_diff/uvhs/backend_run.tcl b/fpga_diff/uvhs/backend_run.tcl index 34bc6b3c..b4c65999 100644 --- a/fpga_diff/uvhs/backend_run.tcl +++ b/fpga_diff/uvhs/backend_run.tcl @@ -5,10 +5,7 @@ source [file join [file dirname [file normalize [info script]]] flow_common.tcl] set_working_space hw.dat -set fpga_threads [uvhs::env_or_default UVHS_FPGA_THREADS 8] -set fpga_processes [uvhs::env_or_default UVHS_FPGA_PROCESSES 16] -set_parallel_option -max_threads $fpga_threads \ - -max_processes $fpga_processes -label fpga +set_parallel_option -max_threads 4 -max_processes 8 -label fpga set_option time.auto_clock_config true set_option clock.transform_clock.multi_iteration true @@ -19,10 +16,10 @@ set_option time.incremental_sign_off true set platform [uvhs::env_or_default PLATFORM U2.2] create_system_design -name VU19P_X4 -platform $platform -uvhs::source_required assemble_uvhs.tcl +uvhs::source_required topology.tcl set ::env(UVHS_ASSIGN_PIN_TOP) none -uvhs::source_required assign_pin_u22_f2.tcl +uvhs::source_required assign_pin.tcl unset ::env(UVHS_ASSIGN_PIN_TOP) create_design -name test @@ -41,13 +38,34 @@ infer_clock report_clock -inferred transform_clock uvhs::source_required async_clocks.tcl -uvhs::source_required partition.tcl -uvhs::configure_fill_rates +set fill_rate_args {} +foreach {option variable} { + -lut UVHS_LUT_FILL_RATE + -lut6 UVHS_LUT6_FILL_RATE +} { + set value [uvhs::env_or_default $variable ""] + if {$value eq ""} { + continue + } + if {![string is double -strict $value] || $value <= 0 || $value > 100} { + error "$variable must be in (0, 100], got '$value'" + } + lappend fill_rate_args $option $value +} +if {[llength $fill_rate_args]} { + puts "INFO: set UVHS fill rates: $fill_rate_args" + set_fill_rate {*}$fill_rate_args +} trigger_probe -group sweep_design -remap report_clock -uvhs::run_partition +check_design +report_resource -depth 4 +report_system_resource +list_partition_constraints -all +partition_design -tdc -tdss true +report_resource -depth 4 instrument_design localize_design -replicate_cell -clock -self_check @@ -66,8 +84,7 @@ save_runtime_data set_option compile.resourceUsageLimit 100 set_option compile.strategyNum 1 -set_option compile.strategy0 \ - [uvhs::env_or_default UVHS_COMPILE_STRATEGY uv_high_fanout_explore] +set_option compile.strategy0 uv_high_fanout_explore set_option compile.stage.preOpt \ [uvhs::path vivado_pre_opt.tcl] diff --git a/fpga_diff/uvhs/check_flow_tools.sh b/fpga_diff/uvhs/check_flow_tools.sh deleted file mode 100644 index ba29282f..00000000 --- a/fpga_diff/uvhs/check_flow_tools.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -root_dir="$(cd "$script_dir/.." && pwd)" - -required=( - Makefile - tools/rtl_filelist_lib.sh - uvhs/uvhs.mk - uvhs/README.md - uvhs/flow_common.tcl - uvhs/frontend_run.tcl - uvhs/backend_run.tcl - uvhs/partition.tcl - uvhs/assemble_uvhs.tcl - uvhs/assign_pin_u22_f2.tcl - uvhs/async_clocks.tcl - uvhs/timing_common.tcl - uvhs/vivado_pre_opt.tcl - uvhs/export_vivado_ip.tcl - uvhs/generate_filelist.sh - uvhs/shell_compat.sh - uvhs/enqueue_runtime_command.sh - uvhs/runtime_session.sh - uvhs/uv_shell_exec_compat.sh - uvhs/hw_run_download.tcl - uvhs/runtime_control.tcl - uvhs/runtime_command.tcl - src/tcl/common/AXI_bridge.tcl - src/tcl/common/xdma_ep.tcl -) - -for path in "${required[@]}"; do - test -f "$root_dir/$path" || { - echo "ERROR: missing required UVHS flow file: $path" >&2 - exit 1 - } -done - -bash -n "$root_dir/uvhs/check_flow_tools.sh" -bash -n "$root_dir/tools/rtl_filelist_lib.sh" -bash -n "$root_dir/uvhs/generate_filelist.sh" -bash -n "$root_dir/uvhs/shell_compat.sh" -bash -n "$root_dir/uvhs/enqueue_runtime_command.sh" -bash -n "$root_dir/uvhs/runtime_session.sh" -bash -n "$root_dir/uvhs/uv_shell_exec_compat.sh" - -if command -v tclsh >/dev/null 2>&1; then - while IFS= read -r -d '' path; do - tclsh /dev/stdin "$path" <<'TCL' -set fh [open [lindex $argv 0] r] -set source [read $fh] -close $fh -if {![info complete $source]} { exit 1 } -TCL - done < <(find "$root_dir/uvhs" -type f -name '*.tcl' -print0) -fi - -if grep -R -n -E '/home/|setenv\.local|NUTSHELL_LEGACY_DIFFTEST_HOSTIF|UVHS_XDMA_ST_LOOPBACK_SMOKE|UVHS_CPU_LIVENESS_GBD' \ - --include='*.mk' --include='*.sh' --include='*.tcl' --include='*.sv' \ - --exclude='check_flow_tools.sh' "$root_dir/uvhs"; then - echo "ERROR: removed local paths or legacy/debug controls remain in UVHS sources" >&2 - exit 1 -fi - -echo "OK: UVHS flow source checks passed" diff --git a/fpga_diff/uvhs/enqueue_runtime_command.sh b/fpga_diff/uvhs/enqueue_runtime_command.sh deleted file mode 100755 index 6c672bbb..00000000 --- a/fpga_diff/uvhs/enqueue_runtime_command.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -if (( $# < 2 )); then - echo "usage: $0 [argument ...]" >&2 - exit 64 -fi - -command_file=$1 -tcl_script=$2 -shift 2 - -if [[ ! -f $tcl_script ]]; then - echo "ERROR: runtime Tcl script not found: $tcl_script" >&2 - exit 2 -fi -if [[ -e $command_file || -e $command_file.running ]]; then - echo "ERROR: a UVHS runtime command is already pending" >&2 - exit 3 -fi - -timeout=${UVHS_RUNTIME_COMMAND_TIMEOUT:-600} -if [[ ! $timeout =~ ^[1-9][0-9]*$ ]]; then - echo "ERROR: UVHS_RUNTIME_COMMAND_TIMEOUT must be a positive integer" >&2 - exit 64 -fi -result_file="${command_file}.result.$$" - -tcl_quote() { - local value=$1 - value=${value//\\/\\\\} - value=${value//\"/\\\"} - value=${value//\$/\\\$} - value=${value//\[/\\[} - value=${value//\]/\\]} - printf '"%s"' "$value" -} - -mkdir -p "$(dirname "$command_file")" -tmp_file="${command_file}.tmp.$$" -trap 'rm -f "$tmp_file" "$result_file"' EXIT - -{ - printf 'set uvhs_result_file ' - tcl_quote "$result_file" - printf '\n' - printf 'set argv [list' - for argument in "$@"; do - printf ' ' - tcl_quote "$argument" - done - printf ']\nsource ' - tcl_quote "$tcl_script" - printf '\n' -} >"$tmp_file" - -mv -n "$tmp_file" "$command_file" -if [[ -e $tmp_file ]]; then - echo "ERROR: command file appeared while enqueueing: $command_file" >&2 - exit 4 -fi -trap - EXIT -echo "INFO: enqueued UVHS runtime command: $command_file" - -deadline=$((SECONDS + timeout)) -while [[ ! -f $result_file ]]; do - if (( SECONDS >= deadline )); then - echo "ERROR: timed out waiting for UVHS runtime command after ${timeout}s" >&2 - exit 5 - fi - sleep 0.2 -done - -status=$(sed -n '1p' "$result_file") -message=$(sed -n '2,$p' "$result_file") -rm -f "$result_file" -if [[ $status != 0 ]]; then - echo "ERROR: UVHS runtime command failed: $message" >&2 - exit 6 -fi -if [[ -n $message ]]; then - echo "INFO: $message" -fi diff --git a/fpga_diff/uvhs/frontend_run.tcl b/fpga_diff/uvhs/frontend_run.tcl index a072bb6f..40214fcd 100644 --- a/fpga_diff/uvhs/frontend_run.tcl +++ b/fpga_diff/uvhs/frontend_run.tcl @@ -74,10 +74,7 @@ proc uvhs::start_frontend_shell_compat {} { create_working_space hw.dat set_option syn.computeFeCheckSum true -set frontend_threads [uvhs::env_or_default UVHS_FRONTEND_THREADS 16] -set frontend_processes [uvhs::env_or_default UVHS_FRONTEND_PROCESSES 64] -set_parallel_option -max_threads $frontend_threads \ - -max_processes $frontend_processes -label frontend +set_parallel_option -max_threads 4 -max_processes 16 -label frontend set_option global.log.label MEMORY set_option syn.checkMultiDriver false @@ -96,8 +93,8 @@ set design_top fpga_top_debug set ddr_inst_path ${design_top}.core_def.U_UVHS_UVW_AXI4_TO_DDR4 create_system_design -name VU19P_X4 -platform $platform -uvhs::source_required assemble_uvhs.tcl -uvhs::source_required assign_pin_u22_f2.tcl +uvhs::source_required topology.tcl +uvhs::source_required assign_pin.tcl set_constraint_files [uvhs::path timing_common.tcl] foreach reset_port {rstn_sw6 rstn_sw5 rstn_sw4} { create_reset -port ${design_top}.${reset_port} -active 0 diff --git a/fpga_diff/uvhs/generate_filelist.sh b/fpga_diff/uvhs/generate_filelist.sh deleted file mode 100755 index 2d25a919..00000000 --- a/fpga_diff/uvhs/generate_filelist.sh +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -usage() { - echo "Usage: $0 CORE_BUILD_DIR UVHS_WORK_DIR CPU OUTPUT [--] [RTL_INCLUDE ...]" >&2 - exit 2 -} - -[[ $# -ge 4 ]] || usage -core_dir=$(realpath -e -- "$1") -work_dir=$(realpath -e -- "$2") -cpu=$3 -output=$4 -shift 4 -if [[ ${1:-} == -- ]]; then - shift -fi - -script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) -fpga_diff_dir=$(cd -- "$script_dir/.." && pwd) -source "$fpga_diff_dir/tools/rtl_filelist_lib.sh" -rtl_flist_parse_inputs "$PWD" "$@" - -core_rtl_dir="$core_dir/rtl" -core_generated_dir="$core_dir/generated-src" -[[ -d $core_rtl_dir ]] || rtl_flist_fail "FPGA release RTL not found: $core_rtl_dir" - -mkdir -p "$(dirname -- "$output")" -tmp_dir=$(mktemp -d) -trap 'rm -rf "$tmp_dir"' EXIT -tmp_output="$tmp_dir/filelist.f" - -{ - printf '+define+SYNTHESIS\n+define+XIANGSHAN_FPGA\n+define+UVHS\n' - printf '+define+DDR4_16G_X8\n+define+DQ64\n+define+DDR4_2400\n' - printf '+define+DQ=64\n+define+MICRON_DDR\n+define+DDR4_16Gbx8\n' - printf '+define+DDR4\n+define+SRAM_SYN\n+define+DATA_VERSION=0\n' - if [[ $cpu == nutshell ]]; then - printf '+define+CPU_NUTSHELL\n' - fi - if [[ $cpu == kmh ]] && - grep -Eq '^[[:space:]]*(input|output)[[:space:]].*dma_awready' "$core_rtl_dir/SimTop.sv"; then - printf '+define+CONFIG_SIMTOP_HAS_DMA\n' - fi - - printf '+incdir+%s\n' "$core_dir" "$core_rtl_dir" - if [[ -d $core_generated_dir ]]; then - printf '+incdir+%s\n' "$core_generated_dir" - fi - printf '+incdir+%s/src/rtl/common\n' "$fpga_diff_dir" - - find "$fpga_diff_dir/src/rtl/common" -type f \ - \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ - ! -name 'u0_xdma.v' -print | LC_ALL=C sort - if [[ -d $work_dir/rtl/stubs ]]; then - find "$work_dir/rtl/stubs" -type f -name '*.v' -print | LC_ALL=C sort - fi - if [[ -d $fpga_diff_dir/src/rtl/$cpu ]]; then - find "$fpga_diff_dir/src/rtl/$cpu" -type f \ - \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ - -print | LC_ALL=C sort - fi - find "$core_rtl_dir" -type f \ - \( -name '*.v' -o -name '*.sv' -o -name '*.vh' -o -name '*.svh' \) \ - -print | LC_ALL=C sort - if ((${#rtl_flist_include_dirs[@]})); then - printf '+incdir+%s\n' "${rtl_flist_include_dirs[@]}" - fi - if ((${#rtl_flist_files[@]})); then - printf '%s\n' "${rtl_flist_files[@]}" - fi -} > "$tmp_output" - -mv -- "$tmp_output" "$output" - -case $cpu in - kmh|nutshell) required_modules=(SimTop) ;; - nanhu) required_modules=(XlnFpgaTop) ;; - *) required_modules=() ;; -esac - -for module_name in "${required_modules[@]}"; do - found=0 - while IFS= read -r source_file; do - [[ $source_file != +* && -f $source_file ]] || continue - if grep -Eq "^[[:space:]]*module[[:space:]]+$module_name([[:space:]#(]|$)" "$source_file"; then - found=1 - break - fi - done < "$output" - [[ $found == 1 ]] || rtl_flist_fail "required module not found: $module_name" - echo "INFO: found required module: $module_name" -done - -echo "INFO: generated UVHS file list $output" diff --git a/fpga_diff/uvhs/hw_run_download.tcl b/fpga_diff/uvhs/hw_run_download.tcl index e6cf1949..c089ff73 100644 --- a/fpga_diff/uvhs/hw_run_download.tcl +++ b/fpga_diff/uvhs/hw_run_download.tcl @@ -1,12 +1,112 @@ # Download a completed UVHS database and retain the owning runtime session for # reset and memory commands. -set uvhs_script_dir [file dirname [file normalize [info script]]] -set uvhs_control_script [file join $uvhs_script_dir runtime_control.tcl] -if {![file exists $uvhs_control_script]} { - error "UVHS runtime control script not found: $uvhs_control_script" +proc uvhs_hold_soc_for_download {} { + reset -name rstn_sw6 -value 0 + reset -name rstn_sw5 -value 0 + reset -name rstn_sw4 -value 0 + query -reset +} + +proc uvhs_release_soc_after_download {} { + reset -name rstn_sw6 -value 0 + reset -name rstn_sw5 -value 0 + reset -name rstn_sw4 -value 0 + after 1000 + reset -name rstn_sw6 -value 1 + reset -name rstn_sw4 -value 1 + after 1000 + reset -name rstn_sw5 -value 1 + after 1000 + query -reset +} + +proc uvhs_halt_soc {} { + reset -name rstn_sw5 -value 0 + query -reset +} + +proc uvhs_reset_cpu {} { + reset -name rstn_sw5 -value 0 + after 500 + reset -name rstn_sw5 -value 1 + after 500 + query -reset +} + +proc uvhs_hold_cpu_for_memory {} { + reset -name rstn_sw5 -value 0 + after 100 +} + +proc uvhs_release_cpu_after_memory {} { + reset -name rstn_sw5 -value 1 + after 500 + query -reset +} + +proc uvhs_signal_runtime_ready {} { + if {![info exists ::env(UVHS_RUNTIME_READY_FILE)] || + $::env(UVHS_RUNTIME_READY_FILE) eq ""} { + return + } + set ready_file $::env(UVHS_RUNTIME_READY_FILE) + file mkdir [file dirname $ready_file] + set temp_file "${ready_file}.tmp.[pid]" + set output [open $temp_file w] + puts $output [pid] + close $output + file rename -force $temp_file $ready_file + puts "INFO: UVHS runtime command service is ready" +} + +proc uvhs_clear_runtime_ready {} { + if {[info exists ::env(UVHS_RUNTIME_READY_FILE)] && + $::env(UVHS_RUNTIME_READY_FILE) ne ""} { + file delete -force $::env(UVHS_RUNTIME_READY_FILE) + } +} + +proc uvhs_poll_command_file {} { + if {![info exists ::env(UVHS_COMMAND_FILE)] || $::env(UVHS_COMMAND_FILE) eq ""} { + after 500 uvhs_poll_command_file + return + } + set command_file $::env(UVHS_COMMAND_FILE) + if {[file exists $command_file]} { + set running_file "${command_file}.running" + set uvhs_result_file "" + set command_status [catch { + file rename -force $command_file $running_file + puts "INFO: sourcing UVHS runtime command: $running_file" + source $running_file + } command_message] + if {$command_status != 0} { + set command_message "UVHS runtime command failed: $command_message" + } + catch {file delete -force $running_file} + if {$uvhs_result_file ne ""} { + set result_tmp "${uvhs_result_file}.tmp.[pid]" + set result [open $result_tmp w] + puts $result $command_status + puts -nonewline $result $command_message + close $result + file rename -force $result_tmp $uvhs_result_file + } + if {$command_status != 0} { + puts stderr "ERROR: $command_message" + } + } + after 500 uvhs_poll_command_file +} + +proc uvhs_serve_runtime_commands {} { + set ::uvhs_keepalive 0 + uvhs_signal_runtime_ready + uvhs_poll_command_file + vwait ::uvhs_keepalive + uvhs_clear_runtime_ready } -source $uvhs_control_script query -user query -fpgas -all diff --git a/fpga_diff/uvhs/partition.tcl b/fpga_diff/uvhs/partition.tcl deleted file mode 100644 index a18c2d37..00000000 --- a/fpga_diff/uvhs/partition.tcl +++ /dev/null @@ -1,31 +0,0 @@ -namespace eval uvhs { - proc configure_fill_rates {} { - set args {} - foreach {option variable} { - -lut UVHS_LUT_FILL_RATE - -lut6 UVHS_LUT6_FILL_RATE - } { - set value [env_or_default $variable ""] - if {$value eq ""} { - continue - } - if {![string is double -strict $value] || $value <= 0 || $value > 100} { - error "$variable must be in (0, 100], got '$value'" - } - lappend args $option $value - } - if {[llength $args]} { - puts "INFO: set UVHS fill rates: $args" - set_fill_rate {*}$args - } - } - - proc run_partition {} { - check_design - report_resource -depth 4 - report_system_resource - list_partition_constraints -all - partition_design -tdc -tdss true - report_resource -depth 4 - } -} diff --git a/fpga_diff/uvhs/runtime_command.tcl b/fpga_diff/uvhs/runtime_command.tcl index c46e85c3..315edd61 100644 --- a/fpga_diff/uvhs/runtime_command.tcl +++ b/fpga_diff/uvhs/runtime_command.tcl @@ -1,8 +1,3 @@ -if {[llength [info commands uvhs_reset_cpu]] == 0} { - set uvhs_script_dir [file dirname [file normalize [info script]]] - source [file join $uvhs_script_dir runtime_control.tcl] -} - proc uvhs_temp_dir {} { if {[info exists ::env(UVHS_RUNTIME_TMP_DIR)] && $::env(UVHS_RUNTIME_TMP_DIR) ne ""} { set path $::env(UVHS_RUNTIME_TMP_DIR) diff --git a/fpga_diff/uvhs/runtime_control.tcl b/fpga_diff/uvhs/runtime_control.tcl deleted file mode 100644 index e2a67364..00000000 --- a/fpga_diff/uvhs/runtime_control.tcl +++ /dev/null @@ -1,110 +0,0 @@ -proc uvhs_hold_soc_for_download {} { - reset -name rstn_sw6 -value 0 - reset -name rstn_sw5 -value 0 - reset -name rstn_sw4 -value 0 - query -reset -} - -proc uvhs_release_soc_after_download {} { - reset -name rstn_sw6 -value 0 - reset -name rstn_sw5 -value 0 - reset -name rstn_sw4 -value 0 - after 1000 - - reset -name rstn_sw6 -value 1 - reset -name rstn_sw4 -value 1 - after 1000 - - reset -name rstn_sw5 -value 1 - after 1000 - query -reset -} - -proc uvhs_halt_soc {} { - reset -name rstn_sw5 -value 0 - query -reset -} - -proc uvhs_reset_cpu {} { - reset -name rstn_sw5 -value 0 - after 500 - reset -name rstn_sw5 -value 1 - after 500 - query -reset -} - -proc uvhs_hold_cpu_for_memory {} { - reset -name rstn_sw5 -value 0 - after 100 -} - -proc uvhs_release_cpu_after_memory {} { - reset -name rstn_sw5 -value 1 - after 500 - query -reset -} - -proc uvhs_signal_runtime_ready {} { - if {![info exists ::env(UVHS_RUNTIME_READY_FILE)] || - $::env(UVHS_RUNTIME_READY_FILE) eq ""} { - return - } - - set ready_file $::env(UVHS_RUNTIME_READY_FILE) - file mkdir [file dirname $ready_file] - set temp_file "${ready_file}.tmp.[pid]" - set output [open $temp_file w] - puts $output [pid] - close $output - file rename -force $temp_file $ready_file - puts "INFO: UVHS runtime command service is ready" -} - -proc uvhs_clear_runtime_ready {} { - if {[info exists ::env(UVHS_RUNTIME_READY_FILE)] && - $::env(UVHS_RUNTIME_READY_FILE) ne ""} { - file delete -force $::env(UVHS_RUNTIME_READY_FILE) - } -} - -proc uvhs_poll_command_file {} { - if {![info exists ::env(UVHS_COMMAND_FILE)] || $::env(UVHS_COMMAND_FILE) eq ""} { - after 500 uvhs_poll_command_file - return - } - - set command_file $::env(UVHS_COMMAND_FILE) - if {[file exists $command_file]} { - set running_file "${command_file}.running" - set uvhs_result_file "" - set command_status [catch { - file rename -force $command_file $running_file - puts "INFO: sourcing UVHS runtime command: $running_file" - source $running_file - } command_message] - if {$command_status != 0} { - set command_message "UVHS runtime command failed: $command_message" - } - catch {file delete -force $running_file} - if {$uvhs_result_file ne ""} { - set result_tmp "${uvhs_result_file}.tmp.[pid]" - set result [open $result_tmp w] - puts $result $command_status - puts -nonewline $result $command_message - close $result - file rename -force $result_tmp $uvhs_result_file - } - if {$command_status != 0} { - puts stderr "ERROR: $command_message" - } - } - after 500 uvhs_poll_command_file -} - -proc uvhs_serve_runtime_commands {} { - set ::uvhs_keepalive 0 - uvhs_signal_runtime_ready - uvhs_poll_command_file - vwait ::uvhs_keepalive - uvhs_clear_runtime_ready -} diff --git a/fpga_diff/uvhs/runtime_session.sh b/fpga_diff/uvhs/runtime_session.sh index 05f6abf1..cc0c6d78 100755 --- a/fpga_diff/uvhs/runtime_session.sh +++ b/fpga_diff/uvhs/runtime_session.sh @@ -8,6 +8,7 @@ usage: [argument ...] runtime_session.sh active runtime_session.sh check + runtime_session.sh enqueue [argument ...] runtime_session.sh wait EOF exit 64 @@ -41,6 +42,16 @@ show_log_tail() { fi } +tcl_quote() { + local value=$1 + value=${value//\\/\\\\} + value=${value//\"/\\\"} + value=${value//\$/\\\$} + value=${value//\[/\\[} + value=${value//\]/\\]} + printf '"%s"' "$value" +} + action=${1:-} [[ -n $action ]] || usage shift @@ -131,6 +142,62 @@ case $action in fi echo "INFO: UVHS runtime is ready (PID $pid)" ;; + enqueue) + (( $# >= 3 )) || usage + command_file=$1 + tcl_script=$2 + timeout=$3 + shift 3 + validate_timeout "$timeout" + [[ -f $tcl_script ]] || { + echo "ERROR: runtime Tcl script not found: $tcl_script" >&2 + exit 9 + } + if [[ -e $command_file || -e $command_file.running ]]; then + echo "ERROR: a UVHS runtime command is already pending" >&2 + exit 10 + fi + + result_file="${command_file}.result.$$" + temp_file="${command_file}.tmp.$$" + mkdir -p "$(dirname "$command_file")" + trap 'rm -f "$temp_file" "$result_file"' EXIT + { + printf 'set uvhs_result_file ' + tcl_quote "$result_file" + printf '\nset argv [list' + for argument in "$@"; do + printf ' ' + tcl_quote "$argument" + done + printf ']\nsource ' + tcl_quote "$tcl_script" + printf '\n' + } >"$temp_file" + mv -n "$temp_file" "$command_file" + [[ ! -e $temp_file ]] || { + echo "ERROR: command file appeared while enqueueing: $command_file" >&2 + exit 11 + } + echo "INFO: enqueued UVHS runtime command: $command_file" + + deadline=$((SECONDS + timeout)) + while [[ ! -f $result_file ]]; do + if (( SECONDS >= deadline )); then + echo "ERROR: timed out waiting for UVHS runtime command after ${timeout}s" >&2 + exit 12 + fi + sleep 0.2 + done + status=$(sed -n '1p' "$result_file") + message=$(sed -n '2,$p' "$result_file") + rm -f "$result_file" + if [[ $status != 0 ]]; then + echo "ERROR: UVHS runtime command failed: $message" >&2 + exit 13 + fi + [[ -z $message ]] || echo "INFO: $message" + ;; wait) (( $# == 4 )) || usage pid_file=$1 diff --git a/fpga_diff/uvhs/timing_common.tcl b/fpga_diff/uvhs/timing_common.tcl index 464d1785..5e62ed5a 100644 --- a/fpga_diff/uvhs/timing_common.tcl +++ b/fpga_diff/uvhs/timing_common.tcl @@ -11,10 +11,6 @@ proc fpga_diff_top_port {name} { create_clock -name TMCLK -period 1000 [get_ports [fpga_diff_top_port clk8_p]] create_clock -name ddr_ref_clk -period 12.5 [get_ports [fpga_diff_top_port clk7_p]] -set fpga_diff_cpu_clk_period_ns 40 -if {[info exists ::env(UVHS_CPU_CLK_PERIOD_NS)] && $::env(UVHS_CPU_CLK_PERIOD_NS) ne ""} { - set fpga_diff_cpu_clk_period_ns $::env(UVHS_CPU_CLK_PERIOD_NS) -} -create_clock -name CPU_CLK_IN -period $fpga_diff_cpu_clk_period_ns [get_ports [fpga_diff_top_port clk5_p]] +create_clock -name CPU_CLK_IN -period 40 [get_ports [fpga_diff_top_port clk5_p]] create_clock -name jtag_vclk -period 83.333 [get_ports [fpga_diff_top_port JTAG_TCK]] create_clock -name pcie_ep_refclk -period 10 [get_ports [fpga_diff_top_port pcie_ep_gt_ref_clk_p]] diff --git a/fpga_diff/uvhs/assemble_uvhs.tcl b/fpga_diff/uvhs/topology.tcl similarity index 94% rename from fpga_diff/uvhs/assemble_uvhs.tcl rename to fpga_diff/uvhs/topology.tcl index 59f47066..ee84d584 100644 --- a/fpga_diff/uvhs/assemble_uvhs.tcl +++ b/fpga_diff/uvhs/topology.tcl @@ -1,11 +1,9 @@ ################################################################################ -# Reduce the vendor four-FPGA assembly template to the selected UVHS FPGA. +# Select the active FPGA topology from the vendor four-FPGA board template. ################################################################################ set uvhs_base_assemble ./script/1B_4F_HGC_assemble.tcl -set uvhs_target_pack [uvhs::env_or_default UVHS_TARGET_PACK B0] -set uvhs_target_name [uvhs::env_or_default UVHS_TARGET_FPGA F2] -set uvhs_target_fpga [string tolower "$uvhs_target_pack.$uvhs_target_name"] +set uvhs_target_fpga b0.f2 set uvhs_known_fpgas {b0.f0 b0.f1 b0.f2 b0.f3} set uvhs_keep_fpgas {} foreach uvhs_fpga [split [uvhs::env_or_default UVHS_KEEP_FPGAS $uvhs_target_fpga]] { diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 07ee8e19..cbfc7225 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -1,36 +1,22 @@ UVHS_ROOT_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))/..) -PLATFORM ?= U2.2 UVHS_TEMPLATE_DIR ?= UVHS_UVW_AXI4_TO_DDR4_SRC ?= UVHS_DDR_AXI_WIDTH := $(if $(filter nutshell,$(CPU)),64,256) -UVHS_WORK_DIR ?= $(ENV_SCRIPTS_HOME)/fpga_diff_uvhs_$(CPU)$(if $(strip $(SUFFIX)),-$(strip $(SUFFIX)),) +UVHS_WORK_DIR := $(ENV_SCRIPTS_HOME)/fpga_diff_uvhs_$(CPU)$(if $(strip $(SUFFIX)),-$(strip $(SUFFIX)),) UVHS_FILELIST := $(UVHS_WORK_DIR)/rtl/filelist.f UVHS_EXPORT_IP_FORCE ?= 0 UVHS_EXPORT_IP_JOBS := $(if $(strip $(VIVADO_JOBS)),$(VIVADO_JOBS),8) -UVHS_GBUS_IP_DIR := $(UV_ROOT)/platform/$(PLATFORM)/Prototype/ips/uvw_gbus.3.1 +UVHS_GBUS_IP_DIR := $(UV_ROOT)/platform/U2.2/Prototype/ips/uvw_gbus.3.1 UVHS_GBUS_GENERATOR := $(UVHS_GBUS_IP_DIR)/gen_generalbus_ip.py UVHS_GBUS_JSON := $(UVHS_GBUS_IP_DIR)/uvw_axi3_generalbus.json UVHS_GBUS_GEN_DIR := $(UVHS_WORK_DIR)/ip-gen/generalbus -UVHS_TARGET_PACK ?= B0 -UVHS_TARGET_FPGA ?= F2 UVHS_KEEP_FPGAS ?= -UVHS_CPU_CLK_PERIOD_NS ?= 40 -UVHS_FRONTEND_THREADS ?= 4 -UVHS_FRONTEND_PROCESSES ?= 16 -UVHS_FPGA_THREADS ?= 4 -UVHS_FPGA_PROCESSES ?= 8 -UVHS_COMPILE_STRATEGY ?= uv_high_fanout_explore UVHS_LUT_FILL_RATE ?= $(if $(filter kmh,$(CPU)),80,) UVHS_LUT6_FILL_RATE ?= $(if $(filter kmh,$(CPU)),30,) -XDMA_LINK_WIDTH ?= X4 -XDMA_ENABLE_PF0_BAR1 ?= 1 -XDMA_AXILITE_MASTER_SCALE ?= Kilobytes -XDMA_AXILITE_MASTER_SIZE ?= 512 - UVHS_UVW_AXI4_TO_DDR4_FILES := \ rtl/soc/uvw_axi4_to_ddr4.dcp \ rtl/soc/uvw_axi4_to_ddr4_Stub.v \ @@ -49,8 +35,7 @@ UVHS_RUNTIME_TMP_DIR := $(UVHS_RUNTIME_WORK_DIR)/tmp UVHS_RUNTIME_PID_FILE := $(UVHS_RUNTIME_WORK_DIR)/uv_shell.pid UVHS_RUNTIME_READY_FILE := $(UVHS_RUNTIME_WORK_DIR)/uv_shell.ready UVHS_RUNTIME_LOG := $(UVHS_RUNTIME_WORK_DIR)/uv_shell.log -UVHS_RUNTIME_TIMEOUT ?= 600 -UVHS_COMPAT_PCRE_LIB ?= +UVHS_RUNTIME_TIMEOUT := 600 UVHS_TOOL_ENV = \ PATH="$$UV_ROOT/bin:$$UV_ROOT/lib/venv3.8/bin:$$UV_ROOT/lib/gcc10.3/bin:$$PATH" \ @@ -62,28 +47,20 @@ UVHS_TOOL_ENV = \ UVHS_FLOW_ENV = \ $(UVHS_TOOL_ENV) \ UVHS_FLOW=1 \ - PLATFORM="$(PLATFORM)" \ XDMA_LINK_WIDTH="$(XDMA_LINK_WIDTH)" \ - XDMA_ENABLE_PF0_BAR1="$(XDMA_ENABLE_PF0_BAR1)" \ - XDMA_AXILITE_MASTER_SCALE="$(XDMA_AXILITE_MASTER_SCALE)" \ - XDMA_AXILITE_MASTER_SIZE="$(XDMA_AXILITE_MASTER_SIZE)" \ - UVHS_TARGET_PACK="$(UVHS_TARGET_PACK)" \ - UVHS_TARGET_FPGA="$(UVHS_TARGET_FPGA)" \ UVHS_KEEP_FPGAS="$(UVHS_KEEP_FPGAS)" \ - UVHS_CPU_CLK_PERIOD_NS="$(UVHS_CPU_CLK_PERIOD_NS)" \ - UVHS_COMPILE_STRATEGY="$(UVHS_COMPILE_STRATEGY)" \ UVHS_LUT_FILL_RATE="$(UVHS_LUT_FILL_RATE)" \ UVHS_LUT6_FILL_RATE="$(UVHS_LUT6_FILL_RATE)" -UVHS_PNR_DIR := $(UVHS_WORK_DIR)/hw.dat/Compile/PnR/$(UVHS_TARGET_PACK)/$(UVHS_TARGET_FPGA)/vivado/Rundir/Strategy_$(UVHS_COMPILE_STRATEGY) +UVHS_PNR_DIR := $(UVHS_WORK_DIR)/hw.dat/Compile/PnR/B0/F2/vivado/Rundir/Strategy_uv_high_fanout_explore UVHS_BITSTREAM_DIR := $(UVHS_PNR_DIR)/bitstream -UVHS_BIT_HOME ?= $(UVHS_WORK_DIR)/ready-to-program +UVHS_BIT_HOME := $(UVHS_WORK_DIR)/ready-to-program .PHONY: uvhs uvhs_bitstream uvhs_preflight uvhs_prepare \ uvhs_export_vivado_ip uvhs_export_generalbus \ uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist \ - uvhs_frontend uvhs_backend uvhs_all uvhs_check_timing \ - uvhs_package_bitstream uvhs_tools_check uvhs_clean uvhs_write_bitstream \ + uvhs_frontend uvhs_backend uvhs_check_timing \ + uvhs_package_bitstream uvhs_clean uvhs_write_bitstream \ uvhs_halt_soc uvhs_reset_cpu uvhs_write_ddr uvhs_write_flash \ uvhs_runtime_status uvhs_runtime_check uvhs_runtime_stop @@ -96,6 +73,7 @@ uvhs_preflight: test -x "$$UV_ROOT/bin/uv_shell_exec" test -x "$(UVHS_ROOT_DIR)/uvhs/uv_shell_exec_compat.sh" test -x "$(UVHS_ROOT_DIR)/uvhs/shell_compat.sh" + test -x "$(UVHS_ROOT_DIR)/tools/generate_rtl_filelist.sh" test -f "$(UVHS_ROOT_DIR)/uvhs/vivado_pre_opt.tcl" test -f "$(UVHS_GBUS_GENERATOR)" test -f "$(UVHS_GBUS_JSON)" @@ -110,21 +88,18 @@ uvhs_preflight: ffi="$$(ldconfig -p | awk '\''/libffi[.]so[.]6 / { print $$NF; exit } /libffi[.]so[.]8 / { fallback = $$NF } END { if (fallback != "") print fallback }'\'')"; \ test -n "$$ffi"; \ ln -sfn "$$ffi" "$(UVHS_RUNTIME_LIB_DIR)/libffi.so.6"; \ - pcre="$(UVHS_COMPAT_PCRE_LIB)"; \ - if [ -z "$$pcre" ] && ldd "$$UV_ROOT/bin/uv_shell_exec" 2>/dev/null | grep -q "libpcre[.]so[.]1 => not found"; then \ + pcre=""; \ + if ldd "$$UV_ROOT/bin/uv_shell_exec" 2>/dev/null | grep -q "libpcre[.]so[.]1 => not found"; then \ for candidate in "$$UV_ROOT/shlib_install/libpcre.so.1" "$$UV_ROOT/shlib/libpcre.so.1"; do \ if [ -f "$$candidate" ]; then pcre="$$candidate"; break; fi; \ done; \ if [ -z "$$pcre" ]; then \ - echo "ERROR: uv_shell_exec needs libpcre.so.1; set UVHS_COMPAT_PCRE_LIB" >&2; \ + echo "ERROR: uv_shell_exec needs libpcre.so.1 under UV_ROOT" >&2; \ exit 1; \ fi; \ fi; \ if [ -n "$$pcre" ]; then test -f "$$pcre"; ln -sfn "$$pcre" "$(UVHS_RUNTIME_LIB_DIR)/libpcre.so.1"; fi' -uvhs_tools_check: - bash "$(UVHS_ROOT_DIR)/uvhs/check_flow_tools.sh" - uvhs_prepare: uvhs_preflight test -n "$(UVHS_WORK_DIR)" rm -rf "$(UVHS_WORK_DIR)/script" @@ -212,14 +187,13 @@ uvhs_sync_uvw_axi4_to_ddr4: uvhs_prepare echo "INFO: verified UVHS DDR DCP AXI data width: $$expected_width"' uvhs_filelist: uvhs_export_vivado_ip uvhs_export_generalbus - bash "$(UVHS_ROOT_DIR)/uvhs/generate_filelist.sh" \ + bash "$(UVHS_ROOT_DIR)/tools/generate_rtl_filelist.sh" uvhs \ "$(CORE_DIR)" "$(UVHS_WORK_DIR)" "$(CPU)" "$(UVHS_FILELIST)" \ -- $(RTL_INCLUDE) uvhs_frontend: uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ $(UVHS_FLOW_ENV) \ - UVHS_FRONTEND_THREADS="$(UVHS_FRONTEND_THREADS)" UVHS_FRONTEND_PROCESSES="$(UVHS_FRONTEND_PROCESSES)" \ bash "$$UV_ROOT/bin/uv_shell" -bypass_vivado_version_check \ -s "$(UVHS_ROOT_DIR)/uvhs/frontend_run.tcl" |& tee frontend_run.log; \ grep -Fxq UVHS_FRONTEND_SUCCESS frontend_run.log' @@ -230,15 +204,10 @@ uvhs: uvhs_frontend uvhs_backend: bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ $(UVHS_FLOW_ENV) \ - UVHS_FPGA_THREADS="$(UVHS_FPGA_THREADS)" UVHS_FPGA_PROCESSES="$(UVHS_FPGA_PROCESSES)" \ bash "$$UV_ROOT/bin/uv_shell" -bypass_vivado_version_check \ -s "$(UVHS_ROOT_DIR)/uvhs/backend_run.tcl" |& tee backend_run.log; \ grep -Fxq UVHS_BACKEND_SUCCESS backend_run.log' -# Keep the compatibility target serial even when the caller enables make -j. -uvhs_all: uvhs - $(MAKE) uvhs_backend - uvhs_check_timing: test -f "$(UVHS_BITSTREAM_DIR)/after_xtalk_fix_timing_summary.txt" ! grep -q 'Timing constraints are not met' "$(UVHS_BITSTREAM_DIR)/after_xtalk_fix_timing_summary.txt" @@ -258,7 +227,6 @@ uvhs_bitstream: uvhs_backend uvhs_write_bitstream: test -d "$(UVHS_RUNTIME_DB)" test -f "$(UVHS_ROOT_DIR)/uvhs/hw_run_download.tcl" - test -f "$(UVHS_ROOT_DIR)/uvhs/runtime_control.tcl" test -x "$(UVHS_ROOT_DIR)/uvhs/runtime_session.sh" mkdir -p "$(UVHS_RUNTIME_WORK_DIR)" "$(UVHS_RUNTIME_TMP_DIR)" $(UVHS_TOOL_ENV) UVHS_DB_PATH="$(UVHS_RUNTIME_DB)" \ @@ -281,9 +249,9 @@ uvhs_runtime_status: uvhs_runtime_check @echo "UVHS_RUNTIME_LOG=$(UVHS_RUNTIME_LOG)" define uvhs_runtime_command - UVHS_RUNTIME_COMMAND_TIMEOUT="$(UVHS_RUNTIME_TIMEOUT)" \ - bash "$(UVHS_ROOT_DIR)/uvhs/enqueue_runtime_command.sh" \ - "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_ROOT_DIR)/uvhs/runtime_command.tcl" $(1) + bash "$(UVHS_ROOT_DIR)/uvhs/runtime_session.sh" enqueue \ + "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_ROOT_DIR)/uvhs/runtime_command.tcl" \ + "$(UVHS_RUNTIME_TIMEOUT)" $(1) endef uvhs_halt_soc: uvhs_runtime_check @@ -298,7 +266,7 @@ uvhs_write_ddr: uvhs_runtime_check uvhs_write_flash: uvhs_runtime_check test -f "$(WORKLOAD)" - $(call uvhs_runtime_command,write_flash "$(WORKLOAD)" "$(UVHS_TARGET_PACK)" "$(UVHS_TARGET_FPGA)" 0 0 0x0 0x8000) + $(call uvhs_runtime_command,write_flash "$(WORKLOAD)" B0 F2 0 0 0x0 0x8000) uvhs_runtime_stop: uvhs_runtime_check $(call uvhs_runtime_command,stop) From 33389a3bc041224a59608abca7307e52bfabb492 Mon Sep 17 00:00:00 2001 From: klin02 Date: Sun, 2 Aug 2026 22:23:48 +0800 Subject: [PATCH 14/62] refactor(fpga_diff): tighten UVHS defaults Use the fully routed 70/35 LUT fill-rate pair for XiangShan and fix the validated U2.2 platform in the frontend and backend drivers. Restore update_core_flist.sh as the shared Vivado/UVHS entry point and deduplicate GeneralBus width validation without weakening cache checks. Co-authored-by: Kamimiao --- fpga_diff/Makefile | 2 +- ...e_rtl_filelist.sh => update_core_flist.sh} | 4 ++-- fpga_diff/uvhs/README.md | 6 ++--- fpga_diff/uvhs/backend_run.tcl | 3 +-- fpga_diff/uvhs/frontend_run.tcl | 3 +-- fpga_diff/uvhs/uvhs.mk | 22 +++++++++---------- 6 files changed, 18 insertions(+), 22 deletions(-) rename fpga_diff/tools/{generate_rtl_filelist.sh => update_core_flist.sh} (97%) diff --git a/fpga_diff/Makefile b/fpga_diff/Makefile index a819cac4..680cfc7b 100755 --- a/fpga_diff/Makefile +++ b/fpga_diff/Makefile @@ -42,7 +42,7 @@ bitstream: # RTL_INCLUDE accepts RTL files, directories, and .f/.flist/.list file lists. update_core_flist: - @./tools/generate_rtl_filelist.sh vivado "$(CORE_DIR)" -- $(RTL_INCLUDE) + @./tools/update_core_flist.sh vivado "$(CORE_DIR)" -- $(RTL_INCLUDE) # Launch Vivado with FPGA project configuration vivado: check_vivado_version diff --git a/fpga_diff/tools/generate_rtl_filelist.sh b/fpga_diff/tools/update_core_flist.sh similarity index 97% rename from fpga_diff/tools/generate_rtl_filelist.sh rename to fpga_diff/tools/update_core_flist.sh index 5b930a9d..f793d058 100755 --- a/fpga_diff/tools/generate_rtl_filelist.sh +++ b/fpga_diff/tools/update_core_flist.sh @@ -5,8 +5,8 @@ set -euo pipefail usage() { cat >&2 <<'EOF' Usage: - generate_rtl_filelist.sh vivado CORE_DIR [--] [RTL_INCLUDE ...] - generate_rtl_filelist.sh uvhs CORE_DIR WORK_DIR CPU OUTPUT [--] [RTL_INCLUDE ...] + update_core_flist.sh vivado CORE_DIR [--] [RTL_INCLUDE ...] + update_core_flist.sh uvhs CORE_DIR WORK_DIR CPU OUTPUT [--] [RTL_INCLUDE ...] EOF exit 2 } diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index fa6015d6..21475c67 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -18,7 +18,7 @@ conversion. The UVHS flow only consumes that result. `RTL_INCLUDE` accepts RTL files, directories, and nested `.f`, `.flist`, or `.list` files. Relative entries are resolved from the file list that contains -them. Both build flows call `tools/generate_rtl_filelist.sh`, which uses +them. Both build flows call `tools/update_core_flist.sh`, which uses `tools/rtl_filelist_lib.sh` for parsing. Vivado mode generates `cpu_files.tcl`; UVHS mode combines the parsed additions with release RTL and FPGA-Diff wrappers in `filelist.f`. @@ -60,7 +60,7 @@ timing signoff, bitstream generation, and runtime database commit. Fill-rate validation and automatic partitioning are kept next to that sequence in `backend_run.tcl`. -The default XiangShan partition limits are 80% LUT and 30% LUT6. They can be +The default XiangShan partition limits are 70% LUT and 35% LUT6. They can be changed with `UVHS_LUT_FILL_RATE` and `UVHS_LUT6_FILL_RATE` for placement experiments. `UVHS_EXPORT_IP_FORCE=1` regenerates cached Vivado and generalBus IP. `uvhs_clean` removes only the selected work directory and refuses to run @@ -113,7 +113,7 @@ or DDR pins. | File | Role | | --- | --- | | `uvhs.mk` | Build, packaging, and runtime targets. | -| `../tools/generate_rtl_filelist.sh` | Shared Vivado/UVHS RTL file-list entry point. | +| `../tools/update_core_flist.sh` | Shared Vivado/UVHS RTL file-list entry point. | | `../tools/rtl_filelist_lib.sh` | Nested file-list parsing and path resolution. | | `flow_common.tcl` | Shared UVHS path, environment, and source helpers. | | `frontend_run.tcl` | RTL/IP import, elaboration, and uvsyn frontend. | diff --git a/fpga_diff/uvhs/backend_run.tcl b/fpga_diff/uvhs/backend_run.tcl index b4c65999..5c9ef5e3 100644 --- a/fpga_diff/uvhs/backend_run.tcl +++ b/fpga_diff/uvhs/backend_run.tcl @@ -14,8 +14,7 @@ set_option clock.async_control.force_accept true set_option time.enable_sign_off true set_option time.incremental_sign_off true -set platform [uvhs::env_or_default PLATFORM U2.2] -create_system_design -name VU19P_X4 -platform $platform +create_system_design -name VU19P_X4 -platform U2.2 uvhs::source_required topology.tcl set ::env(UVHS_ASSIGN_PIN_TOP) none diff --git a/fpga_diff/uvhs/frontend_run.tcl b/fpga_diff/uvhs/frontend_run.tcl index 40214fcd..5b9c4dea 100644 --- a/fpga_diff/uvhs/frontend_run.tcl +++ b/fpga_diff/uvhs/frontend_run.tcl @@ -88,10 +88,9 @@ set_option time.enable_sign_off true set_option time.incremental_sign_off true set_option signal.uhd.sampling_clock.allow_local_clock true -set platform [uvhs::env_or_default PLATFORM U2.2] set design_top fpga_top_debug set ddr_inst_path ${design_top}.core_def.U_UVHS_UVW_AXI4_TO_DDR4 -create_system_design -name VU19P_X4 -platform $platform +create_system_design -name VU19P_X4 -platform U2.2 uvhs::source_required topology.tcl uvhs::source_required assign_pin.tcl diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index cbfc7225..7704a7e3 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -14,8 +14,8 @@ UVHS_GBUS_JSON := $(UVHS_GBUS_IP_DIR)/uvw_axi3_generalbus.json UVHS_GBUS_GEN_DIR := $(UVHS_WORK_DIR)/ip-gen/generalbus UVHS_KEEP_FPGAS ?= -UVHS_LUT_FILL_RATE ?= $(if $(filter kmh,$(CPU)),80,) -UVHS_LUT6_FILL_RATE ?= $(if $(filter kmh,$(CPU)),30,) +UVHS_LUT_FILL_RATE ?= $(if $(filter kmh,$(CPU)),70,) +UVHS_LUT6_FILL_RATE ?= $(if $(filter kmh,$(CPU)),35,) UVHS_UVW_AXI4_TO_DDR4_FILES := \ rtl/soc/uvw_axi4_to_ddr4.dcp \ @@ -73,7 +73,7 @@ uvhs_preflight: test -x "$$UV_ROOT/bin/uv_shell_exec" test -x "$(UVHS_ROOT_DIR)/uvhs/uv_shell_exec_compat.sh" test -x "$(UVHS_ROOT_DIR)/uvhs/shell_compat.sh" - test -x "$(UVHS_ROOT_DIR)/tools/generate_rtl_filelist.sh" + test -x "$(UVHS_ROOT_DIR)/tools/update_core_flist.sh" test -f "$(UVHS_ROOT_DIR)/uvhs/vivado_pre_opt.tcl" test -f "$(UVHS_GBUS_GENERATOR)" test -f "$(UVHS_GBUS_JSON)" @@ -126,14 +126,15 @@ uvhs_export_generalbus: uvhs_prepare bash -c 'set -euo pipefail; \ source_ip_dir="$(UVHS_GBUS_IP_DIR)"; generator="$(UVHS_GBUS_GENERATOR)"; \ gen_dir="$(UVHS_GBUS_GEN_DIR)"; release="$$gen_dir/uvw_general_bus"; \ + gbus_stub_is_64() { \ + grep -Eq "output[[:space:]]+\\[63:0\\][[:space:]]*dut_axi_wdata" "$$1" && \ + grep -Eq "input[[:space:]]+\\[63:0\\][[:space:]]*dut_axi_rdata" "$$1"; \ + }; \ test -f "$$generator"; test -f "$(UVHS_GBUS_JSON)"; \ if [ "$(UVHS_EXPORT_IP_FORCE)" = 1 ] || \ [ ! -s "$$release/uvw_general_bus.dcp" ] || \ [ ! -s "$$release/uvw_general_bus_Stub.v" ] || \ - ! grep -Eq "output[[:space:]]+\\[63:0\\][[:space:]]*dut_axi_wdata" \ - "$$release/uvw_general_bus_Stub.v" || \ - ! grep -Eq "input[[:space:]]+\\[63:0\\][[:space:]]*dut_axi_rdata" \ - "$$release/uvw_general_bus_Stub.v"; then \ + ! gbus_stub_is_64 "$$release/uvw_general_bus_Stub.v"; then \ rm -rf "$$gen_dir"; mkdir -p "$$gen_dir"; \ ip_dir="$$gen_dir/ip-src"; \ cp -a "$$source_ip_dir" "$$ip_dir"; \ @@ -153,15 +154,12 @@ uvhs_export_generalbus: uvhs_prepare fi; \ test -s "$$release/uvw_general_bus.dcp"; \ test -s "$$release/uvw_general_bus_Stub.v"; \ + gbus_stub_is_64 "$$release/uvw_general_bus_Stub.v"; \ rm -rf "$(UVHS_WORK_DIR)/rtl/soc/uvw_general_bus"; \ mkdir -p "$(UVHS_WORK_DIR)/rtl/soc" "$(UVHS_WORK_DIR)/rtl/stubs"; \ cp -a "$$release" "$(UVHS_WORK_DIR)/rtl/soc/uvw_general_bus"; \ cp -f "$$release/uvw_general_bus_Stub.v" \ "$(UVHS_WORK_DIR)/rtl/stubs/uvw_general_bus.v"; \ - grep -Eq "output[[:space:]]+\\[63:0\\][[:space:]]*dut_axi_wdata" \ - "$(UVHS_WORK_DIR)/rtl/stubs/uvw_general_bus.v"; \ - grep -Eq "input[[:space:]]+\\[63:0\\][[:space:]]*dut_axi_rdata" \ - "$(UVHS_WORK_DIR)/rtl/stubs/uvw_general_bus.v"; \ echo "INFO: prepared 64-bit UVHS generalBus DCP"' uvhs_sync_uvw_axi4_to_ddr4: uvhs_prepare @@ -187,7 +185,7 @@ uvhs_sync_uvw_axi4_to_ddr4: uvhs_prepare echo "INFO: verified UVHS DDR DCP AXI data width: $$expected_width"' uvhs_filelist: uvhs_export_vivado_ip uvhs_export_generalbus - bash "$(UVHS_ROOT_DIR)/tools/generate_rtl_filelist.sh" uvhs \ + bash "$(UVHS_ROOT_DIR)/tools/update_core_flist.sh" uvhs \ "$(CORE_DIR)" "$(UVHS_WORK_DIR)" "$(CPU)" "$(UVHS_FILELIST)" \ -- $(RTL_INCLUDE) From 491b816eb7ccb387beeb305e162ee9c2c4577131 Mon Sep 17 00:00:00 2001 From: klin02 Date: Sun, 2 Aug 2026 22:56:44 +0800 Subject: [PATCH 15/62] fix(fpga_diff): expose FPGAs for XiangShan partitioning Keep all four B0 FPGAs in the default XiangShan UVHS topology so automatic partitioning can reproduce the routed 70/35 setup. Leave NutShell on the single F2 path. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 3 +++ fpga_diff/uvhs/uvhs.mk | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 21475c67..fea16234 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -66,6 +66,9 @@ experiments. `UVHS_EXPORT_IP_FORCE=1` regenerates cached Vivado and generalBus IP. `uvhs_clean` removes only the selected work directory and refuses to run while its runtime session is active. +XiangShan leaves all four B0 FPGAs available to the automatic partitioner; +the validated 70/35 result used F2 and F3. NutShell keeps the single F2 FPGA. + ## Runtime ```sh diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 7704a7e3..002a867d 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -13,7 +13,7 @@ UVHS_GBUS_GENERATOR := $(UVHS_GBUS_IP_DIR)/gen_generalbus_ip.py UVHS_GBUS_JSON := $(UVHS_GBUS_IP_DIR)/uvw_axi3_generalbus.json UVHS_GBUS_GEN_DIR := $(UVHS_WORK_DIR)/ip-gen/generalbus -UVHS_KEEP_FPGAS ?= +UVHS_KEEP_FPGAS ?= $(if $(filter kmh,$(CPU)),b0.f0 b0.f1 b0.f2 b0.f3,) UVHS_LUT_FILL_RATE ?= $(if $(filter kmh,$(CPU)),70,) UVHS_LUT6_FILL_RATE ?= $(if $(filter kmh,$(CPU)),35,) From 584c828586fbe118d0c6151787db0b6456cb43ba Mon Sep 17 00:00:00 2001 From: klin02 Date: Sun, 2 Aug 2026 23:18:11 +0800 Subject: [PATCH 16/62] refactor(fpga_diff): unify UVHS build entry point Run the frontend and backend serially from make uvhs while retaining the stage targets for debugging and reuse. Remove uvhs_bitstream and the single-F2 packaging path because multi-FPGA runtime uses the committed hw.dat database and its per-FPGA PnR outputs. Co-authored-by: Kamimiao --- fpga_diff/README.md | 1 - fpga_diff/uvhs/README.md | 10 ++++------ fpga_diff/uvhs/uvhs.mk | 26 ++++---------------------- 3 files changed, 8 insertions(+), 29 deletions(-) diff --git a/fpga_diff/README.md b/fpga_diff/README.md index 38077e2a..1c960bc2 100755 --- a/fpga_diff/README.md +++ b/fpga_diff/README.md @@ -57,7 +57,6 @@ invoke: ```shell make uvhs CPU= CORE_DIR=/path/to/release/build SUFFIX= -make uvhs_bitstream CPU= SUFFIX= ``` See [`uvhs/README.md`](uvhs/README.md) for the board-template and vendor-DDR diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index fea16234..9aa9d818 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -36,14 +36,12 @@ FPGA-Diff wrappers in `filelist.f`. ```sh make uvhs CPU= CORE_DIR=/path/to/release/build \ RTL_INCLUDE=/path/to/extra.f SUFFIX= -make uvhs_bitstream CPU= SUFFIX= ``` -`RTL_INCLUDE` is optional. These are the two stable build entry points intended -for an upper-level build system: `uvhs` prepares and synthesizes the UVHS -database, while `uvhs_bitstream` runs backend implementation, checks timing, -and publishes `fpga_top_debug.bit`. The lower-level `uvhs_frontend` and -`uvhs_backend` targets remain available for stage reuse and debugging. +`RTL_INCLUDE` is optional. `uvhs` is the stable build entry point: it runs the +frontend and backend in order, generates the per-FPGA bitstreams, and commits +the runtime database. The lower-level `uvhs_frontend` and `uvhs_backend` +targets remain available for stage reuse and debugging. `uvhs_frontend` performs these steps: diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 002a867d..c1603374 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -52,15 +52,10 @@ UVHS_FLOW_ENV = \ UVHS_LUT_FILL_RATE="$(UVHS_LUT_FILL_RATE)" \ UVHS_LUT6_FILL_RATE="$(UVHS_LUT6_FILL_RATE)" -UVHS_PNR_DIR := $(UVHS_WORK_DIR)/hw.dat/Compile/PnR/B0/F2/vivado/Rundir/Strategy_uv_high_fanout_explore -UVHS_BITSTREAM_DIR := $(UVHS_PNR_DIR)/bitstream -UVHS_BIT_HOME := $(UVHS_WORK_DIR)/ready-to-program - -.PHONY: uvhs uvhs_bitstream uvhs_preflight uvhs_prepare \ +.PHONY: uvhs uvhs_preflight uvhs_prepare \ uvhs_export_vivado_ip uvhs_export_generalbus \ uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist \ - uvhs_frontend uvhs_backend uvhs_check_timing \ - uvhs_package_bitstream uvhs_clean uvhs_write_bitstream \ + uvhs_frontend uvhs_backend uvhs_clean uvhs_write_bitstream \ uvhs_halt_soc uvhs_reset_cpu uvhs_write_ddr uvhs_write_flash \ uvhs_runtime_status uvhs_runtime_check uvhs_runtime_stop @@ -196,8 +191,9 @@ uvhs_frontend: uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist -s "$(UVHS_ROOT_DIR)/uvhs/frontend_run.tcl" |& tee frontend_run.log; \ grep -Fxq UVHS_FRONTEND_SUCCESS frontend_run.log' -# Stable frontend entry point, analogous to the normal `all` project setup. +# Stable build entry point. Keep the stages serialized even under parallel make. uvhs: uvhs_frontend + $(MAKE) uvhs_backend uvhs_backend: bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ @@ -206,20 +202,6 @@ uvhs_backend: -s "$(UVHS_ROOT_DIR)/uvhs/backend_run.tcl" |& tee backend_run.log; \ grep -Fxq UVHS_BACKEND_SUCCESS backend_run.log' -uvhs_check_timing: - test -f "$(UVHS_BITSTREAM_DIR)/after_xtalk_fix_timing_summary.txt" - ! grep -q 'Timing constraints are not met' "$(UVHS_BITSTREAM_DIR)/after_xtalk_fix_timing_summary.txt" - -uvhs_package_bitstream: uvhs_check_timing - test -f "$(UVHS_BITSTREAM_DIR)/pnr.bit" - mkdir -p "$(UVHS_BIT_HOME)" - ln -sf "$(UVHS_BITSTREAM_DIR)/pnr.bit" "$(UVHS_BIT_HOME)/fpga_top_debug.bit" - @echo "FPGA_BIT_HOME=$(UVHS_BIT_HOME)" - -# Stable implementation entry point, analogous to the normal `bitstream` target. -uvhs_bitstream: uvhs_backend - $(MAKE) uvhs_package_bitstream - # The UVHS API requires one session to retain ownership of the downloaded # database. Detach that session after programming and track it in runtime-work. uvhs_write_bitstream: From 192007ca880ee610b690e46b6b4b6d5d3903b112 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 00:27:05 +0800 Subject: [PATCH 17/62] refactor(fpga_diff): consolidate UVHS IP preparation Move Vivado, generalBus, and external DDR preparation behind one helper and keep uvhs.mk focused on flow targets. Rename the retained runtime Tcl entry point to describe its command-server lifetime. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 12 +- fpga_diff/uvhs/prepare_ip.sh | 109 ++++++++++++++++++ ...hw_run_download.tcl => runtime_server.tcl} | 0 fpga_diff/uvhs/uvhs.mk | 109 ++---------------- 4 files changed, 128 insertions(+), 102 deletions(-) create mode 100755 fpga_diff/uvhs/prepare_ip.sh rename fpga_diff/uvhs/{hw_run_download.tcl => runtime_server.tcl} (100%) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 9aa9d818..8f64e0a6 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -41,7 +41,9 @@ make uvhs CPU= CORE_DIR=/path/to/release/build \ `RTL_INCLUDE` is optional. `uvhs` is the stable build entry point: it runs the frontend and backend in order, generates the per-FPGA bitstreams, and commits the runtime database. The lower-level `uvhs_frontend` and `uvhs_backend` -targets remain available for stage reuse and debugging. +targets remain available for stage reuse and debugging. `ENV_SCRIPTS_HOME` +defaults to the current `fpga_diff` directory; it only needs to be overridden +when build outputs should live elsewhere. `uvhs_frontend` performs these steps: @@ -82,7 +84,8 @@ make uvhs_runtime_stop CPU= SUFFIX= `uvhs_write_bitstream` downloads the completed runtime database, initializes the hardware, and keeps a detached UVHS session alive. Later reset and memory commands must use that same session. Its PID, command files, and log are stored -under `runtime-work` in the selected build directory. +under `runtime-work` in the selected build directory. The session has no idle +timeout; use `uvhs_runtime_stop` after testing to release it cleanly. `uvhs_write_ddr` converts the Vivado address/data-pair format to the DDR DCP word width and calls `writemem -rtl`. It leaves the CPU halted until @@ -113,7 +116,7 @@ or DDR pins. | File | Role | | --- | --- | -| `uvhs.mk` | Build, packaging, and runtime targets. | +| `uvhs.mk` | Build and runtime target wiring. | | `../tools/update_core_flist.sh` | Shared Vivado/UVHS RTL file-list entry point. | | `../tools/rtl_filelist_lib.sh` | Nested file-list parsing and path resolution. | | `flow_common.tcl` | Shared UVHS path, environment, and source helpers. | @@ -124,9 +127,10 @@ or DDR pins. | `timing_common.tcl` | External clock constraints. | | `async_clocks.tcl` | Asynchronous clock groups used by backend and Vivado PnR. | | `vivado_pre_opt.tcl` | XDMA refclock and CDC constraints. | +| `prepare_ip.sh` | Vivado IP export plus generalBus and DDR DCP preparation. | | `export_vivado_ip.tcl` | Repository-owned Vivado IP export. | | `shell_compat.sh` | Generated launcher shell correction. | | `uv_shell_exec_compat.sh` | Runtime library wrapper. | -| `hw_run_download.tcl` | Download, reset sequencing, and command service. | +| `runtime_server.tcl` | Download, reset sequencing, and command service. | | `runtime_command.tcl` | Reset, DDR, and flash operations. | | `runtime_session.sh` | Runtime lifecycle, command submission, and status. | diff --git a/fpga_diff/uvhs/prepare_ip.sh b/fpga_diff/uvhs/prepare_ip.sh new file mode 100755 index 00000000..eb422e5b --- /dev/null +++ b/fpga_diff/uvhs/prepare_ip.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +set -euo pipefail + +[[ $# == 7 ]] || { + echo "Usage: $0 ORIGIN_DIR WORK_DIR CORE_DIR JOBS FORCE DDR_SOURCE DDR_WIDTH" >&2 + exit 64 +} +: "${UV_ROOT:?UV_ROOT is not set}" +: "${UV_XILINX_VIVADO:?UV_XILINX_VIVADO is not set}" + +origin_dir=$1 +work_dir=$2 +core_dir=$3 +jobs=$4 +force=$5 +ddr_source=$6 +ddr_width=$7 + +require_file() { + [[ -s $1 ]] || { + echo "ERROR: required UVHS IP file is missing or empty: $1" >&2 + exit 1 + } +} + +generalbus_stub_is_64() { + grep -Eq 'output[[:space:]]+\[63:0\][[:space:]]*dut_axi_wdata' "$1" && + grep -Eq 'input[[:space:]]+\[63:0\][[:space:]]*dut_axi_rdata' "$1" +} + +# Export the Vivado IP owned by this repository. +vivado=$UV_XILINX_VIVADO/bin/vivado +version=$("$vivado" -version | awk '/^Vivado v/ { sub(/^Vivado v/, ""); sub(/ .*/, ""); print; exit }') +[[ -n $version ]] || { + echo "ERROR: unable to determine Vivado version from $vivado" >&2 + exit 1 +} +vivado_args=( + --origin_dir "$origin_dir" --out_dir "$work_dir" + --vivado_version "$version" --core_dir "$core_dir" --jobs "$jobs" +) +[[ $force != 1 ]] || vivado_args+=(--force) +export VIVADO_HOME=$UV_XILINX_VIVADO XILINX_VIVADO=$UV_XILINX_VIVADO +"$vivado" -mode batch -source "$origin_dir/uvhs/export_vivado_ip.tcl" \ + -tclargs "${vivado_args[@]}" + +# Generate the vendor generalBus from a private copy. Its original generator +# removes the Vivado project before an asynchronous DCP copy has completed. +gbus_source=$UV_ROOT/platform/U2.2/Prototype/ips/uvw_gbus.3.1 +gbus_gen=$work_dir/ip-gen/generalbus +gbus_release=$gbus_gen/uvw_general_bus +require_file "$gbus_source/gen_generalbus_ip.py" +require_file "$gbus_source/uvw_axi3_generalbus.json" +if [[ $force == 1 || ! -s $gbus_release/uvw_general_bus.dcp || + ! -s $gbus_release/uvw_general_bus_Stub.v ]] || + ! generalbus_stub_is_64 "$gbus_release/uvw_general_bus_Stub.v"; then + rm -rf "$gbus_gen" + mkdir -p "$gbus_gen" + cp -a "$gbus_source" "$gbus_gen/ip-src" + generator=$gbus_gen/ip-src/gen_generalbus_ip.py + sed -i '/os[.]popen.*f_dcp_in.*f_dcp_out/c\ shutil.copy2(f_dcp_in, f_dcp_out)' \ + "$generator" + grep -Fq 'shutil.copy2(f_dcp_in, f_dcp_out)' "$generator" + json=$gbus_gen/uvw_axi3_generalbus.json + cp -f "$gbus_source/uvw_axi3_generalbus.json" "$json" + sed -i -E \ + "s|(\"IP_LOCATION\"[[:space:]]*:[[:space:]]*)\"[^\"]*\"|\1\"$gbus_gen/ip-src\"|; \ + s|(\"DATA_WIDTH\"[[:space:]]*:[[:space:]]*)\"[^\"]*\"|\1\"64\"|" "$json" + (cd "$gbus_gen" && PATH="$UV_XILINX_VIVADO/bin:$PATH" \ + python3 "$generator" -j "$json") +fi +require_file "$gbus_release/uvw_general_bus.dcp" +require_file "$gbus_release/uvw_general_bus_Stub.v" +generalbus_stub_is_64 "$gbus_release/uvw_general_bus_Stub.v" +rm -rf "$work_dir/rtl/soc/uvw_general_bus" +mkdir -p "$work_dir/rtl/soc" "$work_dir/rtl/stubs" +cp -a "$gbus_release" "$work_dir/rtl/soc/uvw_general_bus" +cp -f "$gbus_release/uvw_general_bus_Stub.v" "$work_dir/rtl/stubs/uvw_general_bus.v" +echo "INFO: prepared 64-bit UVHS generalBus DCP" + +# Import the externally generated DDR DCP using its canonical work-tree names. +[[ $ddr_width == 64 || $ddr_width == 256 ]] || { + echo "ERROR: unsupported UVHS DDR AXI width: $ddr_width" >&2 + exit 1 +} +ddr_files=( + rtl/soc/uvw_axi4_to_ddr4.dcp rtl/soc/uvw_axi4_to_ddr4_Stub.v + script/uvw_axi4_to_ddr4_pblock.tcl script/custom_parts_ddr4_KSM26SES8_2666.csv +) +for rel in "${ddr_files[@]}"; do + base=${rel##*/} + destination=$work_dir/$rel + source_file= + for candidate in "$ddr_source/$rel" "$ddr_source/$base"; do + [[ ! -f $candidate ]] || { source_file=$candidate; break; } + done + [[ -n $source_file ]] || source_file=$(find "$ddr_source" -type f -name "$base" -size +0c -print -quit) + [[ -z $source_file ]] || { mkdir -p "$(dirname "$destination")"; cp -f "$source_file" "$destination"; } +done +for rel in "${ddr_files[@]:0:3}"; do require_file "$work_dir/$rel"; done +ddr_stub=$work_dir/rtl/soc/uvw_axi4_to_ddr4_Stub.v +if gzip -t "$ddr_stub" 2>/dev/null; then + gzip -dc "$ddr_stub" >"$ddr_stub.decompressed" + mv -f "$ddr_stub.decompressed" "$ddr_stub" +fi +last_bit=$((ddr_width - 1)) +grep -Eq "input[[:space:]]+\[$last_bit:0\][[:space:]]*ddr4ip_dut_axi_wdata" "$ddr_stub" +grep -Eq "output[[:space:]]+\[$last_bit:0\][[:space:]]*ddr4ip_dut_axi_rdata" "$ddr_stub" +echo "INFO: verified UVHS DDR DCP AXI data width: $ddr_width" diff --git a/fpga_diff/uvhs/hw_run_download.tcl b/fpga_diff/uvhs/runtime_server.tcl similarity index 100% rename from fpga_diff/uvhs/hw_run_download.tcl rename to fpga_diff/uvhs/runtime_server.tcl diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index c1603374..9a4dc680 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -8,24 +8,11 @@ UVHS_FILELIST := $(UVHS_WORK_DIR)/rtl/filelist.f UVHS_EXPORT_IP_FORCE ?= 0 UVHS_EXPORT_IP_JOBS := $(if $(strip $(VIVADO_JOBS)),$(VIVADO_JOBS),8) -UVHS_GBUS_IP_DIR := $(UV_ROOT)/platform/U2.2/Prototype/ips/uvw_gbus.3.1 -UVHS_GBUS_GENERATOR := $(UVHS_GBUS_IP_DIR)/gen_generalbus_ip.py -UVHS_GBUS_JSON := $(UVHS_GBUS_IP_DIR)/uvw_axi3_generalbus.json -UVHS_GBUS_GEN_DIR := $(UVHS_WORK_DIR)/ip-gen/generalbus UVHS_KEEP_FPGAS ?= $(if $(filter kmh,$(CPU)),b0.f0 b0.f1 b0.f2 b0.f3,) UVHS_LUT_FILL_RATE ?= $(if $(filter kmh,$(CPU)),70,) UVHS_LUT6_FILL_RATE ?= $(if $(filter kmh,$(CPU)),35,) -UVHS_UVW_AXI4_TO_DDR4_FILES := \ - rtl/soc/uvw_axi4_to_ddr4.dcp \ - rtl/soc/uvw_axi4_to_ddr4_Stub.v \ - script/uvw_axi4_to_ddr4_pblock.tcl \ - script/custom_parts_ddr4_KSM26SES8_2666.csv -UVHS_UVW_AXI4_TO_DDR4_REQUIRED_FILES := \ - rtl/soc/uvw_axi4_to_ddr4.dcp \ - rtl/soc/uvw_axi4_to_ddr4_Stub.v \ - script/uvw_axi4_to_ddr4_pblock.tcl UVHS_DDR_RTL_INST := fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4 UVHS_RUNTIME_LIB_DIR := $(UVHS_WORK_DIR)/.uvhs-runtime-lib UVHS_RUNTIME_DB := $(UVHS_WORK_DIR)/hw.dat @@ -53,8 +40,7 @@ UVHS_FLOW_ENV = \ UVHS_LUT6_FILL_RATE="$(UVHS_LUT6_FILL_RATE)" .PHONY: uvhs uvhs_preflight uvhs_prepare \ - uvhs_export_vivado_ip uvhs_export_generalbus \ - uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist \ + uvhs_prepare_ip uvhs_filelist \ uvhs_frontend uvhs_backend uvhs_clean uvhs_write_bitstream \ uvhs_halt_soc uvhs_reset_cpu uvhs_write_ddr uvhs_write_flash \ uvhs_runtime_status uvhs_runtime_check uvhs_runtime_stop @@ -68,12 +54,9 @@ uvhs_preflight: test -x "$$UV_ROOT/bin/uv_shell_exec" test -x "$(UVHS_ROOT_DIR)/uvhs/uv_shell_exec_compat.sh" test -x "$(UVHS_ROOT_DIR)/uvhs/shell_compat.sh" + test -x "$(UVHS_ROOT_DIR)/uvhs/prepare_ip.sh" test -x "$(UVHS_ROOT_DIR)/tools/update_core_flist.sh" test -f "$(UVHS_ROOT_DIR)/uvhs/vivado_pre_opt.tcl" - test -f "$(UVHS_GBUS_GENERATOR)" - test -f "$(UVHS_GBUS_JSON)" - command -v python3 >/dev/null - command -v gzip >/dev/null test -d "$(UVHS_TEMPLATE_DIR)/script" test -f "$(UVHS_TEMPLATE_DIR)/Makefile" test -f "$(UVHS_TEMPLATE_DIR)/script/1B_4F_HGC_assemble.tcl" @@ -103,88 +86,18 @@ uvhs_prepare: uvhs_preflight cp -f "$(UVHS_TEMPLATE_DIR)/Makefile" "$(UVHS_WORK_DIR)/Makefile" mkdir -p "$(UVHS_WORK_DIR)/rtl/soc" "$(UVHS_WORK_DIR)/rtl/device/pcie" -uvhs_export_vivado_ip: uvhs_prepare - bash -c 'set -euo pipefail; \ - export VIVADO_HOME="$$UV_XILINX_VIVADO" XILINX_VIVADO="$$UV_XILINX_VIVADO"; \ - version="$$("$$UV_XILINX_VIVADO/bin/vivado" -version | sed -n "s/^Vivado v\\([^ ]*\\).*/\\1/p" | head -n 1)"; \ - test -n "$$version"; \ - $(UVHS_FLOW_ENV) "$$UV_XILINX_VIVADO/bin/vivado" -mode batch \ - -source "$(UVHS_ROOT_DIR)/uvhs/export_vivado_ip.tcl" -tclargs \ - --origin_dir "$(UVHS_ROOT_DIR)" --out_dir "$(UVHS_WORK_DIR)" \ - --vivado_version "$$version" --core_dir "$(CORE_DIR)" \ - --jobs "$(UVHS_EXPORT_IP_JOBS)" \ - $(if $(filter 1,$(UVHS_EXPORT_IP_FORCE)),--force,)' - -# The vendor generator starts an asynchronous DCP copy before deleting its -# project. Make that copy synchronous in the private work-directory copy. -uvhs_export_generalbus: uvhs_prepare - bash -c 'set -euo pipefail; \ - source_ip_dir="$(UVHS_GBUS_IP_DIR)"; generator="$(UVHS_GBUS_GENERATOR)"; \ - gen_dir="$(UVHS_GBUS_GEN_DIR)"; release="$$gen_dir/uvw_general_bus"; \ - gbus_stub_is_64() { \ - grep -Eq "output[[:space:]]+\\[63:0\\][[:space:]]*dut_axi_wdata" "$$1" && \ - grep -Eq "input[[:space:]]+\\[63:0\\][[:space:]]*dut_axi_rdata" "$$1"; \ - }; \ - test -f "$$generator"; test -f "$(UVHS_GBUS_JSON)"; \ - if [ "$(UVHS_EXPORT_IP_FORCE)" = 1 ] || \ - [ ! -s "$$release/uvw_general_bus.dcp" ] || \ - [ ! -s "$$release/uvw_general_bus_Stub.v" ] || \ - ! gbus_stub_is_64 "$$release/uvw_general_bus_Stub.v"; then \ - rm -rf "$$gen_dir"; mkdir -p "$$gen_dir"; \ - ip_dir="$$gen_dir/ip-src"; \ - cp -a "$$source_ip_dir" "$$ip_dir"; \ - gen_script="$$ip_dir/gen_generalbus_ip.py"; \ - sed -i "/os[.]popen.*f_dcp_in.*f_dcp_out/c\\ shutil.copy2(f_dcp_in, f_dcp_out)" \ - "$$gen_script"; \ - grep -Fq "shutil.copy2(f_dcp_in, f_dcp_out)" "$$gen_script"; \ - json="$$gen_dir/uvw_axi3_generalbus.json"; \ - cp -f "$(UVHS_GBUS_JSON)" "$$json"; \ - sed -i -E \ - "s|(\"IP_LOCATION\"[[:space:]]*:[[:space:]]*)\"[^\"]*\"|\1\"$$ip_dir\"|; \ - s|(\"DATA_WIDTH\"[[:space:]]*:[[:space:]]*)\"[^\"]*\"|\1\"64\"|" \ - "$$json"; \ - export VIVADO_HOME="$$UV_XILINX_VIVADO" XILINX_VIVADO="$$UV_XILINX_VIVADO"; \ - cd "$$gen_dir"; \ - PATH="$$UV_XILINX_VIVADO/bin:$$PATH" python3 "$$gen_script" -j "$$json"; \ - fi; \ - test -s "$$release/uvw_general_bus.dcp"; \ - test -s "$$release/uvw_general_bus_Stub.v"; \ - gbus_stub_is_64 "$$release/uvw_general_bus_Stub.v"; \ - rm -rf "$(UVHS_WORK_DIR)/rtl/soc/uvw_general_bus"; \ - mkdir -p "$(UVHS_WORK_DIR)/rtl/soc" "$(UVHS_WORK_DIR)/rtl/stubs"; \ - cp -a "$$release" "$(UVHS_WORK_DIR)/rtl/soc/uvw_general_bus"; \ - cp -f "$$release/uvw_general_bus_Stub.v" \ - "$(UVHS_WORK_DIR)/rtl/stubs/uvw_general_bus.v"; \ - echo "INFO: prepared 64-bit UVHS generalBus DCP"' - -uvhs_sync_uvw_axi4_to_ddr4: uvhs_prepare - bash -c 'set -euo pipefail; \ - src="$(UVHS_UVW_AXI4_TO_DDR4_SRC)"; work="$(UVHS_WORK_DIR)"; \ - for rel in $(UVHS_UVW_AXI4_TO_DDR4_FILES); do \ - base="$${rel##*/}"; dst="$$work/$$rel"; found=""; \ - for candidate in "$$src/$$rel" "$$src/$$base"; do \ - if [ -f "$$candidate" ]; then found="$$candidate"; break; fi; \ - done; \ - if [ -z "$$found" ]; then found="$$(find "$$src" -type f -name "$$base" -size +0c -print -quit)"; fi; \ - if [ -n "$$found" ]; then mkdir -p "$$(dirname "$$dst")"; cp -f "$$found" "$$dst"; fi; \ - done; \ - for rel in $(UVHS_UVW_AXI4_TO_DDR4_REQUIRED_FILES); do test -s "$$work/$$rel"; done; \ - expected_width="$(UVHS_DDR_AXI_WIDTH)"; last_bit="$$((expected_width - 1))"; \ - stub="$$work/rtl/soc/uvw_axi4_to_ddr4_Stub.v"; \ - if gzip -t "$$stub" 2>/dev/null; then \ - gzip -dc "$$stub" > "$$stub.decompressed"; \ - mv -f "$$stub.decompressed" "$$stub"; \ - fi; \ - grep -Eq "input[[:space:]]+\\[$$last_bit:0\\][[:space:]]*ddr4ip_dut_axi_wdata" "$$stub"; \ - grep -Eq "output[[:space:]]+\\[$$last_bit:0\\][[:space:]]*ddr4ip_dut_axi_rdata" "$$stub"; \ - echo "INFO: verified UVHS DDR DCP AXI data width: $$expected_width"' +uvhs_prepare_ip: uvhs_prepare + $(UVHS_FLOW_ENV) bash "$(UVHS_ROOT_DIR)/uvhs/prepare_ip.sh" \ + "$(UVHS_ROOT_DIR)" "$(UVHS_WORK_DIR)" "$(CORE_DIR)" \ + "$(UVHS_EXPORT_IP_JOBS)" "$(UVHS_EXPORT_IP_FORCE)" \ + "$(UVHS_UVW_AXI4_TO_DDR4_SRC)" "$(UVHS_DDR_AXI_WIDTH)" -uvhs_filelist: uvhs_export_vivado_ip uvhs_export_generalbus +uvhs_filelist: uvhs_prepare_ip bash "$(UVHS_ROOT_DIR)/tools/update_core_flist.sh" uvhs \ "$(CORE_DIR)" "$(UVHS_WORK_DIR)" "$(CPU)" "$(UVHS_FILELIST)" \ -- $(RTL_INCLUDE) -uvhs_frontend: uvhs_sync_uvw_axi4_to_ddr4 uvhs_filelist +uvhs_frontend: uvhs_filelist bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ $(UVHS_FLOW_ENV) \ bash "$$UV_ROOT/bin/uv_shell" -bypass_vivado_version_check \ @@ -206,7 +119,7 @@ uvhs_backend: # database. Detach that session after programming and track it in runtime-work. uvhs_write_bitstream: test -d "$(UVHS_RUNTIME_DB)" - test -f "$(UVHS_ROOT_DIR)/uvhs/hw_run_download.tcl" + test -f "$(UVHS_ROOT_DIR)/uvhs/runtime_server.tcl" test -x "$(UVHS_ROOT_DIR)/uvhs/runtime_session.sh" mkdir -p "$(UVHS_RUNTIME_WORK_DIR)" "$(UVHS_RUNTIME_TMP_DIR)" $(UVHS_TOOL_ENV) UVHS_DB_PATH="$(UVHS_RUNTIME_DB)" \ @@ -219,7 +132,7 @@ uvhs_write_bitstream: "$(UVHS_RUNTIME_TIMEOUT)" \ bash "$$UV_ROOT/bin/uv_shell" -rt_shell \ -workdir "$(UVHS_RUNTIME_WORK_DIR)" \ - -script "$(UVHS_ROOT_DIR)/uvhs/hw_run_download.tcl" + -script "$(UVHS_ROOT_DIR)/uvhs/runtime_server.tcl" uvhs_runtime_check: bash "$(UVHS_ROOT_DIR)/uvhs/runtime_session.sh" check \ From 6bb38acb29983b1bbb0b9c9b7d3aa0477e47343a Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 01:18:49 +0800 Subject: [PATCH 18/62] refactor(fpga_diff): organize UVHS flow scripts Separate compilation and runtime helpers into dedicated directories while keeping uvhs.mk as the stable entry point. Rename the shared clock file to timing.tcl and retain post-transform asynchronous clock constraints. Document the verified runtime release behavior and updated script layout. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 41 +++++++++++-------- .../uvhs/{ => compilation}/assign_pin.tcl | 0 .../uvhs/{ => compilation}/async_clocks.tcl | 0 .../uvhs/{ => compilation}/backend_run.tcl | 0 .../{ => compilation}/export_vivado_ip.tcl | 2 +- .../uvhs/{ => compilation}/flow_common.tcl | 0 .../uvhs/{ => compilation}/frontend_run.tcl | 2 +- .../uvhs/{ => compilation}/prepare_ip.sh | 3 +- .../uvhs/{ => compilation}/shell_compat.sh | 0 .../timing.tcl} | 0 fpga_diff/uvhs/{ => compilation}/topology.tcl | 0 .../uvhs/{ => compilation}/vivado_pre_opt.tcl | 0 .../uvhs/{ => runtime}/runtime_command.tcl | 0 .../uvhs/{ => runtime}/runtime_server.tcl | 0 .../uvhs/{ => runtime}/runtime_session.sh | 0 .../{ => runtime}/uv_shell_exec_compat.sh | 0 fpga_diff/uvhs/uvhs.mk | 36 ++++++++-------- 17 files changed, 48 insertions(+), 36 deletions(-) rename fpga_diff/uvhs/{ => compilation}/assign_pin.tcl (100%) rename fpga_diff/uvhs/{ => compilation}/async_clocks.tcl (100%) rename fpga_diff/uvhs/{ => compilation}/backend_run.tcl (100%) rename fpga_diff/uvhs/{ => compilation}/export_vivado_ip.tcl (99%) rename fpga_diff/uvhs/{ => compilation}/flow_common.tcl (100%) rename fpga_diff/uvhs/{ => compilation}/frontend_run.tcl (98%) rename fpga_diff/uvhs/{ => compilation}/prepare_ip.sh (97%) rename fpga_diff/uvhs/{ => compilation}/shell_compat.sh (100%) rename fpga_diff/uvhs/{timing_common.tcl => compilation/timing.tcl} (100%) rename fpga_diff/uvhs/{ => compilation}/topology.tcl (100%) rename fpga_diff/uvhs/{ => compilation}/vivado_pre_opt.tcl (100%) rename fpga_diff/uvhs/{ => runtime}/runtime_command.tcl (100%) rename fpga_diff/uvhs/{ => runtime}/runtime_server.tcl (100%) rename fpga_diff/uvhs/{ => runtime}/runtime_session.sh (100%) rename fpga_diff/uvhs/{ => runtime}/uv_shell_exec_compat.sh (100%) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 8f64e0a6..4cb8f45b 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -58,7 +58,12 @@ when build outputs should live elsewhere. transformation, remap, partition, localization, system routing, FPGA PnR, timing signoff, bitstream generation, and runtime database commit. Fill-rate validation and automatic partitioning are kept next to that sequence in -`backend_run.tcl`. +`compilation/backend_run.tcl`. + +`compilation/timing.tcl` supplies the external clocks to the frontend. The +asynchronous groups are applied from `compilation/async_clocks.tcl` after UVHS +has inferred and transformed clocks, then applied again to each linked FPGA +netlist before Vivado optimization. The default XiangShan partition limits are 70% LUT and 35% LUT6. They can be changed with `UVHS_LUT_FILL_RATE` and `UVHS_LUT6_FILL_RATE` for placement @@ -86,6 +91,10 @@ the hardware, and keeps a detached UVHS session alive. Later reset and memory commands must use that same session. Its PID, command files, and log are stored under `runtime-work` in the selected build directory. The session has no idle timeout; use `uvhs_runtime_stop` after testing to release it cleanly. +After the session stops, the released FPGA reports link down; loading the same +database and calling `initialize` without `download` fails. Start the next +runtime session with `uvhs_write_bitstream` so it reloads and downloads +`hw.dat`. `uvhs_write_ddr` converts the Vivado address/data-pair format to the DDR DCP word width and calls `writemem -rtl`. It leaves the CPU halted until @@ -119,18 +128,18 @@ or DDR pins. | `uvhs.mk` | Build and runtime target wiring. | | `../tools/update_core_flist.sh` | Shared Vivado/UVHS RTL file-list entry point. | | `../tools/rtl_filelist_lib.sh` | Nested file-list parsing and path resolution. | -| `flow_common.tcl` | Shared UVHS path, environment, and source helpers. | -| `frontend_run.tcl` | RTL/IP import, elaboration, and uvsyn frontend. | -| `backend_run.tcl` | Fill-rate setup, partition, routing, PnR, and database commit. | -| `topology.tcl` | Selects the FPGA set from the vendor board assembly. | -| `assign_pin.tcl` | B0/F2 clock, PCIe, UART, JTAG, SD, and control pins. | -| `timing_common.tcl` | External clock constraints. | -| `async_clocks.tcl` | Asynchronous clock groups used by backend and Vivado PnR. | -| `vivado_pre_opt.tcl` | XDMA refclock and CDC constraints. | -| `prepare_ip.sh` | Vivado IP export plus generalBus and DDR DCP preparation. | -| `export_vivado_ip.tcl` | Repository-owned Vivado IP export. | -| `shell_compat.sh` | Generated launcher shell correction. | -| `uv_shell_exec_compat.sh` | Runtime library wrapper. | -| `runtime_server.tcl` | Download, reset sequencing, and command service. | -| `runtime_command.tcl` | Reset, DDR, and flash operations. | -| `runtime_session.sh` | Runtime lifecycle, command submission, and status. | +| `compilation/flow_common.tcl` | Shared UVHS path, environment, and source helpers. | +| `compilation/frontend_run.tcl` | RTL/IP import, elaboration, and uvsyn frontend. | +| `compilation/backend_run.tcl` | Fill-rate setup, partition, routing, PnR, and database commit. | +| `compilation/topology.tcl` | Selects the FPGA set from the vendor board assembly. | +| `compilation/assign_pin.tcl` | B0/F2 clock, PCIe, UART, JTAG, SD, and control pins. | +| `compilation/timing.tcl` | External clock constraints registered by the frontend. | +| `compilation/async_clocks.tcl` | Asynchronous groups applied after clock transformation. | +| `compilation/vivado_pre_opt.tcl` | XDMA refclock and CDC constraints. | +| `compilation/prepare_ip.sh` | Vivado IP export plus generalBus and DDR DCP preparation. | +| `compilation/export_vivado_ip.tcl` | Repository-owned Vivado IP export. | +| `compilation/shell_compat.sh` | Generated launcher shell correction. | +| `runtime/uv_shell_exec_compat.sh` | Runtime library wrapper used by build and runtime shells. | +| `runtime/runtime_server.tcl` | Download, reset sequencing, and command service. | +| `runtime/runtime_command.tcl` | Reset, DDR, and flash operations. | +| `runtime/runtime_session.sh` | Runtime lifecycle, command submission, and status. | diff --git a/fpga_diff/uvhs/assign_pin.tcl b/fpga_diff/uvhs/compilation/assign_pin.tcl similarity index 100% rename from fpga_diff/uvhs/assign_pin.tcl rename to fpga_diff/uvhs/compilation/assign_pin.tcl diff --git a/fpga_diff/uvhs/async_clocks.tcl b/fpga_diff/uvhs/compilation/async_clocks.tcl similarity index 100% rename from fpga_diff/uvhs/async_clocks.tcl rename to fpga_diff/uvhs/compilation/async_clocks.tcl diff --git a/fpga_diff/uvhs/backend_run.tcl b/fpga_diff/uvhs/compilation/backend_run.tcl similarity index 100% rename from fpga_diff/uvhs/backend_run.tcl rename to fpga_diff/uvhs/compilation/backend_run.tcl diff --git a/fpga_diff/uvhs/export_vivado_ip.tcl b/fpga_diff/uvhs/compilation/export_vivado_ip.tcl similarity index 99% rename from fpga_diff/uvhs/export_vivado_ip.tcl rename to fpga_diff/uvhs/compilation/export_vivado_ip.tcl index 3ff8174e..5af2584f 100644 --- a/fpga_diff/uvhs/export_vivado_ip.tcl +++ b/fpga_diff/uvhs/compilation/export_vivado_ip.tcl @@ -11,7 +11,7 @@ set core_dir "" proc print_help {} { puts "Usage:" - puts " vivado -mode batch -source uvhs/export_vivado_ip.tcl -tclargs \\" + puts " vivado -mode batch -source uvhs/compilation/export_vivado_ip.tcl -tclargs \\" puts " --origin_dir --out_dir \[--vivado_version \] \[--core_dir \] \[--force\] \[--jobs N\]" exit 0 } diff --git a/fpga_diff/uvhs/flow_common.tcl b/fpga_diff/uvhs/compilation/flow_common.tcl similarity index 100% rename from fpga_diff/uvhs/flow_common.tcl rename to fpga_diff/uvhs/compilation/flow_common.tcl diff --git a/fpga_diff/uvhs/frontend_run.tcl b/fpga_diff/uvhs/compilation/frontend_run.tcl similarity index 98% rename from fpga_diff/uvhs/frontend_run.tcl rename to fpga_diff/uvhs/compilation/frontend_run.tcl index 5b9c4dea..f0672fa4 100644 --- a/fpga_diff/uvhs/frontend_run.tcl +++ b/fpga_diff/uvhs/compilation/frontend_run.tcl @@ -94,7 +94,7 @@ create_system_design -name VU19P_X4 -platform U2.2 uvhs::source_required topology.tcl uvhs::source_required assign_pin.tcl -set_constraint_files [uvhs::path timing_common.tcl] +set_constraint_files [uvhs::path timing.tcl] foreach reset_port {rstn_sw6 rstn_sw5 rstn_sw4} { create_reset -port ${design_top}.${reset_port} -active 0 } diff --git a/fpga_diff/uvhs/prepare_ip.sh b/fpga_diff/uvhs/compilation/prepare_ip.sh similarity index 97% rename from fpga_diff/uvhs/prepare_ip.sh rename to fpga_diff/uvhs/compilation/prepare_ip.sh index eb422e5b..7c6ac733 100755 --- a/fpga_diff/uvhs/prepare_ip.sh +++ b/fpga_diff/uvhs/compilation/prepare_ip.sh @@ -15,6 +15,7 @@ jobs=$4 force=$5 ddr_source=$6 ddr_width=$7 +script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) require_file() { [[ -s $1 ]] || { @@ -41,7 +42,7 @@ vivado_args=( ) [[ $force != 1 ]] || vivado_args+=(--force) export VIVADO_HOME=$UV_XILINX_VIVADO XILINX_VIVADO=$UV_XILINX_VIVADO -"$vivado" -mode batch -source "$origin_dir/uvhs/export_vivado_ip.tcl" \ +"$vivado" -mode batch -source "$script_dir/export_vivado_ip.tcl" \ -tclargs "${vivado_args[@]}" # Generate the vendor generalBus from a private copy. Its original generator diff --git a/fpga_diff/uvhs/shell_compat.sh b/fpga_diff/uvhs/compilation/shell_compat.sh similarity index 100% rename from fpga_diff/uvhs/shell_compat.sh rename to fpga_diff/uvhs/compilation/shell_compat.sh diff --git a/fpga_diff/uvhs/timing_common.tcl b/fpga_diff/uvhs/compilation/timing.tcl similarity index 100% rename from fpga_diff/uvhs/timing_common.tcl rename to fpga_diff/uvhs/compilation/timing.tcl diff --git a/fpga_diff/uvhs/topology.tcl b/fpga_diff/uvhs/compilation/topology.tcl similarity index 100% rename from fpga_diff/uvhs/topology.tcl rename to fpga_diff/uvhs/compilation/topology.tcl diff --git a/fpga_diff/uvhs/vivado_pre_opt.tcl b/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl similarity index 100% rename from fpga_diff/uvhs/vivado_pre_opt.tcl rename to fpga_diff/uvhs/compilation/vivado_pre_opt.tcl diff --git a/fpga_diff/uvhs/runtime_command.tcl b/fpga_diff/uvhs/runtime/runtime_command.tcl similarity index 100% rename from fpga_diff/uvhs/runtime_command.tcl rename to fpga_diff/uvhs/runtime/runtime_command.tcl diff --git a/fpga_diff/uvhs/runtime_server.tcl b/fpga_diff/uvhs/runtime/runtime_server.tcl similarity index 100% rename from fpga_diff/uvhs/runtime_server.tcl rename to fpga_diff/uvhs/runtime/runtime_server.tcl diff --git a/fpga_diff/uvhs/runtime_session.sh b/fpga_diff/uvhs/runtime/runtime_session.sh similarity index 100% rename from fpga_diff/uvhs/runtime_session.sh rename to fpga_diff/uvhs/runtime/runtime_session.sh diff --git a/fpga_diff/uvhs/uv_shell_exec_compat.sh b/fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh similarity index 100% rename from fpga_diff/uvhs/uv_shell_exec_compat.sh rename to fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 9a4dc680..7e7d4363 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -1,4 +1,6 @@ UVHS_ROOT_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))/..) +UVHS_COMPILATION_DIR := $(UVHS_ROOT_DIR)/uvhs/compilation +UVHS_RUNTIME_DIR := $(UVHS_ROOT_DIR)/uvhs/runtime UVHS_TEMPLATE_DIR ?= UVHS_UVW_AXI4_TO_DDR4_SRC ?= @@ -29,7 +31,7 @@ UVHS_TOOL_ENV = \ MAKEFLAGS="$${MAKEFLAGS:+$$MAKEFLAGS }SHELL=/bin/bash" \ LD_LIBRARY_PATH="$(UVHS_RUNTIME_LIB_DIR):$${LD_LIBRARY_PATH:-}" \ UVHS_RUNTIME_LIB_DIR="$(UVHS_RUNTIME_LIB_DIR)" \ - UVSHELL_EXEC_NAME="$(UVHS_ROOT_DIR)/uvhs/uv_shell_exec_compat.sh" + UVSHELL_EXEC_NAME="$(UVHS_RUNTIME_DIR)/uv_shell_exec_compat.sh" UVHS_FLOW_ENV = \ $(UVHS_TOOL_ENV) \ @@ -52,11 +54,11 @@ uvhs_preflight: test -x "$$UV_XILINX_VIVADO/bin/vivado" test -n "$$UV_LICENSE" test -x "$$UV_ROOT/bin/uv_shell_exec" - test -x "$(UVHS_ROOT_DIR)/uvhs/uv_shell_exec_compat.sh" - test -x "$(UVHS_ROOT_DIR)/uvhs/shell_compat.sh" - test -x "$(UVHS_ROOT_DIR)/uvhs/prepare_ip.sh" + test -x "$(UVHS_RUNTIME_DIR)/uv_shell_exec_compat.sh" + test -x "$(UVHS_COMPILATION_DIR)/shell_compat.sh" + test -x "$(UVHS_COMPILATION_DIR)/prepare_ip.sh" test -x "$(UVHS_ROOT_DIR)/tools/update_core_flist.sh" - test -f "$(UVHS_ROOT_DIR)/uvhs/vivado_pre_opt.tcl" + test -f "$(UVHS_COMPILATION_DIR)/vivado_pre_opt.tcl" test -d "$(UVHS_TEMPLATE_DIR)/script" test -f "$(UVHS_TEMPLATE_DIR)/Makefile" test -f "$(UVHS_TEMPLATE_DIR)/script/1B_4F_HGC_assemble.tcl" @@ -87,7 +89,7 @@ uvhs_prepare: uvhs_preflight mkdir -p "$(UVHS_WORK_DIR)/rtl/soc" "$(UVHS_WORK_DIR)/rtl/device/pcie" uvhs_prepare_ip: uvhs_prepare - $(UVHS_FLOW_ENV) bash "$(UVHS_ROOT_DIR)/uvhs/prepare_ip.sh" \ + $(UVHS_FLOW_ENV) bash "$(UVHS_COMPILATION_DIR)/prepare_ip.sh" \ "$(UVHS_ROOT_DIR)" "$(UVHS_WORK_DIR)" "$(CORE_DIR)" \ "$(UVHS_EXPORT_IP_JOBS)" "$(UVHS_EXPORT_IP_FORCE)" \ "$(UVHS_UVW_AXI4_TO_DDR4_SRC)" "$(UVHS_DDR_AXI_WIDTH)" @@ -101,7 +103,7 @@ uvhs_frontend: uvhs_filelist bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ $(UVHS_FLOW_ENV) \ bash "$$UV_ROOT/bin/uv_shell" -bypass_vivado_version_check \ - -s "$(UVHS_ROOT_DIR)/uvhs/frontend_run.tcl" |& tee frontend_run.log; \ + -s "$(UVHS_COMPILATION_DIR)/frontend_run.tcl" |& tee frontend_run.log; \ grep -Fxq UVHS_FRONTEND_SUCCESS frontend_run.log' # Stable build entry point. Keep the stages serialized even under parallel make. @@ -112,38 +114,38 @@ uvhs_backend: bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ $(UVHS_FLOW_ENV) \ bash "$$UV_ROOT/bin/uv_shell" -bypass_vivado_version_check \ - -s "$(UVHS_ROOT_DIR)/uvhs/backend_run.tcl" |& tee backend_run.log; \ + -s "$(UVHS_COMPILATION_DIR)/backend_run.tcl" |& tee backend_run.log; \ grep -Fxq UVHS_BACKEND_SUCCESS backend_run.log' # The UVHS API requires one session to retain ownership of the downloaded # database. Detach that session after programming and track it in runtime-work. uvhs_write_bitstream: test -d "$(UVHS_RUNTIME_DB)" - test -f "$(UVHS_ROOT_DIR)/uvhs/runtime_server.tcl" - test -x "$(UVHS_ROOT_DIR)/uvhs/runtime_session.sh" + test -f "$(UVHS_RUNTIME_DIR)/runtime_server.tcl" + test -x "$(UVHS_RUNTIME_DIR)/runtime_session.sh" mkdir -p "$(UVHS_RUNTIME_WORK_DIR)" "$(UVHS_RUNTIME_TMP_DIR)" $(UVHS_TOOL_ENV) UVHS_DB_PATH="$(UVHS_RUNTIME_DB)" \ UVHS_COMMAND_FILE="$(UVHS_RUNTIME_COMMAND_FILE)" \ UVHS_RUNTIME_READY_FILE="$(UVHS_RUNTIME_READY_FILE)" \ UVHS_RUNTIME_TMP_DIR="$(UVHS_RUNTIME_TMP_DIR)" \ - bash "$(UVHS_ROOT_DIR)/uvhs/runtime_session.sh" start \ + bash "$(UVHS_RUNTIME_DIR)/runtime_session.sh" start \ "$(UVHS_RUNTIME_PID_FILE)" "$(UVHS_RUNTIME_READY_FILE)" \ "$(UVHS_RUNTIME_LOG)" "$(UVHS_RUNTIME_COMMAND_FILE)" \ "$(UVHS_RUNTIME_TIMEOUT)" \ bash "$$UV_ROOT/bin/uv_shell" -rt_shell \ -workdir "$(UVHS_RUNTIME_WORK_DIR)" \ - -script "$(UVHS_ROOT_DIR)/uvhs/runtime_server.tcl" + -script "$(UVHS_RUNTIME_DIR)/runtime_server.tcl" uvhs_runtime_check: - bash "$(UVHS_ROOT_DIR)/uvhs/runtime_session.sh" check \ + bash "$(UVHS_RUNTIME_DIR)/runtime_session.sh" check \ "$(UVHS_RUNTIME_PID_FILE)" "$(UVHS_RUNTIME_READY_FILE)" uvhs_runtime_status: uvhs_runtime_check @echo "UVHS_RUNTIME_LOG=$(UVHS_RUNTIME_LOG)" define uvhs_runtime_command - bash "$(UVHS_ROOT_DIR)/uvhs/runtime_session.sh" enqueue \ - "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_ROOT_DIR)/uvhs/runtime_command.tcl" \ + bash "$(UVHS_RUNTIME_DIR)/runtime_session.sh" enqueue \ + "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_DIR)/runtime_command.tcl" \ "$(UVHS_RUNTIME_TIMEOUT)" $(1) endef @@ -163,12 +165,12 @@ uvhs_write_flash: uvhs_runtime_check uvhs_runtime_stop: uvhs_runtime_check $(call uvhs_runtime_command,stop) - bash "$(UVHS_ROOT_DIR)/uvhs/runtime_session.sh" wait \ + bash "$(UVHS_RUNTIME_DIR)/runtime_session.sh" wait \ "$(UVHS_RUNTIME_PID_FILE)" "$(UVHS_RUNTIME_READY_FILE)" \ "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_TIMEOUT)" uvhs_clean: - @! bash "$(UVHS_ROOT_DIR)/uvhs/runtime_session.sh" active \ + @! bash "$(UVHS_RUNTIME_DIR)/runtime_session.sh" active \ "$(UVHS_RUNTIME_PID_FILE)" >/dev/null 2>&1 || \ { echo "ERROR: stop the UVHS runtime before cleaning" >&2; exit 1; } test -n "$(UVHS_WORK_DIR)" From 346611384830b1bdbe5195f22efae9ed9ca58f01 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 01:22:08 +0800 Subject: [PATCH 19/62] fix(fpga_diff): constrain UVHS clocks in frontend Declare asynchronous clock groups with the primary frontend clocks so uvsyn does not optimize unrelated domains as synchronous. Reapply the same groups after UVHS clock transformation and per-FPGA Vivado linking. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 10 +++++----- fpga_diff/uvhs/compilation/async_clocks.tcl | 4 ++-- fpga_diff/uvhs/compilation/timing.tcl | 2 ++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 4cb8f45b..3d5fa2e4 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -60,10 +60,10 @@ timing signoff, bitstream generation, and runtime database commit. Fill-rate validation and automatic partitioning are kept next to that sequence in `compilation/backend_run.tcl`. -`compilation/timing.tcl` supplies the external clocks to the frontend. The -asynchronous groups are applied from `compilation/async_clocks.tcl` after UVHS -has inferred and transformed clocks, then applied again to each linked FPGA -netlist before Vivado optimization. +`compilation/timing.tcl` supplies the external clocks and asynchronous groups +to the frontend. The groups are applied again after UVHS has inferred and +transformed clocks, then once more to each linked FPGA netlist before Vivado +optimization. The default XiangShan partition limits are 70% LUT and 35% LUT6. They can be changed with `UVHS_LUT_FILL_RATE` and `UVHS_LUT6_FILL_RATE` for placement @@ -134,7 +134,7 @@ or DDR pins. | `compilation/topology.tcl` | Selects the FPGA set from the vendor board assembly. | | `compilation/assign_pin.tcl` | B0/F2 clock, PCIe, UART, JTAG, SD, and control pins. | | `compilation/timing.tcl` | External clock constraints registered by the frontend. | -| `compilation/async_clocks.tcl` | Asynchronous groups applied after clock transformation. | +| `compilation/async_clocks.tcl` | Shared asynchronous groups for frontend, backend, and PnR. | | `compilation/vivado_pre_opt.tcl` | XDMA refclock and CDC constraints. | | `compilation/prepare_ip.sh` | Vivado IP export plus generalBus and DDR DCP preparation. | | `compilation/export_vivado_ip.tcl` | Repository-owned Vivado IP export. | diff --git a/fpga_diff/uvhs/compilation/async_clocks.tcl b/fpga_diff/uvhs/compilation/async_clocks.tcl index ff0fc1b1..f8988499 100644 --- a/fpga_diff/uvhs/compilation/async_clocks.tcl +++ b/fpga_diff/uvhs/compilation/async_clocks.tcl @@ -1,8 +1,8 @@ ################################################################################ # UVHS asynchronous clock constraints. # -# backend_run.tcl and the Vivado pre-opt stage load this after generated clocks -# are available. +# timing.tcl establishes the frontend relation. The backend and Vivado pre-opt +# stages load this again after transformed or linked clocks are available. ################################################################################ set fpga_diff_async_groups [list] diff --git a/fpga_diff/uvhs/compilation/timing.tcl b/fpga_diff/uvhs/compilation/timing.tcl index 5e62ed5a..572c1520 100644 --- a/fpga_diff/uvhs/compilation/timing.tcl +++ b/fpga_diff/uvhs/compilation/timing.tcl @@ -14,3 +14,5 @@ create_clock -name ddr_ref_clk -period 12.5 [get_ports [fpga_diff_top_port clk7_ create_clock -name CPU_CLK_IN -period 40 [get_ports [fpga_diff_top_port clk5_p]] create_clock -name jtag_vclk -period 83.333 [get_ports [fpga_diff_top_port JTAG_TCK]] create_clock -name pcie_ep_refclk -period 10 [get_ports [fpga_diff_top_port pcie_ep_gt_ref_clk_p]] + +source [file join [file dirname [file normalize [info script]]] async_clocks.tcl] From c3096c0fc494376a7babc9c7f92892778bf0b0ac Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 02:27:34 +0800 Subject: [PATCH 20/62] feat(fpga_diff): add UVHS waveform capture Accept an opt-in probe Tcl file during frontend synthesis. Add a runtime capture command that reconstructs USDB data and converts it to VCD. Keep runtime operations in the database-owning server. Simplify file-based session dispatch and preflight checks, and deduplicate the Vivado IP run setup. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 114 +++++- .../uvhs/compilation/export_vivado_ip.tcl | 48 +-- fpga_diff/uvhs/compilation/frontend_run.tcl | 10 + fpga_diff/uvhs/compilation/prepare_ip.sh | 7 +- fpga_diff/uvhs/runtime/runtime_command.tcl | 194 --------- fpga_diff/uvhs/runtime/runtime_server.tcl | 368 ++++++++++++++---- fpga_diff/uvhs/runtime/runtime_session.sh | 71 ++-- .../uvhs/runtime/uv_shell_exec_compat.sh | 43 +- fpga_diff/uvhs/uvhs.mk | 130 ++++--- 9 files changed, 574 insertions(+), 411 deletions(-) delete mode 100644 fpga_diff/uvhs/runtime/runtime_command.tcl diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 3d5fa2e4..5670195a 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -51,9 +51,24 @@ when build outputs should live elsewhere. 2. Prepares repository-owned Vivado IP and the 64-bit generalBus DCP. 3. Imports the selected DDR DCP and validates its AXI width. 4. Builds the complete RTL file list and checks the expected top module. -5. Elaborates and synthesizes the design with uvsyn. +5. Sources an optional `UVHS_PROBE_TCL`, then elaborates and synthesizes the + design with uvsyn. 6. Registers the DDR instance used by runtime `writemem`. +`uvhs_preflight` is an early prerequisite check, not a synthesis or hardware +test. Its loops check the three required environment variables, host commands, +the selected CPU and release directory, UVHS/Vivado executables, repository +helper scripts, board-template files, and the external DDR directory. This +keeps a missing input from being discovered after a multi-hour run has started. + +IP preparation intentionally retains two files. `prepare_ip.sh` is the outer +orchestrator for three different sources: repository Vivado IP, the vendor +Python generalBus generator, and an external DDR checkpoint. The child +`export_vivado_ip.tcl` must run inside Vivado because it uses project, IP, BD, +and checkpoint commands. Merging them would require Vivado to launch a nested +Vivado process or embedding a generated Tcl file in shell, neither of which +simplifies the execution model. + `uvhs_backend` follows the vendor implementation sequence: clock inference and transformation, remap, partition, localization, system routing, FPGA PnR, timing signoff, bitstream generation, and runtime database commit. Fill-rate @@ -83,6 +98,7 @@ make uvhs_halt_soc CPU= SUFFIX= make uvhs_write_ddr CPU= SUFFIX= WORKLOAD=/path/to/image.txt make uvhs_write_flash CPU= SUFFIX= WORKLOAD=/path/to/image.bin make uvhs_reset_cpu CPU= SUFFIX= +make uvhs_capture CPU= SUFFIX= TRIGGER=/path/to/trigger.ini make uvhs_runtime_stop CPU= SUFFIX= ``` @@ -105,14 +121,97 @@ word width and calls `writemem -rtl`. It leaves the CPU halted until normal JTAG address map are unchanged. A complete readback match is required before the command succeeds. +The runtime implementation has two control layers: + +- `runtime_server.tcl` is loaded once by the `uv_shell` process that owns the + downloaded database. It implements reset, DDR, flash, waveform capture, and + a small command-file service. Hardware operations therefore remain in the + same UVHS process for the whole board session. +- `runtime_session.sh` runs outside UVHS. `start` detaches `uv_shell` and waits + for its ready marker; `check` verifies the process and, when requested, its + ready marker; `enqueue` writes one Tcl argument list atomically and waits for + its result; and `wait` removes session state after the server handles `stop`. + The one-argument `check` also protects `uvhs_clean`. It contains no board + commands. + +The old `runtime_command.tcl` layer was merged into the server. It previously +redeclared all memory helpers on every command and depended on reset procedures +from the server's global Tcl scope. + +## UVHS Waveform Capture + +The reference probe scripts describe compile-time instrumentation, not a +runtime dump. A probe file contains `probe_net` signals to sample and +`trigger_net` signals that may participate in a trigger condition: + +```tcl +probe_net -clock fpga_top_debug.core_def.inter_soc_clk -add { + fpga_top_debug.core_def.cpu_rstn_io + fpga_top_debug.core_def.difftest_startup_ready_pcie +} +trigger_net -add -group boot -clock \ + fpga_top_debug.core_def.inter_soc_clk -signal { + fpga_top_debug.core_def.cpu_rstn_io +} +``` + +Signal hierarchy must match the selected generated RTL. Build a new database +and bitstream with the file supplied explicitly: + +```sh +make uvhs CPU= CORE_DIR=/path/to/release/build SUFFIX=probe \ + UVHS_PROBE_TCL=/path/to/probe.tcl +``` + +The frontend records the probe and trigger declarations. The backend already +runs `trigger_probe -check` after runtime-data initialization and +`trigger_probe -group` after clock transformation, which inserts and groups the +debug hardware before partitioning. + +At runtime, write a trigger condition file using the group and signal names +reported by `query -trigger`: + +```ini +[boot] +LOGIC = OR +fpga_top_debug.core_def.cpu_rstn_io = 1 + +[UHD_FINAL_CONDITIONS_LOGIC] +LOGIC = OR +boot +``` + +After `uvhs_write_bitstream`, `uvhs_capture` checks the condition file, enables +capture and trigger logic, resets the CPU, waits for the trigger, uploads the +UHD data, and reconstructs the waveform. It creates both files below the +selected build directory: + +```text +runtime-work/UHD/uvhs_capture/UvData.usdb +runtime-work/UHD/uvhs_capture/UvData.vcd +``` + +The USDB-to-VCD step is equivalent to: + +```sh +USDB=/path/to/UvData.usdb +$UV_ROOT/uvd/uvs/bin/usdb2vcd \ + -i "$USDB" -o "${USDB%.usdb}.vcd" +``` + +`UVHS_CAPTURE_TIMEOUT` defaults to 60 seconds and `UVHS_CAPTURE_DEPTH` to one +million samples. This is the UVHS UHD path; the normal Vivado flow continues to +use `make dump_ila` and a `.ltx` file. + ## Compatibility Boundary The retained compatibility code is limited to observed tool behavior: - `shell_compat.sh` selects Bash in generated synthesis and PnR launchers that contain Bash syntax. -- `uv_shell_exec_compat.sh` restores runtime libraries after the vendor launcher - sanitizes `LD_LIBRARY_PATH`. +- `uv_shell_exec_compat.sh` prepares the required libffi/libpcre compatibility + links and restores runtime libraries after the vendor launcher sanitizes + `LD_LIBRARY_PATH`. - The generalBus export uses a private generator copy and makes its DCP copy synchronous so the project is not removed before the copy finishes. - `vivado_pre_opt.tcl` preserves the XDMA GT reference clock and marks the @@ -136,10 +235,9 @@ or DDR pins. | `compilation/timing.tcl` | External clock constraints registered by the frontend. | | `compilation/async_clocks.tcl` | Shared asynchronous groups for frontend, backend, and PnR. | | `compilation/vivado_pre_opt.tcl` | XDMA refclock and CDC constraints. | -| `compilation/prepare_ip.sh` | Vivado IP export plus generalBus and DDR DCP preparation. | -| `compilation/export_vivado_ip.tcl` | Repository-owned Vivado IP export. | +| `compilation/prepare_ip.sh` | Coordinates Vivado, generalBus, and external DDR IP preparation. | +| `compilation/export_vivado_ip.tcl` | Runs repository-owned XCI/BD exports inside Vivado. | | `compilation/shell_compat.sh` | Generated launcher shell correction. | | `runtime/uv_shell_exec_compat.sh` | Runtime library wrapper used by build and runtime shells. | -| `runtime/runtime_server.tcl` | Download, reset sequencing, and command service. | -| `runtime/runtime_command.tcl` | Reset, DDR, and flash operations. | -| `runtime/runtime_session.sh` | Runtime lifecycle, command submission, and status. | +| `runtime/runtime_server.tcl` | Download, reset, DDR, flash, capture, and command service. | +| `runtime/runtime_session.sh` | Process lifecycle and atomic command/result transport. | diff --git a/fpga_diff/uvhs/compilation/export_vivado_ip.tcl b/fpga_diff/uvhs/compilation/export_vivado_ip.tcl index 5af2584f..f77039bf 100644 --- a/fpga_diff/uvhs/compilation/export_vivado_ip.tcl +++ b/fpga_diff/uvhs/compilation/export_vivado_ip.tcl @@ -4,7 +4,6 @@ set origin_dir "." set out_dir "./uvhs_ip" -set vivado_version "" set force 0 set jobs 8 set core_dir "" @@ -12,7 +11,7 @@ set core_dir "" proc print_help {} { puts "Usage:" puts " vivado -mode batch -source uvhs/compilation/export_vivado_ip.tcl -tclargs \\" - puts " --origin_dir --out_dir \[--vivado_version \] \[--core_dir \] \[--force\] \[--jobs N\]" + puts " --origin_dir --out_dir \[--core_dir \] \[--force\] \[--jobs N\]" exit 0 } @@ -21,7 +20,6 @@ for {set i 0} {$i < $::argc} {incr i} { switch -- $option { "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } "--out_dir" { incr i; set out_dir [lindex $::argv $i] } - "--vivado_version" { incr i; set vivado_version [lindex $::argv $i] } "--core_dir" { incr i; set core_dir [lindex $::argv $i] } "--force" { set force 1 } "--jobs" { incr i; set jobs [lindex $::argv $i] } @@ -42,10 +40,7 @@ set tcl_dir [file join $origin_dir src tcl common] set export_project_dir [file join $out_dir vivado_ip_export] set export_project [file join $export_project_dir vivado_ip_export.xpr] -if {$vivado_version eq ""} { - set vivado_version [version -short] -} -set ::vivado_version $vivado_version +set ::vivado_version [version -short] set ::core_dir $core_dir if {$force && [file exists $export_project_dir]} { @@ -102,12 +97,7 @@ proc source_ip_tcl {script} { uplevel #0 [list source $script] } -proc run_and_copy_dcp {run_name out_file jobs force} { - if {[file exists $out_file] && !$force} { - puts "INFO: reuse existing $out_file" - return - } - +proc run_synthesis {run_name jobs} { set run [get_runs -quiet $run_name] if {[llength $run] == 0} { error "run $run_name not found" @@ -120,13 +110,23 @@ proc run_and_copy_dcp {run_name out_file jobs force} { set status [get_property STATUS $run] puts "INFO: $run_name status: $status" + if {![string match "*Complete*" $status]} { + error "$run_name did not complete: $status" + } + return $run +} + +proc run_and_copy_dcp {run_name out_file jobs force} { + if {[file exists $out_file] && !$force} { + puts "INFO: reuse existing $out_file" + return + } + + set run [run_synthesis $run_name $jobs] set run_dir [get_property DIRECTORY $run] set dcps [glob -nocomplain [file join $run_dir *.dcp]] if {[llength $dcps] == 0} { - if {![string match "*Complete*" $status]} { - error "$run_name did not complete: $status" - } error "no DCP generated in $run_dir" } @@ -141,21 +141,7 @@ proc run_and_write_opened_dcp {run_name out_file jobs force} { return } - set run [get_runs -quiet $run_name] - if {[llength $run] == 0} { - error "run $run_name not found" - } - - reset_run $run - clear_auto_incremental_imports $run_name - launch_runs $run -jobs $jobs - wait_on_run $run - - set status [get_property STATUS $run] - puts "INFO: $run_name status: $status" - if {![string match "*Complete*" $status]} { - error "$run_name did not complete: $status" - } + run_synthesis $run_name $jobs catch {close_design} open_run $run_name diff --git a/fpga_diff/uvhs/compilation/frontend_run.tcl b/fpga_diff/uvhs/compilation/frontend_run.tcl index f0672fa4..f5a33e37 100644 --- a/fpga_diff/uvhs/compilation/frontend_run.tcl +++ b/fpga_diff/uvhs/compilation/frontend_run.tcl @@ -75,6 +75,7 @@ create_working_space hw.dat set_option syn.computeFeCheckSum true set_parallel_option -max_threads 4 -max_processes 16 -label frontend +set_parallel_option -max_threads 16 -label runtime set_option global.log.label MEMORY set_option syn.checkMultiDriver false @@ -94,6 +95,15 @@ create_system_design -name VU19P_X4 -platform U2.2 uvhs::source_required topology.tcl uvhs::source_required assign_pin.tcl +set probe_script [uvhs::env_or_default UVHS_PROBE_TCL ""] +if {$probe_script ne ""} { + set probe_script [file normalize $probe_script] + if {![file isfile $probe_script]} { + error "UVHS probe script not found: $probe_script" + } + puts "INFO: source UVHS probe script $probe_script" + source $probe_script +} set_constraint_files [uvhs::path timing.tcl] foreach reset_port {rstn_sw6 rstn_sw5 rstn_sw4} { create_reset -port ${design_top}.${reset_port} -active 0 diff --git a/fpga_diff/uvhs/compilation/prepare_ip.sh b/fpga_diff/uvhs/compilation/prepare_ip.sh index 7c6ac733..55bd9dd3 100755 --- a/fpga_diff/uvhs/compilation/prepare_ip.sh +++ b/fpga_diff/uvhs/compilation/prepare_ip.sh @@ -31,14 +31,9 @@ generalbus_stub_is_64() { # Export the Vivado IP owned by this repository. vivado=$UV_XILINX_VIVADO/bin/vivado -version=$("$vivado" -version | awk '/^Vivado v/ { sub(/^Vivado v/, ""); sub(/ .*/, ""); print; exit }') -[[ -n $version ]] || { - echo "ERROR: unable to determine Vivado version from $vivado" >&2 - exit 1 -} vivado_args=( --origin_dir "$origin_dir" --out_dir "$work_dir" - --vivado_version "$version" --core_dir "$core_dir" --jobs "$jobs" + --core_dir "$core_dir" --jobs "$jobs" ) [[ $force != 1 ]] || vivado_args+=(--force) export VIVADO_HOME=$UV_XILINX_VIVADO XILINX_VIVADO=$UV_XILINX_VIVADO diff --git a/fpga_diff/uvhs/runtime/runtime_command.tcl b/fpga_diff/uvhs/runtime/runtime_command.tcl deleted file mode 100644 index 315edd61..00000000 --- a/fpga_diff/uvhs/runtime/runtime_command.tcl +++ /dev/null @@ -1,194 +0,0 @@ -proc uvhs_temp_dir {} { - if {[info exists ::env(UVHS_RUNTIME_TMP_DIR)] && $::env(UVHS_RUNTIME_TMP_DIR) ne ""} { - set path $::env(UVHS_RUNTIME_TMP_DIR) - } else { - set path [pwd] - } - file mkdir $path - return $path -} - -proc uvhs_parse_integer {name value} { - if {![string is wideinteger -strict $value]} { - error "$name is not an integer: $value" - } - return [expr {$value + 0}] -} - -proc uvhs_read_binary {path} { - set input [open $path rb] - fconfigure $input -translation binary -encoding binary - set data [read $input] - close $input - return $data -} - -proc uvhs_write_binary {path data} { - set output [open $path wb] - fconfigure $output -translation binary -encoding binary - puts -nonewline $output $data - close $output -} - -proc uvhs_write_flash_gbus {input_file board fpga port channel base capacity} { - if {![file exists $input_file]} { - error "flash image not found: $input_file" - } - - if {[regexp -nocase {^b([0-9]+)$} $board -> board_index]} { - set board $board_index - } - if {![string is integer -strict $board]} { - error "generalBus board must be an index or B: $board" - } - if {![regexp -nocase {^f([0-9]+)$} $fpga -> fpga_index]} { - error "generalBus FPGA must be F: $fpga" - } - set fpga f$fpga_index - set port [uvhs_parse_integer "generalBus port" $port] - set channel [uvhs_parse_integer "generalBus channel" $channel] - set base [uvhs_parse_integer "flash base" $base] - set capacity [uvhs_parse_integer "flash capacity" $capacity] - set payload [uvhs_read_binary $input_file] - set payload_size [string length $payload] - if {$payload_size == 0} { - error "flash image is empty: $input_file" - } - if {$payload_size > $capacity} { - error "flash image is $payload_size bytes, capacity is $capacity bytes" - } - - set transfer_size [expr {($payload_size + 7) & ~7}] - if {$transfer_size > $capacity} { - error "8-byte-aligned flash transfer exceeds capacity: $transfer_size > $capacity" - } - append payload [string repeat "\x00" [expr {$transfer_size - $payload_size}]] - - set temp_dir [uvhs_temp_dir] - set write_file [file join $temp_dir [format "flash-write-%d.bin" [pid]]] - set read_file [file join $temp_dir [format "flash-read-%d.bin" [pid]]] - uvhs_write_binary $write_file $payload - file delete -force $read_file - - puts [format "INFO: generalBus flash write 0x%llx, %d bytes" $base $transfer_size] - set status [catch { - gbus_dma_write -board $board -fpga $fpga -port $port \ - -addr $base -size $transfer_size -channel $channel -file $write_file - gbus_dma_read -board $board -fpga $fpga -port $port \ - -addr $base -size $transfer_size -channel $channel -file $read_file - set readback [uvhs_read_binary $read_file] - if {![string equal $payload $readback]} { - error "generalBus flash readback mismatch" - } - } message options] - file delete -force $write_file $read_file - if {$status != 0} { - return -options $options $message - } - puts "INFO: generalBus flash full readback passed: $input_file" -} - -proc uvhs_write_ddr_pairs {input_file rtl_path data_width} { - if {![file exists $input_file]} { - error "DDR workload not found: $input_file" - } - if {![string is integer -strict $data_width] || $data_width ni {64 256}} { - error "unsupported DDR AXI data width: $data_width" - } - - set beat_bytes [expr {$data_width / 8}] - set beat_chars [expr {$data_width / 4}] - set input [open $input_file r] - set segment 0 - set line_number 0 - - while {[gets $input address_text] >= 0} { - incr line_number - if {[gets $input data_text] < 0} { - close $input - error "missing data line after line $line_number" - } - incr line_number - set address_text [string trim $address_text] - set data_text [string trim $data_text] - if {![regexp {^[0-9a-fA-F]+$} $address_text]} { - close $input - error "invalid DDR address on line [expr {$line_number - 1}]: $address_text" - } - if {![regexp {^[0-9a-fA-F]+$} $data_text]} { - close $input - error "invalid DDR data on line $line_number" - } - if {[expr {[string length $data_text] % $beat_chars}] != 0} { - close $input - error "DDR data on line $line_number is not aligned to $data_width bits" - } - if {[scan $address_text %llx byte_address] != 1 || [expr {$byte_address % $beat_bytes}] != 0} { - close $input - error "DDR address is not aligned to $beat_bytes bytes: $address_text" - } - - set beat_count [expr {[string length $data_text] / $beat_chars}] - set start_word [expr {$byte_address / $beat_bytes}] - set end_word [expr {$start_word + $beat_count - 1}] - set temp_file [file join [uvhs_temp_dir] [format "ddr-%d-%d.hex" [pid] $segment]] - incr segment - - set output [open $temp_file w] - for {set beat 0} {$beat < $beat_count} {incr beat} { - set first [expr {[string length $data_text] - ($beat + 1) * $beat_chars}] - puts $output [string range $data_text $first [expr {$first + $beat_chars - 1}]] - } - close $output - - puts [format "INFO: DDR backdoor write %s words 0x%llx..0x%llx" \ - $beat_count $start_word $end_word] - set status [catch { - writemem -rtl $rtl_path -start $start_word -end $end_word -file $temp_file -hex - } message options] - file delete -force $temp_file - if {$status != 0} { - close $input - return -options $options $message - } - } - close $input - puts "INFO: DDR backdoor write completed: $input_file" -} - -if {[llength $argv] == 0} { - error "missing UVHS runtime command" -} - -set uvhs_command [lindex $argv 0] -puts "INFO: executing UVHS runtime command: $uvhs_command" -switch -- $uvhs_command { - halt_soc { - uvhs_halt_soc - } - reset_cpu { - uvhs_reset_cpu - } - write_ddr { - if {[llength $argv] < 4} { - error "write_ddr expects 3 arguments" - } - uvhs_hold_cpu_for_memory - uvhs_write_ddr_pairs [lindex $argv 1] [lindex $argv 2] [lindex $argv 3] - } - write_flash { - if {[llength $argv] < 8} { - error "write_flash expects 7 arguments" - } - uvhs_hold_cpu_for_memory - uvhs_write_flash_gbus {*}[lrange $argv 1 7] - uvhs_release_cpu_after_memory - } - stop { - set ::uvhs_keepalive 1 - } - default { - error "unknown UVHS runtime command: $uvhs_command" - } -} -puts "INFO: completed UVHS runtime command: $uvhs_command" diff --git a/fpga_diff/uvhs/runtime/runtime_server.tcl b/fpga_diff/uvhs/runtime/runtime_server.tcl index c089ff73..ec4ade86 100644 --- a/fpga_diff/uvhs/runtime/runtime_server.tcl +++ b/fpga_diff/uvhs/runtime/runtime_server.tcl @@ -1,20 +1,55 @@ -# Download a completed UVHS database and retain the owning runtime session for -# reset and memory commands. +# Download a completed UVHS database and retain its owning runtime session. + +proc uvhs_temp_dir {} { + set path [file join [pwd] tmp] + file mkdir $path + return $path +} + +proc uvhs_parse_integer {name value} { + if {![string is wideinteger -strict $value]} { + error "$name is not an integer: $value" + } + return [expr {$value + 0}] +} + +proc uvhs_read_binary {path} { + set input [open $path rb] + fconfigure $input -translation binary -encoding binary + set data [read $input] + close $input + return $data +} + +proc uvhs_write_binary {path data} { + set output [open $path wb] + fconfigure $output -translation binary -encoding binary + puts -nonewline $output $data + close $output +} + +proc uvhs_write_atomic {path data} { + file mkdir [file dirname $path] + set temp_file "${path}.tmp.[pid]" + uvhs_write_binary $temp_file $data + file rename -force $temp_file $path +} proc uvhs_hold_soc_for_download {} { - reset -name rstn_sw6 -value 0 - reset -name rstn_sw5 -value 0 - reset -name rstn_sw4 -value 0 + foreach reset_name {rstn_sw6 rstn_sw5 rstn_sw4} { + reset -name $reset_name -value 0 + } query -reset } proc uvhs_release_soc_after_download {} { - reset -name rstn_sw6 -value 0 - reset -name rstn_sw5 -value 0 - reset -name rstn_sw4 -value 0 + foreach reset_name {rstn_sw6 rstn_sw5 rstn_sw4} { + reset -name $reset_name -value 0 + } after 1000 - reset -name rstn_sw6 -value 1 - reset -name rstn_sw4 -value 1 + foreach reset_name {rstn_sw6 rstn_sw4} { + reset -name $reset_name -value 1 + } after 1000 reset -name rstn_sw5 -value 1 after 1000 @@ -45,34 +80,231 @@ proc uvhs_release_cpu_after_memory {} { query -reset } -proc uvhs_signal_runtime_ready {} { - if {![info exists ::env(UVHS_RUNTIME_READY_FILE)] || - $::env(UVHS_RUNTIME_READY_FILE) eq ""} { - return +proc uvhs_write_flash_gbus {input_file board fpga port channel base capacity} { + if {![file isfile $input_file]} { + error "flash image not found: $input_file" } - set ready_file $::env(UVHS_RUNTIME_READY_FILE) - file mkdir [file dirname $ready_file] - set temp_file "${ready_file}.tmp.[pid]" - set output [open $temp_file w] - puts $output [pid] - close $output - file rename -force $temp_file $ready_file + + if {[regexp -nocase {^b([0-9]+)$} $board -> board_index]} { + set board $board_index + } + if {![string is integer -strict $board]} { + error "generalBus board must be an index or B: $board" + } + if {![regexp -nocase {^f([0-9]+)$} $fpga -> fpga_index]} { + error "generalBus FPGA must be F: $fpga" + } + set fpga f$fpga_index + set port [uvhs_parse_integer "generalBus port" $port] + set channel [uvhs_parse_integer "generalBus channel" $channel] + set base [uvhs_parse_integer "flash base" $base] + set capacity [uvhs_parse_integer "flash capacity" $capacity] + set payload [uvhs_read_binary $input_file] + set payload_size [string length $payload] + if {$payload_size == 0} { + error "flash image is empty: $input_file" + } + if {$payload_size > $capacity} { + error "flash image is $payload_size bytes, capacity is $capacity bytes" + } + + set transfer_size [expr {($payload_size + 7) & ~7}] + if {$transfer_size > $capacity} { + error "8-byte-aligned flash transfer exceeds capacity: $transfer_size > $capacity" + } + append payload [string repeat "\x00" [expr {$transfer_size - $payload_size}]] + + set temp_dir [uvhs_temp_dir] + set write_file [file join $temp_dir [format "flash-write-%d.bin" [pid]]] + set read_file [file join $temp_dir [format "flash-read-%d.bin" [pid]]] + uvhs_write_binary $write_file $payload + file delete -force $read_file + + puts [format "INFO: generalBus flash write 0x%llx, %d bytes" $base $transfer_size] + set status [catch { + gbus_dma_write -board $board -fpga $fpga -port $port \ + -addr $base -size $transfer_size -channel $channel -file $write_file + gbus_dma_read -board $board -fpga $fpga -port $port \ + -addr $base -size $transfer_size -channel $channel -file $read_file + set readback [uvhs_read_binary $read_file] + if {![string equal $payload $readback]} { + error "generalBus flash readback mismatch" + } + } message options] + file delete -force $write_file $read_file + if {$status != 0} { + return -options $options $message + } + puts "INFO: generalBus flash full readback passed: $input_file" +} + +proc uvhs_write_ddr_pairs {input_file rtl_path data_width} { + if {![file isfile $input_file]} { + error "DDR workload not found: $input_file" + } + if {![string is integer -strict $data_width] || $data_width ni {64 256}} { + error "unsupported DDR AXI data width: $data_width" + } + + set beat_bytes [expr {$data_width / 8}] + set beat_chars [expr {$data_width / 4}] + set input [open $input_file r] + set segment 0 + set line_number 0 + + while {[gets $input address_text] >= 0} { + incr line_number + if {[gets $input data_text] < 0} { + close $input + error "missing data line after line $line_number" + } + incr line_number + set address_text [string trim $address_text] + set data_text [string trim $data_text] + if {![regexp {^[0-9a-fA-F]+$} $address_text]} { + close $input + error "invalid DDR address on line [expr {$line_number - 1}]: $address_text" + } + if {![regexp {^[0-9a-fA-F]+$} $data_text]} { + close $input + error "invalid DDR data on line $line_number" + } + if {[expr {[string length $data_text] % $beat_chars}] != 0} { + close $input + error "DDR data on line $line_number is not aligned to $data_width bits" + } + if {[scan $address_text %llx byte_address] != 1 || + [expr {$byte_address % $beat_bytes}] != 0} { + close $input + error "DDR address is not aligned to $beat_bytes bytes: $address_text" + } + + set beat_count [expr {[string length $data_text] / $beat_chars}] + set start_word [expr {$byte_address / $beat_bytes}] + set end_word [expr {$start_word + $beat_count - 1}] + set temp_file [file join [uvhs_temp_dir] \ + [format "ddr-%d-%d.hex" [pid] $segment]] + incr segment + + set output [open $temp_file w] + for {set beat 0} {$beat < $beat_count} {incr beat} { + set first [expr {[string length $data_text] - ($beat + 1) * $beat_chars}] + puts $output [string range $data_text $first \ + [expr {$first + $beat_chars - 1}]] + } + close $output + + puts [format "INFO: DDR backdoor write %s words 0x%llx..0x%llx" \ + $beat_count $start_word $end_word] + set status [catch { + writemem -rtl $rtl_path -start $start_word -end $end_word \ + -file $temp_file -hex + } message options] + file delete -force $temp_file + if {$status != 0} { + close $input + return -options $options $message + } + } + close $input + puts "INFO: DDR backdoor write completed: $input_file" +} + +proc uvhs_capture_ila {trigger_file output_name timeout depth} { + if {![file isfile $trigger_file]} { + error "trigger condition file not found: $trigger_file" + } + if {![regexp {^[A-Za-z0-9_.-]+$} $output_name]} { + error "capture output name contains unsupported characters: $output_name" + } + set timeout [uvhs_parse_integer "capture timeout" $timeout] + set depth [uvhs_parse_integer "capture depth" $depth] + if {$timeout <= 0 || $depth <= 0} { + error "capture timeout and depth must be positive" + } + + set output_dir [file join [pwd] UHD $output_name] + file delete -force $output_dir + query -trigger + trigger -ini_check $trigger_file + capture -enable + trigger -set -condition $trigger_file -position 5 + trigger -enable + + # The default capture observes boot from CPU reset release. External traffic + # may also satisfy the trigger while this command is waiting. + uvhs_reset_cpu + set trigger_status [trigger -status -wait 1 -timeout $timeout -tclobj] + puts "INFO: UVHS trigger status: $trigger_status" + upload_uhd -depth $depth -out $output_name + wavegen -bindir [file join UHD $output_name] + + set usdb [file join $output_dir UvData.usdb] + if {![file exists $usdb] || [file size $usdb] == 0} { + error "UVHS waveform database was not generated: $usdb" + } + puts "INFO: UVHS waveform database generated: $usdb" +} + +proc uvhs_execute_command {args} { + if {[llength $args] == 0} { + error "missing UVHS runtime command" + } + set command [lindex $args 0] + puts "INFO: executing UVHS runtime command: $command" + switch -- $command { + halt_soc { + if {[llength $args] != 1} { error "halt_soc expects no arguments" } + uvhs_halt_soc + } + reset_cpu { + if {[llength $args] != 1} { error "reset_cpu expects no arguments" } + uvhs_reset_cpu + } + write_ddr { + if {[llength $args] != 4} { error "write_ddr expects 3 arguments" } + uvhs_hold_cpu_for_memory + uvhs_write_ddr_pairs {*}[lrange $args 1 3] + } + write_flash { + if {[llength $args] != 8} { error "write_flash expects 7 arguments" } + uvhs_hold_cpu_for_memory + uvhs_write_flash_gbus {*}[lrange $args 1 7] + uvhs_release_cpu_after_memory + } + capture_ila { + if {[llength $args] != 5} { error "capture_ila expects 4 arguments" } + uvhs_capture_ila {*}[lrange $args 1 4] + } + stop { + if {[llength $args] != 1} { error "stop expects no arguments" } + set ::uvhs_keepalive 1 + } + default { + error "unknown UVHS runtime command: $command" + } + } + puts "INFO: completed UVHS runtime command: $command" +} + +proc uvhs_signal_runtime_ready {} { + uvhs_write_atomic $::uvhs_ready_file "[pid]\n" puts "INFO: UVHS runtime command service is ready" } proc uvhs_clear_runtime_ready {} { - if {[info exists ::env(UVHS_RUNTIME_READY_FILE)] && - $::env(UVHS_RUNTIME_READY_FILE) ne ""} { - file delete -force $::env(UVHS_RUNTIME_READY_FILE) - } + file delete -force $::uvhs_ready_file } -proc uvhs_poll_command_file {} { - if {![info exists ::env(UVHS_COMMAND_FILE)] || $::env(UVHS_COMMAND_FILE) eq ""} { - after 500 uvhs_poll_command_file +proc uvhs_write_command_result {result_file status message} { + if {$result_file eq ""} { return } - set command_file $::env(UVHS_COMMAND_FILE) + uvhs_write_atomic $result_file "$status\n$message" +} + +proc uvhs_poll_command_file {} { + set command_file $::uvhs_command_file if {[file exists $command_file]} { set running_file "${command_file}.running" set uvhs_result_file "" @@ -85,14 +317,7 @@ proc uvhs_poll_command_file {} { set command_message "UVHS runtime command failed: $command_message" } catch {file delete -force $running_file} - if {$uvhs_result_file ne ""} { - set result_tmp "${uvhs_result_file}.tmp.[pid]" - set result [open $result_tmp w] - puts $result $command_status - puts -nonewline $result $command_message - close $result - file rename -force $result_tmp $uvhs_result_file - } + uvhs_write_command_result $uvhs_result_file $command_status $command_message if {$command_status != 0} { puts stderr "ERROR: $command_message" } @@ -101,6 +326,13 @@ proc uvhs_poll_command_file {} { } proc uvhs_serve_runtime_commands {} { + foreach variable {UVHS_COMMAND_FILE UVHS_RUNTIME_READY_FILE} { + if {![info exists ::env($variable)] || $::env($variable) eq ""} { + error "$variable is not set" + } + } + set ::uvhs_command_file $::env(UVHS_COMMAND_FILE) + set ::uvhs_ready_file $::env(UVHS_RUNTIME_READY_FILE) set ::uvhs_keepalive 0 uvhs_signal_runtime_ready uvhs_poll_command_file @@ -108,39 +340,41 @@ proc uvhs_serve_runtime_commands {} { uvhs_clear_runtime_ready } -query -user -query -fpgas -all -query -version +proc uvhs_initialize_runtime {} { + query -user + query -fpgas -all + query -version -if {[info exists ::env(UVHS_DB_PATH)] && $::env(UVHS_DB_PATH) ne ""} { - set uvhs_db_path $::env(UVHS_DB_PATH) -} else { - set uvhs_db_path [file normalize [file join [pwd] .. hw.dat]] -} -puts "INFO: loading runtime database $uvhs_db_path" -load_db -db $uvhs_db_path + if {[info exists ::env(UVHS_DB_PATH)] && $::env(UVHS_DB_PATH) ne ""} { + set db_path $::env(UVHS_DB_PATH) + } else { + set db_path [file normalize [file join [pwd] .. hw.dat]] + } + puts "INFO: loading runtime database $db_path" + load_db -db $db_path -config -connector -query -connector -type fmc -query -voltage + config -connector + query -connector -type fmc + query -voltage -# A release database can lack sign-off defaults. In that case the replay clock -# values already stored in the database remain active. -if {[catch {query -clock -default} uvhs_clock_error]} { - puts "WARN: retaining database replay clocks: $uvhs_clock_error" -} else { - config -clock -default - config -clock -commit - query -clock -} + # A release database can lack sign-off defaults. In that case the replay + # clock values already stored in the database remain active. + if {[catch {query -clock -default} clock_error]} { + puts "WARN: retaining database replay clocks: $clock_error" + } else { + config -clock -default + config -clock -commit + query -clock + } -uvhs_hold_soc_for_download -download -query -ipinfo -initialize -after 1000 -uvhs_release_soc_after_download -query -fpgas -all + uvhs_hold_soc_for_download + download + query -ipinfo + initialize + after 1000 + uvhs_release_soc_after_download + query -fpgas -all +} -# Later commands must execute in the session that owns the downloaded database. +uvhs_initialize_runtime uvhs_serve_runtime_commands diff --git a/fpga_diff/uvhs/runtime/runtime_session.sh b/fpga_diff/uvhs/runtime/runtime_session.sh index cc0c6d78..36b360d8 100755 --- a/fpga_diff/uvhs/runtime/runtime_session.sh +++ b/fpga_diff/uvhs/runtime/runtime_session.sh @@ -6,9 +6,8 @@ usage() { usage: runtime_session.sh start \ [argument ...] - runtime_session.sh active - runtime_session.sh check - runtime_session.sh enqueue [argument ...] + runtime_session.sh check [ready-file] + runtime_session.sh enqueue [argument ...] runtime_session.sh wait EOF exit 64 @@ -27,6 +26,14 @@ process_is_alive() { kill -0 "$1" 2>/dev/null } +write_pid() { + local pid_file=$1 + local pid=$2 + local temp_file="${pid_file}.tmp.$$" + printf '%s\n' "$pid" >"$temp_file" + mv -f "$temp_file" "$pid_file" +} + validate_timeout() { [[ $1 =~ ^[1-9][0-9]*$ ]] || { echo "ERROR: UVHS runtime timeout must be a positive integer" >&2 @@ -79,9 +86,7 @@ case $action in nohup "$@" "$log_file" 2>&1 & pid=$! - pid_temp="${pid_file}.tmp.$$" - printf '%s\n' "$pid" >"$pid_temp" - mv -f "$pid_temp" "$pid_file" + write_pid "$pid_file" "$pid" deadline=$((SECONDS + timeout)) while [[ ! -f $ready_file ]]; do @@ -112,50 +117,38 @@ case $action in echo "ERROR: UVHS runtime published an invalid ready PID" >&2 exit 5 fi - pid_temp="${pid_file}.tmp.$$" - printf '%s\n' "$runtime_pid" >"$pid_temp" - mv -f "$pid_temp" "$pid_file" + write_pid "$pid_file" "$runtime_pid" echo "INFO: UVHS runtime ready (PID $runtime_pid); log: $log_file" ;; - active) - (( $# == 1 )) || usage - pid_file=$1 - if pid=$(read_pid "$pid_file") && process_is_alive "$pid"; then - echo "INFO: UVHS runtime process is active (PID $pid)" - exit 0 - fi - rm -f "$pid_file" - exit 1 - ;; check) - (( $# == 2 )) || usage + (( $# == 1 || $# == 2 )) || usage pid_file=$1 - ready_file=$2 if ! pid=$(read_pid "$pid_file") || ! process_is_alive "$pid"; then - rm -f "$pid_file" "$ready_file" + rm -f "$pid_file" + (( $# != 2 )) || rm -f "$2" echo "ERROR: UVHS runtime is not active; run make uvhs_write_bitstream first" >&2 exit 6 fi - if ! ready_pid=$(read_pid "$ready_file") || [[ $ready_pid != "$pid" ]]; then - echo "ERROR: UVHS runtime PID $pid has no matching ready marker" >&2 - exit 7 + if (( $# == 2 )); then + ready_file=$2 + if ! ready_pid=$(read_pid "$ready_file") || [[ $ready_pid != "$pid" ]]; then + echo "ERROR: UVHS runtime PID $pid has no matching ready marker" >&2 + exit 7 + fi + echo "INFO: UVHS runtime is ready (PID $pid)" + else + echo "INFO: UVHS runtime process is active (PID $pid)" fi - echo "INFO: UVHS runtime is ready (PID $pid)" ;; enqueue) (( $# >= 3 )) || usage command_file=$1 - tcl_script=$2 - timeout=$3 - shift 3 + timeout=$2 + shift 2 validate_timeout "$timeout" - [[ -f $tcl_script ]] || { - echo "ERROR: runtime Tcl script not found: $tcl_script" >&2 - exit 9 - } if [[ -e $command_file || -e $command_file.running ]]; then echo "ERROR: a UVHS runtime command is already pending" >&2 - exit 10 + exit 9 fi result_file="${command_file}.result.$$" @@ -170,14 +163,12 @@ case $action in printf ' ' tcl_quote "$argument" done - printf ']\nsource ' - tcl_quote "$tcl_script" - printf '\n' + printf ']\nuvhs_execute_command {*}$argv\n' } >"$temp_file" mv -n "$temp_file" "$command_file" [[ ! -e $temp_file ]] || { echo "ERROR: command file appeared while enqueueing: $command_file" >&2 - exit 11 + exit 10 } echo "INFO: enqueued UVHS runtime command: $command_file" @@ -185,7 +176,7 @@ case $action in while [[ ! -f $result_file ]]; do if (( SECONDS >= deadline )); then echo "ERROR: timed out waiting for UVHS runtime command after ${timeout}s" >&2 - exit 12 + exit 11 fi sleep 0.2 done @@ -194,7 +185,7 @@ case $action in rm -f "$result_file" if [[ $status != 0 ]]; then echo "ERROR: UVHS runtime command failed: $message" >&2 - exit 13 + exit 12 fi [[ -z $message ]] || echo "INFO: $message" ;; diff --git a/fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh b/fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh index 43eca7d0..da91de9a 100755 --- a/fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh +++ b/fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh @@ -2,13 +2,48 @@ set -euo pipefail : "${UV_ROOT:?UV_ROOT is not set}" +: "${UVHS_RUNTIME_LIB_DIR:?UVHS_RUNTIME_LIB_DIR is not set}" -runtime_library_path=${UVHS_RUNTIME_LIB_DIR:-} +find_library() { + ldconfig -p | awk -v soname="$1" '$1 == soname && !found { print $NF; found = 1 }' +} + +mkdir -p "$UVHS_RUNTIME_LIB_DIR" + +ffi=$(find_library libffi.so.6) +if [[ -z $ffi ]]; then + ffi=$(find_library libffi.so.8) +fi +[[ -n $ffi ]] || { + echo "ERROR: libffi.so.6 or libffi.so.8 is required by uv_shell_exec" >&2 + exit 1 +} +ln -sfn "$ffi" "$UVHS_RUNTIME_LIB_DIR/libffi.so.6" + +if ldd "$UV_ROOT/bin/uv_shell_exec" 2>/dev/null | grep -q 'libpcre[.]so[.]1 => not found'; then + pcre= + for candidate in \ + "$UV_ROOT/shlib_install/libpcre.so.1" \ + "$UV_ROOT/shlib/libpcre.so.1"; do + if [[ -f $candidate ]]; then + pcre=$candidate + break + fi + done + [[ -n $pcre ]] || { + echo "ERROR: uv_shell_exec needs libpcre.so.1 under UV_ROOT" >&2 + exit 1 + } + ln -sfn "$pcre" "$UVHS_RUNTIME_LIB_DIR/libpcre.so.1" +fi + +runtime_library_path=$UVHS_RUNTIME_LIB_DIR if [[ -n ${UMI_LD_LIBRARY_PATH:-} ]]; then - runtime_library_path=${runtime_library_path:+$runtime_library_path:}$UMI_LD_LIBRARY_PATH + runtime_library_path=$runtime_library_path:$UMI_LD_LIBRARY_PATH fi -if [[ -n $runtime_library_path ]]; then - export LD_LIBRARY_PATH=$runtime_library_path +if [[ -n ${LD_LIBRARY_PATH:-} ]]; then + runtime_library_path=$runtime_library_path:$LD_LIBRARY_PATH fi +export LD_LIBRARY_PATH=$runtime_library_path exec "$UV_ROOT/bin/uv_shell_exec" "$@" diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 7e7d4363..5ada9bc8 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -4,13 +4,14 @@ UVHS_RUNTIME_DIR := $(UVHS_ROOT_DIR)/uvhs/runtime UVHS_TEMPLATE_DIR ?= UVHS_UVW_AXI4_TO_DDR4_SRC ?= +UVHS_PROBE_TCL ?= +UVHS_PROBE_PATH := $(if $(strip $(UVHS_PROBE_TCL)),$(abspath $(UVHS_PROBE_TCL)),) UVHS_DDR_AXI_WIDTH := $(if $(filter nutshell,$(CPU)),64,256) UVHS_WORK_DIR := $(ENV_SCRIPTS_HOME)/fpga_diff_uvhs_$(CPU)$(if $(strip $(SUFFIX)),-$(strip $(SUFFIX)),) UVHS_FILELIST := $(UVHS_WORK_DIR)/rtl/filelist.f UVHS_EXPORT_IP_FORCE ?= 0 UVHS_EXPORT_IP_JOBS := $(if $(strip $(VIVADO_JOBS)),$(VIVADO_JOBS),8) - UVHS_KEEP_FPGAS ?= $(if $(filter kmh,$(CPU)),b0.f0 b0.f1 b0.f2 b0.f3,) UVHS_LUT_FILL_RATE ?= $(if $(filter kmh,$(CPU)),70,) UVHS_LUT6_FILL_RATE ?= $(if $(filter kmh,$(CPU)),35,) @@ -20,65 +21,68 @@ UVHS_RUNTIME_LIB_DIR := $(UVHS_WORK_DIR)/.uvhs-runtime-lib UVHS_RUNTIME_DB := $(UVHS_WORK_DIR)/hw.dat UVHS_RUNTIME_WORK_DIR := $(UVHS_WORK_DIR)/runtime-work UVHS_RUNTIME_COMMAND_FILE := $(UVHS_RUNTIME_WORK_DIR)/command.tcl -UVHS_RUNTIME_TMP_DIR := $(UVHS_RUNTIME_WORK_DIR)/tmp UVHS_RUNTIME_PID_FILE := $(UVHS_RUNTIME_WORK_DIR)/uv_shell.pid UVHS_RUNTIME_READY_FILE := $(UVHS_RUNTIME_WORK_DIR)/uv_shell.ready UVHS_RUNTIME_LOG := $(UVHS_RUNTIME_WORK_DIR)/uv_shell.log -UVHS_RUNTIME_TIMEOUT := 600 +UVHS_RUNTIME_TIMEOUT ?= 600 + +UVHS_CAPTURE_TIMEOUT ?= 60 +UVHS_CAPTURE_DEPTH ?= 1000000 +UVHS_CAPTURE_DIR := $(UVHS_RUNTIME_WORK_DIR)/UHD/uvhs_capture +UVHS_CAPTURE_USDB := $(UVHS_CAPTURE_DIR)/UvData.usdb +UVHS_CAPTURE_VCD := $(UVHS_CAPTURE_DIR)/UvData.vcd UVHS_TOOL_ENV = \ PATH="$$UV_ROOT/bin:$$UV_ROOT/lib/venv3.8/bin:$$UV_ROOT/lib/gcc10.3/bin:$$PATH" \ MAKEFLAGS="$${MAKEFLAGS:+$$MAKEFLAGS }SHELL=/bin/bash" \ - LD_LIBRARY_PATH="$(UVHS_RUNTIME_LIB_DIR):$${LD_LIBRARY_PATH:-}" \ UVHS_RUNTIME_LIB_DIR="$(UVHS_RUNTIME_LIB_DIR)" \ UVSHELL_EXEC_NAME="$(UVHS_RUNTIME_DIR)/uv_shell_exec_compat.sh" UVHS_FLOW_ENV = \ $(UVHS_TOOL_ENV) \ UVHS_FLOW=1 \ + UVHS_PROBE_TCL="$(UVHS_PROBE_PATH)" \ XDMA_LINK_WIDTH="$(XDMA_LINK_WIDTH)" \ UVHS_KEEP_FPGAS="$(UVHS_KEEP_FPGAS)" \ UVHS_LUT_FILL_RATE="$(UVHS_LUT_FILL_RATE)" \ UVHS_LUT6_FILL_RATE="$(UVHS_LUT6_FILL_RATE)" .PHONY: uvhs uvhs_preflight uvhs_prepare \ - uvhs_prepare_ip uvhs_filelist \ uvhs_frontend uvhs_backend uvhs_clean uvhs_write_bitstream \ uvhs_halt_soc uvhs_reset_cpu uvhs_write_ddr uvhs_write_flash \ - uvhs_runtime_status uvhs_runtime_check uvhs_runtime_stop + uvhs_capture uvhs_runtime_status uvhs_runtime_stop +# Validate host tools and external inputs before starting a multi-hour build. uvhs_preflight: - test -n "$$UV_ROOT" - test -x "$$UV_ROOT/bin/uv_shell" - test -n "$$UV_XILINX_VIVADO" - test -x "$$UV_XILINX_VIVADO/bin/vivado" - test -n "$$UV_LICENSE" - test -x "$$UV_ROOT/bin/uv_shell_exec" - test -x "$(UVHS_RUNTIME_DIR)/uv_shell_exec_compat.sh" - test -x "$(UVHS_COMPILATION_DIR)/shell_compat.sh" - test -x "$(UVHS_COMPILATION_DIR)/prepare_ip.sh" - test -x "$(UVHS_ROOT_DIR)/tools/update_core_flist.sh" - test -f "$(UVHS_COMPILATION_DIR)/vivado_pre_opt.tcl" - test -d "$(UVHS_TEMPLATE_DIR)/script" - test -f "$(UVHS_TEMPLATE_DIR)/Makefile" - test -f "$(UVHS_TEMPLATE_DIR)/script/1B_4F_HGC_assemble.tcl" - test -d "$(UVHS_UVW_AXI4_TO_DDR4_SRC)" - mkdir -p "$(UVHS_RUNTIME_LIB_DIR)" - bash -c 'set -euo pipefail; \ - ffi="$$(ldconfig -p | awk '\''/libffi[.]so[.]6 / { print $$NF; exit } /libffi[.]so[.]8 / { fallback = $$NF } END { if (fallback != "") print fallback }'\'')"; \ - test -n "$$ffi"; \ - ln -sfn "$$ffi" "$(UVHS_RUNTIME_LIB_DIR)/libffi.so.6"; \ - pcre=""; \ - if ldd "$$UV_ROOT/bin/uv_shell_exec" 2>/dev/null | grep -q "libpcre[.]so[.]1 => not found"; then \ - for candidate in "$$UV_ROOT/shlib_install/libpcre.so.1" "$$UV_ROOT/shlib/libpcre.so.1"; do \ - if [ -f "$$candidate" ]; then pcre="$$candidate"; break; fi; \ - done; \ - if [ -z "$$pcre" ]; then \ - echo "ERROR: uv_shell_exec needs libpcre.so.1 under UV_ROOT" >&2; \ - exit 1; \ - fi; \ - fi; \ - if [ -n "$$pcre" ]; then test -f "$$pcre"; ln -sfn "$$pcre" "$(UVHS_RUNTIME_LIB_DIR)/libpcre.so.1"; fi' + @bash -c 'set -euo pipefail; \ + for variable in UV_ROOT UV_XILINX_VIVADO UV_LICENSE; do \ + [[ -n "$${!variable:-}" ]] || { echo "ERROR: $$variable is not set" >&2; exit 1; }; \ + done; \ + [[ -n "$(CPU)" ]] || { echo "ERROR: CPU is not set" >&2; exit 1; }; \ + for command in bash python3 gzip ldconfig; do \ + command -v "$$command" >/dev/null || { echo "ERROR: command not found: $$command" >&2; exit 1; }; \ + done; \ + for executable in \ + "$$UV_ROOT/bin/uv_shell" "$$UV_ROOT/bin/uv_shell_exec" \ + "$$UV_XILINX_VIVADO/bin/vivado" \ + "$(UVHS_RUNTIME_DIR)/uv_shell_exec_compat.sh" \ + "$(UVHS_COMPILATION_DIR)/shell_compat.sh" \ + "$(UVHS_COMPILATION_DIR)/prepare_ip.sh" \ + "$(UVHS_ROOT_DIR)/tools/update_core_flist.sh"; do \ + [[ -x "$$executable" ]] || { echo "ERROR: executable not found: $$executable" >&2; exit 1; }; \ + done; \ + for file in \ + "$(UVHS_COMPILATION_DIR)/vivado_pre_opt.tcl" \ + "$(UVHS_TEMPLATE_DIR)/Makefile" \ + "$(UVHS_TEMPLATE_DIR)/script/1B_4F_HGC_assemble.tcl"; do \ + [[ -f "$$file" ]] || { echo "ERROR: file not found: $$file" >&2; exit 1; }; \ + done; \ + for directory in "$(CORE_DIR)" "$(UVHS_TEMPLATE_DIR)/script" "$(UVHS_UVW_AXI4_TO_DDR4_SRC)"; do \ + [[ -d "$$directory" ]] || { echo "ERROR: directory not found: $$directory" >&2; exit 1; }; \ + done; \ + if [[ -n "$(UVHS_PROBE_PATH)" && ! -f "$(UVHS_PROBE_PATH)" ]]; then \ + echo "ERROR: UVHS probe script not found: $(UVHS_PROBE_PATH)" >&2; exit 1; \ + fi' uvhs_prepare: uvhs_preflight test -n "$(UVHS_WORK_DIR)" @@ -87,26 +91,22 @@ uvhs_prepare: uvhs_preflight cp -a "$(UVHS_TEMPLATE_DIR)/script" "$(UVHS_WORK_DIR)/" cp -f "$(UVHS_TEMPLATE_DIR)/Makefile" "$(UVHS_WORK_DIR)/Makefile" mkdir -p "$(UVHS_WORK_DIR)/rtl/soc" "$(UVHS_WORK_DIR)/rtl/device/pcie" - -uvhs_prepare_ip: uvhs_prepare $(UVHS_FLOW_ENV) bash "$(UVHS_COMPILATION_DIR)/prepare_ip.sh" \ "$(UVHS_ROOT_DIR)" "$(UVHS_WORK_DIR)" "$(CORE_DIR)" \ "$(UVHS_EXPORT_IP_JOBS)" "$(UVHS_EXPORT_IP_FORCE)" \ "$(UVHS_UVW_AXI4_TO_DDR4_SRC)" "$(UVHS_DDR_AXI_WIDTH)" -uvhs_filelist: uvhs_prepare_ip +uvhs_frontend: uvhs_prepare bash "$(UVHS_ROOT_DIR)/tools/update_core_flist.sh" uvhs \ "$(CORE_DIR)" "$(UVHS_WORK_DIR)" "$(CPU)" "$(UVHS_FILELIST)" \ -- $(RTL_INCLUDE) - -uvhs_frontend: uvhs_filelist bash -c 'set -euo pipefail; cd "$(UVHS_WORK_DIR)"; \ $(UVHS_FLOW_ENV) \ bash "$$UV_ROOT/bin/uv_shell" -bypass_vivado_version_check \ -s "$(UVHS_COMPILATION_DIR)/frontend_run.tcl" |& tee frontend_run.log; \ grep -Fxq UVHS_FRONTEND_SUCCESS frontend_run.log' -# Stable build entry point. Keep the stages serialized even under parallel make. +# Keep frontend and backend serialized even when the caller enables parallel make. uvhs: uvhs_frontend $(MAKE) uvhs_backend @@ -117,17 +117,15 @@ uvhs_backend: -s "$(UVHS_COMPILATION_DIR)/backend_run.tcl" |& tee backend_run.log; \ grep -Fxq UVHS_BACKEND_SUCCESS backend_run.log' -# The UVHS API requires one session to retain ownership of the downloaded -# database. Detach that session after programming and track it in runtime-work. +# The process that downloads the database must retain its runtime ownership. uvhs_write_bitstream: test -d "$(UVHS_RUNTIME_DB)" test -f "$(UVHS_RUNTIME_DIR)/runtime_server.tcl" test -x "$(UVHS_RUNTIME_DIR)/runtime_session.sh" - mkdir -p "$(UVHS_RUNTIME_WORK_DIR)" "$(UVHS_RUNTIME_TMP_DIR)" + mkdir -p "$(UVHS_RUNTIME_WORK_DIR)" $(UVHS_TOOL_ENV) UVHS_DB_PATH="$(UVHS_RUNTIME_DB)" \ UVHS_COMMAND_FILE="$(UVHS_RUNTIME_COMMAND_FILE)" \ UVHS_RUNTIME_READY_FILE="$(UVHS_RUNTIME_READY_FILE)" \ - UVHS_RUNTIME_TMP_DIR="$(UVHS_RUNTIME_TMP_DIR)" \ bash "$(UVHS_RUNTIME_DIR)/runtime_session.sh" start \ "$(UVHS_RUNTIME_PID_FILE)" "$(UVHS_RUNTIME_READY_FILE)" \ "$(UVHS_RUNTIME_LOG)" "$(UVHS_RUNTIME_COMMAND_FILE)" \ @@ -136,41 +134,51 @@ uvhs_write_bitstream: -workdir "$(UVHS_RUNTIME_WORK_DIR)" \ -script "$(UVHS_RUNTIME_DIR)/runtime_server.tcl" -uvhs_runtime_check: +uvhs_runtime_status: bash "$(UVHS_RUNTIME_DIR)/runtime_session.sh" check \ "$(UVHS_RUNTIME_PID_FILE)" "$(UVHS_RUNTIME_READY_FILE)" - -uvhs_runtime_status: uvhs_runtime_check @echo "UVHS_RUNTIME_LOG=$(UVHS_RUNTIME_LOG)" define uvhs_runtime_command + bash "$(UVHS_RUNTIME_DIR)/runtime_session.sh" check \ + "$(UVHS_RUNTIME_PID_FILE)" "$(UVHS_RUNTIME_READY_FILE)" bash "$(UVHS_RUNTIME_DIR)/runtime_session.sh" enqueue \ - "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_DIR)/runtime_command.tcl" \ - "$(UVHS_RUNTIME_TIMEOUT)" $(1) + "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_TIMEOUT)" $(1) endef -uvhs_halt_soc: uvhs_runtime_check +uvhs_halt_soc: $(call uvhs_runtime_command,halt_soc) -uvhs_reset_cpu: uvhs_runtime_check +uvhs_reset_cpu: $(call uvhs_runtime_command,reset_cpu) -uvhs_write_ddr: uvhs_runtime_check +uvhs_write_ddr: test -f "$(WORKLOAD)" - $(call uvhs_runtime_command,write_ddr "$(WORKLOAD)" "$(UVHS_DDR_RTL_INST)" "$(UVHS_DDR_AXI_WIDTH)") + $(call uvhs_runtime_command,write_ddr "$(abspath $(WORKLOAD))" "$(UVHS_DDR_RTL_INST)" "$(UVHS_DDR_AXI_WIDTH)") -uvhs_write_flash: uvhs_runtime_check +uvhs_write_flash: test -f "$(WORKLOAD)" - $(call uvhs_runtime_command,write_flash "$(WORKLOAD)" B0 F2 0 0 0x0 0x8000) - -uvhs_runtime_stop: uvhs_runtime_check + $(call uvhs_runtime_command,write_flash "$(abspath $(WORKLOAD))" B0 F2 0 0 0x0 0x8000) + +uvhs_capture: + test -f "$(TRIGGER)" + test -x "$$UV_ROOT/uvd/uvs/bin/usdb2vcd" + $(call uvhs_runtime_command,capture_ila "$(abspath $(TRIGGER))" uvhs_capture "$(UVHS_CAPTURE_TIMEOUT)" "$(UVHS_CAPTURE_DEPTH)") + test -s "$(UVHS_CAPTURE_USDB)" + $(UVHS_TOOL_ENV) "$$UV_ROOT/uvd/uvs/bin/usdb2vcd" \ + -i "$(UVHS_CAPTURE_USDB)" -o "$(UVHS_CAPTURE_VCD)" + test -s "$(UVHS_CAPTURE_VCD)" + @echo "UVHS_CAPTURE_USDB=$(UVHS_CAPTURE_USDB)" + @echo "UVHS_CAPTURE_VCD=$(UVHS_CAPTURE_VCD)" + +uvhs_runtime_stop: $(call uvhs_runtime_command,stop) bash "$(UVHS_RUNTIME_DIR)/runtime_session.sh" wait \ "$(UVHS_RUNTIME_PID_FILE)" "$(UVHS_RUNTIME_READY_FILE)" \ "$(UVHS_RUNTIME_COMMAND_FILE)" "$(UVHS_RUNTIME_TIMEOUT)" uvhs_clean: - @! bash "$(UVHS_RUNTIME_DIR)/runtime_session.sh" active \ + @! bash "$(UVHS_RUNTIME_DIR)/runtime_session.sh" check \ "$(UVHS_RUNTIME_PID_FILE)" >/dev/null 2>&1 || \ { echo "ERROR: stop the UVHS runtime before cleaning" >&2; exit 1; } test -n "$(UVHS_WORK_DIR)" From 85483d5737fa8edebbb8770e5291d39131bc5152 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 02:49:27 +0800 Subject: [PATCH 21/62] feat(fpga_diff): add default UVHS probe script Source an empty in-tree probe script by default while retaining the external probe override. Add a runtime command to clear trigger conditions and disable capture explicitly. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 33 ++++++++++++++++++++--- fpga_diff/uvhs/compilation/probe_ila.tcl | 0 fpga_diff/uvhs/runtime/runtime_server.tcl | 9 +++++++ fpga_diff/uvhs/uvhs.mk | 7 +++-- 4 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 fpga_diff/uvhs/compilation/probe_ila.tcl diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 5670195a..ee41b7d6 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -141,8 +141,11 @@ from the server's global Tcl scope. ## UVHS Waveform Capture The reference probe scripts describe compile-time instrumentation, not a -runtime dump. A probe file contains `probe_net` signals to sample and -`trigger_net` signals that may participate in a trigger condition: +runtime dump. The frontend sources `compilation/probe_ila.tcl` by default. It +is intentionally empty until stable design-specific signals are selected. Set +`UVHS_PROBE_TCL` to use another file instead. A probe file contains `probe_net` +signals to sample and `trigger_net` signals that may participate in a trigger +condition: ```tcl probe_net -clock fpga_top_debug.core_def.inter_soc_clk -add { @@ -155,8 +158,14 @@ trigger_net -add -group boot -clock \ } ``` -Signal hierarchy must match the selected generated RTL. Build a new database -and bitstream with the file supplied explicitly: +Signal hierarchy must match the selected generated RTL. After adding probes to +the default file, build a new database and bitstream normally: + +```sh +make uvhs CPU= CORE_DIR=/path/to/release/build SUFFIX=probe +``` + +An external probe file can be selected without changing the repository: ```sh make uvhs CPU= CORE_DIR=/path/to/release/build SUFFIX=probe \ @@ -191,6 +200,22 @@ runtime-work/UHD/uvhs_capture/UvData.usdb runtime-work/UHD/uvhs_capture/UvData.vcd ``` +Capture hardware is armed only by `uvhs_capture`. Clear a timed-out or +unwanted capture explicitly with: + +```sh +make uvhs_capture_clear CPU= SUFFIX= +``` + +This runs `trigger -clear`, which clears the trigger configuration and disables +both trigger and capture. Omitting probes at compile time avoids their resource +and timing cost entirely; leaving compiled probes idle avoids capture and +upload traffic but does not recover those implementation resources. In HSP, +capture runs in hardware without stopping the DUT clock. The upload, waveform +generation, and USDB-to-VCD conversion increase debug-command latency rather +than DUT cycle time. A large probe set can still lower the achievable clock +frequency indirectly by adding routing and timing pressure during compilation. + The USDB-to-VCD step is equivalent to: ```sh diff --git a/fpga_diff/uvhs/compilation/probe_ila.tcl b/fpga_diff/uvhs/compilation/probe_ila.tcl new file mode 100644 index 00000000..e69de29b diff --git a/fpga_diff/uvhs/runtime/runtime_server.tcl b/fpga_diff/uvhs/runtime/runtime_server.tcl index ec4ade86..280161d4 100644 --- a/fpga_diff/uvhs/runtime/runtime_server.tcl +++ b/fpga_diff/uvhs/runtime/runtime_server.tcl @@ -246,6 +246,11 @@ proc uvhs_capture_ila {trigger_file output_name timeout depth} { puts "INFO: UVHS waveform database generated: $usdb" } +proc uvhs_capture_clear {} { + trigger -clear + puts "INFO: UVHS trigger conditions and capture are disabled" +} + proc uvhs_execute_command {args} { if {[llength $args] == 0} { error "missing UVHS runtime command" @@ -276,6 +281,10 @@ proc uvhs_execute_command {args} { if {[llength $args] != 5} { error "capture_ila expects 4 arguments" } uvhs_capture_ila {*}[lrange $args 1 4] } + capture_clear { + if {[llength $args] != 1} { error "capture_clear expects no arguments" } + uvhs_capture_clear + } stop { if {[llength $args] != 1} { error "stop expects no arguments" } set ::uvhs_keepalive 1 diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 5ada9bc8..72ed86d3 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -4,7 +4,7 @@ UVHS_RUNTIME_DIR := $(UVHS_ROOT_DIR)/uvhs/runtime UVHS_TEMPLATE_DIR ?= UVHS_UVW_AXI4_TO_DDR4_SRC ?= -UVHS_PROBE_TCL ?= +UVHS_PROBE_TCL ?= $(UVHS_COMPILATION_DIR)/probe_ila.tcl UVHS_PROBE_PATH := $(if $(strip $(UVHS_PROBE_TCL)),$(abspath $(UVHS_PROBE_TCL)),) UVHS_DDR_AXI_WIDTH := $(if $(filter nutshell,$(CPU)),64,256) UVHS_WORK_DIR := $(ENV_SCRIPTS_HOME)/fpga_diff_uvhs_$(CPU)$(if $(strip $(SUFFIX)),-$(strip $(SUFFIX)),) @@ -50,7 +50,7 @@ UVHS_FLOW_ENV = \ .PHONY: uvhs uvhs_preflight uvhs_prepare \ uvhs_frontend uvhs_backend uvhs_clean uvhs_write_bitstream \ uvhs_halt_soc uvhs_reset_cpu uvhs_write_ddr uvhs_write_flash \ - uvhs_capture uvhs_runtime_status uvhs_runtime_stop + uvhs_capture uvhs_capture_clear uvhs_runtime_status uvhs_runtime_stop # Validate host tools and external inputs before starting a multi-hour build. uvhs_preflight: @@ -171,6 +171,9 @@ uvhs_capture: @echo "UVHS_CAPTURE_USDB=$(UVHS_CAPTURE_USDB)" @echo "UVHS_CAPTURE_VCD=$(UVHS_CAPTURE_VCD)" +uvhs_capture_clear: + $(call uvhs_runtime_command,capture_clear) + uvhs_runtime_stop: $(call uvhs_runtime_command,stop) bash "$(UVHS_RUNTIME_DIR)/runtime_session.sh" wait \ From 15fba25c243e0e27c1b3bd1633c0ab5f60944d1e Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 03:04:13 +0800 Subject: [PATCH 22/62] feat(fpga_diff): expose UVHS ILA controls Provide a fill-in probe template that preserves indexed RTL hierarchy paths. Rename waveform targets and runtime commands to the uvhs_ila interface. Expose trigger position, upload depth, and optional depth-counting clock controls. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 69 ++++++++++++++++------- fpga_diff/uvhs/compilation/probe_ila.tcl | 31 ++++++++++ fpga_diff/uvhs/runtime/runtime_server.tcl | 29 ++++++---- fpga_diff/uvhs/uvhs.mk | 35 +++++++----- 4 files changed, 119 insertions(+), 45 deletions(-) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index ee41b7d6..50e4b1e8 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -98,7 +98,8 @@ make uvhs_halt_soc CPU= SUFFIX= make uvhs_write_ddr CPU= SUFFIX= WORKLOAD=/path/to/image.txt make uvhs_write_flash CPU= SUFFIX= WORKLOAD=/path/to/image.bin make uvhs_reset_cpu CPU= SUFFIX= -make uvhs_capture CPU= SUFFIX= TRIGGER=/path/to/trigger.ini +make uvhs_ila CPU= SUFFIX= TRIGGER=/path/to/trigger.ini +make uvhs_ila_clear CPU= SUFFIX= make uvhs_runtime_stop CPU= SUFFIX= ``` @@ -138,22 +139,25 @@ The old `runtime_command.tcl` layer was merged into the server. It previously redeclared all memory helpers on every command and depended on reset procedures from the server's global Tcl scope. -## UVHS Waveform Capture +## UVHS ILA Waveform Capture The reference probe scripts describe compile-time instrumentation, not a -runtime dump. The frontend sources `compilation/probe_ila.tcl` by default. It -is intentionally empty until stable design-specific signals are selected. Set -`UVHS_PROBE_TCL` to use another file instead. A probe file contains `probe_net` -signals to sample and `trigger_net` signals that may participate in a trigger -condition: +runtime dump. The frontend sources `compilation/probe_ila.tcl` by default. Its +template is inactive while the clock and signal lists are empty. Fill the +clock path and the probe/trigger path lists to enable it; the braces preserve +hierarchy indexes such as `[0]`. Set `UVHS_PROBE_TCL` to use another file +instead. The template calls `probe_net` for sampled signals and `trigger_net` +for signals that may participate in a trigger condition. Fill it as follows: ```tcl -probe_net -clock fpga_top_debug.core_def.inter_soc_clk -add { +set uvhs_ila_clock_path [string trim { + fpga_top_debug.core_def.inter_soc_clk +}] +set uvhs_ila_probe_paths { fpga_top_debug.core_def.cpu_rstn_io fpga_top_debug.core_def.difftest_startup_ready_pcie } -trigger_net -add -group boot -clock \ - fpga_top_debug.core_def.inter_soc_clk -signal { +set uvhs_ila_trigger_paths { fpga_top_debug.core_def.cpu_rstn_io } ``` @@ -181,30 +185,41 @@ At runtime, write a trigger condition file using the group and signal names reported by `query -trigger`: ```ini -[boot] +[uvhs_ila] LOGIC = OR fpga_top_debug.core_def.cpu_rstn_io = 1 [UHD_FINAL_CONDITIONS_LOGIC] LOGIC = OR -boot +uvhs_ila ``` -After `uvhs_write_bitstream`, `uvhs_capture` checks the condition file, enables +After `uvhs_write_bitstream`, `uvhs_ila` checks the condition file, enables capture and trigger logic, resets the CPU, waits for the trigger, uploads the UHD data, and reconstructs the waveform. It creates both files below the selected build directory: ```text -runtime-work/UHD/uvhs_capture/UvData.usdb -runtime-work/UHD/uvhs_capture/UvData.vcd +runtime-work/UHD/uvhs_ila/UvData.usdb +runtime-work/UHD/uvhs_ila/UvData.vcd ``` -Capture hardware is armed only by `uvhs_capture`. Clear a timed-out or +The corresponding UVHS runtime sequence is: + +```tcl +trigger -ini_check /path/to/trigger.ini +trigger -set -condition /path/to/trigger.ini -position 70 +capture -enable +trigger -enable +trigger -status -wait 1 -timeout 60 +upload_uhd -depth 1000000 -position 70 -out uvhs_ila +``` + +Capture hardware is armed only by `uvhs_ila`. Clear a timed-out or unwanted capture explicitly with: ```sh -make uvhs_capture_clear CPU= SUFFIX= +make uvhs_ila_clear CPU= SUFFIX= ``` This runs `trigger -clear`, which clears the trigger configuration and disables @@ -215,6 +230,9 @@ capture runs in hardware without stopping the DUT clock. The upload, waveform generation, and USDB-to-VCD conversion increase debug-command latency rather than DUT cycle time. A large probe set can still lower the achievable clock frequency indirectly by adding routing and timing pressure during compilation. +The runtime command service is serial, so `uvhs_ila_clear` is handled after an +in-flight `uvhs_ila` reaches its trigger or timeout; it is not an asynchronous +interrupt for the current wait. The USDB-to-VCD step is equivalent to: @@ -224,9 +242,20 @@ $UV_ROOT/uvd/uvs/bin/usdb2vcd \ -i "$USDB" -o "${USDB%.usdb}.vcd" ``` -`UVHS_CAPTURE_TIMEOUT` defaults to 60 seconds and `UVHS_CAPTURE_DEPTH` to one -million samples. This is the UVHS UHD path; the normal Vivado flow continues to -use `make dump_ila` and a `.ltx` file. +The upload window is controlled when starting the capture: + +```sh +make uvhs_ila CPU= SUFFIX= TRIGGER=/path/to/trigger.ini \ + UVHS_ILA_DEPTH=1000000 UVHS_ILA_POSITION=70 +``` + +`UVHS_ILA_DEPTH` is the total uploaded sample count. `UVHS_ILA_POSITION` is the +percentage after the trigger, from 0 through 100; the example uploads roughly +300,000 samples before the trigger and 700,000 after it. `UVHS_ILA_CLOCK` can +select the depth-counting clock by a runtime-database global clock name or a +frequency; when empty, the tool uses its 200 MHz TS clock. `UVHS_ILA_TIMEOUT` +defaults to 60 seconds. This is the UVHS UHD path; the normal Vivado flow +continues to use `make dump_ila` and a `.ltx` file. ## Compatibility Boundary diff --git a/fpga_diff/uvhs/compilation/probe_ila.tcl b/fpga_diff/uvhs/compilation/probe_ila.tcl index e69de29b..f76c6990 100644 --- a/fpga_diff/uvhs/compilation/probe_ila.tcl +++ b/fpga_diff/uvhs/compilation/probe_ila.tcl @@ -0,0 +1,31 @@ +# Fill only the RTL paths below. Braces preserve hierarchy indexes such as [0]. +# Leave the clock and signal lists empty to build without UHD instrumentation. +set uvhs_ila_group_name uvhs_ila +# Sampling clock path for this probe/trigger group. +set uvhs_ila_clock_path [string trim { +}] +# Probe signal paths, one per line. +set uvhs_ila_probe_paths { +} +# Trigger signal paths, one per line. +set uvhs_ila_trigger_paths { +} + +if {$uvhs_ila_clock_path eq ""} { + if {[llength $uvhs_ila_probe_paths] || + [llength $uvhs_ila_trigger_paths]} { + error "UVHS ILA signals require a sampling clock path" + } +} else { + if {[llength $uvhs_ila_probe_paths]} { + probe_net -clock $uvhs_ila_clock_path -add $uvhs_ila_probe_paths + } + if {[llength $uvhs_ila_trigger_paths]} { + trigger_net -add -group $uvhs_ila_group_name \ + -clock $uvhs_ila_clock_path \ + -signal $uvhs_ila_trigger_paths + } +} + +unset uvhs_ila_group_name uvhs_ila_clock_path +unset uvhs_ila_probe_paths uvhs_ila_trigger_paths diff --git a/fpga_diff/uvhs/runtime/runtime_server.tcl b/fpga_diff/uvhs/runtime/runtime_server.tcl index 280161d4..947e1f6e 100644 --- a/fpga_diff/uvhs/runtime/runtime_server.tcl +++ b/fpga_diff/uvhs/runtime/runtime_server.tcl @@ -210,7 +210,7 @@ proc uvhs_write_ddr_pairs {input_file rtl_path data_width} { puts "INFO: DDR backdoor write completed: $input_file" } -proc uvhs_capture_ila {trigger_file output_name timeout depth} { +proc uvhs_ila {trigger_file output_name timeout depth position clock} { if {![file isfile $trigger_file]} { error "trigger condition file not found: $trigger_file" } @@ -219,16 +219,20 @@ proc uvhs_capture_ila {trigger_file output_name timeout depth} { } set timeout [uvhs_parse_integer "capture timeout" $timeout] set depth [uvhs_parse_integer "capture depth" $depth] + set position [uvhs_parse_integer "capture position" $position] if {$timeout <= 0 || $depth <= 0} { error "capture timeout and depth must be positive" } + if {$position < 0 || $position > 100} { + error "capture position must be between 0 and 100: $position" + } set output_dir [file join [pwd] UHD $output_name] file delete -force $output_dir query -trigger trigger -ini_check $trigger_file + trigger -set -condition $trigger_file -position $position capture -enable - trigger -set -condition $trigger_file -position 5 trigger -enable # The default capture observes boot from CPU reset release. External traffic @@ -236,7 +240,12 @@ proc uvhs_capture_ila {trigger_file output_name timeout depth} { uvhs_reset_cpu set trigger_status [trigger -status -wait 1 -timeout $timeout -tclobj] puts "INFO: UVHS trigger status: $trigger_status" - upload_uhd -depth $depth -out $output_name + set upload_options [list -depth $depth -position $position] + if {$clock ne ""} { + lappend upload_options -clock $clock + } + lappend upload_options -out $output_name + upload_uhd {*}$upload_options wavegen -bindir [file join UHD $output_name] set usdb [file join $output_dir UvData.usdb] @@ -246,7 +255,7 @@ proc uvhs_capture_ila {trigger_file output_name timeout depth} { puts "INFO: UVHS waveform database generated: $usdb" } -proc uvhs_capture_clear {} { +proc uvhs_ila_clear {} { trigger -clear puts "INFO: UVHS trigger conditions and capture are disabled" } @@ -277,13 +286,13 @@ proc uvhs_execute_command {args} { uvhs_write_flash_gbus {*}[lrange $args 1 7] uvhs_release_cpu_after_memory } - capture_ila { - if {[llength $args] != 5} { error "capture_ila expects 4 arguments" } - uvhs_capture_ila {*}[lrange $args 1 4] + ila { + if {[llength $args] != 7} { error "ila expects 6 arguments" } + uvhs_ila {*}[lrange $args 1 6] } - capture_clear { - if {[llength $args] != 1} { error "capture_clear expects no arguments" } - uvhs_capture_clear + ila_clear { + if {[llength $args] != 1} { error "ila_clear expects no arguments" } + uvhs_ila_clear } stop { if {[llength $args] != 1} { error "stop expects no arguments" } diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 72ed86d3..5de50871 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -26,11 +26,13 @@ UVHS_RUNTIME_READY_FILE := $(UVHS_RUNTIME_WORK_DIR)/uv_shell.ready UVHS_RUNTIME_LOG := $(UVHS_RUNTIME_WORK_DIR)/uv_shell.log UVHS_RUNTIME_TIMEOUT ?= 600 -UVHS_CAPTURE_TIMEOUT ?= 60 -UVHS_CAPTURE_DEPTH ?= 1000000 -UVHS_CAPTURE_DIR := $(UVHS_RUNTIME_WORK_DIR)/UHD/uvhs_capture -UVHS_CAPTURE_USDB := $(UVHS_CAPTURE_DIR)/UvData.usdb -UVHS_CAPTURE_VCD := $(UVHS_CAPTURE_DIR)/UvData.vcd +UVHS_ILA_TIMEOUT ?= 60 +UVHS_ILA_DEPTH ?= 1000000 +UVHS_ILA_POSITION ?= 50 +UVHS_ILA_CLOCK ?= +UVHS_ILA_DIR := $(UVHS_RUNTIME_WORK_DIR)/UHD/uvhs_ila +UVHS_ILA_USDB := $(UVHS_ILA_DIR)/UvData.usdb +UVHS_ILA_VCD := $(UVHS_ILA_DIR)/UvData.vcd UVHS_TOOL_ENV = \ PATH="$$UV_ROOT/bin:$$UV_ROOT/lib/venv3.8/bin:$$UV_ROOT/lib/gcc10.3/bin:$$PATH" \ @@ -50,7 +52,7 @@ UVHS_FLOW_ENV = \ .PHONY: uvhs uvhs_preflight uvhs_prepare \ uvhs_frontend uvhs_backend uvhs_clean uvhs_write_bitstream \ uvhs_halt_soc uvhs_reset_cpu uvhs_write_ddr uvhs_write_flash \ - uvhs_capture uvhs_capture_clear uvhs_runtime_status uvhs_runtime_stop + uvhs_ila uvhs_ila_clear uvhs_runtime_status uvhs_runtime_stop # Validate host tools and external inputs before starting a multi-hour build. uvhs_preflight: @@ -160,19 +162,22 @@ uvhs_write_flash: test -f "$(WORKLOAD)" $(call uvhs_runtime_command,write_flash "$(abspath $(WORKLOAD))" B0 F2 0 0 0x0 0x8000) -uvhs_capture: +uvhs_ila: test -f "$(TRIGGER)" test -x "$$UV_ROOT/uvd/uvs/bin/usdb2vcd" - $(call uvhs_runtime_command,capture_ila "$(abspath $(TRIGGER))" uvhs_capture "$(UVHS_CAPTURE_TIMEOUT)" "$(UVHS_CAPTURE_DEPTH)") - test -s "$(UVHS_CAPTURE_USDB)" + $(call uvhs_runtime_command,ila \ + "$(abspath $(TRIGGER))" uvhs_ila \ + "$(UVHS_ILA_TIMEOUT)" "$(UVHS_ILA_DEPTH)" \ + "$(UVHS_ILA_POSITION)" "$(UVHS_ILA_CLOCK)") + test -s "$(UVHS_ILA_USDB)" $(UVHS_TOOL_ENV) "$$UV_ROOT/uvd/uvs/bin/usdb2vcd" \ - -i "$(UVHS_CAPTURE_USDB)" -o "$(UVHS_CAPTURE_VCD)" - test -s "$(UVHS_CAPTURE_VCD)" - @echo "UVHS_CAPTURE_USDB=$(UVHS_CAPTURE_USDB)" - @echo "UVHS_CAPTURE_VCD=$(UVHS_CAPTURE_VCD)" + -i "$(UVHS_ILA_USDB)" -o "$(UVHS_ILA_VCD)" + test -s "$(UVHS_ILA_VCD)" + @echo "UVHS_ILA_USDB=$(UVHS_ILA_USDB)" + @echo "UVHS_ILA_VCD=$(UVHS_ILA_VCD)" -uvhs_capture_clear: - $(call uvhs_runtime_command,capture_clear) +uvhs_ila_clear: + $(call uvhs_runtime_command,ila_clear) uvhs_runtime_stop: $(call uvhs_runtime_command,stop) From 1f80d1bcc088820b86dae1dbd27dbae4ef642804 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 03:53:07 +0800 Subject: [PATCH 23/62] fix(fpga_diff): run GeneralBus export with Bash --- fpga_diff/uvhs/compilation/prepare_ip.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fpga_diff/uvhs/compilation/prepare_ip.sh b/fpga_diff/uvhs/compilation/prepare_ip.sh index 55bd9dd3..2063de58 100755 --- a/fpga_diff/uvhs/compilation/prepare_ip.sh +++ b/fpga_diff/uvhs/compilation/prepare_ip.sh @@ -56,7 +56,9 @@ if [[ $force == 1 || ! -s $gbus_release/uvw_general_bus.dcp || generator=$gbus_gen/ip-src/gen_generalbus_ip.py sed -i '/os[.]popen.*f_dcp_in.*f_dcp_out/c\ shutil.copy2(f_dcp_in, f_dcp_out)' \ "$generator" + sed -i 's|#!/bin/tcsh|#!/usr/bin/env bash|' "$generator" grep -Fq 'shutil.copy2(f_dcp_in, f_dcp_out)' "$generator" + grep -Fq '#!/usr/bin/env bash' "$generator" json=$gbus_gen/uvw_axi3_generalbus.json cp -f "$gbus_source/uvw_axi3_generalbus.json" "$json" sed -i -E \ From 76ef00a9ebe94c1f7da2f00dd9abcd365f7d3a40 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 04:10:39 +0800 Subject: [PATCH 24/62] fix(fpga_diff): reuse staged PCRE1 library --- fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh b/fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh index da91de9a..d17ba026 100755 --- a/fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh +++ b/fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh @@ -23,18 +23,22 @@ ln -sfn "$ffi" "$UVHS_RUNTIME_LIB_DIR/libffi.so.6" if ldd "$UV_ROOT/bin/uv_shell_exec" 2>/dev/null | grep -q 'libpcre[.]so[.]1 => not found'; then pcre= for candidate in \ + "$UVHS_RUNTIME_LIB_DIR/libpcre.so.1" \ "$UV_ROOT/shlib_install/libpcre.so.1" \ - "$UV_ROOT/shlib/libpcre.so.1"; do - if [[ -f $candidate ]]; then + "$UV_ROOT/shlib/libpcre.so.1" \ + "$(find_library libpcre.so.3)"; do + if [[ -n $candidate && -f $candidate ]]; then pcre=$candidate break fi done [[ -n $pcre ]] || { - echo "ERROR: uv_shell_exec needs libpcre.so.1 under UV_ROOT" >&2 + echo "ERROR: uv_shell_exec needs PCRE1 (libpcre.so.1 or libpcre.so.3)" >&2 exit 1 } - ln -sfn "$pcre" "$UVHS_RUNTIME_LIB_DIR/libpcre.so.1" + if [[ $pcre != "$UVHS_RUNTIME_LIB_DIR/libpcre.so.1" ]]; then + ln -sfn "$pcre" "$UVHS_RUNTIME_LIB_DIR/libpcre.so.1" + fi fi runtime_library_path=$UVHS_RUNTIME_LIB_DIR From 376a34b297b69f65dbb8086b09706620bb6100a1 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 04:13:35 +0800 Subject: [PATCH 25/62] fix(fpga_diff): qualify UVHS pin helpers --- fpga_diff/uvhs/compilation/assign_pin.tcl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fpga_diff/uvhs/compilation/assign_pin.tcl b/fpga_diff/uvhs/compilation/assign_pin.tcl index 0453358b..8914efd4 100644 --- a/fpga_diff/uvhs/compilation/assign_pin.tcl +++ b/fpga_diff/uvhs/compilation/assign_pin.tcl @@ -12,8 +12,8 @@ proc pin_name {top port} { return "${top}.${port}" } -set top [env_or_default UVHS_ASSIGN_PIN_TOP fpga_top_debug] -set xdma_link_width [string toupper [string trim [env_or_default XDMA_LINK_WIDTH X4]]] +set top [uvhs::env_or_default UVHS_ASSIGN_PIN_TOP fpga_top_debug] +set xdma_link_width [string toupper [string trim [uvhs::env_or_default XDMA_LINK_WIDTH X4]]] if {$xdma_link_width ni {X4 X8}} { error "XDMA_LINK_WIDTH must be one of X4/X8, got '$xdma_link_width'" } @@ -40,9 +40,9 @@ apc16_pin led3 5 # UART0 defaults to the F2 APC16 sideband connector. A two-FPGA build can # route it through the F1 UV_FMCH_FLASH USB-UART with FMC indices 311/270. -set uvhs_uart0_connector [env_or_default UVHS_UART0_CONNECTOR b0.F2_APC16] -set uvhs_uart0_tx_index [env_or_default UVHS_UART0_TX_INDEX [lindex $apc16_indices 6]] -set uvhs_uart0_rx_index [env_or_default UVHS_UART0_RX_INDEX [lindex $apc16_indices 7]] +set uvhs_uart0_connector [uvhs::env_or_default UVHS_UART0_CONNECTOR b0.F2_APC16] +set uvhs_uart0_tx_index [uvhs::env_or_default UVHS_UART0_TX_INDEX [lindex $apc16_indices 6]] +set uvhs_uart0_rx_index [uvhs::env_or_default UVHS_UART0_RX_INDEX [lindex $apc16_indices 7]] puts "INFO: UART0 pins: TX ${uvhs_uart0_connector}\[$uvhs_uart0_tx_index\], RX ${uvhs_uart0_connector}\[$uvhs_uart0_rx_index\]" assign_pin -port [pin_name $top uart0_sout] -connector $uvhs_uart0_connector -index $uvhs_uart0_tx_index assign_pin -port [pin_name $top uart0_sin] -connector $uvhs_uart0_connector -index $uvhs_uart0_rx_index From 066855cb45b8edcd38143f854cbcc13ed2356777 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 04:22:38 +0800 Subject: [PATCH 26/62] fix(fpga_diff): restore UVHS worker libraries --- fpga_diff/uvhs/README.md | 2 +- fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh | 10 +++++++++- fpga_diff/uvhs/uvhs.mk | 7 +++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 50e4b1e8..4a8e420d 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -292,6 +292,6 @@ or DDR pins. | `compilation/prepare_ip.sh` | Coordinates Vivado, generalBus, and external DDR IP preparation. | | `compilation/export_vivado_ip.tcl` | Runs repository-owned XCI/BD exports inside Vivado. | | `compilation/shell_compat.sh` | Generated launcher shell correction. | -| `runtime/uv_shell_exec_compat.sh` | Runtime library wrapper used by build and runtime shells. | +| `runtime/uv_shell_exec_compat.sh` | Runtime library wrapper for UVHS shells and generated Python workers. | | `runtime/runtime_server.tcl` | Download, reset, DDR, flash, capture, and command service. | | `runtime/runtime_session.sh` | Process lifecycle and atomic command/result transport. | diff --git a/fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh b/fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh index d17ba026..ff0b23aa 100755 --- a/fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh +++ b/fpga_diff/uvhs/runtime/uv_shell_exec_compat.sh @@ -50,4 +50,12 @@ if [[ -n ${LD_LIBRARY_PATH:-} ]]; then fi export LD_LIBRARY_PATH=$runtime_library_path -exec "$UV_ROOT/bin/uv_shell_exec" "$@" +if [[ -n ${UVHS_COMPAT_BIN:-} ]]; then + export PATH=$UVHS_COMPAT_BIN:$PATH +fi + +executable="$UV_ROOT/bin/uv_shell_exec" +case ${0##*/} in + python|python3) executable="$UV_ROOT/lib/venv3.8/bin/${0##*/}" ;; +esac +exec "$executable" "$@" diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 5de50871..a91e658a 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -18,6 +18,7 @@ UVHS_LUT6_FILL_RATE ?= $(if $(filter kmh,$(CPU)),35,) UVHS_DDR_RTL_INST := fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4 UVHS_RUNTIME_LIB_DIR := $(UVHS_WORK_DIR)/.uvhs-runtime-lib +UVHS_COMPAT_BIN := $(UVHS_WORK_DIR)/.uvhs-compat-bin UVHS_RUNTIME_DB := $(UVHS_WORK_DIR)/hw.dat UVHS_RUNTIME_WORK_DIR := $(UVHS_WORK_DIR)/runtime-work UVHS_RUNTIME_COMMAND_FILE := $(UVHS_RUNTIME_WORK_DIR)/command.tcl @@ -38,6 +39,7 @@ UVHS_TOOL_ENV = \ PATH="$$UV_ROOT/bin:$$UV_ROOT/lib/venv3.8/bin:$$UV_ROOT/lib/gcc10.3/bin:$$PATH" \ MAKEFLAGS="$${MAKEFLAGS:+$$MAKEFLAGS }SHELL=/bin/bash" \ UVHS_RUNTIME_LIB_DIR="$(UVHS_RUNTIME_LIB_DIR)" \ + UVHS_COMPAT_BIN="$(UVHS_COMPAT_BIN)" \ UVSHELL_EXEC_NAME="$(UVHS_RUNTIME_DIR)/uv_shell_exec_compat.sh" UVHS_FLOW_ENV = \ @@ -90,6 +92,11 @@ uvhs_prepare: uvhs_preflight test -n "$(UVHS_WORK_DIR)" rm -rf "$(UVHS_WORK_DIR)/script" mkdir -p "$(UVHS_WORK_DIR)" + mkdir -p "$(UVHS_COMPAT_BIN)" + ln -sfn "$(UVHS_RUNTIME_DIR)/uv_shell_exec_compat.sh" \ + "$(UVHS_COMPAT_BIN)/python" + ln -sfn "$(UVHS_RUNTIME_DIR)/uv_shell_exec_compat.sh" \ + "$(UVHS_COMPAT_BIN)/python3" cp -a "$(UVHS_TEMPLATE_DIR)/script" "$(UVHS_WORK_DIR)/" cp -f "$(UVHS_TEMPLATE_DIR)/Makefile" "$(UVHS_WORK_DIR)/Makefile" mkdir -p "$(UVHS_WORK_DIR)/rtl/soc" "$(UVHS_WORK_DIR)/rtl/device/pcie" From aac92e369a8952f66a500a26cd1fe00071db36de Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 04:29:11 +0800 Subject: [PATCH 27/62] fix(fpga_diff): inline UVHS async constraints --- fpga_diff/uvhs/README.md | 3 +-- fpga_diff/uvhs/compilation/async_clocks.tcl | 12 ------------ fpga_diff/uvhs/compilation/backend_run.tcl | 2 +- fpga_diff/uvhs/compilation/timing.tcl | 9 ++++++++- fpga_diff/uvhs/compilation/vivado_pre_opt.tcl | 7 ++++++- 5 files changed, 16 insertions(+), 17 deletions(-) delete mode 100644 fpga_diff/uvhs/compilation/async_clocks.tcl diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 4a8e420d..5f418bef 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -286,8 +286,7 @@ or DDR pins. | `compilation/backend_run.tcl` | Fill-rate setup, partition, routing, PnR, and database commit. | | `compilation/topology.tcl` | Selects the FPGA set from the vendor board assembly. | | `compilation/assign_pin.tcl` | B0/F2 clock, PCIe, UART, JTAG, SD, and control pins. | -| `compilation/timing.tcl` | External clock constraints registered by the frontend. | -| `compilation/async_clocks.tcl` | Shared asynchronous groups for frontend, backend, and PnR. | +| `compilation/timing.tcl` | External clock and asynchronous-group constraints. | | `compilation/vivado_pre_opt.tcl` | XDMA refclock and CDC constraints. | | `compilation/prepare_ip.sh` | Coordinates Vivado, generalBus, and external DDR IP preparation. | | `compilation/export_vivado_ip.tcl` | Runs repository-owned XCI/BD exports inside Vivado. | diff --git a/fpga_diff/uvhs/compilation/async_clocks.tcl b/fpga_diff/uvhs/compilation/async_clocks.tcl deleted file mode 100644 index f8988499..00000000 --- a/fpga_diff/uvhs/compilation/async_clocks.tcl +++ /dev/null @@ -1,12 +0,0 @@ -################################################################################ -# UVHS asynchronous clock constraints. -# -# timing.tcl establishes the frontend relation. The backend and Vivado pre-opt -# stages load this again after transformed or linked clocks are available. -################################################################################ - -set fpga_diff_async_groups [list] -foreach fpga_diff_clock {TMCLK ddr_ref_clk CPU_CLK_IN jtag_vclk pcie_ep_refclk} { - lappend fpga_diff_async_groups -group [get_clocks -include_generated_clocks $fpga_diff_clock] -} -eval [linsert $fpga_diff_async_groups 0 set_clock_groups -asynchronous] diff --git a/fpga_diff/uvhs/compilation/backend_run.tcl b/fpga_diff/uvhs/compilation/backend_run.tcl index 5c9ef5e3..f5e4c7c2 100644 --- a/fpga_diff/uvhs/compilation/backend_run.tcl +++ b/fpga_diff/uvhs/compilation/backend_run.tcl @@ -36,7 +36,7 @@ sweep_design infer_clock report_clock -inferred transform_clock -uvhs::source_required async_clocks.tcl +fpga_diff_set_async_clock_groups set fill_rate_args {} foreach {option variable} { -lut UVHS_LUT_FILL_RATE diff --git a/fpga_diff/uvhs/compilation/timing.tcl b/fpga_diff/uvhs/compilation/timing.tcl index 572c1520..6085d266 100644 --- a/fpga_diff/uvhs/compilation/timing.tcl +++ b/fpga_diff/uvhs/compilation/timing.tcl @@ -15,4 +15,11 @@ create_clock -name CPU_CLK_IN -period 40 [get_ports [fpga_diff_top_port clk5_p]] create_clock -name jtag_vclk -period 83.333 [get_ports [fpga_diff_top_port JTAG_TCK]] create_clock -name pcie_ep_refclk -period 10 [get_ports [fpga_diff_top_port pcie_ep_gt_ref_clk_p]] -source [file join [file dirname [file normalize [info script]]] async_clocks.tcl] +proc fpga_diff_set_async_clock_groups {} { + set groups [list] + foreach clock {TMCLK ddr_ref_clk CPU_CLK_IN jtag_vclk pcie_ep_refclk} { + lappend groups -group [get_clocks -include_generated_clocks $clock] + } + set_clock_groups -asynchronous {*}$groups +} +fpga_diff_set_async_clock_groups diff --git a/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl b/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl index 8e0ccb01..463fb204 100644 --- a/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl +++ b/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl @@ -81,4 +81,9 @@ foreach {label patterns} { } puts "INFO: XDMA CDC total ASYNC_REG count=[llength $fpga_diff_xdma_cdc_cells]" -source [file join [file dirname [file normalize [info script]]] async_clocks.tcl] +set fpga_diff_async_groups [list] +foreach fpga_diff_clock {TMCLK ddr_ref_clk CPU_CLK_IN jtag_vclk pcie_ep_refclk} { + lappend fpga_diff_async_groups -group \ + [get_clocks -include_generated_clocks $fpga_diff_clock] +} +set_clock_groups -asynchronous {*}$fpga_diff_async_groups From 650027e4f8776bb58f1c46e9296e90b5b628f259 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 04:33:30 +0800 Subject: [PATCH 28/62] fix(fpga_diff): constrain UVHS XDMA AXI clock --- fpga_diff/uvhs/compilation/backend_run.tcl | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fpga_diff/uvhs/compilation/backend_run.tcl b/fpga_diff/uvhs/compilation/backend_run.tcl index f5e4c7c2..98e6816a 100644 --- a/fpga_diff/uvhs/compilation/backend_run.tcl +++ b/fpga_diff/uvhs/compilation/backend_run.tcl @@ -33,6 +33,18 @@ init_runtime_data trigger_probe -check sweep_design +set xdma_axi_clock_pin \ + [get_pins -quiet core_def/xdma_ep_i/TO_DIFFTEST_PCIE_CLK] +if {[llength $xdma_axi_clock_pin] != 1} { + error "required XDMA AXI clock pin not found" +} +set xdma_axi_clock_period [expr { + [string equal -nocase [uvhs::env_or_default XDMA_LINK_WIDTH X4] X8] + ? 4.0 : 8.0 +}] +create_clock -name XDMA_AXI_ACLK -period $xdma_axi_clock_period \ + $xdma_axi_clock_pin + infer_clock report_clock -inferred transform_clock From bb2fd5ef0dd9696634469b7a0e3a18dc3b3df1b9 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 04:46:29 +0800 Subject: [PATCH 29/62] docs(fpga_diff): document UVHS ILA limits Describe the one-shot runtime controls and the trigger-relative upload window. Record the PDDR4DME conflict observed when UHD capture and DUT DDR share the single-F2 topology. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 48 ++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 5f418bef..ce3a6994 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -194,10 +194,10 @@ LOGIC = OR uvhs_ila ``` -After `uvhs_write_bitstream`, `uvhs_ila` checks the condition file, enables -capture and trigger logic, resets the CPU, waits for the trigger, uploads the -UHD data, and reconstructs the waveform. It creates both files below the -selected build directory: +After `uvhs_write_bitstream`, `uvhs_ila` is the one-shot capture start command. +It checks the condition file, enables capture and trigger logic, resets the +CPU, waits for the trigger, uploads the UHD data, and reconstructs the +waveform. It creates both files below the selected build directory: ```text runtime-work/UHD/uvhs_ila/UvData.usdb @@ -215,21 +215,22 @@ trigger -status -wait 1 -timeout 60 upload_uhd -depth 1000000 -position 70 -out uvhs_ila ``` -Capture hardware is armed only by `uvhs_ila`. Clear a timed-out or -unwanted capture explicitly with: +Capture hardware is armed only by `uvhs_ila`. Clear the trigger configuration +after a timed-out or unwanted capture with: ```sh make uvhs_ila_clear CPU= SUFFIX= ``` -This runs `trigger -clear`, which clears the trigger configuration and disables -both trigger and capture. Omitting probes at compile time avoids their resource -and timing cost entirely; leaving compiled probes idle avoids capture and -upload traffic but does not recover those implementation resources. In HSP, -capture runs in hardware without stopping the DUT clock. The upload, waveform -generation, and USDB-to-VCD conversion increase debug-command latency rather -than DUT cycle time. A large probe set can still lower the achievable clock -frequency indirectly by adding routing and timing pressure during compilation. +This runs the prototyping command `trigger -clear`; it removes the configured +conditions so the trigger is no longer armed. Omitting probes at compile time +avoids their resource and timing cost entirely; leaving compiled probes idle +avoids capture and upload traffic but does not recover those implementation +resources. In HSP, capture runs in hardware without stopping the DUT clock. +The upload, waveform generation, and USDB-to-VCD conversion increase +debug-command latency rather than DUT cycle time. A large probe set can still +lower the achievable clock frequency indirectly by adding routing and timing +pressure during compilation. The runtime command service is serial, so `uvhs_ila_clear` is handled after an in-flight `uvhs_ila` reaches its trigger or timeout; it is not an asynchronous interrupt for the current wait. @@ -251,11 +252,20 @@ make uvhs_ila CPU= SUFFIX= TRIGGER=/path/to/trigger.ini \ `UVHS_ILA_DEPTH` is the total uploaded sample count. `UVHS_ILA_POSITION` is the percentage after the trigger, from 0 through 100; the example uploads roughly -300,000 samples before the trigger and 700,000 after it. `UVHS_ILA_CLOCK` can -select the depth-counting clock by a runtime-database global clock name or a -frequency; when empty, the tool uses its 200 MHz TS clock. `UVHS_ILA_TIMEOUT` -defaults to 60 seconds. This is the UVHS UHD path; the normal Vivado flow -continues to use `make dump_ila` and a `.ltx` file. +300,000 samples before the trigger and 700,000 after it. Position 0 keeps the +window before the trigger, 50 centers it, and 100 keeps the window after the +trigger. `UVHS_ILA_CLOCK` can select the depth-counting clock by a +runtime-database global clock name or a frequency; when empty, the tool uses +its 200 MHz TS clock. `UVHS_ILA_TIMEOUT` defaults to 60 seconds. This is the +UVHS UHD path; the normal Vivado flow continues to use `make dump_ila` and a +`.ltx` file. + +UHD capture inserts its own external DDR wrapper on every FPGA containing a +probe group. On the current single-F2 NutShell topology, that capture memory +and the DUT DDR IP both require the F2 PDDR4DME/FMC3 resource, so a probe-enabled +build fails `bind_system` with `BND-026`. Keep the template empty for the normal +single-F2 bitstream. A probe-enabled build requires a topology that provides a +separate compatible UHD capture-memory resource. ## Compatibility Boundary From 15a0b2629f16d827713fd728f13bfff06248091f Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 10:40:56 +0800 Subject: [PATCH 30/62] fix(fpga_diff): balance UVHS partition blocks --- fpga_diff/uvhs/compilation/backend_run.tcl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fpga_diff/uvhs/compilation/backend_run.tcl b/fpga_diff/uvhs/compilation/backend_run.tcl index 98e6816a..ea05a1d7 100644 --- a/fpga_diff/uvhs/compilation/backend_run.tcl +++ b/fpga_diff/uvhs/compilation/backend_run.tcl @@ -75,7 +75,8 @@ check_design report_resource -depth 4 report_system_resource list_partition_constraints -all -partition_design -tdc -tdss true +partition_design -tdc -tdss true \ + -bs_max_blk_ratio 0.96 -bs_min_blk_ratio 0.005 report_resource -depth 4 instrument_design From b9c9eccc71d567c7e46da435246600c2dbb86232 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 11:09:06 +0800 Subject: [PATCH 31/62] fix(fpga_diff): reserve UVHS debug DDR cards --- fpga_diff/uvhs/README.md | 10 +++++----- fpga_diff/uvhs/compilation/backend_run.tcl | 7 +++++++ fpga_diff/uvhs/compilation/frontend_run.tcl | 1 + fpga_diff/uvhs/compilation/partition.tcl | 10 ++++++++++ fpga_diff/uvhs/uvhs.mk | 3 ++- 5 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 fpga_diff/uvhs/compilation/partition.tcl diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index ce3a6994..16d74ce0 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -261,11 +261,10 @@ UVHS UHD path; the normal Vivado flow continues to use `make dump_ila` and a `.ltx` file. UHD capture inserts its own external DDR wrapper on every FPGA containing a -probe group. On the current single-F2 NutShell topology, that capture memory -and the DUT DDR IP both require the F2 PDDR4DME/FMC3 resource, so a probe-enabled -build fails `bind_system` with `BND-026`. Keep the template empty for the normal -single-F2 bitstream. A probe-enabled build requires a topology that provides a -separate compatible UHD capture-memory resource. +probe group. The four PDDR4DME cards on the FPGA FMC3 connectors are reserved +for UHD. The DUT DDR controller is constrained to B0/F0, which owns the separate +`pddr4dme_user_inst`; NutShell therefore keeps both B0/F0 and B0/F2. This avoids +sharing the B0/F2 UHD card between the DUT and waveform capture. ## Compatibility Boundary @@ -295,6 +294,7 @@ or DDR pins. | `compilation/frontend_run.tcl` | RTL/IP import, elaboration, and uvsyn frontend. | | `compilation/backend_run.tcl` | Fill-rate setup, partition, routing, PnR, and database commit. | | `compilation/topology.tcl` | Selects the FPGA set from the vendor board assembly. | +| `compilation/partition.tcl` | Places the DUT DDR controller on the user-DDR FPGA. | | `compilation/assign_pin.tcl` | B0/F2 clock, PCIe, UART, JTAG, SD, and control pins. | | `compilation/timing.tcl` | External clock and asynchronous-group constraints. | | `compilation/vivado_pre_opt.tcl` | XDMA refclock and CDC constraints. | diff --git a/fpga_diff/uvhs/compilation/backend_run.tcl b/fpga_diff/uvhs/compilation/backend_run.tcl index ea05a1d7..f4e0c715 100644 --- a/fpga_diff/uvhs/compilation/backend_run.tcl +++ b/fpga_diff/uvhs/compilation/backend_run.tcl @@ -45,6 +45,13 @@ set xdma_axi_clock_period [expr { create_clock -name XDMA_AXI_ACLK -period $xdma_axi_clock_period \ $xdma_axi_clock_pin +set ddr_ui_clock_pin [get_pins -quiet \ + core_def/U_UVHS_UVW_AXI4_TO_DDR4/ddr4ip_ddr4_user_clk] +if {[llength $ddr_ui_clock_pin] != 1} { + error "required DDR user-interface clock pin not found" +} +create_clock -name DDR_UI_CLK -period 5.0 $ddr_ui_clock_pin + infer_clock report_clock -inferred transform_clock diff --git a/fpga_diff/uvhs/compilation/frontend_run.tcl b/fpga_diff/uvhs/compilation/frontend_run.tcl index f5a33e37..0ea39539 100644 --- a/fpga_diff/uvhs/compilation/frontend_run.tcl +++ b/fpga_diff/uvhs/compilation/frontend_run.tcl @@ -95,6 +95,7 @@ create_system_design -name VU19P_X4 -platform U2.2 uvhs::source_required topology.tcl uvhs::source_required assign_pin.tcl +set_partition_constraint_file [uvhs::path partition.tcl] set probe_script [uvhs::env_or_default UVHS_PROBE_TCL ""] if {$probe_script ne ""} { set probe_script [file normalize $probe_script] diff --git a/fpga_diff/uvhs/compilation/partition.tcl b/fpga_diff/uvhs/compilation/partition.tcl new file mode 100644 index 00000000..9a6896b4 --- /dev/null +++ b/fpga_diff/uvhs/compilation/partition.tcl @@ -0,0 +1,10 @@ +################################################################################ +# Keep the DUT DDR controller on the FPGA connected to the user DDR card. +################################################################################ + +set uvhs_ddr_cell \ + [get_cells {fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4}] +if {[llength $uvhs_ddr_cell] != 1} { + error "expected one UVHS DUT DDR instance, got [llength $uvhs_ddr_cell]" +} +create_fpga -name b0.f0 -cells $uvhs_ddr_cell diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index a91e658a..6ab50890 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -12,7 +12,7 @@ UVHS_FILELIST := $(UVHS_WORK_DIR)/rtl/filelist.f UVHS_EXPORT_IP_FORCE ?= 0 UVHS_EXPORT_IP_JOBS := $(if $(strip $(VIVADO_JOBS)),$(VIVADO_JOBS),8) -UVHS_KEEP_FPGAS ?= $(if $(filter kmh,$(CPU)),b0.f0 b0.f1 b0.f2 b0.f3,) +UVHS_KEEP_FPGAS ?= $(if $(filter kmh,$(CPU)),b0.f0 b0.f1 b0.f2 b0.f3,b0.f0 b0.f2) UVHS_LUT_FILL_RATE ?= $(if $(filter kmh,$(CPU)),70,) UVHS_LUT6_FILL_RATE ?= $(if $(filter kmh,$(CPU)),35,) @@ -77,6 +77,7 @@ uvhs_preflight: done; \ for file in \ "$(UVHS_COMPILATION_DIR)/vivado_pre_opt.tcl" \ + "$(UVHS_COMPILATION_DIR)/partition.tcl" \ "$(UVHS_TEMPLATE_DIR)/Makefile" \ "$(UVHS_TEMPLATE_DIR)/script/1B_4F_HGC_assemble.tcl"; do \ [[ -f "$$file" ]] || { echo "ERROR: file not found: $$file" >&2; exit 1; }; \ From 709a74d490aa25039dedc67206ded29f4edbf6bf Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 11:29:59 +0800 Subject: [PATCH 32/62] fix(fpga_diff): query UVHS partition RTL cell --- fpga_diff/uvhs/compilation/partition.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fpga_diff/uvhs/compilation/partition.tcl b/fpga_diff/uvhs/compilation/partition.tcl index 9a6896b4..4a616eca 100644 --- a/fpga_diff/uvhs/compilation/partition.tcl +++ b/fpga_diff/uvhs/compilation/partition.tcl @@ -3,7 +3,7 @@ ################################################################################ set uvhs_ddr_cell \ - [get_cells {fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4}] + [get_cells -rtl {fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4}] if {[llength $uvhs_ddr_cell] != 1} { error "expected one UVHS DUT DDR instance, got [llength $uvhs_ddr_cell]" } From a3115d5a1379b50122868595a3511c36d6da0165 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 11:38:12 +0800 Subject: [PATCH 33/62] fix(fpga_diff): recreate UVHS frontend database --- fpga_diff/uvhs/compilation/frontend_run.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fpga_diff/uvhs/compilation/frontend_run.tcl b/fpga_diff/uvhs/compilation/frontend_run.tcl index 0ea39539..874e2a98 100644 --- a/fpga_diff/uvhs/compilation/frontend_run.tcl +++ b/fpga_diff/uvhs/compilation/frontend_run.tcl @@ -71,7 +71,7 @@ proc uvhs::start_frontend_shell_compat {} { puts "INFO: started UVHS frontend shell compatibility helper" } -create_working_space hw.dat +create_working_space -force hw.dat set_option syn.computeFeCheckSum true set_parallel_option -max_threads 4 -max_processes 16 -label frontend From 4748d39176ad273a98dfcb8897b16f34cc428c15 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 11:43:02 +0800 Subject: [PATCH 34/62] fix(fpga_diff): constrain UVHS partition after elaboration --- fpga_diff/uvhs/compilation/frontend_run.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fpga_diff/uvhs/compilation/frontend_run.tcl b/fpga_diff/uvhs/compilation/frontend_run.tcl index 874e2a98..80a9a20f 100644 --- a/fpga_diff/uvhs/compilation/frontend_run.tcl +++ b/fpga_diff/uvhs/compilation/frontend_run.tcl @@ -95,7 +95,6 @@ create_system_design -name VU19P_X4 -platform U2.2 uvhs::source_required topology.tcl uvhs::source_required assign_pin.tcl -set_partition_constraint_file [uvhs::path partition.tcl] set probe_script [uvhs::env_or_default UVHS_PROBE_TCL ""] if {$probe_script ne ""} { set probe_script [file normalize $probe_script] @@ -128,6 +127,7 @@ if {![file exists $filelist]} { } read_verilog -f $filelist -mfcu elaborate_design $design_top +set_partition_constraint_file [uvhs::path partition.tcl] uvhs::start_frontend_shell_compat synthesize_design -parallel_option frontend save_working_space From b23566429368ff1c7d70f6dd4709670ce11754d6 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 12:00:07 +0800 Subject: [PATCH 35/62] fix(fpga_diff): align UVHS backend constraints --- fpga_diff/uvhs/compilation/backend_run.tcl | 20 ++++++++++++++++++++ fpga_diff/uvhs/compilation/frontend_run.tcl | 1 - fpga_diff/uvhs/compilation/partition.tcl | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/fpga_diff/uvhs/compilation/backend_run.tcl b/fpga_diff/uvhs/compilation/backend_run.tcl index f4e0c715..97f0187b 100644 --- a/fpga_diff/uvhs/compilation/backend_run.tcl +++ b/fpga_diff/uvhs/compilation/backend_run.tcl @@ -24,6 +24,7 @@ unset ::env(UVHS_ASSIGN_PIN_TOP) create_design -name test read_netlist link_design +uvhs::source_required partition.tcl report_resource -depth 4 instrument_design @@ -52,6 +53,25 @@ if {[llength $ddr_ui_clock_pin] != 1} { } create_clock -name DDR_UI_CLK -period 5.0 $ddr_ui_clock_pin +foreach {clock_name master_name cell_name} { + SOC_GATED_CLK CPU_CLK_IN core_def/SOC_CLK_CTRL_UVin_bufgce_1 + RTC_GATED_CLK TMCLK core_def/RTC_CLK_CTRL_UVin_bufgce_1 +} { + set master_clock [get_clocks -quiet $master_name] + set input_pin [get_pins -quiet ${cell_name}/I] + set output_pin [get_pins -quiet ${cell_name}/O] + if {![llength $input_pin] && ![llength $output_pin]} { + puts "INFO: skip optimized-away generated clock $clock_name" + continue + } + if {[llength $master_clock] != 1 || [llength $input_pin] != 1 || + [llength $output_pin] != 1} { + error "required generated clock path not found for $clock_name" + } + create_generated_clock -add -name $clock_name \ + -master_clock $master_clock -source $input_pin -divide_by 1 $output_pin +} + infer_clock report_clock -inferred transform_clock diff --git a/fpga_diff/uvhs/compilation/frontend_run.tcl b/fpga_diff/uvhs/compilation/frontend_run.tcl index 80a9a20f..190b221b 100644 --- a/fpga_diff/uvhs/compilation/frontend_run.tcl +++ b/fpga_diff/uvhs/compilation/frontend_run.tcl @@ -127,7 +127,6 @@ if {![file exists $filelist]} { } read_verilog -f $filelist -mfcu elaborate_design $design_top -set_partition_constraint_file [uvhs::path partition.tcl] uvhs::start_frontend_shell_compat synthesize_design -parallel_option frontend save_working_space diff --git a/fpga_diff/uvhs/compilation/partition.tcl b/fpga_diff/uvhs/compilation/partition.tcl index 4a616eca..0b01aad7 100644 --- a/fpga_diff/uvhs/compilation/partition.tcl +++ b/fpga_diff/uvhs/compilation/partition.tcl @@ -3,7 +3,7 @@ ################################################################################ set uvhs_ddr_cell \ - [get_cells -rtl {fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4}] + [get_cells -quiet {core_def/U_UVHS_UVW_AXI4_TO_DDR4}] if {[llength $uvhs_ddr_cell] != 1} { error "expected one UVHS DUT DDR instance, got [llength $uvhs_ddr_cell]" } From c464e15649fdb6acc3b3224d5f73e6e7dee6bcf3 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 13:15:46 +0800 Subject: [PATCH 36/62] fix(fpga_diff): bind UVHS user DDR resources Pin the external DDR wrapper to B0/F0/FMC0 so UHD retains the per-FPGA FMC3 cards. Keep the DDR status on F0 and localize the derived SOC clock for F0/F2 partitioning. Co-authored-by: Kamimiao --- fpga_diff/uvhs/compilation/assign_pin.tcl | 10 ++++++---- fpga_diff/uvhs/compilation/backend_run.tcl | 6 +++++- fpga_diff/uvhs/compilation/partition.tcl | 11 ++++++++++- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/fpga_diff/uvhs/compilation/assign_pin.tcl b/fpga_diff/uvhs/compilation/assign_pin.tcl index 8914efd4..065fa440 100644 --- a/fpga_diff/uvhs/compilation/assign_pin.tcl +++ b/fpga_diff/uvhs/compilation/assign_pin.tcl @@ -1,8 +1,8 @@ ################################################################################ -# Pin assignment for fpga_diff on a U2.2 VU19P FPGA (b0.f2). +# Pin assignment for fpga_diff on the U2.2 VU19P platform. # -# This file targets the single-FPGA b0.f2 configuration. All user-visible top -# ports bind to b0.F2_* connectors instead of the mixed F0/F1/F2 template. +# CPU, PCIe, and low-speed I/O use b0.f2. DDR-owned status follows the user DDR +# controller on b0.f0. ################################################################################ proc pin_name {top port} { @@ -36,7 +36,9 @@ proc apc16_pin {port slot} { # rstn_sw* are exported as UVHS global resets and must not also be assign_pin'd. apc16_pin led0 3 apc16_pin led2 4 -apc16_pin led3 5 +# led3 is driven by the DDR calibration status and must follow the user DDR to +# F0. FMC1 is unused by the U2.2 assembly template. +assign_pin -port [pin_name $top led3] -connector b0.F0_FMC1 -index 311 # UART0 defaults to the F2 APC16 sideband connector. A two-FPGA build can # route it through the F1 UV_FMCH_FLASH USB-UART with FMC indices 311/270. diff --git a/fpga_diff/uvhs/compilation/backend_run.tcl b/fpga_diff/uvhs/compilation/backend_run.tcl index 97f0187b..6f166cb2 100644 --- a/fpga_diff/uvhs/compilation/backend_run.tcl +++ b/fpga_diff/uvhs/compilation/backend_run.tcl @@ -74,8 +74,12 @@ foreach {clock_name master_name cell_name} { infer_clock report_clock -inferred -transform_clock fpga_diff_set_async_clock_groups +set soc_gated_clock [get_clocks -quiet SOC_GATED_CLK] +if {[llength $soc_gated_clock] == 1} { + config_clock -localize $soc_gated_clock +} +transform_clock set fill_rate_args {} foreach {option variable} { -lut UVHS_LUT_FILL_RATE diff --git a/fpga_diff/uvhs/compilation/partition.tcl b/fpga_diff/uvhs/compilation/partition.tcl index 0b01aad7..c42e29eb 100644 --- a/fpga_diff/uvhs/compilation/partition.tcl +++ b/fpga_diff/uvhs/compilation/partition.tcl @@ -1,5 +1,5 @@ ################################################################################ -# Keep the DUT DDR controller on the FPGA connected to the user DDR card. +# Keep the DUT DDR controller on the FPGA and connector of the user DDR card. ################################################################################ set uvhs_ddr_cell \ @@ -8,3 +8,12 @@ if {[llength $uvhs_ddr_cell] != 1} { error "expected one UVHS DUT DDR instance, got [llength $uvhs_ddr_cell]" } create_fpga -name b0.f0 -cells $uvhs_ddr_cell +set uvhs_ddr_connector b0.F0_FMC0 +set_property -name connector -value $uvhs_ddr_connector \ + -objects $uvhs_ddr_cell +set uvhs_bound_ddr_connector \ + [get_property -name connector -objects $uvhs_ddr_cell] +if {$uvhs_bound_ddr_connector ne $uvhs_ddr_connector} { + error "failed to constrain UVHS DUT DDR to $uvhs_ddr_connector" +} +puts "INFO: constrain UVHS DUT DDR to $uvhs_bound_ddr_connector" From ca393798d0d12be4c9e1d7a7aeb3ccbfbf88c170 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 14:19:22 +0800 Subject: [PATCH 37/62] fix(fpga_diff): avoid localizing UVHS derived clock Let UVHS distribute SOC_GATED_CLK across the F0/F2 partition. Explicit localization creates a replicated clock cone constrained into F0 IO resources, conflicting with user DDR and Aurora clock placement. Co-authored-by: Kamimiao --- fpga_diff/uvhs/compilation/backend_run.tcl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fpga_diff/uvhs/compilation/backend_run.tcl b/fpga_diff/uvhs/compilation/backend_run.tcl index 6f166cb2..c93328c3 100644 --- a/fpga_diff/uvhs/compilation/backend_run.tcl +++ b/fpga_diff/uvhs/compilation/backend_run.tcl @@ -75,10 +75,6 @@ foreach {clock_name master_name cell_name} { infer_clock report_clock -inferred fpga_diff_set_async_clock_groups -set soc_gated_clock [get_clocks -quiet SOC_GATED_CLK] -if {[llength $soc_gated_clock] == 1} { - config_clock -localize $soc_gated_clock -} transform_clock set fill_rate_args {} foreach {option variable} { From 691881a06473aa4fd850bc599efd7b47812b9a64 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 14:38:17 +0800 Subject: [PATCH 38/62] fix(fpga_diff): keep UVHS led3 on F2 Keep the status output with the CPU and XDMA sideband pins. Assigning it to the F0 user-DDR partition crosses the SOC clock timing group and makes transform_clock fail. Co-authored-by: Kamimiao --- fpga_diff/uvhs/compilation/assign_pin.tcl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fpga_diff/uvhs/compilation/assign_pin.tcl b/fpga_diff/uvhs/compilation/assign_pin.tcl index 065fa440..23f5903e 100644 --- a/fpga_diff/uvhs/compilation/assign_pin.tcl +++ b/fpga_diff/uvhs/compilation/assign_pin.tcl @@ -32,13 +32,11 @@ proc apc16_pin {port slot} { assign_pin -port [pin_name $top $port] -connector b0.F2_APC16 -index [lindex $apc16_indices $slot] } -# Low-speed debug/control pins on the unused f2 APC16 connector. +# Low-speed debug/control pins on the unused F2 APC16 connector. # rstn_sw* are exported as UVHS global resets and must not also be assign_pin'd. apc16_pin led0 3 apc16_pin led2 4 -# led3 is driven by the DDR calibration status and must follow the user DDR to -# F0. FMC1 is unused by the U2.2 assembly template. -assign_pin -port [pin_name $top led3] -connector b0.F0_FMC1 -index 311 +apc16_pin led3 5 # UART0 defaults to the F2 APC16 sideband connector. A two-FPGA build can # route it through the F1 UV_FMCH_FLASH USB-UART with FMC indices 311/270. From b0c6c23a260482c0ea6c0d85cb674b84cc877ace Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 15:12:57 +0800 Subject: [PATCH 39/62] fix(fpga_diff): leave DDR status LED unbound The calibration-status output crosses the user-DDR and CPU partitions. It is not part of the functional interface, so do not bind it to either FPGA sideband connector. Co-authored-by: Kamimiao --- fpga_diff/uvhs/compilation/assign_pin.tcl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fpga_diff/uvhs/compilation/assign_pin.tcl b/fpga_diff/uvhs/compilation/assign_pin.tcl index 23f5903e..5f189073 100644 --- a/fpga_diff/uvhs/compilation/assign_pin.tcl +++ b/fpga_diff/uvhs/compilation/assign_pin.tcl @@ -1,8 +1,8 @@ ################################################################################ # Pin assignment for fpga_diff on the U2.2 VU19P platform. # -# CPU, PCIe, and low-speed I/O use b0.f2. DDR-owned status follows the user DDR -# controller on b0.f0. +# CPU, PCIe, and low-speed I/O use b0.f2. The user-DDR controller is bound to +# b0.f0 separately by partition.tcl. ################################################################################ proc pin_name {top port} { @@ -36,7 +36,8 @@ proc apc16_pin {port slot} { # rstn_sw* are exported as UVHS global resets and must not also be assign_pin'd. apc16_pin led0 3 apc16_pin led2 4 -apc16_pin led3 5 +# led3 is the DDR calibration-status output. It crosses the user-DDR and +# CPU partitions, so it must remain an unbound top-level status signal. # UART0 defaults to the F2 APC16 sideband connector. A two-FPGA build can # route it through the F1 UV_FMCH_FLASH USB-UART with FMC indices 311/270. From 1eba6eaf1a225e16632d50dd0aa72689389b2320 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 15:53:50 +0800 Subject: [PATCH 40/62] fix(fpga_diff): use global UVHS SoC clock Route SOC_GATED_CLK across B0/F0 and B0/F2 through the platform global clock, retaining the hard user-DDR placement and its F0 calibration-status pin without localizing clock primitives. Co-authored-by: Kamimiao --- fpga_diff/uvhs/compilation/assign_pin.tcl | 4 ++-- fpga_diff/uvhs/compilation/backend_run.tcl | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/fpga_diff/uvhs/compilation/assign_pin.tcl b/fpga_diff/uvhs/compilation/assign_pin.tcl index 5f189073..846d3a56 100644 --- a/fpga_diff/uvhs/compilation/assign_pin.tcl +++ b/fpga_diff/uvhs/compilation/assign_pin.tcl @@ -36,8 +36,8 @@ proc apc16_pin {port slot} { # rstn_sw* are exported as UVHS global resets and must not also be assign_pin'd. apc16_pin led0 3 apc16_pin led2 4 -# led3 is the DDR calibration-status output. It crosses the user-DDR and -# CPU partitions, so it must remain an unbound top-level status signal. +# led3 is driven by the user-DDR calibration status on F0. +assign_pin -port [pin_name $top led3] -connector b0.F0_FMC1 -index 311 # UART0 defaults to the F2 APC16 sideband connector. A two-FPGA build can # route it through the F1 UV_FMCH_FLASH USB-UART with FMC indices 311/270. diff --git a/fpga_diff/uvhs/compilation/backend_run.tcl b/fpga_diff/uvhs/compilation/backend_run.tcl index c93328c3..bc815e73 100644 --- a/fpga_diff/uvhs/compilation/backend_run.tcl +++ b/fpga_diff/uvhs/compilation/backend_run.tcl @@ -75,6 +75,12 @@ foreach {clock_name master_name cell_name} { infer_clock report_clock -inferred fpga_diff_set_async_clock_groups +# Drive the SoC and F0 user-DDR clock cones with the board global-clock path. +# Localizing this cone replicates clock primitives into the DDR FPGA. +set soc_gated_clock [get_clocks -quiet SOC_GATED_CLK] +if {[llength $soc_gated_clock] == 1} { + config_clock -use_global_clock $soc_gated_clock +} transform_clock set fill_rate_args {} foreach {option variable} { From cc8ab996ab0c08ca43a6c64aec9266f4de3dc656 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 23:32:42 +0800 Subject: [PATCH 41/62] fix(fpga_diff): preserve UVHS DiffTest clock gating Drive the UVHS DDR wrapper from the ungated source while sharing the DiffTest clock enable with the CPU clock gate. Keep the CPU and DDR timing groups separate during partitioning and exclude only the expected DDR AXI local-clock TDM check. Co-authored-by: Kamimiao --- fpga_diff/src/rtl/common/core_def_xdma.sv | 10 +++++++--- fpga_diff/uvhs/compilation/backend_run.tcl | 11 ++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/fpga_diff/src/rtl/common/core_def_xdma.sv b/fpga_diff/src/rtl/common/core_def_xdma.sv index 36f1d62b..ab05dd06 100755 --- a/fpga_diff/src/rtl/common/core_def_xdma.sv +++ b/fpga_diff/src/rtl/common/core_def_xdma.sv @@ -1245,6 +1245,7 @@ wire [0:0] br2cfg_wvalid; wire [`CONFIG_DIFFTEST_HOST_AXIS_BYTES-1:0] difftest_from_host_axis_tkeep; wire difftest_from_host_axis_tlast; wire difftest_clock_enable; + wire difftest_clock_gate_enable; wire inter_soc_clk; wire inter_soc_sync_rstn; wire inter_rtc_clk; @@ -1265,6 +1266,9 @@ wire [0:0] br2cfg_wvalid; wire difftest_pcie_clock; assign sys_rstn_io = sys_rstn & ~io_host_reset; assign cpu_rstn_io = cpu_rstn & ~io_host_reset; + assign difftest_clock_gate_enable = + difftest_clock_enable || ~io_host_diff_enable || + ~sys_rstn_io || ~cpu_rstn_io; RST_SYNC #( .SYNC_STAGES(3), @@ -1352,7 +1356,7 @@ wire [0:0] br2cfg_wvalid; DifftestClockGate SOC_CLK_CTRL( .CK (sys_clk_i), - .E (difftest_clock_enable || ~io_host_diff_enable || ~sys_rstn_io || ~cpu_rstn_io), + .E (difftest_clock_gate_enable), .Q (inter_soc_clk) ); @@ -1442,7 +1446,7 @@ assign cpu2ddr_s2m_rid = {4'b0, uvhs_ddr_rid}; assign init_calib_complete = rstn_sw4 & ~uvhs_ddr_user_rst; uvw_axi4_to_ddr4 U_UVHS_UVW_AXI4_TO_DDR4 ( - .ddr4ip_dut_axi_aclk (inter_soc_clk), + .ddr4ip_dut_axi_aclk (sys_clk_i), .ddr4ip_dut_axi_aresetn (rstn_sw4), .ddr4ip_dut_axi_awaddr (uvhs_ddr_awaddr), .ddr4ip_dut_axi_awburst (cpu2ddr_m2s_awburst), @@ -1483,7 +1487,7 @@ uvw_axi4_to_ddr4 U_UVHS_UVW_AXI4_TO_DDR4 ( .ddr4ip_dut_axi_rready (cpu2ddr_m2s_rready), .ddr4ip_dut_axi_rresp (cpu2ddr_s2m_rresp), .ddr4ip_dut_axi_rvalid (cpu2ddr_s2m_rvalid), - .ddr4ip_dut_axi_aclk_en (1'b1), + .ddr4ip_dut_axi_aclk_en (difftest_clock_gate_enable), .ddr4ip_ddr4_user_clk (), .ddr4ip_ddr4_user_rst (uvhs_ddr_user_rst), .sysbus_ghbd_i (256'b0), diff --git a/fpga_diff/uvhs/compilation/backend_run.tcl b/fpga_diff/uvhs/compilation/backend_run.tcl index bc815e73..66f2c11e 100644 --- a/fpga_diff/uvhs/compilation/backend_run.tcl +++ b/fpga_diff/uvhs/compilation/backend_run.tcl @@ -8,6 +8,9 @@ set_working_space hw.dat set_parallel_option -max_threads 4 -max_processes 8 -label fpga set_option time.auto_clock_config true +set_option time.group_io_logic false +set_option time.clock_part_group_mode 2 +set_option part.allow_timing_group_merge false set_option clock.transform_clock.multi_iteration true set_option clock.glitch.force_transform true set_option clock.async_control.force_accept true @@ -75,12 +78,6 @@ foreach {clock_name master_name cell_name} { infer_clock report_clock -inferred fpga_diff_set_async_clock_groups -# Drive the SoC and F0 user-DDR clock cones with the board global-clock path. -# Localizing this cone replicates clock primitives into the DDR FPGA. -set soc_gated_clock [get_clocks -quiet SOC_GATED_CLK] -if {[llength $soc_gated_clock] == 1} { - config_clock -use_global_clock $soc_gated_clock -} transform_clock set fill_rate_args {} foreach {option variable} { @@ -117,7 +114,7 @@ localize_design -replicate_cell -clock -self_check sweep_design -keep_feedthrough localize_design -data route_design -check_timing -verbose +check_timing -verbose -exclude local_clock_domain_cross_TDM report_system_performance -show_clock_relation -verbose report_path -normalize -exception -tdr -net -rtl \ -max_path 100 -sort_by fmax From 39ca3f9940f0c7f7f0167af966d3706c944093dc Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 3 Aug 2026 23:32:55 +0800 Subject: [PATCH 42/62] fix(fpga_diff): isolate UVHS runtime files Keep temporary and ILA output under the selected runtime work directory, and pass it explicitly to the retained UVHS session. Reapply the 25 MHz CPU debug clock before downloading a database. Co-authored-by: Kamimiao --- fpga_diff/uvhs/runtime/runtime_server.tcl | 14 +++++++++----- fpga_diff/uvhs/uvhs.mk | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/fpga_diff/uvhs/runtime/runtime_server.tcl b/fpga_diff/uvhs/runtime/runtime_server.tcl index 947e1f6e..0dbd8344 100644 --- a/fpga_diff/uvhs/runtime/runtime_server.tcl +++ b/fpga_diff/uvhs/runtime/runtime_server.tcl @@ -1,7 +1,7 @@ # Download a completed UVHS database and retain its owning runtime session. proc uvhs_temp_dir {} { - set path [file join [pwd] tmp] + set path [file join $::uvhs_runtime_work_dir tmp] file mkdir $path return $path } @@ -227,7 +227,7 @@ proc uvhs_ila {trigger_file output_name timeout depth position clock} { error "capture position must be between 0 and 100: $position" } - set output_dir [file join [pwd] UHD $output_name] + set output_dir [file join $::uvhs_runtime_work_dir UHD $output_name] file delete -force $output_dir query -trigger trigger -ini_check $trigger_file @@ -344,13 +344,16 @@ proc uvhs_poll_command_file {} { } proc uvhs_serve_runtime_commands {} { - foreach variable {UVHS_COMMAND_FILE UVHS_RUNTIME_READY_FILE} { + foreach variable { + UVHS_COMMAND_FILE UVHS_RUNTIME_READY_FILE UVHS_RUNTIME_WORK_DIR + } { if {![info exists ::env($variable)] || $::env($variable) eq ""} { error "$variable is not set" } } set ::uvhs_command_file $::env(UVHS_COMMAND_FILE) set ::uvhs_ready_file $::env(UVHS_RUNTIME_READY_FILE) + set ::uvhs_runtime_work_dir $::env(UVHS_RUNTIME_WORK_DIR) set ::uvhs_keepalive 0 uvhs_signal_runtime_ready uvhs_poll_command_file @@ -381,9 +384,10 @@ proc uvhs_initialize_runtime {} { puts "WARN: retaining database replay clocks: $clock_error" } else { config -clock -default - config -clock -commit - query -clock } + config -clock -name clk5_p -frequency 25000000 + config -clock -commit + query -clock uvhs_hold_soc_for_download download diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 6ab50890..0479760c 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -134,6 +134,7 @@ uvhs_write_bitstream: test -x "$(UVHS_RUNTIME_DIR)/runtime_session.sh" mkdir -p "$(UVHS_RUNTIME_WORK_DIR)" $(UVHS_TOOL_ENV) UVHS_DB_PATH="$(UVHS_RUNTIME_DB)" \ + UVHS_RUNTIME_WORK_DIR="$(UVHS_RUNTIME_WORK_DIR)" \ UVHS_COMMAND_FILE="$(UVHS_RUNTIME_COMMAND_FILE)" \ UVHS_RUNTIME_READY_FILE="$(UVHS_RUNTIME_READY_FILE)" \ bash "$(UVHS_RUNTIME_DIR)/runtime_session.sh" start \ From 607d990df12acd69e6b1a3d159f432ad2623f63e Mon Sep 17 00:00:00 2001 From: klin02 Date: Tue, 4 Aug 2026 01:42:40 +0800 Subject: [PATCH 43/62] feat(fpga_diff): split UVHS waveform capture Arm UHD capture separately so fpga-host can install trigger conditions\nbefore releasing the CPU and preserve a pre-trigger window. Add a\ndedicated USDB-to-VCD target and prepare writable UHD output paths.\n\nCo-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 73 ++++++++++++++------ fpga_diff/uvhs/compilation/probe_ila.tcl | 3 +- fpga_diff/uvhs/runtime/runtime_server.tcl | 81 ++++++++++++++++++----- fpga_diff/uvhs/uvhs.mk | 29 +++++--- 4 files changed, 137 insertions(+), 49 deletions(-) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 16d74ce0..217cd6b6 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -98,7 +98,9 @@ make uvhs_halt_soc CPU= SUFFIX= make uvhs_write_ddr CPU= SUFFIX= WORKLOAD=/path/to/image.txt make uvhs_write_flash CPU= SUFFIX= WORKLOAD=/path/to/image.bin make uvhs_reset_cpu CPU= SUFFIX= -make uvhs_ila CPU= SUFFIX= TRIGGER=/path/to/trigger.ini +make uvhs_ila_arm CPU= SUFFIX= TRIGGER=/path/to/trigger.ini +make uvhs_ila CPU= SUFFIX= +make uvhs_vcd CPU= SUFFIX= make uvhs_ila_clear CPU= SUFFIX= make uvhs_runtime_stop CPU= SUFFIX= ``` @@ -151,14 +153,14 @@ for signals that may participate in a trigger condition. Fill it as follows: ```tcl set uvhs_ila_clock_path [string trim { - fpga_top_debug.core_def.inter_soc_clk + fpga_top_debug.core_def.sys_clk_i }] set uvhs_ila_probe_paths { fpga_top_debug.core_def.cpu_rstn_io - fpga_top_debug.core_def.difftest_startup_ready_pcie + fpga_top_debug.core_def.io_host_ila_trigger } set uvhs_ila_trigger_paths { - fpga_top_debug.core_def.cpu_rstn_io + fpga_top_debug.core_def.io_host_ila_trigger } ``` @@ -187,17 +189,19 @@ reported by `query -trigger`: ```ini [uvhs_ila] LOGIC = OR -fpga_top_debug.core_def.cpu_rstn_io = 1 +fpga_top_debug.core_def.io_host_ila_trigger = R [UHD_FINAL_CONDITIONS_LOGIC] LOGIC = OR uvhs_ila ``` -After `uvhs_write_bitstream`, `uvhs_ila` is the one-shot capture start command. -It checks the condition file, enables capture and trigger logic, resets the -CPU, waits for the trigger, uploads the UHD data, and reconstructs the -waveform. It creates both files below the selected build directory: +Waveform capture is split around the host run. `uvhs_ila_arm` validates and +installs the trigger condition, starts capture, and returns immediately. It +does not reset or release the CPU. `uvhs_ila` waits for an armed trigger, +uploads the UHD data, reconstructs the waveform database, and calls +`uvhs_vcd`. The standalone `uvhs_vcd` target repeats only the USDB-to-VCD +conversion. The commands create both files below the selected build directory: ```text runtime-work/UHD/uvhs_ila/UvData.usdb @@ -208,15 +212,36 @@ The corresponding UVHS runtime sequence is: ```tcl trigger -ini_check /path/to/trigger.ini -trigger -set -condition /path/to/trigger.ini -position 70 +trigger -set -condition /path/to/trigger.ini -position 0 capture -enable trigger -enable trigger -status -wait 1 -timeout 60 -upload_uhd -depth 1000000 -position 70 -out uvhs_ila +upload_uhd -depth 1000000 -position 0 -out uvhs_ila +``` + +The FPGA host clears `HOST_IO_ILA_TRIGGER`, invokes `FPGA_ILA_DUMP_CMD`, and +then releases the CPU. It raises that signal at Good Trap or DiffTest failure. +Use `uvhs_ila_arm` as the hook so the complete capture window precedes the +host trigger: + +```sh +export FPGA_ILA_DUMP_CMD='ssh \ + "make -C /path/to/env-scripts/fpga_diff uvhs_ila_arm \ + CPU= SUFFIX= TRIGGER=/path/to/trigger.ini \ + UVHS_ILA_POSITION=0"' + +/path/to/fpga-host + +# Run on the runtime host after fpga-host exits. +make uvhs_ila CPU= SUFFIX= ``` -Capture hardware is armed only by `uvhs_ila`. Clear the trigger configuration -after a timed-out or unwanted capture with: +The arm command must use the same runtime work directory as +`uvhs_write_bitstream`. If the FPGA host and UVHS runtime are on one machine, +omit `ssh `. The trigger signal must be listed in the compile-time +`trigger_net` group; adding it to RTL with `mark_debug` alone is not sufficient. + +Clear the trigger configuration after a timed-out or unwanted capture with: ```sh make uvhs_ila_clear CPU= SUFFIX= @@ -232,8 +257,8 @@ debug-command latency rather than DUT cycle time. A large probe set can still lower the achievable clock frequency indirectly by adding routing and timing pressure during compilation. The runtime command service is serial, so `uvhs_ila_clear` is handled after an -in-flight `uvhs_ila` reaches its trigger or timeout; it is not an asynchronous -interrupt for the current wait. +in-flight `uvhs_ila` wait reaches its trigger or timeout; it is not an +asynchronous interrupt for the current wait. The USDB-to-VCD step is equivalent to: @@ -246,17 +271,21 @@ $UV_ROOT/uvd/uvs/bin/usdb2vcd \ The upload window is controlled when starting the capture: ```sh -make uvhs_ila CPU= SUFFIX= TRIGGER=/path/to/trigger.ini \ - UVHS_ILA_DEPTH=1000000 UVHS_ILA_POSITION=70 +make uvhs_ila_arm CPU= SUFFIX= TRIGGER=/path/to/trigger.ini \ + UVHS_ILA_POSITION=0 +make uvhs_ila CPU= SUFFIX= UVHS_ILA_DEPTH=1000000 ``` `UVHS_ILA_DEPTH` is the total uploaded sample count. `UVHS_ILA_POSITION` is the -percentage after the trigger, from 0 through 100; the example uploads roughly -300,000 samples before the trigger and 700,000 after it. Position 0 keeps the -window before the trigger, 50 centers it, and 100 keeps the window after the -trigger. `UVHS_ILA_CLOCK` can select the depth-counting clock by a +percentage after the trigger, from 0 through 100. Position 0, the default, +keeps the window before the trigger; 50 centers it; 100 keeps the window after +the trigger. `UVHS_ILA_CLOCK` can select the depth-counting clock by a runtime-database global clock name or a frequency; when empty, the tool uses -its 200 MHz TS clock. `UVHS_ILA_TIMEOUT` defaults to 60 seconds. This is the +its 200 MHz TS clock. If the compile-time sampling path is a gated clock, pass +its backend clock path through `UVHS_ILA_GATED_CLOCK`; its frequency defaults +to 25 MHz and can be changed with `UVHS_ILA_GATED_CLOCK_FREQUENCY`. Prefer the +ungated parent clock in new probe files so capture completion does not depend +on DUT clock-gate state. `UVHS_ILA_TIMEOUT` defaults to 60 seconds. This is the UVHS UHD path; the normal Vivado flow continues to use `make dump_ila` and a `.ltx` file. diff --git a/fpga_diff/uvhs/compilation/probe_ila.tcl b/fpga_diff/uvhs/compilation/probe_ila.tcl index f76c6990..f90317a0 100644 --- a/fpga_diff/uvhs/compilation/probe_ila.tcl +++ b/fpga_diff/uvhs/compilation/probe_ila.tcl @@ -1,7 +1,8 @@ # Fill only the RTL paths below. Braces preserve hierarchy indexes such as [0]. # Leave the clock and signal lists empty to build without UHD instrumentation. set uvhs_ila_group_name uvhs_ila -# Sampling clock path for this probe/trigger group. +# Sampling clock path for this probe/trigger group. Prefer the ungated parent +# clock so post-trigger samples can complete after the DUT clock stops. set uvhs_ila_clock_path [string trim { }] # Probe signal paths, one per line. diff --git a/fpga_diff/uvhs/runtime/runtime_server.tcl b/fpga_diff/uvhs/runtime/runtime_server.tcl index 0dbd8344..cfb07b34 100644 --- a/fpga_diff/uvhs/runtime/runtime_server.tcl +++ b/fpga_diff/uvhs/runtime/runtime_server.tcl @@ -6,6 +6,21 @@ proc uvhs_temp_dir {} { return $path } +proc uvhs_prepare_uhd_root {} { + set path [file join $::uvhs_runtime_work_dir UHD] + set writable_path $path + if {![catch {file lstat $path attributes}] && + $attributes(type) eq "link"} { + set writable_path [file readlink $path] + if {[file pathtype $writable_path] ne "absolute"} { + set writable_path [file join [file dirname $path] $writable_path] + } + } + file mkdir $writable_path + file attributes $writable_path -permissions 00777 + return $path +} + proc uvhs_parse_integer {name value} { if {![string is wideinteger -strict $value]} { error "$name is not an integer: $value" @@ -210,37 +225,62 @@ proc uvhs_write_ddr_pairs {input_file rtl_path data_width} { puts "INFO: DDR backdoor write completed: $input_file" } -proc uvhs_ila {trigger_file output_name timeout depth position clock} { +proc uvhs_ila_arm { + trigger_file position gated_clock gated_clock_frequency +} { if {![file isfile $trigger_file]} { error "trigger condition file not found: $trigger_file" } - if {![regexp {^[A-Za-z0-9_.-]+$} $output_name]} { - error "capture output name contains unsupported characters: $output_name" - } - set timeout [uvhs_parse_integer "capture timeout" $timeout] - set depth [uvhs_parse_integer "capture depth" $depth] set position [uvhs_parse_integer "capture position" $position] - if {$timeout <= 0 || $depth <= 0} { - error "capture timeout and depth must be positive" - } if {$position < 0 || $position > 100} { error "capture position must be between 0 and 100: $position" } + if {$gated_clock ne ""} { + set gated_clock_frequency [uvhs_parse_integer \ + "gated capture clock frequency" $gated_clock_frequency] + if {$gated_clock_frequency <= 0} { + error "gated capture clock frequency must be positive" + } + } - set output_dir [file join $::uvhs_runtime_work_dir UHD $output_name] - file delete -force $output_dir + unset -nocomplain ::uvhs_ila_position + trigger -clear query -trigger trigger -ini_check $trigger_file + if {$gated_clock ne ""} { + trigger -set -gatedclk $gated_clock \ + -frequency $gated_clock_frequency -polarity H + } trigger -set -condition $trigger_file -position $position capture -enable trigger -enable + set ::uvhs_ila_position $position + puts "INFO: UVHS waveform capture armed at position $position" +} + +proc uvhs_ila_wait {output_name timeout depth clock} { + if {![info exists ::uvhs_ila_position]} { + error "UVHS waveform capture is not armed; run ila_arm first" + } + if {![regexp {^[A-Za-z0-9_.-]+$} $output_name]} { + error "capture output name contains unsupported characters: $output_name" + } + set timeout [uvhs_parse_integer "capture timeout" $timeout] + set depth [uvhs_parse_integer "capture depth" $depth] + if {$timeout <= 0 || $depth <= 0} { + error "capture timeout and depth must be positive" + } - # The default capture observes boot from CPU reset release. External traffic - # may also satisfy the trigger while this command is waiting. - uvhs_reset_cpu set trigger_status [trigger -status -wait 1 -timeout $timeout -tclobj] puts "INFO: UVHS trigger status: $trigger_status" - set upload_options [list -depth $depth -position $position] + if {![regexp -nocase {Waveform Data Ready\s+true} $trigger_status]} { + error "UVHS waveform data is not ready" + } + + set output_dir [file join [uvhs_prepare_uhd_root] $output_name] + file delete -force $output_dir + set upload_options [list -depth $depth \ + -position $::uvhs_ila_position] if {$clock ne ""} { lappend upload_options -clock $clock } @@ -257,6 +297,7 @@ proc uvhs_ila {trigger_file output_name timeout depth position clock} { proc uvhs_ila_clear {} { trigger -clear + unset -nocomplain ::uvhs_ila_position puts "INFO: UVHS trigger conditions and capture are disabled" } @@ -286,9 +327,13 @@ proc uvhs_execute_command {args} { uvhs_write_flash_gbus {*}[lrange $args 1 7] uvhs_release_cpu_after_memory } - ila { - if {[llength $args] != 7} { error "ila expects 6 arguments" } - uvhs_ila {*}[lrange $args 1 6] + ila_arm { + if {[llength $args] != 5} { error "ila_arm expects 4 arguments" } + uvhs_ila_arm {*}[lrange $args 1 4] + } + ila_wait { + if {[llength $args] != 5} { error "ila_wait expects 4 arguments" } + uvhs_ila_wait {*}[lrange $args 1 4] } ila_clear { if {[llength $args] != 1} { error "ila_clear expects no arguments" } diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 0479760c..951c54a3 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -29,8 +29,10 @@ UVHS_RUNTIME_TIMEOUT ?= 600 UVHS_ILA_TIMEOUT ?= 60 UVHS_ILA_DEPTH ?= 1000000 -UVHS_ILA_POSITION ?= 50 +UVHS_ILA_POSITION ?= 0 UVHS_ILA_CLOCK ?= +UVHS_ILA_GATED_CLOCK ?= +UVHS_ILA_GATED_CLOCK_FREQUENCY ?= 25000000 UVHS_ILA_DIR := $(UVHS_RUNTIME_WORK_DIR)/UHD/uvhs_ila UVHS_ILA_USDB := $(UVHS_ILA_DIR)/UvData.usdb UVHS_ILA_VCD := $(UVHS_ILA_DIR)/UvData.vcd @@ -54,7 +56,8 @@ UVHS_FLOW_ENV = \ .PHONY: uvhs uvhs_preflight uvhs_prepare \ uvhs_frontend uvhs_backend uvhs_clean uvhs_write_bitstream \ uvhs_halt_soc uvhs_reset_cpu uvhs_write_ddr uvhs_write_flash \ - uvhs_ila uvhs_ila_clear uvhs_runtime_status uvhs_runtime_stop + uvhs_ila_arm uvhs_ila uvhs_vcd uvhs_ila_clear \ + uvhs_runtime_status uvhs_runtime_stop # Validate host tools and external inputs before starting a multi-hour build. uvhs_preflight: @@ -171,18 +174,28 @@ uvhs_write_flash: test -f "$(WORKLOAD)" $(call uvhs_runtime_command,write_flash "$(abspath $(WORKLOAD))" B0 F2 0 0 0x0 0x8000) -uvhs_ila: +uvhs_ila_arm: test -f "$(TRIGGER)" - test -x "$$UV_ROOT/uvd/uvs/bin/usdb2vcd" - $(call uvhs_runtime_command,ila \ - "$(abspath $(TRIGGER))" uvhs_ila \ + $(call uvhs_runtime_command,ila_arm \ + "$(abspath $(TRIGGER))" "$(UVHS_ILA_POSITION)" \ + "$(UVHS_ILA_GATED_CLOCK)" \ + "$(UVHS_ILA_GATED_CLOCK_FREQUENCY)") + +uvhs_ila: + $(call uvhs_runtime_command,ila_wait uvhs_ila \ "$(UVHS_ILA_TIMEOUT)" "$(UVHS_ILA_DEPTH)" \ - "$(UVHS_ILA_POSITION)" "$(UVHS_ILA_CLOCK)") + "$(UVHS_ILA_CLOCK)") test -s "$(UVHS_ILA_USDB)" + $(MAKE) uvhs_vcd + @echo "UVHS_ILA_USDB=$(UVHS_ILA_USDB)" + +uvhs_vcd: + test -x "$$UV_ROOT/uvd/uvs/bin/usdb2vcd" + test -s "$(UVHS_ILA_USDB)" + rm -f "$(UVHS_ILA_VCD)" $(UVHS_TOOL_ENV) "$$UV_ROOT/uvd/uvs/bin/usdb2vcd" \ -i "$(UVHS_ILA_USDB)" -o "$(UVHS_ILA_VCD)" test -s "$(UVHS_ILA_VCD)" - @echo "UVHS_ILA_USDB=$(UVHS_ILA_USDB)" @echo "UVHS_ILA_VCD=$(UVHS_ILA_VCD)" uvhs_ila_clear: From 9384ff3c654fe42b000ed877942b83655fb2c540 Mon Sep 17 00:00:00 2001 From: klin02 Date: Tue, 4 Aug 2026 02:05:23 +0800 Subject: [PATCH 44/62] fix(fpga_diff): exclude UVHS clock TDM checks Use the supported clock_tdm check group so the expected inter-FPGA clock-domain crossings do not abort backend compilation. Co-authored-by: Kamimiao --- fpga_diff/uvhs/compilation/backend_run.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fpga_diff/uvhs/compilation/backend_run.tcl b/fpga_diff/uvhs/compilation/backend_run.tcl index 66f2c11e..2df276da 100644 --- a/fpga_diff/uvhs/compilation/backend_run.tcl +++ b/fpga_diff/uvhs/compilation/backend_run.tcl @@ -114,7 +114,7 @@ localize_design -replicate_cell -clock -self_check sweep_design -keep_feedthrough localize_design -data route_design -check_timing -verbose -exclude local_clock_domain_cross_TDM +check_timing -verbose -exclude clock_tdm report_system_performance -show_clock_relation -verbose report_path -normalize -exception -tdr -net -rtl \ -max_path 100 -sort_by fmax From d698f8b662eb8429835b5e697fb42129b68b1305 Mon Sep 17 00:00:00 2001 From: klin02 Date: Tue, 4 Aug 2026 03:18:37 +0800 Subject: [PATCH 45/62] docs(fpga_diff): clarify UVHS trigger window Document the capture-stop pipeline tail observed with position zero so the pre-trigger guarantee matches the validated waveform. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 217cd6b6..5dac8152 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -221,8 +221,8 @@ upload_uhd -depth 1000000 -position 0 -out uvhs_ila The FPGA host clears `HOST_IO_ILA_TRIGGER`, invokes `FPGA_ILA_DUMP_CMD`, and then releases the CPU. It raises that signal at Good Trap or DiffTest failure. -Use `uvhs_ila_arm` as the hook so the complete capture window precedes the -host trigger: +Use `uvhs_ila_arm` as the hook so capture starts before the host releases the +CPU and the requested history precedes the host trigger: ```sh export FPGA_ILA_DUMP_CMD='ssh \ @@ -279,9 +279,12 @@ make uvhs_ila CPU= SUFFIX= UVHS_ILA_DEPTH=1000000 `UVHS_ILA_DEPTH` is the total uploaded sample count. `UVHS_ILA_POSITION` is the percentage after the trigger, from 0 through 100. Position 0, the default, keeps the window before the trigger; 50 centers it; 100 keeps the window after -the trigger. `UVHS_ILA_CLOCK` can select the depth-counting clock by a -runtime-database global clock name or a frequency; when empty, the tool uses -its 200 MHz TS clock. If the compile-time sampling path is a gated clock, pass +the trigger. Position 0 requests no intentional post-trigger allocation, but +the trigger-recognition and capture-stop pipeline can still leave a small tail +after the sampled trigger edge. `UVHS_ILA_CLOCK` can select the depth-counting +clock by a runtime-database global clock name or a frequency; when empty, the +tool uses its 200 MHz TS clock. If the compile-time sampling path is a gated +clock, pass its backend clock path through `UVHS_ILA_GATED_CLOCK`; its frequency defaults to 25 MHz and can be changed with `UVHS_ILA_GATED_CLOCK_FREQUENCY`. Prefer the ungated parent clock in new probe files so capture completion does not depend From 5710f484b0ba93e7a4adb6f075965768a8302a87 Mon Sep 17 00:00:00 2001 From: klin02 Date: Thu, 6 Aug 2026 13:17:58 +0800 Subject: [PATCH 46/62] fix(fpga_diff): align UVHS UART topology Drive UART16550 at 50 MHz and bind it to the physical F1 flash daughter card while preserving the Vivado clocking interface. Carry the validated XDMA clock grouping and XiangShan fetch-path partition strategy into the maintained flow. Co-authored-by: Kamimiao --- fpga_diff/src/rtl/common/core_def_xdma.sv | 2 ++ fpga_diff/src/rtl/common/fpga_top_debug.sv | 6 +++++- fpga_diff/src/tcl/common/AXI_bridge.tcl | 23 ++++++++++++++++----- fpga_diff/uvhs/README.md | 21 +++++++++++++------ fpga_diff/uvhs/compilation/assign_pin.tcl | 14 ++++++------- fpga_diff/uvhs/compilation/backend_run.tcl | 4 ++-- fpga_diff/uvhs/compilation/partition.tcl | 24 ++++++++++++++++++++++ fpga_diff/uvhs/compilation/timing.tcl | 13 ++++++++++-- fpga_diff/uvhs/runtime/runtime_server.tcl | 1 + fpga_diff/uvhs/uvhs.mk | 2 +- 10 files changed, 86 insertions(+), 24 deletions(-) diff --git a/fpga_diff/src/rtl/common/core_def_xdma.sv b/fpga_diff/src/rtl/common/core_def_xdma.sv index ab05dd06..ce7a0ba5 100755 --- a/fpga_diff/src/rtl/common/core_def_xdma.sv +++ b/fpga_diff/src/rtl/common/core_def_xdma.sv @@ -1827,6 +1827,8 @@ AXI_bridge CFG_AXI_bridge_i (.SYS_INTER_CLK (inter_soc_clk), `ifdef UVHS .SYS_INTER_ARESETN (inter_soc_sync_rstn), + .UART_ACLK (uart_sclk), + .UART_ARESETN (uart_sclk_sync_rstn), `endif .ACLK (sys_clk_i), .ARESETN (axi_bclk_sync_rstn), diff --git a/fpga_diff/src/rtl/common/fpga_top_debug.sv b/fpga_diff/src/rtl/common/fpga_top_debug.sv index 3b1d03a3..31d5d6a9 100755 --- a/fpga_diff/src/rtl/common/fpga_top_debug.sv +++ b/fpga_diff/src/rtl/common/fpga_top_debug.sv @@ -15,7 +15,7 @@ module fpga_top_debug input clk8_n, input clk7_p, // ddr 80MHz input clk7_n, - input clk6_p, // system 200MHz + input clk6_p, // system 200MHz / UVHS UART 50MHz input clk6_n, input clk5_p, // debug 25MHz input clk5_n, @@ -233,7 +233,11 @@ IBUFDS_GTE4 refclk2_ibuf ( `endif assign sys_clk_i = dbg_clk_buf; +`ifdef UVHS +assign dev_clk_i = cqetmclk_buf; +`else assign dev_clk_i = dbg_clk_buf; +`endif `ifndef UVHS vio_0 u_vio( diff --git a/fpga_diff/src/tcl/common/AXI_bridge.tcl b/fpga_diff/src/tcl/common/AXI_bridge.tcl index ce08a588..f0f37217 100644 --- a/fpga_diff/src/tcl/common/AXI_bridge.tcl +++ b/fpga_diff/src/tcl/common/AXI_bridge.tcl @@ -300,6 +300,10 @@ proc create_root_design { parentCell } { set_property CONFIG.ASSOCIATED_RESET {SYS_INTER_ARESETN} $SYS_INTER_CLK set SYS_INTER_ARESETN [ create_bd_port -dir I -type rst SYS_INTER_ARESETN ] set_property CONFIG.POLARITY {ACTIVE_LOW} $SYS_INTER_ARESETN + set UART_ACLK [ create_bd_port -dir I -type clk -freq_hz 50000000 UART_ACLK ] + set UART_ARESETN [ create_bd_port -dir I -type rst UART_ARESETN ] + set_property CONFIG.ASSOCIATED_RESET {UART_ARESETN} $UART_ACLK + set_property CONFIG.POLARITY {ACTIVE_LOW} $UART_ARESETN } set uart0_intc [ create_bd_port -dir O -type intr uart0_intc ] @@ -379,32 +383,35 @@ proc create_root_design { parentCell } { [get_bd_pins axi_apb_bridge_0/s_axi_aclk] \ [get_bd_pins axi_interconnect_0/ACLK] \ [get_bd_pins axi_interconnect_0/M00_ACLK] \ - [get_bd_pins axi_interconnect_0/M01_ACLK] \ [get_bd_pins axi_interconnect_0/M02_ACLK] \ [get_bd_pins axi_interconnect_0/M03_ACLK] \ [get_bd_pins axi_interconnect_0/S01_ACLK] \ - [get_bd_pins axi_uart16550_0/s_axi_aclk] \ [get_bd_pins extllc_bram_ctrl/s_axi_aclk] \ [get_bd_pins jtag_axi_flash/aclk] \ ] if {$uvhs_flow} { lappend aclk_pins [get_bd_pins axi_interconnect_0/S02_ACLK] + } else { + lappend aclk_pins \ + [get_bd_pins axi_interconnect_0/M01_ACLK] \ + [get_bd_pins axi_uart16550_0/s_axi_aclk] } connect_bd_net -net ACLK_0_1 [get_bd_ports ACLK] {*}$aclk_pins set aresetn_pins [list \ [get_bd_pins axi_apb_bridge_0/s_axi_aresetn] \ [get_bd_pins axi_interconnect_0/ARESETN] \ [get_bd_pins axi_interconnect_0/M00_ARESETN] \ - [get_bd_pins axi_interconnect_0/M01_ARESETN] \ [get_bd_pins axi_interconnect_0/M02_ARESETN] \ [get_bd_pins axi_interconnect_0/M03_ARESETN] \ [get_bd_pins axi_interconnect_0/S01_ARESETN] \ - [get_bd_pins axi_uart16550_0/s_axi_aresetn] \ [get_bd_pins extllc_bram_ctrl/s_axi_aresetn] \ [get_bd_pins jtag_axi_flash/aresetn] \ ] if {!$uvhs_flow} { - lappend aresetn_pins [get_bd_pins axi_interconnect_0/S00_ARESETN] + lappend aresetn_pins \ + [get_bd_pins axi_interconnect_0/S00_ARESETN] \ + [get_bd_pins axi_interconnect_0/M01_ARESETN] \ + [get_bd_pins axi_uart16550_0/s_axi_aresetn] } else { lappend aresetn_pins [get_bd_pins axi_interconnect_0/S02_ARESETN] } @@ -412,6 +419,12 @@ proc create_root_design { parentCell } { connect_bd_net -net SYS_INTER_CLK_1 [get_bd_ports SYS_INTER_CLK] [get_bd_pins axi_interconnect_0/S00_ACLK] if {$uvhs_flow} { connect_bd_net -net SYS_INTER_ARESETN_1 [get_bd_ports SYS_INTER_ARESETN] [get_bd_pins axi_interconnect_0/S00_ARESETN] + connect_bd_net -net UART_ACLK_1 [get_bd_ports UART_ACLK] \ + [get_bd_pins axi_interconnect_0/M01_ACLK] \ + [get_bd_pins axi_uart16550_0/s_axi_aclk] + connect_bd_net -net UART_ARESETN_1 [get_bd_ports UART_ARESETN] \ + [get_bd_pins axi_interconnect_0/M01_ARESETN] \ + [get_bd_pins axi_uart16550_0/s_axi_aresetn] } connect_bd_net -net axi_uart16550_0_ip2intc_irpt [get_bd_ports uart0_intc] [get_bd_pins axi_uart16550_0/ip2intc_irpt] connect_bd_net -net xlconstant_0_dout [get_bd_pins axi_uart16550_0/freeze] [get_bd_pins xlconstant_0/dout] diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 5dac8152..8082a6c6 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -86,8 +86,16 @@ experiments. `UVHS_EXPORT_IP_FORCE=1` regenerates cached Vivado and generalBus IP. `uvhs_clean` removes only the selected work directory and refuses to run while its runtime session is active. -XiangShan leaves all four B0 FPGAs available to the automatic partitioner; -the validated 70/35 result used F2 and F3. NutShell keeps the single F2 FPGA. +The default topology keeps B0/F0 for user DDR, B0/F1 for the physical +UV_FMCH_FLASH USB-UART, and B0/F2 for XDMA and the XiangShan fetch path. The +remaining logic is partitioned automatically. XiangShan uses the validated +fetch-path colocation together with high partition effort and the +`uv_placer_balance_slrs` PnR strategy. + +UVHS drives the AXI UART16550 from `clk6_p` at a fixed 50 MHz while `clk5_p` +remains the 25 MHz CPU/SoC clock. The runtime configures both clocks before +download. This matches the 50 MHz UART clock declared by the XiangShan FPGA +device tree and keeps UART baud timing independent of CPU clock gating. ## Runtime @@ -295,8 +303,9 @@ UVHS UHD path; the normal Vivado flow continues to use `make dump_ila` and a UHD capture inserts its own external DDR wrapper on every FPGA containing a probe group. The four PDDR4DME cards on the FPGA FMC3 connectors are reserved for UHD. The DUT DDR controller is constrained to B0/F0, which owns the separate -`pddr4dme_user_inst`; NutShell therefore keeps both B0/F0 and B0/F2. This avoids -sharing the B0/F2 UHD card between the DUT and waveform capture. +`pddr4dme_user_inst`. The default topology also keeps B0/F1 for the USB-UART +daughter card and B0/F2 for CPU/XDMA. This avoids sharing an UHD card with the +DUT DDR controller. ## Compatibility Boundary @@ -326,8 +335,8 @@ or DDR pins. | `compilation/frontend_run.tcl` | RTL/IP import, elaboration, and uvsyn frontend. | | `compilation/backend_run.tcl` | Fill-rate setup, partition, routing, PnR, and database commit. | | `compilation/topology.tcl` | Selects the FPGA set from the vendor board assembly. | -| `compilation/partition.tcl` | Places the DUT DDR controller on the user-DDR FPGA. | -| `compilation/assign_pin.tcl` | B0/F2 clock, PCIe, UART, JTAG, SD, and control pins. | +| `compilation/partition.tcl` | Places user DDR on B0/F0 and the XiangShan fetch path on B0/F2. | +| `compilation/assign_pin.tcl` | Physical UART daughter-card, clock, PCIe, JTAG, SD, and control pins. | | `compilation/timing.tcl` | External clock and asynchronous-group constraints. | | `compilation/vivado_pre_opt.tcl` | XDMA refclock and CDC constraints. | | `compilation/prepare_ip.sh` | Coordinates Vivado, generalBus, and external DDR IP preparation. | diff --git a/fpga_diff/uvhs/compilation/assign_pin.tcl b/fpga_diff/uvhs/compilation/assign_pin.tcl index 846d3a56..e7c98ec4 100644 --- a/fpga_diff/uvhs/compilation/assign_pin.tcl +++ b/fpga_diff/uvhs/compilation/assign_pin.tcl @@ -1,8 +1,8 @@ ################################################################################ # Pin assignment for fpga_diff on the U2.2 VU19P platform. # -# CPU, PCIe, and low-speed I/O use b0.f2. The user-DDR controller is bound to -# b0.f0 separately by partition.tcl. +# CPU, PCIe, and low-speed debug I/O use b0.f2. UART0 uses the USB-UART on the +# flash daughter card at b0.F1_FMC0. The user-DDR controller uses b0.f0. ################################################################################ proc pin_name {top port} { @@ -39,11 +39,11 @@ apc16_pin led2 4 # led3 is driven by the user-DDR calibration status on F0. assign_pin -port [pin_name $top led3] -connector b0.F0_FMC1 -index 311 -# UART0 defaults to the F2 APC16 sideband connector. A two-FPGA build can -# route it through the F1 UV_FMCH_FLASH USB-UART with FMC indices 311/270. -set uvhs_uart0_connector [uvhs::env_or_default UVHS_UART0_CONNECTOR b0.F2_APC16] -set uvhs_uart0_tx_index [uvhs::env_or_default UVHS_UART0_TX_INDEX [lindex $apc16_indices 6]] -set uvhs_uart0_rx_index [uvhs::env_or_default UVHS_UART0_RX_INDEX [lindex $apc16_indices 7]] +# UV_FMCH_FLASH drives USB_UART_RX at FMC[270] and receives USB_UART_TX at +# FMC[311], so the FPGA RX/TX directions map to 270/311 respectively. +set uvhs_uart0_connector b0.F1_FMC0 +set uvhs_uart0_tx_index 311 +set uvhs_uart0_rx_index 270 puts "INFO: UART0 pins: TX ${uvhs_uart0_connector}\[$uvhs_uart0_tx_index\], RX ${uvhs_uart0_connector}\[$uvhs_uart0_rx_index\]" assign_pin -port [pin_name $top uart0_sout] -connector $uvhs_uart0_connector -index $uvhs_uart0_tx_index assign_pin -port [pin_name $top uart0_sin] -connector $uvhs_uart0_connector -index $uvhs_uart0_rx_index diff --git a/fpga_diff/uvhs/compilation/backend_run.tcl b/fpga_diff/uvhs/compilation/backend_run.tcl index 2df276da..d38fcd59 100644 --- a/fpga_diff/uvhs/compilation/backend_run.tcl +++ b/fpga_diff/uvhs/compilation/backend_run.tcl @@ -106,7 +106,7 @@ report_resource -depth 4 report_system_resource list_partition_constraints -all partition_design -tdc -tdss true \ - -bs_max_blk_ratio 0.96 -bs_min_blk_ratio 0.005 + -bs_max_blk_ratio 0.96 -bs_min_blk_ratio 0.005 -effort high report_resource -depth 4 instrument_design @@ -126,7 +126,7 @@ save_runtime_data set_option compile.resourceUsageLimit 100 set_option compile.strategyNum 1 -set_option compile.strategy0 uv_high_fanout_explore +set_option compile.strategy0 uv_placer_balance_slrs set_option compile.stage.preOpt \ [uvhs::path vivado_pre_opt.tcl] diff --git a/fpga_diff/uvhs/compilation/partition.tcl b/fpga_diff/uvhs/compilation/partition.tcl index c42e29eb..0dabdc2d 100644 --- a/fpga_diff/uvhs/compilation/partition.tcl +++ b/fpga_diff/uvhs/compilation/partition.tcl @@ -17,3 +17,27 @@ if {$uvhs_bound_ddr_connector ne $uvhs_ddr_connector} { error "failed to constrain UVHS DUT DDR to $uvhs_ddr_connector" } puts "INFO: constrain UVHS DUT DDR to $uvhs_bound_ddr_connector" + +# Keep the XiangShan instruction-fetch path with XDMA and the physical UART +# endpoint. Other CPUs do not contain these hierarchy paths and stay automatic. +set uvhs_fetch_path_names { + core_def/U_CPU_TOP/u_XSTop/soc/core_with_l2 + core_def/U_CPU_TOP/u_XSTop/soc/nocMisc + core_def/U_CPU_TOP/u_XSTop/soc/tl2axi4 + core_def/CFG_AXI_bridge_i + core_def/U_UVHS_FLASH_GBUS +} +set uvhs_xiangshan_cell [get_cells -quiet {core_def/U_CPU_TOP/u_XSTop}] +if {[llength $uvhs_xiangshan_cell] == 1} { + set uvhs_fetch_path_cells [get_cells -quiet $uvhs_fetch_path_names] + if {[llength $uvhs_fetch_path_cells] != [llength $uvhs_fetch_path_names]} { + error "incomplete XiangShan fetch path: expected [llength $uvhs_fetch_path_names] cells, got [llength $uvhs_fetch_path_cells]" + } + create_fpga -name b0.f2 -cells $uvhs_fetch_path_cells + puts "INFO: constrain XiangShan fetch path to b0.f2: $uvhs_fetch_path_cells" +} elseif {[llength $uvhs_xiangshan_cell]} { + error "expected at most one XiangShan top cell, got [llength $uvhs_xiangshan_cell]" +} else { + puts "INFO: skip XiangShan fetch-path constraint for this CPU" +} +unset -nocomplain uvhs_fetch_path_names uvhs_fetch_path_cells uvhs_xiangshan_cell diff --git a/fpga_diff/uvhs/compilation/timing.tcl b/fpga_diff/uvhs/compilation/timing.tcl index 6085d266..649358a1 100644 --- a/fpga_diff/uvhs/compilation/timing.tcl +++ b/fpga_diff/uvhs/compilation/timing.tcl @@ -6,20 +6,29 @@ set fpga_diff_top fpga_top_debug proc fpga_diff_top_port {name} { - return "${::fpga_diff_top}.${name}" + set scoped_name "${::fpga_diff_top}.${name}" + if {[llength [get_ports -quiet $scoped_name]] == 1} { + return $scoped_name + } + return $name } create_clock -name TMCLK -period 1000 [get_ports [fpga_diff_top_port clk8_p]] create_clock -name ddr_ref_clk -period 12.5 [get_ports [fpga_diff_top_port clk7_p]] create_clock -name CPU_CLK_IN -period 40 [get_ports [fpga_diff_top_port clk5_p]] +create_clock -name UART_CLK_IN -period 20 [get_ports [fpga_diff_top_port clk6_p]] create_clock -name jtag_vclk -period 83.333 [get_ports [fpga_diff_top_port JTAG_TCK]] create_clock -name pcie_ep_refclk -period 10 [get_ports [fpga_diff_top_port pcie_ep_gt_ref_clk_p]] proc fpga_diff_set_async_clock_groups {} { set groups [list] - foreach clock {TMCLK ddr_ref_clk CPU_CLK_IN jtag_vclk pcie_ep_refclk} { + foreach clock {TMCLK ddr_ref_clk CPU_CLK_IN UART_CLK_IN jtag_vclk} { lappend groups -group [get_clocks -include_generated_clocks $clock] } + set pcie_clocks [concat \ + [get_clocks -include_generated_clocks pcie_ep_refclk] \ + [get_clocks -quiet XDMA_AXI_ACLK]] + lappend groups -group [lsort -unique $pcie_clocks] set_clock_groups -asynchronous {*}$groups } fpga_diff_set_async_clock_groups diff --git a/fpga_diff/uvhs/runtime/runtime_server.tcl b/fpga_diff/uvhs/runtime/runtime_server.tcl index cfb07b34..3db371f1 100644 --- a/fpga_diff/uvhs/runtime/runtime_server.tcl +++ b/fpga_diff/uvhs/runtime/runtime_server.tcl @@ -431,6 +431,7 @@ proc uvhs_initialize_runtime {} { config -clock -default } config -clock -name clk5_p -frequency 25000000 + config -clock -name clk6_p -frequency 50000000 config -clock -commit query -clock diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 951c54a3..d378fcf6 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -12,7 +12,7 @@ UVHS_FILELIST := $(UVHS_WORK_DIR)/rtl/filelist.f UVHS_EXPORT_IP_FORCE ?= 0 UVHS_EXPORT_IP_JOBS := $(if $(strip $(VIVADO_JOBS)),$(VIVADO_JOBS),8) -UVHS_KEEP_FPGAS ?= $(if $(filter kmh,$(CPU)),b0.f0 b0.f1 b0.f2 b0.f3,b0.f0 b0.f2) +UVHS_KEEP_FPGAS ?= b0.f0 b0.f1 b0.f2 UVHS_LUT_FILL_RATE ?= $(if $(filter kmh,$(CPU)),70,) UVHS_LUT6_FILL_RATE ?= $(if $(filter kmh,$(CPU)),35,) From 83cba23e6f2894c077cb6c7000aa943243e1942c Mon Sep 17 00:00:00 2001 From: klin02 Date: Fri, 7 Aug 2026 10:42:02 +0800 Subject: [PATCH 47/62] fix(fpga_diff): colocate UVHS memory and host paths --- fpga_diff/uvhs/README.md | 12 ++--- fpga_diff/uvhs/compilation/partition.tcl | 66 ++++++++++++++++-------- 2 files changed, 51 insertions(+), 27 deletions(-) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 8082a6c6..415792e0 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -86,11 +86,11 @@ experiments. `UVHS_EXPORT_IP_FORCE=1` regenerates cached Vivado and generalBus IP. `uvhs_clean` removes only the selected work directory and refuses to run while its runtime session is active. -The default topology keeps B0/F0 for user DDR, B0/F1 for the physical -UV_FMCH_FLASH USB-UART, and B0/F2 for XDMA and the XiangShan fetch path. The -remaining logic is partitioned automatically. XiangShan uses the validated -fetch-path colocation together with high partition effort and the -`uv_placer_balance_slrs` PnR strategy. +The default topology keeps the XiangShan CHI/CMN memory path with user DDR on +B0/F0, the physical UV_FMCH_FLASH USB-UART on B0/F1, and the core, DiffTest +endpoint, and XDMA host path on B0/F2. The remaining logic is partitioned +automatically. XiangShan uses these path constraints together with high +partition effort and the `uv_placer_balance_slrs` PnR strategy. UVHS drives the AXI UART16550 from `clk6_p` at a fixed 50 MHz while `clk5_p` remains the 25 MHz CPU/SoC clock. The runtime configures both clocks before @@ -335,7 +335,7 @@ or DDR pins. | `compilation/frontend_run.tcl` | RTL/IP import, elaboration, and uvsyn frontend. | | `compilation/backend_run.tcl` | Fill-rate setup, partition, routing, PnR, and database commit. | | `compilation/topology.tcl` | Selects the FPGA set from the vendor board assembly. | -| `compilation/partition.tcl` | Places user DDR on B0/F0 and the XiangShan fetch path on B0/F2. | +| `compilation/partition.tcl` | Places CHI/CMN and DDR on B0/F0, and the core/DiffTest/XDMA path on B0/F2. | | `compilation/assign_pin.tcl` | Physical UART daughter-card, clock, PCIe, JTAG, SD, and control pins. | | `compilation/timing.tcl` | External clock and asynchronous-group constraints. | | `compilation/vivado_pre_opt.tcl` | XDMA refclock and CDC constraints. | diff --git a/fpga_diff/uvhs/compilation/partition.tcl b/fpga_diff/uvhs/compilation/partition.tcl index 0dabdc2d..1ce8cd44 100644 --- a/fpga_diff/uvhs/compilation/partition.tcl +++ b/fpga_diff/uvhs/compilation/partition.tcl @@ -7,37 +7,61 @@ set uvhs_ddr_cell \ if {[llength $uvhs_ddr_cell] != 1} { error "expected one UVHS DUT DDR instance, got [llength $uvhs_ddr_cell]" } -create_fpga -name b0.f0 -cells $uvhs_ddr_cell -set uvhs_ddr_connector b0.F0_FMC0 -set_property -name connector -value $uvhs_ddr_connector \ - -objects $uvhs_ddr_cell -set uvhs_bound_ddr_connector \ - [get_property -name connector -objects $uvhs_ddr_cell] -if {$uvhs_bound_ddr_connector ne $uvhs_ddr_connector} { - error "failed to constrain UVHS DUT DDR to $uvhs_ddr_connector" -} -puts "INFO: constrain UVHS DUT DDR to $uvhs_bound_ddr_connector" -# Keep the XiangShan instruction-fetch path with XDMA and the physical UART -# endpoint. Other CPUs do not contain these hierarchy paths and stay automatic. -set uvhs_fetch_path_names { - core_def/U_CPU_TOP/u_XSTop/soc/core_with_l2 +# Keep the XiangShan memory path with the user DDR. Keep the core and DiffTest +# host path with XDMA. UART pins remain on the physical F1 daughter card. +set uvhs_f0_cells $uvhs_ddr_cell +set uvhs_memory_path_names { + core_def/U_CPU_TOP/u_XSTop/soc/chi_extllc_opt core_def/U_CPU_TOP/u_XSTop/soc/nocMisc core_def/U_CPU_TOP/u_XSTop/soc/tl2axi4 +} +set uvhs_host_path_names { + core_def/U_CPU_TOP/u_XSTop/soc/core_with_l2 + core_def/U_CPU_TOP/u_XSTop/endpoint + core_def/U_CPU_TOP/u_XSTop/difftest_cfg + core_def/U_CPU_TOP/u_XSTop/difftest_host + core_def/U_CPU_TOP/u_XSTop/difftest_memCtrl + core_def/xdma_ep_i core_def/CFG_AXI_bridge_i core_def/U_UVHS_FLASH_GBUS } set uvhs_xiangshan_cell [get_cells -quiet {core_def/U_CPU_TOP/u_XSTop}] if {[llength $uvhs_xiangshan_cell] == 1} { - set uvhs_fetch_path_cells [get_cells -quiet $uvhs_fetch_path_names] - if {[llength $uvhs_fetch_path_cells] != [llength $uvhs_fetch_path_names]} { - error "incomplete XiangShan fetch path: expected [llength $uvhs_fetch_path_names] cells, got [llength $uvhs_fetch_path_cells]" + set uvhs_memory_path_cells [get_cells -quiet $uvhs_memory_path_names] + if {[llength $uvhs_memory_path_cells] != [llength $uvhs_memory_path_names]} { + error [format "incomplete XiangShan memory path: expected %d cells, got %d" \ + [llength $uvhs_memory_path_names] \ + [llength $uvhs_memory_path_cells]] } - create_fpga -name b0.f2 -cells $uvhs_fetch_path_cells - puts "INFO: constrain XiangShan fetch path to b0.f2: $uvhs_fetch_path_cells" + set uvhs_host_path_cells [get_cells -quiet $uvhs_host_path_names] + if {[llength $uvhs_host_path_cells] != [llength $uvhs_host_path_names]} { + error [format "incomplete XiangShan host path: expected %d cells, got %d" \ + [llength $uvhs_host_path_names] \ + [llength $uvhs_host_path_cells]] + } + set uvhs_f0_cells [concat $uvhs_f0_cells $uvhs_memory_path_cells] + create_fpga -name b0.f2 -cells $uvhs_host_path_cells + puts "INFO: constrain XiangShan host path to b0.f2: $uvhs_host_path_cells" } elseif {[llength $uvhs_xiangshan_cell]} { error "expected at most one XiangShan top cell, got [llength $uvhs_xiangshan_cell]" } else { - puts "INFO: skip XiangShan fetch-path constraint for this CPU" + puts "INFO: skip XiangShan partition constraints for this CPU" +} +create_fpga -name b0.f0 -cells $uvhs_f0_cells +set uvhs_ddr_connector b0.F0_FMC0 +set_property -name connector -value $uvhs_ddr_connector \ + -objects $uvhs_ddr_cell +set uvhs_bound_ddr_connector \ + [get_property -name connector -objects $uvhs_ddr_cell] +if {$uvhs_bound_ddr_connector ne $uvhs_ddr_connector} { + error "failed to constrain UVHS DUT DDR to $uvhs_ddr_connector" +} +puts "INFO: constrain UVHS DUT DDR to $uvhs_bound_ddr_connector" +if {[info exists uvhs_memory_path_cells]} { + puts "INFO: constrain XiangShan memory path to b0.f0: $uvhs_memory_path_cells" } -unset -nocomplain uvhs_fetch_path_names uvhs_fetch_path_cells uvhs_xiangshan_cell +unset -nocomplain uvhs_ddr_cell uvhs_ddr_connector \ + uvhs_bound_ddr_connector uvhs_f0_cells uvhs_memory_path_names \ + uvhs_memory_path_cells uvhs_host_path_names uvhs_host_path_cells \ + uvhs_xiangshan_cell From 4d0b81f61c023a58a091c139112e7f9199a358a3 Mon Sep 17 00:00:00 2001 From: klin02 Date: Fri, 7 Aug 2026 16:54:05 +0800 Subject: [PATCH 48/62] fix(fpga_diff): constrain UVHS DDR reset CDC Exclude the asynchronous DDR reset path into the first-stage TDM synchronizer after UVHS partitioning. Co-authored-by: Kamimiao --- fpga_diff/uvhs/compilation/vivado_pre_opt.tcl | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl b/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl index 463fb204..fd90581a 100644 --- a/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl +++ b/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl @@ -87,3 +87,28 @@ foreach fpga_diff_clock {TMCLK ddr_ref_clk CPU_CLK_IN jtag_vclk pcie_ep_refclk} [get_clocks -include_generated_clocks $fpga_diff_clock] } set_clock_groups -asynchronous {*}$fpga_diff_async_groups + +# The DDR reset controller is clocked by the MIG MMCM. When partitioning puts +# its peripheral_aresetn consumer on another FPGA, UVHS inserts a TDM input +# synchronizer clocked by the GT TX clock. The MIG clock is not a DUT clock, so +# the generated DUT-to-TDM exceptions do not cover this reset-only crossing. +set fpga_diff_ddr_reset_q_pins [get_pins -hier -quiet -filter { + REF_PIN_NAME == Q && + NAME =~ */core_def/U_UVHS_UVW_AXI4_TO_DDR4/*/proc_sys_reset_0/U0/ACTIVE_LOW_PR_OUT_DFF*/Q +}] +if {[llength $fpga_diff_ddr_reset_q_pins]} { + set fpga_diff_tdm_tx_sync_d_pins [get_pins -hier -quiet -filter { + REF_PIN_NAME == D && + NAME =~ */uvtdm_tx_ctrl_inst/sync_flop_0_reg*/D + }] + if {![llength $fpga_diff_tdm_tx_sync_d_pins]} { + error "DDR reset sources found, but no TDM TX synchronizer inputs matched" + } + set_false_path -from $fpga_diff_ddr_reset_q_pins \ + -to $fpga_diff_tdm_tx_sync_d_pins + puts "INFO: constrained DDR reset-to-TDM CDC: \ + sources=[llength $fpga_diff_ddr_reset_q_pins] \ + destinations=[llength $fpga_diff_tdm_tx_sync_d_pins]" +} else { + puts "INFO: no DDR reset-to-TDM CDC sources on this FPGA" +} From 1a1b89ef86cb7ac4619bf4fdc7e4bc5b1f35122f Mon Sep 17 00:00:00 2001 From: klin02 Date: Fri, 7 Aug 2026 17:11:28 +0800 Subject: [PATCH 49/62] fix(fpga_diff): use valid CDC startpoints Constrain the DDR reset crossing from its sequential cells so Vivado accepts the post-link false path. Co-authored-by: Kamimiao --- fpga_diff/uvhs/compilation/vivado_pre_opt.tcl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl b/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl index fd90581a..79a715e1 100644 --- a/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl +++ b/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl @@ -92,11 +92,11 @@ set_clock_groups -asynchronous {*}$fpga_diff_async_groups # its peripheral_aresetn consumer on another FPGA, UVHS inserts a TDM input # synchronizer clocked by the GT TX clock. The MIG clock is not a DUT clock, so # the generated DUT-to-TDM exceptions do not cover this reset-only crossing. -set fpga_diff_ddr_reset_q_pins [get_pins -hier -quiet -filter { - REF_PIN_NAME == Q && - NAME =~ */core_def/U_UVHS_UVW_AXI4_TO_DDR4/*/proc_sys_reset_0/U0/ACTIVE_LOW_PR_OUT_DFF*/Q +set fpga_diff_ddr_reset_regs [get_cells -hier -quiet -filter { + IS_SEQUENTIAL && + NAME =~ */core_def/U_UVHS_UVW_AXI4_TO_DDR4/*/proc_sys_reset_0/U0/ACTIVE_LOW_PR_OUT_DFF* }] -if {[llength $fpga_diff_ddr_reset_q_pins]} { +if {[llength $fpga_diff_ddr_reset_regs]} { set fpga_diff_tdm_tx_sync_d_pins [get_pins -hier -quiet -filter { REF_PIN_NAME == D && NAME =~ */uvtdm_tx_ctrl_inst/sync_flop_0_reg*/D @@ -104,10 +104,10 @@ if {[llength $fpga_diff_ddr_reset_q_pins]} { if {![llength $fpga_diff_tdm_tx_sync_d_pins]} { error "DDR reset sources found, but no TDM TX synchronizer inputs matched" } - set_false_path -from $fpga_diff_ddr_reset_q_pins \ + set_false_path -from $fpga_diff_ddr_reset_regs \ -to $fpga_diff_tdm_tx_sync_d_pins puts "INFO: constrained DDR reset-to-TDM CDC: \ - sources=[llength $fpga_diff_ddr_reset_q_pins] \ + sources=[llength $fpga_diff_ddr_reset_regs] \ destinations=[llength $fpga_diff_tdm_tx_sync_d_pins]" } else { puts "INFO: no DDR reset-to-TDM CDC sources on this FPGA" From 4b606041cd3c5e4a31e7f9c33d651f3a9abea1ba Mon Sep 17 00:00:00 2001 From: klin02 Date: Sat, 8 Aug 2026 00:13:18 +0800 Subject: [PATCH 50/62] fix(fpga_diff): normalize UVHS signoff constraints Translate the generated DDR clock alias and Vivado reset-path syntax before the UVHS timing worker reads the signoff UDC. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 12 ++- fpga_diff/uvhs/compilation/shell_compat.sh | 119 ++++++++++++++++++++- 2 files changed, 124 insertions(+), 7 deletions(-) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 415792e0..67801e94 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -311,8 +311,9 @@ DUT DDR controller. The retained compatibility code is limited to observed tool behavior: -- `shell_compat.sh` selects Bash in generated synthesis and PnR launchers that - contain Bash syntax. +- `shell_compat.sh` selects Bash in generated synthesis and PnR launchers and + translates the observed Vivado-to-UVHS signoff differences for the DDR UI + clock alias and multicycle reset syntax. - `uv_shell_exec_compat.sh` prepares the required libffi/libpcre compatibility links and restores runtime libraries after the vendor launcher sanitizes `LD_LIBRARY_PATH`. @@ -321,8 +322,9 @@ The retained compatibility code is limited to observed tool behavior: - `vivado_pre_opt.tcl` preserves the XDMA GT reference clock and marks the validated XDMA CDC registers. -The flow does not patch generated timing XDC, hierarchy names, VIO/ILA logic, -or DDR pins. +The flow does not patch user timing constraints, hierarchy names, VIO/ILA +logic, or DDR pins. The generated signoff UDC is normalized only immediately +before the UVHS timing worker reads it. ## Files @@ -341,7 +343,7 @@ or DDR pins. | `compilation/vivado_pre_opt.tcl` | XDMA refclock and CDC constraints. | | `compilation/prepare_ip.sh` | Coordinates Vivado, generalBus, and external DDR IP preparation. | | `compilation/export_vivado_ip.tcl` | Runs repository-owned XCI/BD exports inside Vivado. | -| `compilation/shell_compat.sh` | Generated launcher shell correction. | +| `compilation/shell_compat.sh` | Generated launcher and signoff-constraint compatibility. | | `runtime/uv_shell_exec_compat.sh` | Runtime library wrapper for UVHS shells and generated Python workers. | | `runtime/runtime_server.tcl` | Download, reset, DDR, flash, capture, and command service. | | `runtime/runtime_session.sh` | Process lifecycle and atomic command/result transport. | diff --git a/fpga_diff/uvhs/compilation/shell_compat.sh b/fpga_diff/uvhs/compilation/shell_compat.sh index 754676d8..bfbf1c87 100755 --- a/fpga_diff/uvhs/compilation/shell_compat.sh +++ b/fpga_diff/uvhs/compilation/shell_compat.sh @@ -2,7 +2,7 @@ set -euo pipefail usage() { - echo "Usage: $0 wait-module MODULE_MAKEFILE | patch-pnr PNR_DIR" >&2 + echo "Usage: $0 wait-module MODULE_MAKEFILE | patch-pnr PNR_DIR | patch-signoff SIGNOFF_DIR" >&2 exit 2 } @@ -18,6 +18,108 @@ patch_makefile() { "$makefile" } +patch_signoff_worker() { + local worker=$1 + local helper=$2 + local marker='# fpga_diff UVHS signoff compatibility' + local temporary="${worker}.fpga-diff.$$" + + if grep -Fxq "$marker" "$worker"; then + return + fi + if ! awk -v marker="$marker" -v helper="$helper" ' + $0 == "if {[file exists $dumpPath/cstr.tcl]} {" { + print marker + print "exec bash {" helper "} patch-signoff $dumpPath" + inserted++ + } + { print } + END { if (inserted != 1) exit 1 } + ' "$worker" > "$temporary"; then + rm -f "$temporary" + echo "ERROR: unsupported generated signoff worker: $worker" >&2 + exit 1 + fi + chmod --reference="$worker" "$temporary" + mv "$temporary" "$worker" +} + +patch_signoff_constraints() { + local signoff_dir=$1 + local udc="$signoff_dir/cstr/FPGA_filtered.udc" + local clock_map="$signoff_dir/cstr.tcl" + local alias_count + local supported_alias_count + local identity_map_count + local mapped_count + local mmcm_count + local reset_count + local multiplier_count_before + local multiplier_count_after + + [[ -f $udc && -f $clock_map ]] || { + echo "ERROR: signoff constraints not found under $signoff_dir" >&2 + exit 1 + } + + alias_count=$(grep -c '^create_generated_clock -name DDR_UI_CLK ' "$udc" || true) + supported_alias_count=$(grep -cE \ + '^create_generated_clock -name DDR_UI_CLK .* -master_clock \[get_clocks mmcm_clkout0\] \[get_pins .*/ddr4ip_ddr4_user_clk\]$' \ + "$udc" || true) + identity_map_count=$(grep -cF '{DDR_UI_CLK DDR_UI_CLK}' "$clock_map" || true) + mapped_count=$(grep -cF '{DDR_UI_CLK mmcm_clkout0}' "$clock_map" || true) + mmcm_count=$(grep -c '^create_generated_clock -name mmcm_clkout0 ' "$udc" || true) + + ((alias_count <= 1 && identity_map_count <= 1 && mapped_count <= 1 && + identity_map_count + mapped_count <= 1)) || { + echo "ERROR: ambiguous DDR signoff clock constraints in $signoff_dir" >&2 + exit 1 + } + ((alias_count == supported_alias_count)) || { + echo "ERROR: unsupported DDR signoff clock alias in $udc" >&2 + exit 1 + } + if ((alias_count == 1)); then + ((identity_map_count == 1 && mapped_count == 0 && mmcm_count == 1)) || { + echo "ERROR: DDR signoff clock mapping has no unique MIG MMCM clock" >&2 + exit 1 + } + sed -i 's/{DDR_UI_CLK DDR_UI_CLK}/{DDR_UI_CLK mmcm_clkout0}/' \ + "$clock_map" + sed -i '/^create_generated_clock -name DDR_UI_CLK .*\/ddr4ip_ddr4_user_clk]$/d' \ + "$udc" + fi + + reset_count=$(awk ' + /^set_multicycle_path / && / -reset_path / { count++ } + END { print count + 0 } + ' "$udc") + multiplier_count_before=$(grep -c ' -path_multiplier ' "$udc" || true) + if ((reset_count > 0)); then + sed -E -i ' + /^set_multicycle_path .* -reset_path .* [0-9]+$/ { + s/ -reset_path// + s/ ([0-9]+)$/ -path_multiplier \1/ + } + ' "$udc" + fi + multiplier_count_after=$(grep -c ' -path_multiplier ' "$udc" || true) + + ! grep -q '^create_generated_clock -name DDR_UI_CLK ' "$udc" || { + echo "ERROR: failed to remove DDR signoff clock alias" >&2 + exit 1 + } + ! grep -q '^set_multicycle_path .* -reset_path ' "$udc" || { + echo "ERROR: failed to translate Vivado reset-path constraints" >&2 + exit 1 + } + ((multiplier_count_after == multiplier_count_before + reset_count)) || { + echo "ERROR: incomplete multicycle-path translation in $udc" >&2 + exit 1 + } + echo "INFO: normalized UVHS signoff constraints: DDR aliases=$alias_count, reset paths=$reset_count" +} + wait_for_module_makefile() { local module_makefile=$1 @@ -40,8 +142,12 @@ wait_for_module_makefile() { patch_pnr_scripts() { local pnr_dir=$1 + local helper local wrapper_count=0 local makefile_count=0 + local worker_count=0 + + helper=$(realpath "$0") [[ -d $pnr_dir ]] || { echo "ERROR: PnR script directory not found: $pnr_dir" >&2 @@ -60,6 +166,10 @@ patch_pnr_scripts() { patch_makefile "$makefile" ((makefile_count += 1)) done < <(find "$pnr_dir" -type f -name Makefile -print0) + while IFS= read -r -d '' worker; do + patch_signoff_worker "$worker" "$helper" + ((worker_count += 1)) + done < <(find "$pnr_dir" -type f -name signoff_worker.tcl -print0) ((wrapper_count > 0)) || { echo "ERROR: no generated Vivado wrapper found under $pnr_dir" >&2 @@ -69,12 +179,17 @@ patch_pnr_scripts() { echo "ERROR: no generated PnR Makefile found under $pnr_dir" >&2 exit 1 } - echo "INFO: selected Bash in $wrapper_count wrappers and $makefile_count PnR Makefiles" + ((worker_count > 0)) || { + echo "ERROR: no generated signoff worker found under $pnr_dir" >&2 + exit 1 + } + echo "INFO: selected Bash in $wrapper_count wrappers and $makefile_count PnR Makefiles; patched $worker_count signoff workers" } [[ $# -eq 2 ]] || usage case $1 in wait-module) wait_for_module_makefile "$2" ;; patch-pnr) patch_pnr_scripts "$2" ;; + patch-signoff) patch_signoff_constraints "$2" ;; *) usage ;; esac From 9500cf6cd76edaddbab565c45e9842bb34b36cee Mon Sep 17 00:00:00 2001 From: klin02 Date: Sat, 8 Aug 2026 19:51:30 +0800 Subject: [PATCH 51/62] fix(fpga_diff): colocate UVHS memory adapters --- fpga_diff/uvhs/compilation/partition.tcl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fpga_diff/uvhs/compilation/partition.tcl b/fpga_diff/uvhs/compilation/partition.tcl index 1ce8cd44..0d78692b 100644 --- a/fpga_diff/uvhs/compilation/partition.tcl +++ b/fpga_diff/uvhs/compilation/partition.tcl @@ -14,7 +14,11 @@ set uvhs_f0_cells $uvhs_ddr_cell set uvhs_memory_path_names { core_def/U_CPU_TOP/u_XSTop/soc/chi_extllc_opt core_def/U_CPU_TOP/u_XSTop/soc/nocMisc + core_def/U_CPU_TOP/u_XSTop/soc/widget + core_def/U_CPU_TOP/u_XSTop/soc/fragmenter core_def/U_CPU_TOP/u_XSTop/soc/tl2axi4 + core_def/U_CPU_TOP/u_XSTop/soc/axi4yank + core_def/U_CPU_TOP/u_XSTop/soc/axi4buf } set uvhs_host_path_names { core_def/U_CPU_TOP/u_XSTop/soc/core_with_l2 From 00b4e0fc43e158ef2682be739fec770ed4db2db1 Mon Sep 17 00:00:00 2001 From: klin02 Date: Sun, 9 Aug 2026 12:44:06 +0800 Subject: [PATCH 52/62] fix(fpga_diff): use UVHS signoff clock Keep the CPU and SoC clock at the system signoff frequency stored in the selected runtime database instead of overriding every partition result with 25 MHz. Retain the fixed 50 MHz UART clock required by the device tree. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 10 ++++++---- fpga_diff/uvhs/runtime/runtime_server.tcl | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 67801e94..95783afa 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -92,10 +92,12 @@ endpoint, and XDMA host path on B0/F2. The remaining logic is partitioned automatically. XiangShan uses these path constraints together with high partition effort and the `uv_placer_balance_slrs` PnR strategy. -UVHS drives the AXI UART16550 from `clk6_p` at a fixed 50 MHz while `clk5_p` -remains the 25 MHz CPU/SoC clock. The runtime configures both clocks before -download. This matches the 50 MHz UART clock declared by the XiangShan FPGA -device tree and keeps UART baud timing independent of CPU clock gating. +UVHS drives the AXI UART16550 from `clk6_p` at a fixed 50 MHz. The CPU/SoC +`clk5_p` frequency comes from the system sign-off result committed in the +selected runtime database, so each partition and PnR result runs at its own +reported frequency. The fixed UART clock matches the 50 MHz clock declared by +the XiangShan FPGA device tree and keeps UART baud timing independent of CPU +clock gating. ## Runtime diff --git a/fpga_diff/uvhs/runtime/runtime_server.tcl b/fpga_diff/uvhs/runtime/runtime_server.tcl index 3db371f1..5d01f042 100644 --- a/fpga_diff/uvhs/runtime/runtime_server.tcl +++ b/fpga_diff/uvhs/runtime/runtime_server.tcl @@ -430,7 +430,8 @@ proc uvhs_initialize_runtime {} { } else { config -clock -default } - config -clock -name clk5_p -frequency 25000000 + # Keep clk5_p at the system sign-off frequency committed in this runtime DB. + # It varies with the partition and PnR result, so it must not be hard-coded. config -clock -name clk6_p -frequency 50000000 config -clock -commit query -clock From dca66ac85865f74b21937b7067ff70b668262f2a Mon Sep 17 00:00:00 2001 From: klin02 Date: Sun, 9 Aug 2026 15:54:50 +0800 Subject: [PATCH 53/62] fix(fpga_diff): route UVHS clock enable at x1 --- fpga_diff/uvhs/compilation/partition.tcl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fpga_diff/uvhs/compilation/partition.tcl b/fpga_diff/uvhs/compilation/partition.tcl index 0d78692b..0c86110b 100644 --- a/fpga_diff/uvhs/compilation/partition.tcl +++ b/fpga_diff/uvhs/compilation/partition.tcl @@ -65,7 +65,16 @@ puts "INFO: constrain UVHS DUT DDR to $uvhs_bound_ddr_connector" if {[info exists uvhs_memory_path_cells]} { puts "INFO: constrain XiangShan memory path to b0.f0: $uvhs_memory_path_cells" } +if {[llength $uvhs_xiangshan_cell] == 1} { + set uvhs_clock_enable_net \ + [get_nets -quiet {core_def/difftest_clock_gate_enable}] + if {[llength $uvhs_clock_enable_net] != 1} { + error "expected one DiffTest clock-enable net, got [llength $uvhs_clock_enable_net]" + } + assign_route -signals $uvhs_clock_enable_net -path {b0.f2 b0.f0} + puts "INFO: constrain DiffTest clock enable to direct b0.f2-b0.f0 route" +} unset -nocomplain uvhs_ddr_cell uvhs_ddr_connector \ uvhs_bound_ddr_connector uvhs_f0_cells uvhs_memory_path_names \ uvhs_memory_path_cells uvhs_host_path_names uvhs_host_path_cells \ - uvhs_xiangshan_cell + uvhs_xiangshan_cell uvhs_clock_enable_net From 6dd1aa5d78e5a363eb83ac6c32bc9ab7483ec28e Mon Sep 17 00:00:00 2001 From: klin02 Date: Sun, 9 Aug 2026 19:37:58 +0800 Subject: [PATCH 54/62] fix(fpga_diff): colocate UVHS IMSIC bridge Keep the AXI-side IMSIC fan-in with APLIC and CMN on F0 so only the narrow MSI request and acknowledgement interface crosses to the core on F2. Co-authored-by: Kamimiao --- fpga_diff/uvhs/compilation/partition.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/fpga_diff/uvhs/compilation/partition.tcl b/fpga_diff/uvhs/compilation/partition.tcl index 0c86110b..6b1d7a86 100644 --- a/fpga_diff/uvhs/compilation/partition.tcl +++ b/fpga_diff/uvhs/compilation/partition.tcl @@ -14,6 +14,7 @@ set uvhs_f0_cells $uvhs_ddr_cell set uvhs_memory_path_names { core_def/U_CPU_TOP/u_XSTop/soc/chi_extllc_opt core_def/U_CPU_TOP/u_XSTop/soc/nocMisc + core_def/U_CPU_TOP/u_XSTop/soc/imsic_bus_tops core_def/U_CPU_TOP/u_XSTop/soc/widget core_def/U_CPU_TOP/u_XSTop/soc/fragmenter core_def/U_CPU_TOP/u_XSTop/soc/tl2axi4 From 224e25c4059625e7893dada562396329e1bf4c9d Mon Sep 17 00:00:00 2001 From: klin02 Date: Sun, 9 Aug 2026 19:38:08 +0800 Subject: [PATCH 55/62] refactor(fpga_diff): name UVHS board assembly Rename the FPGA-selection helper to match the vendor assembly terminology and update both compilation stages and documentation. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 2 +- fpga_diff/uvhs/compilation/{topology.tcl => assemble.tcl} | 2 +- fpga_diff/uvhs/compilation/backend_run.tcl | 2 +- fpga_diff/uvhs/compilation/frontend_run.tcl | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename fpga_diff/uvhs/compilation/{topology.tcl => assemble.tcl} (98%) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 95783afa..0e2b33db 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -338,7 +338,7 @@ before the UVHS timing worker reads it. | `compilation/flow_common.tcl` | Shared UVHS path, environment, and source helpers. | | `compilation/frontend_run.tcl` | RTL/IP import, elaboration, and uvsyn frontend. | | `compilation/backend_run.tcl` | Fill-rate setup, partition, routing, PnR, and database commit. | -| `compilation/topology.tcl` | Selects the FPGA set from the vendor board assembly. | +| `compilation/assemble.tcl` | Assembles the FPGA set from the vendor board description. | | `compilation/partition.tcl` | Places CHI/CMN and DDR on B0/F0, and the core/DiffTest/XDMA path on B0/F2. | | `compilation/assign_pin.tcl` | Physical UART daughter-card, clock, PCIe, JTAG, SD, and control pins. | | `compilation/timing.tcl` | External clock and asynchronous-group constraints. | diff --git a/fpga_diff/uvhs/compilation/topology.tcl b/fpga_diff/uvhs/compilation/assemble.tcl similarity index 98% rename from fpga_diff/uvhs/compilation/topology.tcl rename to fpga_diff/uvhs/compilation/assemble.tcl index ee84d584..28ad8c87 100644 --- a/fpga_diff/uvhs/compilation/topology.tcl +++ b/fpga_diff/uvhs/compilation/assemble.tcl @@ -1,5 +1,5 @@ ################################################################################ -# Select the active FPGA topology from the vendor four-FPGA board template. +# Assemble the active FPGA set from the vendor four-FPGA board template. ################################################################################ set uvhs_base_assemble ./script/1B_4F_HGC_assemble.tcl diff --git a/fpga_diff/uvhs/compilation/backend_run.tcl b/fpga_diff/uvhs/compilation/backend_run.tcl index d38fcd59..70a9e2a9 100644 --- a/fpga_diff/uvhs/compilation/backend_run.tcl +++ b/fpga_diff/uvhs/compilation/backend_run.tcl @@ -18,7 +18,7 @@ set_option time.enable_sign_off true set_option time.incremental_sign_off true create_system_design -name VU19P_X4 -platform U2.2 -uvhs::source_required topology.tcl +uvhs::source_required assemble.tcl set ::env(UVHS_ASSIGN_PIN_TOP) none uvhs::source_required assign_pin.tcl diff --git a/fpga_diff/uvhs/compilation/frontend_run.tcl b/fpga_diff/uvhs/compilation/frontend_run.tcl index 190b221b..2a5d01ee 100644 --- a/fpga_diff/uvhs/compilation/frontend_run.tcl +++ b/fpga_diff/uvhs/compilation/frontend_run.tcl @@ -93,7 +93,7 @@ set design_top fpga_top_debug set ddr_inst_path ${design_top}.core_def.U_UVHS_UVW_AXI4_TO_DDR4 create_system_design -name VU19P_X4 -platform U2.2 -uvhs::source_required topology.tcl +uvhs::source_required assemble.tcl uvhs::source_required assign_pin.tcl set probe_script [uvhs::env_or_default UVHS_PROBE_TCL ""] if {$probe_script ne ""} { From b8bc3fd74605ad9156cc60feacc9dde9c8c1d400 Mon Sep 17 00:00:00 2001 From: klin02 Date: Sun, 9 Aug 2026 20:13:29 +0800 Subject: [PATCH 56/62] fix(fpga_diff): colocate UVHS configuration path Keep the CPU configuration bridge, runtime flash interface, syscfg, and boot ROM with nocMisc on F0 to remove the redundant F0-F2 AXI round trip. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 9 ++++---- fpga_diff/uvhs/compilation/partition.tcl | 26 ++++++++++++++++++------ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 0e2b33db..ea67b776 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -86,9 +86,10 @@ experiments. `UVHS_EXPORT_IP_FORCE=1` regenerates cached Vivado and generalBus IP. `uvhs_clean` removes only the selected work directory and refuses to run while its runtime session is active. -The default topology keeps the XiangShan CHI/CMN memory path with user DDR on -B0/F0, the physical UV_FMCH_FLASH USB-UART on B0/F1, and the core, DiffTest -endpoint, and XDMA host path on B0/F2. The remaining logic is partitioned +The default topology keeps the XiangShan CHI/CMN memory path, configuration +bridge, runtime flash interface, syscfg, and boot ROM with user DDR on B0/F0. +The physical UV_FMCH_FLASH USB-UART remains on B0/F1, while the core, DiffTest +endpoint, and XDMA host path stay on B0/F2. The remaining logic is partitioned automatically. XiangShan uses these path constraints together with high partition effort and the `uv_placer_balance_slrs` PnR strategy. @@ -339,7 +340,7 @@ before the UVHS timing worker reads it. | `compilation/frontend_run.tcl` | RTL/IP import, elaboration, and uvsyn frontend. | | `compilation/backend_run.tcl` | Fill-rate setup, partition, routing, PnR, and database commit. | | `compilation/assemble.tcl` | Assembles the FPGA set from the vendor board description. | -| `compilation/partition.tcl` | Places CHI/CMN and DDR on B0/F0, and the core/DiffTest/XDMA path on B0/F2. | +| `compilation/partition.tcl` | Places memory/configuration on B0/F0 and the core/DiffTest/XDMA path on B0/F2. | | `compilation/assign_pin.tcl` | Physical UART daughter-card, clock, PCIe, JTAG, SD, and control pins. | | `compilation/timing.tcl` | External clock and asynchronous-group constraints. | | `compilation/vivado_pre_opt.tcl` | XDMA refclock and CDC constraints. | diff --git a/fpga_diff/uvhs/compilation/partition.tcl b/fpga_diff/uvhs/compilation/partition.tcl index 6b1d7a86..a586f117 100644 --- a/fpga_diff/uvhs/compilation/partition.tcl +++ b/fpga_diff/uvhs/compilation/partition.tcl @@ -8,8 +8,9 @@ if {[llength $uvhs_ddr_cell] != 1} { error "expected one UVHS DUT DDR instance, got [llength $uvhs_ddr_cell]" } -# Keep the XiangShan memory path with the user DDR. Keep the core and DiffTest -# host path with XDMA. UART pins remain on the physical F1 daughter card. +# Keep the XiangShan memory and configuration paths with the user DDR. Keep the +# core and DiffTest host path with XDMA. UART pins remain on the physical F1 +# daughter card. set uvhs_f0_cells $uvhs_ddr_cell set uvhs_memory_path_names { core_def/U_CPU_TOP/u_XSTop/soc/chi_extllc_opt @@ -21,6 +22,12 @@ set uvhs_memory_path_names { core_def/U_CPU_TOP/u_XSTop/soc/axi4yank core_def/U_CPU_TOP/u_XSTop/soc/axi4buf } +set uvhs_config_path_names { + core_def/CFG_AXI_bridge_i + core_def/U_UVHS_FLASH_GBUS + core_def/U_SYS_CFG + core_def/u_rom +} set uvhs_host_path_names { core_def/U_CPU_TOP/u_XSTop/soc/core_with_l2 core_def/U_CPU_TOP/u_XSTop/endpoint @@ -28,8 +35,6 @@ set uvhs_host_path_names { core_def/U_CPU_TOP/u_XSTop/difftest_host core_def/U_CPU_TOP/u_XSTop/difftest_memCtrl core_def/xdma_ep_i - core_def/CFG_AXI_bridge_i - core_def/U_UVHS_FLASH_GBUS } set uvhs_xiangshan_cell [get_cells -quiet {core_def/U_CPU_TOP/u_XSTop}] if {[llength $uvhs_xiangshan_cell] == 1} { @@ -39,13 +44,20 @@ if {[llength $uvhs_xiangshan_cell] == 1} { [llength $uvhs_memory_path_names] \ [llength $uvhs_memory_path_cells]] } + set uvhs_config_path_cells [get_cells -quiet $uvhs_config_path_names] + if {[llength $uvhs_config_path_cells] != [llength $uvhs_config_path_names]} { + error [format "incomplete XiangShan configuration path: expected %d cells, got %d" \ + [llength $uvhs_config_path_names] \ + [llength $uvhs_config_path_cells]] + } set uvhs_host_path_cells [get_cells -quiet $uvhs_host_path_names] if {[llength $uvhs_host_path_cells] != [llength $uvhs_host_path_names]} { error [format "incomplete XiangShan host path: expected %d cells, got %d" \ [llength $uvhs_host_path_names] \ [llength $uvhs_host_path_cells]] } - set uvhs_f0_cells [concat $uvhs_f0_cells $uvhs_memory_path_cells] + set uvhs_f0_cells [concat $uvhs_f0_cells $uvhs_memory_path_cells \ + $uvhs_config_path_cells] create_fpga -name b0.f2 -cells $uvhs_host_path_cells puts "INFO: constrain XiangShan host path to b0.f2: $uvhs_host_path_cells" } elseif {[llength $uvhs_xiangshan_cell]} { @@ -65,6 +77,7 @@ if {$uvhs_bound_ddr_connector ne $uvhs_ddr_connector} { puts "INFO: constrain UVHS DUT DDR to $uvhs_bound_ddr_connector" if {[info exists uvhs_memory_path_cells]} { puts "INFO: constrain XiangShan memory path to b0.f0: $uvhs_memory_path_cells" + puts "INFO: constrain XiangShan configuration path to b0.f0: $uvhs_config_path_cells" } if {[llength $uvhs_xiangshan_cell] == 1} { set uvhs_clock_enable_net \ @@ -77,5 +90,6 @@ if {[llength $uvhs_xiangshan_cell] == 1} { } unset -nocomplain uvhs_ddr_cell uvhs_ddr_connector \ uvhs_bound_ddr_connector uvhs_f0_cells uvhs_memory_path_names \ - uvhs_memory_path_cells uvhs_host_path_names uvhs_host_path_cells \ + uvhs_memory_path_cells uvhs_config_path_names uvhs_config_path_cells \ + uvhs_host_path_names uvhs_host_path_cells \ uvhs_xiangshan_cell uvhs_clock_enable_net From 1577e48dc15a0d1db642c7638aeb0c5d5e659d3e Mon Sep 17 00:00:00 2001 From: klin02 Date: Sun, 9 Aug 2026 20:37:12 +0800 Subject: [PATCH 57/62] feat(fpga_diff): retain UVHS host trigger Keep the XDMA host trigger in the default UHD probe group so host-controlled capture remains available without a build-specific probe file. Document that external probe overrides must preserve it.\n\nCo-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 13 +++++++------ fpga_diff/uvhs/compilation/probe_ila.tcl | 7 +++++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index ea67b776..7aa938c1 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -155,12 +155,13 @@ from the server's global Tcl scope. ## UVHS ILA Waveform Capture The reference probe scripts describe compile-time instrumentation, not a -runtime dump. The frontend sources `compilation/probe_ila.tcl` by default. Its -template is inactive while the clock and signal lists are empty. Fill the -clock path and the probe/trigger path lists to enable it; the braces preserve -hierarchy indexes such as `[0]`. Set `UVHS_PROBE_TCL` to use another file -instead. The template calls `probe_net` for sampled signals and `trigger_net` -for signals that may participate in a trigger condition. Fill it as follows: +runtime dump. The frontend sources `compilation/probe_ila.tcl` by default. It +always samples the XDMA host trigger on `core_def.sys_clk_i`; add temporary +design-specific paths to its probe and trigger lists as needed. The braces +preserve hierarchy indexes such as `[0]`. Set `UVHS_PROBE_TCL` to use another +file instead; an override must retain the XDMA host trigger if host-controlled +capture is required. The template calls `probe_net` for sampled signals and +`trigger_net` for signals that may participate in a trigger condition. ```tcl set uvhs_ila_clock_path [string trim { diff --git a/fpga_diff/uvhs/compilation/probe_ila.tcl b/fpga_diff/uvhs/compilation/probe_ila.tcl index f90317a0..1ba4ac40 100644 --- a/fpga_diff/uvhs/compilation/probe_ila.tcl +++ b/fpga_diff/uvhs/compilation/probe_ila.tcl @@ -1,15 +1,18 @@ -# Fill only the RTL paths below. Braces preserve hierarchy indexes such as [0]. -# Leave the clock and signal lists empty to build without UHD instrumentation. +# The XDMA host trigger is always available. Add temporary design-specific +# paths below when a build needs more probes or trigger sources. set uvhs_ila_group_name uvhs_ila # Sampling clock path for this probe/trigger group. Prefer the ungated parent # clock so post-trigger samples can complete after the DUT clock stops. set uvhs_ila_clock_path [string trim { + fpga_top_debug.core_def.sys_clk_i }] # Probe signal paths, one per line. set uvhs_ila_probe_paths { + fpga_top_debug.core_def.io_host_ila_trigger } # Trigger signal paths, one per line. set uvhs_ila_trigger_paths { + fpga_top_debug.core_def.io_host_ila_trigger } if {$uvhs_ila_clock_path eq ""} { From 8ff41f05c0bc447afbaffe34b2fa0cf91013b0c8 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 10 Aug 2026 01:48:38 +0800 Subject: [PATCH 58/62] fix(fpga_diff): scope UVHS DDR reset CDC Only constrain TDM synchronizer inputs reached by the local DDR reset source. Some FPGA partitions contain the DDR reset source without a TDM endpoint, which should not abort pre-opt. Co-authored-by: Kamimiao --- fpga_diff/uvhs/compilation/vivado_pre_opt.tcl | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl b/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl index 79a715e1..ed393692 100644 --- a/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl +++ b/fpga_diff/uvhs/compilation/vivado_pre_opt.tcl @@ -97,18 +97,29 @@ set fpga_diff_ddr_reset_regs [get_cells -hier -quiet -filter { NAME =~ */core_def/U_UVHS_UVW_AXI4_TO_DDR4/*/proc_sys_reset_0/U0/ACTIVE_LOW_PR_OUT_DFF* }] if {[llength $fpga_diff_ddr_reset_regs]} { - set fpga_diff_tdm_tx_sync_d_pins [get_pins -hier -quiet -filter { + set fpga_diff_tdm_tx_sync_candidates [get_pins -hier -quiet -filter { REF_PIN_NAME == D && NAME =~ */uvtdm_tx_ctrl_inst/sync_flop_0_reg*/D }] - if {![llength $fpga_diff_tdm_tx_sync_d_pins]} { - error "DDR reset sources found, but no TDM TX synchronizer inputs matched" + set fpga_diff_tdm_tx_sync_d_pins {} + if {[llength $fpga_diff_tdm_tx_sync_candidates]} { + set fpga_diff_ddr_reset_endpoints \ + [all_fanout -flat -endpoints_only -from $fpga_diff_ddr_reset_regs] + foreach fpga_diff_pin $fpga_diff_tdm_tx_sync_candidates { + if {[lsearch -exact $fpga_diff_ddr_reset_endpoints $fpga_diff_pin] >= 0} { + lappend fpga_diff_tdm_tx_sync_d_pins $fpga_diff_pin + } + } + } + if {[llength $fpga_diff_tdm_tx_sync_d_pins]} { + set_false_path -from $fpga_diff_ddr_reset_regs \ + -to $fpga_diff_tdm_tx_sync_d_pins + puts "INFO: constrained DDR reset-to-TDM CDC: \ + sources=[llength $fpga_diff_ddr_reset_regs] \ + destinations=[llength $fpga_diff_tdm_tx_sync_d_pins]" + } else { + puts "INFO: no DDR reset-to-TDM CDC endpoints on this FPGA" } - set_false_path -from $fpga_diff_ddr_reset_regs \ - -to $fpga_diff_tdm_tx_sync_d_pins - puts "INFO: constrained DDR reset-to-TDM CDC: \ - sources=[llength $fpga_diff_ddr_reset_regs] \ - destinations=[llength $fpga_diff_tdm_tx_sync_d_pins]" } else { puts "INFO: no DDR reset-to-TDM CDC sources on this FPGA" } From 973676c0647620d4ec2063d956037af6acdaf040 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 10 Aug 2026 10:10:02 +0800 Subject: [PATCH 59/62] fix(fpga_diff): detect DDR signoff master clock --- fpga_diff/uvhs/compilation/shell_compat.sh | 39 +++++++++++++--------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/fpga_diff/uvhs/compilation/shell_compat.sh b/fpga_diff/uvhs/compilation/shell_compat.sh index bfbf1c87..f86587e8 100755 --- a/fpga_diff/uvhs/compilation/shell_compat.sh +++ b/fpga_diff/uvhs/compilation/shell_compat.sh @@ -49,10 +49,10 @@ patch_signoff_constraints() { local udc="$signoff_dir/cstr/FPGA_filtered.udc" local clock_map="$signoff_dir/cstr.tcl" local alias_count - local supported_alias_count + local ddr_map_count + local ddr_master_clock local identity_map_count - local mapped_count - local mmcm_count + local master_clock_count local reset_count local multiplier_count_before local multiplier_count_after @@ -63,31 +63,38 @@ patch_signoff_constraints() { } alias_count=$(grep -c '^create_generated_clock -name DDR_UI_CLK ' "$udc" || true) - supported_alias_count=$(grep -cE \ - '^create_generated_clock -name DDR_UI_CLK .* -master_clock \[get_clocks mmcm_clkout0\] \[get_pins .*/ddr4ip_ddr4_user_clk\]$' \ - "$udc" || true) + ddr_map_count=$(grep -oE '\{DDR_UI_CLK [^}]+\}' "$clock_map" | wc -l || true) identity_map_count=$(grep -cF '{DDR_UI_CLK DDR_UI_CLK}' "$clock_map" || true) - mapped_count=$(grep -cF '{DDR_UI_CLK mmcm_clkout0}' "$clock_map" || true) - mmcm_count=$(grep -c '^create_generated_clock -name mmcm_clkout0 ' "$udc" || true) - ((alias_count <= 1 && identity_map_count <= 1 && mapped_count <= 1 && - identity_map_count + mapped_count <= 1)) || { + ((alias_count <= 1 && ddr_map_count <= 1 && identity_map_count <= 1)) || { echo "ERROR: ambiguous DDR signoff clock constraints in $signoff_dir" >&2 exit 1 } - ((alias_count == supported_alias_count)) || { - echo "ERROR: unsupported DDR signoff clock alias in $udc" >&2 - exit 1 - } if ((alias_count == 1)); then - ((identity_map_count == 1 && mapped_count == 0 && mmcm_count == 1)) || { + ddr_master_clock=$(sed -nE ' + /^create_generated_clock -name DDR_UI_CLK .*\/ddr4ip_ddr4_user_clk]$/ { + s/.* -master_clock \[get_clocks ([^]]+)\] \[get_pins .*/\1/p + } + ' "$udc") + [[ $ddr_master_clock =~ ^[[:alnum:]_.:/-]+$ ]] || { + echo "ERROR: unsupported DDR signoff clock alias in $udc" >&2 + exit 1 + } + master_clock_count=$(grep -cF \ + "create_generated_clock -name $ddr_master_clock " "$udc" || true) + ((identity_map_count == 1 && ddr_map_count == 1 && + master_clock_count == 1)) || { echo "ERROR: DDR signoff clock mapping has no unique MIG MMCM clock" >&2 exit 1 } - sed -i 's/{DDR_UI_CLK DDR_UI_CLK}/{DDR_UI_CLK mmcm_clkout0}/' \ + sed -i "s/{DDR_UI_CLK DDR_UI_CLK}/{DDR_UI_CLK $ddr_master_clock}/" \ "$clock_map" sed -i '/^create_generated_clock -name DDR_UI_CLK .*\/ddr4ip_ddr4_user_clk]$/d' \ "$udc" + grep -Fq "{DDR_UI_CLK $ddr_master_clock}" "$clock_map" || { + echo "ERROR: failed to map DDR signoff clock to $ddr_master_clock" >&2 + exit 1 + } fi reset_count=$(awk ' From ff11b9c0bf96c88e9c387f2bb33fd3903f3b2486 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 10 Aug 2026 19:16:17 +0800 Subject: [PATCH 60/62] fix(fpga_diff): discover UVHS generalBus endpoint Query the downloaded runtime database for its unique generalBus instance instead of hard-coding the FPGA selected by one partition. Co-authored-by: Kamimiao --- fpga_diff/uvhs/runtime/runtime_server.tcl | 47 ++++++++++++++--------- fpga_diff/uvhs/uvhs.mk | 3 +- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/fpga_diff/uvhs/runtime/runtime_server.tcl b/fpga_diff/uvhs/runtime/runtime_server.tcl index 5d01f042..b76aed04 100644 --- a/fpga_diff/uvhs/runtime/runtime_server.tcl +++ b/fpga_diff/uvhs/runtime/runtime_server.tcl @@ -95,23 +95,32 @@ proc uvhs_release_cpu_after_memory {} { query -reset } -proc uvhs_write_flash_gbus {input_file board fpga port channel base capacity} { +proc uvhs_find_gbus_endpoint {} { + set ip_info [query -ipinfo -tclobj] + set endpoints {} + foreach line [split $ip_info "\n"] { + if {[regexp -nocase {^\s*\S+\s+\S+\s+B([0-9]+)\.F([0-9]+)\s+[0-9]+\s+\S+\s+gbus\s+([0-9]+)} \ + $line -> board_index fpga_index instance]} { + lappend endpoints [list $board_index f$fpga_index $instance] + } + } + set endpoints [lsort -unique $endpoints] + if {[llength $endpoints] != 1} { + error "expected one generalBus endpoint, got [llength $endpoints]: $endpoints" + } + return [lindex $endpoints 0] +} + +proc uvhs_write_flash_gbus {input_file base capacity} { if {![file isfile $input_file]} { error "flash image not found: $input_file" } - if {[regexp -nocase {^b([0-9]+)$} $board -> board_index]} { - set board $board_index - } - if {![string is integer -strict $board]} { - error "generalBus board must be an index or B: $board" - } - if {![regexp -nocase {^f([0-9]+)$} $fpga -> fpga_index]} { - error "generalBus FPGA must be F: $fpga" - } - set fpga f$fpga_index - set port [uvhs_parse_integer "generalBus port" $port] - set channel [uvhs_parse_integer "generalBus channel" $channel] + lassign [uvhs_find_gbus_endpoint] board fpga instance + # The generated generalBus DCP has one internal AXI port and one channel. + # The port shown by query -ipinfo is its system-bus slot, not this port ID. + set port 0 + set channel 0 set base [uvhs_parse_integer "flash base" $base] set capacity [uvhs_parse_integer "flash capacity" $capacity] set payload [uvhs_read_binary $input_file] @@ -135,11 +144,13 @@ proc uvhs_write_flash_gbus {input_file board fpga port channel base capacity} { uvhs_write_binary $write_file $payload file delete -force $read_file - puts [format "INFO: generalBus flash write 0x%llx, %d bytes" $base $transfer_size] + puts [format \ + "INFO: generalBus B%d.%s instance %d flash write 0x%llx, %d bytes" \ + $board $fpga $instance $base $transfer_size] set status [catch { - gbus_dma_write -board $board -fpga $fpga -port $port \ + gbus_dma_write -board $board -fpga $fpga -instance $instance -port $port \ -addr $base -size $transfer_size -channel $channel -file $write_file - gbus_dma_read -board $board -fpga $fpga -port $port \ + gbus_dma_read -board $board -fpga $fpga -instance $instance -port $port \ -addr $base -size $transfer_size -channel $channel -file $read_file set readback [uvhs_read_binary $read_file] if {![string equal $payload $readback]} { @@ -322,9 +333,9 @@ proc uvhs_execute_command {args} { uvhs_write_ddr_pairs {*}[lrange $args 1 3] } write_flash { - if {[llength $args] != 8} { error "write_flash expects 7 arguments" } + if {[llength $args] != 4} { error "write_flash expects 3 arguments" } uvhs_hold_cpu_for_memory - uvhs_write_flash_gbus {*}[lrange $args 1 7] + uvhs_write_flash_gbus {*}[lrange $args 1 3] uvhs_release_cpu_after_memory } ila_arm { diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index d378fcf6..785e2960 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -1,6 +1,7 @@ UVHS_ROOT_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))/..) UVHS_COMPILATION_DIR := $(UVHS_ROOT_DIR)/uvhs/compilation UVHS_RUNTIME_DIR := $(UVHS_ROOT_DIR)/uvhs/runtime +TRIGGER ?= $(UVHS_RUNTIME_DIR)/trigger.ini UVHS_TEMPLATE_DIR ?= UVHS_UVW_AXI4_TO_DDR4_SRC ?= @@ -172,7 +173,7 @@ uvhs_write_ddr: uvhs_write_flash: test -f "$(WORKLOAD)" - $(call uvhs_runtime_command,write_flash "$(abspath $(WORKLOAD))" B0 F2 0 0 0x0 0x8000) + $(call uvhs_runtime_command,write_flash "$(abspath $(WORKLOAD))" 0x0 0x8000) uvhs_ila_arm: test -f "$(TRIGGER)" From 68f9085d8832f1f2746a015111948e72d7a8f34c Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 10 Aug 2026 19:17:19 +0800 Subject: [PATCH 61/62] feat(fpga_diff): add KMH UVHS probe profile Keep the validated KMH probe set as an explicit profile and pair it with the repository host-trigger condition. Exclude the temporary RTL trigger so clean builds do not need debug-only logic. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 45 +- fpga_diff/uvhs/compilation/probe_kmh.tcl | 1216 ++++++++++++++++++++++ fpga_diff/uvhs/runtime/trigger.ini | 7 + 3 files changed, 1251 insertions(+), 17 deletions(-) create mode 100644 fpga_diff/uvhs/compilation/probe_kmh.tcl create mode 100644 fpga_diff/uvhs/runtime/trigger.ini diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index 7aa938c1..d8ef148e 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -130,10 +130,11 @@ runtime session with `uvhs_write_bitstream` so it reloads and downloads word width and calls `writemem -rtl`. It leaves the CPU halted until `uvhs_reset_cpu` is issued. -`uvhs_write_flash` writes through the 64-bit generalBus and the existing -32-bit AXI flash bridge. The generalBus view starts at offset zero; the CPU and -normal JTAG address map are unchanged. A complete readback match is required -before the command succeeds. +`uvhs_write_flash` locates the compiled generalBus endpoint with +`query -ipinfo -tclobj`, then writes through its 64-bit AXI port and the +existing 32-bit AXI flash bridge. The generalBus view starts at offset zero; +the CPU and normal JTAG address map are unchanged. A complete readback match +is required before the command succeeds. The runtime implementation has two control layers: @@ -154,14 +155,17 @@ from the server's global Tcl scope. ## UVHS ILA Waveform Capture -The reference probe scripts describe compile-time instrumentation, not a -runtime dump. The frontend sources `compilation/probe_ila.tcl` by default. It -always samples the XDMA host trigger on `core_def.sys_clk_i`; add temporary -design-specific paths to its probe and trigger lists as needed. The braces -preserve hierarchy indexes such as `[0]`. Set `UVHS_PROBE_TCL` to use another -file instead; an override must retain the XDMA host trigger if host-controlled -capture is required. The template calls `probe_net` for sampled signals and -`trigger_net` for signals that may participate in a trigger condition. +The probe scripts describe compile-time instrumentation, not a runtime dump. +The frontend sources `compilation/probe_ila.tcl` by default. It samples only +the XDMA host trigger on `core_def.sys_clk_i`. `compilation/probe_kmh.tcl` is +the larger XiangShan profile used by the 2026-08-04 and 2026-08-07 debug +builds. Its generated hierarchy must be checked before it is reused with a +different XiangShan RTL revision. The braces preserve hierarchy indexes such +as `[0]`. Set `UVHS_PROBE_TCL` to select a profile or an external file; an +override must retain the XDMA host trigger if host-controlled capture is +required. Set it to an empty value for a build with no UHD instrumentation. +The scripts call `probe_net` for sampled signals and `trigger_net` for signals +that may participate in a trigger condition. ```tcl set uvhs_ila_clock_path [string trim { @@ -183,11 +187,15 @@ the default file, build a new database and bitstream normally: make uvhs CPU= CORE_DIR=/path/to/release/build SUFFIX=probe ``` -An external probe file can be selected without changing the repository: +Select the repository KMH profile, an external profile, or no ILA as follows: ```sh +make uvhs CPU= CORE_DIR=/path/to/release/build SUFFIX=probe \ + UVHS_PROBE_TCL=/path/to/env-scripts/fpga_diff/uvhs/compilation/probe_kmh.tcl make uvhs CPU= CORE_DIR=/path/to/release/build SUFFIX=probe \ UVHS_PROBE_TCL=/path/to/probe.tcl +make uvhs CPU= CORE_DIR=/path/to/release/build SUFFIX=noila \ + UVHS_PROBE_TCL= ``` The frontend records the probe and trigger declarations. The backend already @@ -195,8 +203,9 @@ runs `trigger_probe -check` after runtime-data initialization and `trigger_probe -group` after clock transformation, which inserts and groups the debug hardware before partitioning. -At runtime, write a trigger condition file using the group and signal names -reported by `query -trigger`: +At runtime, `uvhs_ila_arm` uses `runtime/trigger.ini` by default. Set `TRIGGER` +to another condition file using the group and signal names reported by +`query -trigger`: ```ini [uvhs_ila] @@ -239,8 +248,7 @@ CPU and the requested history precedes the host trigger: ```sh export FPGA_ILA_DUMP_CMD='ssh \ "make -C /path/to/env-scripts/fpga_diff uvhs_ila_arm \ - CPU= SUFFIX= TRIGGER=/path/to/trigger.ini \ - UVHS_ILA_POSITION=0"' + CPU= SUFFIX= UVHS_ILA_POSITION=0"' /path/to/fpga-host @@ -347,7 +355,10 @@ before the UVHS timing worker reads it. | `compilation/vivado_pre_opt.tcl` | XDMA refclock and CDC constraints. | | `compilation/prepare_ip.sh` | Coordinates Vivado, generalBus, and external DDR IP preparation. | | `compilation/export_vivado_ip.tcl` | Runs repository-owned XCI/BD exports inside Vivado. | +| `compilation/probe_ila.tcl` | Minimal host-trigger UHD probe profile. | +| `compilation/probe_kmh.tcl` | KMH debug UHD probe profile. | | `compilation/shell_compat.sh` | Generated launcher and signoff-constraint compatibility. | | `runtime/uv_shell_exec_compat.sh` | Runtime library wrapper for UVHS shells and generated Python workers. | | `runtime/runtime_server.tcl` | Download, reset, DDR, flash, capture, and command service. | | `runtime/runtime_session.sh` | Process lifecycle and atomic command/result transport. | +| `runtime/trigger.ini` | Default rising-edge host trigger condition. | diff --git a/fpga_diff/uvhs/compilation/probe_kmh.tcl b/fpga_diff/uvhs/compilation/probe_kmh.tcl new file mode 100644 index 00000000..3d836717 --- /dev/null +++ b/fpga_diff/uvhs/compilation/probe_kmh.tcl @@ -0,0 +1,1216 @@ +# KMH probe profile used by the 2026-08-04 and 2026-08-07 debug builds. +# Signal paths must be checked when the generated XiangShan hierarchy changes. +probe_net -clock {fpga_top_debug.core_def.sys_clk_i} -add { \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_awaddr \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_awlen \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_awready \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_awsize \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_awvalid \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_awid \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_wdata \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_wlast \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_wready \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_wvalid \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_bready \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_bresp \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_bvalid \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_bid \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_araddr \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_arlen \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_arready \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_arsize \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_arvalid \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_arid \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_rdata \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_rlast \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_rready \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_rresp \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_rvalid \ +fpga_top_debug.core_def.U_UVHS_UVW_AXI4_TO_DDR4.ddr4ip_dut_axi_rid \ +} +probe_net -clock {fpga_top_debug.core_def.sys_clk_i} -add { \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.io_csrio_tlb_satp_mode[3:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.io_csrio_tlb_satp_asid[15:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.io_csrio_tlb_vsatp_mode[3:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.io_csrio_tlb_vsatp_asid[15:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.io_csrio_tlb_hgatp_mode[3:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.io_csrio_tlb_hgatp_vmid[15:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.io_csrio_tlb_priv_mxr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.io_csrio_tlb_priv_sum \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.io_csrio_tlb_priv_vmxr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.io_csrio_tlb_priv_vsum \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.io_csrio_tlb_priv_virt \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.io_csrio_tlb_priv_spvp \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.io_csrio_tlb_priv_imode[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.io_csrio_tlb_priv_dmode[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.Fence.io_fenceio_sfence_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.Fence.io_fenceio_sfence_bits_rs1 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.Fence.io_fenceio_sfence_bits_rs2 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.Fence.io_fenceio_sfence_bits_addr[49:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.Fence.io_fenceio_sfence_bits_id[15:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.Fence.io_fenceio_sfence_bits_flushPipe \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.Fence.io_fenceio_sfence_bits_hv \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.Fence.io_fenceio_sfence_bits_hg \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_0_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_0_req_bits_vaddr[49:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_0_resp_bits_paddr_0[47:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_0_resp_bits_miss \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_0_resp_bits_excp_0_gpf_ld \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_0_resp_bits_excp_0_gpf_st \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_0_resp_bits_excp_0_pf_ld \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_0_resp_bits_excp_0_pf_st \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_0_resp_bits_excp_0_af_ld \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_0_resp_bits_excp_0_af_st \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_1_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_1_req_bits_vaddr[49:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_1_resp_bits_paddr_0[47:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_1_resp_bits_miss \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_1_resp_bits_excp_0_gpf_ld \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_1_resp_bits_excp_0_pf_ld \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_1_resp_bits_excp_0_af_ld \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_2_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_2_req_bits_vaddr[49:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_2_resp_bits_paddr_0[47:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_2_resp_bits_miss \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_2_resp_bits_excp_0_gpf_ld \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_2_resp_bits_excp_0_pf_ld \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.io_requestor_2_resp_bits_excp_0_af_ld \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.io_w_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.io_w_bits_wayIdx[5:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_0 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_3 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_6 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_7 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_8 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_9 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_10 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_11 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_12 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_13 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_14 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_15 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_16 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_17 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_18 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_19 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_20 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_21 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_22 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_23 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_24 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_25 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_26 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_27 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_28 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_29 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_30 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_31 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_32 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_33 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_34 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_35 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_36 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_37 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_38 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_39 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_40 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_41 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_42 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_43 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_44 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_45 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_46 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_47 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_0 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_1 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_2 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_3 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_6 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_7 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_8 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_9 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_10 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_11 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_12 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_13 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_14 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_15 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_16 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_17 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_18 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_19 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_20 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_21 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_22 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_23 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_24 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_25 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_26 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_27 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_28 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_29 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_30 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_31 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_32 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_33 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_34 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_35 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_36 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_37 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_38 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_39 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_40 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_41 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_42 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_43 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_44 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_45 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_46 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_1_47 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_0 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_1 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_2 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_3 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_6 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_7 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_8 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_9 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_10 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_11 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_12 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_13 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_14 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_15 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_16 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_17 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_18 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_19 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_20 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_21 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_22 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_23 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_24 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_25 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_26 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_27 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_28 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_29 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_30 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_31 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_32 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_33 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_34 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_35 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_36 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_37 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_38 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_39 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_40 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_41 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_42 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_43 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_44 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_45 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_46 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_ld_tlb_ld.entries.page_ldtlb_storage_fa.hitVecReg_2_47 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.io_requestor_0_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.io_requestor_0_req_bits_vaddr[49:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.io_requestor_0_resp_bits_paddr_0[47:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.io_requestor_0_resp_bits_miss \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.io_requestor_0_resp_bits_excp_0_gpf_st \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.io_requestor_0_resp_bits_excp_0_pf_st \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.io_requestor_0_resp_bits_excp_0_af_st \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.io_requestor_1_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.io_requestor_1_req_bits_vaddr[49:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.io_requestor_1_resp_bits_paddr_0[47:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.io_requestor_1_resp_bits_miss \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.io_requestor_1_resp_bits_excp_0_gpf_st \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.io_requestor_1_resp_bits_excp_0_pf_st \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.io_requestor_1_resp_bits_excp_0_af_st \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.io_w_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.io_w_bits_wayIdx[5:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_0 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_2 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_3 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_6 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_7 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_8 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_9 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_10 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_11 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_12 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_13 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_14 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_15 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_16 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_17 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_18 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_19 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_20 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_21 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_22 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_23 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_24 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_25 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_26 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_27 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_28 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_29 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_30 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_31 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_32 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_33 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_34 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_35 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_36 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_37 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_38 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_39 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_40 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_41 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_42 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_43 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_44 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_45 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_46 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_47 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_0 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_1 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_2 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_3 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_6 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_7 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_8 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_9 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_10 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_11 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_12 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_13 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_14 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_15 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_16 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_17 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_18 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_19 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_20 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_21 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_22 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_23 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_24 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_25 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_26 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_27 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_28 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_29 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_30 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_31 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_32 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_33 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_34 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_35 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_36 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_37 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_38 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_39 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_40 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_41 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_42 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_43 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_44 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_45 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_46 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dtlb_st_tlb_st.entries.page_sttlb_storage_fa.hitVecReg_1_47 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.io_requestor_0_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.io_requestor_0_req_bits_vaddr[49:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.io_requestor_0_resp_bits_paddr_0[47:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.io_requestor_0_resp_bits_miss \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.io_requestor_0_resp_bits_excp_0_gpf_instr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.io_requestor_0_resp_bits_excp_0_pf_instr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.io_requestor_0_resp_bits_excp_0_af_instr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.io_requestor_1_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.io_requestor_1_req_bits_vaddr[49:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.io_requestor_1_resp_bits_paddr_0[47:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.io_requestor_1_resp_bits_miss \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.io_requestor_1_resp_bits_excp_0_gpf_instr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.io_requestor_1_resp_bits_excp_0_pf_instr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.io_requestor_1_resp_bits_excp_0_af_instr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.io_w_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.io_w_bits_wayIdx[5:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_0 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_2 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_3 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_6 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_7 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_8 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_9 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_10 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_11 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_12 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_13 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_14 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_15 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_16 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_17 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_18 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_19 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_20 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_21 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_22 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_23 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_24 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_25 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_26 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_27 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_28 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_29 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_30 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_31 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_32 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_33 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_34 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_35 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_36 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_37 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_38 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_39 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_40 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_41 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_42 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_43 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_44 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_45 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_46 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_47 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_0 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_1 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_2 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_3 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_6 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_7 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_8 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_9 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_10 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_11 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_12 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_13 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_14 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_15 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_16 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_17 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_18 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_19 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_20 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_21 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_22 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_23 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_24 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_25 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_26 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_27 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_28 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_29 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_30 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_31 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_32 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_33 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_34 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_35 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_36 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_37 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_38 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_39 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_40 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_41 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_42 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_43 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_44 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_45 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_46 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.frontend.inner_itlb.entries.page_itlb_storage_fa.hitVecReg_1_47 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_req_0_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_req_0_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_req_0_bits_vpn[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_req_0_bits_s2xlate[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s2xlate[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_entry_tag[34:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_entry_n \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_entry_perm_d \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_entry_perm_a \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_entry_perm_g \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_entry_perm_u \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_entry_perm_x \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_entry_perm_w \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_entry_perm_r \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_entry_ppn[40:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_entry_level[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_entry_v \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_addr_low[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_ppn_low_0[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_ppn_low_1[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_ppn_low_2[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_ppn_low_3[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_ppn_low_4[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_ppn_low_5[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_ppn_low_6[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_ppn_low_7[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_valididx_0 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_valididx_1 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_valididx_2 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_valididx_3 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_valididx_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_valididx_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_valididx_6 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_valididx_7 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_pteidx_0 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_pteidx_1 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_pteidx_2 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_pteidx_3 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_pteidx_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_pteidx_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_pteidx_6 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_pteidx_7 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_pf \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s1_af \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s2_entry_tag[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s2_entry_n \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s2_entry_ppn[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s2_entry_perm_d \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s2_entry_perm_a \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s2_entry_perm_g \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s2_entry_perm_u \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s2_entry_perm_x \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s2_entry_perm_w \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s2_entry_perm_r \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s2_entry_level[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s2_gpf \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_0_resp_bits_s2_gaf \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.tlbCounter[5:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_req_0_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_req_0_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_req_0_bits_vpn[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_req_0_bits_s2xlate[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s2xlate[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_entry_tag[34:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_entry_n \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_entry_perm_d \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_entry_perm_a \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_entry_perm_g \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_entry_perm_u \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_entry_perm_x \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_entry_perm_w \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_entry_perm_r \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_entry_ppn[40:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_entry_level[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_entry_v \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_addr_low[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_ppn_low_0[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_ppn_low_1[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_ppn_low_2[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_ppn_low_3[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_ppn_low_4[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_ppn_low_5[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_ppn_low_6[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_ppn_low_7[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_valididx_0 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_valididx_1 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_valididx_2 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_valididx_3 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_valididx_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_valididx_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_valididx_6 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_valididx_7 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_pteidx_0 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_pteidx_1 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_pteidx_2 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_pteidx_3 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_pteidx_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_pteidx_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_pteidx_6 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_pteidx_7 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_pf \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s1_af \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s2_entry_tag[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s2_entry_n \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s2_entry_ppn[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s2_entry_perm_d \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s2_entry_perm_a \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s2_entry_perm_g \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s2_entry_perm_u \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s2_entry_perm_x \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s2_entry_perm_w \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s2_entry_perm_r \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s2_entry_level[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s2_gpf \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.io_tlb_1_resp_bits_s2_gaf \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.auto_out_a_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.auto_out_a_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.auto_out_a_bits_source[3:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.auto_out_a_bits_address[47:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.auto_out_d_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.auto_out_d_bits_opcode[3:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.auto_out_d_bits_size[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.auto_out_d_bits_source[3:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.auto_out_d_bits_data[255:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_req_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_req_bits_req_info_vpn[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_req_bits_req_info_s2xlate[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_req_bits_req_info_source[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_req_bits_isFirst \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_req_bits_isHptwReq \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_req_bits_hptwId[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_req_info_vpn[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_req_info_s2xlate[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_req_info_source[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_isFirst \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_hit \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_prefetch \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_bypassed \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toFsm_l3Hit \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toFsm_l2Hit \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toFsm_l1Hit \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toFsm_stage1Hit \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toFsm_ppn[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_isHptwReq \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_l3Hit \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_l2Hit \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_l1Hit \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_ppn[35:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_id[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_resp_entry_tag[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_resp_entry_vmid[13:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_resp_entry_n \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_resp_entry_pbmt[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_resp_entry_ppn[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_resp_entry_perm_d \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_resp_entry_perm_a \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_resp_entry_perm_g \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_resp_entry_perm_u \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_resp_entry_perm_x \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_resp_entry_perm_w \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_resp_entry_perm_r \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_resp_entry_level[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_resp_gpf \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_resp_bits_toHptw_bypassed \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_refill_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_refill_bits_levelOH_sp \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_refill_bits_levelOH_l0 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_refill_bits_levelOH_l1 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_refill_bits_levelOH_l2 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_refill_bits_levelOH_l3 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_refill_bits_req_info_dup_0_vpn[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_refill_bits_req_info_dup_0_s2xlate[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_refill_bits_req_info_dup_0_source[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.cache.io_refill_bits_sel_pte_dup_0[63:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.io_req_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.io_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.io_req_bits_req_info_vpn[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.io_req_bits_req_info_s2xlate[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.io_req_bits_req_info_source[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.idle \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.level[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.s_mem_req \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.w_mem_resp \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.s_hptw_req \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.w_hptw_resp \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.accessFault \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.find_pte \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.guestFault \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.io_mem_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.io_resp_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.io_llptw_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.io_hptw_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.ptw.io_hptw_req_bits_gvpn[43:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.io_req_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.io_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.io_req_bits_gvpn[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.io_req_bits_ppn[35:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.io_req_bits_l3Hit \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.io_req_bits_l2Hit \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.io_req_bits_l1Hit \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.io_req_bits_bypassed \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.idle \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.level[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.af_level[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.l3Hit \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.l2Hit \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.l1Hit \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.bypassed \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.io_mem_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.hptw.io_resp_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.llptw.io_in_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.llptw.io_in_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.llptw.io_in_bits_req_info_vpn[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.llptw.io_in_bits_req_info_s2xlate[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.llptw.io_in_bits_req_info_source[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.llptw.io_out_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.llptw.io_mem_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.missQueue.io_out_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.missQueue.io_out_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_ptw.ptw.missQueue.io_out_bits_req_info_vpn[37:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.state \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.enqPtrGenModule.enqPtrVec_0_flag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.enqPtrGenModule.enqPtrVec_0_value[7:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.deqPtrGenModule.deqPtrVec_0_flag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.deqPtrGenModule.deqPtrVec_0_value[7:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.io_commits_commitValid_0 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.io_commits_commitValid_1 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.io_commits_commitValid_2 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.io_commits_commitValid_3 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.io_commits_commitValid_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.io_commits_commitValid_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.io_commits_commitValid_6 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.io_commits_commitValid_7 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.io_commits_isCommit \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.hasWFI \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.io_frontend_toFtq_redirect_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.io_frontend_toFtq_redirect_bits_cfiUpdate_target[49:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.io_frontend_cfVec_0_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.io_frontend_cfVec_0_bits_instr[31:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_0.s3_in_nc \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_0.s3_in_mmio \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_0.s3_in_uop_robIdx_flag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_0.s3_in_uop_robIdx_value[7:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_0.s3_in_vaddr[49:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_0.s3_in_paddr[47:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_0.s3_exception \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_0.s3_mis_align_r \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_0.toMisalignBufferValid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_1.s3_in_nc \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_1.s3_in_mmio \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_1.s3_in_uop_robIdx_flag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_1.s3_in_uop_robIdx_value[7:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_1.s3_in_vaddr[49:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_1.s3_in_paddr[47:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_1.s3_exception \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_1.s3_mis_align_r \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_1.toMisalignBufferValid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_2.s3_in_nc \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_2.s3_in_mmio \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_2.s3_in_uop_robIdx_flag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_2.s3_in_uop_robIdx_value[7:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_2.s3_in_vaddr[49:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_2.s3_in_paddr[47:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_2.s3_exception \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_2.s3_mis_align_r \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_LoadUnit_2.toMisalignBufferValid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_0.io_out_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_0.io_out_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_0.io_out_bits_uop_fuType \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_0.io_out_bits_uop_fuOpType \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_0.io_out_bits_uop_robIdx_value \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_0.io_out_bits_uop_sqIdx_flag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_0.io_out_bits_uop_sqIdx_value \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_0.io_out_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_1.io_out_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_1.io_out_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_1.io_out_bits_uop_fuType \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_1.io_out_bits_uop_fuOpType \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_1.io_out_bits_uop_robIdx_value \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_1.io_out_bits_uop_sqIdx_flag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_1.io_out_bits_uop_sqIdx_value \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_stdExeUnits_1.io_out_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_0.s2_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_0.s2_in_uop_robIdx_flag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_0.s2_in_uop_robIdx_value \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_0.s2_in_vaddr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_0.s2_in_paddr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_0.s2_in_nc \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_0.s2_in_mmio \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_0.s2_pbmt \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_0.io_misalign_enq_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_0.s1_toMisalignBufferValid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_1.s2_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_1.s2_in_uop_robIdx_flag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_1.s2_in_uop_robIdx_value \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_1.s2_in_vaddr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_1.s2_in_paddr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_1.s2_in_nc \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_1.s2_in_mmio \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_1.s2_pbmt \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_1.io_misalign_enq_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_StoreUnit_1.s1_toMisalignBufferValid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_loadMisalignBuffer.bufferState[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_loadMisalignBuffer.req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_loadMisalignBuffer.req_uop_robIdx_flag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_loadMisalignBuffer.req_uop_robIdx_value[7:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_loadMisalignBuffer.io_splitLoadResp_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_storeMisalignBuffer.bufferState[2:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_storeMisalignBuffer.req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_storeMisalignBuffer.req_uop_robIdx_flag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_storeMisalignBuffer.req_uop_robIdx_value[7:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_storeMisalignBuffer.io_splitStoreResp_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_robIdx_flag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_robIdx_value \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_hasException \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_isEnqExcp \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_0 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_1 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_2 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_3 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_6 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_7 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_8 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_9 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_10 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_11 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_12 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_13 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_14 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_15 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_16 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_17 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_18 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_19 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_20 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_21 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_22 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_exceptionVec_23 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_isFetchMalAddr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_flushPipe \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_replayInst \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_singleStep \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_crossPageIPFFix \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.rob.exceptionGen.io_state_bits_trigger \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapEntryHSEvent.valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapEntryHSEvent.out_scause_bits_ExceptionCode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapEntryHSEvent.out_sepc_bits_epc \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapEntryHSEvent.out_stval_bits_ALL \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapEntryVSEvent.valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapEntryVSEvent.out_vsepc_bits_epc \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapEntryVSEvent.out_vscause_bits_ExceptionCode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapEntryVSEvent.out_vstval_bits_ALL \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.PRVM[1:0] \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.V \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_0_bits_uop_robIdx_value \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_0_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_0_bits_uop_exceptionVec_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_0_bits_uop_exceptionVec_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_0_bits_uop_exceptionVec_13 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_0_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_1_bits_uop_robIdx_value \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_1_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_1_bits_uop_exceptionVec_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_1_bits_uop_exceptionVec_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_1_bits_uop_exceptionVec_13 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_1_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_2_bits_uop_robIdx_value \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_2_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_2_bits_uop_exceptionVec_4 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_2_bits_uop_exceptionVec_5 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_2_bits_uop_exceptionVec_13 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackLda_2_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_0_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_0_bits_uop_robIdx_value \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_0_bits_uop_robIdx_flag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_0_bits_debug_isMMIO \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_0_bits_debug_isNCIO \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_0_bits_uop_exceptionVec_6 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_0_bits_uop_exceptionVec_7 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_0_bits_uop_exceptionVec_15 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_1_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_1_bits_uop_robIdx_value \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_1_bits_uop_robIdx_flag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_1_bits_debug_isMMIO \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_1_bits_debug_isNCIO \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_1_bits_uop_exceptionVec_6 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_1_bits_uop_exceptionVec_7 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.io_mem_to_ooo_writebackSta_1_bits_uop_exceptionVec_15 \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_in_0_bits_vaddr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_in_0_bits_addr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_in_0_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_in_0_bits_mask \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_in_0_bits_vecValid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_in_0_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_in_0_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_in_1_bits_vaddr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_in_1_bits_addr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_in_1_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_in_1_bits_mask \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_in_1_bits_vecValid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_in_1_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_in_1_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_a_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_a_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_a_bits_source \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_a_bits_address \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_b_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_b_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_b_bits_param \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_b_bits_address \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_d_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_d_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_d_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_d_bits_size \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_d_bits_source \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_d_bits_corrupt \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.decode.decoders_0.isZimop \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.decode.decoders_1.isZimop \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.decode.decoders_2.isZimop \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.decode.decoders_3.isZimop \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.decode.decoders_4.isZimop \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_ctrlBlock.decode.decoders_5.isZimop \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.time_0.updated \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.time_0.mHPM_time_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.time_0.mHPM_time_bits \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.sstcIRGen.i_stime_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.sstcIRGen.i_stime_bits \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.sstcIRGen.i_vstime_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.sstcIRGen.i_vstime_bits \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.sstcIRGen.i_stimecmp_wen \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.sstcIRGen.i_stimecmp_rdata \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.sstcIRGen.i_vstimecmp_wen \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.sstcIRGen.i_vstimecmp_rdata \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.sstcIRGen.i_htimedeltaWen \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.sstcIRGen.i_menvcfg_wen \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.sstcIRGen.i_menvcfg_STCE \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.sstcIRGen.i_henvcfg_wen \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.sstcIRGen.i_henvcfg_STCE \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.sstcIRGen.o_STIP \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.sstcIRGen.o_VSTIP \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapHandleMod.io_in_trapInfo_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapHandleMod.io_in_trapInfo_bits_trapVec \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapHandleMod.io_in_trapInfo_bits_intrVec \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapHandleMod.io_in_trapInfo_bits_isInterrupt \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapHandleMod.io_in_trapInfo_bits_singleStep \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapHandleMod.io_in_trapInfo_bits_irToHS \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapHandleMod.io_in_trapInfo_bits_irToVS \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapHandleMod.io_in_privState_PRVM \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapHandleMod.io_out_entryPrivState_PRVM \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapHandleMod.io_out_entryPrivState_V \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapHandleMod.io_out_causeNO_Interrupt \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapHandleMod.io_out_causeNO_ExceptionCode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapHandleMod.io_out_dbltrpToMN \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapHandleMod.io_out_hasDTExcp \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.backend.inner_intExuBlock.exus_7.csr.csrMod.trapHandleMod.io_out_pcFromXtvec \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_a_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_c_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_c_bits_param \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_c_bits_size \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_c_bits_source \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_c_bits_address \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_c_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_client_out_d_bits_denied \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_uncache_in_a_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_uncache_in_a_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_uncache_in_a_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_uncache_in_a_bits_size \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_uncache_in_a_bits_source \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_uncache_in_a_bits_address \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_uncache_in_a_bits_mask \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_uncache_in_a_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_uncache_in_d_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_uncache_in_d_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_uncache_in_d_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_uncache_in_d_bits_size \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_uncache_in_d_bits_source \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_dcache.auto_uncache_in_d_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_dcache_req_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_dcache_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_dcache_req_bits_vaddr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_dcache_req_bits_addr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_dcache_req_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_dcache_req_bits_mask \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_dcache_req_bits_id \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_dcache_main_pipe_hit_resp_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_dcache_main_pipe_hit_resp_bits_id \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_dcache_replay_resp_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_sbuffer.io_dcache_replay_resp_bits_id \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_req_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_req_bits_robIdx_flag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_req_bits_robIdx_value \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_req_bits_addr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_req_bits_vaddr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_req_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_req_bits_mask \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_req_bits_id \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_req_bits_nc \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_req_bits_memBackTypeMM \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_idResp_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_idResp_bits_mid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_idResp_bits_nc \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_resp_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_resp_bits_nc \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_resp_bits_denied \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.core.memBlock.inner_lsq.storeQueue.io_uncache_resp_bits_corrupt \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_qos \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_tgtID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_txnID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_returnNID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_stashNIDValid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_returnTxnID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_size \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_addr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_ns \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_likelyshared \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_allowRetry \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_order \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_pCrdType \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_memAttr_allocate \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_memAttr_cacheable \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_memAttr_device \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_memAttr_ewa \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_snpAttr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_lpIDWithPadding \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_snoopMe \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_expCompAck \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_tagOp \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_traceTag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_mpam_perfMonGroup \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_mpam_partID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_mpam_mpamNS \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_req_bits_rsvdc \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_rsp_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_rsp_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_rsp_bits_qos \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_rsp_bits_tgtID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_rsp_bits_txnID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_rsp_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_rsp_bits_respErr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_rsp_bits_resp \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_rsp_bits_fwdState \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_rsp_bits_cBusy \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_rsp_bits_dbID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_rsp_bits_pCrdType \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_rsp_bits_tagOp \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_rsp_bits_traceTag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_qos \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_tgtID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_txnID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_homeNID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_respErr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_resp \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_dataSource \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_cBusy \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_dbID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_ccID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_dataID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_tagOp \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_tag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_tu \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_traceTag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_rsvdc \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_be \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_dataCheck \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_tx_dat_bits_poison \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_rsp_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_rsp_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_rsp_bits_qos \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_rsp_bits_tgtID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_rsp_bits_srcID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_rsp_bits_txnID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_rsp_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_rsp_bits_respErr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_rsp_bits_resp \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_rsp_bits_fwdState \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_rsp_bits_cBusy \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_rsp_bits_dbID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_rsp_bits_pCrdType \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_rsp_bits_tagOp \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_rsp_bits_traceTag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_qos \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_tgtID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_srcID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_txnID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_homeNID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_respErr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_resp \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_dataSource \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_cBusy \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_dbID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_ccID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_dataID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_tagOp \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_tag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_tu \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_traceTag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_rsvdc \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_be \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_dataCheck \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_dat_bits_poison \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_bits_qos \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_bits_srcID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_bits_txnID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_bits_fwdNID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_bits_fwdTxnID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_bits_addr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_bits_ns \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_bits_doNotGoToSD \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_bits_retToSrc \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_bits_traceTag \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_bits_mpam_perfMonGroup \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_bits_mpam_partID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_in_rx_snp_bits_mpam_mpamNS \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_txsactive \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_rxsactive \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_syscoreq \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_syscoack \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_tx_linkactivereq \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_tx_linkactiveack \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_tx_req_flitpend \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_tx_req_flitv \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_tx_req_lcrdv \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_tx_rsp_flitpend \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_tx_rsp_flitv \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_tx_rsp_lcrdv \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_tx_dat_flitpend \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_tx_dat_flitv \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_tx_dat_lcrdv \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_rx_linkactivereq \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_rx_linkactiveack \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_rx_rsp_flitpend \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_rx_rsp_flitv \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_rx_rsp_lcrdv \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_rx_dat_flitpend \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_rx_dat_flitv \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_rx_dat_lcrdv \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_rx_snp_flitpend \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_rx_snp_flitv \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_out_rx_snp_lcrdv \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.inner_l2cache.linkMonitor.io_nodeID \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_out_d_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_out_d_bits_param \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_out_d_bits_size \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_out_d_bits_source \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_out_d_bits_sink \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_out_d_bits_denied \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_out_d_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_out_d_bits_corrupt \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_in_a_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_in_a_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_in_a_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_in_a_bits_param \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_in_a_bits_size \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_in_a_bits_source \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_in_a_bits_address \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_in_a_bits_user_memBackType_MM \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_in_a_bits_user_memPageType_NC \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_in_a_bits_mask \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_in_a_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_in_a_bits_corrupt \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_in_d_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_buffers_in_d_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_a_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_a_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_a_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_a_bits_param \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_a_bits_size \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_a_bits_source \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_a_bits_address \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_a_bits_user_alias \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_a_bits_user_reqSource \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_a_bits_user_needHint \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_a_bits_mask \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_a_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_a_bits_corrupt \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_d_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_d_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_d_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_d_bits_param \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_d_bits_size \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_d_bits_source \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_d_bits_sink \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_d_bits_denied \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_d_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_1_d_bits_corrupt \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_a_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_a_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_a_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_a_bits_param \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_a_bits_size \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_a_bits_source \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_a_bits_address \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_a_bits_user_alias \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_a_bits_user_vaddr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_a_bits_user_reqSource \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_a_bits_user_needHint \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_a_bits_echo_isKeyword \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_a_bits_mask \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_a_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_a_bits_corrupt \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_b_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_b_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_b_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_b_bits_param \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_b_bits_size \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_b_bits_source \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_b_bits_address \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_b_bits_mask \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_b_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_b_bits_corrupt \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_c_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_c_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_c_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_c_bits_param \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_c_bits_size \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_c_bits_source \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_c_bits_address \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_c_bits_user_alias \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_c_bits_user_vaddr \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_c_bits_user_reqSource \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_c_bits_user_needHint \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_c_bits_echo_isKeyword \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_c_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_c_bits_corrupt \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_d_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_d_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_d_bits_opcode \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_d_bits_param \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_d_bits_size \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_d_bits_source \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_d_bits_sink \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_d_bits_denied \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_d_bits_echo_isKeyword \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_d_bits_data \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_d_bits_corrupt \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_e_ready \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_e_valid \ +fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_e_bits_sink \ +fpga_top_debug.core_def.io_host_ila_trigger \ +} +trigger_net -add -group uvhs_ila \ +-clock fpga_top_debug.core_def.sys_clk_i \ +-signal { \ +fpga_top_debug.core_def.io_host_ila_trigger \ +} diff --git a/fpga_diff/uvhs/runtime/trigger.ini b/fpga_diff/uvhs/runtime/trigger.ini new file mode 100644 index 00000000..defdf3d8 --- /dev/null +++ b/fpga_diff/uvhs/runtime/trigger.ini @@ -0,0 +1,7 @@ +[uvhs_ila] +LOGIC = OR +fpga_top_debug.core_def.io_host_ila_trigger = R + +[UHD_FINAL_CONDITIONS_LOGIC] +LOGIC = OR +uvhs_ila From a877b981af2c822f2794e9036f059cf984dcf5f6 Mon Sep 17 00:00:00 2001 From: klin02 Date: Mon, 10 Aug 2026 19:19:53 +0800 Subject: [PATCH 62/62] fix(fpga_diff): preserve KMH trigger group Keep the committed trigger condition compatible with the test0 group already present in the validated 0804 and 0807 runtime databases. Require an explicit trigger file so other probe profiles cannot silently use the wrong group. Co-authored-by: Kamimiao --- fpga_diff/uvhs/README.md | 16 +++++++++------- fpga_diff/uvhs/compilation/probe_kmh.tcl | 2 +- fpga_diff/uvhs/runtime/trigger.ini | 4 ++-- fpga_diff/uvhs/uvhs.mk | 1 - 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/fpga_diff/uvhs/README.md b/fpga_diff/uvhs/README.md index d8ef148e..c6094e00 100644 --- a/fpga_diff/uvhs/README.md +++ b/fpga_diff/uvhs/README.md @@ -203,18 +203,18 @@ runs `trigger_probe -check` after runtime-data initialization and `trigger_probe -group` after clock transformation, which inserts and groups the debug hardware before partitioning. -At runtime, `uvhs_ila_arm` uses `runtime/trigger.ini` by default. Set `TRIGGER` -to another condition file using the group and signal names reported by -`query -trigger`: +At runtime, `runtime/trigger.ini` matches the `test0` group in +`probe_kmh.tcl`. Use another condition file for another probe profile, based +on the group and signal names reported by `query -trigger`: ```ini -[uvhs_ila] +[test0] LOGIC = OR fpga_top_debug.core_def.io_host_ila_trigger = R [UHD_FINAL_CONDITIONS_LOGIC] LOGIC = OR -uvhs_ila +test0 ``` Waveform capture is split around the host run. `uvhs_ila_arm` validates and @@ -248,7 +248,9 @@ CPU and the requested history precedes the host trigger: ```sh export FPGA_ILA_DUMP_CMD='ssh \ "make -C /path/to/env-scripts/fpga_diff uvhs_ila_arm \ - CPU= SUFFIX= UVHS_ILA_POSITION=0"' + CPU= SUFFIX= \ + TRIGGER=/path/to/env-scripts/fpga_diff/uvhs/runtime/trigger.ini \ + UVHS_ILA_POSITION=0"' /path/to/fpga-host @@ -361,4 +363,4 @@ before the UVHS timing worker reads it. | `runtime/uv_shell_exec_compat.sh` | Runtime library wrapper for UVHS shells and generated Python workers. | | `runtime/runtime_server.tcl` | Download, reset, DDR, flash, capture, and command service. | | `runtime/runtime_session.sh` | Process lifecycle and atomic command/result transport. | -| `runtime/trigger.ini` | Default rising-edge host trigger condition. | +| `runtime/trigger.ini` | KMH rising-edge host trigger condition. | diff --git a/fpga_diff/uvhs/compilation/probe_kmh.tcl b/fpga_diff/uvhs/compilation/probe_kmh.tcl index 3d836717..02e6be4b 100644 --- a/fpga_diff/uvhs/compilation/probe_kmh.tcl +++ b/fpga_diff/uvhs/compilation/probe_kmh.tcl @@ -1209,7 +1209,7 @@ fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar fpga_top_debug.core_def.U_CPU_TOP.u_XSTop.soc.core_with_l2.l2top.auto_inner_xbar_in_0_e_bits_sink \ fpga_top_debug.core_def.io_host_ila_trigger \ } -trigger_net -add -group uvhs_ila \ +trigger_net -add -group test0 \ -clock fpga_top_debug.core_def.sys_clk_i \ -signal { \ fpga_top_debug.core_def.io_host_ila_trigger \ diff --git a/fpga_diff/uvhs/runtime/trigger.ini b/fpga_diff/uvhs/runtime/trigger.ini index defdf3d8..7a3ff735 100644 --- a/fpga_diff/uvhs/runtime/trigger.ini +++ b/fpga_diff/uvhs/runtime/trigger.ini @@ -1,7 +1,7 @@ -[uvhs_ila] +[test0] LOGIC = OR fpga_top_debug.core_def.io_host_ila_trigger = R [UHD_FINAL_CONDITIONS_LOGIC] LOGIC = OR -uvhs_ila +test0 diff --git a/fpga_diff/uvhs/uvhs.mk b/fpga_diff/uvhs/uvhs.mk index 785e2960..8ad06252 100644 --- a/fpga_diff/uvhs/uvhs.mk +++ b/fpga_diff/uvhs/uvhs.mk @@ -1,7 +1,6 @@ UVHS_ROOT_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))/..) UVHS_COMPILATION_DIR := $(UVHS_ROOT_DIR)/uvhs/compilation UVHS_RUNTIME_DIR := $(UVHS_ROOT_DIR)/uvhs/runtime -TRIGGER ?= $(UVHS_RUNTIME_DIR)/trigger.ini UVHS_TEMPLATE_DIR ?= UVHS_UVW_AXI4_TO_DDR4_SRC ?=