diff options
| author | Wade Fife <wade.fife@ettus.com> | 2020-10-13 16:52:34 -0500 | 
|---|---|---|
| committer | Wade Fife <wade.fife@ettus.com> | 2020-12-11 07:41:13 -0600 | 
| commit | c6578eda2ba482b87583ebd989cdf5cbd5c3f672 (patch) | |
| tree | 6ef5751015edb1a0a6b6f38ddf16c53612337c3a /fpga/usrp3/lib | |
| parent | 744e60bd598df4677a88df10d1fceb56e7c1ee36 (diff) | |
| download | uhd-c6578eda2ba482b87583ebd989cdf5cbd5c3f672.tar.gz uhd-c6578eda2ba482b87583ebd989cdf5cbd5c3f672.tar.bz2 uhd-c6578eda2ba482b87583ebd989cdf5cbd5c3f672.zip | |
fpga: e320: Improve timing on LVDS interface
Diffstat (limited to 'fpga/usrp3/lib')
| -rw-r--r-- | fpga/usrp3/lib/io_cap_gen/cat_io_lvds_dual_mode.v | 260 | ||||
| -rw-r--r-- | fpga/usrp3/lib/sim/io_cap_gen/cat_io_lvds_dual_mode_tb/Makefile | 77 | ||||
| -rw-r--r-- | fpga/usrp3/lib/sim/io_cap_gen/cat_io_lvds_dual_mode_tb/cat_io_lvds_dual_mode_tb.sv (renamed from fpga/usrp3/lib/sim/io_cap_gen/cat_io_lvds/cat_io_lvds_dual_mode_tb.v) | 557 | 
3 files changed, 539 insertions, 355 deletions
| diff --git a/fpga/usrp3/lib/io_cap_gen/cat_io_lvds_dual_mode.v b/fpga/usrp3/lib/io_cap_gen/cat_io_lvds_dual_mode.v index 13b6ae1f9..f49cf58d2 100644 --- a/fpga/usrp3/lib/io_cap_gen/cat_io_lvds_dual_mode.v +++ b/fpga/usrp3/lib/io_cap_gen/cat_io_lvds_dual_mode.v @@ -7,15 +7,15 @@  //  // Description:  // -// This is an LVDS interface for the AD9361 (Catalina). It uses the cat_io_lvds  -// module to implement the interface, but supports both 1R1T and 2R2T timing  -// modes while using full LVDS bandwidth. That is, it can support 1R1T at twice  +// This is an LVDS interface for the AD9361 (Catalina). It uses the cat_io_lvds +// module to implement the interface, but supports both 1R1T and 2R2T timing +// modes while using full LVDS bandwidth. That is, it can support 1R1T at twice  // the sample rate of 2R2T.  // -// This is controlled by the a_mimo control signal. When MIMO = 0 (1R1T mode),  -// the radio_clk frequency equals that of rx_clk/2 and the data is output to  -// both radio channels. If MIMO = 1 (2R2T), the frequency of radio_clk equals  -// rx_clk/4 and the data stream is split between channel 0 and channel 1. This is used  +// This is controlled by the a_mimo control signal. When MIMO = 0 (1R1T mode), +// the radio_clk frequency equals that of rx_clk/2 and the data is output to +// both radio channels. If MIMO = 1 (2R2T), the frequency of radio_clk equals +// rx_clk/4 and the data stream is split between channel 0 and channel 1. This is used  // for 2R2T mode.  // @@ -37,7 +37,6 @@ module cat_io_lvds_dual_mode #(    parameter OUTPUT_CLOCK_DELAY = 16,    parameter OUTPUT_DATA_DELAY  = 0  ) ( -  input rst,    input clk200,    // Data and frame timing (asynchronous, glitch free) @@ -51,18 +50,19 @@ module cat_io_lvds_dual_mode #(    input       ctrl_ld_in_data_delay,    input       ctrl_ld_in_clk_delay,    input [4:0] ctrl_out_data_delay, -  input [4:0] ctrl_out_clk_delay,   +  input [4:0] ctrl_out_clk_delay,    input       ctrl_ld_out_data_delay,    input       ctrl_ld_out_clk_delay,    // Baseband sample interface +  input  radio_rst,           // Glitch-free, synchronous to radio_clk    output radio_clk,    // -  output reg        rx_aligned, -  output reg [11:0] rx_i0, -  output reg [11:0] rx_q0, -  output reg [11:0] rx_i1, -  output reg [11:0] rx_q1, +  output reg    rx_aligned, +  output [11:0] rx_i0, +  output [11:0] rx_q0, +  output [11:0] rx_i1, +  output [11:0] rx_q1,    //    input  [11:0] tx_i0,    input  [11:0] tx_q0, @@ -84,7 +84,7 @@ module cat_io_lvds_dual_mode #(    output [5:0] tx_d_p,    output [5:0] tx_d_n  ); -   +    wire radio_clk_1x;    // rx_clk_p divided by 4    wire radio_clk_2x;    // rx_clk_p divided by 2 @@ -115,7 +115,8 @@ module cat_io_lvds_dual_mode #(    // Clock Mux    //--------------------------------------------------------------------------- -  // Use radio_clk_1x when MIMO = 1, radio_clk_2x when MIMO = 0 +  // Select the source for radio_clk. Use radio_clk_1x when MIMO = 1 or +  // radio_clk_2x when MIMO = 0.    BUFGCTRL BUFGCTRL_radio_clk (      .I0      (radio_clk_1x),      .I1      (radio_clk_2x), @@ -146,7 +147,7 @@ module cat_io_lvds_dual_mode #(    //    //   align_2x       ______|‾‾‾‾‾‾‾‾‾‾‾|___________|‾‾‾‾‾‾‾‾‾‾‾|___________|    // -  // These two alignment signals allow us to tell where in the frame period we  +  // These two alignment signals allow us to tell where in the frame period we    // are so that we can deserialize in the correct order.    //    //--------------------------------------------------------------------------- @@ -161,7 +162,7 @@ module cat_io_lvds_dual_mode #(    always @(posedge radio_clk_2x)    begin -    // Align data capture to 1x clock so that we stay in sync with data.  +    // Align data capture to 1x clock so that we stay in sync with data.      // Otherwise, the data might be serialized in the wrong order.      align_2x <= align_1x;    end @@ -171,12 +172,20 @@ module cat_io_lvds_dual_mode #(    // Rx MIMO/SISO Serialization    //---------------------------------------------------------------------------    // -  // This block of code takes the dual outputs when in SISO mode and serializes  -  // them. Because we use the 2x clock when in SISO mode, this allows us to  +  // This block of code takes the dual outputs when in SISO mode and serializes +  // them. Because we use the 2x clock when in SISO mode, this allows us to    // double the data rate when using a single channel.    //    //--------------------------------------------------------------------------- +  wire rx_aligned_t; +  reg rx_aligned_reg; + +  wire [11:0] rx_i0_t; +  wire [11:0] rx_q0_t; +  wire [11:0] rx_i1_t; +  wire [11:0] rx_q1_t; +    reg [11:0] rx_i0_ser;    reg [11:0] rx_q0_ser;    reg [11:0] rx_i1_ser; @@ -187,19 +196,21 @@ module cat_io_lvds_dual_mode #(    reg [11:0] rx_i1_out;    reg [11:0] rx_q1_out; +  reg rx_out_val; +    always @(posedge radio_clk_2x)    begin -    rx_aligned <= rx_aligned_t; +    rx_aligned_reg <= rx_aligned_t;      if (align_1x ^ align_2x) begin -      // This clock cycle corresponds to the first 1x cycle in which two  +      // This clock cycle corresponds to the first 1x cycle in which two        // samples are output, so grab data from port 0.        rx_i0_ser <= rx_i0_t;        rx_q0_ser <= rx_q0_t;        rx_i1_ser <= rx_i0_t;        rx_q1_ser <= rx_q0_t;      end else begin -      // This radio_clk_2x cycle corresponds to the second 1x cycle in which  +      // This radio_clk_2x cycle corresponds to the second 1x cycle in which        // two samples are output, so grab data from port 1.        rx_i0_ser <= rx_i1_t;        rx_q0_ser <= rx_q1_t; @@ -209,11 +220,17 @@ module cat_io_lvds_dual_mode #(      // Select the correct Rx output based on MIMO setting      if (r_mimo) begin +      // In MIMO mode, we get new data for both channels every other +      // radio_clk_2x clock cycle. +      rx_out_val <= ~rx_out_val;        rx_i0_out <= rx_i0_t;        rx_q0_out <= rx_q0_t;        rx_i1_out <= rx_i1_t;        rx_q1_out <= rx_q1_t;      end else begin +      // In SISO mode, we get new data for one channel on every radio_clk_2x +      // cock cycle. +      rx_out_val <= 1'b1;        rx_i0_out <= rx_i0_ser;        rx_q0_out <= rx_q0_ser;        rx_i1_out <= rx_i1_ser; @@ -223,35 +240,106 @@ module cat_io_lvds_dual_mode #(    //--------------------------------------------------------------------------- -  // Synchronize Rx to radio_clk Domain +  // Cross RX Data from radio_clk_2x to radio_clk Domain    //---------------------------------------------------------------------------    // -  //  This crosses the radio data from the radio_clk_1x domain to the radio_clk  -  //  domain. We use the falling edge of radio_clk to allow for the BUFG  -  //  insertion delay. +  //  The clocks are synchronous and the data input rate matches the data +  //  output rate, so this FIFO should never overflow or underflow once it is +  //  primed and starts being read.    //    //--------------------------------------------------------------------------- -  reg [11:0] rx_i0_fall; -  reg [11:0] rx_q0_fall; -  reg [11:0] rx_i1_fall; -  reg [11:0] rx_q1_fall; -    -  always @(negedge radio_clk) -  begin -    rx_i0_fall <= rx_i0_out; -    rx_q0_fall <= rx_q0_out; -    rx_i1_fall <= rx_i1_out; -    rx_q1_fall <= rx_q1_out; +  wire rx_fifo_full; +  wire rx_fifo_empty; +  reg  rx_fifo_rd_en; + +  fifo_short_2clk fifo_short_2clk_rx ( +    .rst           (radio_rst),         // Asynchronous reset input +    .wr_clk        (radio_clk_2x), +    .rd_clk        (radio_clk), +    .din           ({rx_i1_out, rx_q1_out, rx_i0_out, rx_q0_out}), +    .wr_en         (rx_out_val & ~rx_fifo_full & rx_aligned_reg), +    .rd_en         (rx_fifo_rd_en & ~rx_fifo_empty), +    .dout          ({rx_i1, rx_q1, rx_i0, rx_q0 }), +    .full          (rx_fifo_full), +    .empty         (rx_fifo_empty), +    .rd_data_count (), +    .wr_data_count () +  ); + +  // Wait until the FIFO is partially filled before we start reading out data. +  // Go back to waiting if the FIFO empties. +  always @(posedge radio_clk) begin +    if (radio_rst) begin +      rx_fifo_rd_en <= 1'b0; +      rx_aligned    <= 1'b0; +    end else begin +      if (!rx_fifo_empty) begin +        rx_fifo_rd_en <= 1'b1; +        rx_aligned    <= 1'b1; +      end else if (rx_fifo_empty) begin +        rx_fifo_rd_en <= 1'b0; +        rx_aligned    <= 1'b0; +      end +    end    end -  // Re-clock data on the rising edge to present the whole period to external IP -  always @(posedge radio_clk) -  begin -    rx_i0 <= rx_i0_fall; -    rx_q0 <= rx_q0_fall; -    rx_i1 <= rx_i1_fall; -    rx_q1 <= rx_q1_fall; + +  //--------------------------------------------------------------------------- +  // Cross TX Data from radio_clk domain to radio_clk_2x Domain +  //--------------------------------------------------------------------------- +  // +  //  The clocks are synchronous and the data input rate matches the data +  //  output rate, so this FIFO should never overflow or underflow once it is +  //  primed and starts being read. +  // +  //--------------------------------------------------------------------------- + +  // Cross the radio_rst to radio_clk_2x +  synchronizer #( +    .INITIAL_VAL (1'b1) +  ) synchronizer_radio_rst_2x ( +    .clk (radio_clk_2x), +    .rst (1'b0), +    .in  (radio_rst), +    .out (radio_rst_2x) +  ); + +  wire [11:0] tx_i0_del0; +  wire [11:0] tx_q0_del0; +  wire [11:0] tx_i1_del0; +  wire [11:0] tx_q1_del0; + +  wire tx_fifo_full; +  wire tx_fifo_empty; +  reg  tx_fifo_rd_en; + +  fifo_short_2clk fifo_short_2clk_tx ( +    .rst           (radio_rst),         // Asynchronous reset input +    .wr_clk        (radio_clk), +    .rd_clk        (radio_clk_2x), +    .din           ({tx_i1, tx_q1, tx_i0, tx_q0}), +    .wr_en         (~tx_fifo_full), +    .rd_en         (tx_fifo_rd_en & ~tx_fifo_empty), +    .dout          ({tx_i1_del0, tx_q1_del0, tx_i0_del0, tx_q0_del0}), +    .full          (tx_fifo_full), +    .empty         (tx_fifo_empty), +    .rd_data_count (), +    .wr_data_count () +  ); + +  // Wait until the FIFO is partially filled before we start reading out data. +  // Go back to waiting if the FIFO empties. +  always @(posedge radio_clk_2x) begin +    if (radio_rst_2x) begin +      tx_fifo_rd_en <= 1'b0; +    end else begin +      if (!tx_fifo_empty) begin +        tx_fifo_rd_en <= 1'b1; +      end else if (tx_fifo_empty) begin +        tx_fifo_rd_en <= 1'b0; +      end +    end    end @@ -259,51 +347,56 @@ module cat_io_lvds_dual_mode #(    // Tx MIMO/SISO Deserialization    //---------------------------------------------------------------------------    // -  // This block of code takes the serialized output from the radios and  -  // parallelizes it onto the two radio ports of the Catalina interface. It  -  // also takes the radio data, output on the radio_clk domain, and crosses it  +  // This block of code takes the serialized output from the radios and +  // parallelizes it onto the two radio ports of the Catalina interface. It +  // also takes the radio data, output on the radio_clk domain, and crosses it    // to the radio_clk_1x domain.    //    //--------------------------------------------------------------------------- -  reg [11:0] tx_i0_del; -  reg [11:0] tx_q0_del; -  reg [11:0] tx_i1_del; -  reg [11:0] tx_q1_del; +  reg [11:0] tx_i0_del1; +  reg [11:0] tx_q0_del1; +  reg [11:0] tx_i1_del1; +  reg [11:0] tx_q1_del1; + +  reg [11:0] tx_i0_t; +  reg [11:0] tx_q0_t; +  reg [11:0] tx_i1_t; +  reg [11:0] tx_q1_t;    always @(posedge radio_clk_2x)    begin -    // Capture copy of the data delayed by one radio_clk_2c cycle. -    tx_i0_del <= tx_i0; -    tx_q0_del <= tx_q0; -    tx_i1_del <= tx_i1; -    tx_q1_del <= tx_q1; +    // Capture copy of the data delayed by one radio_clk_2x cycle. +    tx_i0_del1 <= tx_i0_del0; +    tx_q0_del1 <= tx_q0_del0; +    tx_i1_del1 <= tx_i1_del0; +    tx_q1_del1 <= tx_q1_del0;    end    always @(posedge radio_clk_1x)    begin      if (r_mimo) begin -      // In MIMO mode, radio_clk is radio_clk_1x, so we just capture the same  +      // In MIMO mode, radio_clk is radio_clk_1x, so we just capture the same        // data for each radio_clk_1x cycle. -      tx_i0_t <= tx_i0; -      tx_q0_t <= tx_q0; -      tx_i1_t <= tx_i1; -      tx_q1_t <= tx_q1; +      tx_i0_t <= tx_i0_del0; +      tx_q0_t <= tx_q0_del0; +      tx_i1_t <= tx_i1_del0; +      tx_q1_t <= tx_q1_del0;      end else begin -      // In SISO mode, data is updated every radio_clk_2x cycle, so we output  -      // the data from the previous radio_clk_2x cycle onto channel 0 and the  -      // data from the current radio_clk_2x cycle onto channel 1. This puts the  +      // In SISO mode, data is updated every radio_clk_2x cycle, so we output +      // the data from the previous radio_clk_2x cycle onto channel 0 and the +      // data from the current radio_clk_2x cycle onto channel 1. This puts the        // data in the correct order when in 1R1T mode.        if (r_tx_ch == 0) begin -        tx_i0_t <= tx_i0_del; -        tx_q0_t <= tx_q0_del; -        tx_i1_t <= tx_i0; -        tx_q1_t <= tx_q0; +        tx_i0_t <= tx_i0_del1; +        tx_q0_t <= tx_q0_del1; +        tx_i1_t <= tx_i0_del0; +        tx_q1_t <= tx_q0_del0;        end else begin -        tx_i0_t <= tx_i1_del; -        tx_q0_t <= tx_q1_del; -        tx_i1_t <= tx_i1; -        tx_q1_t <= tx_q1; +        tx_i0_t <= tx_i1_del1; +        tx_q0_t <= tx_q1_del1; +        tx_i1_t <= tx_i1_del0; +        tx_q1_t <= tx_q1_del0;        end      end    end @@ -313,17 +406,6 @@ module cat_io_lvds_dual_mode #(    // Catalina TX/RX Interface    //--------------------------------------------------------------------------- -  wire        rx_aligned_t; -  wire [11:0] rx_i0_t; -  wire [11:0] rx_q0_t; -  wire [11:0] rx_i1_t; -  wire [11:0] rx_q1_t; - -  reg [11:0] tx_i0_t; -  reg [11:0] tx_q0_t; -  reg [11:0] tx_i1_t; -  reg [11:0] tx_q1_t; -      cat_io_lvds #(      .INVERT_FRAME_RX    (0),      .INVERT_DATA_RX     (6'b00_0000), @@ -343,13 +425,13 @@ module cat_io_lvds_dual_mode #(      .OUTPUT_DATA_DELAY  (OUTPUT_DATA_DELAY),      .USE_BUFG           (0)    ) cat_io_lvds_i0 ( -    .rst    (rst), +    .rst    (radio_rst),      .clk200 (clk200), -     +      // Data and frame timing      .mimo         (1),       // Set to 1 to always return all samples      .frame_sample (~r_mimo), // Frame timing corresponds to SISO/MIMO setting -     +      // Delay control interface      .ctrl_clk               (ctrl_clk),      // @@ -362,7 +444,7 @@ module cat_io_lvds_dual_mode #(      .ctrl_out_clk_delay     (ctrl_out_clk_delay),      .ctrl_ld_out_data_delay (ctrl_ld_out_data_delay),      .ctrl_ld_out_clk_delay  (ctrl_ld_out_clk_delay), -     +      // Baseband sample interface      .radio_clk    (radio_clk_1x),      .radio_clk_2x (radio_clk_2x), @@ -377,7 +459,7 @@ module cat_io_lvds_dual_mode #(      .tx_q0        (tx_q0_t),      .tx_i1        (tx_i1_t),      .tx_q1        (tx_q1_t), -     +      // Catalina interface      .rx_clk_p   (rx_clk_p),      .rx_clk_n   (rx_clk_n), diff --git a/fpga/usrp3/lib/sim/io_cap_gen/cat_io_lvds_dual_mode_tb/Makefile b/fpga/usrp3/lib/sim/io_cap_gen/cat_io_lvds_dual_mode_tb/Makefile new file mode 100644 index 000000000..20795a9a8 --- /dev/null +++ b/fpga/usrp3/lib/sim/io_cap_gen/cat_io_lvds_dual_mode_tb/Makefile @@ -0,0 +1,77 @@ +# +# Copyright 2020 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# + +#------------------------------------------------- +# Top-of-Makefile +#------------------------------------------------- +# Define BASE_DIR to point to the "top" dir. +BASE_DIR = $(abspath ../../../../top) +# Include viv_sim_preample after defining BASE_DIR +include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak + +#------------------------------------------------- +# Design Specific +#------------------------------------------------- +# Define part using PART_ID (<device>/<package>/<speedgrade>) +ARCH = kintex7 +PART_ID = xc7k410t/ffg900/-2 + +# Include makefiles and sources for the DUT and its dependencies +include $(BASE_DIR)/../lib/fifo/Makefile.srcs +include $(BASE_DIR)/../lib/axi/Makefile.srcs +include $(BASE_DIR)/../lib/control/Makefile.srcs +include $(BASE_DIR)/../lib/io_cap_gen/Makefile.srcs + +DESIGN_SRCS += $(abspath \ +$(FIFO_SRCS) \ +$(AXI_SRCS) \ +$(CONTROL_LIB_SRCS) \ +$(CAT_CAP_GEN_SRCS) \ +) + +#------------------------------------------------- +# IP Specific +#------------------------------------------------- +# If simulation contains IP, define the IP_DIR and point +# it to the base level IP directory +IP_DIR = $(BASE_DIR)/e320/ip +LIB_IP_DIR = $(BASE_DIR)/../lib/ip + +# Include makefiles and sources for all IP components +# *after* defining the IP_DIR +include $(IP_DIR)/fifo_short_2clk/Makefile.inc + +DESIGN_SRCS += $(abspath \ +$(IP_FIFO_SHORT_2CLK_SRCS) \ +) + +#------------------------------------------------- +# Testbench Specific +#------------------------------------------------- +include $(BASE_DIR)/../sim/general/Makefile.srcs +include $(BASE_DIR)/../sim/axi/Makefile.srcs + +MODELSIM_LIBS += unisims_ver secureip fifo_generator_v13_2_4 + +# Define only one top-level module +SIM_TOP = cat_io_lvds_dual_mode_tb glbl + +# Simulation runtime in microseconds +SIM_RUNTIME_US = 1000 + +SIM_SRCS = \ +$(IP_BUILD_DIR)/fifo_short_2clk/simulation/fifo_generator_vlog_beh.v \ +$(IP_BUILD_DIR)/fifo_short_2clk/sim/fifo_short_2clk.v \ +$(abspath cat_io_lvds_dual_mode_tb.sv) \ +$(VIVADO_PATH)/data/verilog/src/glbl.v \ + +#------------------------------------------------- +# Bottom-of-Makefile +#------------------------------------------------- +# Include all simulator specific makefiles here +# Each should define a unique target to simulate +# e.g. xsim, vsim, etc and a common "clean" target +include $(BASE_DIR)/../tools/make/viv_simulator.mak diff --git a/fpga/usrp3/lib/sim/io_cap_gen/cat_io_lvds/cat_io_lvds_dual_mode_tb.v b/fpga/usrp3/lib/sim/io_cap_gen/cat_io_lvds_dual_mode_tb/cat_io_lvds_dual_mode_tb.sv index ecb744086..c2a1d1e3c 100644 --- a/fpga/usrp3/lib/sim/io_cap_gen/cat_io_lvds/cat_io_lvds_dual_mode_tb.v +++ b/fpga/usrp3/lib/sim/io_cap_gen/cat_io_lvds_dual_mode_tb/cat_io_lvds_dual_mode_tb.sv @@ -1,17 +1,20 @@  // -// Copyright 2016 Ettus Research, A National Instruments Company +// Copyright 2020 Ettus Research, A National Instruments Company  //  // SPDX-License-Identifier: LGPL-3.0-or-later  //  // Module: cat_io_lvds_dual_mode_tb  // -// Description: Testbench for cat_io_lvds_dual_mode.  +// Description: Testbench for cat_io_lvds_dual_mode.  //  `timescale 1ns/1ps  module cat_io_lvds_dual_mode_tb(); +  `include "test_exec.svh" +  import PkgTestExec::*; +    localparam CLK_PERIOD    = 10;    localparam CLK200_PERIOD = 2.5; @@ -28,8 +31,7 @@ module cat_io_lvds_dual_mode_tb();    localparam OUTPUT_CLOCK_DELAY = 31;    localparam OUTPUT_DATA_DELAY  = 0; -  reg [8*19:0] test_status; -  reg          check_enabled;   // Controls when output checking is performed +  reg       check_enabled;   // Controls when output checking is performed    reg       clk    = 0;    reg       rx_clk = 0; @@ -42,7 +44,7 @@ module cat_io_lvds_dual_mode_tb();    reg       rx_frame;    reg [7:0] rx_count = 0; -  // Each channel's data begins with a unique identifier (A../B.. or C../D..)  +  // Each channel's data begins with a unique identifier (A../B.. or C../D..)    // followed by a count, which should always be sequential.    wire [11:0] i0 = { 4'hA, rx_count };    wire [11:0] q0 = { 4'hB, rx_count }; @@ -96,66 +98,78 @@ module cat_io_lvds_dual_mode_tb();    // Tasks    //--------------------------------------------------------------------------- -  // Output a single burst of 2*len samples. In MIMO mode, this consists of len  -  // samples on each channel. In SISO mode, this consists of 2*len samples on   +  // Output a single burst of 2*len samples. In MIMO mode, this consists of len +  // samples on each channel. In SISO mode, this consists of 2*len samples on    // the same channel. -  task Burst; -    input [31:0] len; -    input        do_mimo; -    begin -      repeat(len) -        begin -          mimo <= do_mimo; - -          // Channel 0 sample -          @(posedge clk); -          rx_d <= i0[11:6]; -          rx_frame <= 1; -          @(posedge clk); -          rx_d <= q0[11:6]; -          rx_frame <= 1; -          @(posedge clk); -          rx_d <= i0[5:0]; -          rx_frame <= do_mimo; -          @(posedge clk); -          rx_d <= q0[5:0]; -          rx_frame <= do_mimo; - -          // Channel 1 sample / Second channel 0 sample -          @(posedge clk); -          rx_d <= i1[11:6]; -          rx_frame <= ~do_mimo; -          @(posedge clk); -          rx_d <= q1[11:6]; -          rx_frame <= ~do_mimo; -          @(posedge clk); -          rx_d <= i1[5:0]; -          rx_frame <= 0; -          @(posedge clk); -          rx_d <= q1[5:0]; -          rx_frame <= 0; - -          rx_count <= rx_count + 1; -        end -    end -  endtask // Burst +  task Burst(int len, logic do_mimo); +    repeat(len) +      begin +        mimo <= do_mimo; + +        // Channel 0 sample +        @(posedge clk); +        rx_d <= i0[11:6]; +        rx_frame <= 1; +        @(posedge clk); +        rx_d <= q0[11:6]; +        rx_frame <= 1; +        @(posedge clk); +        rx_d <= i0[5:0]; +        rx_frame <= do_mimo; +        @(posedge clk); +        rx_d <= q0[5:0]; +        rx_frame <= do_mimo; + +        // Channel 1 sample / Second channel 0 sample +        @(posedge clk); +        rx_d <= i1[11:6]; +        rx_frame <= ~do_mimo; +        @(posedge clk); +        rx_d <= q1[11:6]; +        rx_frame <= ~do_mimo; +        @(posedge clk); +        rx_d <= i1[5:0]; +        rx_frame <= 0; +        @(posedge clk); +        rx_d <= q1[5:0]; +        rx_frame <= 0; + +        rx_count <= rx_count + 1; +      end +  endtask : Burst -  // Test receiving/transmitting 2*len samples, checking len-2 for correctness.  -  // The output is checked by the Tx and Rx Output Checkers below. We have to  -  // be a little bit careful when we enable output checking, because it takes a  -  // few clock cycles for data to propagate through, and we don't want to check  +  // Output zeros for len clk cycles (model what happens when the RFDC stops +  // giving us data). +  task Idle(int len = 100); +    rx_d     <= 0; +    rx_frame <= 0; +    repeat (len) @(posedge clk); +  endtask : Idle + + +  task Reset(int num_cycles = 20); +    reset <= 1; +    repeat(num_cycles) @(negedge rx_clk); +    reset <= 0; +    repeat(2) @(negedge rx_clk); +  endtask : Reset + + +  // Test receiving/transmitting 2*len samples, checking len-2 for correctness. +  // The output is checked by the Tx and Rx Output Checkers below. We have to +  // be a little bit careful when we enable output checking, because it takes a +  // few clock cycles for data to propagate through, and we don't want to check    // the outputs when the outputs are not valid.    task TestBurst;      input [31:0] len;      input        do_mimo;      begin        if (len <= 2) begin -        $display("ERROR @%0t in %m: In TestBurst, len must be > 2", $time); -        $finish; +        $fatal(1, "ERROR @%0t in %m: In TestBurst, len must be > 2", $time);        end -      // Input several bursts, to fill the pipeline and cause results on the  +      // Input several bursts, to fill the pipeline and cause results on the        // outputs before we start checking.        Burst(1, do_mimo); @@ -178,183 +192,212 @@ module cat_io_lvds_dual_mode_tb();    // Test Procedure    //--------------------------------------------------------------------------- -  initial -    begin -      // Initial values -      check_enabled <= 1'b0; -      test_status <= "Reset"; -      reset = 1; -      mimo  = 1; -      ctrl_in_clk_delay      = INPUT_CLOCK_DELAY; -      ctrl_in_data_delay     = INPUT_DATA_DELAY; -      ctrl_ld_in_data_delay  = 1'b0; -      ctrl_ld_in_clk_delay   = 1'b0; -      ctrl_out_clk_delay     = OUTPUT_CLOCK_DELAY; -      ctrl_out_data_delay    = OUTPUT_DATA_DELAY; -      ctrl_ld_out_data_delay = 1'b0; +  initial begin : main + +    test.start_tb("cat_io_lvds_dual_mode_tb"); + +    // Initial values +    check_enabled <= 1'b0; +    reset = 1; +    mimo  = 1; +    ctrl_in_clk_delay      = INPUT_CLOCK_DELAY; +    ctrl_in_data_delay     = INPUT_DATA_DELAY; +    ctrl_ld_in_data_delay  = 1'b0; +    ctrl_ld_in_clk_delay   = 1'b0; +    ctrl_out_clk_delay     = OUTPUT_CLOCK_DELAY; +    ctrl_out_data_delay    = OUTPUT_DATA_DELAY; +    ctrl_ld_out_data_delay = 1'b0; +    ctrl_ld_out_clk_delay  = 1'b0; + +    Reset(); + +    //----------------------------------------------------------------------- +    // Test Changing Delays + +    test.start_test("Load IO delays"); + +    if (CLOCK_IDELAY_MODE == "VAR_LOAD") begin +      ctrl_ld_in_clk_delay  = 1'b1; +      @(negedge rx_clk); +      ctrl_ld_in_clk_delay  = 1'b0; +      @(negedge rx_clk); +    end + +    if (DATA_IDELAY_MODE == "VAR_LOAD") begin +      ctrl_ld_in_data_delay = 1'b1; +      @(negedge rx_clk); +      ctrl_ld_in_data_delay = 1'b0; +      @(negedge rx_clk); +    end + +    if (CLOCK_ODELAY_MODE == "VAR_LOAD") begin +      ctrl_ld_out_clk_delay  = 1'b1; +      @(negedge rx_clk);        ctrl_ld_out_clk_delay  = 1'b0; -      repeat(10) @(negedge rx_clk); -      reset = 0;        @(negedge rx_clk); +    end -      //----------------------------------------------------------------------- -      // Test Changing Delays +    if (DATA_ODELAY_MODE == "VAR_LOAD") begin +      ctrl_ld_out_data_delay = 1'b1; +      @(negedge rx_clk); +      ctrl_ld_out_data_delay = 1'b0; +      @(negedge rx_clk); +    end -      test_status <= "Load IO delays"; +    test.end_test(); -      if (CLOCK_IDELAY_MODE == "VAR_LOAD") begin -        ctrl_ld_in_clk_delay  = 1'b1; -        @(negedge rx_clk); -        ctrl_ld_in_clk_delay  = 1'b0; -        @(negedge rx_clk); -      end +    //----------------------------------------------------------------------- +    // Startup -      if (DATA_IDELAY_MODE == "VAR_LOAD") begin -        ctrl_ld_in_data_delay = 1'b1; -        @(negedge rx_clk); -        ctrl_ld_in_data_delay = 1'b0; -        @(negedge rx_clk); -      end +    test.start_test("Load IO delays"); -      if (CLOCK_ODELAY_MODE == "VAR_LOAD") begin -        ctrl_ld_out_clk_delay  = 1'b1; -        @(negedge rx_clk); -        ctrl_ld_out_clk_delay  = 1'b0; -        @(negedge rx_clk); -      end +    // Pump a few clock cycles to get things started (flush out X values) +    Burst(2,1); -      if (DATA_ODELAY_MODE == "VAR_LOAD") begin -        ctrl_ld_out_data_delay = 1'b1; -        @(negedge rx_clk); -        ctrl_ld_out_data_delay = 1'b0; -        @(negedge rx_clk); -      end +    test.end_test(); -      //----------------------------------------------------------------------- -      // Startup -      test_status <= "Startup"; +    //----------------------------------------------------------------------- +    // Test MIMO -      // Pump a few clock cycles to get things started (flush out X values) -      Burst(2,1); +    test.start_test("Test MIMO"); -      //----------------------------------------------------------------------- -      // Test MIMO +    // Input data until the Rx circuit aligns +    $display("Wait align 1"); +    while (!rx_aligned) begin +      Burst(1,1); +    end -      // Input data until the Rx circuit aligns -      test_status <= "Wait align 1"; -      while (!rx_aligned) begin -        Burst(1,1); -      end +    // Input some new samples +    $display("Burst 1 (MIMO)"); +    TestBurst(30, 1); -      // Input some new samples -      test_status <= "Burst 1 (MIMO)"; -      TestBurst(30, 1); - -      // Reset and do another burst -      test_status <= "Reset 2"; -      reset = 1; -      repeat(20) @(negedge rx_clk); -      reset = 0; -      repeat(2) @(negedge rx_clk);       - -      // Input data until the Rx circuit aligns -      test_status <= "Wait align 2"; -      while (!rx_aligned) begin -        Burst(1,1); -      end +    // Reset and do another burst +    $display("Reset 2"); +    Reset(); -      // Input some new samples -      test_status <= "Burst 2 (MIMO)"; -      TestBurst(23, 1); +    // Input data until the Rx circuit aligns +    $display("Wait align 2"); +    while (!rx_aligned) begin +      Burst(1,1); +    end -      //----------------------------------------------------------------------- -      // Test SISO (transmit channel 0) +    // Input some new samples +    $display("Burst 2 (MIMO)"); +    TestBurst(23, 1); -      tx_ch <= 1'b0; +    test.end_test(); -      // Reset and do another burst -      test_status <= "Reset 3"; -      reset = 1; -      repeat(20) @(negedge rx_clk); -      reset = 0; -      repeat(2) @(negedge rx_clk);       +    //----------------------------------------------------------------------- +    // Test SISO (transmit channel 0) -      // Input data until the Rx circuit aligns in SISO mode -      test_status <= "Wait align 3"; -      while (!rx_aligned) begin -        Burst(1,0); -      end +    test.start_test("Test SISO (transmit channel 0)"); -      // Test SISO mode -      test_status <= "Burst 3 (SISO, Ch 0)"; -      TestBurst(25, 0); - -      // Reset and do another burst -      test_status <= "Reset 4"; -      reset = 1; -      repeat(20) @(negedge rx_clk); -      reset = 0; -      repeat(2) @(negedge rx_clk);       - -      // Input data until the Rx circuit aligns in SISO mode -      test_status <= "Wait align 4"; -      while (!rx_aligned) begin -        Burst(1,0); -      end +    tx_ch <= 1'b0; -      // Test SISO mode -      test_status <= "Burst 4 (SISO, Ch 0)"; -      TestBurst(27, 0); +    // Reset and do another burst +    $display("Reset 3"); +    Reset(); -      //----------------------------------------------------------------------- -      // Test SISO (transmit channel 1) +    // Input data until the Rx circuit aligns in SISO mode +    $display("Wait align 3"); +    while (!rx_aligned) Burst(1,0); -      tx_ch <= 1'b1; +    // Test SISO mode +    $display("Burst 3 (SISO, Ch 0)"); +    TestBurst(25, 0); -      // Reset and do another burst -      test_status <= "Reset 5"; -      reset = 1; -      repeat(20) @(negedge rx_clk); -      reset = 0; -      repeat(2) @(negedge rx_clk);       +    // Reset and do another burst +    $display("Reset 4"); +    Reset(); -      // Input data until the Rx circuit aligns in SISO mode -      test_status <= "Wait align 5"; -      while (!rx_aligned) begin -        Burst(1,0); -      end +    // Input data until the Rx circuit aligns in SISO mode +    $display("Wait align 4"); +    while (!rx_aligned) Burst(1,0); -      // Test SISO mode -      test_status <= "Burst 5 (SISO, Ch 1)"; -      TestBurst(25, 0); - -      // Reset and do another burst -      test_status <= "Reset 6"; -      reset = 1; -      repeat(20) @(negedge rx_clk); -      reset = 0; -      repeat(2) @(negedge rx_clk);       - -      // Input data until the Rx circuit aligns in SISO mode -      test_status <= "Wait align 6"; -      while (!rx_aligned) begin -        Burst(1,0); -      end +    // Test SISO mode +    $display("Burst 4 (SISO, Ch 0)"); +    TestBurst(27, 0); -      // Test SISO mode -      test_status <= "Burst 6 (SISO, Ch 1)"; -      TestBurst(27, 0); +    test.end_test(); -      //----------------------------------------------------------------------- -      // Done +    //----------------------------------------------------------------------- +    // Test SISO (transmit channel 1) + +    test.start_test("Test SISO (transmit channel 1)"); + +    tx_ch <= 1'b1; + +    // Reset and do another burst +    $display("Reset 5"); +    Reset(); + +    // Input data until the Rx circuit aligns in SISO mode +    $display("Wait align 5"); +    while (!rx_aligned) Burst(1,0); + +    // Test SISO mode +    $display("Burst 5 (SISO, Ch 1)"); +    TestBurst(25, 0); + +    // Reset and do another burst +    $display("Reset 6"); +    Reset(); + +    // Input data until the Rx circuit aligns in SISO mode +    $display("Wait align 6"); +    while (!rx_aligned) Burst(1,0); + +    // Test SISO mode +    $display("Burst 6 (SISO, Ch 1)"); +    TestBurst(27, 0); + +    test.end_test(); + +    //----------------------------------------------------------------------- +    // Test going Idle then starting SISO, without reset + +    test.start_test("Test Idle then SISO"); + +    tx_ch <= 1'b1; + +    $display("Wait idle flush 6"); +    while (rx_aligned) Idle(1); +    $display("Wait align 6"); +    while (!rx_aligned) Burst(1,0); -      test_status <= "Finished"; -      repeat(50) @(negedge rx_clk); +    // Test SISO mode +    $display("Burst 6 (SISO, Ch 1)"); +    TestBurst(25, 0); -      $finish; +    test.end_test(); + +    //----------------------------------------------------------------------- +    // Test going Idle then starting MIMO, without reset + +    test.start_test("Test Idle then MIMO"); + +    tx_ch <= 1'b1; + +    $display("Wait idle flush 7"); +    while (rx_aligned) Idle(1); +    $display("Wait align 7"); +    while (!rx_aligned) begin +      Burst(1,1);      end +    // Test SISO mode +    $display("Burst 7 (SISO, Ch 1)"); +    TestBurst(25, 1); + +    test.end_test(); + +    //----------------------------------------------------------------------- +    // Done + +    test.end_tb(); +  end : main +    //---------------------------------------------------------------------------    // Rx Output Checker @@ -391,78 +434,69 @@ module cat_io_lvds_dual_mode_tb();            // Check prefix for channel 0            if (rx_i0[11:8] != 4'hA || rx_q0[11:8] != 4'hB) begin -            $display("ERROR @%0t in %m: Rx channel 0 didn't have expected A/B prefix in MIMO mode", $time); -            $finish; +            $fatal(1, "ERROR in %m: Rx channel 0 didn't have expected A/B prefix in MIMO mode");            end            // Check prefix for channel 1            if (rx_i1[11:8] != 4'hC || rx_q1[11:8] != 4'hD) begin -            $display("ERROR @%0t in %m: Rx channel 1 didn't have expected C/D in MIMO mode", $time); -            $finish; +            $fatal(1, "ERROR in %m: Rx channel 1 didn't have expected C/D in MIMO mode");            end            // All outputs should have the same count in MIMO mode            if (! (rx_i0[7:0] == rx_q0[7:0] && -                 rx_i0[7:0] == rx_i1[7:0] &&  +                 rx_i0[7:0] == rx_i1[7:0] &&                   rx_i0[7:0] == rx_q1[7:0]) ) begin -            $display("ERROR @%0t in %m: Rx data counts didn't match on all outputs in MIMO mode", $time); -            $finish; +            $fatal(1, "ERROR in %m: Rx data counts didn't match on all outputs in MIMO mode");            end            // Make sure the count increments            if (rx_i0[7:0] != rx_i0_del1[7:0] + 8'd1 || rx_q0[7:0] != rx_q0_del1[7:0] + 8'd1 ||                rx_i1[7:0] != rx_i1_del1[7:0] + 8'd1 || rx_q1[7:0] != rx_q1_del1[7:0] + 8'd1) begin -            $display("ERROR @%0t in %m: Rx data count didn't increment as expected", $time); -            $finish; +            $fatal(1, "ERROR in %m: Rx data count didn't increment as expected");            end          end else begin  // if (mimo)            // In SISO mode, both outputs should be the same            if (rx_i0 != rx_i1 || rx_q0 != rx_q1) begin -            $display("ERROR @%0t in %m: Rx channel 0 and 1 don't match in SISO mode", $time); -            $finish; +            $fatal(1, "ERROR in %m: Rx channel 0 and 1 don't match in SISO mode");            end -          // Check channel 0 prefix. No need to check channel 1, since we  +          // Check channel 0 prefix. No need to check channel 1, since we            // already checked that the channels match. -          if (!((rx_i0[11:8] == 4'hA && rx_q0[11:8] == 4'hB) ||  +          if (!((rx_i0[11:8] == 4'hA && rx_q0[11:8] == 4'hB) ||                  (rx_i0[11:8] == 4'hC && rx_q0[11:8] == 4'hD))) begin -            $display("ERROR @%0t in %m: Rx data didn't have expected A/B or C/D prefix in SISO mode", $time); -            $finish; +            $fatal(1, "ERROR in %m: Rx data didn't have expected A/B or C/D prefix in SISO mode");            end -          // Make sure we're alternating between channel data. No need to check  +          // Make sure we're alternating between channel data. No need to check            // channel 1, since we already checked that the channels match.            if (!((rx_i0[11:8] == 4'hA && rx_i0_del1[11:8] == 4'hC) ||                  (rx_i0[11:8] == 4'hC && rx_i0_del1[11:8] == 4'hA) ||                  (rx_q0[11:8] == 4'hB && rx_q0_del1[11:8] == 4'hD) ||                  (rx_q0[11:8] == 4'hD && rx_q0_del1[11:8] == 4'hB))) begin -            $display("ERROR @%0t in %m: Rx data not toggling between channel data in SISO mode", $time); -            $finish; +            $fatal(1, "ERROR in %m: Rx data not toggling between channel data in SISO mode");            end -          // Make sure the counts are the same for both I and Q. No need to  +          // Make sure the counts are the same for both I and Q. No need to            // check channel 1, since we already checked that the channels match.            if (rx_i0[7:0] != rx_q0[7:0]) begin -            $display("ERROR @%0t in %m: Rx data counts didn't match on all outputs in SISO mode", $time); -            $finish; +            $fatal(1, "ERROR in %m: Rx data counts didn't match on all outputs in SISO mode");            end -          // Make sure the count increments every other clock cycle. No need to  +          // Make sure the count increments every other clock cycle. No need to            // check channel 1, since we already checked that the channels match.            if (!(                rx_i0[7:0] != rx_i0_del2[7:0] + 8'd1 && (rx_i0[7:0] == rx_i0_del1[7:0] || rx_i0[7:0] == rx_i0_del1[7:0] + 8'd1) &&                rx_q0[7:0] != rx_q0_del2[7:0] + 8'd1 && (rx_q0[7:0] == rx_q0_del1[7:0] || rx_q0[7:0] == rx_q0_del1[7:0] + 8'd1)              )) begin -            $display("ERROR @%0t in %m: Rx data count didn't increment as expected", $time); -            $finish; +            $fatal(1, "ERROR in %m: Rx data count didn't increment as expected");            end          end  // if (mimo)        end  // if (!first_rx_check) -      // Make sure we've captured at least one set of values, so we have a  +      // Make sure we've captured at least one set of values, so we have a        // previous set to look back to.        first_rx_check <= 1'b0; @@ -486,7 +520,7 @@ module cat_io_lvds_dual_mode_tb();    // Tx Output Checker    //---------------------------------------------------------------------------    // -  // The code implements a loopback, so the output should match the input. In  +  // The code implements a loopback, so the output should match the input. In    // SISO mode, however, the frame signal may not be aligned.    //    //--------------------------------------------------------------------------- @@ -549,7 +583,7 @@ module cat_io_lvds_dual_mode_tb();        if (check_enabled) begin          if (!first_tx_check) begin -    +            if (mimo) begin              //-----------------------------------------------------------------              // Check MIMO output @@ -557,55 +591,49 @@ module cat_io_lvds_dual_mode_tb();              // Check that the frame signal is correct              if (tx_frame_check != 8'b11110000) begin -              $display("ERROR @%0t in %m: Tx frame was not correct in MIMO mode", $time); -              $finish; +              $fatal(1, "ERROR @%0t in %m: Tx frame was not correct in MIMO mode", $time);              end -   +              // Check prefix for channel 0              if (tx_i0_check[11:8] != 4'hA || tx_q0_check[11:8] != 4'hB) begin -              $display("ERROR @%0t in %m: Tx channel 0 didn't have expected A/B prefix in MIMO mode", $time); -              $finish; +              $fatal(1, "ERROR @%0t in %m: Tx channel 0 didn't have expected A/B prefix in MIMO mode", $time);              end -   +              // Check prefix for channel 1              if (tx_i1_check[11:8] != 4'hC || tx_q1_check[11:8] != 4'hD) begin -              $display("ERROR @%0t in %m: Tx channel 1 didn't have expected C/D in MIMO mode", $time); -              $finish; +              $fatal(1, "ERROR @%0t in %m: Tx channel 1 didn't have expected C/D in MIMO mode", $time);              end -   +              // All outputs should have the same count in MIMO mode -            if (! (tx_i0_check[7:0] == tx_q0_check[7:0] &&  +            if (! (tx_i0_check[7:0] == tx_q0_check[7:0] &&                     tx_i0_check[7:0] == tx_i1_check[7:0] &&                     tx_i0_check[7:0] == tx_q1_check[7:0]) ) begin -              $display("ERROR @%0t in %m: Rx data counts didn't match on all outputs in MIMO mode", $time); -              $finish; +              $fatal(1, "ERROR @%0t in %m: Rx data counts didn't match on all outputs in MIMO mode", $time);              end -   +              // Make sure the count increments              if (tx_i0_check[7:0] != tx_i0_del1[7:0] + 8'd1 || tx_q0_check[7:0] != tx_q0_del1[7:0] + 8'd1 ||                  tx_i1_check[7:0] != tx_i1_del1[7:0] + 8'd1 || tx_q1_check[7:0] != tx_q1_del1[7:0] + 8'd1) begin -              $display("ERROR @%0t in %m: Rx data count didn't increment as expected", $time); -              $finish; +              $fatal(1, "ERROR @%0t in %m: Rx data count didn't increment as expected", $time);              end -           -          end else begin   + +          end else begin              //-----------------------------------------------------------------              // Check SISO Output              //-----------------------------------------------------------------              // Check that the frame signal is correct              if (tx_frame_check != 8'b11001100) begin -              $display("ERROR @%0t in %m: Tx frame was not correct in SISO mode", $time); -              $finish; +              $fatal(1, "ERROR @%0t in %m: Tx frame was not correct in SISO mode", $time);              end -            // In SISO mode, the data we get depends on which channel is  +            // In SISO mode, the data we get depends on which channel is              // selected.              //              //        Channel 0:                   Channel 1:              //  ...,A01,B01,A02,B02,...  OR  ...,C01,D01,C02,D02,... -            //  +            //              // So we should receive              //              //       A01 A03 A05 @@ -626,40 +654,37 @@ module cat_io_lvds_dual_mode_tb();                ((tx_ch == 0 &&                  tx_i0_check[11:8] == 4'hA &&                  tx_q0_check[11:8] == 4'hB) || -               (tx_ch == 1 &&  +               (tx_ch == 1 &&                  tx_i0_check[11:8] == 4'hC && -                tx_q0_check[11:8] == 4'hD)) &&  +                tx_q0_check[11:8] == 4'hD)) &&                // Samples 0 and 1 prefixes equal samples 2 and 3 prefixes -              (tx_i0_check[11:8] == tx_i1_check[11:8]  &&  +              (tx_i0_check[11:8] == tx_i1_check[11:8]  &&                 tx_q0_check[11:8] == tx_q1_check[11:8])                )) begin -              $display("ERROR @%0t in %m: Tx channel didn't have expected prefixes in SISO mode", $time); -              $finish; +              $fatal(1, "ERROR @%0t in %m: Tx channel didn't have expected prefixes in SISO mode", $time);              end -   +              // Check that the data count matches between samples              if (!(                tx_i0_check[7:0] == tx_q0_check[7:0] &&                tx_i1_check[7:0] == tx_q1_check[7:0] &&                tx_i0_check[7:0] == tx_i1_check[7:0] - 8'd1                )) begin -              $display("ERROR @%0t in %m: Tx channel data counts didn't correlate in SISO mode", $time); -              $finish; +              $fatal(1, "ERROR @%0t in %m: Tx channel data counts didn't correlate in SISO mode", $time);              end              // Make sure the count increments form one burst to the next -            if (tx_i0_check[7:0] != tx_i0_del1[7:0] + 8'd2 ||  +            if (tx_i0_check[7:0] != tx_i0_del1[7:0] + 8'd2 ||                  tx_q0_check[7:0] != tx_q0_del1[7:0] + 8'd2 ||                  tx_i1_check[7:0] != tx_i1_del1[7:0] + 8'd2 ||                  tx_q1_check[7:0] != tx_q1_del1[7:0] + 8'd2) begin -              $display("ERROR @%0t in %m: Tx data count didn't increment as expected", $time); -              $finish; +              $fatal(1, "ERROR @%0t in %m: Tx data count didn't increment as expected", $time);              end -           +            end          end else begin  // if (!first_tx_check) -          // Make sure we've captured at least one set of values, so we have a  +          // Make sure we've captured at least one set of values, so we have a            // previous set to look back to.            first_tx_check <= 1'b0;          end  // if (!first_tx_check) @@ -670,7 +695,7 @@ module cat_io_lvds_dual_mode_tb();          tx_i1_del1 <= tx_i1_check;          tx_q1_del1 <= tx_q1_check; -      end else begin  // if (check_enabled)         +      end else begin  // if (check_enabled)          first_tx_check <= 1'b1;        end  // if (check_enabled) @@ -727,13 +752,12 @@ module cat_io_lvds_dual_mode_tb();      .OUTPUT_CLOCK_DELAY (OUTPUT_CLOCK_DELAY),      .OUTPUT_DATA_DELAY  (OUTPUT_DATA_DELAY)    ) cat_io_lvds_dual_mode_dut ( -    .rst    (reset),      .clk200 (clk200), -     +      // Data and frame timing      .a_mimo  (mimo),      .a_tx_ch (tx_ch), -     +      // Delay control interface      .ctrl_clk               (rx_clk),      // @@ -746,8 +770,9 @@ module cat_io_lvds_dual_mode_tb();      .ctrl_out_clk_delay     (ctrl_out_clk_delay),      .ctrl_ld_out_data_delay (ctrl_ld_out_data_delay),      .ctrl_ld_out_clk_delay  (ctrl_ld_out_clk_delay), -     +      // Baseband sample interface +    .radio_rst  (reset),      .radio_clk  (radio_clk),      .rx_aligned (rx_aligned),      // @@ -760,7 +785,7 @@ module cat_io_lvds_dual_mode_tb();      .tx_q0      (tx_q0),      .tx_i1      (tx_i1),      .tx_q1      (tx_q1), -     +      // Catalina interface      .rx_clk_p   (rx_clk),      .rx_clk_n   (~rx_clk), | 
