Files
b210-k7-fpga/top/x400/rf/sim/tb_x410_rf_reset_controller.vhd
T
adf6f576c6 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
2023-05-23 09:06:17 +02:00

437 lines
18 KiB
VHDL

--
-- Copyright 2021 Ettus Research, a National Instruments Brand
--
-- SPDX-License-Identifier: LGPL-3.0-or-later
--
-- Module: tb_x410_rf_reset_controller
--
-- Description:
--
-- Testbench for x410_rf_reset_controller.
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
library WORK;
use WORK.PkgRFDC_REGS_REGMAP.all;
entity tb_x410_rf_reset_controller is
end tb_x410_rf_reset_controller;
architecture RTL of tb_x410_rf_reset_controller is
component x410_rf_reset_controller
port (
ConfigClk : in std_logic;
DataClk : in std_logic;
PllRefClk : in std_logic;
RfClk : in std_logic;
RfClk2x : in std_logic;
DataClk2x : in std_logic;
dAdcResetPulse : in std_logic;
dDacResetPulse : in std_logic;
dAdcDataOutReset_n : out std_logic;
r2AdcFirReset_n : out std_logic;
rAdcRfdcAxiReset_n : out std_logic;
rAdcEnableData : out std_logic;
rAdcGearboxReset_n : out std_logic;
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;
cSoftwareControl : in std_logic_vector(31 downto 0);
cSoftwareStatus : out std_logic_vector(31 downto 0));
end component;
signal cSoftwareStatus : std_logic_vector(31 downto 0);
signal r2AdcFirReset_n : std_logic;
signal r2DacFirReset_n : std_logic;
signal rAdcGearboxReset_n : std_logic;
signal rDacGearboxReset_n : std_logic;
signal cSoftwareControl : std_logic_vector(31 downto 0) := (others => '0');
signal dAdcResetPulse : std_logic := '0';
signal dDacResetPulse : std_logic := '0';
constant kSwReset : std_logic := '0';
constant kTimedReset : std_logic := '1';
-- All constants mentioned below are number of the particular clock cycles
-- PllRefClk period. For example, kDataClkCycles is the total number of
-- DataClk cycles in the PllRefClk period.
constant kDataClkCycles : integer := 2;
constant kDataClk2xCycles : integer := 4;
constant kRfClkCycles : integer := 3;
constant kRfClk2xCycles : integer := 6;
constant kConfigPer : time := 25 ns;
-- Make sure the PllRefClk period is a least common multiple of all the other
-- derived clock.
constant kPllRefClkPer : time := 12 ns;
constant kDataClkPer : time := kPllRefClkPer/2;
constant kDataClk2xPer : time := kPllRefClkPer/4;
constant kRfClkPer : time := kPllRefClkPer/3;
constant kRfClk2xPer : time := kPllRefClkPer/6;
signal pReset : boolean := false;
signal dCount : integer := 0;
signal d2Count : integer := 0;
signal rCount : integer := 0;
signal r2Count : integer := 0;
signal StopSim : boolean;
signal ConfigClk : std_logic := '1';
signal RfClk : std_logic := '1';
signal RfClk2x : std_logic := '1';
signal DataClk : std_logic := '1';
signal DataClk2x : std_logic := '1';
signal PllRefClk : std_logic := '1';
signal dAdcDataOutReset_n : std_logic := '0';
signal dAdcDataOutResetDlyd_n : std_logic := '0';
signal dDacDataInReset_n : std_logic := '0';
signal dDacDataInResetDlyd_n : std_logic := '0';
signal d2DacFirReset_n : std_logic := '0';
signal d2DacFirResetDlyd_n : std_logic := '0';
signal rAdcRfdcAxiReset_n : std_logic := '0';
signal rAdcRfdcAxiResetDlyd_n : std_logic := '0';
signal rDacRfdcAxiReset_n : std_logic := '0';
signal rDacRfdcAxiResetDlyd_n : std_logic := '0';
signal r2AdcFirResetDlyd_n : std_logic := '0';
signal r2DacFirResetDlyd_n : std_logic := '0';
signal ExpectedSwAdcResetDone : std_logic := '0';
signal ExpectedAdcReset : std_logic := '0';
signal ExpectedSwDacResetDone : std_logic := '0';
signal ExpectedDacReset : std_logic := '0';
signal ExpectedAxiAdcResetOut : std_logic := '0';
signal ExpectedAxiDacResetOut : std_logic := '0';
-- Make sure the wait time for reset done check is at least 10 ConfigClk
-- cycles to account for all clock domain crossings. We also have some status
-- check in the testbench which requires the wait to be additional ConfigClk
-- cycles. This wait is in ConfigClk period.
constant kResetDoneWait : positive := 10;
procedure ClkWait(signal clk : in std_logic; X : positive := 1) is
begin
for i in 1 to X loop
wait until rising_edge(clk);
end loop;
end procedure ClkWait;
-- Check phase alignment of reset. We want to make sure the reset is asserted
-- on the 1st rising clock edge after the rising edge of PllRefClk.
procedure CheckAlignment(
signal Clk : in std_logic; -- Synchronous reset clock
signal Reset_n : in std_logic; -- Synchronous reset
signal ResetDlyd_n : inout std_logic; -- Delayed synchronous reset
signal PhaseCount : in integer; -- Phase count used to check alignment
Message : string) is -- Assertion message
begin
-- Check if reset is asserted on the 1st Clk after the rising edge of
-- PllRefClk.
if falling_edge(Clk) then
ResetDlyd_n <= Reset_n;
if Reset_n = '0' and ResetDlyd_n = '1' then
assert PhaseCount = 1
report Message & " reset is not asserted in the expected time" severity error;
end if;
end if;
end procedure CheckAlignment;
-- Procedure to generate phase counter that is used to check the alignment of
-- phase of all clocks related to PllRefClk.
procedure PhaseCounter(
signal Clk : in std_logic; -- Clock related to PllRefClk
signal Reset : in boolean; -- Reset synchronous to PllRefClk
signal PhaseCount : inout integer; -- Phase count of Clk with respect to PllRefClk
ClockCycles : integer) is -- Number of Clk clock cycles in PllRefClk period
begin
if rising_edge(Clk) then
if Reset or PhaseCount = ClockCycles-1 then
PhaseCount <= 0;
else
PhaseCount <= PhaseCount+1;
end if;
end if;
end procedure PhaseCounter;
procedure CheckExpectedValue(
signal Clk : in std_logic;
signal Actual : in std_logic;
signal Expected : in std_logic;
Message : string) is
begin
if falling_edge(Clk) then
-- Check if the actual value is as expected.
assert std_match(Actual, Expected)
report Message & " not as expected" & LF
& "Expected = " & std_logic'image(Expected) & LF
& "Actual = " & std_logic'image(Actual) severity error;
end if;
end procedure CheckExpectedValue;
begin
ConfigClk <= not ConfigClk after kConfigPer/2 when not StopSim else '0';
RfClk <= not RfClk after kRfClkPer/2 when not StopSim else '0';
RfClk2x <= not RfClk2x after kRfClk2xPer/2 when not StopSim else '0';
DataClk <= not DataClk after kDataClkPer/2 when not StopSim else '0';
DataClk2x <= not DataClk2x after kDataClk2xPer/2 when not StopSim else '0';
PllRefClk <= not PllRefClk after kPllRefClkPer/2 when not StopSim else '0';
-- rAdcEnableData is a constant and is not tested.
dut: x410_rf_reset_controller
port map (
ConfigClk => ConfigClk,
DataClk => DataClk,
PllRefClk => PllRefClk,
RfClk => RfClk,
RfClk2x => RfClk2x,
DataClk2x => DataClk2x,
dAdcResetPulse => dAdcResetPulse,
dDacResetPulse => dDacResetPulse,
dAdcDataOutReset_n => dAdcDataOutReset_n,
r2AdcFirReset_n => r2AdcFirReset_n,
rAdcRfdcAxiReset_n => rAdcRfdcAxiReset_n,
rAdcEnableData => open,
rAdcGearboxReset_n => rAdcGearboxReset_n,
dDacDataInReset_n => dDacDataInReset_n,
r2DacFirReset_n => r2DacFirReset_n,
d2DacFirReset_n => d2DacFirReset_n,
rDacRfdcAxiReset_n => rDacRfdcAxiReset_n,
rDacGearboxReset_n => rDacGearboxReset_n,
cSoftwareControl => cSoftwareControl,
cSoftwareStatus => cSoftwareStatus
);
main: process
-- Procedure to generate software reset and expected DUR reset output.
procedure StrobeReset(
signal TimedReset : out std_logic; -- SW Reset control
signal ExpectedResetOut : out std_logic; -- Expected reset values
signal ExpectedAxiResetOut : out std_logic; -- Expected reset values
signal SwResetStatus : out std_logic; -- Expected SW reset status
SwReset : integer; -- SW Reset control
ResetType : std_logic; -- 0 = SW reset, 1 = UHD timed reset
ResetWait : positive := 1) is -- Wait time for test iteration
begin
if ResetType = kSwReset then
-- Assert software reset control on the rising edge of ConfigClk. Also
-- change the expected status to don't care as the status will change
-- only after few ConfigClk period.
ClkWait(ConfigClk);
TimedReset <= '0';
cSoftwareControl(SwReset) <= '1';
SwResetStatus <= '-';
ExpectedResetOut <= '-';
ExpectedAxiResetOut <= '-';
ClkWait(ConfigClk, 1);
SwResetStatus <= '0';
-- Wait for additional ConfigClk before changing the expected reset
-- value to '0'. This wait is needed to account for pipeline and clock
-- crossing delays.
ClkWait(ConfigClk, 1);
-- Changed expected reset output to '0' (active low).
ExpectedResetOut <= '0';
ExpectedAxiResetOut <= '0';
ClkWait(ConfigClk,1);
-- SW reset status should be asserted after 3 ConfigClk periods. This
-- wait is needed to account for pipeline and clock crossings.
SwResetStatus <= '1';
-- De-assert software reset
ClkWait(ConfigClk,2);
cSoftwareControl(SwReset) <= '0';
-- Change the expected reset outputs to don't care as it will take few
-- PllRefClk cycles and ConfigClk to DataClock crossing.
ExpectedAxiResetOut <= '-';
ClkWait(ConfigClk,1);
ExpectedAxiResetOut <= '1';
-- After few ConfigClk cycles, all reset outputs should be de-asserted.
ClkWait(ConfigClk,1);
ExpectedResetOut <= '-';
ClkWait(ConfigClk,2);
ExpectedResetOut <= '1';
-- Wait for ResetWait time before exiting the test iteration.
ClkWait(ConfigClk,ResetWait);
else -- Timed command.
ClkWait(DataClk,ResetWait);
TimedReset <= '1';
-- RFDC should not be asserted with timed reset.
ExpectedAxiResetOut <= '1';
-- Strobe the reset pulse only for one DataClk period.
ClkWait(DataClk,1);
TimedReset <= '0';
ClkWait(PllRefClk,2);
ExpectedResetOut <= '-';
-- Wait for 3 PllRefClk to account for pipeline delays.
ClkWait(PllRefClk,1);
ExpectedResetOut <= '0';
ClkWait(PllRefClk,2);
ExpectedResetOut <= '-';
-- Reset should be asserted only for two PllRefClk cycles.
ClkWait(PllRefClk,2);
ExpectedResetOut <= '1';
ClkWait(DataClk,ResetWait); -- Wait between test.
end if;
end procedure StrobeReset;
begin
-- Expected power on reset values.
ExpectedAdcReset <= '0';
ExpectedAxiAdcResetOut <= '0';
ExpectedDacReset <= '0';
ExpectedAxiDacResetOut <= '0';
ClkWait(ConfigClk,1);
ClkWait(RfClk,1);
ExpectedAxiAdcResetOut <= '1';
ExpectedAxiDacResetOut <= '1';
ClkWait(ConfigClk,1);
ExpectedAdcReset <= '-';
ExpectedDacReset <= '-';
ClkWait(ConfigClk,1);
ExpectedAdcReset <= '1';
ExpectedDacReset <= '1';
ClkWait(ConfigClk,5);
-- This reset is for simulation to have a common reference to check for
-- clock alignment.
ClkWait(PllRefClk,1);
pReset <= true;
ClkWait(PllRefClk,1);
pReset <= false;
ClkWait(PllRefClk,1);
---------------------------------------------------------------------------
-- Test resets from software
---------------------------------------------------------------------------
-----------------------------------
-- ADC
-----------------------------------
StrobeReset(dAdcResetPulse, ExpectedAdcReset, ExpectedAxiAdcResetOut,
ExpectedSwAdcResetDone, kADC_RESET, kSwReset, kResetDoneWait);
-- Align reset to the rising edge of PllRefClk
ClkWait(PllRefClk,1);
StrobeReset(dAdcResetPulse, ExpectedAdcReset, ExpectedAxiAdcResetOut,
ExpectedSwAdcResetDone, kADC_RESET, kTimedReset, kResetDoneWait);
StrobeReset(dAdcResetPulse, ExpectedAdcReset, ExpectedAxiAdcResetOut,
ExpectedSwAdcResetDone, kADC_RESET, kSwReset, kResetDoneWait);
-- Align reset to the falling edge of PllRefClk.
ClkWait(PllRefClk,1);
ClkWait(DataClk,1);
StrobeReset(dAdcResetPulse, ExpectedAdcReset, ExpectedAxiAdcResetOut,
ExpectedSwAdcResetDone, kADC_RESET, kTimedReset, kResetDoneWait);
-----------------------------------
-- DAC
-----------------------------------
StrobeReset(dDacResetPulse, ExpectedDacReset, ExpectedAxiDacResetOut,
ExpectedSwDacResetDone, kDAC_RESET, kSwReset, kResetDoneWait);
-- Align reset to the rising edge of PllRefClk.
ClkWait(PllRefClk,1);
StrobeReset(dDacResetPulse, ExpectedDacReset, ExpectedAxiDacResetOut,
ExpectedSwDacResetDone, kDAC_RESET, kTimedReset, kResetDoneWait);
StrobeReset(dDacResetPulse, ExpectedDacReset, ExpectedAxiDacResetOut,
ExpectedSwDacResetDone, kDAC_RESET, kSwReset, kResetDoneWait);
-- Align reset to the falling edge of PllRefClk.
ClkWait(PllRefClk,1);
ClkWait(DataClk,1);
StrobeReset(dDacResetPulse, ExpectedDacReset, ExpectedAxiDacResetOut,
ExpectedSwDacResetDone, kDAC_RESET, kTimedReset, kResetDoneWait);
StopSim <= true;
wait;
end process main;
-----------------------------------------------------------------------------
-- Reset from software and UHD timed command
-----------------------------------------------------------------------------
-- Check if the correct resets are getting asserted when UHD timed reset or
-- software reset is asserted. Except for RFDC AXI-S reset all other resets
-- should be strobed for UHD timed reset.
-----------------------------------------------------------------------------
-- Check if the reset done status is getting asserted as expected.
CheckExpectedValue(ConfigClk, cSoftwareStatus(kADC_SEQ_DONE),
ExpectedSwAdcResetDone, "ADC reset done status");
CheckExpectedValue(ConfigClk, cSoftwareStatus(kDAC_SEQ_DONE),
ExpectedSwDacResetDone, "DAC reset done status");
-- Check if resets state in DataClk is as expected.
CheckExpectedValue(DataClk, dAdcDataOutReset_n, ExpectedAdcReset,
"ADC data out reset");
CheckExpectedValue(DataClk, dDacDataInReset_n, ExpectedDacReset,
"DAC data out reset");
-- Check if resets state in DataClk2x is as expected.
CheckExpectedValue(DataClk2x, d2DacFirReset_n, ExpectedDacReset,
"400M interpolator reset");
---- Check if resets state in RfClk2x is as expected.
CheckExpectedValue(RfClk2x, r2AdcFirReset_n, ExpectedAdcReset,
"ADC re-sampler reset");
CheckExpectedValue(RfClk2x, r2DacFirReset_n, ExpectedDacReset,
"DAC re-sampler reset");
---- Check if resets state in RfClk is as expected.
CheckExpectedValue(RfClk, rAdcRfdcAxiReset_n, ExpectedAxiAdcResetOut,
"ADC RFDC AXI-S interface reset");
CheckExpectedValue(RfClk, rDacRfdcAxiReset_n, ExpectedAxiDacResetOut,
"DAC RFDC AXI-S interface reset");
CheckExpectedValue(RfClk, rAdcGearboxReset_n, ExpectedAdcReset,
"ADC gearbox reset");
CheckExpectedValue(RfClk, rDacGearboxReset_n, ExpectedDacReset,
"DAC gearbox reset");
-----------------------------------------------------------------------------
-- Reset alignment checks for resets
-----------------------------------------------------------------------------
-----------------------------------
-- Clock counter
-----------------------------------
-- We use counters to check the phase of all the derived clocks with respect
-- to PllRefClk. Each counter will rollover at the rising edge of PllRefClk.
-----------------------------------
PhaseCounter(DataClk, pReset, dCount, kDataClkCycles);
PhaseCounter(DataClk2x, pReset, d2Count, kDataClk2xCycles);
PhaseCounter(RfClk, pReset, rCount, kRfClkCycles);
PhaseCounter(RfClk2x, pReset, r2Count, kRfClk2xCycles);
-- Check for DataClk based synchronous reset alignment to PllRefClk.
CheckAlignment(DataClk, dAdcDataOutReset_n, dAdcDataOutResetDlyd_n, dCount,
"ADC data out");
CheckAlignment(DataClk, dDacDataInReset_n, dDacDataInResetDlyd_n, dCount,
"DAC data in");
-- Check for DataClk2x based synchronous reset alignment to PllRefClk.
CheckAlignment(DataClk2x, d2DacFirReset_n, d2DacFirResetDlyd_n, d2Count,
"400M DAC FIR Filter");
-- Check for RfClk based synchronous reset alignment to PllRefClk.
CheckAlignment(RfClk, rAdcRfdcAxiReset_n, rAdcRfdcAxiResetDlyd_n, rCount,
"ADC RFDC reset ");
CheckAlignment(RfClk, rDacRfdcAxiReset_n, rDacRfdcAxiResetDlyd_n, rCount,
"DAC RFDC reset ");
-- Check for RfClk2x based synchronous reset alignment to PllRefClk.
CheckAlignment(RfClk2x, r2AdcFirReset_n, r2AdcFirResetDlyd_n, r2Count,
"ADC decimation filter reset ");
CheckAlignment(RfClk2x, r2DacFirReset_n, r2DacFirResetDlyd_n, r2Count,
"DAC interpolation filter reset ");
end RTL;