mpm/fpga: x4xx: Major updates in preparation for future devices

FPGA:
- Split up MB registers that control daughterboard specific settings so
  that daughterboards 0 and 1 could have different setings, in
  preparation for future devices that require different settings.
  This requires a compat number bump to 8.0.
- Add registers for additional RFDC information, including the
  block/tile mapping of the individual channels, and information about
  resampling capabilities
- Identify sections of code that would be specific to X410/ZBX and move
  them to their own headers, so it's trivial to add device-specific
  sections of code instead for other devices in the future.
  - This includes constraints for clocks and I/O pins.
- Remove ability to do timed ctrlport transactions to the MB CPLD, this
  was unused and possibly broken.
- Move daughterboard-specific code into its own code location
  (dboards/zbx)
- Move X410-specific register documentation to its own location
  (doc/X410)
- Refactor Makefiles to split out X410/ZBX specific components and allow
  switching between device types
- Add 512-bit AXI interconnects
- Make number of timekeepers configurable (X410 keeps the single
  timekeeper)

MPM:
- Required compat is bumped to 8.0
- Now supports new registers for detecting DSP capabilities and
  multi-rate settings for the daughterboards
- Adds MMCM controls (currently unused)

Co-authored-by: Wade Fife <wade.fife@ni.com>
Co-authored-by: Ryan Marlow <ryan@lmarlow.com>
Co-authored-by: Martin Braun <martin.braun@ettus.com>
Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com>


Original-commit: c1d268917ea65dd9c5a42366014cb96d3c025223
This commit is contained in:
Javier Valenzuela
2023-05-23 09:06:17 +02:00
committed by Martin Braun
co-authored by Wade Fife Ryan Marlow Martin Braun Humberto Jimenez
parent ffdcc016cc
commit adf6f576c6
79 changed files with 41079 additions and 2315 deletions
+9 -4
View File
@@ -98,8 +98,9 @@ module rf_core_100m (
// Control/status vectors from/to RFDC.
// Notice these are all in the s_axi_config_clk domain.
output wire [15:0] dsp_info_sclk,
output wire [9:0] dsp_info_sclk,
output wire [15:0] axi_status_sclk,
output wire [15:0] rfdc_info_sclk,
// Resets.
input wire adc_data_out_resetn_dclk,
@@ -114,8 +115,8 @@ module rf_core_100m (
output wire [95:0] version_info
);
`include "../../regmap/rfdc_regs_regmap_utils.vh"
`include "../../regmap/versioning_regs_regmap_utils.vh"
`include "../../regmap/x410/rfdc_regs_regmap_utils.vh"
`include "../../regmap/x410/versioning_regs_regmap_utils.vh"
`include "../../regmap/versioning_utils.vh"
// Fixed for this implementation.
@@ -177,10 +178,14 @@ module rf_core_100m (
);
// Drive the DSP info vector with information on this specific DSP chain.
assign dsp_info_sclk[FABRIC_DSP_BW_MSB :FABRIC_DSP_BW] = FABRIC_DSP_BW_100M;
assign dsp_info_sclk[FABRIC_DSP_RX_CNT_MSB:FABRIC_DSP_RX_CNT] = NUM_ADC_CHANNELS;
assign dsp_info_sclk[FABRIC_DSP_TX_CNT_MSB:FABRIC_DSP_TX_CNT] = NUM_DAC_CHANNELS;
// This RF core always consumes 2 SPC from the gearbox per I/Q signal
assign rfdc_info_sclk[RFDC_INFO_SPC_RX_MSB:RFDC_INFO_SPC_RX] = $clog2(2);
assign rfdc_info_sclk[RFDC_INFO_SPC_TX_MSB:RFDC_INFO_SPC_TX] = $clog2(4);
assign rfdc_info_sclk[RFDC_INFO_XTRA_RESAMP_MSB:RFDC_INFO_XTRA_RESAMP] = 4'd3;
//---------------------------------------------------------------------------
// ADC Post-Processing
//---------------------------------------------------------------------------
+9 -7
View File
@@ -89,8 +89,9 @@ module rf_core_200m (
// Control/status vectors from/to RFDC.
// Notice these are all in the s_axi_config_clk domain.
output reg [15:0] dsp_info_sclk,
output wire [9:0] dsp_info_sclk,
output wire [15:0] axi_status_sclk,
output wire [15:0] rfdc_info_sclk,
// Resets.
input wire adc_data_out_resetn_dclk,
@@ -105,7 +106,7 @@ module rf_core_200m (
output wire [95:0] version_info
);
`include "../../regmap/rfdc_regs_regmap_utils.vh"
`include "../../regmap/x410/rfdc_regs_regmap_utils.vh"
//---------------------------------------------------------------------------
// 400 MHz RF Core
@@ -170,11 +171,12 @@ module rf_core_200m (
.version_info (version_info)
);
// Change reported bandwidth 200 MHz
always @(*) begin
dsp_info_sclk <= dsp_info_sclk_400m;
dsp_info_sclk[FABRIC_DSP_BW_MSB : FABRIC_DSP_BW] <= FABRIC_DSP_BW_200M;
end
assign dsp_info_sclk = dsp_info_sclk_400m;
// This RF core always consumes 8 SPC from the gearbox per I/Q signal
assign rfdc_info_sclk[RFDC_INFO_SPC_RX_MSB:RFDC_INFO_SPC_RX] = $clog2(8);
assign rfdc_info_sclk[RFDC_INFO_SPC_TX_MSB:RFDC_INFO_SPC_TX] = $clog2(16);
assign rfdc_info_sclk[RFDC_INFO_XTRA_RESAMP_MSB:RFDC_INFO_XTRA_RESAMP] = 4'd6;
//---------------------------------------------------------------------------
+9 -4
View File
@@ -101,8 +101,9 @@ module rf_core_400m (
// Control/status vectors from/to RFDC.
// Notice these are all in the s_axi_config_clk domain.
output wire [15:0] dsp_info_sclk,
output wire [9:0] dsp_info_sclk,
output wire [15:0] axi_status_sclk,
output wire [15:0] rfdc_info_sclk,
// Resets.
input wire adc_data_out_resetn_dclk,
@@ -117,8 +118,8 @@ module rf_core_400m (
output wire [95:0] version_info
);
`include "../../regmap/rfdc_regs_regmap_utils.vh"
`include "../../regmap/versioning_regs_regmap_utils.vh"
`include "../../regmap/x410/rfdc_regs_regmap_utils.vh"
`include "../../regmap/x410/versioning_regs_regmap_utils.vh"
`include "../../regmap/versioning_utils.vh"
// Fixed for this implementation
@@ -181,10 +182,14 @@ module rf_core_400m (
);
// Drive the DSP info vector with information on this specific DSP chain.
assign dsp_info_sclk[FABRIC_DSP_BW_MSB :FABRIC_DSP_BW] = FABRIC_DSP_BW_400M;
assign dsp_info_sclk[FABRIC_DSP_RX_CNT_MSB:FABRIC_DSP_RX_CNT] = NUM_ADC_CHANNELS;
assign dsp_info_sclk[FABRIC_DSP_TX_CNT_MSB:FABRIC_DSP_TX_CNT] = NUM_DAC_CHANNELS;
// This RF core always consumes 8 SPC from the gearbox per I/Q signal
assign rfdc_info_sclk[RFDC_INFO_SPC_RX_MSB:RFDC_INFO_SPC_RX] = $clog2(8);
assign rfdc_info_sclk[RFDC_INFO_SPC_TX_MSB:RFDC_INFO_SPC_TX] = $clog2(16);
assign rfdc_info_sclk[RFDC_INFO_XTRA_RESAMP_MSB:RFDC_INFO_XTRA_RESAMP] = 4'd3;
//---------------------------------------------------------------------------
// ADC Post-Processing
//---------------------------------------------------------------------------
+5 -2
View File
@@ -8,11 +8,14 @@ RF_COMMON_SRCS = $(abspath $(addprefix $(BASE_DIR)/../top/x400/rf/common/, \
PkgRf.vhd \
axis_mux.vhd \
capture_sysref.v \
clock_gates.vhd \
gpio_to_axis_mux.vhd \
rf_nco_reset.vhd \
rf_reset.vhd \
rf_reset_controller.vhd \
scale_2x.vhd \
sync_wrapper.v \
))
RF_X410_SRCS = $(abspath $(addprefix $(BASE_DIR)/../top/x400/rf/x410/, \
x410_rf_reset_controller.vhd \
x410_clock_gates.vhd \
))
+12 -3
View File
@@ -7,8 +7,15 @@
//
// Description:
//
// Capture SYSREF and transfer it to the higher clock domain. Module incurs
// in 2 pll_ref_clk cycles + 1 rfdc_clk cycle of delay.
// Capture SYSREF and transfer it to the higher clock domain.
// For X410, module incurs in 2 pll_ref_clk cycles + 1 rfdc_clk
// cycle of delay. For X440, module synchronizes to each
// pll_ref_clk and rfdc_clk separately, incurring in 2 cycles
// for each clock.
//
// Parameters:
//
// DEVICE_TYPE : Type of device for which SYSREF is synchronized.
//
module capture_sysref (
@@ -25,7 +32,9 @@ module capture_sysref (
output wire sysref_out_rclk // RFDC output (Domain: rfdc_clk).
);
reg sysref_pclk_ms = 1'b0, sysref_pclk = 1'b0, sysref_rclk = 1'b0;
(* ASYNC_REG = "TRUE" *) reg sysref_pclk_ms = 1'b0;
reg sysref_pclk = 1'b0;
reg sysref_rclk = 1'b0;
// Capture SYSREF synchronously with the pll_ref_clk, but double-sync it just
// in case static timing isn't met so as not to destroy downstream logic.
+101 -6
View File
@@ -1,5 +1,5 @@
--
-- Copyright 2021 Ettus Research, a National Instruments Brand
-- Copyright 2022 Ettus Research, a National Instruments Brand
--
-- SPDX-License-Identifier: LGPL-3.0-or-later
--
@@ -38,8 +38,6 @@ entity gpio_to_axis_mux is
-- mux_select(n) chooses the data source for AXIS interface n.
-- '0' chooses s_axis_tdata_n. '1' chooses gpio as the data source.
-- The only used bits are 0, 1, 4, 5. The remaining bits are reserved for
-- future expansion.
mux_select : in std_logic_vector(7 downto 0);
s_axis_0_aclk : in std_logic;
@@ -72,7 +70,39 @@ entity gpio_to_axis_mux is
s_axis_tready_3 : out std_logic;
m_axis_3_aclk : in std_logic;
m_axis_tvalid_3 : out std_logic;
m_axis_tdata_3 : out std_logic_vector(kAxiWidth - 1 downto 0)
m_axis_tdata_3 : out std_logic_vector(kAxiWidth - 1 downto 0);
s_axis_4_aclk : in std_logic;
s_axis_tdata_4 : in std_logic_vector(kAxiWidth - 1 downto 0);
s_axis_tvalid_4 : in std_logic;
s_axis_tready_4 : out std_logic;
m_axis_4_aclk : in std_logic;
m_axis_tvalid_4 : out std_logic;
m_axis_tdata_4 : out std_logic_vector(kAxiWidth - 1 downto 0);
s_axis_5_aclk : in std_logic;
s_axis_tdata_5 : in std_logic_vector(kAxiWidth - 1 downto 0);
s_axis_tvalid_5 : in std_logic;
s_axis_tready_5 : out std_logic;
m_axis_5_aclk : in std_logic;
m_axis_tvalid_5 : out std_logic;
m_axis_tdata_5 : out std_logic_vector(kAxiWidth - 1 downto 0);
s_axis_6_aclk : in std_logic;
s_axis_tdata_6 : in std_logic_vector(kAxiWidth - 1 downto 0);
s_axis_tvalid_6 : in std_logic;
s_axis_tready_6 : out std_logic;
m_axis_6_aclk : in std_logic;
m_axis_tvalid_6 : out std_logic;
m_axis_tdata_6 : out std_logic_vector(kAxiWidth - 1 downto 0);
s_axis_7_aclk : in std_logic;
s_axis_tdata_7 : in std_logic_vector(kAxiWidth - 1 downto 0);
s_axis_tvalid_7 : in std_logic;
s_axis_tready_7 : out std_logic;
m_axis_7_aclk : in std_logic;
m_axis_tvalid_7 : out std_logic;
m_axis_tdata_7 : out std_logic_vector(kAxiWidth - 1 downto 0)
);
end entity;
@@ -118,7 +148,7 @@ begin
kAxiWidth => kAxiWidth)
port map (
gpio => gpio,
mux_select => mux_select(4),
mux_select => mux_select(2),
s_axis_aclk => s_axis_2_aclk,
s_axis_tdata => s_axis_tdata_2,
s_axis_tvalid => s_axis_tvalid_2,
@@ -134,7 +164,7 @@ begin
kAxiWidth => kAxiWidth)
port map (
gpio => gpio,
mux_select => mux_select(5),
mux_select => mux_select(3),
s_axis_aclk => s_axis_3_aclk,
s_axis_tdata => s_axis_tdata_3,
s_axis_tvalid => s_axis_tvalid_3,
@@ -144,4 +174,69 @@ begin
m_axis_tdata => m_axis_tdata_3
);
axis_mux4: entity work.axis_mux (RTL)
generic map (
kGpioWidth => kGpioWidth,
kAxiWidth => kAxiWidth)
port map (
gpio => gpio,
mux_select => mux_select(4),
s_axis_aclk => s_axis_4_aclk,
s_axis_tdata => s_axis_tdata_4,
s_axis_tvalid => s_axis_tvalid_4,
s_axis_tready => s_axis_tready_4,
m_axis_aclk => m_axis_4_aclk,
m_axis_tvalid => m_axis_tvalid_4,
m_axis_tdata => m_axis_tdata_4
);
axis_mux5: entity work.axis_mux (RTL)
generic map (
kGpioWidth => kGpioWidth,
kAxiWidth => kAxiWidth)
port map (
gpio => gpio,
mux_select => mux_select(5),
s_axis_aclk => s_axis_5_aclk,
s_axis_tdata => s_axis_tdata_5,
s_axis_tvalid => s_axis_tvalid_5,
s_axis_tready => s_axis_tready_5,
m_axis_aclk => m_axis_5_aclk,
m_axis_tvalid => m_axis_tvalid_5,
m_axis_tdata => m_axis_tdata_5
);
axis_mux6: entity work.axis_mux (RTL)
generic map (
kGpioWidth => kGpioWidth,
kAxiWidth => kAxiWidth)
port map (
gpio => gpio,
mux_select => mux_select(6),
s_axis_aclk => s_axis_6_aclk,
s_axis_tdata => s_axis_tdata_6,
s_axis_tvalid => s_axis_tvalid_6,
s_axis_tready => s_axis_tready_6,
m_axis_aclk => m_axis_6_aclk,
m_axis_tvalid => m_axis_tvalid_6,
m_axis_tdata => m_axis_tdata_6
);
axis_mux7: entity work.axis_mux (RTL)
generic map (
kGpioWidth => kGpioWidth,
kAxiWidth => kAxiWidth)
port map (
gpio => gpio,
mux_select => mux_select(7),
s_axis_aclk => s_axis_7_aclk,
s_axis_tdata => s_axis_tdata_7,
s_axis_tvalid => s_axis_tvalid_7,
s_axis_tready => s_axis_tready_7,
m_axis_aclk => m_axis_7_aclk,
m_axis_tvalid => m_axis_tvalid_7,
m_axis_tdata => m_axis_tdata_7
);
end RTL;
+20 -1
View File
@@ -59,6 +59,13 @@ entity rf_nco_reset is
cAdc0xNcoUpdateBusy : in std_logic;
cAdc0xNcoUpdateReq : out std_logic := '0';
-----------------------------------
--ADC Tile 225
-----------------------------------
-- ADC common NCO update controls and status.
cAdc1xNcoUpdateBusy : in std_logic;
cAdc1xNcoUpdateReq : out std_logic := '0';
-----------------------------------
--ADC Tile 226
-----------------------------------
@@ -66,6 +73,13 @@ entity rf_nco_reset is
cAdc2xNcoUpdateBusy : in std_logic;
cAdc2xNcoUpdateReq : out std_logic := '0';
-----------------------------------
--ADC Tile 227
-----------------------------------
-- ADC common NCO update controls and status.
cAdc3xNcoUpdateBusy : in std_logic;
cAdc3xNcoUpdateReq : out std_logic := '0';
-- NCO reset can be initiated only when cNcoPhaseRst is set to '1' and
-- cNcoUpdateEn = 0x20. The FSM in this entity will set these values when
-- an NCO reset is initiated during synchronization. These ports are common
@@ -146,7 +160,9 @@ begin
cDac0xSysrefIntReenable <= '0';
cDac1xNcoUpdateReq <= '0';
cAdc0xNcoUpdateReq <= '0';
cAdc1xNcoUpdateReq <= '0';
cAdc2xNcoUpdateReq <= '0';
cAdc3xNcoUpdateReq <= '0';
case cResetState is
-- Stay in this state until NCO reset sequence is initiated. NCO reset
-- is initiated only on the rising edge of SYSREF.
@@ -177,7 +193,9 @@ begin
cResetState <= CheckUpdateDone;
cDac1xNcoUpdateReq <= '1';
cAdc0xNcoUpdateReq <= '1';
cAdc1xNcoUpdateReq <= '1';
cAdc2xNcoUpdateReq <= '1';
cAdc3xNcoUpdateReq <= '1';
end if;
-- In this state, we check if the RFDC block is ready for NCO reset.
@@ -187,7 +205,8 @@ begin
cSysrefIntGating <= '1';
cResetState <= CheckUpdateDone;
if cDac0xNcoUpdateBusy = "10" and cAdc0xNcoUpdateBusy = '0' and
cAdc2xNcoUpdateBusy = '0' and cDac1xNcoUpdateBusy = '0' and
cAdc1xNcoUpdateBusy = '0' and cAdc2xNcoUpdateBusy = '0' and
cAdc3xNcoUpdateBusy = '0' and cDac1xNcoUpdateBusy = '0' and
cSysref = '1' and cSysrefDlyd = '0' then
cDac0xSysrefIntReenable <= '1';
cResetState <= CheckResetDone;
+14 -13
View File
@@ -36,8 +36,9 @@ include ../200m/Makefile.srcs
include ../400m/Makefile.srcs
DESIGN_SRCS += $(abspath \
../../regmap/PkgRFDC_REGS_REGMAP.vhd \
../../regmap/x410/PkgRFDC_REGS_REGMAP.vhd \
$(RF_COMMON_SRCS) \
$(RF_X410_SRCS) \
$(RF_100M_SRCS) \
$(RF_200M_SRCS) \
$(RF_400M_SRCS) \
@@ -68,18 +69,18 @@ SIM_TOP = rf_all_tb
SIM_RUNTIME_US = 1000
SIM_SRCS = \
$(abspath tb_adc_gearbox_2x1.vhd ) \
$(abspath tb_adc_gearbox_2x4.vhd ) \
$(abspath tb_adc_gearbox_8x4.vhd ) \
$(abspath tb_capture_sysref.vhd ) \
$(abspath tb_dac_gearbox_12x8.vhd ) \
$(abspath tb_dac_gearbox_4x2.vhd ) \
$(abspath tb_dac_gearbox_6x12.vhd ) \
$(abspath tb_ddc_400m_saturate.vhd ) \
$(abspath tb_duc_400m_saturate.vhd ) \
$(abspath tb_rf_nco_reset.vhd ) \
$(abspath tb_rf_reset_controller.vhd) \
$(abspath rf_all_tb.sv ) \
$(abspath tb_adc_gearbox_2x1.vhd ) \
$(abspath tb_adc_gearbox_2x4.vhd ) \
$(abspath tb_adc_gearbox_8x4.vhd ) \
$(abspath tb_capture_sysref.vhd ) \
$(abspath tb_dac_gearbox_12x8.vhd ) \
$(abspath tb_dac_gearbox_4x2.vhd ) \
$(abspath tb_dac_gearbox_6x12.vhd ) \
$(abspath tb_ddc_400m_saturate.vhd ) \
$(abspath tb_duc_400m_saturate.vhd ) \
$(abspath tb_rf_nco_reset.vhd ) \
$(abspath tb_x410_rf_reset_controller.vhd ) \
$(abspath rf_all_tb.sv ) \
#-------------------------------------------------
# Bottom-of-Makefile
+22 -22
View File
@@ -15,17 +15,17 @@ module rf_all_tb;
`include "test_exec.svh"
import PkgTestExec::*;
tb_adc_gearbox_2x1 tb_adc_gearbox_2x1_i ();
tb_adc_gearbox_2x4 tb_adc_gearbox_2x4_i ();
tb_adc_gearbox_8x4 tb_adc_gearbox_8x4_i ();
tb_capture_sysref tb_capture_sysref_i ();
tb_dac_gearbox_12x8 tb_dac_gearbox_12x8_i ();
tb_dac_gearbox_4x2 tb_dac_gearbox_4x2_i ();
tb_dac_gearbox_6x12 tb_dac_gearbox_6x12_i ();
tb_ddc_400m_saturate tb_ddc_400m_saturate_i ();
tb_duc_400m_saturate tb_duc_400m_saturate_i ();
tb_rf_nco_reset tb_rf_nco_reset_i ();
tb_rf_reset_controller tb_rf_reset_controller_i ();
tb_adc_gearbox_2x1 tb_adc_gearbox_2x1_i ();
tb_adc_gearbox_2x4 tb_adc_gearbox_2x4_i ();
tb_adc_gearbox_8x4 tb_adc_gearbox_8x4_i ();
tb_capture_sysref tb_capture_sysref_i ();
tb_dac_gearbox_12x8 tb_dac_gearbox_12x8_i ();
tb_dac_gearbox_4x2 tb_dac_gearbox_4x2_i ();
tb_dac_gearbox_6x12 tb_dac_gearbox_6x12_i ();
tb_ddc_400m_saturate tb_ddc_400m_saturate_i ();
tb_duc_400m_saturate tb_duc_400m_saturate_i ();
tb_rf_nco_reset tb_rf_nco_reset_i ();
tb_x410_rf_reset_controller tb_x410_rf_reset_controller_i ();
initial begin
test.start_tb("rf_all_tb", 1ms);
@@ -34,17 +34,17 @@ module rf_all_tb;
forever begin
#100ns;
if (
tb_adc_gearbox_2x1_i.StopSim &&
tb_adc_gearbox_2x4_i.StopSim &&
tb_adc_gearbox_8x4_i.StopSim &&
tb_capture_sysref_i.StopSim &&
tb_dac_gearbox_12x8_i.StopSim &&
tb_dac_gearbox_4x2_i.StopSim &&
tb_dac_gearbox_6x12_i.StopSim &&
tb_ddc_400m_saturate_i.StopSim &&
tb_duc_400m_saturate_i.StopSim &&
tb_rf_nco_reset_i.StopSim &&
tb_rf_reset_controller_i.StopSim
tb_adc_gearbox_2x1_i.StopSim &&
tb_adc_gearbox_2x4_i.StopSim &&
tb_adc_gearbox_8x4_i.StopSim &&
tb_capture_sysref_i.StopSim &&
tb_dac_gearbox_12x8_i.StopSim &&
tb_dac_gearbox_4x2_i.StopSim &&
tb_dac_gearbox_6x12_i.StopSim &&
tb_ddc_400m_saturate_i.StopSim &&
tb_duc_400m_saturate_i.StopSim &&
tb_rf_nco_reset_i.StopSim &&
tb_x410_rf_reset_controller_i.StopSim
) break;
end
test.end_test();
+12
View File
@@ -21,7 +21,9 @@ end tb_rf_nco_reset;
architecture RTL of tb_rf_nco_reset is
signal cAdc0xNcoUpdateReq : std_logic;
signal cAdc1xNcoUpdateReq : std_logic;
signal cAdc2xNcoUpdateReq : std_logic;
signal cAdc3xNcoUpdateReq : std_logic;
signal cDac0xNcoUpdateReq : std_logic;
signal cDac0xSysrefIntGating : std_logic;
signal cDac0xSysrefIntReenable : std_logic;
@@ -33,7 +35,9 @@ architecture RTL of tb_rf_nco_reset is
signal cDac0xNcoUpdateBusy : std_logic_vector(1 downto 0) := "00";
signal dStartNcoReset : std_logic := '0';
signal cAdc0xNcoUpdateBusy : std_logic := '0';
signal cAdc1xNcoUpdateBusy : std_logic := '0';
signal cAdc2xNcoUpdateBusy : std_logic := '0';
signal cAdc3xNcoUpdateBusy : std_logic := '0';
signal cDac1xNcoUpdateBusy : std_logic := '0';
signal cSysref_ms, cSysref : std_logic := '0';
@@ -100,8 +104,12 @@ begin
cDac1xNcoUpdateReq => cDac1xNcoUpdateReq,
cAdc0xNcoUpdateBusy => cAdc0xNcoUpdateBusy,
cAdc0xNcoUpdateReq => cAdc0xNcoUpdateReq,
cAdc1xNcoUpdateBusy => cAdc1xNcoUpdateBusy,
cAdc1xNcoUpdateReq => cAdc1xNcoUpdateReq,
cAdc2xNcoUpdateBusy => cAdc2xNcoUpdateBusy,
cAdc2xNcoUpdateReq => cAdc2xNcoUpdateReq,
cAdc3xNcoUpdateBusy => cAdc3xNcoUpdateBusy,
cAdc3xNcoUpdateReq => cAdc3xNcoUpdateReq,
cNcoPhaseRst => cNcoPhaseRst,
cNcoUpdateEn => cNcoUpdateEn,
dNcoResetDone => dNcoResetDone
@@ -180,7 +188,9 @@ begin
cRfdcNcoState <= CheckUpdate;
cDac1xNcoUpdateBusy <= cDac1xNcoUpdateReq;
cAdc0xNcoUpdateBusy <= cAdc0xNcoUpdateReq;
cAdc1xNcoUpdateBusy <= cAdc1xNcoUpdateReq;
cAdc2xNcoUpdateBusy <= cAdc2xNcoUpdateReq;
cAdc3xNcoUpdateBusy <= cAdc3xNcoUpdateReq;
-- It takes 5 clock cycles to update each RFDC internal registers with
-- the used request change. In rf_nco_reset entity, we only want to
@@ -194,7 +204,9 @@ begin
cDac0xNcoUpdateBusy <= "10"; --Indicates that SYSREF is gated.
cDac1xNcoUpdateBusy <= '0';
cAdc0xNcoUpdateBusy <= '0';
cAdc1xNcoUpdateBusy <= '0';
cAdc2xNcoUpdateBusy <= '0';
cAdc3xNcoUpdateBusy <= '0';
end if;
cWrCount <= cWrCount + 1;
@@ -3,11 +3,11 @@
--
-- SPDX-License-Identifier: LGPL-3.0-or-later
--
-- Module: tb_rf_reset_controller
-- Module: tb_x410_rf_reset_controller
--
-- Description:
--
-- Testbench for rf_reset_controller.
-- Testbench for x410_rf_reset_controller.
--
library IEEE;
@@ -17,13 +17,13 @@ library IEEE;
library WORK;
use WORK.PkgRFDC_REGS_REGMAP.all;
entity tb_rf_reset_controller is
end tb_rf_reset_controller;
entity tb_x410_rf_reset_controller is
end tb_x410_rf_reset_controller;
architecture RTL of tb_rf_reset_controller is
architecture RTL of tb_x410_rf_reset_controller is
component rf_reset_controller
component x410_rf_reset_controller
port (
ConfigClk : in std_logic;
DataClk : in std_logic;
@@ -185,7 +185,7 @@ begin
PllRefClk <= not PllRefClk after kPllRefClkPer/2 when not StopSim else '0';
-- rAdcEnableData is a constant and is not tested.
dut: rf_reset_controller
dut: x410_rf_reset_controller
port map (
ConfigClk => ConfigClk,
DataClk => DataClk,
+300
View File
@@ -0,0 +1,300 @@
--
-- Copyright 2021 Ettus Research, a National Instruments Brand
--
-- SPDX-License-Identifier: LGPL-3.0-or-later
--
-- Module: x410_clock_gates
--
-- Description:
--
-- Gate propagation of DataClk and RfdcClk instances until the PLL lock
-- status signal is stable and software has acknowledged it by asserting the
-- pertinent controls.
--
-- RfdcClks are used on other Xilinx IP components in the Board Design, and
-- Vivado fails to detect their frequency correctly their buffer is
-- explicitly instantiated in the Block Design. Therefore, we only generate
-- the buffer enable signals for these clocks within this component.
--
-- Since DataClk are only used in other Custom IP blocks within the Block
-- design, it is possible to instantiate the clock buffers within this block
-- for without running into IP generation failures.
--
-- Parameters:
--
-- kReliableClkPeriodNs: Clock period (ns) for ReliableClk.
--
library IEEE;
use IEEE.std_logic_1164.ALL;
use IEEE.numeric_std.ALL;
library UNISIM;
use UNISIM.Vcomponents.ALL;
library WORK;
use WORK.PkgRFDC_REGS_REGMAP.all;
entity x410_clock_gates is
generic (
kReliableClkPeriodNs : integer := 25
);
port (
-- MMCM reset
-- This clock will be asserted via AXI access before any clocking
-- configuration done, signals coming into this component will not change
-- immediately after this reset is de-asserted.
rPllReset_n : in std_logic;
aPllLocked : in std_logic;
-- Input Clocks (from MMCM)
ReliableClk : in std_logic;
DataClk1xPll : in std_logic;
DataClk2xPll : in std_logic;
-- Buffered Clock Outputs (to design)
DataClk1x : out std_logic;
DataClk2x : out std_logic;
-- Buffers for these signals must be instantiated on Block design for clock
-- rates to be identified. The Utility Buffers instantiated on the Block
-- Design require signals to be of type std_logic_vector.
aEnableRfBufg1x : out std_logic_vector(0 downto 0);
aEnableRfBufg2x : out std_logic_vector(0 downto 0);
-- PLL Status Signals
rPllLocked : out std_logic;
-- Window Interface
rSafeToEnableGatedClks : in std_logic;
rGatedBaseClksValid : out std_logic;
-- AXI GPIO interface
rSoftwareControl : in std_logic_vector(31 downto 0);
rSoftwareStatus : out std_logic_vector(31 downto 0)
);
end x410_clock_gates;
architecture STRUCT of x410_clock_gates is
component sync_wrapper
generic (
WIDTH : integer := 1;
STAGES : integer := 2;
INITIAL_VAL : integer := 0;
FALSE_PATH_TO_IN : integer := 1);
port (
clk : in std_logic;
rst : in std_logic;
signal_in : in std_logic_vector((WIDTH-1) downto 0);
signal_out : out std_logic_vector((WIDTH-1) downto 0));
end component;
component BUFGCE
generic(
CE_TYPE : string);
port (
O : out std_ulogic;
CE : in std_ulogic;
I : in std_ulogic);
end component;
-- UltraScale MMCM max lock time = 100 us / 25 ns = 4,000 clk cycles. If the
-- division kPllLockTimeNs / kReliableClkPeriodNs does not evaluate to an
-- integer, Vivado could either round up or down. In case they round down, we
-- add '1' to the result to ensure we have the full lock time accounted for.
-- In this case, it is better to count 1 more than necessary than kill the
-- process prematurely.
constant kPllLockTimeNs : integer := 100000;
constant kMaxPllLockCount : integer := kPllLockTimeNs / kReliableClkPeriodNs + 1;
signal rLockedFilterCount : integer range 0 to kMaxPllLockCount-1 := kMaxPllLockCount-1;
signal rClearDataClkUnlockedSticky : std_logic;
-----------------------------------------------------------------------------
-- PLL locked signals
-----------------------------------------------------------------------------
-- Synchronizer signals
signal aPllLockedLcl : std_logic_vector(0 downto 0);
signal rPllLockedDs : std_logic_vector(0 downto 0) := (others => '0');
-- Lock status indicators
signal rPllLockedLcl : std_logic := '0';
signal rPllUnlockedSticky : std_logic := '0';
-- Safe BUFG enable signals
signal rEnableDataClk1x,
rEnableDataClk2x,
rEnableRfdcClk1x,
rEnableRfdcClk2x : std_logic;
signal rEnableDataBufg1x : std_logic := '0';
signal rEnableDataBufg2x : std_logic := '0';
signal rEnableRfdcBufg1xLcl : std_logic := '0';
signal rEnableRfdcBufg2xLcl : std_logic := '0';
-- Active high version of reset required for synchronizer blocks.
signal rPllReset : std_logic;
-- Since these signals control sensitive components (clock enables), we apply
-- a dont_touch attribute to preserve the signals through both synthesis and
-- P&R. Implementation of "dont_touch" has been confirmed after P&R.
attribute dont_touch : string;
attribute dont_touch of rEnableDataBufg1x : signal is "TRUE";
attribute dont_touch of rEnableDataBufg2x : signal is "TRUE";
attribute dont_touch of aEnableRfBufg1x : signal is "TRUE";
attribute dont_touch of aEnableRfBufg2x : signal is "TRUE";
attribute X_INTERFACE_INFO : string;
attribute X_INTERFACE_PARAMETER : string;
attribute X_INTERFACE_INFO of DataClk1xPll : signal is
"xilinx.com:signal:clock:1.0 DataClk1xPll CLK";
attribute X_INTERFACE_INFO of DataClk2xPll : signal is
"xilinx.com:signal:clock:1.0 DataClk2xPll CLK";
begin
rPllReset <= not rPllReset_n;
-- Assert rGatedBaseClksValid once the PLL has been locked for the specified
-- time.
rGatedBaseClksValid <= rPllLockedLcl;
DataClkEnables : process(ReliableClk)
begin
if rising_edge(ReliableClk) then
if rPllReset_n = '0' then
rEnableDataBufg1x <= '0';
rEnableDataBufg2x <= '0';
rEnableRfdcBufg1xLcl <= '0';
rEnableRfdcBufg2xLcl <= '0';
else
rEnableDataBufg1x <=
rSafeToEnableGatedClks and
rEnableDataClk1x and
(not rPllUnlockedSticky);
rEnableDataBufg2x <=
rSafeToEnableGatedClks and
rEnableDataClk2x and
(not rPllUnlockedSticky);
rEnableRfdcBufg1xLcl <=
rSafeToEnableGatedClks and
rEnableRfdcClk1x and
(not rPllUnlockedSticky);
rEnableRfdcBufg2xLcl <=
rSafeToEnableGatedClks and
rEnableRfdcClk2x and
(not rPllUnlockedSticky);
end if;
end if;
end process DataClkEnables;
aEnableRfBufg1x(0) <= rEnableRfdcBufg1xLcl;
aEnableRfBufg2x(0) <= rEnableRfdcBufg2xLcl;
DataClk1xSafeBufg: BUFGCE
generic map(
CE_TYPE => "ASYNC"
)
port map (
I => DataClk1xPll,
CE => rEnableDataBufg1x,
O => DataClk1x
);
DataClk2xSafeBufg: BUFGCE
generic map(
CE_TYPE => "ASYNC"
)
port map (
I => DataClk2xPll,
CE => rEnableDataBufg2x,
O => DataClk2x
);
-----------------------------------------------------------------------------
-- Create PLL Lock Signal
-----------------------------------------------------------------------------
-- Double-sync the incoming aPllLocked signal from the PLL.
aPllLockedLcl(0) <= aPllLocked;
DataClkPllLockedDS: sync_wrapper
generic map (
WIDTH => 1,
STAGES => open,
INITIAL_VAL => open,
FALSE_PATH_TO_IN => open)
port map (
clk => ReliableClk,
rst => rPllReset,
signal_in => aPllLockedLcl,
signal_out => rPllLockedDs
);
-- Filter the Lock signal. Assert a lock when the PLL lock signal has been
-- asserted for kPllLockTimeNs
--
-- !!! SAFE COUNTER STARTUP !!!
-- rLockedFilterCount cannot start incrementing until rPllReset_n is
-- de-asserted. Once rPllReset_n is de-asserted through a AXI access, input
-- values for the registers in this state machine will not change until the
-- MMCM locks and the double synchronizer reflects a locked status, making
-- this start-up safe.
PllLockFilter: process (ReliableClk)
begin
if rising_edge(ReliableClk) then
if rPllReset_n = '0' then
rLockedFilterCount <= kMaxPllLockCount-1;
rPllLockedLcl <= '0';
else
if rPllLockedDs(0) = '1' then
if rLockedFilterCount = 0 then
rPllLockedLcl <= '1';
else
rPllLockedLcl <= '0';
rLockedFilterCount <= rLockedFilterCount - 1;
end if;
else
rLockedFilterCount <= kMaxPllLockCount-1;
rPllLockedLcl <= '0';
end if;
end if;
end if;
end process PllLockFilter;
-- Sticky bit to hold '1' if PLL ever comes unlocked
PllStickyBit: process (ReliableClk)
begin
if rising_edge(ReliableClk) then
if (not rPllReset_n or rClearDataClkUnlockedSticky) = '1' then
rPllUnlockedSticky <= '0';
else
if rPllLockedLcl = '1' and rPllLockedDs(0) = '0' then
rPllUnlockedSticky <= '1';
end if;
end if;
end if;
end process;
rPllLocked <= rPllLockedLcl;
-- AXI transaction decoding
rClearDataClkUnlockedSticky <= rSoftwareControl(kCLEAR_DATA_CLK_UNLOCKED);
rEnableDataClk1x <= rSoftwareControl(kENABLE_DATA_CLK);
rEnableDataClk2x <= rSoftwareControl(kENABLE_DATA_CLK_2X);
rEnableRfdcClk1x <= rSoftwareControl(kENABLE_RF_CLK);
rEnableRfdcClk2x <= rSoftwareControl(kENABLE_RF_CLK_2X);
rSoftwareStatus(kDATA_CLK_PLL_LOCKED) <= rPllLockedLcl;
rSoftwareStatus(kDATA_CLK_PLL_UNLOCKED_STICKY) <= rPllUnlockedSticky;
end STRUCT;
@@ -0,0 +1,208 @@
--
-- Copyright 2021 Ettus Research, a National Instruments Brand
--
-- SPDX-License-Identifier: LGPL-3.0-or-later
--
-- Module: x410_rf_reset_controller
--
-- Description:
--
-- Control RFDC, ADC, and DAC resets.
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
library WORK;
use WORK.PkgRFDC_REGS_REGMAP.all;
entity x410_rf_reset_controller is
port(
-- Clocks
-- Config clock is async to all the others.
ConfigClk : in std_logic;
DataClk : in std_logic;
PllRefClk : in std_logic;
RfClk : in std_logic;
RfClk2x : in std_logic;
DataClk2x : in std_logic;
-- Master resets from the Radio
dAdcResetPulse : in std_logic;
dDacResetPulse : in std_logic;
-- ADC Resets
dAdcDataOutReset_n : out std_logic;
r2AdcFirReset_n : out std_logic;
rAdcRfdcAxiReset_n : out std_logic;
rAdcEnableData : out std_logic;
rAdcGearboxReset_n : out std_logic;
-- DAC Resets
dDacDataInReset_n : out std_logic;
r2DacFirReset_n : out std_logic;
d2DacFirReset_n : out std_logic;
rDacRfdcAxiReset_n : out std_logic;
rDacGearboxReset_n : out std_logic;
-- SW Control and Status
-- Control to initiate resets to RFDC and decimation block including the
-- gearboxes. The reset status is a sticky status of both ADC and DAC.
cSoftwareControl : in std_logic_vector(31 downto 0);
cSoftwareStatus : out std_logic_vector(31 downto 0)
);
end x410_rf_reset_controller;
architecture RTL of x410_rf_reset_controller is
-- POR value for all resets are high.
signal cTriggerAdcReset : std_logic := '1';
signal cTriggerAdcResetDlyd : std_logic := '1';
signal cTriggerDacReset : std_logic := '1';
signal cTriggerDacResetDlyd : std_logic := '1';
signal dTriggerAdcReset_ms : std_logic := '1';
signal dTriggerAdcReset : std_logic := '1';
signal dTriggerDacReset_ms : std_logic := '1';
signal dTriggerDacReset : std_logic := '1';
-- POR value of all reset done signals are set to low.
signal cTriggerAdcResetDone_ms : std_logic := '0';
signal cTriggerAdcResetDone : std_logic := '0';
signal cAdcResetDoneSticky : std_logic := '0';
signal cTriggerDacResetDone_ms : std_logic := '0';
signal cTriggerDacResetDone : std_logic := '0';
signal cDacResetDoneSticky : std_logic := '0';
attribute ASYNC_REG : string;
attribute ASYNC_REG of dTriggerAdcReset : signal is "TRUE";
attribute ASYNC_REG of dTriggerDacReset : signal is "TRUE";
attribute ASYNC_REG of cTriggerAdcResetDone : signal is "TRUE";
attribute ASYNC_REG of cTriggerDacResetDone : signal is "TRUE";
attribute ASYNC_REG of dTriggerAdcReset_ms : signal is "TRUE";
attribute ASYNC_REG of dTriggerDacReset_ms : signal is "TRUE";
attribute ASYNC_REG of cTriggerAdcResetDone_ms : signal is "TRUE";
attribute ASYNC_REG of cTriggerDacResetDone_ms : signal is "TRUE";
begin
-- rAdcEnableData is set to '1' as we don't control the flow of RX data.
rAdcEnableData <= '1';
cTriggerAdcReset <= cSoftwareControl(kADC_RESET);
cTriggerDacReset <= cSoftwareControl(kDAC_RESET);
cSoftwareStatus <= (
kADC_SEQ_DONE => cAdcResetDoneSticky,
kDAC_SEQ_DONE => cDacResetDoneSticky,
others => '0'
);
-----------------------------------------------------------------------------
-- High-Level Resets Using ConfigClk
-----------------------------------------------------------------------------
-- Pass the master FSM reset around to the other clock domains and then
-- return them back to the ConfigClk domain. This is also a handy way to
-- prove all your clocks are toggling to some extent.
-----------------------------------------------------------------------------
SeqResetDataClk : process(DataClk)
begin
if rising_edge(DataClk) then
-- double-syncs have no sync reset!
dTriggerAdcReset_ms <= cTriggerAdcReset;
dTriggerAdcReset <= dTriggerAdcReset_ms;
dTriggerDacReset_ms <= cTriggerDacReset;
dTriggerDacReset <= dTriggerDacReset_ms;
end if;
end process;
-----------------------------------------------------------------------------
-- Reset Sequence Done Status
-----------------------------------------------------------------------------
-- Now back to ConfigClk! We provide the status for all software controlled
-- resets. We move the signal from ConfigClk to DataClk domain and move it
-- back to ConfigClk domain. This just proves that DataClk is toggling and
-- the reset requested by software is sampled in the DataClk.
-----------------------------------------------------------------------------
SeqResetDone : process(ConfigClk)
begin
if rising_edge(ConfigClk) then
-- double-syncs have no sync reset!
cTriggerAdcResetDone_ms <= dTriggerAdcReset;
cTriggerAdcResetDone <= cTriggerAdcResetDone_ms;
cTriggerDacResetDone_ms <= dTriggerDacReset;
cTriggerDacResetDone <= cTriggerDacResetDone_ms;
end if;
end process;
-- ADC reset done
SwAdcResetDone: process(ConfigClk)
begin
if rising_edge(ConfigClk) then
cTriggerAdcResetDlyd <= cTriggerAdcReset;
-- De-assert reset status on the rising edge of SW ADC reset.
if cTriggerAdcReset = '1' and cTriggerAdcResetDlyd = '0' then
cAdcResetDoneSticky <= '0';
-- Assert and hold the ADC reset status on ADC reset strobe.
elsif cTriggerAdcResetDone = '1' then
cAdcResetDoneSticky <= '1';
end if;
end if;
end process SwAdcResetDone;
-- DAC reset done
SwDacResetDone: process(ConfigClk)
begin
if rising_edge(ConfigClk) then
cTriggerDacResetDlyd <= cTriggerDacReset;
-- De-assert reset status on the rising edge of SW DAC reset.
if cTriggerDacReset = '1' and cTriggerDacResetDlyd = '0' then
cDacResetDoneSticky <= '0';
-- Assert and hold the DAC reset status on DAC reset strobe.
elsif cTriggerDacResetDone = '1' then
cDacResetDoneSticky <= '1';
end if;
end if;
end process SwDacResetDone;
-----------------------------------------------------------------------------
-- rf_reset Instances
-----------------------------------------------------------------------------
AdcResets: entity work.rf_reset (RTL)
port map (
DataClk => DataClk,
PllRefClk => PllRefClk,
RfClk => RfClk,
RfClk2x => RfClk2x,
DataClk2x => DataClk2x,
dTimedReset => dAdcResetPulse,
dSwReset => dTriggerAdcReset,
dReset_n => dAdcDataOutReset_n,
d2Reset_n => open,
r2Reset_n => r2AdcFirReset_n,
rAxiReset_n => rAdcRfdcAxiReset_n,
rReset_n => rAdcGearboxReset_n
);
DacResets: entity work.rf_reset (RTL)
port map (
DataClk => DataClk,
PllRefClk => PllRefClk,
RfClk => RfClk,
RfClk2x => RfClk2x,
DataClk2x => DataClk2x,
dTimedReset => dDacResetPulse,
dSwReset => dTriggerDacReset,
dReset_n => dDacDataInReset_n,
d2Reset_n => d2DacFirReset_n,
r2Reset_n => r2DacFirReset_n,
rAxiReset_n => rDacRfdcAxiReset_n,
rReset_n => rDacGearboxReset_n
);
end RTL;