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:
committed by
Martin Braun
co-authored by
Wade Fife
Ryan Marlow
Martin Braun
Humberto Jimenez
parent
ffdcc016cc
commit
adf6f576c6
@@ -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
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -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 \
|
||||
))
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+7
-7
@@ -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,
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user