x400: sim: Move testbenches to sim folder
Original-commit: c0f9496d59947f8c9411b28d63d0c8e6244102a0
This commit is contained in:
@@ -0,0 +1,436 @@
|
||||
--
|
||||
-- Copyright 2021 Ettus Research, a National Instruments Brand
|
||||
--
|
||||
-- SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
--
|
||||
-- Module: tb_rf_reset_controller
|
||||
--
|
||||
-- Description:
|
||||
--
|
||||
-- Testbench for 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_rf_reset_controller is
|
||||
end tb_rf_reset_controller;
|
||||
|
||||
|
||||
architecture RTL of tb_rf_reset_controller is
|
||||
|
||||
component 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: 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;
|
||||
Reference in New Issue
Block a user