fpga: lib: Add 2 to 1 gearbox module
Original-commit: 7f36cced81fb05d3cc107a0a0773fcdfc26f8d64
This commit is contained in:
committed by
Aaron Rossetto
parent
7fda8365de
commit
b7bd308e9c
@@ -23,6 +23,7 @@ binary_encoder.v \
|
|||||||
db_control.v \
|
db_control.v \
|
||||||
fe_control.v \
|
fe_control.v \
|
||||||
filter_bad_sid.v \
|
filter_bad_sid.v \
|
||||||
|
gearbox_2x1.v \
|
||||||
gpio_atr_io.v \
|
gpio_atr_io.v \
|
||||||
gpio_atr.v \
|
gpio_atr.v \
|
||||||
gray2bin.v \
|
gray2bin.v \
|
||||||
|
|||||||
@@ -0,0 +1,180 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 Ettus Research, a National Instruments Brand
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
//
|
||||||
|
// Module: gearbox_2x1
|
||||||
|
//
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
// Moves data between two clock domains at a constant data rate. This module
|
||||||
|
// requires that the clocks be related and that there is a 2:1 ratio between
|
||||||
|
// the two clocks. Static timing analysis is assumed for the clock domain
|
||||||
|
// crossing. The module supports going from a slow clock to a fast clock (2
|
||||||
|
// words per 1x clock cycle to 1 word per 2x clock cycle) or from a fast
|
||||||
|
// clock to a slow clock (1 word per 1x clock cycle to 2 words per 2x clock
|
||||||
|
// cycles) depending on the parameters provided.
|
||||||
|
//
|
||||||
|
// Note that there are no tready signals, so downstream logic must always be
|
||||||
|
// ready.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
//
|
||||||
|
// WORD_W : Bits per word
|
||||||
|
// IN_WORDS : Number of input words per clock cycle
|
||||||
|
// OUT_WORDS : Number of output words per clock cycle
|
||||||
|
// BIG_ENDIAN : Order in which to input/output words when multiple words per
|
||||||
|
// clock cycle are needed. Little endian means the first word is
|
||||||
|
// in the least-significant position. Big endian means the first
|
||||||
|
// word is in the most-significant position.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
module gearbox_2x1 #(
|
||||||
|
parameter WORD_W = 8,
|
||||||
|
parameter IN_WORDS = 2,
|
||||||
|
parameter OUT_WORDS = 1,
|
||||||
|
parameter BIG_ENDIAN = 0
|
||||||
|
) (
|
||||||
|
input wire i_clk,
|
||||||
|
input wire i_rst,
|
||||||
|
input wire [IN_WORDS*WORD_W-1:0] i_tdata,
|
||||||
|
input wire i_tvalid,
|
||||||
|
|
||||||
|
input wire o_clk,
|
||||||
|
input wire o_rst,
|
||||||
|
output reg [OUT_WORDS*WORD_W-1:0] o_tdata,
|
||||||
|
output reg o_tvalid = 1'b0
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam IN_W = WORD_W * IN_WORDS;
|
||||||
|
localparam OUT_W = WORD_W * OUT_WORDS;
|
||||||
|
|
||||||
|
generate
|
||||||
|
|
||||||
|
// Make sure the ratios are supported
|
||||||
|
if (IN_WORDS != 2*OUT_WORDS && OUT_WORDS != 2*IN_WORDS) begin : gen_ERROR
|
||||||
|
IN_WORDS_and_OUT_WORDS_must_have_a_2_to_1_ratio();
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// 2 words to 1 word (slow clock to fast clock)
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if (IN_WORDS > OUT_WORDS) begin : gen_slow_to_fast
|
||||||
|
reg [IN_W-1:0] i_tdata_reg;
|
||||||
|
reg i_tvalid_reg;
|
||||||
|
reg i_toggle = 1'b0;
|
||||||
|
|
||||||
|
always @(posedge i_clk) begin
|
||||||
|
if (i_rst) begin
|
||||||
|
i_tdata_reg <= 'bX;
|
||||||
|
i_tvalid_reg <= 1'b0;
|
||||||
|
i_toggle <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
i_tdata_reg <= i_tdata;
|
||||||
|
i_tvalid_reg <= i_tvalid;
|
||||||
|
if (i_tvalid) begin
|
||||||
|
i_toggle <= ~i_toggle;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
reg [IN_W-1:0] o_tdata_reg;
|
||||||
|
reg o_tvalid_reg = 1'b0;
|
||||||
|
reg o_toggle;
|
||||||
|
reg o_toggle_dly;
|
||||||
|
reg o_data_sel;
|
||||||
|
|
||||||
|
always @(posedge o_clk) begin
|
||||||
|
if (o_rst) begin
|
||||||
|
o_tdata_reg <= 'bX;
|
||||||
|
o_tvalid <= 1'b0;
|
||||||
|
o_tvalid_reg <= 1'b0;
|
||||||
|
o_toggle <= 1'bX;
|
||||||
|
o_toggle_dly <= 1'bX;
|
||||||
|
o_data_sel <= 1'bX;
|
||||||
|
end else begin
|
||||||
|
// Clock crossing
|
||||||
|
o_tvalid_reg <= i_tvalid_reg;
|
||||||
|
o_toggle <= i_toggle;
|
||||||
|
o_tdata_reg <= i_tdata_reg;
|
||||||
|
|
||||||
|
// Determine which output to select
|
||||||
|
o_toggle_dly <= o_toggle;
|
||||||
|
o_data_sel <= BIG_ENDIAN ^ (o_toggle == o_toggle_dly);
|
||||||
|
|
||||||
|
// Select the correct output for this clock cycle
|
||||||
|
o_tvalid <= o_tvalid_reg;
|
||||||
|
o_tdata <= o_data_sel ?
|
||||||
|
o_tdata_reg[0 +: OUT_W] : o_tdata_reg[IN_W/2 +: OUT_W];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// 1 word to 2 words (fast clock to slow clock)
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
end else begin : gen_fast_to_slow
|
||||||
|
reg [IN_W-1:0] i_gear_reg;
|
||||||
|
reg [OUT_W-1:0] i_gear_tdata;
|
||||||
|
reg i_gear_one_word = 1'b0;
|
||||||
|
reg i_gear_tvalid = 1'b0;
|
||||||
|
reg i_gear_tvalid_dly = 1'b0;
|
||||||
|
|
||||||
|
always @(posedge i_clk) begin
|
||||||
|
if (i_rst) begin
|
||||||
|
i_gear_reg <= 'bX;
|
||||||
|
i_gear_tdata <= 'bX;
|
||||||
|
i_gear_one_word <= 1'b0;
|
||||||
|
i_gear_tvalid <= 1'b0;
|
||||||
|
i_gear_tvalid_dly <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
// Default assignments
|
||||||
|
i_gear_tvalid <= 1'b0;
|
||||||
|
i_gear_tvalid_dly <= i_gear_tvalid;
|
||||||
|
|
||||||
|
if (i_tvalid) begin
|
||||||
|
// Track if the gearbox has one word saved
|
||||||
|
i_gear_one_word <= ~i_gear_one_word;
|
||||||
|
i_gear_reg <= i_tdata;
|
||||||
|
if (i_gear_one_word) begin
|
||||||
|
// This is the second word, so output the new word on i_gear_reg_t*
|
||||||
|
i_gear_tdata <= BIG_ENDIAN ?
|
||||||
|
{ i_gear_reg, i_tdata } : { i_tdata, i_gear_reg };
|
||||||
|
i_gear_tvalid <= 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
reg [OUT_W-1:0] o_gear_tdata;
|
||||||
|
reg o_gear_tvalid = 1'b0;
|
||||||
|
reg o_gear_tvalid_dly = 1'b0;
|
||||||
|
reg o_tvalid_reg = 1'b0;
|
||||||
|
|
||||||
|
always @(posedge o_clk) begin
|
||||||
|
if (o_rst) begin
|
||||||
|
o_gear_tvalid <= 1'b0;
|
||||||
|
o_gear_tvalid_dly <= 1'b0;
|
||||||
|
o_gear_tdata <= 'bX;
|
||||||
|
o_tvalid <= 1'b0;
|
||||||
|
o_tdata <= 'bX;
|
||||||
|
end else begin
|
||||||
|
// Clock crossing
|
||||||
|
o_gear_tvalid <= i_gear_tvalid;
|
||||||
|
o_gear_tvalid_dly <= i_gear_tvalid_dly;
|
||||||
|
o_gear_tdata <= i_gear_tdata;
|
||||||
|
|
||||||
|
// Control tvalid
|
||||||
|
o_tvalid <= o_gear_tvalid | o_gear_tvalid_dly;
|
||||||
|
o_tdata <= o_gear_tdata;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2021 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
|
||||||
|
#-------------------------------------------------
|
||||||
|
|
||||||
|
DESIGN_SRCS += $(abspath \
|
||||||
|
$(abspath ../../../control/gearbox_2x1.v) \
|
||||||
|
)
|
||||||
|
|
||||||
|
#-------------------------------------------------
|
||||||
|
# Testbench Specific
|
||||||
|
#-------------------------------------------------
|
||||||
|
SIM_TOP = gearbox_2x1_all_tb
|
||||||
|
SIM_SRCS = \
|
||||||
|
$(abspath gearbox_2x1_tb.sv) \
|
||||||
|
$(abspath gearbox_2x1_all_tb.sv) \
|
||||||
|
|
||||||
|
#-------------------------------------------------
|
||||||
|
# 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
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 Ettus Research, a National Instruments Brand
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
//
|
||||||
|
// Module: gearbox_2x1_all_tb
|
||||||
|
//
|
||||||
|
// Description: Top-level testbench for gearbox_2x1, testing different
|
||||||
|
// configurations of the module.
|
||||||
|
//
|
||||||
|
|
||||||
|
module gearbox_2x1_all_tb;
|
||||||
|
gearbox_2x1_tb #(.IN_WORDS(1), .OUT_WORDS(2), .BIG_ENDIAN(0), .PHASE(0)) gearbox_2x1_tb_1();
|
||||||
|
gearbox_2x1_tb #(.IN_WORDS(2), .OUT_WORDS(1), .BIG_ENDIAN(0), .PHASE(0)) gearbox_2x1_tb_2();
|
||||||
|
gearbox_2x1_tb #(.IN_WORDS(2), .OUT_WORDS(4), .BIG_ENDIAN(1), .PHASE(0)) gearbox_2x1_tb_3();
|
||||||
|
gearbox_2x1_tb #(.IN_WORDS(4), .OUT_WORDS(2), .BIG_ENDIAN(1), .PHASE(0)) gearbox_2x1_tb_4();
|
||||||
|
gearbox_2x1_tb #(.IN_WORDS(1), .OUT_WORDS(2), .BIG_ENDIAN(0), .PHASE(1)) gearbox_2x1_tb_5();
|
||||||
|
gearbox_2x1_tb #(.IN_WORDS(2), .OUT_WORDS(1), .BIG_ENDIAN(0), .PHASE(1)) gearbox_2x1_tb_6();
|
||||||
|
endmodule : gearbox_2x1_all_tb
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 Ettus Research, a National Instruments Brand
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
//
|
||||||
|
// Module: gearbox_2x1_tb
|
||||||
|
//
|
||||||
|
// Description: Testbench for gearbox_2x1.
|
||||||
|
//
|
||||||
|
|
||||||
|
`default_nettype none
|
||||||
|
|
||||||
|
|
||||||
|
module gearbox_2x1_tb #(
|
||||||
|
parameter IN_WORDS = 2,
|
||||||
|
parameter OUT_WORDS = 1,
|
||||||
|
parameter BIG_ENDIAN = 0,
|
||||||
|
parameter PHASE = 1
|
||||||
|
);
|
||||||
|
|
||||||
|
`include "test_exec.svh"
|
||||||
|
|
||||||
|
import PkgTestExec::*;
|
||||||
|
|
||||||
|
localparam WORD_W = 4;
|
||||||
|
|
||||||
|
// Clock periods
|
||||||
|
localparam real SLOW_CLK_PER_NS = 10.0;
|
||||||
|
localparam real FAST_CLK_PER_NS = SLOW_CLK_PER_NS / 2.0;
|
||||||
|
localparam real CLK_IN_PER_NS = (IN_WORDS > OUT_WORDS) ?
|
||||||
|
SLOW_CLK_PER_NS : FAST_CLK_PER_NS;
|
||||||
|
localparam real CLK_OUT_PER_NS = (OUT_WORDS > IN_WORDS) ?
|
||||||
|
SLOW_CLK_PER_NS : FAST_CLK_PER_NS;
|
||||||
|
|
||||||
|
// Give the faster clock a T/2 phase offset
|
||||||
|
localparam FAST_CLK_PHASE = PHASE * (FAST_CLK_PER_NS / 2.0);
|
||||||
|
localparam real IN_PHASE = (IN_WORDS > OUT_WORDS) ? 0.0 : FAST_CLK_PHASE;
|
||||||
|
localparam real OUT_PHASE = (OUT_WORDS > IN_WORDS) ? 0.0 : FAST_CLK_PHASE;
|
||||||
|
|
||||||
|
// Get gearbox total input and output widths
|
||||||
|
localparam IN_WORD_W = WORD_W * IN_WORDS;
|
||||||
|
localparam OUT_WORD_W = WORD_W * OUT_WORDS;
|
||||||
|
|
||||||
|
// Number of simulation cycles to run for
|
||||||
|
localparam NUM_TEST_CYCLES = 50000;
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Clocks and Resets
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bit i_clk;
|
||||||
|
bit o_clk;
|
||||||
|
|
||||||
|
bit i_rst;
|
||||||
|
bit o_rst;
|
||||||
|
|
||||||
|
sim_clock_gen #(.PERIOD(CLK_IN_PER_NS), .AUTOSTART(0), .PHASE(IN_PHASE))
|
||||||
|
clk_gen_in (.clk(i_clk), .rst(i_rst));
|
||||||
|
sim_clock_gen #(.PERIOD(CLK_OUT_PER_NS),.AUTOSTART(0), .PHASE(OUT_PHASE))
|
||||||
|
clk_gen_out (.clk(o_clk), .rst(o_rst));
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Device Under Test (DUT)
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bit [ IN_WORD_W-1:0] i_tdata = { IN_WORD_W { 1'bX }};
|
||||||
|
bit i_tvalid = 0;
|
||||||
|
bit [OUT_WORD_W-1:0] o_tdata;
|
||||||
|
bit o_tvalid;
|
||||||
|
|
||||||
|
gearbox_2x1 #(
|
||||||
|
.WORD_W (WORD_W),
|
||||||
|
.IN_WORDS (IN_WORDS),
|
||||||
|
.OUT_WORDS (OUT_WORDS),
|
||||||
|
.BIG_ENDIAN (BIG_ENDIAN)
|
||||||
|
) gearbox_2x1_i (
|
||||||
|
.i_clk (i_clk),
|
||||||
|
.i_rst (i_rst),
|
||||||
|
.i_tdata (i_tdata),
|
||||||
|
.i_tvalid (i_tvalid),
|
||||||
|
.o_clk (o_clk),
|
||||||
|
.o_rst (o_rst),
|
||||||
|
.o_tdata (o_tdata),
|
||||||
|
.o_tvalid (o_tvalid)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Input Generator
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bit enable_input = 0;
|
||||||
|
longint i_count;
|
||||||
|
mailbox #(bit [IN_WORD_W-1:0]) i_queue = new;
|
||||||
|
|
||||||
|
initial forever begin : gen_input
|
||||||
|
clk_gen_in.clk_wait_r();
|
||||||
|
if (i_rst || !enable_input) begin
|
||||||
|
i_tdata <= { IN_WORD_W { 1'bX }};
|
||||||
|
i_tvalid <= 1'b0;
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
// Input randomly to the gearbox
|
||||||
|
if ($urandom() % 2 == 0) begin
|
||||||
|
bit [ IN_WORD_W-1:0] next_input;
|
||||||
|
next_input = $urandom();
|
||||||
|
i_count = i_count + 1;
|
||||||
|
i_tdata <= next_input;
|
||||||
|
i_tvalid <= 1'b1;
|
||||||
|
i_queue.put(next_input);
|
||||||
|
end else begin
|
||||||
|
i_tdata <= { IN_WORD_W { 1'bX }};
|
||||||
|
i_tvalid <= 1'b0;
|
||||||
|
end
|
||||||
|
end : gen_input
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Packer/Unpacker
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Take the data from i_queue and repack it into o_queue with the correct
|
||||||
|
// width and using the correct endianness.
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
mailbox #(bit [OUT_WORD_W-1:0]) o_queue = new;
|
||||||
|
|
||||||
|
initial if (IN_WORDS > OUT_WORDS) begin : unpacker
|
||||||
|
bit [IN_WORD_W-1:0] in_word;
|
||||||
|
forever begin
|
||||||
|
i_queue.get(in_word);
|
||||||
|
if (BIG_ENDIAN) begin
|
||||||
|
for (int i = IN_WORDS/OUT_WORDS-1; i >= 0; i--) begin
|
||||||
|
o_queue.put(in_word[OUT_WORD_W*i +: OUT_WORD_W]);
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
for (int i = 0; i < IN_WORDS/OUT_WORDS; i++) begin
|
||||||
|
o_queue.put(in_word[OUT_WORD_W*i +: OUT_WORD_W]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end else begin : packer
|
||||||
|
bit [OUT_WORD_W-1:0] out_word;
|
||||||
|
forever begin
|
||||||
|
if (BIG_ENDIAN) begin
|
||||||
|
for (int i = OUT_WORDS/IN_WORDS-1; i >= 0; i--) begin
|
||||||
|
i_queue.get(out_word[IN_WORD_W*i +: IN_WORD_W]);
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
for (int i = 0; i < OUT_WORDS/IN_WORDS; i++) begin
|
||||||
|
i_queue.get(out_word[IN_WORD_W*i +: IN_WORD_W]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
o_queue.put(out_word);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Output Checker
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
longint o_count;
|
||||||
|
bit [OUT_WORD_W-1:0] expected, actual;
|
||||||
|
|
||||||
|
initial forever begin : check_output
|
||||||
|
string msg;
|
||||||
|
clk_gen_out.clk_wait_r();
|
||||||
|
if (o_rst) begin
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
if (o_tvalid) begin
|
||||||
|
o_count++;
|
||||||
|
actual = o_tdata;
|
||||||
|
o_queue.get(expected);
|
||||||
|
msg = $sformatf("Output didn't match expected value! Expected 0x%0X, received 0x%0X.",
|
||||||
|
expected, actual);
|
||||||
|
`ASSERT_ERROR(actual == expected, msg);
|
||||||
|
end
|
||||||
|
end : check_output
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Main Test Process
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
initial begin : tb_main
|
||||||
|
string msg;
|
||||||
|
string tb_name;
|
||||||
|
int min_out_words, max_out_words;
|
||||||
|
|
||||||
|
// Initialize the test exec object for this testbench
|
||||||
|
tb_name = $sformatf( {
|
||||||
|
"gearbox_2x1_tb\n",
|
||||||
|
"IN_WORDS = %01d\n",
|
||||||
|
"OUT_WORDS = %01d\n",
|
||||||
|
"BIG_ENDIAN = %01d\n",
|
||||||
|
"PHASE = %01d" },
|
||||||
|
IN_WORDS, OUT_WORDS, BIG_ENDIAN, PHASE
|
||||||
|
);
|
||||||
|
test.start_tb(tb_name);
|
||||||
|
|
||||||
|
// Don't start the clocks until after start_tb() returns. This ensures that
|
||||||
|
// the clocks aren't toggling while other instances of this testbench are
|
||||||
|
// running, which speeds up simulation time.
|
||||||
|
clk_gen_in.start();
|
||||||
|
clk_gen_out.start();
|
||||||
|
|
||||||
|
//--------------------------------
|
||||||
|
// Reset
|
||||||
|
//--------------------------------
|
||||||
|
|
||||||
|
test.start_test("Reset", 10us);
|
||||||
|
clk_gen_in.reset();
|
||||||
|
clk_gen_out.reset();
|
||||||
|
if (i_rst) @i_rst;
|
||||||
|
if (o_rst) @o_rst;
|
||||||
|
test.end_test();
|
||||||
|
|
||||||
|
//--------------------------------
|
||||||
|
// Test Sequences
|
||||||
|
//--------------------------------
|
||||||
|
|
||||||
|
test.start_test("Random data", 10ms);
|
||||||
|
|
||||||
|
enable_input <= 1;
|
||||||
|
|
||||||
|
// Let it run for a while
|
||||||
|
clk_gen_in.clk_wait_r(NUM_TEST_CYCLES);
|
||||||
|
|
||||||
|
// Stop inputting and wait long enough for any data to propagate through
|
||||||
|
enable_input <= 0;
|
||||||
|
repeat (8*OUT_WORDS) @i_clk;
|
||||||
|
repeat (8*IN_WORDS) @o_clk;
|
||||||
|
|
||||||
|
// Calculate how many words we expect to have received on the output. We
|
||||||
|
// might be in the middle of a word, so it might be less than what was
|
||||||
|
// input.
|
||||||
|
if (OUT_WORDS > IN_WORDS) begin
|
||||||
|
min_out_words = ((i_count * IN_WORDS) / OUT_WORDS) * OUT_WORDS;
|
||||||
|
max_out_words = min_out_words;
|
||||||
|
end else begin
|
||||||
|
min_out_words = (i_count-1) * IN_WORDS;
|
||||||
|
max_out_words = i_count * IN_WORDS;
|
||||||
|
end
|
||||||
|
|
||||||
|
// Make sure the word counts match
|
||||||
|
msg = $sformatf("Word counts don't match. Input %0d, output %0d.",
|
||||||
|
IN_WORDS*i_count, OUT_WORDS*o_count);
|
||||||
|
`ASSERT_ERROR(o_count*OUT_WORDS >= min_out_words &&
|
||||||
|
o_count*OUT_WORDS <= max_out_words , msg);
|
||||||
|
msg = $sformatf("Only %0d words input. Expected about %0d.",
|
||||||
|
i_count*IN_WORDS, 0.5*NUM_TEST_CYCLES*IN_WORDS);
|
||||||
|
`ASSERT_ERROR(i_count > 0.4*NUM_TEST_CYCLES, msg);
|
||||||
|
|
||||||
|
$display("Tested %0d output words", o_count);
|
||||||
|
|
||||||
|
test.end_test();
|
||||||
|
|
||||||
|
//--------------------------------
|
||||||
|
// Finish Up
|
||||||
|
//--------------------------------
|
||||||
|
|
||||||
|
// End the TB, but don't $finish, since we don't want to kill other
|
||||||
|
// instances of this testbench that may be running.
|
||||||
|
test.end_tb(0);
|
||||||
|
|
||||||
|
// Kill the clocks to end this instance of the testbench
|
||||||
|
clk_gen_in.kill();
|
||||||
|
clk_gen_out.kill();
|
||||||
|
|
||||||
|
end : tb_main
|
||||||
|
|
||||||
|
endmodule : gearbox_2x1_tb
|
||||||
|
|
||||||
|
|
||||||
|
`default_nettype wire
|
||||||
Reference in New Issue
Block a user