Files
b210-k7-fpga/top/x400/rf/sim/tb_rf_nco_reset.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

294 lines
10 KiB
VHDL

--
-- Copyright 2021 Ettus Research, a National Instruments Brand
--
-- SPDX-License-Identifier: LGPL-3.0-or-later
--
-- Module: tb_rf_nco_reset
--
-- Description:
--
-- Self-checking testbench for NCO reset sequencing.
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity tb_rf_nco_reset is
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;
signal cDac1xNcoUpdateReq : std_logic;
signal cNcoPhaseRst : std_logic;
signal cNcoUpdateEn : std_logic_vector(5 downto 0);
signal dNcoResetDone : std_logic;
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';
signal cSysrefDlyd : std_logic_vector(1 downto 0) := "00";
signal cDac0xSysrefIntGatingDlyd : std_logic := '0';
signal cNcoPhaseRstDlyd : std_logic_vector(2 downto 0) := "000";
signal cWrCount : integer := 0;
type RfdcNcoState_t is (Idle, GateSysref, UpdateReq, CheckUpdate,
SysrefEn, WaitForSysref, ResetDone);
signal cRfdcNcoState : RfdcNcoState_t := Idle;
signal StopSim : boolean;
constant kConfigClkPer : time := 25 ns;
-- SYSREF period is 2.5 MHz.
constant kSysrefPer : time := 400 ns;
-- DataClk period is 125 MHz and generated from the same clocking chip that
-- generated SYSREF and are related.
constant kDataClkPer : time := kSysrefPer/50;
signal ConfigClk : std_logic := '0';
signal DataClk : std_logic := '0';
signal dSysref : std_logic := '0';
procedure DataClkWait(X : positive := 1) is
begin
for i in 1 to X loop
wait until rising_edge(DataClk);
end loop;
end procedure DataClkWait;
procedure ConfigClkWait(X : positive := 1) is
begin
for i in 1 to X loop
wait until rising_edge(ConfigClk);
end loop;
end procedure ConfigClkWait;
procedure SysrefWait(X : positive := 1) is
begin
for i in 1 to X loop
wait until rising_edge(dSysref);
end loop;
end procedure SysrefWait;
begin
ConfigClk <= not ConfigClk after kConfigClkPer/2 when not StopSim else '0';
DataClk <= not DataClk after kDataClkPer/2 when not StopSim else '0';
dSysref <= not dSysref after kSysrefPer/2 when not StopSim else '0';
-- Both cNcoPhaseRst and cNcoUpdateEn are constants in the DUT.
dut: entity WORK.rf_nco_reset (RTL)
port map (
ConfigClk => ConfigClk,
DataClk => DataClk,
dSysref => dSysref,
dStartNcoReset => dStartNcoReset,
cDac0xNcoUpdateBusy => cDac0xNcoUpdateBusy,
cDac0xNcoUpdateReq => cDac0xNcoUpdateReq,
cDac0xSysrefIntGating => cDac0xSysrefIntGating,
cDac0xSysrefIntReenable => cDac0xSysrefIntReenable,
cDac1xNcoUpdateBusy => cDac1xNcoUpdateBusy,
cDac1xNcoUpdateReq => cDac1xNcoUpdateReq,
cAdc0xNcoUpdateBusy => cAdc0xNcoUpdateBusy,
cAdc0xNcoUpdateReq => cAdc0xNcoUpdateReq,
cAdc1xNcoUpdateBusy => cAdc1xNcoUpdateBusy,
cAdc1xNcoUpdateReq => cAdc1xNcoUpdateReq,
cAdc2xNcoUpdateBusy => cAdc2xNcoUpdateBusy,
cAdc2xNcoUpdateReq => cAdc2xNcoUpdateReq,
cAdc3xNcoUpdateBusy => cAdc3xNcoUpdateBusy,
cAdc3xNcoUpdateReq => cAdc3xNcoUpdateReq,
cNcoPhaseRst => cNcoPhaseRst,
cNcoUpdateEn => cNcoUpdateEn,
dNcoResetDone => dNcoResetDone
);
main: process
-- Procedure to sweep the entire SYSREF period.
-- When we strobe dStartNcoReset for one DataClk cycle. NCO reset sequence
-- is initiated. In this procedure, we sweep the dStartNcoReset strobe the
-- entire SYSREF cycle.
procedure SysrefSweep is
constant kSysrefInRfCycles : integer := kSysrefPer/kDataClkPer;
begin
for i in 1 to kSysrefInRfCycles loop
wait until cDac0xSysrefIntGating = '0' for 1 us;
assert cDac0xSysrefIntGating = '0'
report "NCO phase reset does not de-assert"
severity error;
SysrefWait;
DataClkWait(i);
dStartNcoReset <= '0';
DataClkWait;
dStartNcoReset <= '1';
DataClkWait;
dStartNcoReset <= '0';
-- Wait for a minimum of 3 SYSREF period. 1 SYSREF edge is used to
-- initiate NCO reset, 1 SYSREF edge is used to re-enable SYSREF and 1
-- SYSREF edge is used by RFDC to reset all NCOs.
SysrefWait(3);
end loop;
end procedure;
begin
-- Strobe dStartNcoReset across entire SYSREF period.
SysrefSweep;
-- Wait for a minimum of 3 SYSREF cycles to make sure NCO reset is complete.
SysrefWait(3);
StopSim <= true;
wait;
end process;
-- Process to mimic RFDC NCO reset
-- This state machine is based of "NCO frequency hopping" section in PG269
-- (v2.2). Refer to multi-mode subsection for more details.
MimicRfdc: process(ConfigClk)
begin
if falling_edge(ConfigClk) then
cRfdcNcoState <= Idle;
case cRfdcNcoState is
-- Wait until SYSREF internal gating is asserted.
when Idle =>
cWrCount <= 0;
if cDac0xSysrefIntGating = '1' then
cRfdcNcoState <= GateSysref;
end if;
-- Change cDac0xNcoUpdateBusy to "11" to indicate SYSREF is gated
-- internally when NCO update is requested on DAC tile 228.
-- cDac0xNcoUpdateBusy(0) is set to '1', the SYSREF is gated and
-- cDac0xNcoUpdateBusy(1) is set to '1', to indicate the NCO reset
-- process has started, but not complete.
when GateSysref =>
cRfdcNcoState <= GateSysref;
if cDac0xNcoUpdateReq = '1' then
cRfdcNcoState <= UpdateReq;
cDac0xNcoUpdateBusy <= "11";
end if;
-- If NCO reset is requested on other tiles, assert NCO update busy on
-- other tiles as well.
when UpdateReq =>
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
-- reset the NCO, which is a single bit. So, it should take only 5
-- ConfigClk for the update. When the internal register is updated, set
-- cDac0xNcoUpdateBusy(0) to '0'.
when CheckUpdate =>
cRfdcNcoState <= CheckUpdate;
if cWrCount > 4 then
cRfdcNcoState <= SysrefEn;
cDac0xNcoUpdateBusy <= "10"; --Indicates that SYSREF is gated.
cDac1xNcoUpdateBusy <= '0';
cAdc0xNcoUpdateBusy <= '0';
cAdc1xNcoUpdateBusy <= '0';
cAdc2xNcoUpdateBusy <= '0';
cAdc3xNcoUpdateBusy <= '0';
end if;
cWrCount <= cWrCount + 1;
-- Wait until internal SYSREF gating is disabled.
when SysrefEn =>
cWrCount <= 0;
cRfdcNcoState <= SysrefEn;
if cDac0xSysrefIntReenable = '1' then
if cSysrefDlyd(0) = '0' and cSysref = '1' then
cDac0xNcoUpdateBusy <= "00"; --Indicates that NCO reset is complete.
cRfdcNcoState <= ResetDone;
else
cRfdcNcoState <= WaitForSysref;
end if;
end if;
-- NCO reset is done on the rising edge of SYSREF. When NCO reset is
-- complete, set cDac0xNcoUpdateBusy(1) to '0'.
when WaitForSysref =>
cRfdcNcoState <= WaitForSysref;
if cSysrefDlyd(0) = '0' and cSysref = '1' then
cDac0xNcoUpdateBusy <= "00"; --Indicates that NCO reset is complete.
cRfdcNcoState <= ResetDone;
end if;
-- Wait in this state, until the next NCO reset is requested.
when ResetDone =>
cRfdcNcoState <= ResetDone;
if cDac0xSysrefIntGating = '1' then
cRfdcNcoState <= GateSysref;
end if;
end case;
end if;
end process;
-- SYSREF clock crossing from DataClk to ConfigClk and some pipelines.
ConfigClkSysref: process(ConfigClk)
begin
if rising_edge(ConfigClk) then
cSysref_ms <= dSysref;
cSysref <= cSysref_ms;
cSysrefDlyd <= cSysrefDlyd(cSysrefDlyd'high-1) & cSysref;
cDac0xSysrefIntGatingDlyd <= cDac0xSysrefIntGating;
cNcoPhaseRstDlyd <= cNcoPhaseRstDlyd(cNcoPhaseRstDlyd'high downto 1)
& cDac0xNcoUpdateBusy(1);
end if;
end process;
-- Assertions
process(ConfigClk)
begin
if falling_edge(ConfigClk) then
--Check if cNcoPhaseRst is a constant of '1'.
assert cNcoPhaseRst = '1'
report "NCO phase reset signal should be constant."
severity error;
-- Check if cNcoUpdateEn is a constant of "100000".
assert cNcoUpdateEn = "100000"
report "NCO phase reset signal should be constant."
severity error;
-- Check if NCO reset was requested on the rising edge of SYSREF.
if cDac0xSysrefIntGating = '1' and cDac0xSysrefIntGatingDlyd = '0' then
assert cSysrefDlyd = "01"
report "NCO reset did not start on SYSREF rising edge"
severity error;
end if;
-- We wait for couple of clock cycles after NCO done signal is toggled in
-- from the RFDC. RFDC uses cDac0xNcoUpdateBusy(1) to indicate NCO reset
-- process is done. It is important to wait a minimum of three clock
-- cycles before this check is done. This wait is needed for clock
-- crossing.
if cNcoPhaseRstDlyd(2) = '1' and cNcoPhaseRstDlyd(1) = '0' then
assert dNcoResetDone = '1'
report "NCO Reset done should have been asserted after NCO " &
"reset request is de-asserted"
severity error;
end if;
end if;
end process;
end RTL;