From 30a4b7fc2b0e3a85305518d521b7e0f05d018bdd Mon Sep 17 00:00:00 2001 From: Lars Amsel Date: Fri, 31 Jul 2026 10:25:02 -0500 Subject: [PATCH] fpga: x440: add 800 MHz images --- .../top/x400/x440_CG_800_rfnoc_image_core.yml | 19 ++++ .../top/x400/x440_X4_800_rfnoc_image_core.yml | 19 ++++ fpga/usrp3/top/x400/x4xx.sv | 90 +++++++++++++++++-- host/include/uhd/rfnoc/core/x440_bsp.yml | 10 ++- .../periph_manager/x4xx_clock_policy.py | 1 + 5 files changed, 129 insertions(+), 10 deletions(-) create mode 100644 fpga/usrp3/top/x400/x440_CG_800_rfnoc_image_core.yml create mode 100644 fpga/usrp3/top/x400/x440_X4_800_rfnoc_image_core.yml diff --git a/fpga/usrp3/top/x400/x440_CG_800_rfnoc_image_core.yml b/fpga/usrp3/top/x400/x440_CG_800_rfnoc_image_core.yml new file mode 100644 index 000000000..618d71e5e --- /dev/null +++ b/fpga/usrp3/top/x400/x440_CG_800_rfnoc_image_core.yml @@ -0,0 +1,19 @@ +# General parameters +# ----------------------------------------- +schema: rfnoc_imagebuilder_args # Identifier for the schema used to validate this file +copyright: >- # Copyright information used in file headers + Copyright 2026 Ettus Research, a National Instruments Brand +license: >- # License information used in file headers + SPDX-License-Identifier: LGPL-3.0-or-later +version: '1.0' # File version +chdr_width: 512 # Bit width of the CHDR bus for this image +device: 'x440' # USRP type +image_core_name: 'usrp_x440_fpga_CG_800' # Name to use for the generated output files +default_target: 'X440' # Default make target + +inherit: + - 'x440_CG_1600_rfnoc_image_core.yml' + +parameters: + RF_BW: 800 + ENABLE_CLOCK_WD: True # Enable 1GS/s limit for shipping bitfiles diff --git a/fpga/usrp3/top/x400/x440_X4_800_rfnoc_image_core.yml b/fpga/usrp3/top/x400/x440_X4_800_rfnoc_image_core.yml new file mode 100644 index 000000000..9bcb20de2 --- /dev/null +++ b/fpga/usrp3/top/x400/x440_X4_800_rfnoc_image_core.yml @@ -0,0 +1,19 @@ +# General parameters +# ----------------------------------------- +schema: rfnoc_imagebuilder_args # Identifier for the schema used to validate this file +copyright: >- # Copyright information used in file headers + Copyright 2026 Ettus Research, a National Instruments Brand +license: >- # License information used in file headers + SPDX-License-Identifier: LGPL-3.0-or-later +version: '1.0' # File version +chdr_width: 512 # Bit width of the CHDR bus for this image +device: 'x440' # USRP type +image_core_name: 'usrp_x440_fpga_X4_800' # Name to use for the generated output files +default_target: 'X440' # Default make target + +inherit: + - 'x440_X4_1600_rfnoc_image_core.yml' + +parameters: + RF_BW: 800 + ENABLE_CLOCK_WD: True # Enable 1GS/s limit for shipping bitfiles \ No newline at end of file diff --git a/fpga/usrp3/top/x400/x4xx.sv b/fpga/usrp3/top/x400/x4xx.sv index e29a603dd..bff9a8593 100644 --- a/fpga/usrp3/top/x400/x4xx.sv +++ b/fpga/usrp3/top/x400/x4xx.sv @@ -404,6 +404,8 @@ module x4xx ( wire data_clk_2x; wire [NUM_DBOARDS-1:0] radio_clk; wire [NUM_DBOARDS-1:0] radio_clk_2x; + wire [NUM_DBOARDS-1:0] rfdc_clk_fault; + wire data_clock_locked; // Low-power output clocks from PS to PL wire clk40; // 40.000 MHz @@ -611,6 +613,75 @@ module x4xx ( ); + //--------------------------------------------------------------------------- + // Clocking Watchdog + //--------------------------------------------------------------------------- + + // This is only defined for the products that support it, so define it to be + // disabled by default. + `ifndef ENABLE_CLOCK_WD + `define ENABLE_CLOCK_WD 0 + `endif + + if (`ENABLE_CLOCK_WD) begin : gen_clock_wd + // Mode-dependent max RFDC clock rate (in Hz) + // Maps sample rates to approximate rfdc_clk frequencies + // 125 MHz is the max rate for the RFDC interface clocks + localparam int MAX_RFDC_CLK_RATE = 1_000_000_000 / RFDC_SPC; + + wire mgt_refclk_i; + wire mgt_refclk_fabric; + wire mgt_refclk_fabric_rst; + + // The clocking watchdog needs a clock that cannot be changed by the PS. + // The LMK1 reference clock is a good choice since it is a fixed 100 MHz + // clock. + + // Instantiate the MGT Input Buffer + IBUFDS_GTE4 #( + .REFCLK_HROW_CK_SEL (2'b00) // Selects ODIV2 to be driven by I/IB + ) IBUFDS_GTE4_inst ( + .I (MGT_REFCLK_LMK1_P), + .IB (MGT_REFCLK_LMK1_N), + .CEB (1'b0), // Clock enable (active-low) + .O (), // Reserved for GT quad reference clock + .ODIV2 (mgt_refclk_i) // 100 MHz LMK1 + ); + + // Instantiate the GT Global Buffer + BUFG_GT BUFG_GT_inst ( + .I (mgt_refclk_i), + .CE (1'b1), + .CEMASK (1'b0), + .CLR (1'b0), + .DIV (3'b000), // No divide + .O (mgt_refclk_fabric) + ); + + // Synchronize areset into mgt_refclk_fabric domain + reset_sync reset_sync_mgt_refclk_fabric ( + .clk (mgt_refclk_fabric), + .reset_in (areset), + .reset_out (mgt_refclk_fabric_rst) + ); + + for (genvar db_i = 0; db_i < NUM_DBOARDS; db_i = db_i + 1) begin : gen_clocking_watchdog + clocking_watchdog #( + .MAX_CLOCK_RATE(MAX_RFDC_CLK_RATE), + .MONITOR_CLK_FREQ(100_000_000) // mgt_refclk_fabric is 100 MHz + ) rfdc_clocking_watchdog_i ( + .monitor_clk (mgt_refclk_fabric), + .rst (mgt_refclk_fabric_rst), + .clock_locked (data_clock_locked), + .watched_clk (rfdc_clk[db_i]), + .clock_fault (rfdc_clk_fault[db_i]) + ); + end + end else begin : gen_no_clock_wd + assign rfdc_clk_fault = '0; + end + + //--------------------------------------------------------------------------- // PPS Handling //--------------------------------------------------------------------------- @@ -1835,7 +1906,7 @@ module x4xx ( .tx_resampler_reset_pulse_dclk (tx_resampler_reset_pulse_dclk), .data_clk (data_clk), .data_clk_2x (data_clk_2x), - .data_clock_locked (), + .data_clock_locked (data_clock_locked), .enable_gated_clocks_clk40 (1'b1), .enable_sysref_r0clk (1'b1), .gated_base_clks_valid_clk40 (), @@ -3335,11 +3406,18 @@ module x4xx ( // the LSBs, whereas the interface of rf_core assumes that Q is in MSBs and I // is in the LSBs. Here we swap I and Q to match the ordering of each // interface. - genvar iq_i; - generate for ( iq_i = 0; iq_i < RADIO_SPC*NUM_CHANNELS; iq_i = iq_i + 1) begin : gen_iq_swap - assign rx_data_iq[iq_i*32 +: 32] = { rx_data_qi[iq_i*32 +: 16], rx_data_qi[iq_i*32+16 +: 16] }; - assign tx_data_qi[iq_i*32 +: 32] = { tx_data_iq[iq_i*32 +: 16], tx_data_iq[iq_i*32+16 +: 16] }; - end endgenerate + for (genvar db = 0; db < NUM_DBOARDS; db = db + 1) begin : gen_db + for (genvar ch = NUM_CH_PER_DB*db; ch < NUM_CH_PER_DB*(db+1); ch = ch + 1) begin : gen_ch + for (genvar iq_i = RADIO_SPC*ch; iq_i < RADIO_SPC*(ch+1); iq_i = iq_i + 1) begin : gen_iq_swap + assign rx_data_iq[iq_i*32 +: 32] = rfdc_clk_fault[db] ? '0 + : { rx_data_qi[iq_i*32 +: 16], + rx_data_qi[iq_i*32+16 +: 16] }; + assign tx_data_qi[iq_i*32 +: 32] = rfdc_clk_fault[db] ? '0 + : { tx_data_iq[iq_i*32 +: 16], + tx_data_iq[iq_i*32+16 +: 16] }; + end + end + end // Version information mapping // Each component consists of a 96-bit vector (refer to versioning_utils.vh) diff --git a/host/include/uhd/rfnoc/core/x440_bsp.yml b/host/include/uhd/rfnoc/core/x440_bsp.yml index 0b7afc6f5..f281a7209 100644 --- a/host/include/uhd/rfnoc/core/x440_bsp.yml +++ b/host/include/uhd/rfnoc/core/x440_bsp.yml @@ -4,7 +4,7 @@ family: ULTRASCALE parameters: RF_BW: 1600 - NUM_PORTS_PER_RADIO: ${ 1 if parameters['RF_BW'] == 1600 else 4 } + NUM_PORTS_PER_RADIO: ${ 1 if parameters['RF_BW'] in (800, 1600) else 4 } ENABLE_DRAM: False NUM_DRAM_BANKS: 0 NUM_DRAM_CHANS: 0 @@ -12,11 +12,12 @@ parameters: FP_GPIO_BANK_WIDTH: 12 USE_FABRIC_RESAMPLERS: False DISABLE_TX: False + ENABLE_CLOCK_WD: False RADIO_NIPC: "${ 2 if parameters['USE_FABRIC_RESAMPLERS'] else 8 }" checks: - - condition: ${int(parameters['RF_BW'] in [200, 400, 1600])} - message: "RF_BW must be one of 200, 400, 1600 (is: ${parameters['RF_BW']})." + - condition: ${int(parameters['RF_BW'] in [200, 400, 800, 1600])} + message: "RF_BW must be one of 200, 400, 800, 1600 (is: ${parameters['RF_BW']})." - condition: ${not parameters['ENABLE_DRAM'] or int(parameters['NUM_DRAM_BANKS']) in [1, 2]} message: "NUM_DRAM_BANKS must be 1 or 2 when enabling DRAM (is: ${parameters['NUM_DRAM_BANKS']})." - condition: ${int(parameters['DRAM_WIDTH'] in [64, 128, 512])} @@ -59,7 +60,7 @@ checks: The RADIO_NIPC value is not valid. The default values of RADIO_NIPC will be correct, so please remove the RADIO_NIPC parameter from the image core file. severity: error - - condition: ${ (parameters['NUM_PORTS_PER_RADIO'] == 1 and parameters['RF_BW'] == 1600) or (parameters['NUM_PORTS_PER_RADIO'] == 4 and parameters['RF_BW'] != 1600)} + - condition: ${ (parameters['NUM_PORTS_PER_RADIO'] == 1 and parameters['RF_BW'] in (800, 1600)) or (parameters['NUM_PORTS_PER_RADIO'] == 4 and parameters['RF_BW'] not in (800, 1600))} message: | The NUM_PORTS_PER_RADIO value is not valid. The default values of NUM_PORTS_PER_RADIO will be correct, so please remove the NUM_PORTS_PER_RADIO parameter from the image core file. @@ -75,6 +76,7 @@ make_defs: - DRAM_W=${parameters['DRAM_WIDTH']} - USE_FABRIC_RESAMPLERS=${1 if parameters['USE_FABRIC_RESAMPLERS'] else 0} - DISABLE_TX=${1 if parameters['DISABLE_TX'] else 0} + - ENABLE_CLOCK_WD=${1 if parameters['ENABLE_CLOCK_WD'] else 0} generate_dts: True dts_includes: diff --git a/mpm/python/usrp_mpm/periph_manager/x4xx_clock_policy.py b/mpm/python/usrp_mpm/periph_manager/x4xx_clock_policy.py index f83132770..55e7341db 100644 --- a/mpm/python/usrp_mpm/periph_manager/x4xx_clock_policy.py +++ b/mpm/python/usrp_mpm/periph_manager/x4xx_clock_policy.py @@ -380,6 +380,7 @@ class X440ClockPolicy(X4xxClockPolicy): bandwidth_to_default_mcr = { 200: 245.76e6, 400: 368.64e6, + 800: 368.64e6, 1600: 368.64e6, }