fpga: Add X440/FBX support
Co-authored-by: Martin Braun <martin.braun@ettus.com> Co-authored-by: Wade Fife <wade.fife@ni.com> Co-authored-by: Ryan Marlow <ryan@lmarlow.com> Original-commit: 596760a12e4834e47589c12f8a4fd083aa2f7c25
This commit is contained in:
committed by
Aki Tomita
co-authored by
Martin Braun
Wade Fife
Ryan Marlow
parent
a405111ce7
commit
5cadf901c7
@@ -6,6 +6,7 @@
|
||||
|
||||
RF_COMMON_SRCS = $(abspath $(addprefix $(BASE_DIR)/../top/x400/rf/common/, \
|
||||
PkgRf.vhd \
|
||||
adc_iq_repacker.v \
|
||||
axis_mux.vhd \
|
||||
capture_sysref.v \
|
||||
gpio_to_axis_mux.vhd \
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
//
|
||||
// Copyright 2022 Ettus Research, A National Instruments Brand
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: adc_iq_repacker
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// This component repacks IQ from independent vectors into a single
|
||||
// output signal, and implements data swapping when requested.
|
||||
//
|
||||
// The parameters for this component describe the expected amount of
|
||||
// data to be received as well as the data to be generated.
|
||||
//
|
||||
// - SPC = Samples per cycle: amount of samples to be expected
|
||||
// on each I and Q input vector on each "clk" cycle.
|
||||
// - SAMPLE_WIDTH = Amount of bits composing each sample
|
||||
//
|
||||
// This modules incurs in two clk cycles of delay on the data and valid
|
||||
// signals from input to output.
|
||||
//
|
||||
// Example case : SPC = 2, SAMPLE_WIDTH = 16
|
||||
//
|
||||
// adc_x_in size(for I and Q) = 2 x 16 = 32
|
||||
// adc_out size = 2 x 2 x 16 = 64
|
||||
//
|
||||
// _______ _______ _______ ______
|
||||
// clk _| |_______| |_______| |_______|
|
||||
// _ _______________ _______________ _______________ ______
|
||||
// adc_i_in _X_____I1,I0_____X_____I3,I2_____X____32{'X'}____X______
|
||||
// _ _______________ _______________ _______________ ______
|
||||
// adc_q_in _X_____Q1,Q0_____X_____Q3,Q2_____X____32{'X'}____X______
|
||||
// _______________________________
|
||||
// valid_in _| |______________________
|
||||
// _ _______________ _______________ _______________ ______
|
||||
// adc_out _X____64{'X'}____X____64{'X'}____X__Q1,I1,Q0,I0__X__Q3,..
|
||||
// ______________________
|
||||
// valid_out _________________________________|
|
||||
//
|
||||
// When the swap input is high, the order in which Q and I samples
|
||||
// appear on the output vector is inverted
|
||||
//
|
||||
// _______ _______ _______ ______
|
||||
// clk _| |_______| |_______| |_______|
|
||||
// _ _______________ _______________ _______________ ______
|
||||
// adc_i_in _X_____I1,I0_____X_____I3,I2_____X____32{'X'}____X______
|
||||
// _ _______________ _______________ _______________ ______
|
||||
// adc_q_in _X_____Q1,Q0_____X_____Q3,Q2_____X____32{'X'}____X______
|
||||
// _______________________________
|
||||
// valid_in _| |______________________
|
||||
// _ _______________ _______________ _______________ ______
|
||||
// adc_out _X____64{'X'}____X____64{'X'}____X__I1,Q1,I0,Q0__X__I3,..
|
||||
// ______________________
|
||||
// valid_out _________________________________|
|
||||
//
|
||||
// Parameters:
|
||||
// SPC = Samples per cycle
|
||||
// SAMPLE_WIDTH = width of i/q sample inputs. Output will be 2*SAMPLE_WIDTH
|
||||
//
|
||||
|
||||
module adc_iq_repacker #(
|
||||
parameter SPC = 1,
|
||||
parameter SAMPLE_WIDTH = 16
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
// Data in
|
||||
input wire [SPC*SAMPLE_WIDTH-1:0] adc_q_in,
|
||||
input wire [SPC*SAMPLE_WIDTH-1:0] adc_i_in,
|
||||
input wire valid_in,
|
||||
// This signal is currently driven in a related clock, and even though it runs at half the rate is should be fine
|
||||
// to handle it in this clock domain(in nature it will also stay high one asserted until the next reset.)
|
||||
input wire enable,
|
||||
// Data is packed [Q,I] (I in LSBs) when swap_iq is '0', and [I,Q] otherwise
|
||||
input wire swap_iq,
|
||||
|
||||
// Data out
|
||||
output reg [SPC*SAMPLE_WIDTH*2-1:0] data_out_tdata,
|
||||
output reg data_out_tvalid
|
||||
);
|
||||
|
||||
localparam IQ_WIDTH = SAMPLE_WIDTH*2;
|
||||
|
||||
reg valid = 1'b0, valid_dly = 1'b0;
|
||||
reg [SPC*SAMPLE_WIDTH-1:0] adc_q_data_in = {SPC*SAMPLE_WIDTH{1'b0}};
|
||||
reg [SPC*SAMPLE_WIDTH-1:0] adc_i_data_in = {SPC*SAMPLE_WIDTH{1'b0}};
|
||||
|
||||
integer sample_num;
|
||||
|
||||
// It is safe to not reset this domain because all of the input signals will be cleared
|
||||
// by a synchronous reset. Safe default values are assigned to all these registers.
|
||||
always @(posedge clk) begin
|
||||
adc_q_data_in <= adc_q_in;
|
||||
adc_i_data_in <= adc_i_in;
|
||||
// Place Q in the MSBs, I in the LSBs by default, unless swapped = 1.
|
||||
for (sample_num=0; sample_num < (SPC); sample_num = sample_num + 1)
|
||||
begin : data_out_gen
|
||||
if (swap_iq) begin
|
||||
data_out_tdata[sample_num*(IQ_WIDTH) +: IQ_WIDTH] <=
|
||||
{adc_i_data_in[sample_num*(SAMPLE_WIDTH) +: SAMPLE_WIDTH],
|
||||
adc_q_data_in[sample_num*(SAMPLE_WIDTH) +: SAMPLE_WIDTH]};
|
||||
end else begin
|
||||
data_out_tdata[sample_num*(IQ_WIDTH) +: IQ_WIDTH] <=
|
||||
{adc_q_data_in[sample_num*(SAMPLE_WIDTH) +: SAMPLE_WIDTH],
|
||||
adc_i_data_in[sample_num*(SAMPLE_WIDTH) +: SAMPLE_WIDTH]};
|
||||
end
|
||||
end
|
||||
// Valid is simply a transferred version of the 1x clock's valid. Delay it one
|
||||
// more cycle to align outputs.
|
||||
valid <= valid_in && enable;
|
||||
data_out_tvalid <= valid;
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -1,300 +0,0 @@
|
||||
--
|
||||
-- Copyright 2021 Ettus Research, a National Instruments Brand
|
||||
--
|
||||
-- SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
--
|
||||
-- Module: 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 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 clock_gates;
|
||||
|
||||
architecture STRUCT of 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;
|
||||
@@ -1,208 +0,0 @@
|
||||
--
|
||||
-- Copyright 2021 Ettus Research, a National Instruments Brand
|
||||
--
|
||||
-- SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
--
|
||||
-- Module: 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 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 rf_reset_controller;
|
||||
|
||||
|
||||
architecture RTL of 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