aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3
diff options
context:
space:
mode:
authorWade Fife <wade.fife@ettus.com>2020-10-13 16:52:34 -0500
committerWade Fife <wade.fife@ettus.com>2020-12-11 07:41:13 -0600
commitc6578eda2ba482b87583ebd989cdf5cbd5c3f672 (patch)
tree6ef5751015edb1a0a6b6f38ddf16c53612337c3a /fpga/usrp3
parent744e60bd598df4677a88df10d1fceb56e7c1ee36 (diff)
downloaduhd-c6578eda2ba482b87583ebd989cdf5cbd5c3f672.tar.gz
uhd-c6578eda2ba482b87583ebd989cdf5cbd5c3f672.tar.bz2
uhd-c6578eda2ba482b87583ebd989cdf5cbd5c3f672.zip
fpga: e320: Improve timing on LVDS interface
Diffstat (limited to 'fpga/usrp3')
-rw-r--r--fpga/usrp3/lib/io_cap_gen/cat_io_lvds_dual_mode.v260
-rw-r--r--fpga/usrp3/lib/sim/io_cap_gen/cat_io_lvds_dual_mode_tb/Makefile77
-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
-rw-r--r--fpga/usrp3/top/e320/e320.v5
4 files changed, 541 insertions, 358 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),
diff --git a/fpga/usrp3/top/e320/e320.v b/fpga/usrp3/top/e320/e320.v
index 92a8332f8..873677c06 100644
--- a/fpga/usrp3/top/e320/e320.v
+++ b/fpga/usrp3/top/e320/e320.v
@@ -818,7 +818,6 @@ module e320 (
wire [REG_DWIDTH-1:0] dboard_status;
wire mimo_busclk, mimo_radioclk;
wire tx_chan_sel_busclk, tx_chan_sel_radioclk;
- wire rx_aligned;
wire tx_pll_lock_busclk, rx_pll_lock_busclk;
@@ -890,7 +889,6 @@ module e320 (
.OUTPUT_CLOCK_DELAY (0),
.OUTPUT_DATA_DELAY (OUTPUT_DATA_DELAY)
) cat_io_lvds_dual_mode_i0 (
- .rst (radio_rst),
.clk200 (bus_clk), // 200 MHz clock
// Data and frame timing
@@ -911,9 +909,10 @@ module e320 (
.ctrl_ld_out_clk_delay (1'b0),
// Sample interface
+ .radio_rst (radio_rst),
.radio_clk (radio_clk),
- .rx_aligned (rx_aligned),
//
+ .rx_aligned (),
.rx_i0 (rx_i0),
.rx_q0 (rx_q0),
.rx_i1 (rx_i1),