fpga: rfnoc: Add support for 512-bit CHDR widths
This fixes the rfnoc_null_src_sink, chdr_crossbar_nxn, and chdr_stream_endpoint blocks so that wider CHDR widths are properly supported. It also updates PkgChdrBfm to able to properly test these blocks. The testbenches have been updated to test both 64 and 512-bit widths. Original-commit: 3af8dcaacfa4bf36dcae3bdbf0b353385b7063c6
This commit is contained in:
@@ -29,10 +29,11 @@ $(RFNOC_OOT_SRCS) \
|
|||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
# Testbench Specific
|
# Testbench Specific
|
||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
SIM_TOP = rfnoc_block_null_src_sink_tb
|
SIM_TOP = rfnoc_block_null_src_sink_all_tb
|
||||||
|
|
||||||
SIM_SRCS = \
|
SIM_SRCS = \
|
||||||
$(abspath rfnoc_block_null_src_sink_tb.sv) \
|
$(abspath rfnoc_block_null_src_sink_tb.sv) \
|
||||||
|
$(abspath rfnoc_block_null_src_sink_all_tb.sv) \
|
||||||
|
|
||||||
# MODELSIM_USER_DO = $(abspath wave.do)
|
# MODELSIM_USER_DO = $(abspath wave.do)
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
module noc_shell_null_src_sink #(
|
module noc_shell_null_src_sink #(
|
||||||
parameter [9:0] THIS_PORTID = 10'd0,
|
parameter [9:0] THIS_PORTID = 10'd0,
|
||||||
parameter CHDR_W = 64,
|
parameter CHDR_W = 64,
|
||||||
|
parameter ITEM_W = 32,
|
||||||
|
parameter NIPC = 2,
|
||||||
parameter [5:0] MTU = 10
|
parameter [5:0] MTU = 10
|
||||||
) (
|
) (
|
||||||
//---------------------
|
//---------------------
|
||||||
@@ -82,8 +84,8 @@ module noc_shell_null_src_sink #(
|
|||||||
output wire axis_data_clk,
|
output wire axis_data_clk,
|
||||||
output wire axis_data_rst,
|
output wire axis_data_rst,
|
||||||
// Payload Stream to User Logic: sink
|
// Payload Stream to User Logic: sink
|
||||||
output wire [32*2-1:0] m_sink_payload_tdata,
|
output wire [ITEM_W*NIPC-1:0] m_sink_payload_tdata,
|
||||||
output wire [2-1:0] m_sink_payload_tkeep,
|
output wire [NIPC-1:0] m_sink_payload_tkeep,
|
||||||
output wire m_sink_payload_tlast,
|
output wire m_sink_payload_tlast,
|
||||||
output wire m_sink_payload_tvalid,
|
output wire m_sink_payload_tvalid,
|
||||||
input wire m_sink_payload_tready,
|
input wire m_sink_payload_tready,
|
||||||
@@ -94,8 +96,8 @@ module noc_shell_null_src_sink #(
|
|||||||
output wire m_sink_context_tvalid,
|
output wire m_sink_context_tvalid,
|
||||||
input wire m_sink_context_tready,
|
input wire m_sink_context_tready,
|
||||||
// Payload Stream to User Logic: loop
|
// Payload Stream to User Logic: loop
|
||||||
output wire [32*2-1:0] m_loop_payload_tdata,
|
output wire [ITEM_W*NIPC-1:0] m_loop_payload_tdata,
|
||||||
output wire [2-1:0] m_loop_payload_tkeep,
|
output wire [NIPC-1:0] m_loop_payload_tkeep,
|
||||||
output wire m_loop_payload_tlast,
|
output wire m_loop_payload_tlast,
|
||||||
output wire m_loop_payload_tvalid,
|
output wire m_loop_payload_tvalid,
|
||||||
input wire m_loop_payload_tready,
|
input wire m_loop_payload_tready,
|
||||||
@@ -106,8 +108,8 @@ module noc_shell_null_src_sink #(
|
|||||||
output wire m_loop_context_tvalid,
|
output wire m_loop_context_tvalid,
|
||||||
input wire m_loop_context_tready,
|
input wire m_loop_context_tready,
|
||||||
// Payload Stream from User Logic: source
|
// Payload Stream from User Logic: source
|
||||||
input wire [32*2-1:0] s_source_payload_tdata,
|
input wire [ITEM_W*NIPC-1:0] s_source_payload_tdata,
|
||||||
input wire [1:0] s_source_payload_tkeep,
|
input wire [NIPC-1:0] s_source_payload_tkeep,
|
||||||
input wire s_source_payload_tlast,
|
input wire s_source_payload_tlast,
|
||||||
input wire s_source_payload_tvalid,
|
input wire s_source_payload_tvalid,
|
||||||
output wire s_source_payload_tready,
|
output wire s_source_payload_tready,
|
||||||
@@ -118,8 +120,8 @@ module noc_shell_null_src_sink #(
|
|||||||
input wire s_source_context_tvalid,
|
input wire s_source_context_tvalid,
|
||||||
output wire s_source_context_tready,
|
output wire s_source_context_tready,
|
||||||
// Payload Stream from User Logic: loop
|
// Payload Stream from User Logic: loop
|
||||||
input wire [32*2-1:0] s_loop_payload_tdata,
|
input wire [ITEM_W*NIPC-1:0] s_loop_payload_tdata,
|
||||||
input wire [1:0] s_loop_payload_tkeep,
|
input wire [NIPC-1:0] s_loop_payload_tkeep,
|
||||||
input wire s_loop_payload_tlast,
|
input wire s_loop_payload_tlast,
|
||||||
input wire s_loop_payload_tvalid,
|
input wire s_loop_payload_tvalid,
|
||||||
output wire s_loop_payload_tready,
|
output wire s_loop_payload_tready,
|
||||||
@@ -233,8 +235,8 @@ module noc_shell_null_src_sink #(
|
|||||||
|
|
||||||
chdr_to_axis_pyld_ctxt #(
|
chdr_to_axis_pyld_ctxt #(
|
||||||
.CHDR_W (CHDR_W),
|
.CHDR_W (CHDR_W),
|
||||||
.ITEM_W (32),
|
.ITEM_W (ITEM_W),
|
||||||
.NIPC (2),
|
.NIPC (NIPC),
|
||||||
.SYNC_CLKS (1),
|
.SYNC_CLKS (1),
|
||||||
.CONTEXT_FIFO_SIZE ($clog2(2)),
|
.CONTEXT_FIFO_SIZE ($clog2(2)),
|
||||||
.PAYLOAD_FIFO_SIZE ($clog2(2)),
|
.PAYLOAD_FIFO_SIZE ($clog2(2)),
|
||||||
@@ -266,8 +268,8 @@ module noc_shell_null_src_sink #(
|
|||||||
|
|
||||||
chdr_to_axis_pyld_ctxt #(
|
chdr_to_axis_pyld_ctxt #(
|
||||||
.CHDR_W (CHDR_W),
|
.CHDR_W (CHDR_W),
|
||||||
.ITEM_W (32),
|
.ITEM_W (ITEM_W),
|
||||||
.NIPC (2),
|
.NIPC (NIPC),
|
||||||
.SYNC_CLKS (1),
|
.SYNC_CLKS (1),
|
||||||
.CONTEXT_FIFO_SIZE ($clog2(2)),
|
.CONTEXT_FIFO_SIZE ($clog2(2)),
|
||||||
.PAYLOAD_FIFO_SIZE ($clog2(2)),
|
.PAYLOAD_FIFO_SIZE ($clog2(2)),
|
||||||
@@ -303,8 +305,8 @@ module noc_shell_null_src_sink #(
|
|||||||
|
|
||||||
axis_pyld_ctxt_to_chdr #(
|
axis_pyld_ctxt_to_chdr #(
|
||||||
.CHDR_W (CHDR_W),
|
.CHDR_W (CHDR_W),
|
||||||
.ITEM_W (32),
|
.ITEM_W (ITEM_W),
|
||||||
.NIPC (2),
|
.NIPC (NIPC),
|
||||||
.SYNC_CLKS (1),
|
.SYNC_CLKS (1),
|
||||||
.CONTEXT_FIFO_SIZE ($clog2(2)),
|
.CONTEXT_FIFO_SIZE ($clog2(2)),
|
||||||
.PAYLOAD_FIFO_SIZE ($clog2(2)),
|
.PAYLOAD_FIFO_SIZE ($clog2(2)),
|
||||||
@@ -338,8 +340,8 @@ module noc_shell_null_src_sink #(
|
|||||||
|
|
||||||
axis_pyld_ctxt_to_chdr #(
|
axis_pyld_ctxt_to_chdr #(
|
||||||
.CHDR_W (CHDR_W),
|
.CHDR_W (CHDR_W),
|
||||||
.ITEM_W (32),
|
.ITEM_W (ITEM_W),
|
||||||
.NIPC (2),
|
.NIPC (NIPC),
|
||||||
.SYNC_CLKS (1),
|
.SYNC_CLKS (1),
|
||||||
.CONTEXT_FIFO_SIZE ($clog2(2)),
|
.CONTEXT_FIFO_SIZE ($clog2(2)),
|
||||||
.PAYLOAD_FIFO_SIZE ($clog2(2)),
|
.PAYLOAD_FIFO_SIZE ($clog2(2)),
|
||||||
|
|||||||
@@ -4,30 +4,46 @@
|
|||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
//
|
//
|
||||||
// Module: rfnoc_block_null_src_sink
|
// Module: rfnoc_block_null_src_sink
|
||||||
|
//
|
||||||
// Description:
|
// Description:
|
||||||
//
|
//
|
||||||
|
// This block can source, sink, or loopback data. Each port is used for a
|
||||||
|
// specific purpose. The RFNoC CHDR ports are mapped is as follows:
|
||||||
|
//
|
||||||
|
// Input Port 0 : Sink
|
||||||
|
// Input Port 1 : Loopback in
|
||||||
|
// Output Port 0 : Source
|
||||||
|
// Output Port 1 : Loopback out
|
||||||
|
//
|
||||||
// Parameters:
|
// Parameters:
|
||||||
|
// THIS_PORTID : Control crossbar port to which this block is connected
|
||||||
|
// CHDR_W : AXIS-CHDR data bus width
|
||||||
|
// MTU : Maximum transmission unit (i.e., maximum packet size in
|
||||||
|
// CHDR words is 2**MTU).
|
||||||
|
// ITEM_W : Item width
|
||||||
|
// NIPC : Items per Clock
|
||||||
//
|
//
|
||||||
// Signals:
|
// Signals:
|
||||||
|
|
||||||
module rfnoc_block_null_src_sink #(
|
module rfnoc_block_null_src_sink #(
|
||||||
parameter [9:0] THIS_PORTID = 10'd0,
|
parameter [9:0] THIS_PORTID = 10'd0,
|
||||||
parameter CHDR_W = 64,
|
parameter CHDR_W = 64,
|
||||||
parameter NIPC = 2,
|
parameter [5:0] MTU = 10,
|
||||||
parameter [5:0] MTU = 10
|
parameter ITEM_W = 32,
|
||||||
|
parameter NIPC = CHDR_W/ITEM_W
|
||||||
)(
|
)(
|
||||||
// RFNoC Framework Clocks and Resets
|
// RFNoC Framework Clocks and Resets
|
||||||
input wire rfnoc_chdr_clk,
|
input wire rfnoc_chdr_clk,
|
||||||
input wire rfnoc_ctrl_clk,
|
input wire rfnoc_ctrl_clk,
|
||||||
// RFNoC Backend Interface
|
// RFNoC Backend Interface
|
||||||
input wire [511:0] rfnoc_core_config,
|
input wire [511:0] rfnoc_core_config,
|
||||||
output wire [511:0] rfnoc_core_status,
|
output wire [511:0] rfnoc_core_status,
|
||||||
// 2 CHDR Input Ports (from framework)
|
// 2 CHDR Input Ports (from framework)
|
||||||
input wire [(CHDR_W*2)-1:0] s_rfnoc_chdr_tdata,
|
input wire [(CHDR_W*2)-1:0] s_rfnoc_chdr_tdata,
|
||||||
input wire [1:0] s_rfnoc_chdr_tlast,
|
input wire [1:0] s_rfnoc_chdr_tlast,
|
||||||
input wire [1:0] s_rfnoc_chdr_tvalid,
|
input wire [1:0] s_rfnoc_chdr_tvalid,
|
||||||
output wire [1:0] s_rfnoc_chdr_tready,
|
output wire [1:0] s_rfnoc_chdr_tready,
|
||||||
// 2 CHDR Output Ports (to framework)
|
// 2 CHDR Output Ports (to framework)
|
||||||
output wire [(CHDR_W*2)-1:0] m_rfnoc_chdr_tdata,
|
output wire [(CHDR_W*2)-1:0] m_rfnoc_chdr_tdata,
|
||||||
output wire [1:0] m_rfnoc_chdr_tlast,
|
output wire [1:0] m_rfnoc_chdr_tlast,
|
||||||
output wire [1:0] m_rfnoc_chdr_tvalid,
|
output wire [1:0] m_rfnoc_chdr_tvalid,
|
||||||
@@ -72,22 +88,24 @@ module rfnoc_block_null_src_sink #(
|
|||||||
reg ctrlport_resp_ack;
|
reg ctrlport_resp_ack;
|
||||||
reg [31:0] ctrlport_resp_data;
|
reg [31:0] ctrlport_resp_data;
|
||||||
|
|
||||||
wire [(32*NIPC)-1:0] src_pyld_tdata , loop_pyld_tdata ;
|
wire [(ITEM_W*NIPC)-1:0] src_pyld_tdata , loop_pyld_tdata ;
|
||||||
wire [NIPC-1:0] src_pyld_tkeep , loop_pyld_tkeep ;
|
wire [NIPC-1:0] src_pyld_tkeep , loop_pyld_tkeep ;
|
||||||
wire src_pyld_tlast , snk_pyld_tlast , loop_pyld_tlast ;
|
wire src_pyld_tlast , snk_pyld_tlast , loop_pyld_tlast ;
|
||||||
wire src_pyld_tvalid, snk_pyld_tvalid, loop_pyld_tvalid;
|
wire src_pyld_tvalid, snk_pyld_tvalid, loop_pyld_tvalid;
|
||||||
wire src_pyld_tready, snk_pyld_tready, loop_pyld_tready;
|
wire src_pyld_tready, snk_pyld_tready, loop_pyld_tready;
|
||||||
|
|
||||||
wire [CHDR_W-1:0] src_ctxt_tdata , loop_ctxt_tdata ;
|
wire [CHDR_W-1:0] src_ctxt_tdata , loop_ctxt_tdata ;
|
||||||
wire [3:0] src_ctxt_tuser , loop_ctxt_tuser ;
|
wire [3:0] src_ctxt_tuser , loop_ctxt_tuser ;
|
||||||
wire src_ctxt_tlast , loop_ctxt_tlast ;
|
wire src_ctxt_tlast , loop_ctxt_tlast ;
|
||||||
wire src_ctxt_tvalid, loop_ctxt_tvalid;
|
wire src_ctxt_tvalid, loop_ctxt_tvalid;
|
||||||
wire src_ctxt_tready, snk_ctxt_tready, loop_ctxt_tready;
|
wire src_ctxt_tready, snk_ctxt_tready, loop_ctxt_tready;
|
||||||
|
|
||||||
// NoC Shell
|
// NoC Shell
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
noc_shell_null_src_sink #(
|
noc_shell_null_src_sink #(
|
||||||
.THIS_PORTID (THIS_PORTID),
|
.THIS_PORTID (THIS_PORTID),
|
||||||
|
.NIPC (NIPC),
|
||||||
|
.ITEM_W (ITEM_W),
|
||||||
.CHDR_W (CHDR_W),
|
.CHDR_W (CHDR_W),
|
||||||
.MTU (MTU)
|
.MTU (MTU)
|
||||||
) noc_shell_null_src_sink_i (
|
) noc_shell_null_src_sink_i (
|
||||||
@@ -257,18 +275,17 @@ module rfnoc_block_null_src_sink #(
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
assign src_pyld_tdata = {NIPC{{~src_line_cnt[15:0], src_line_cnt[15:0]}}};
|
assign src_pyld_tdata = {NIPC{{~src_line_cnt[ITEM_W/2-1:0], src_line_cnt[ITEM_W/2-1:0]}}};
|
||||||
assign src_pyld_tkeep = {NIPC{1'b1}};
|
assign src_pyld_tkeep = {NIPC{1'b1}};
|
||||||
assign src_pyld_tlast = (lines_left == 12'd0);
|
assign src_pyld_tlast = (lines_left == 12'd0);
|
||||||
assign src_pyld_tvalid = (state == ST_PYLD);
|
assign src_pyld_tvalid = (state == ST_PYLD);
|
||||||
|
|
||||||
assign src_ctxt_tdata = chdr_build_header(
|
assign src_ctxt_tdata = chdr_build_header(
|
||||||
6'd0, 1'b0, 1'b0, CHDR_PKT_TYPE_DATA, CHDR_NO_MDATA, src_pkt_cnt[15:0], reg_src_bpp, 16'd0);
|
6'd0, 1'b0, 1'b0, CHDR_PKT_TYPE_DATA, CHDR_NO_MDATA, src_pkt_cnt[15:0], reg_src_bpp, 16'd0);
|
||||||
assign src_ctxt_tuser = CONTEXT_FIELD_HDR;
|
assign src_ctxt_tuser = CHDR_W > 64 ? CONTEXT_FIELD_HDR_TS : CONTEXT_FIELD_HDR;
|
||||||
assign src_ctxt_tlast = 1'b1;
|
assign src_ctxt_tlast = 1'b1;
|
||||||
assign src_ctxt_tvalid = (state == ST_HDR && reg_src_en);
|
assign src_ctxt_tvalid = (state == ST_HDR && reg_src_en);
|
||||||
|
|
||||||
|
|
||||||
// Register Interface
|
// Register Interface
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
always @(posedge rfnoc_chdr_clk) begin
|
always @(posedge rfnoc_chdr_clk) begin
|
||||||
@@ -294,7 +311,7 @@ module rfnoc_block_null_src_sink #(
|
|||||||
if (ctrlport_req_rd) begin
|
if (ctrlport_req_rd) begin
|
||||||
case(ctrlport_req_addr)
|
case(ctrlport_req_addr)
|
||||||
REG_CTRL_STATUS:
|
REG_CTRL_STATUS:
|
||||||
ctrlport_resp_data <= {NIPC[7:0], 8'd32, state, 12'h0, reg_src_en, reg_clear_cnts};
|
ctrlport_resp_data <= {NIPC[7:0],ITEM_W[7:0], state, 12'h0, reg_src_en, reg_clear_cnts};
|
||||||
REG_SRC_LINES_PER_PKT:
|
REG_SRC_LINES_PER_PKT:
|
||||||
ctrlport_resp_data <= {20'h0, reg_src_lpp};
|
ctrlport_resp_data <= {20'h0, reg_src_lpp};
|
||||||
REG_SRC_BYTES_PER_PKT:
|
REG_SRC_BYTES_PER_PKT:
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 Ettus Research, a National Instruments Brand
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
//
|
||||||
|
// Module: chdr_stream_endpoint_all_tb
|
||||||
|
//
|
||||||
|
// Description: Testbench for chdr_stream_endpoint that runs multiple widths
|
||||||
|
//
|
||||||
|
|
||||||
|
module rfnoc_block_null_src_sink_all_tb#(
|
||||||
|
/* no PARAM */
|
||||||
|
)(
|
||||||
|
/* no IO */
|
||||||
|
);
|
||||||
|
|
||||||
|
rfnoc_block_null_src_sink_tb #(.TEST_NAME("64B"),.CHDR_W(64)) CHDR64 ();
|
||||||
|
rfnoc_block_null_src_sink_tb #(.TEST_NAME("512B"),.CHDR_W(512)) CHDR512 ();
|
||||||
|
|
||||||
|
// Wait for all done
|
||||||
|
bit clk,rst;
|
||||||
|
sim_clock_gen #(100.0) clk_gen (clk, rst);
|
||||||
|
always_ff@(posedge clk)
|
||||||
|
if (CHDR64.test.done && CHDR512.test.done) $finish(1);
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2019 Ettus Research, A National Instruments Company
|
// Copyright 2020 Ettus Research, A National Instruments Brand
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
//
|
//
|
||||||
@@ -9,9 +9,15 @@
|
|||||||
`default_nettype none
|
`default_nettype none
|
||||||
|
|
||||||
|
|
||||||
module rfnoc_block_null_src_sink_tb;
|
module rfnoc_block_null_src_sink_tb #(
|
||||||
|
parameter TEST_NAME = "rfnoc_block_null_src_sink_tb",
|
||||||
|
parameter CHDR_W = 64
|
||||||
|
)(
|
||||||
|
/* no IO */
|
||||||
|
);
|
||||||
|
|
||||||
// Include macros and time declarations for use with PkgTestExec
|
// Include macros and time declarations for use with PkgTestExec
|
||||||
|
`define TEST_EXEC_OBJ test
|
||||||
`include "test_exec.svh"
|
`include "test_exec.svh"
|
||||||
|
|
||||||
import PkgTestExec::*;
|
import PkgTestExec::*;
|
||||||
@@ -23,10 +29,10 @@ module rfnoc_block_null_src_sink_tb;
|
|||||||
localparam NOC_ID = 32'h0000_0001;
|
localparam NOC_ID = 32'h0000_0001;
|
||||||
localparam [9:0] THIS_PORTID = 10'h17;
|
localparam [9:0] THIS_PORTID = 10'h17;
|
||||||
localparam [15:0] THIS_EPID = 16'hDEAD;
|
localparam [15:0] THIS_EPID = 16'hDEAD;
|
||||||
localparam int CHDR_W = 64;
|
localparam int ITEM_W = 32;
|
||||||
localparam int ITEM_W = 32;
|
localparam int NIPC = CHDR_W/ITEM_W; // Expected Data generation only works for full words
|
||||||
localparam int SPP = 201;
|
localparam int SPP = 201;
|
||||||
localparam int LPP = ((SPP+1)/2);
|
localparam int LPP = SPP % NIPC == 0 ? SPP/NIPC : SPP/NIPC+1;
|
||||||
localparam int NUM_PKTS = 50;
|
localparam int NUM_PKTS = 50;
|
||||||
|
|
||||||
localparam int PORT_SRCSNK = 0;
|
localparam int PORT_SRCSNK = 0;
|
||||||
@@ -49,6 +55,8 @@ module rfnoc_block_null_src_sink_tb;
|
|||||||
AxiStreamIf #(CHDR_W) s0_chdr (rfnoc_chdr_clk); // Optional data iface
|
AxiStreamIf #(CHDR_W) s0_chdr (rfnoc_chdr_clk); // Optional data iface
|
||||||
AxiStreamIf #(CHDR_W) s1_chdr (rfnoc_chdr_clk); // Optional data iface
|
AxiStreamIf #(CHDR_W) s1_chdr (rfnoc_chdr_clk); // Optional data iface
|
||||||
|
|
||||||
|
TestExec test = new();
|
||||||
|
|
||||||
typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t;
|
typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t;
|
||||||
|
|
||||||
// Bus functional model for a software block controller
|
// Bus functional model for a software block controller
|
||||||
@@ -58,29 +66,30 @@ module rfnoc_block_null_src_sink_tb;
|
|||||||
rfnoc_block_null_src_sink #(
|
rfnoc_block_null_src_sink #(
|
||||||
.THIS_PORTID (THIS_PORTID),
|
.THIS_PORTID (THIS_PORTID),
|
||||||
.CHDR_W (CHDR_W),
|
.CHDR_W (CHDR_W),
|
||||||
.NIPC (2),
|
.ITEM_W (ITEM_W),
|
||||||
|
.NIPC (NIPC),
|
||||||
.MTU (10)
|
.MTU (10)
|
||||||
) dut (
|
) dut (
|
||||||
.rfnoc_chdr_clk (backend.chdr_clk),
|
.rfnoc_chdr_clk (backend.chdr_clk),
|
||||||
.rfnoc_ctrl_clk (backend.ctrl_clk),
|
.rfnoc_ctrl_clk (backend.ctrl_clk),
|
||||||
.rfnoc_core_config (backend.slave.cfg),
|
.rfnoc_core_config (backend.cfg),
|
||||||
.rfnoc_core_status (backend.slave.sts),
|
.rfnoc_core_status (backend.sts),
|
||||||
.s_rfnoc_chdr_tdata ({m1_chdr.slave.tdata , m0_chdr.slave.tdata }),
|
.s_rfnoc_chdr_tdata ({m1_chdr.tdata , m0_chdr.tdata }),
|
||||||
.s_rfnoc_chdr_tlast ({m1_chdr.slave.tlast , m0_chdr.slave.tlast }),
|
.s_rfnoc_chdr_tlast ({m1_chdr.tlast , m0_chdr.tlast }),
|
||||||
.s_rfnoc_chdr_tvalid({m1_chdr.slave.tvalid , m0_chdr.slave.tvalid }),
|
.s_rfnoc_chdr_tvalid({m1_chdr.tvalid , m0_chdr.tvalid }),
|
||||||
.s_rfnoc_chdr_tready({m1_chdr.slave.tready , m0_chdr.slave.tready }),
|
.s_rfnoc_chdr_tready({m1_chdr.tready , m0_chdr.tready }),
|
||||||
.m_rfnoc_chdr_tdata ({s1_chdr.master.tdata , s0_chdr.master.tdata }),
|
.m_rfnoc_chdr_tdata ({s1_chdr.tdata , s0_chdr.tdata }),
|
||||||
.m_rfnoc_chdr_tlast ({s1_chdr.master.tlast , s0_chdr.master.tlast }),
|
.m_rfnoc_chdr_tlast ({s1_chdr.tlast , s0_chdr.tlast }),
|
||||||
.m_rfnoc_chdr_tvalid({s1_chdr.master.tvalid, s0_chdr.master.tvalid}),
|
.m_rfnoc_chdr_tvalid({s1_chdr.tvalid, s0_chdr.tvalid}),
|
||||||
.m_rfnoc_chdr_tready({s1_chdr.master.tready, s0_chdr.master.tready}),
|
.m_rfnoc_chdr_tready({s1_chdr.tready, s0_chdr.tready}),
|
||||||
.s_rfnoc_ctrl_tdata (m_ctrl.slave.tdata ),
|
.s_rfnoc_ctrl_tdata (m_ctrl.tdata ),
|
||||||
.s_rfnoc_ctrl_tlast (m_ctrl.slave.tlast ),
|
.s_rfnoc_ctrl_tlast (m_ctrl.tlast ),
|
||||||
.s_rfnoc_ctrl_tvalid(m_ctrl.slave.tvalid ),
|
.s_rfnoc_ctrl_tvalid(m_ctrl.tvalid ),
|
||||||
.s_rfnoc_ctrl_tready(m_ctrl.slave.tready ),
|
.s_rfnoc_ctrl_tready(m_ctrl.tready ),
|
||||||
.m_rfnoc_ctrl_tdata (s_ctrl.master.tdata ),
|
.m_rfnoc_ctrl_tdata (s_ctrl.tdata ),
|
||||||
.m_rfnoc_ctrl_tlast (s_ctrl.master.tlast ),
|
.m_rfnoc_ctrl_tlast (s_ctrl.tlast ),
|
||||||
.m_rfnoc_ctrl_tvalid(s_ctrl.master.tvalid),
|
.m_rfnoc_ctrl_tvalid(s_ctrl.tvalid),
|
||||||
.m_rfnoc_ctrl_tready(s_ctrl.master.tready)
|
.m_rfnoc_ctrl_tready(s_ctrl.tready)
|
||||||
);
|
);
|
||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
@@ -95,7 +104,7 @@ module rfnoc_block_null_src_sink_tb;
|
|||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
test.start_tb("rfnoc_block_null_src_sink_tb");
|
test.start_tb({TEST_NAME,"rfnoc_block_null_src_sink_tb"});
|
||||||
|
|
||||||
// Start the stream endpoint BFM
|
// Start the stream endpoint BFM
|
||||||
blk_ctrl = new(backend, m_ctrl, s_ctrl);
|
blk_ctrl = new(backend, m_ctrl, s_ctrl);
|
||||||
@@ -107,7 +116,7 @@ module rfnoc_block_null_src_sink_tb;
|
|||||||
|
|
||||||
// Startup block (Software initialization)
|
// Startup block (Software initialization)
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
test.start_test("Flush block then reset it");
|
test.start_test({TEST_NAME,"Flush block then reset it"});
|
||||||
begin
|
begin
|
||||||
test.start_timeout(timeout, 10us, "Waiting for flush_and_reset");
|
test.start_timeout(timeout, 10us, "Waiting for flush_and_reset");
|
||||||
#100; //Wait for GSR to deassert
|
#100; //Wait for GSR to deassert
|
||||||
@@ -118,7 +127,7 @@ module rfnoc_block_null_src_sink_tb;
|
|||||||
|
|
||||||
// Run Tests
|
// Run Tests
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
test.start_test("Read Block Info");
|
test.start_test({TEST_NAME,"Read Block Info"});
|
||||||
begin
|
begin
|
||||||
test.start_timeout(timeout, 1us, "Waiting for block info response");
|
test.start_timeout(timeout, 1us, "Waiting for block info response");
|
||||||
// Get static block info and validate it
|
// Get static block info and validate it
|
||||||
@@ -130,19 +139,20 @@ module rfnoc_block_null_src_sink_tb;
|
|||||||
|
|
||||||
// Read status register and validate it
|
// Read status register and validate it
|
||||||
blk_ctrl.reg_read(dut.REG_CTRL_STATUS, rvalue);
|
blk_ctrl.reg_read(dut.REG_CTRL_STATUS, rvalue);
|
||||||
`ASSERT_ERROR(rvalue[31:24] == 2, "Incorrect NIPC Value");
|
`ASSERT_ERROR(rvalue[31:24] == NIPC, "Incorrect NIPC Value");
|
||||||
`ASSERT_ERROR(rvalue[23:16] == ITEM_W, "Incorrect ITEM_W Value");
|
`ASSERT_ERROR(rvalue[23:16] == ITEM_W, "Incorrect ITEM_W Value");
|
||||||
test.end_timeout(timeout);
|
test.end_timeout(timeout);
|
||||||
end
|
end
|
||||||
test.end_test();
|
test.end_test();
|
||||||
|
|
||||||
test.start_test("Stream Data Through Loopback Port");
|
test.start_test({TEST_NAME,"Stream Data Through Loopback Port m1->s1"});
|
||||||
begin
|
begin
|
||||||
// Send and receive packets
|
// Send and receive packets
|
||||||
repeat (NUM_PKTS) begin
|
repeat (NUM_PKTS) begin
|
||||||
chdr_word_t rx_data[$];
|
chdr_word_t rx_data[$];
|
||||||
int rx_bytes;
|
int rx_bytes;
|
||||||
automatic ItemDataBuff #(logic[ITEM_W-1:0]) tx_dbuff = new, rx_dbuff = new;
|
automatic ItemDataBuff #(logic[ITEM_W-1:0],CHDR_W) tx_dbuff = new;
|
||||||
|
automatic ItemDataBuff #(logic[ITEM_W-1:0],CHDR_W) rx_dbuff = new;
|
||||||
for (int i = 0; i < SPP; i++)
|
for (int i = 0; i < SPP; i++)
|
||||||
tx_dbuff.put($urandom());
|
tx_dbuff.put($urandom());
|
||||||
test.start_timeout(timeout, 5us, "Waiting for pkt to loop back");
|
test.start_timeout(timeout, 5us, "Waiting for pkt to loop back");
|
||||||
@@ -173,16 +183,16 @@ module rfnoc_block_null_src_sink_tb;
|
|||||||
end
|
end
|
||||||
test.end_test();
|
test.end_test();
|
||||||
|
|
||||||
test.start_test("Stream Data To Sink Port");
|
test.start_test({TEST_NAME,"Stream Data To Sink Port m0"});
|
||||||
begin
|
begin
|
||||||
// Send packets
|
// Send packets
|
||||||
repeat (NUM_PKTS) begin
|
repeat (NUM_PKTS) begin
|
||||||
chdr_word_t rx_data[$];
|
chdr_word_t rx_data[$];
|
||||||
int rx_bytes;
|
int rx_bytes;
|
||||||
automatic ItemDataBuff #(logic[ITEM_W-1:0]) tx_dbuff = new;
|
automatic ItemDataBuff #(logic[ITEM_W-1:0],CHDR_W) tx_dbuff = new;
|
||||||
for (int i = 0; i < SPP; i++)
|
for (int i = 0; i < SPP; i++)
|
||||||
tx_dbuff.put($urandom());
|
tx_dbuff.put($urandom());
|
||||||
test.start_timeout(timeout, 5us, "Waiting for pkt to loop back");
|
test.start_timeout(timeout, 5us, "Waiting to send packet");
|
||||||
blk_ctrl.send(PORT_SRCSNK, tx_dbuff.to_chdr_payload(), tx_dbuff.get_bytes());
|
blk_ctrl.send(PORT_SRCSNK, tx_dbuff.to_chdr_payload(), tx_dbuff.get_bytes());
|
||||||
test.end_timeout(timeout);
|
test.end_timeout(timeout);
|
||||||
end
|
end
|
||||||
@@ -208,11 +218,12 @@ module rfnoc_block_null_src_sink_tb;
|
|||||||
end
|
end
|
||||||
test.end_test();
|
test.end_test();
|
||||||
|
|
||||||
test.start_test("Stream Data From Source Port");
|
test.start_test({TEST_NAME,"Stream Data From Source Port s0"});
|
||||||
begin
|
begin
|
||||||
// Turn on the source for some time then stop it
|
// Turn on the source for some time then stop it
|
||||||
blk_ctrl.reg_write(dut.REG_SRC_LINES_PER_PKT, LPP-1);
|
blk_ctrl.reg_write(dut.REG_SRC_LINES_PER_PKT, LPP-1);
|
||||||
blk_ctrl.reg_write(dut.REG_SRC_BYTES_PER_PKT, (LPP+1)*8);
|
// A line is generated as NIPC Items
|
||||||
|
blk_ctrl.reg_write(dut.REG_SRC_BYTES_PER_PKT, (LPP+1)*ITEM_W/8*NIPC);
|
||||||
blk_ctrl.reg_write(dut.REG_CTRL_STATUS, 2'b10);
|
blk_ctrl.reg_write(dut.REG_CTRL_STATUS, 2'b10);
|
||||||
repeat ((NUM_PKTS / 10) * LPP) @(posedge rfnoc_chdr_clk);
|
repeat ((NUM_PKTS / 10) * LPP) @(posedge rfnoc_chdr_clk);
|
||||||
blk_ctrl.reg_write(dut.REG_CTRL_STATUS, 2'b00);
|
blk_ctrl.reg_write(dut.REG_CTRL_STATUS, 2'b00);
|
||||||
@@ -228,7 +239,7 @@ module rfnoc_block_null_src_sink_tb;
|
|||||||
test.start_timeout(timeout, 5us, "Waiting for pkt to arrive");
|
test.start_timeout(timeout, 5us, "Waiting for pkt to arrive");
|
||||||
exp_data.delete();
|
exp_data.delete();
|
||||||
for (int i = p*LPP; i < (p+1)*LPP; i++)
|
for (int i = p*LPP; i < (p+1)*LPP; i++)
|
||||||
exp_data.push_back({~i[15:0], i[15:0], ~i[15:0], i[15:0]});
|
exp_data.push_back({NIPC{{~i[ITEM_W/2-1:0], i[ITEM_W/2-1:0]}}});
|
||||||
blk_ctrl.recv(PORT_SRCSNK, rx_data, rx_bytes);
|
blk_ctrl.recv(PORT_SRCSNK, rx_data, rx_bytes);
|
||||||
`ASSERT_ERROR(blk_ctrl.compare_data(exp_data, rx_data), "Data mismatch");
|
`ASSERT_ERROR(blk_ctrl.compare_data(exp_data, rx_data), "Data mismatch");
|
||||||
test.end_timeout(timeout);
|
test.end_timeout(timeout);
|
||||||
@@ -236,7 +247,7 @@ module rfnoc_block_null_src_sink_tb;
|
|||||||
end
|
end
|
||||||
test.end_test();
|
test.end_test();
|
||||||
|
|
||||||
test.start_test("Clear Counts");
|
test.start_test({TEST_NAME,"Clear Counts"});
|
||||||
begin
|
begin
|
||||||
test.start_timeout(timeout, 1us, "Waiting for clear and readbacks");
|
test.start_timeout(timeout, 1us, "Waiting for clear and readbacks");
|
||||||
// Clear
|
// Clear
|
||||||
@@ -266,7 +277,7 @@ module rfnoc_block_null_src_sink_tb;
|
|||||||
// Finish Up
|
// Finish Up
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
// Display final statistics and results
|
// Display final statistics and results
|
||||||
test.end_tb();
|
test.end_tb(.finish(0));
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
@@ -411,7 +411,7 @@ module chdr_stream_output #(
|
|||||||
if (CHDR_W < 128)
|
if (CHDR_W < 128)
|
||||||
state <= ST_STRC_W1;
|
state <= ST_STRC_W1;
|
||||||
else
|
else
|
||||||
state <= ST_STRC_WAIT;
|
state <= fc_resync_req ? ST_PASS_DATA : ST_STRC_WAIT;
|
||||||
end
|
end
|
||||||
|
|
||||||
// ST_STRC_W1
|
// ST_STRC_W1
|
||||||
@@ -527,7 +527,7 @@ module chdr_stream_output #(
|
|||||||
assign msg_o_tready = msg_o_tvalid && (state == ST_PASS_DATA || state == ST_STRC_WAIT);
|
assign msg_o_tready = msg_o_tvalid && (state == ST_PASS_DATA || state == ST_STRC_WAIT);
|
||||||
|
|
||||||
// Acknowledge a flow control resync command
|
// Acknowledge a flow control resync command
|
||||||
assign fc_resync_ack = fc_resync_req && (state == ST_STRC_W1) &&
|
assign fc_resync_ack = fc_resync_req && (state == ST_STRC_W1 || state == ST_STRC_W0) &&
|
||||||
chdr_out_tvalid && chdr_out_tready && chdr_out_tlast;
|
chdr_out_tvalid && chdr_out_tready && chdr_out_tlast;
|
||||||
|
|
||||||
// ---------------------------------------------------
|
// ---------------------------------------------------
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ module chdr_to_axis_ctrl #(
|
|||||||
ST_CHDR_HDR: begin
|
ST_CHDR_HDR: begin
|
||||||
ch2ct_nmdata <= chdr_get_num_mdata(ch2ct_tdata[63:0]) - 5'd1;
|
ch2ct_nmdata <= chdr_get_num_mdata(ch2ct_tdata[63:0]) - 5'd1;
|
||||||
if (!ch2ct_tlast)
|
if (!ch2ct_tlast)
|
||||||
ch2ct_state <= (chdr_get_num_mdata(ch2ct_tdata[63:0]) == 5'd0) ?
|
ch2ct_state <= (chdr_get_num_mdata(ch2ct_tdata[63:0]) == 5'd0) ?
|
||||||
ST_CTRL_HDR : ST_CHDR_MDATA;
|
ST_CTRL_HDR : ST_CHDR_MDATA;
|
||||||
else
|
else
|
||||||
ch2ct_state <= ST_CHDR_HDR; // Premature termination
|
ch2ct_state <= ST_CHDR_HDR; // Premature termination
|
||||||
@@ -152,7 +152,7 @@ module chdr_to_axis_ctrl #(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Create the first two lines of the Ctrl word (wide)
|
// Create the first two lines of the Ctrl word (wide)
|
||||||
// using data from CHDR packet
|
// using data from CHDR packet
|
||||||
wire [CHDR_W-1:0] ch2ct_new_ctrl_hdr;
|
wire [CHDR_W-1:0] ch2ct_new_ctrl_hdr;
|
||||||
assign ch2ct_new_ctrl_hdr[63:0] = {
|
assign ch2ct_new_ctrl_hdr[63:0] = {
|
||||||
axis_ctrl_build_hdr_hi(
|
axis_ctrl_build_hdr_hi(
|
||||||
@@ -172,7 +172,7 @@ module chdr_to_axis_ctrl #(
|
|||||||
assign ch2ct_new_ctrl_hdr[CHDR_W-1:64] = ch2ct_tdata[CHDR_W-1:64];
|
assign ch2ct_new_ctrl_hdr[CHDR_W-1:64] = ch2ct_tdata[CHDR_W-1:64];
|
||||||
end endgenerate
|
end endgenerate
|
||||||
|
|
||||||
wire [CHDR_W-1:0] ch2ct_wctrl_tdata =
|
wire [CHDR_W-1:0] ch2ct_wctrl_tdata =
|
||||||
(ch2ct_state == ST_CTRL_HDR) ? ch2ct_new_ctrl_hdr : ch2ct_tdata;
|
(ch2ct_state == ST_CTRL_HDR) ? ch2ct_new_ctrl_hdr : ch2ct_tdata;
|
||||||
|
|
||||||
axis_width_conv #(
|
axis_width_conv #(
|
||||||
@@ -205,7 +205,7 @@ module chdr_to_axis_ctrl #(
|
|||||||
// - Use the Ctrl RemDstPort as the CHDR DstPort (forward the master's request)
|
// - Use the Ctrl RemDstPort as the CHDR DstPort (forward the master's request)
|
||||||
// - Use the this_epid as CHDR SrcEPID (return path for the CHDR packet)
|
// - Use the this_epid as CHDR SrcEPID (return path for the CHDR packet)
|
||||||
// - Use the Ctrl SrcPort as the CHDR SrcPort (return path to the master)
|
// - Use the Ctrl SrcPort as the CHDR SrcPort (return path to the master)
|
||||||
// - Ignore the Ctrl DstPort because the packet has already been routed
|
// - Ignore the Ctrl DstPort because the packet has already been routed
|
||||||
|
|
||||||
wire [CHDR_W-1:0] ct2ch_wctrl_tdata;
|
wire [CHDR_W-1:0] ct2ch_wctrl_tdata;
|
||||||
wire ct2ch_wctrl_tlast, ct2ch_wctrl_tvalid, ct2ch_wctrl_tready;
|
wire ct2ch_wctrl_tlast, ct2ch_wctrl_tvalid, ct2ch_wctrl_tready;
|
||||||
@@ -238,8 +238,7 @@ module chdr_to_axis_ctrl #(
|
|||||||
end else if (ct2ch_tvalid && ct2ch_tready) begin
|
end else if (ct2ch_tvalid && ct2ch_tready) begin
|
||||||
case (ct2ch_state)
|
case (ct2ch_state)
|
||||||
ST_CHDR_HDR: begin
|
ST_CHDR_HDR: begin
|
||||||
if (!ct2ch_tlast)
|
ct2ch_state <= ST_CTRL_HDR;
|
||||||
ct2ch_state <= ST_CTRL_HDR;
|
|
||||||
end
|
end
|
||||||
ST_CTRL_HDR: begin
|
ST_CTRL_HDR: begin
|
||||||
if (ct2ch_tlast)
|
if (ct2ch_tlast)
|
||||||
@@ -264,56 +263,60 @@ module chdr_to_axis_ctrl #(
|
|||||||
// Hold the first line to generate info for the outgoing CHDR header
|
// Hold the first line to generate info for the outgoing CHDR header
|
||||||
assign ct2ch_wctrl_tready = (ct2ch_state == ST_CTRL_HDR || ct2ch_state == ST_CTRL_BODY) ? ct2ch_tready : 1'b0;
|
assign ct2ch_wctrl_tready = (ct2ch_state == ST_CTRL_HDR || ct2ch_state == ST_CTRL_BODY) ? ct2ch_tready : 1'b0;
|
||||||
|
|
||||||
wire [7:0] ct2ch_32bit_lines = 8'd3 + // Header + OpWord
|
wire [7:0] ct2ch_num_data = {4'h0, axis_ctrl_get_num_data(ct2ch_wctrl_tdata[31:0])};
|
||||||
(axis_ctrl_get_has_time(ct2ch_wctrl_tdata[31:0]) ? 8'd2 : 8'd0) + // Timestamp
|
wire [7:0] ct2ch_timestamp = axis_ctrl_get_has_time(ct2ch_wctrl_tdata[31:0]) ? 8'd2 : 8'd0;
|
||||||
({4'h0, axis_ctrl_get_num_data(ct2ch_wctrl_tdata[31:0])}); // Data words
|
wire [7:0] ct2ch_32bit_lines = CHDR_W/32 + // CHDR header
|
||||||
|
8'd3 + // CTL Header + OpWord
|
||||||
|
ct2ch_timestamp + // Timestamp
|
||||||
|
ct2ch_num_data; // Data words
|
||||||
|
|
||||||
wire [15:0] ct2ch_chdr_lines = 16'd1 + // CHDR header
|
reg [CHDR_W-1:0] ct2ch_sm_tdata,ct2ch_chdr_hdr;
|
||||||
ct2ch_32bit_lines[7:$clog2(CHDR_W/32)] + // Convert 32-bit lines to CHDR_W
|
reg [63:0] ct2ch_ctrl_hdr;
|
||||||
(|ct2ch_32bit_lines[$clog2(CHDR_W/32)-1:0]); // Residue
|
|
||||||
|
|
||||||
reg [63:0] ct2ch_chdr_tdata;
|
always @(*) begin
|
||||||
|
ct2ch_chdr_hdr = 0;
|
||||||
|
ct2ch_chdr_hdr = chdr_build_header(
|
||||||
|
6'd0, /* VC */
|
||||||
|
1'b0, 1'b0, /* eob, eov */
|
||||||
|
CHDR_PKT_TYPE_CTRL,
|
||||||
|
CHDR_NO_MDATA,
|
||||||
|
ct2ch_seqnum,
|
||||||
|
(ct2ch_32bit_lines << $clog2(32/8)), /* length in bytes */
|
||||||
|
axis_ctrl_get_rem_dst_epid(ct2ch_wctrl_tdata[63:32]));
|
||||||
|
ct2ch_ctrl_hdr = {
|
||||||
|
axis_ctrl_build_hdr_hi(
|
||||||
|
10'd0, /* Unused in CHDR Control payload */
|
||||||
|
this_epid /* This is the SrcEPID */
|
||||||
|
),
|
||||||
|
axis_ctrl_build_hdr_lo(
|
||||||
|
axis_ctrl_get_is_ack (ct2ch_wctrl_tdata[31:0]),
|
||||||
|
axis_ctrl_get_has_time(ct2ch_wctrl_tdata[31:0]),
|
||||||
|
axis_ctrl_get_seq_num (ct2ch_wctrl_tdata[31:0]),
|
||||||
|
axis_ctrl_get_num_data(ct2ch_wctrl_tdata[31:0]),
|
||||||
|
axis_ctrl_get_src_port(ct2ch_wctrl_tdata[31:0]),
|
||||||
|
axis_ctrl_get_rem_dst_port(ct2ch_wctrl_tdata[63:32])
|
||||||
|
)
|
||||||
|
};
|
||||||
|
end
|
||||||
always @(*) begin
|
always @(*) begin
|
||||||
case (ct2ch_state)
|
case (ct2ch_state)
|
||||||
ST_CHDR_HDR: begin
|
ST_CHDR_HDR: begin
|
||||||
ct2ch_chdr_tdata = chdr_build_header(
|
// regardless of width CHDR is always a full word
|
||||||
6'd0, /* VC */
|
ct2ch_sm_tdata = ct2ch_chdr_hdr;
|
||||||
1'b0, 1'b0, /* eob, eov */
|
|
||||||
CHDR_PKT_TYPE_CTRL,
|
|
||||||
CHDR_NO_MDATA,
|
|
||||||
ct2ch_seqnum,
|
|
||||||
(ct2ch_chdr_lines << $clog2(CHDR_W/8)), /* length in bytes */
|
|
||||||
axis_ctrl_get_rem_dst_epid(ct2ch_wctrl_tdata[63:32])
|
|
||||||
);
|
|
||||||
end
|
end
|
||||||
ST_CTRL_HDR: begin
|
ST_CTRL_HDR: begin
|
||||||
ct2ch_chdr_tdata = {
|
ct2ch_sm_tdata = ct2ch_wctrl_tdata;
|
||||||
axis_ctrl_build_hdr_hi(
|
ct2ch_sm_tdata[63:0] = ct2ch_ctrl_hdr;
|
||||||
10'd0, /* Unused in CHDR Control payload */
|
|
||||||
this_epid /* This is the SrcEPID */
|
|
||||||
),
|
|
||||||
axis_ctrl_build_hdr_lo(
|
|
||||||
axis_ctrl_get_is_ack (ct2ch_wctrl_tdata[31:0]),
|
|
||||||
axis_ctrl_get_has_time(ct2ch_wctrl_tdata[31:0]),
|
|
||||||
axis_ctrl_get_seq_num (ct2ch_wctrl_tdata[31:0]),
|
|
||||||
axis_ctrl_get_num_data(ct2ch_wctrl_tdata[31:0]),
|
|
||||||
axis_ctrl_get_src_port(ct2ch_wctrl_tdata[31:0]),
|
|
||||||
axis_ctrl_get_rem_dst_port(ct2ch_wctrl_tdata[63:32])
|
|
||||||
)
|
|
||||||
};
|
|
||||||
end
|
end
|
||||||
default: begin
|
default: begin
|
||||||
ct2ch_chdr_tdata = ct2ch_wctrl_tdata[63:0];
|
ct2ch_sm_tdata = ct2ch_wctrl_tdata;
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
// Output signals
|
// Output signals
|
||||||
assign ct2ch_tdata[63:0] = ct2ch_chdr_tdata;
|
assign ct2ch_tdata = ct2ch_sm_tdata;
|
||||||
assign ct2ch_tlast = ct2ch_wctrl_tlast;
|
assign ct2ch_tlast = ct2ch_wctrl_tlast && (ct2ch_state != ST_CHDR_HDR);
|
||||||
assign ct2ch_tvalid = ct2ch_wctrl_tvalid;
|
assign ct2ch_tvalid = ct2ch_wctrl_tvalid;
|
||||||
generate if (CHDR_W > 64) begin
|
|
||||||
assign ct2ch_tdata[CHDR_W-1:64] = ct2ch_wctrl_tdata[CHDR_W-1:64];
|
|
||||||
end endgenerate
|
|
||||||
|
|
||||||
endmodule // chdr_to_axis_ctrl
|
endmodule // chdr_to_axis_ctrl
|
||||||
|
|||||||
@@ -34,9 +34,10 @@ $(RFNOC_CORE_SRCS) \
|
|||||||
# Testbench Specific
|
# Testbench Specific
|
||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
# Define only one toplevel module
|
# Define only one toplevel module
|
||||||
SIM_TOP = chdr_crossbar_nxn_tb
|
SIM_TOP = chdr_crossbar_nxn_all_tb
|
||||||
|
|
||||||
SIM_SRCS = \
|
SIM_SRCS = \
|
||||||
|
$(abspath chdr_crossbar_nxn_all_tb.sv) \
|
||||||
$(abspath chdr_crossbar_nxn_tb.sv) \
|
$(abspath chdr_crossbar_nxn_tb.sv) \
|
||||||
$(abspath ../crossbar_tb.sv) \
|
$(abspath ../crossbar_tb.sv) \
|
||||||
$(abspath ../chdr_traffic_source_sim.sv) \
|
$(abspath ../chdr_traffic_source_sim.sv) \
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 Ettus Research, a National Instruments Brand
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
//
|
||||||
|
// Module: chdr_crossbar_nxn
|
||||||
|
//
|
||||||
|
// Description: Testbench for chdr_crossbar_nxn that runs multiple widths
|
||||||
|
//
|
||||||
|
|
||||||
|
module chdr_crossbar_nxn_all_tb#(
|
||||||
|
/* no PARAM */
|
||||||
|
)(
|
||||||
|
/* no IO */
|
||||||
|
);
|
||||||
|
|
||||||
|
chdr_crossbar_nxn_tb #(.TEST_NAME("64B"),.CHDR_W(64)) CHDR64 ();
|
||||||
|
chdr_crossbar_nxn_tb #(.TEST_NAME("512B"),.CHDR_W(512)) CHDR512 ();
|
||||||
|
|
||||||
|
// Wait for all done
|
||||||
|
bit clk,rst;
|
||||||
|
sim_clock_gen #(100.0) clk_gen (clk, rst);
|
||||||
|
always_ff@(posedge clk)
|
||||||
|
if (CHDR64.impl.done && CHDR512.impl.done) $finish(1);
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -6,12 +6,17 @@
|
|||||||
|
|
||||||
`timescale 1ns/1ps
|
`timescale 1ns/1ps
|
||||||
|
|
||||||
module chdr_crossbar_nxn_tb();
|
module chdr_crossbar_nxn_tb#(
|
||||||
|
parameter TEST_NAME = "chdr_crossbar_nxn_tb",
|
||||||
|
parameter CHDR_W = 64
|
||||||
|
)(
|
||||||
|
/* no IO */
|
||||||
|
);
|
||||||
crossbar_tb #(
|
crossbar_tb #(
|
||||||
.TEST_NAME ("chdr_crossbar_nxn_tb"),
|
.TEST_NAME (TEST_NAME ),
|
||||||
.ROUTER_IMPL ("chdr_crossbar_nxn" ), // Router implementation
|
.ROUTER_IMPL ("chdr_crossbar_nxn" ), // Router implementation
|
||||||
.ROUTER_PORTS (10 ), // Number of ports
|
.ROUTER_PORTS (10 ), // Number of ports
|
||||||
.ROUTER_DWIDTH (64 ), // Router datapath width
|
.ROUTER_DWIDTH (CHDR_W ), // Router datapath width
|
||||||
.MTU_LOG2 (7 ), // log2 of max packet size for router
|
.MTU_LOG2 (7 ), // log2 of max packet size for router
|
||||||
.NUM_MASTERS (10 ), // Number of data generators in test
|
.NUM_MASTERS (10 ), // Number of data generators in test
|
||||||
.TEST_MAX_PACKETS (100 ), // How many packets to stream per test case?
|
.TEST_MAX_PACKETS (100 ), // How many packets to stream per test case?
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ module chdr_traffic_sink_sim #(
|
|||||||
s_chdr.reset();
|
s_chdr.reset();
|
||||||
while (1) begin
|
while (1) begin
|
||||||
// A session begins on the posedge of start_stb
|
// A session begins on the posedge of start_stb
|
||||||
while (~start_stb) @(posedge clk);
|
while (start_stb !== 1) @(posedge clk);
|
||||||
session = session + 1;
|
session = session + 1;
|
||||||
$sformat(filename, "%s/pkts_node%05d_inj%03d_lpp%05d_traffic%c_sess%04d.csv",
|
$sformat(filename, "%s/pkts_node%05d_inj%03d_lpp%05d_traffic%c_sess%04d.csv",
|
||||||
FILE_PATH, NODE_ID, injection_rate, lines_per_pkt, traffic_patt, session);
|
FILE_PATH, NODE_ID, injection_rate, lines_per_pkt, traffic_patt, session);
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ module chdr_traffic_source_sim #(
|
|||||||
m_chdr.reset();
|
m_chdr.reset();
|
||||||
while (1) begin
|
while (1) begin
|
||||||
// A generation session begins on the posedge of start_stb
|
// A generation session begins on the posedge of start_stb
|
||||||
while (~start_stb) @(posedge clk);
|
while (start_stb !== 1) @(posedge clk);
|
||||||
curr_pkt_num = 'd0;
|
curr_pkt_num = 'd0;
|
||||||
m_chdr.reset();
|
m_chdr.reset();
|
||||||
num_samps_xferd = 'd0;
|
num_samps_xferd = 'd0;
|
||||||
|
|||||||
@@ -58,12 +58,18 @@ module crossbar_tb #(
|
|||||||
//----------------------------------------------------
|
//----------------------------------------------------
|
||||||
// Instantiate traffic generators, checkers, buses
|
// Instantiate traffic generators, checkers, buses
|
||||||
//----------------------------------------------------
|
//----------------------------------------------------
|
||||||
localparam FILE_PATH = {`WORKING_DIR, "/data/", ROUTER_IMPL};
|
`ifndef WORKING_DIR
|
||||||
|
// For XSim
|
||||||
|
localparam FILE_PATH = {`WORKING_DIR, "/data/", ROUTER_IMPL};
|
||||||
|
`else
|
||||||
|
// For ModelSim
|
||||||
|
localparam FILE_PATH = {"./work", "/data/", ROUTER_IMPL};
|
||||||
|
`endif
|
||||||
|
|
||||||
// Data buses
|
// Data buses
|
||||||
axis_t #(.DWIDTH(ROUTER_DWIDTH), .NUM_STREAMS(ROUTER_PORTS)) src2rtr_axis (.clk(clk));
|
axis_t #(.DWIDTH(ROUTER_DWIDTH), .NUM_STREAMS(ROUTER_PORTS)) src2rtr_axis (.clk(clk));
|
||||||
axis_t #(.DWIDTH(ROUTER_DWIDTH), .NUM_STREAMS(ROUTER_PORTS)) rtr2snk_axis (.clk(clk));
|
axis_t #(.DWIDTH(ROUTER_DWIDTH), .NUM_STREAMS(ROUTER_PORTS)) rtr2snk_axis (.clk(clk));
|
||||||
|
|
||||||
// Control buses
|
// Control buses
|
||||||
settings_bus_master #(.SR_AWIDTH(16), .SR_DWIDTH(32)) rtr_sb (.clk(clk));
|
settings_bus_master #(.SR_AWIDTH(16), .SR_DWIDTH(32)) rtr_sb (.clk(clk));
|
||||||
wire rtr_sb_ack;
|
wire rtr_sb_ack;
|
||||||
@@ -75,6 +81,7 @@ module crossbar_tb #(
|
|||||||
logic [31:0] set_num_pkts_to_send;
|
logic [31:0] set_num_pkts_to_send;
|
||||||
logic snk_start_stb = 0;
|
logic snk_start_stb = 0;
|
||||||
logic src_start_stb = 0;
|
logic src_start_stb = 0;
|
||||||
|
bit done = 0;
|
||||||
|
|
||||||
wire [63:0] session_duration [0:ROUTER_PORTS-1];
|
wire [63:0] session_duration [0:ROUTER_PORTS-1];
|
||||||
wire [ROUTER_PORTS-1:0] src_active;
|
wire [ROUTER_PORTS-1:0] src_active;
|
||||||
@@ -99,7 +106,7 @@ module crossbar_tb #(
|
|||||||
.MTU (MTU_LOG2),
|
.MTU (MTU_LOG2),
|
||||||
.NODE_ID (i),
|
.NODE_ID (i),
|
||||||
.NUM_NODES (ROUTER_PORTS)
|
.NUM_NODES (ROUTER_PORTS)
|
||||||
) traffic_src (
|
) traffic_src (
|
||||||
.clk (clk),
|
.clk (clk),
|
||||||
.rst (rst),
|
.rst (rst),
|
||||||
.current_time (timestamp),
|
.current_time (timestamp),
|
||||||
@@ -117,14 +124,14 @@ module crossbar_tb #(
|
|||||||
.xfer_count (src_xfer_count[i]),
|
.xfer_count (src_xfer_count[i]),
|
||||||
.pkt_count (src_pkt_count[i])
|
.pkt_count (src_pkt_count[i])
|
||||||
);
|
);
|
||||||
|
|
||||||
chdr_traffic_sink_sim #(
|
chdr_traffic_sink_sim #(
|
||||||
.WIDTH (ROUTER_DWIDTH),
|
.WIDTH (ROUTER_DWIDTH),
|
||||||
.MTU (MTU_LOG2),
|
.MTU (MTU_LOG2),
|
||||||
.NODE_ID (i),
|
.NODE_ID (i),
|
||||||
.NUM_NODES (ROUTER_PORTS),
|
.NUM_NODES (ROUTER_PORTS),
|
||||||
.FILE_PATH (TEST_GEN_LL_FILES==1 ? FILE_PATH : "")
|
.FILE_PATH (TEST_GEN_LL_FILES==1 ? FILE_PATH : "")
|
||||||
) traffic_sink (
|
) traffic_sink (
|
||||||
.clk (clk),
|
.clk (clk),
|
||||||
.rst (rst),
|
.rst (rst),
|
||||||
.current_time (timestamp),
|
.current_time (timestamp),
|
||||||
@@ -152,8 +159,8 @@ module crossbar_tb #(
|
|||||||
axi_fifo #(
|
axi_fifo #(
|
||||||
.WIDTH(ROUTER_DWIDTH+1), .SIZE(0)
|
.WIDTH(ROUTER_DWIDTH+1), .SIZE(0)
|
||||||
) fifo_i (
|
) fifo_i (
|
||||||
.clk (clk),
|
.clk (clk),
|
||||||
.reset (rst),
|
.reset (rst),
|
||||||
.clear (1'b0),
|
.clear (1'b0),
|
||||||
.i_tdata ({src2rtr_axis.tlast[i], src2rtr_axis.tdata[((i+1)*ROUTER_DWIDTH)-1:i*ROUTER_DWIDTH]}),
|
.i_tdata ({src2rtr_axis.tlast[i], src2rtr_axis.tdata[((i+1)*ROUTER_DWIDTH)-1:i*ROUTER_DWIDTH]}),
|
||||||
.i_tvalid (src2rtr_axis.tvalid[i]),
|
.i_tvalid (src2rtr_axis.tvalid[i]),
|
||||||
@@ -178,7 +185,7 @@ module crossbar_tb #(
|
|||||||
.reset (rst),
|
.reset (rst),
|
||||||
.clear (1'b0),
|
.clear (1'b0),
|
||||||
.local_addr (8'd0),
|
.local_addr (8'd0),
|
||||||
// Inputs
|
// Inputs
|
||||||
.i_tdata (src2rtr_axis.tdata),
|
.i_tdata (src2rtr_axis.tdata),
|
||||||
.i_tlast (src2rtr_axis.tlast),
|
.i_tlast (src2rtr_axis.tlast),
|
||||||
.i_tvalid (src2rtr_axis.tvalid),
|
.i_tvalid (src2rtr_axis.tvalid),
|
||||||
@@ -210,7 +217,7 @@ module crossbar_tb #(
|
|||||||
.NPORTS_MGMT (0),
|
.NPORTS_MGMT (0),
|
||||||
.EXT_RTCFG_PORT (1)
|
.EXT_RTCFG_PORT (1)
|
||||||
) router_dut_i (
|
) router_dut_i (
|
||||||
// General
|
// General
|
||||||
.clk (clk),
|
.clk (clk),
|
||||||
.reset (rst),
|
.reset (rst),
|
||||||
// Inputs
|
// Inputs
|
||||||
@@ -242,12 +249,12 @@ module crossbar_tb #(
|
|||||||
// General
|
// General
|
||||||
.clk (clk),
|
.clk (clk),
|
||||||
.reset (rst),
|
.reset (rst),
|
||||||
// Inputs
|
// Inputs
|
||||||
.s_axis_tdata (src2rtr_axis.tdata),
|
.s_axis_tdata (src2rtr_axis.tdata),
|
||||||
.s_axis_tlast (src2rtr_axis.tlast),
|
.s_axis_tlast (src2rtr_axis.tlast),
|
||||||
.s_axis_tvalid (src2rtr_axis.tvalid),
|
.s_axis_tvalid (src2rtr_axis.tvalid),
|
||||||
.s_axis_tready (src2rtr_axis.tready),
|
.s_axis_tready (src2rtr_axis.tready),
|
||||||
// Output
|
// Output
|
||||||
.m_axis_tdata (rtr2snk_axis.tdata),
|
.m_axis_tdata (rtr2snk_axis.tdata),
|
||||||
.m_axis_tlast (rtr2snk_axis.tlast),
|
.m_axis_tlast (rtr2snk_axis.tlast),
|
||||||
.m_axis_tvalid (rtr2snk_axis.tvalid),
|
.m_axis_tvalid (rtr2snk_axis.tvalid),
|
||||||
@@ -313,7 +320,7 @@ module crossbar_tb #(
|
|||||||
@(posedge clk);
|
@(posedge clk);
|
||||||
if (deadlock_re) $display("WARNING: Deadlock detected");
|
if (deadlock_re) $display("WARNING: Deadlock detected");
|
||||||
if (deadlock_fe) $display("Recovered from deadlock");
|
if (deadlock_fe) $display("Recovered from deadlock");
|
||||||
end
|
end
|
||||||
// Wait for sink blocks to finish consuming
|
// Wait for sink blocks to finish consuming
|
||||||
$display("All packets transmitted. Waiting to flush...");
|
$display("All packets transmitted. Waiting to flush...");
|
||||||
while (|snk_active) @(posedge clk);
|
while (|snk_active) @(posedge clk);
|
||||||
@@ -423,6 +430,7 @@ module crossbar_tb #(
|
|||||||
`TEST_CASE_DONE(1)
|
`TEST_CASE_DONE(1)
|
||||||
|
|
||||||
`TEST_BENCH_DONE
|
`TEST_BENCH_DONE
|
||||||
|
done = 1;
|
||||||
end // initial begin
|
end // initial begin
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
@@ -29,11 +29,12 @@ $(RFNOC_XBAR_SRCS) \
|
|||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
# Testbench Specific
|
# Testbench Specific
|
||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
SIM_TOP = chdr_stream_endpoint_tb
|
SIM_TOP = chdr_stream_endpoint_all_tb
|
||||||
|
|
||||||
SIM_SRCS = \
|
SIM_SRCS = \
|
||||||
$(abspath lossy_xport_model.v) \
|
$(abspath lossy_xport_model.v) \
|
||||||
$(abspath chdr_stream_endpoint_tb.sv) \
|
$(abspath chdr_stream_endpoint_tb.sv) \
|
||||||
|
$(abspath chdr_stream_endpoint_all_tb.sv) \
|
||||||
|
|
||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
# Bottom-of-Makefile
|
# Bottom-of-Makefile
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 Ettus Research, a National Instruments Brand
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
//
|
||||||
|
// Module: chdr_stream_endpoint_all_tb
|
||||||
|
//
|
||||||
|
// Description: Testbench for chdr_stream_endpoint that runs multiple widths
|
||||||
|
//
|
||||||
|
|
||||||
|
module chdr_stream_endpoint_all_tb#(
|
||||||
|
/* no PARAM */
|
||||||
|
)(
|
||||||
|
/* no IO */
|
||||||
|
);
|
||||||
|
|
||||||
|
chdr_stream_endpoint_tb #(.TEST_NAME("64B"),.CHDR_W(64)) CHDR64 ();
|
||||||
|
chdr_stream_endpoint_tb #(.TEST_NAME("512B"),.CHDR_W(512)) CHDR512 ();
|
||||||
|
|
||||||
|
// Wait for all done
|
||||||
|
bit clk,rst;
|
||||||
|
sim_clock_gen #(100.0) clk_gen (clk, rst);
|
||||||
|
always_ff@(posedge clk)
|
||||||
|
if (CHDR64.test.done && CHDR512.test.done) $finish(1);
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2019 Ettus Research, A National Instruments Company
|
// Copyright 2020 Ettus Research, A National Instruments Brand
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
//
|
//
|
||||||
@@ -8,14 +8,18 @@
|
|||||||
|
|
||||||
`default_nettype none
|
`default_nettype none
|
||||||
|
|
||||||
|
module chdr_stream_endpoint_tb#(
|
||||||
module chdr_stream_endpoint_tb;
|
parameter TEST_NAME = "chdr_stream_endpoint_tb",
|
||||||
|
parameter CHDR_W = 64
|
||||||
|
)(
|
||||||
|
/* no IO */
|
||||||
|
);
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
// Global settings
|
// Global settings
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
|
||||||
// Include macros and time declarations for use with PkgTestExec
|
// Include macros and time declarations for use with PkgTestExec
|
||||||
|
`define TEST_EXEC_OBJ test
|
||||||
`include "test_exec.svh"
|
`include "test_exec.svh"
|
||||||
|
|
||||||
import PkgTestExec::*;
|
import PkgTestExec::*;
|
||||||
@@ -34,7 +38,6 @@ module chdr_stream_endpoint_tb;
|
|||||||
localparam int FAST_STALL_PROB = 0;
|
localparam int FAST_STALL_PROB = 0;
|
||||||
localparam int SLOW_STALL_PROB = 35;
|
localparam int SLOW_STALL_PROB = 35;
|
||||||
|
|
||||||
localparam int CHDR_W = 64;
|
|
||||||
localparam int MTU = 7;
|
localparam int MTU = 7;
|
||||||
localparam [15:0] PROTOVER = {8'd1, 8'd0};
|
localparam [15:0] PROTOVER = {8'd1, 8'd0};
|
||||||
localparam [15:0] DEV_ID = 16'hBEEF;
|
localparam [15:0] DEV_ID = 16'hBEEF;
|
||||||
@@ -108,14 +111,14 @@ module chdr_stream_endpoint_tb;
|
|||||||
.m_axis_chdr_tlast (a2c_chdr_tlast ),
|
.m_axis_chdr_tlast (a2c_chdr_tlast ),
|
||||||
.m_axis_chdr_tvalid (a2c_chdr_tvalid ),
|
.m_axis_chdr_tvalid (a2c_chdr_tvalid ),
|
||||||
.m_axis_chdr_tready (a2c_chdr_tready ),
|
.m_axis_chdr_tready (a2c_chdr_tready ),
|
||||||
.s_axis_data_tdata ({m_a1_data.slave.tdata , m_a0_data.slave.tdata }),
|
.s_axis_data_tdata ({m_a1_data.tdata , m_a0_data.tdata }),
|
||||||
.s_axis_data_tlast ({m_a1_data.slave.tlast , m_a0_data.slave.tlast }),
|
.s_axis_data_tlast ({m_a1_data.tlast , m_a0_data.tlast }),
|
||||||
.s_axis_data_tvalid ({m_a1_data.slave.tvalid , m_a0_data.slave.tvalid }),
|
.s_axis_data_tvalid ({m_a1_data.tvalid , m_a0_data.tvalid }),
|
||||||
.s_axis_data_tready ({m_a1_data.slave.tready , m_a0_data.slave.tready }),
|
.s_axis_data_tready ({m_a1_data.tready , m_a0_data.tready }),
|
||||||
.m_axis_data_tdata ({s_a1_data.master.tdata , s_a0_data.master.tdata }),
|
.m_axis_data_tdata ({s_a1_data.tdata , s_a0_data.tdata }),
|
||||||
.m_axis_data_tlast ({s_a1_data.master.tlast , s_a0_data.master.tlast }),
|
.m_axis_data_tlast ({s_a1_data.tlast , s_a0_data.tlast }),
|
||||||
.m_axis_data_tvalid ({s_a1_data.master.tvalid, s_a0_data.master.tvalid}),
|
.m_axis_data_tvalid ({s_a1_data.tvalid, s_a0_data.tvalid}),
|
||||||
.m_axis_data_tready ({s_a1_data.master.tready, s_a0_data.master.tready}),
|
.m_axis_data_tready ({s_a1_data.tready, s_a0_data.tready}),
|
||||||
.s_axis_ctrl_tdata (a_ctrl_out_tdata ),
|
.s_axis_ctrl_tdata (a_ctrl_out_tdata ),
|
||||||
.s_axis_ctrl_tlast (a_ctrl_loop_tlast ),
|
.s_axis_ctrl_tlast (a_ctrl_loop_tlast ),
|
||||||
.s_axis_ctrl_tvalid (a_ctrl_loop_tvalid ),
|
.s_axis_ctrl_tvalid (a_ctrl_loop_tvalid ),
|
||||||
@@ -157,14 +160,14 @@ module chdr_stream_endpoint_tb;
|
|||||||
.m_axis_chdr_tlast (b2c_chdr_tlast ),
|
.m_axis_chdr_tlast (b2c_chdr_tlast ),
|
||||||
.m_axis_chdr_tvalid (b2c_chdr_tvalid ),
|
.m_axis_chdr_tvalid (b2c_chdr_tvalid ),
|
||||||
.m_axis_chdr_tready (b2c_chdr_tready ),
|
.m_axis_chdr_tready (b2c_chdr_tready ),
|
||||||
.s_axis_data_tdata ({m_b1_data.slave.tdata , m_b0_data.slave.tdata }),
|
.s_axis_data_tdata ({m_b1_data.tdata , m_b0_data.tdata }),
|
||||||
.s_axis_data_tlast ({m_b1_data.slave.tlast , m_b0_data.slave.tlast }),
|
.s_axis_data_tlast ({m_b1_data.tlast , m_b0_data.tlast }),
|
||||||
.s_axis_data_tvalid ({m_b1_data.slave.tvalid , m_b0_data.slave.tvalid }),
|
.s_axis_data_tvalid ({m_b1_data.tvalid , m_b0_data.tvalid }),
|
||||||
.s_axis_data_tready ({m_b1_data.slave.tready , m_b0_data.slave.tready }),
|
.s_axis_data_tready ({m_b1_data.tready , m_b0_data.tready }),
|
||||||
.m_axis_data_tdata ({s_b1_data.master.tdata , s_b0_data.master.tdata }),
|
.m_axis_data_tdata ({s_b1_data.tdata , s_b0_data.tdata }),
|
||||||
.m_axis_data_tlast ({s_b1_data.master.tlast , s_b0_data.master.tlast }),
|
.m_axis_data_tlast ({s_b1_data.tlast , s_b0_data.tlast }),
|
||||||
.m_axis_data_tvalid ({s_b1_data.master.tvalid, s_b0_data.master.tvalid}),
|
.m_axis_data_tvalid ({s_b1_data.tvalid, s_b0_data.tvalid}),
|
||||||
.m_axis_data_tready ({s_b1_data.master.tready, s_b0_data.master.tready}),
|
.m_axis_data_tready ({s_b1_data.tready, s_b0_data.tready}),
|
||||||
.s_axis_ctrl_tdata (b_ctrl_out_tdata ),
|
.s_axis_ctrl_tdata (b_ctrl_out_tdata ),
|
||||||
.s_axis_ctrl_tlast (b_ctrl_loop_tlast ),
|
.s_axis_ctrl_tlast (b_ctrl_loop_tlast ),
|
||||||
.s_axis_ctrl_tvalid (b_ctrl_loop_tvalid ),
|
.s_axis_ctrl_tvalid (b_ctrl_loop_tvalid ),
|
||||||
@@ -194,14 +197,14 @@ module chdr_stream_endpoint_tb;
|
|||||||
.clk (rfnoc_chdr_clk),
|
.clk (rfnoc_chdr_clk),
|
||||||
.reset (rfnoc_chdr_rst),
|
.reset (rfnoc_chdr_rst),
|
||||||
.device_id (DEV_ID),
|
.device_id (DEV_ID),
|
||||||
.s_axis_tdata ({b2c_chdr_tdata, a2c_chdr_tdata, m_tb_chdr.slave.tdata }),
|
.s_axis_tdata ({b2c_chdr_tdata, a2c_chdr_tdata, m_tb_chdr.tdata }),
|
||||||
.s_axis_tlast ({b2c_chdr_tlast, a2c_chdr_tlast, m_tb_chdr.slave.tlast }),
|
.s_axis_tlast ({b2c_chdr_tlast, a2c_chdr_tlast, m_tb_chdr.tlast }),
|
||||||
.s_axis_tvalid ({b2c_chdr_tvalid, a2c_chdr_tvalid, m_tb_chdr.slave.tvalid }),
|
.s_axis_tvalid ({b2c_chdr_tvalid, a2c_chdr_tvalid, m_tb_chdr.tvalid }),
|
||||||
.s_axis_tready ({b2c_chdr_tready, a2c_chdr_tready, m_tb_chdr.slave.tready }),
|
.s_axis_tready ({b2c_chdr_tready, a2c_chdr_tready, m_tb_chdr.tready }),
|
||||||
.m_axis_tdata ({c2bx_chdr_tdata, c2ax_chdr_tdata, s_tb_chdr.master.tdata }),
|
.m_axis_tdata ({c2bx_chdr_tdata, c2ax_chdr_tdata, s_tb_chdr.tdata }),
|
||||||
.m_axis_tlast ({c2bx_chdr_tlast, c2ax_chdr_tlast, s_tb_chdr.master.tlast }),
|
.m_axis_tlast ({c2bx_chdr_tlast, c2ax_chdr_tlast, s_tb_chdr.tlast }),
|
||||||
.m_axis_tvalid ({c2bx_chdr_tvalid, c2ax_chdr_tvalid, s_tb_chdr.master.tvalid}),
|
.m_axis_tvalid ({c2bx_chdr_tvalid, c2ax_chdr_tvalid, s_tb_chdr.tvalid}),
|
||||||
.m_axis_tready ({c2bx_chdr_tready, c2ax_chdr_tready, s_tb_chdr.master.tready}),
|
.m_axis_tready ({c2bx_chdr_tready, c2ax_chdr_tready, s_tb_chdr.tready}),
|
||||||
.ext_rtcfg_stb ('0),
|
.ext_rtcfg_stb ('0),
|
||||||
.ext_rtcfg_addr ('0),
|
.ext_rtcfg_addr ('0),
|
||||||
.ext_rtcfg_data ('0),
|
.ext_rtcfg_data ('0),
|
||||||
@@ -264,14 +267,15 @@ module chdr_stream_endpoint_tb;
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
// Respond with an ACK and the source and destination ports swapped
|
// Respond with an ACK and the source and destination ports swapped
|
||||||
assign a_ctrl_out_tdata =
|
assign a_ctrl_out_tdata =
|
||||||
a_first ? {1'b1, a_ctrl_in_tdata[30:20], a_ctrl_in_tdata[9:0], a_ctrl_in_tdata[19:10]} : a_ctrl_in_tdata;
|
a_first ? {1'b1, a_ctrl_in_tdata[30:20], a_ctrl_in_tdata[9:0], a_ctrl_in_tdata[19:10]} : a_ctrl_in_tdata;
|
||||||
assign b_ctrl_out_tdata =
|
assign b_ctrl_out_tdata =
|
||||||
b_first ? {1'b1, b_ctrl_in_tdata[30:20], b_ctrl_in_tdata[9:0], b_ctrl_in_tdata[19:10]} : b_ctrl_in_tdata;
|
b_first ? {1'b1, b_ctrl_in_tdata[30:20], b_ctrl_in_tdata[9:0], b_ctrl_in_tdata[19:10]} : b_ctrl_in_tdata;
|
||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
// Test Utilities
|
// Test Utilities
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
TestExec test = new();
|
||||||
integer cached_mgmt_seqnum = 0;
|
integer cached_mgmt_seqnum = 0;
|
||||||
integer cached_ctrl_seqnum = 0;
|
integer cached_ctrl_seqnum = 0;
|
||||||
integer cached_data_seqnum = 0;
|
integer cached_data_seqnum = 0;
|
||||||
@@ -320,7 +324,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
op_payload:{32'h0, sep_a.REG_OSTRM_DATA_ERR_CNT}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd2};
|
op_payload:{32'h0, sep_a.REG_OSTRM_DATA_ERR_CNT}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd2};
|
||||||
tx_mgmt_pl.ops[3] = '{ // Hop 2: Read status
|
tx_mgmt_pl.ops[3] = '{ // Hop 2: Read status
|
||||||
op_payload:{32'h0, sep_a.REG_OSTRM_ROUTE_ERR_CNT}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd1};
|
op_payload:{32'h0, sep_a.REG_OSTRM_ROUTE_ERR_CNT}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd1};
|
||||||
tx_mgmt_pl.ops[4] = '{ // Hop 2: Stream Endpoint: Return
|
tx_mgmt_pl.ops[4] = '{ // Hop 2: Stream Endpoint: Return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
||||||
tx_mgmt_pl.ops[5] = '{ // Hop 3: Nop for return
|
tx_mgmt_pl.ops[5] = '{ // Hop 3: Nop for return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
||||||
@@ -357,7 +361,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
automatic ctrl_op_word_t ctrl_op;
|
automatic ctrl_op_word_t ctrl_op;
|
||||||
automatic ctrl_word_t ctrl_data[$];
|
automatic ctrl_word_t ctrl_data[$];
|
||||||
automatic chdr_word_t ctrl_ts;
|
automatic chdr_word_t ctrl_ts;
|
||||||
|
|
||||||
ctrl_data.delete();
|
ctrl_data.delete();
|
||||||
for (int i = 0; i < $urandom_range(15,1); i++)
|
for (int i = 0; i < $urandom_range(15,1); i++)
|
||||||
ctrl_data[i] = $urandom();
|
ctrl_data[i] = $urandom();
|
||||||
@@ -406,6 +410,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
if (VERBOSE) begin $write("ExpRx"); exp_chdr.print(); end
|
if (VERBOSE) begin $write("ExpRx"); exp_chdr.print(); end
|
||||||
|
|
||||||
// Validate contents
|
// Validate contents
|
||||||
|
exp_chdr.disable_comparing_beyond_length = 1;
|
||||||
`ASSERT_ERROR(exp_chdr.equal(rx_chdr),
|
`ASSERT_ERROR(exp_chdr.equal(rx_chdr),
|
||||||
"Received CHDR control packet was incorrect");
|
"Received CHDR control packet was incorrect");
|
||||||
end
|
end
|
||||||
@@ -527,12 +532,12 @@ module chdr_stream_endpoint_tb;
|
|||||||
|
|
||||||
// Shared Variables
|
// Shared Variables
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
timeout_t timeout;
|
timeout_t timeout;
|
||||||
string tc_label;
|
string tc_label;
|
||||||
bit stop_responder = 0;
|
automatic bit stop_responder = 0;
|
||||||
logic [31:0] seq_err_count;
|
logic [31:0] seq_err_count;
|
||||||
logic [31:0] route_err_count;
|
logic [31:0] route_err_count;
|
||||||
logic [31:0] data_err_count;
|
logic [31:0] data_err_count;
|
||||||
|
|
||||||
a_signal_data_err = 0;
|
a_signal_data_err = 0;
|
||||||
b_signal_data_err = 0;
|
b_signal_data_err = 0;
|
||||||
@@ -543,9 +548,10 @@ module chdr_stream_endpoint_tb;
|
|||||||
b_rterr_prob = 0;
|
b_rterr_prob = 0;
|
||||||
b_lossy_input = 0;
|
b_lossy_input = 0;
|
||||||
|
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
test.start_tb("chdr_stream_endpoint_tb");
|
test.start_tb({TEST_NAME,"chdr_stream_endpoint_tb"});
|
||||||
|
|
||||||
// Start the BFMs
|
// Start the BFMs
|
||||||
a0_data_bfm.run();
|
a0_data_bfm.run();
|
||||||
@@ -562,7 +568,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
rfnoc_ctrl_clk_gen.reset();
|
rfnoc_ctrl_clk_gen.reset();
|
||||||
rfnoc_chdr_clk_gen.reset();
|
rfnoc_chdr_clk_gen.reset();
|
||||||
|
|
||||||
test.start_test("Wait for reset");
|
test.start_test({TEST_NAME,"Wait for reset"});
|
||||||
test.start_timeout(timeout, 1us, "Waiting for reset");
|
test.start_timeout(timeout, 1us, "Waiting for reset");
|
||||||
while (rfnoc_ctrl_rst) @(posedge rfnoc_ctrl_clk);
|
while (rfnoc_ctrl_rst) @(posedge rfnoc_ctrl_clk);
|
||||||
while (rfnoc_chdr_rst) @(posedge rfnoc_chdr_clk);
|
while (rfnoc_chdr_rst) @(posedge rfnoc_chdr_clk);
|
||||||
@@ -572,7 +578,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
|
|
||||||
// Discover Topology
|
// Discover Topology
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
test.start_test("Discover Topology");
|
test.start_test({TEST_NAME,"Discover Topology"});
|
||||||
begin
|
begin
|
||||||
automatic chdr_header_t tx_mgmt_hdr, rx_mgmt_hdr;
|
automatic chdr_header_t tx_mgmt_hdr, rx_mgmt_hdr;
|
||||||
automatic chdr_mgmt_t tx_mgmt_pl, rx_mgmt_pl;
|
automatic chdr_mgmt_t tx_mgmt_pl, rx_mgmt_pl;
|
||||||
@@ -587,9 +593,9 @@ module chdr_stream_endpoint_tb;
|
|||||||
// Send a node info request to the crossbar
|
// Send a node info request to the crossbar
|
||||||
tx_mgmt_pl.header.num_hops = 2;
|
tx_mgmt_pl.header.num_hops = 2;
|
||||||
tx_mgmt_pl.ops.delete();
|
tx_mgmt_pl.ops.delete();
|
||||||
tx_mgmt_pl.ops[0] = '{ // Hop 1: Send node info
|
tx_mgmt_pl.ops[0] = '{ // Hop 1: Send node info
|
||||||
op_payload:48'h0, op_code:MGMT_OP_INFO_REQ, ops_pending:8'd1};
|
op_payload:48'h0, op_code:MGMT_OP_INFO_REQ, ops_pending:8'd1};
|
||||||
tx_mgmt_pl.ops[1] = '{ // Hop 1: Return
|
tx_mgmt_pl.ops[1] = '{ // Hop 1: Return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
||||||
tx_mgmt_pl.ops[2] = '{ // Hop 2: Nop for return
|
tx_mgmt_pl.ops[2] = '{ // Hop 2: Nop for return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
||||||
@@ -605,7 +611,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
`ASSERT_ERROR(rx_mgmt_pl.ops[1] == exp_mgmt_op,
|
`ASSERT_ERROR(rx_mgmt_pl.ops[1] == exp_mgmt_op,
|
||||||
"Discover XB: Mgmt response ops were incorrect");
|
"Discover XB: Mgmt response ops were incorrect");
|
||||||
|
|
||||||
// *Status* We just discovered a crossbar with 3 ports!
|
// *Status* We just discovered a crossbar with 3 ports!
|
||||||
|
|
||||||
// Configure the crossbar routing table with our (TB) address
|
// Configure the crossbar routing table with our (TB) address
|
||||||
// then send node info request on the other two ports
|
// then send node info request on the other two ports
|
||||||
@@ -613,11 +619,11 @@ module chdr_stream_endpoint_tb;
|
|||||||
tx_mgmt_pl.ops.delete();
|
tx_mgmt_pl.ops.delete();
|
||||||
tx_mgmt_pl.ops[0] = '{ // Hop 1: Crossbar: Config router to return packet to dest
|
tx_mgmt_pl.ops[0] = '{ // Hop 1: Crossbar: Config router to return packet to dest
|
||||||
op_payload:{22'h0, PORT_TB, EPID_TB}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd1};
|
op_payload:{22'h0, PORT_TB, EPID_TB}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd1};
|
||||||
tx_mgmt_pl.ops[1] = '{ // Hop 1: Crossbar: Config router
|
tx_mgmt_pl.ops[1] = '{ // Hop 1: Crossbar: Config router
|
||||||
op_payload:{38'h0, PORT_A}, op_code:MGMT_OP_SEL_DEST, ops_pending:8'd0};
|
op_payload:{38'h0, PORT_A}, op_code:MGMT_OP_SEL_DEST, ops_pending:8'd0};
|
||||||
tx_mgmt_pl.ops[2] = '{ // Hop 2: Stream Endpoint: Send node info
|
tx_mgmt_pl.ops[2] = '{ // Hop 2: Stream Endpoint: Send node info
|
||||||
op_payload:48'h0, op_code:MGMT_OP_INFO_REQ, ops_pending:8'd1};
|
op_payload:48'h0, op_code:MGMT_OP_INFO_REQ, ops_pending:8'd1};
|
||||||
tx_mgmt_pl.ops[3] = '{ // Hop 2: Return
|
tx_mgmt_pl.ops[3] = '{ // Hop 2: Return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
||||||
tx_mgmt_pl.ops[4] = '{ // Hop 3: TB: Nop for return
|
tx_mgmt_pl.ops[4] = '{ // Hop 3: TB: Nop for return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
||||||
@@ -638,11 +644,11 @@ module chdr_stream_endpoint_tb;
|
|||||||
// Send node info request on the last port
|
// Send node info request on the last port
|
||||||
tx_mgmt_pl.header.num_hops = 3;
|
tx_mgmt_pl.header.num_hops = 3;
|
||||||
tx_mgmt_pl.ops.delete();
|
tx_mgmt_pl.ops.delete();
|
||||||
tx_mgmt_pl.ops[0] = '{ // Hop 1: Crossbar: Config router
|
tx_mgmt_pl.ops[0] = '{ // Hop 1: Crossbar: Config router
|
||||||
op_payload:{38'h0, PORT_B}, op_code:MGMT_OP_SEL_DEST, ops_pending:8'd0};
|
op_payload:{38'h0, PORT_B}, op_code:MGMT_OP_SEL_DEST, ops_pending:8'd0};
|
||||||
tx_mgmt_pl.ops[1] = '{ // Hop 2: Stream Endpoint: Send node info
|
tx_mgmt_pl.ops[1] = '{ // Hop 2: Stream Endpoint: Send node info
|
||||||
op_payload:48'h0, op_code:MGMT_OP_INFO_REQ, ops_pending:8'd1};
|
op_payload:48'h0, op_code:MGMT_OP_INFO_REQ, ops_pending:8'd1};
|
||||||
tx_mgmt_pl.ops[2] = '{ // Hop 2: Return
|
tx_mgmt_pl.ops[2] = '{ // Hop 2: Return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
||||||
tx_mgmt_pl.ops[3] = '{ // Hop 3: TB: Nop for return
|
tx_mgmt_pl.ops[3] = '{ // Hop 3: TB: Nop for return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
||||||
@@ -664,7 +670,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
|
|
||||||
// Configure Routes to Stream Endpoints A and B
|
// Configure Routes to Stream Endpoints A and B
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
test.start_test("Configure Routes");
|
test.start_test({TEST_NAME,"Configure Routes"});
|
||||||
begin
|
begin
|
||||||
automatic chdr_header_t tx_mgmt_hdr, rx_mgmt_hdr;
|
automatic chdr_header_t tx_mgmt_hdr, rx_mgmt_hdr;
|
||||||
automatic chdr_mgmt_t tx_mgmt_pl, rx_mgmt_pl;
|
automatic chdr_mgmt_t tx_mgmt_pl, rx_mgmt_pl;
|
||||||
@@ -680,9 +686,9 @@ module chdr_stream_endpoint_tb;
|
|||||||
|
|
||||||
tx_mgmt_pl.ops[0] = '{ // Hop 1: Crossbar: Config path to EP A
|
tx_mgmt_pl.ops[0] = '{ // Hop 1: Crossbar: Config path to EP A
|
||||||
op_payload:{22'h0, PORT_A, EPID_A}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd2};
|
op_payload:{22'h0, PORT_A, EPID_A}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd2};
|
||||||
tx_mgmt_pl.ops[1] = '{ // Hop 1: Crossbar: Config path to EP B
|
tx_mgmt_pl.ops[1] = '{ // Hop 1: Crossbar: Config path to EP B
|
||||||
op_payload:{22'h0, PORT_B, EPID_B}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd1};
|
op_payload:{22'h0, PORT_B, EPID_B}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd1};
|
||||||
tx_mgmt_pl.ops[2] = '{ // Hop 1: Request node info to make the packet come back
|
tx_mgmt_pl.ops[2] = '{ // Hop 1: Request node info to make the packet come back
|
||||||
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
||||||
tx_mgmt_pl.ops[3] = '{ // Hop 2: Nop for return
|
tx_mgmt_pl.ops[3] = '{ // Hop 2: Nop for return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
||||||
@@ -701,13 +707,13 @@ module chdr_stream_endpoint_tb;
|
|||||||
|
|
||||||
// Configure Stream Endpoints
|
// Configure Stream Endpoints
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
test.start_test("Configure Stream Endpoints");
|
test.start_test({TEST_NAME,"Configure Stream Endpoints"});
|
||||||
begin
|
begin
|
||||||
automatic chdr_header_t tx_mgmt_hdr, rx_mgmt_hdr;
|
automatic chdr_header_t tx_mgmt_hdr, rx_mgmt_hdr;
|
||||||
automatic chdr_mgmt_t tx_mgmt_pl, rx_mgmt_pl;
|
automatic chdr_mgmt_t tx_mgmt_pl, rx_mgmt_pl;
|
||||||
automatic chdr_mgmt_op_t exp_mgmt_op;
|
automatic chdr_mgmt_op_t exp_mgmt_op;
|
||||||
|
|
||||||
logic [15:0] epids[2] = {EPID_A, EPID_B};
|
automatic logic [15:0] epids[2] = {EPID_A, EPID_B};
|
||||||
foreach (epids[i]) begin
|
foreach (epids[i]) begin
|
||||||
// Generic management header
|
// Generic management header
|
||||||
tx_mgmt_pl.header = '{
|
tx_mgmt_pl.header = '{
|
||||||
@@ -727,13 +733,13 @@ module chdr_stream_endpoint_tb;
|
|||||||
op_payload:{32'h0, sep_a.REG_EPID_SELF}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd2};
|
op_payload:{32'h0, sep_a.REG_EPID_SELF}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd2};
|
||||||
tx_mgmt_pl.ops[4] = '{ // Hop 2: Read EPID
|
tx_mgmt_pl.ops[4] = '{ // Hop 2: Read EPID
|
||||||
op_payload:{32'h0, sep_a.REG_OSTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd1};
|
op_payload:{32'h0, sep_a.REG_OSTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd1};
|
||||||
tx_mgmt_pl.ops[5] = '{ // Hop 2: Stream Endpoint: Return
|
tx_mgmt_pl.ops[5] = '{ // Hop 2: Stream Endpoint: Return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
||||||
tx_mgmt_pl.ops[6] = '{ // Hop 3: Nop for return
|
tx_mgmt_pl.ops[6] = '{ // Hop 3: Nop for return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
||||||
tx_mgmt_hdr = '{
|
tx_mgmt_hdr = '{
|
||||||
pkt_type:CHDR_MANAGEMENT, seq_num:cached_mgmt_seqnum++, dst_epid:epids[i], default:'0};
|
pkt_type:CHDR_MANAGEMENT, seq_num:cached_mgmt_seqnum++, dst_epid:epids[i], default:'0};
|
||||||
|
|
||||||
// Send the packet and check the response
|
// Send the packet and check the response
|
||||||
send_recv_mgmt_packet(tx_mgmt_hdr, tx_mgmt_pl, rx_mgmt_hdr, rx_mgmt_pl);
|
send_recv_mgmt_packet(tx_mgmt_hdr, tx_mgmt_pl, rx_mgmt_hdr, rx_mgmt_pl);
|
||||||
`ASSERT_ERROR(rx_mgmt_pl.header.num_hops == 1,
|
`ASSERT_ERROR(rx_mgmt_pl.header.num_hops == 1,
|
||||||
@@ -752,13 +758,13 @@ module chdr_stream_endpoint_tb;
|
|||||||
|
|
||||||
// Setup a stream between Endpoint A and B
|
// Setup a stream between Endpoint A and B
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
test.start_test("Setup bidirectional stream between endpoints A and B");
|
test.start_test({TEST_NAME,"Setup bidirectional stream between endpoints A and B"});
|
||||||
begin
|
begin
|
||||||
automatic chdr_header_t tx_mgmt_hdr, rx_mgmt_hdr;
|
automatic chdr_header_t tx_mgmt_hdr, rx_mgmt_hdr;
|
||||||
automatic chdr_mgmt_t tx_mgmt_pl, rx_mgmt_pl;
|
automatic chdr_mgmt_t tx_mgmt_pl, rx_mgmt_pl;
|
||||||
automatic chdr_mgmt_op_t exp_mgmt_op;
|
automatic chdr_mgmt_op_t exp_mgmt_op;
|
||||||
|
|
||||||
logic [15:0] epids[2] = {EPID_A, EPID_B};
|
automatic logic [15:0] epids[2] = {EPID_A, EPID_B};
|
||||||
foreach (epids[i]) begin
|
foreach (epids[i]) begin
|
||||||
// Generic management header
|
// Generic management header
|
||||||
tx_mgmt_pl.header = '{
|
tx_mgmt_pl.header = '{
|
||||||
@@ -784,7 +790,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
op_payload:{32'h44, sep_a.REG_ISTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd2}; // Swap 32-bit words, endianness
|
op_payload:{32'h44, sep_a.REG_ISTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd2}; // Swap 32-bit words, endianness
|
||||||
tx_mgmt_pl.ops[7] = '{ // Hop 2: Configure lossy and start config
|
tx_mgmt_pl.ops[7] = '{ // Hop 2: Configure lossy and start config
|
||||||
op_payload:{32'h47, sep_a.REG_OSTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd1}; // Swap 32-bit words, endianness, lossy and reset
|
op_payload:{32'h47, sep_a.REG_OSTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd1}; // Swap 32-bit words, endianness, lossy and reset
|
||||||
tx_mgmt_pl.ops[8] = '{ // Hop 2: Stream Endpoint: Return
|
tx_mgmt_pl.ops[8] = '{ // Hop 2: Stream Endpoint: Return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
||||||
tx_mgmt_pl.ops[9] = '{ // Hop 3: Nop for return
|
tx_mgmt_pl.ops[9] = '{ // Hop 3: Nop for return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
||||||
@@ -818,7 +824,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
op_payload:{32'h0, sep_a.REG_OSTRM_DATA_ERR_CNT}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd2};
|
op_payload:{32'h0, sep_a.REG_OSTRM_DATA_ERR_CNT}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd2};
|
||||||
tx_mgmt_pl.ops[7] = '{ // Hop 2: Read status
|
tx_mgmt_pl.ops[7] = '{ // Hop 2: Read status
|
||||||
op_payload:{32'h0, sep_a.REG_OSTRM_ROUTE_ERR_CNT}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd1};
|
op_payload:{32'h0, sep_a.REG_OSTRM_ROUTE_ERR_CNT}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd1};
|
||||||
tx_mgmt_pl.ops[8] = '{ // Hop 2: Stream Endpoint: Return
|
tx_mgmt_pl.ops[8] = '{ // Hop 2: Stream Endpoint: Return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
||||||
tx_mgmt_pl.ops[9] = '{ // Hop 3: Nop for return
|
tx_mgmt_pl.ops[9] = '{ // Hop 3: Nop for return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
||||||
@@ -859,7 +865,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
cached_ctrl_seqnum = 0;
|
cached_ctrl_seqnum = 0;
|
||||||
for (int cfg = 0; cfg < 2; cfg++) begin
|
for (int cfg = 0; cfg < 2; cfg++) begin
|
||||||
$sformat(tc_label, "Control Xact to A (%s)", (cfg?"Slow":"Fast"));
|
$sformat(tc_label, "Control Xact to A (%s)", (cfg?"Slow":"Fast"));
|
||||||
test.start_test(tc_label);
|
test.start_test({TEST_NAME,tc_label});
|
||||||
begin
|
begin
|
||||||
tb_chdr_bfm.set_master_stall_prob(cfg?SLOW_STALL_PROB:FAST_STALL_PROB);
|
tb_chdr_bfm.set_master_stall_prob(cfg?SLOW_STALL_PROB:FAST_STALL_PROB);
|
||||||
tb_chdr_bfm.set_slave_stall_prob(cfg?SLOW_STALL_PROB:FAST_STALL_PROB);
|
tb_chdr_bfm.set_slave_stall_prob(cfg?SLOW_STALL_PROB:FAST_STALL_PROB);
|
||||||
@@ -874,7 +880,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
cached_ctrl_seqnum = 0;
|
cached_ctrl_seqnum = 0;
|
||||||
for (int cfg = 0; cfg < 2; cfg++) begin
|
for (int cfg = 0; cfg < 2; cfg++) begin
|
||||||
$sformat(tc_label, "Control Xact to B (%s)", (cfg?"Slow":"Fast"));
|
$sformat(tc_label, "Control Xact to B (%s)", (cfg?"Slow":"Fast"));
|
||||||
test.start_test(tc_label);
|
test.start_test({TEST_NAME,tc_label});
|
||||||
begin
|
begin
|
||||||
tb_chdr_bfm.set_master_stall_prob(cfg?SLOW_STALL_PROB:FAST_STALL_PROB);
|
tb_chdr_bfm.set_master_stall_prob(cfg?SLOW_STALL_PROB:FAST_STALL_PROB);
|
||||||
tb_chdr_bfm.set_slave_stall_prob(cfg?SLOW_STALL_PROB:FAST_STALL_PROB);
|
tb_chdr_bfm.set_slave_stall_prob(cfg?SLOW_STALL_PROB:FAST_STALL_PROB);
|
||||||
@@ -892,7 +898,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
automatic logic slv_cfg = cfg[1];
|
automatic logic slv_cfg = cfg[1];
|
||||||
$sformat(tc_label, "Stream Data from A to B (%s Mst, %s Slv)",
|
$sformat(tc_label, "Stream Data from A to B (%s Mst, %s Slv)",
|
||||||
(mst_cfg?"Slow":"Fast"), (slv_cfg?"Slow":"Fast"));
|
(mst_cfg?"Slow":"Fast"), (slv_cfg?"Slow":"Fast"));
|
||||||
test.start_test(tc_label);
|
test.start_test({TEST_NAME,tc_label});
|
||||||
begin
|
begin
|
||||||
set_unidir_stall_prob(EPID_A, EPID_B,
|
set_unidir_stall_prob(EPID_A, EPID_B,
|
||||||
mst_cfg?SLOW_STALL_PROB:FAST_STALL_PROB,
|
mst_cfg?SLOW_STALL_PROB:FAST_STALL_PROB,
|
||||||
@@ -911,7 +917,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
automatic logic slv_cfg = cfg[1];
|
automatic logic slv_cfg = cfg[1];
|
||||||
$sformat(tc_label, "Stream Data from B to A (%s Mst, %s Slv)",
|
$sformat(tc_label, "Stream Data from B to A (%s Mst, %s Slv)",
|
||||||
(mst_cfg?"Slow":"Fast"), (slv_cfg?"Slow":"Fast"));
|
(mst_cfg?"Slow":"Fast"), (slv_cfg?"Slow":"Fast"));
|
||||||
test.start_test(tc_label);
|
test.start_test({TEST_NAME,tc_label});
|
||||||
begin
|
begin
|
||||||
set_unidir_stall_prob(EPID_B, EPID_A,
|
set_unidir_stall_prob(EPID_B, EPID_A,
|
||||||
mst_cfg?SLOW_STALL_PROB:FAST_STALL_PROB,
|
mst_cfg?SLOW_STALL_PROB:FAST_STALL_PROB,
|
||||||
@@ -929,7 +935,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
automatic logic slv_cfg = cfg[1];
|
automatic logic slv_cfg = cfg[1];
|
||||||
$sformat(tc_label, "Stream Data between A <=> B simultaneously (%s Mst, %s Slv)",
|
$sformat(tc_label, "Stream Data between A <=> B simultaneously (%s Mst, %s Slv)",
|
||||||
(mst_cfg?"Slow":"Fast"), (slv_cfg?"Slow":"Fast"));
|
(mst_cfg?"Slow":"Fast"), (slv_cfg?"Slow":"Fast"));
|
||||||
test.start_test(tc_label);
|
test.start_test({TEST_NAME,tc_label});
|
||||||
begin
|
begin
|
||||||
set_bidir_stall_prob(
|
set_bidir_stall_prob(
|
||||||
mst_cfg?SLOW_STALL_PROB:FAST_STALL_PROB,
|
mst_cfg?SLOW_STALL_PROB:FAST_STALL_PROB,
|
||||||
@@ -950,7 +956,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
automatic logic slv_cfg = cfg[1];
|
automatic logic slv_cfg = cfg[1];
|
||||||
$sformat(tc_label, "Stream Data and Control between A <=> B (%s Mst, %s Slv)",
|
$sformat(tc_label, "Stream Data and Control between A <=> B (%s Mst, %s Slv)",
|
||||||
(mst_cfg?"Slow":"Fast"), (slv_cfg?"Slow":"Fast"));
|
(mst_cfg?"Slow":"Fast"), (slv_cfg?"Slow":"Fast"));
|
||||||
test.start_test(tc_label);
|
test.start_test({TEST_NAME,tc_label});
|
||||||
begin
|
begin
|
||||||
tb_chdr_bfm.set_master_stall_prob(mst_cfg?SLOW_STALL_PROB:FAST_STALL_PROB);
|
tb_chdr_bfm.set_master_stall_prob(mst_cfg?SLOW_STALL_PROB:FAST_STALL_PROB);
|
||||||
tb_chdr_bfm.set_slave_stall_prob(slv_cfg?SLOW_STALL_PROB:FAST_STALL_PROB);
|
tb_chdr_bfm.set_slave_stall_prob(slv_cfg?SLOW_STALL_PROB:FAST_STALL_PROB);
|
||||||
@@ -976,9 +982,9 @@ module chdr_stream_endpoint_tb;
|
|||||||
|
|
||||||
// Check zero sequence errors after streaming
|
// Check zero sequence errors after streaming
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
test.start_test("Check zero sequence errors after streaming");
|
test.start_test({TEST_NAME,"Check zero sequence errors after streaming"});
|
||||||
begin
|
begin
|
||||||
logic [15:0] epids[2] = {EPID_A, EPID_B};
|
automatic logic [15:0] epids[2] = {EPID_A, EPID_B};
|
||||||
foreach (epids[i]) begin
|
foreach (epids[i]) begin
|
||||||
mgmt_read_err_counts(epids[i], seq_err_count, route_err_count, data_err_count);
|
mgmt_read_err_counts(epids[i], seq_err_count, route_err_count, data_err_count);
|
||||||
`ASSERT_ERROR(seq_err_count == 32'd0, "Check NoErrs: Incorrect seq error count");
|
`ASSERT_ERROR(seq_err_count == 32'd0, "Check NoErrs: Incorrect seq error count");
|
||||||
@@ -988,9 +994,13 @@ module chdr_stream_endpoint_tb;
|
|||||||
end
|
end
|
||||||
test.end_test();
|
test.end_test();
|
||||||
|
|
||||||
|
|
||||||
// Force sequence error
|
// Force sequence error
|
||||||
|
// Note: Occasional StreamCommand to resynch occur, which
|
||||||
|
// can cause the count to be greater than just the number data packets
|
||||||
|
// that are sent, so the comparisons are to > instead of ==
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
test.start_test("Force sequence error");
|
test.start_test({TEST_NAME,"Force sequence error"});
|
||||||
begin
|
begin
|
||||||
// First sequence error
|
// First sequence error
|
||||||
send_recv_data_packets(EPID_A, EPID_B, 1, cached_data_seqnum++, 1);
|
send_recv_data_packets(EPID_A, EPID_B, 1, cached_data_seqnum++, 1);
|
||||||
@@ -999,7 +1009,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
b_seqerr_prob = 0;
|
b_seqerr_prob = 0;
|
||||||
repeat (100) @(posedge rfnoc_chdr_clk); // Wait for sequence error to reach the upstream port
|
repeat (100) @(posedge rfnoc_chdr_clk); // Wait for sequence error to reach the upstream port
|
||||||
mgmt_read_err_counts(EPID_A, seq_err_count, route_err_count, data_err_count);
|
mgmt_read_err_counts(EPID_A, seq_err_count, route_err_count, data_err_count);
|
||||||
`ASSERT_ERROR(seq_err_count == 32'd1, "Force SeqErr: Incorrect seq error count");
|
`ASSERT_ERROR(seq_err_count > 32'd0, "Force SeqErr: Incorrect seq error count");
|
||||||
`ASSERT_ERROR(route_err_count == 32'd0, "Force SeqErr: Incorrect route error count");
|
`ASSERT_ERROR(route_err_count == 32'd0, "Force SeqErr: Incorrect route error count");
|
||||||
`ASSERT_ERROR(data_err_count == 32'd0, "Force SeqErr: Incorrect data error count");
|
`ASSERT_ERROR(data_err_count == 32'd0, "Force SeqErr: Incorrect data error count");
|
||||||
|
|
||||||
@@ -1010,7 +1020,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
b_seqerr_prob = 0;
|
b_seqerr_prob = 0;
|
||||||
repeat (100) @(posedge rfnoc_chdr_clk); // Wait for sequence error to reach the upstream port
|
repeat (100) @(posedge rfnoc_chdr_clk); // Wait for sequence error to reach the upstream port
|
||||||
mgmt_read_err_counts(EPID_A, seq_err_count, route_err_count, data_err_count);
|
mgmt_read_err_counts(EPID_A, seq_err_count, route_err_count, data_err_count);
|
||||||
`ASSERT_ERROR(seq_err_count > 32'd1, "Force SeqErr: Incorrect seq error count");
|
`ASSERT_ERROR(seq_err_count > 32'd2, "Force SeqErr: Incorrect seq error count");
|
||||||
`ASSERT_ERROR(route_err_count == 32'd0, "Force SeqErr: Incorrect route error count");
|
`ASSERT_ERROR(route_err_count == 32'd0, "Force SeqErr: Incorrect route error count");
|
||||||
`ASSERT_ERROR(data_err_count == 32'd0, "Force SeqErr: Incorrect data error count");
|
`ASSERT_ERROR(data_err_count == 32'd0, "Force SeqErr: Incorrect data error count");
|
||||||
end
|
end
|
||||||
@@ -1018,7 +1028,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
|
|
||||||
// Force routing error
|
// Force routing error
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
test.start_test("Force routing error");
|
test.start_test({TEST_NAME,"Force routing error"});
|
||||||
begin
|
begin
|
||||||
logic [31:0] old_route_err_count;
|
logic [31:0] old_route_err_count;
|
||||||
// First sequence error
|
// First sequence error
|
||||||
@@ -1048,13 +1058,13 @@ module chdr_stream_endpoint_tb;
|
|||||||
|
|
||||||
// Setup a stream between Endpoint A and B
|
// Setup a stream between Endpoint A and B
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
test.start_test("Reconfigure flow control (reset state)");
|
test.start_test({TEST_NAME,"Reconfigure flow control (reset state)"});
|
||||||
begin
|
begin
|
||||||
automatic chdr_header_t tx_mgmt_hdr, rx_mgmt_hdr;
|
automatic chdr_header_t tx_mgmt_hdr, rx_mgmt_hdr;
|
||||||
automatic chdr_mgmt_t tx_mgmt_pl, rx_mgmt_pl;
|
automatic chdr_mgmt_t tx_mgmt_pl, rx_mgmt_pl;
|
||||||
automatic chdr_mgmt_op_t exp_mgmt_op;
|
automatic chdr_mgmt_op_t exp_mgmt_op;
|
||||||
|
|
||||||
logic [15:0] epids[2] = {EPID_A, EPID_B};
|
automatic logic [15:0] epids[2] = {EPID_A, EPID_B};
|
||||||
foreach (epids[i]) begin
|
foreach (epids[i]) begin
|
||||||
// Generic management header
|
// Generic management header
|
||||||
tx_mgmt_pl.header = '{
|
tx_mgmt_pl.header = '{
|
||||||
@@ -1070,7 +1080,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
op_payload:{32'd0, sep_a.REG_ISTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd2};
|
op_payload:{32'd0, sep_a.REG_ISTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd2};
|
||||||
tx_mgmt_pl.ops[2] = '{ // Hop 2: Configure lossy and start config
|
tx_mgmt_pl.ops[2] = '{ // Hop 2: Configure lossy and start config
|
||||||
op_payload:{32'd3, sep_a.REG_OSTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd1};
|
op_payload:{32'd3, sep_a.REG_OSTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd1};
|
||||||
tx_mgmt_pl.ops[3] = '{ // Hop 2: Stream Endpoint: Return
|
tx_mgmt_pl.ops[3] = '{ // Hop 2: Stream Endpoint: Return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
||||||
tx_mgmt_pl.ops[4] = '{ // Hop 3: Nop for return
|
tx_mgmt_pl.ops[4] = '{ // Hop 3: Nop for return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
||||||
@@ -1092,7 +1102,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
||||||
tx_mgmt_pl.ops[1] = '{ // Hop 2: Read status
|
tx_mgmt_pl.ops[1] = '{ // Hop 2: Read status
|
||||||
op_payload:{32'h0, sep_a.REG_OSTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd1};
|
op_payload:{32'h0, sep_a.REG_OSTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd1};
|
||||||
tx_mgmt_pl.ops[2] = '{ // Hop 2: Stream Endpoint: Return
|
tx_mgmt_pl.ops[2] = '{ // Hop 2: Stream Endpoint: Return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0};
|
||||||
tx_mgmt_pl.ops[3] = '{ // Hop 3: Nop for return
|
tx_mgmt_pl.ops[3] = '{ // Hop 3: Nop for return
|
||||||
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0};
|
||||||
@@ -1112,9 +1122,9 @@ module chdr_stream_endpoint_tb;
|
|||||||
|
|
||||||
// Check zero errors after reinit
|
// Check zero errors after reinit
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
test.start_test("Check zero errors after reinit");
|
test.start_test({TEST_NAME,"Check zero errors after reinit"});
|
||||||
begin
|
begin
|
||||||
logic [15:0] epids[2] = {EPID_A, EPID_B};
|
automatic logic [15:0] epids[2] = {EPID_A, EPID_B};
|
||||||
foreach (epids[i]) begin
|
foreach (epids[i]) begin
|
||||||
mgmt_read_err_counts(epids[i], seq_err_count, route_err_count, data_err_count);
|
mgmt_read_err_counts(epids[i], seq_err_count, route_err_count, data_err_count);
|
||||||
`ASSERT_ERROR(seq_err_count == 32'd0, "Check NoErrs: Incorrect seq error count");
|
`ASSERT_ERROR(seq_err_count == 32'd0, "Check NoErrs: Incorrect seq error count");
|
||||||
@@ -1126,7 +1136,7 @@ module chdr_stream_endpoint_tb;
|
|||||||
|
|
||||||
// Stream data between A <=> B simultaneously
|
// Stream data between A <=> B simultaneously
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
test.start_test("Stream Data between A <=> B with a lossy link");
|
test.start_test({TEST_NAME,"Stream Data between A <=> B with a lossy link"});
|
||||||
begin
|
begin
|
||||||
cached_data_seqnum = 0;
|
cached_data_seqnum = 0;
|
||||||
set_bidir_stall_prob(FAST_STALL_PROB, SLOW_STALL_PROB);
|
set_bidir_stall_prob(FAST_STALL_PROB, SLOW_STALL_PROB);
|
||||||
@@ -1145,7 +1155,8 @@ module chdr_stream_endpoint_tb;
|
|||||||
// Finish Up
|
// Finish Up
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
// Display final statistics and results
|
// Display final statistics and results
|
||||||
test.end_tb();
|
test.end_tb(.finish(0));
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
`default_nettype wire
|
||||||
+223
-183
@@ -1,16 +1,15 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2019 Ettus Research, A National Instruments Company
|
// Copyright 2020 Ettus Research, A National Instruments Brand
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
//
|
//
|
||||||
// Module: PkgChdrBfm
|
// Module: PkgChdrBfm
|
||||||
//
|
//
|
||||||
// Description: Package for a bi-directional CHDR bus functional model (BFM),
|
// Description: Package for a bi-directional CHDR bus functional model (BFM),
|
||||||
// which consists primarily of the ChdrPacket and ChdrBfm classes.
|
// which consists primarily of the ChdrPacket and ChdrBfm classes.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package PkgChdrBfm;
|
package PkgChdrBfm;
|
||||||
|
|
||||||
import PkgChdrUtils::*;
|
import PkgChdrUtils::*;
|
||||||
@@ -21,10 +20,13 @@ package PkgChdrBfm;
|
|||||||
// CHDR Packet Class
|
// CHDR Packet Class
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
class ChdrPacket #(int CHDR_W = 64);
|
class ChdrPacket #(parameter int CHDR_W = 64,
|
||||||
|
parameter int USER_WIDTH = 1);
|
||||||
|
|
||||||
typedef ChdrPacket #(CHDR_W) ChdrPacket_t;
|
typedef ChdrPacket #(CHDR_W,USER_WIDTH) ChdrPacket_t;
|
||||||
|
typedef AxiStreamPacket #(CHDR_W, USER_WIDTH) AxisPacket_t;
|
||||||
typedef ChdrData #(CHDR_W)::chdr_word_t chdr_word_t;
|
typedef ChdrData #(CHDR_W)::chdr_word_t chdr_word_t;
|
||||||
|
typedef AxisPacket_t::data_t data_t;
|
||||||
|
|
||||||
const int BYTES_PER_CHDR_W = CHDR_W / 8;
|
const int BYTES_PER_CHDR_W = CHDR_W / 8;
|
||||||
|
|
||||||
@@ -33,6 +35,8 @@ package PkgChdrBfm;
|
|||||||
chdr_word_t metadata[$];
|
chdr_word_t metadata[$];
|
||||||
chdr_word_t data[$];
|
chdr_word_t data[$];
|
||||||
|
|
||||||
|
bit disable_comparing_beyond_length = 1;
|
||||||
|
|
||||||
extern function ChdrPacket_t copy();
|
extern function ChdrPacket_t copy();
|
||||||
extern function bit equal(ChdrPacket_t packet);
|
extern function bit equal(ChdrPacket_t packet);
|
||||||
extern function string sprint(bit pretty = 1);
|
extern function string sprint(bit pretty = 1);
|
||||||
@@ -44,22 +48,22 @@ package PkgChdrBfm;
|
|||||||
input chdr_word_t metadata[$] = {},
|
input chdr_word_t metadata[$] = {},
|
||||||
input chdr_timestamp_t timestamp = 0,
|
input chdr_timestamp_t timestamp = 0,
|
||||||
input int data_byte_length = -1);
|
input int data_byte_length = -1);
|
||||||
extern function void read_raw (output chdr_header_t header,
|
extern function void read_raw (output chdr_header_t header,
|
||||||
output chdr_word_t data[$],
|
output chdr_word_t data[$],
|
||||||
output chdr_word_t metadata[$],
|
output chdr_word_t metadata[$],
|
||||||
output chdr_timestamp_t timestamp,
|
output chdr_timestamp_t timestamp,
|
||||||
output int data_byte_length);
|
output int data_byte_length);
|
||||||
extern function void write_stream_status(ref chdr_header_t header,
|
extern function void write_stream_status(ref chdr_header_t header,
|
||||||
ref chdr_str_status_t status);
|
ref chdr_str_status_t status);
|
||||||
extern function void read_stream_status (output chdr_header_t header,
|
extern function void read_stream_status (output chdr_header_t header,
|
||||||
output chdr_str_status_t status);
|
output chdr_str_status_t status);
|
||||||
extern function void write_stream_cmd (ref chdr_header_t header,
|
extern function void write_stream_cmd (ref chdr_header_t header,
|
||||||
ref chdr_str_command_t command);
|
ref chdr_str_command_t command);
|
||||||
extern function void read_stream_cmd (output chdr_header_t header,
|
extern function void read_stream_cmd (output chdr_header_t header,
|
||||||
output chdr_str_command_t command);
|
output chdr_str_command_t command);
|
||||||
extern function void write_mgmt (ref chdr_header_t header,
|
extern function void write_mgmt (ref chdr_header_t header,
|
||||||
ref chdr_mgmt_t mgmt);
|
ref chdr_mgmt_t mgmt);
|
||||||
extern function void read_mgmt (output chdr_header_t header,
|
extern function void read_mgmt (output chdr_header_t header,
|
||||||
output chdr_mgmt_t mgmt);
|
output chdr_mgmt_t mgmt);
|
||||||
extern function void write_ctrl (ref chdr_header_t header,
|
extern function void write_ctrl (ref chdr_header_t header,
|
||||||
ref chdr_ctrl_header_t ctrl_header,
|
ref chdr_ctrl_header_t ctrl_header,
|
||||||
@@ -72,17 +76,22 @@ package PkgChdrBfm;
|
|||||||
output ctrl_word_t ctrl_data[$],
|
output ctrl_word_t ctrl_data[$],
|
||||||
output chdr_timestamp_t ctrl_timestamp);
|
output chdr_timestamp_t ctrl_timestamp);
|
||||||
|
|
||||||
|
|
||||||
// Helper methods
|
// Helper methods
|
||||||
extern function int header_bytes();
|
extern function int header_bytes();
|
||||||
extern function int mdata_bytes();
|
extern function int mdata_bytes();
|
||||||
extern function int data_bytes();
|
extern function int data_bytes();
|
||||||
extern function void update_lengths();
|
extern function void update_lengths(int payload_bytes = 0);
|
||||||
|
|
||||||
extern function string sprint_raw();
|
extern function string sprint_raw();
|
||||||
extern function string sprint_pretty();
|
extern function string sprint_pretty();
|
||||||
|
|
||||||
extern function bit chdr_word_queues_equal(ref chdr_word_t a[$], ref chdr_word_t b[$]);
|
extern function bit chdr_word_queues_equal(ref chdr_word_t a[$],
|
||||||
|
ref chdr_word_t b[$],
|
||||||
|
input int data_byte_length = -1);
|
||||||
|
|
||||||
|
// AXI-Stream/CHDR Conversion Functions
|
||||||
|
extern function void axis_to_chdr (AxisPacket_t axis_packet);
|
||||||
|
extern function AxisPacket_t chdr_to_axis ();
|
||||||
|
|
||||||
endclass : ChdrPacket;
|
endclass : ChdrPacket;
|
||||||
|
|
||||||
@@ -123,12 +132,6 @@ package PkgChdrBfm;
|
|||||||
extern function bit try_get_chdr(output ChdrPacket_t chdr_packet);
|
extern function bit try_get_chdr(output ChdrPacket_t chdr_packet);
|
||||||
extern task peek_chdr(output ChdrPacket_t chdr_packet);
|
extern task peek_chdr(output ChdrPacket_t chdr_packet);
|
||||||
extern function bit try_peek_chdr(output ChdrPacket_t chdr_packet);
|
extern function bit try_peek_chdr(output ChdrPacket_t chdr_packet);
|
||||||
|
|
||||||
|
|
||||||
// AXI-Stream/CHDR Conversion Functions
|
|
||||||
extern function ChdrPacket_t axis_to_chdr (AxisPacket_t axis_packet);
|
|
||||||
extern function AxisPacket_t chdr_to_axis (ChdrPacket_t chdr_packet);
|
|
||||||
|
|
||||||
endclass : ChdrBfm
|
endclass : ChdrBfm
|
||||||
|
|
||||||
|
|
||||||
@@ -151,8 +154,17 @@ package PkgChdrBfm;
|
|||||||
|
|
||||||
// Return true if this packet equals that of the argument
|
// Return true if this packet equals that of the argument
|
||||||
function bit ChdrPacket::equal(ChdrPacket_t packet);
|
function bit ChdrPacket::equal(ChdrPacket_t packet);
|
||||||
|
int payload_length;
|
||||||
|
payload_length = header.length;
|
||||||
|
payload_length -= BYTES_PER_CHDR_W; // subtract header bytes
|
||||||
|
if (CHDR_W == 64) begin // subtract TS bytes if not in header word
|
||||||
|
if (header.pkt_type == CHDR_DATA_WITH_TS) begin
|
||||||
|
payload_length -= BYTES_PER_CHDR_W;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
payload_length -= packet.metadata.size() * BYTES_PER_CHDR_W; // subtract metadata length
|
||||||
if (header != packet.header) return 0;
|
if (header != packet.header) return 0;
|
||||||
if (!chdr_word_queues_equal(data, packet.data)) return 0;
|
if (!chdr_word_queues_equal(data, packet.data,payload_length)) return 0;
|
||||||
if (!chdr_word_queues_equal(metadata, packet.metadata)) return 0;
|
if (!chdr_word_queues_equal(metadata, packet.metadata)) return 0;
|
||||||
if (header.pkt_type == CHDR_DATA_WITH_TS && timestamp !== packet.timestamp) return 0;
|
if (header.pkt_type == CHDR_DATA_WITH_TS && timestamp !== packet.timestamp) return 0;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -176,6 +188,7 @@ package PkgChdrBfm;
|
|||||||
return str;
|
return str;
|
||||||
endfunction : sprint_raw
|
endfunction : sprint_raw
|
||||||
|
|
||||||
|
|
||||||
// Format the contents of the packet into a string (dissect contents)
|
// Format the contents of the packet into a string (dissect contents)
|
||||||
function string ChdrPacket::sprint_pretty();
|
function string ChdrPacket::sprint_pretty();
|
||||||
string str;
|
string str;
|
||||||
@@ -236,6 +249,7 @@ package PkgChdrBfm;
|
|||||||
return str;
|
return str;
|
||||||
endfunction : sprint_pretty
|
endfunction : sprint_pretty
|
||||||
|
|
||||||
|
|
||||||
function string ChdrPacket::sprint(bit pretty = 1);
|
function string ChdrPacket::sprint(bit pretty = 1);
|
||||||
if (pretty)
|
if (pretty)
|
||||||
return sprint_pretty();
|
return sprint_pretty();
|
||||||
@@ -243,6 +257,7 @@ package PkgChdrBfm;
|
|||||||
return sprint_raw();
|
return sprint_raw();
|
||||||
endfunction: sprint
|
endfunction: sprint
|
||||||
|
|
||||||
|
|
||||||
// Print the contents of the packet
|
// Print the contents of the packet
|
||||||
function void ChdrPacket::print(bit pretty = 1);
|
function void ChdrPacket::print(bit pretty = 1);
|
||||||
$display(sprint(pretty));
|
$display(sprint(pretty));
|
||||||
@@ -284,7 +299,7 @@ package PkgChdrBfm;
|
|||||||
|
|
||||||
// Read the contents of this packet
|
// Read the contents of this packet
|
||||||
function void ChdrPacket::read_raw (
|
function void ChdrPacket::read_raw (
|
||||||
output chdr_header_t header,
|
output chdr_header_t header,
|
||||||
output chdr_word_t data[$],
|
output chdr_word_t data[$],
|
||||||
output chdr_word_t metadata[$],
|
output chdr_word_t metadata[$],
|
||||||
output chdr_timestamp_t timestamp,
|
output chdr_timestamp_t timestamp,
|
||||||
@@ -315,7 +330,7 @@ package PkgChdrBfm;
|
|||||||
|
|
||||||
// Read this packet as a status packet
|
// Read this packet as a status packet
|
||||||
function void ChdrPacket::read_stream_status (
|
function void ChdrPacket::read_stream_status (
|
||||||
output chdr_header_t header,
|
output chdr_header_t header,
|
||||||
output chdr_str_status_t status
|
output chdr_str_status_t status
|
||||||
);
|
);
|
||||||
// Make sure it's a stream status packet
|
// Make sure it's a stream status packet
|
||||||
@@ -383,7 +398,7 @@ package PkgChdrBfm;
|
|||||||
|
|
||||||
// Insert the header
|
// Insert the header
|
||||||
data.push_back( mgmt.header );
|
data.push_back( mgmt.header );
|
||||||
|
|
||||||
// Insert the ops
|
// Insert the ops
|
||||||
foreach (mgmt.ops[i]) begin
|
foreach (mgmt.ops[i]) begin
|
||||||
data.push_back( mgmt.ops[i] );
|
data.push_back( mgmt.ops[i] );
|
||||||
@@ -433,6 +448,7 @@ package PkgChdrBfm;
|
|||||||
input chdr_timestamp_t ctrl_timestamp = 0
|
input chdr_timestamp_t ctrl_timestamp = 0
|
||||||
);
|
);
|
||||||
bit partial_word;
|
bit partial_word;
|
||||||
|
int byte_count = 0;
|
||||||
ctrl_word_t mandatory_data;
|
ctrl_word_t mandatory_data;
|
||||||
ChdrData #(CHDR_W, 64)::item_queue_t data64;
|
ChdrData #(CHDR_W, 64)::item_queue_t data64;
|
||||||
|
|
||||||
@@ -442,10 +458,12 @@ package PkgChdrBfm;
|
|||||||
|
|
||||||
// Insert word 0 of control payload
|
// Insert word 0 of control payload
|
||||||
data64.push_back(ctrl_header);
|
data64.push_back(ctrl_header);
|
||||||
|
byte_count+=8;
|
||||||
|
|
||||||
// Insert word 1 of control payload, if timestamp is used
|
// Insert word 1 of control payload, if timestamp is used
|
||||||
if (ctrl_header.has_time) begin
|
if (ctrl_header.has_time) begin
|
||||||
data64.push_back(ctrl_timestamp);
|
data64.push_back(ctrl_timestamp);
|
||||||
|
byte_count+=8;
|
||||||
end
|
end
|
||||||
|
|
||||||
// Make sure the amount of data passed matches the header
|
// Make sure the amount of data passed matches the header
|
||||||
@@ -457,6 +475,7 @@ package PkgChdrBfm;
|
|||||||
// and first word of control data.
|
// and first word of control data.
|
||||||
mandatory_data = (ctrl_header.num_data > 0) ? ctrl_data[0] : '0;
|
mandatory_data = (ctrl_header.num_data > 0) ? ctrl_data[0] : '0;
|
||||||
data64.push_back({mandatory_data, ctrl_op_word[31:0]});
|
data64.push_back({mandatory_data, ctrl_op_word[31:0]});
|
||||||
|
byte_count+=8;
|
||||||
// We have a half CHDR word if num_data is even
|
// We have a half CHDR word if num_data is even
|
||||||
partial_word = (ctrl_header.num_data[0] == '0);
|
partial_word = (ctrl_header.num_data[0] == '0);
|
||||||
|
|
||||||
@@ -465,15 +484,17 @@ package PkgChdrBfm;
|
|||||||
if (i == ctrl_data.size()-1) begin
|
if (i == ctrl_data.size()-1) begin
|
||||||
// num_data must be even in this case, so last word is half filled
|
// num_data must be even in this case, so last word is half filled
|
||||||
data64.push_back({ 32'b0, ctrl_data[i] });
|
data64.push_back({ 32'b0, ctrl_data[i] });
|
||||||
|
byte_count+=4;
|
||||||
end else begin
|
end else begin
|
||||||
data64.push_back({ ctrl_data[i+1], ctrl_data[i] });
|
data64.push_back({ ctrl_data[i+1], ctrl_data[i] });
|
||||||
|
byte_count+=8;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
// Convert from 64-bit words to CHDR_W-bit words
|
// Convert from 64-bit words to CHDR_W-bit words
|
||||||
data = ChdrData #(CHDR_W, 64)::item_to_chdr(data64);
|
data = ChdrData #(CHDR_W, 64)::item_to_chdr(data64);
|
||||||
|
|
||||||
update_lengths();
|
update_lengths(.payload_bytes(byte_count));
|
||||||
endfunction : write_ctrl
|
endfunction : write_ctrl
|
||||||
|
|
||||||
|
|
||||||
@@ -530,7 +551,6 @@ package PkgChdrBfm;
|
|||||||
while (dptr < data32.size()) begin
|
while (dptr < data32.size()) begin
|
||||||
ctrl_data.push_back(data32[dptr++]);
|
ctrl_data.push_back(data32[dptr++]);
|
||||||
end
|
end
|
||||||
|
|
||||||
endfunction : read_ctrl
|
endfunction : read_ctrl
|
||||||
|
|
||||||
|
|
||||||
@@ -557,21 +577,30 @@ package PkgChdrBfm;
|
|||||||
endfunction : data_bytes;
|
endfunction : data_bytes;
|
||||||
|
|
||||||
|
|
||||||
// Update the length and num_mdata header fields of the packet based on the
|
// Update the length and num_mdata header fields of the packet based on the
|
||||||
// size of the metadata queue and the data queue.
|
// size of the metadata queue and the data queue.
|
||||||
function void ChdrPacket::update_lengths();
|
function void ChdrPacket::update_lengths(int payload_bytes = 0);
|
||||||
int num_bytes;
|
int num_bytes;
|
||||||
int num_mdata;
|
int num_mdata;
|
||||||
|
int my_payload_bytes;
|
||||||
|
|
||||||
// Calculate NumMData based on the size of metadata queue
|
// Calculate NumMData based on the size of metadata queue
|
||||||
num_mdata = metadata.size();
|
num_mdata = metadata.size();
|
||||||
assert(num_mdata < 2**$bits(chdr_num_mdata_t)) else
|
assert(num_mdata < 2**$bits(chdr_num_mdata_t)) else
|
||||||
$fatal(1, "ChdrPacket::update_lengths(): Calculated NumMData exceeds maximum size");
|
$fatal(1, "ChdrPacket::update_lengths(): Calculated NumMData exceeds maximum size");
|
||||||
|
|
||||||
|
if (payload_bytes == 0) begin
|
||||||
|
// Calculate if optional argument not provided
|
||||||
|
my_payload_bytes = data.size() * BYTES_PER_CHDR_W;
|
||||||
|
end else begin
|
||||||
|
// Use optional argument if provided
|
||||||
|
my_payload_bytes = payload_bytes;
|
||||||
|
end
|
||||||
|
|
||||||
// Calculate the Length field
|
// Calculate the Length field
|
||||||
num_bytes = header_bytes() + // Header
|
num_bytes = header_bytes() + // Header
|
||||||
num_mdata * BYTES_PER_CHDR_W + // Metadata
|
num_mdata * BYTES_PER_CHDR_W + // Metadata
|
||||||
data.size() * BYTES_PER_CHDR_W; // Payload
|
my_payload_bytes; // Payload
|
||||||
assert(num_bytes < 2**$bits(chdr_length_t)) else
|
assert(num_bytes < 2**$bits(chdr_length_t)) else
|
||||||
$fatal(1, "ChdrPacket::update_lengths(): Calculated Length exceeds maximum size");
|
$fatal(1, "ChdrPacket::update_lengths(): Calculated Length exceeds maximum size");
|
||||||
|
|
||||||
@@ -581,28 +610,169 @@ package PkgChdrBfm;
|
|||||||
endfunction : update_lengths
|
endfunction : update_lengths
|
||||||
|
|
||||||
|
|
||||||
// Returns 1 if the queues have the same contents, otherwise returns 0. This
|
// Returns 1 if the queues have the same contents, up to the
|
||||||
// function is equivalent to (a == b), but this doesn't work correctly yet in
|
// data_byte_length, if present.
|
||||||
// Vivado 2018.3.
|
function automatic bit ChdrPacket::chdr_word_queues_equal(
|
||||||
function automatic bit ChdrPacket::chdr_word_queues_equal(ref chdr_word_t a[$], ref chdr_word_t b[$]);
|
ref chdr_word_t a[$],
|
||||||
|
ref chdr_word_t b[$],
|
||||||
|
input int data_byte_length = -1
|
||||||
|
);
|
||||||
chdr_word_t x, y;
|
chdr_word_t x, y;
|
||||||
|
int bytes_remaining = data_byte_length;
|
||||||
if (a.size() != b.size()) return 0;
|
if (a.size() != b.size()) return 0;
|
||||||
foreach (a[i]) begin
|
foreach (a[i]) begin
|
||||||
x = a[i];
|
x = a[i];
|
||||||
y = b[i];
|
y = b[i];
|
||||||
if (x !== y) return 0;
|
if(data_byte_length > 0 && // only if optional argument is valid
|
||||||
|
disable_comparing_beyond_length && // only if optional feature is enabled
|
||||||
|
bytes_remaining < BYTES_PER_CHDR_W) begin // only compare bytes on last word
|
||||||
|
for (int b = 0; b < bytes_remaining*8; b += 8) begin
|
||||||
|
if (x[b+:8] !== y[b+:8]) return 0;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
if (x !== y) return 0;
|
||||||
|
end
|
||||||
|
bytes_remaining -= BYTES_PER_CHDR_W;
|
||||||
end
|
end
|
||||||
return 1;
|
return 1;
|
||||||
endfunction : chdr_word_queues_equal
|
endfunction : chdr_word_queues_equal
|
||||||
|
|
||||||
|
|
||||||
|
// Convert the data payload of an AXI Stream packet data structure to a CHDR
|
||||||
|
// packet data structure.
|
||||||
|
function void ChdrPacket::axis_to_chdr (AxisPacket_t axis_packet);
|
||||||
|
enum int { ST_HEADER, ST_TIMESTAMP, ST_METADATA, ST_PAYLOAD } rx_state;
|
||||||
|
data_t word;
|
||||||
|
int num_rx_mdata;
|
||||||
|
int num_rx_bytes;
|
||||||
|
ChdrPacket_t chdr_packet = new();
|
||||||
|
|
||||||
|
rx_state = ST_HEADER;
|
||||||
|
|
||||||
|
for(int i = 0; i < axis_packet.data.size(); i++) begin
|
||||||
|
word = axis_packet.data[i];
|
||||||
|
|
||||||
|
case (rx_state)
|
||||||
|
ST_HEADER : begin
|
||||||
|
num_rx_bytes += BYTES_PER_CHDR_W;
|
||||||
|
header = word[63:0];
|
||||||
|
|
||||||
|
// Depending on the size of the word, we could have just the header
|
||||||
|
// or both the header and the timestamp in this word.
|
||||||
|
if (header.pkt_type == CHDR_DATA_WITH_TS) begin
|
||||||
|
if (CHDR_W >= 128) begin
|
||||||
|
timestamp = word[127:64];
|
||||||
|
rx_state = ST_METADATA;
|
||||||
|
end else begin
|
||||||
|
rx_state = ST_TIMESTAMP;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
rx_state = ST_METADATA;
|
||||||
|
end
|
||||||
|
|
||||||
|
// Check if there's no metadata, in which case we can skip it
|
||||||
|
if (rx_state == ST_METADATA && header.num_mdata == 0) begin
|
||||||
|
rx_state = ST_PAYLOAD;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ST_TIMESTAMP : begin
|
||||||
|
num_rx_bytes += BYTES_PER_CHDR_W;
|
||||||
|
timestamp = word;
|
||||||
|
rx_state = (header.num_mdata > 0) ? ST_METADATA : ST_PAYLOAD;
|
||||||
|
end
|
||||||
|
ST_METADATA : begin
|
||||||
|
metadata.push_back(word);
|
||||||
|
num_rx_mdata++;
|
||||||
|
num_rx_bytes += BYTES_PER_CHDR_W;
|
||||||
|
if (num_rx_mdata == header.num_mdata) rx_state = ST_PAYLOAD;
|
||||||
|
end
|
||||||
|
ST_PAYLOAD : begin
|
||||||
|
data.push_back(word);
|
||||||
|
num_rx_bytes += BYTES_PER_CHDR_W;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
assert (rx_state == ST_PAYLOAD) else begin
|
||||||
|
$error("ChdrPacket::axis_to_chdr: Malformed CHDR packet");
|
||||||
|
end
|
||||||
|
|
||||||
|
// Check length field, noting that the last word may be partially filled
|
||||||
|
assert (header.length >= num_rx_bytes-(BYTES_PER_CHDR_W-1) &&
|
||||||
|
header.length <= num_rx_bytes) else begin
|
||||||
|
$error("ChdrPacket::axis_to_chdr: Incorrect CHDR length");
|
||||||
|
end
|
||||||
|
endfunction : axis_to_chdr
|
||||||
|
|
||||||
|
|
||||||
|
// Convert a CHDR packet data structure to a an AXI-Stream packet data
|
||||||
|
// structure.
|
||||||
|
function ChdrPacket::AxisPacket_t ChdrPacket::chdr_to_axis ();
|
||||||
|
int num_words, expected_words;
|
||||||
|
data_t bus_word = 0;
|
||||||
|
AxisPacket_t axis_packet = new();
|
||||||
|
|
||||||
|
// Check that we have the right number of metadata words
|
||||||
|
assert (metadata.size() == header.num_mdata) else begin
|
||||||
|
$error("ChdrPacket::chdr_to_axis: Packet metadata size doesn't match header NumMData field");
|
||||||
|
end
|
||||||
|
|
||||||
|
// Calculate the number of words needed to represent this packet
|
||||||
|
num_words = data.size() + metadata.size();
|
||||||
|
if (header.pkt_type == CHDR_DATA_WITH_TS && CHDR_W == 64) begin
|
||||||
|
// Add two words, one for header and one for timestamp
|
||||||
|
num_words += 2;
|
||||||
|
end else begin
|
||||||
|
// Add one word only for header (which may or may not include a timestamp)
|
||||||
|
num_words += 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
// Calculate the number of words represented by the Length field
|
||||||
|
expected_words = header.length / BYTES_PER_CHDR_W;
|
||||||
|
if (header.length % BYTES_PER_CHDR_W != 0) expected_words++;
|
||||||
|
|
||||||
|
// Make sure length field matches actual packet length
|
||||||
|
assert (num_words == expected_words) else begin
|
||||||
|
$error("ChdrPacket::chdr_to_axis: Packet size doesn't match header Length field");
|
||||||
|
end
|
||||||
|
|
||||||
|
// Insert header
|
||||||
|
bus_word[63:0] = header;
|
||||||
|
if (CHDR_W == 64) begin
|
||||||
|
axis_packet.data.push_back(bus_word);
|
||||||
|
if (header.pkt_type == CHDR_DATA_WITH_TS) begin
|
||||||
|
// Insert timestamp
|
||||||
|
axis_packet.data.push_back(timestamp);
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
// Copy the timestamp word from the header, regardless of whether or not
|
||||||
|
// this packet uses the timestamp field.
|
||||||
|
bus_word[127:64] = timestamp;
|
||||||
|
axis_packet.data.push_back(bus_word);
|
||||||
|
end
|
||||||
|
|
||||||
|
// Insert metadata
|
||||||
|
foreach (metadata[i]) begin
|
||||||
|
bus_word = metadata[i];
|
||||||
|
axis_packet.data.push_back(bus_word);
|
||||||
|
end
|
||||||
|
|
||||||
|
// Insert payload
|
||||||
|
foreach (data[i]) begin
|
||||||
|
bus_word = data[i];
|
||||||
|
axis_packet.data.push_back(bus_word);
|
||||||
|
end
|
||||||
|
|
||||||
|
return axis_packet;
|
||||||
|
endfunction : chdr_to_axis
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// CHDR BFM Class Methods
|
// CHDR BFM Class Methods
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Class constructor. This must be given an interface for the master
|
||||||
// Class constructor. This must be given an interface for the master
|
|
||||||
// connection and an interface for the slave connection.
|
// connection and an interface for the slave connection.
|
||||||
function ChdrBfm::new (
|
function ChdrBfm::new (
|
||||||
virtual AxiStreamIf #(CHDR_W, USER_WIDTH).master master,
|
virtual AxiStreamIf #(CHDR_W, USER_WIDTH).master master,
|
||||||
@@ -614,195 +784,65 @@ package PkgChdrBfm;
|
|||||||
end
|
end
|
||||||
endfunction : new
|
endfunction : new
|
||||||
|
|
||||||
|
|
||||||
// Queue the provided packet for transmission
|
// Queue the provided packet for transmission
|
||||||
task ChdrBfm::put_chdr (ChdrPacket_t chdr_packet);
|
task ChdrBfm::put_chdr (ChdrPacket_t chdr_packet);
|
||||||
AxisPacket_t axis_packet;
|
AxisPacket_t axis_packet;
|
||||||
|
|
||||||
axis_packet = chdr_to_axis(chdr_packet);
|
axis_packet = chdr_packet.chdr_to_axis();
|
||||||
super.put(axis_packet);
|
super.put(axis_packet);
|
||||||
endtask : put_chdr
|
endtask : put_chdr
|
||||||
|
|
||||||
|
|
||||||
// Attempt to queue the provided packet for transmission. Return 1 if
|
// Attempt to queue the provided packet for transmission. Return 1 if
|
||||||
// successful, return 0 if the queue is full.
|
// successful, return 0 if the queue is full.
|
||||||
function bit ChdrBfm::try_put_chdr (ChdrPacket_t chdr_packet);
|
function bit ChdrBfm::try_put_chdr (ChdrPacket_t chdr_packet);
|
||||||
AxisPacket_t axis_packet;
|
AxisPacket_t axis_packet;
|
||||||
bit status;
|
bit status;
|
||||||
|
|
||||||
axis_packet = chdr_to_axis(chdr_packet);
|
axis_packet = chdr_packet.chdr_to_axis();
|
||||||
return super.try_put(axis_packet);
|
return super.try_put(axis_packet);
|
||||||
endfunction : try_put_chdr
|
endfunction : try_put_chdr
|
||||||
|
|
||||||
|
|
||||||
// Get the next packet when it becomes available (wait if necessary)
|
// Get the next packet when it becomes available (wait if necessary)
|
||||||
task ChdrBfm::get_chdr (output ChdrPacket_t chdr_packet);
|
task ChdrBfm::get_chdr (output ChdrPacket_t chdr_packet);
|
||||||
AxisPacket_t axis_packet;
|
AxisPacket_t axis_packet;
|
||||||
super.get(axis_packet);
|
super.get(axis_packet);
|
||||||
chdr_packet = axis_to_chdr(axis_packet);
|
chdr_packet = new();
|
||||||
|
chdr_packet.axis_to_chdr(axis_packet);
|
||||||
endtask : get_chdr
|
endtask : get_chdr
|
||||||
|
|
||||||
|
|
||||||
// Get the next packet if there's one available and return 1. Return 0 if
|
// Get the next packet if there's one available and return 1. Return 0 if
|
||||||
// there's no packet available.
|
// there's no packet available.
|
||||||
function bit ChdrBfm::try_get_chdr (output ChdrPacket_t chdr_packet);
|
function bit ChdrBfm::try_get_chdr (output ChdrPacket_t chdr_packet);
|
||||||
AxisPacket_t axis_packet;
|
AxisPacket_t axis_packet;
|
||||||
if (!super.try_get(axis_packet)) return 0;
|
if (!super.try_get(axis_packet)) return 0;
|
||||||
chdr_packet = axis_to_chdr(axis_packet);
|
chdr_packet = new();
|
||||||
|
chdr_packet.axis_to_chdr(axis_packet);
|
||||||
return 1;
|
return 1;
|
||||||
endfunction : try_get_chdr
|
endfunction : try_get_chdr
|
||||||
|
|
||||||
|
|
||||||
// Get the next packet when it becomes available (wait if necessary), but
|
// Get the next packet when it becomes available (wait if necessary), but
|
||||||
// don't remove it from the receive queue.
|
// don't remove it from the receive queue.
|
||||||
task ChdrBfm::peek_chdr (output ChdrPacket_t chdr_packet);
|
task ChdrBfm::peek_chdr (output ChdrPacket_t chdr_packet);
|
||||||
AxisPacket_t axis_packet;
|
AxisPacket_t axis_packet;
|
||||||
super.peek(axis_packet);
|
super.peek(axis_packet);
|
||||||
chdr_packet = axis_to_chdr(axis_packet);
|
chdr_packet = new();
|
||||||
|
chdr_packet.axis_to_chdr(axis_packet);
|
||||||
endtask : peek_chdr
|
endtask : peek_chdr
|
||||||
|
|
||||||
|
|
||||||
// Get the next packet if there's one available and return 1, but don't
|
// Get the next packet if there's one available and return 1, but don't
|
||||||
// remove it from the receive queue. Return 0 if there's no packet available.
|
// remove it from the receive queue. Return 0 if there's no packet available.
|
||||||
function bit ChdrBfm::try_peek_chdr (output ChdrPacket_t chdr_packet);
|
function bit ChdrBfm::try_peek_chdr (output ChdrPacket_t chdr_packet);
|
||||||
AxisPacket_t axis_packet;
|
AxisPacket_t axis_packet;
|
||||||
if (!super.try_get(axis_packet)) return 0;
|
if (!super.try_get(axis_packet)) return 0;
|
||||||
chdr_packet = axis_to_chdr(axis_packet);
|
chdr_packet = new();
|
||||||
|
chdr_packet.axis_to_chdr(axis_packet);
|
||||||
return 1;
|
return 1;
|
||||||
endfunction : try_peek_chdr
|
endfunction : try_peek_chdr
|
||||||
|
|
||||||
|
|
||||||
// Convert the data payload of an AXI Stream packet data structure to a CHDR
|
|
||||||
// packet data structure.
|
|
||||||
function ChdrBfm::ChdrPacket_t ChdrBfm::axis_to_chdr (AxisPacket_t axis_packet);
|
|
||||||
enum int { ST_HEADER, ST_TIMESTAMP, ST_METADATA, ST_PAYLOAD } rx_state;
|
|
||||||
data_t word;
|
|
||||||
int num_rx_mdata;
|
|
||||||
int num_rx_bytes;
|
|
||||||
ChdrPacket_t chdr_packet = new();
|
|
||||||
|
|
||||||
rx_state = ST_HEADER;
|
|
||||||
|
|
||||||
for(int i = 0; i < axis_packet.data.size(); i++) begin
|
|
||||||
word = axis_packet.data[i];
|
|
||||||
|
|
||||||
case (rx_state)
|
|
||||||
ST_HEADER : begin
|
|
||||||
num_rx_bytes += BYTES_PER_CHDR_W;
|
|
||||||
chdr_packet.header = word[63:0];
|
|
||||||
|
|
||||||
// Depending on the size of the word, we could have just the header
|
|
||||||
// or both the header and the timestamp in this word.
|
|
||||||
if (chdr_packet.header.pkt_type == CHDR_DATA_WITH_TS) begin
|
|
||||||
if (CHDR_W >= 128) begin
|
|
||||||
chdr_packet.timestamp = word[127:64];
|
|
||||||
rx_state = ST_METADATA;
|
|
||||||
end else begin
|
|
||||||
rx_state = ST_TIMESTAMP;
|
|
||||||
end
|
|
||||||
end else begin
|
|
||||||
rx_state = ST_METADATA;
|
|
||||||
end
|
|
||||||
|
|
||||||
// Check if there's no metadata, in which case we can skip it
|
|
||||||
if (rx_state == ST_METADATA && chdr_packet.header.num_mdata == 0) begin
|
|
||||||
rx_state = ST_PAYLOAD;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
ST_TIMESTAMP : begin
|
|
||||||
num_rx_bytes += BYTES_PER_CHDR_W;
|
|
||||||
chdr_packet.timestamp = word;
|
|
||||||
rx_state = (chdr_packet.header.num_mdata > 0) ? ST_METADATA : ST_PAYLOAD;
|
|
||||||
end
|
|
||||||
ST_METADATA : begin
|
|
||||||
chdr_packet.metadata.push_back(word);
|
|
||||||
num_rx_mdata++;
|
|
||||||
num_rx_bytes += BYTES_PER_CHDR_W;
|
|
||||||
if (num_rx_mdata == chdr_packet.header.num_mdata) rx_state = ST_PAYLOAD;
|
|
||||||
end
|
|
||||||
ST_PAYLOAD : begin
|
|
||||||
chdr_packet.data.push_back(word);
|
|
||||||
num_rx_bytes += BYTES_PER_CHDR_W;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
|
|
||||||
assert (rx_state == ST_PAYLOAD) else begin
|
|
||||||
$error("ChdrBfm::axis_to_chdr: Malformed CHDR packet");
|
|
||||||
end
|
|
||||||
|
|
||||||
// Check length field, noting that the last word may be partially filled
|
|
||||||
assert (chdr_packet.header.length >= num_rx_bytes-(BYTES_PER_CHDR_W-1) &&
|
|
||||||
chdr_packet.header.length <= num_rx_bytes) else begin
|
|
||||||
$error("ChdrBfm::axis_to_chdr: Incorrect CHDR length");
|
|
||||||
end
|
|
||||||
|
|
||||||
return chdr_packet;
|
|
||||||
|
|
||||||
endfunction : axis_to_chdr
|
|
||||||
|
|
||||||
|
|
||||||
// Convert a CHDR packet data structure to a an AXI-Stream packet data
|
|
||||||
// structure.
|
|
||||||
function ChdrBfm::AxisPacket_t ChdrBfm::chdr_to_axis (ChdrPacket_t chdr_packet);
|
|
||||||
int num_words, expected_words;
|
|
||||||
data_t bus_word = 0;
|
|
||||||
AxisPacket_t axis_packet = new();
|
|
||||||
|
|
||||||
// Check that we have the right number of metadata words
|
|
||||||
assert (chdr_packet.metadata.size() == chdr_packet.header.num_mdata) else begin
|
|
||||||
$error("ChdrBfm::chdr_to_axis: Packet metadata size doesn't match header NumMData field");
|
|
||||||
end
|
|
||||||
|
|
||||||
// Calculate the number of words needed to represent this packet
|
|
||||||
num_words = chdr_packet.data.size() + chdr_packet.metadata.size();
|
|
||||||
if (chdr_packet.header.pkt_type == CHDR_DATA_WITH_TS && CHDR_W == 64) begin
|
|
||||||
// Add two words, one for header and one for timestamp
|
|
||||||
num_words += 2;
|
|
||||||
end else begin
|
|
||||||
// Add one word only for header (which may or may not include a timestamp)
|
|
||||||
num_words += 1;
|
|
||||||
end
|
|
||||||
|
|
||||||
// Calculate the number of words represented by the Length field
|
|
||||||
expected_words = chdr_packet.header.length / BYTES_PER_CHDR_W;
|
|
||||||
if (chdr_packet.header.length % BYTES_PER_CHDR_W != 0) expected_words++;
|
|
||||||
|
|
||||||
// Make sure length field matches actual packet length
|
|
||||||
assert (num_words == expected_words) else begin
|
|
||||||
$error("ChdrBfm::chdr_to_axis: Packet size doesn't match header Length field");
|
|
||||||
end
|
|
||||||
|
|
||||||
// Insert header
|
|
||||||
bus_word[63:0] = chdr_packet.header;
|
|
||||||
if (CHDR_W == 64) begin
|
|
||||||
axis_packet.data.push_back(bus_word);
|
|
||||||
if (chdr_packet.header.pkt_type == CHDR_DATA_WITH_TS) begin
|
|
||||||
// Insert timestamp
|
|
||||||
axis_packet.data.push_back(chdr_packet.timestamp);
|
|
||||||
end
|
|
||||||
end else begin
|
|
||||||
// Copy the timestamp word from the header, regardless of whether or not
|
|
||||||
// this packet uses the timestamp field.
|
|
||||||
bus_word[127:64] = chdr_packet.timestamp;
|
|
||||||
axis_packet.data.push_back(bus_word);
|
|
||||||
end
|
|
||||||
|
|
||||||
// Insert metadata
|
|
||||||
foreach (chdr_packet.metadata[i]) begin
|
|
||||||
bus_word = chdr_packet.metadata[i];
|
|
||||||
axis_packet.data.push_back(bus_word);
|
|
||||||
end
|
|
||||||
|
|
||||||
// Insert payload
|
|
||||||
foreach (chdr_packet.data[i]) begin
|
|
||||||
bus_word = chdr_packet.data[i];
|
|
||||||
axis_packet.data.push_back(bus_word);
|
|
||||||
end
|
|
||||||
|
|
||||||
return axis_packet;
|
|
||||||
|
|
||||||
endfunction : chdr_to_axis
|
|
||||||
|
|
||||||
|
|
||||||
endpackage : PkgChdrBfm
|
endpackage : PkgChdrBfm
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ package PkgRfnocItemUtils;
|
|||||||
|
|
||||||
// Check if the contents of two buffers is equal
|
// Check if the contents of two buffers is equal
|
||||||
function bit equal(
|
function bit equal(
|
||||||
ItemDataBuff #(item_t) rhs
|
ItemDataBuff #(item_t,CHDR_W) rhs
|
||||||
);
|
);
|
||||||
if (this.size() != rhs.size()) return 0;
|
if (this.size() != rhs.size()) return 0;
|
||||||
for (int i = 0; i < this.size(); i++) begin
|
for (int i = 0; i < this.size(); i++) begin
|
||||||
|
|||||||
+17
-16
@@ -5,7 +5,7 @@
|
|||||||
//
|
//
|
||||||
// Module: PkgTestExec
|
// Module: PkgTestExec
|
||||||
//
|
//
|
||||||
// Description: This package provides infrastructure for tracking the state of
|
// Description: This package provides infrastructure for tracking the state of
|
||||||
// testbench execution and the results of each test.
|
// testbench execution and the results of each test.
|
||||||
//
|
//
|
||||||
|
|
||||||
@@ -29,6 +29,7 @@ package PkgTestExec;
|
|||||||
int num_assertions; // Number of assertions checked for the current test
|
int num_assertions; // Number of assertions checked for the current test
|
||||||
time start_time, end_time; // Start and end time of the testbench
|
time start_time, end_time; // Start and end time of the testbench
|
||||||
bit stop_on_error = 1; // Configuration option to stop when an error occurs
|
bit stop_on_error = 1; // Configuration option to stop when an error occurs
|
||||||
|
bit done = 0; // Flag that sets when tb is finished
|
||||||
bit test_status[$]; // Pass/fail status of each test
|
bit test_status[$]; // Pass/fail status of each test
|
||||||
|
|
||||||
timeout_t tb_timeout; // Handle to timeout for the overall testbench
|
timeout_t tb_timeout; // Handle to timeout for the overall testbench
|
||||||
@@ -54,7 +55,7 @@ package PkgTestExec;
|
|||||||
// Get the sempahore, to prevent multiple overlapping instances of the
|
// Get the sempahore, to prevent multiple overlapping instances of the
|
||||||
// same testbench.
|
// same testbench.
|
||||||
test_sem.get();
|
test_sem.get();
|
||||||
|
done = 0;
|
||||||
$display("========================================================");
|
$display("========================================================");
|
||||||
$display("TESTBENCH STARTED: %s", tb_name);
|
$display("TESTBENCH STARTED: %s", tb_name);
|
||||||
$display("========================================================");
|
$display("========================================================");
|
||||||
@@ -65,8 +66,8 @@ package PkgTestExec;
|
|||||||
num_finished = 0;
|
num_finished = 0;
|
||||||
num_passed = 0;
|
num_passed = 0;
|
||||||
start_timeout(
|
start_timeout(
|
||||||
tb_timeout,
|
tb_timeout,
|
||||||
time_limit,
|
time_limit,
|
||||||
$sformatf("Testbench \"%s\" time limit exceeded", tb_name),
|
$sformatf("Testbench \"%s\" time limit exceeded", tb_name),
|
||||||
SEV_FATAL
|
SEV_FATAL
|
||||||
);
|
);
|
||||||
@@ -75,7 +76,7 @@ package PkgTestExec;
|
|||||||
|
|
||||||
// Call end_tb() at the end of a testbench to report final statistics and,
|
// Call end_tb() at the end of a testbench to report final statistics and,
|
||||||
// optionally, end simulation.
|
// optionally, end simulation.
|
||||||
//
|
//
|
||||||
// finish: Set to 1 (default) to cause $finish() to be called at the
|
// finish: Set to 1 (default) to cause $finish() to be called at the
|
||||||
// end of simulation, cuasing the simulator to close.
|
// end of simulation, cuasing the simulator to close.
|
||||||
//
|
//
|
||||||
@@ -83,7 +84,6 @@ package PkgTestExec;
|
|||||||
assert (num_started == num_finished) else begin
|
assert (num_started == num_finished) else begin
|
||||||
$fatal(1, "Testbench ended before test completed");
|
$fatal(1, "Testbench ended before test completed");
|
||||||
end
|
end
|
||||||
|
|
||||||
end_time = $time;
|
end_time = $time;
|
||||||
$display("========================================================");
|
$display("========================================================");
|
||||||
$display("TESTBENCH FINISHED: %s", tb_name);
|
$display("TESTBENCH FINISHED: %s", tb_name);
|
||||||
@@ -98,6 +98,7 @@ package PkgTestExec;
|
|||||||
|
|
||||||
end_timeout(tb_timeout);
|
end_timeout(tb_timeout);
|
||||||
|
|
||||||
|
done = 1;
|
||||||
if (finish) $finish();
|
if (finish) $finish();
|
||||||
|
|
||||||
// Release the semaphore to allow new instances of the testbench to run
|
// Release the semaphore to allow new instances of the testbench to run
|
||||||
@@ -118,8 +119,8 @@ package PkgTestExec;
|
|||||||
// Create a timeout for this test
|
// Create a timeout for this test
|
||||||
if (time_limit > 0) begin
|
if (time_limit > 0) begin
|
||||||
start_timeout(
|
start_timeout(
|
||||||
test_timeout,
|
test_timeout,
|
||||||
time_limit,
|
time_limit,
|
||||||
$sformatf("Test \"%s\" time limit exceeded", test_name),
|
$sformatf("Test \"%s\" time limit exceeded", test_name),
|
||||||
SEV_FATAL
|
SEV_FATAL
|
||||||
);
|
);
|
||||||
@@ -133,7 +134,7 @@ package PkgTestExec;
|
|||||||
endtask : start_test
|
endtask : start_test
|
||||||
|
|
||||||
|
|
||||||
// Call end_test() at the end of each test.
|
// Call end_test() at the end of each test.
|
||||||
//
|
//
|
||||||
// test_result: Optional value to indicate the overall pass/fail result
|
// test_result: Optional value to indicate the overall pass/fail result
|
||||||
// of the test. Use non-zero for pass, 0 for fail.
|
// of the test. Use non-zero for pass, 0 for fail.
|
||||||
@@ -149,7 +150,7 @@ package PkgTestExec;
|
|||||||
|
|
||||||
passed = test_status[num_started-1] && test_result;
|
passed = test_status[num_started-1] && test_result;
|
||||||
num_finished++;
|
num_finished++;
|
||||||
$display("[TEST CASE %3d] (t = %t) DONE... %s",
|
$display("[TEST CASE %3d] (t = %t) DONE... %s",
|
||||||
num_started, $time, passed ? "Passed" : "FAILED");
|
num_started, $time, passed ? "Passed" : "FAILED");
|
||||||
|
|
||||||
if (passed) num_passed++;
|
if (passed) num_passed++;
|
||||||
@@ -163,7 +164,7 @@ package PkgTestExec;
|
|||||||
//
|
//
|
||||||
// expr: The expression value to be asserted
|
// expr: The expression value to be asserted
|
||||||
// message: String to report if the assertion fails
|
// message: String to report if the assertion fails
|
||||||
//
|
//
|
||||||
function void assert_error(int expr, string message = "");
|
function void assert_error(int expr, string message = "");
|
||||||
num_assertions++;
|
num_assertions++;
|
||||||
assert (expr) else begin
|
assert (expr) else begin
|
||||||
@@ -178,7 +179,7 @@ package PkgTestExec;
|
|||||||
//
|
//
|
||||||
// expr: The expression value to be asserted
|
// expr: The expression value to be asserted
|
||||||
// message: String to report if the assertion fails
|
// message: String to report if the assertion fails
|
||||||
//
|
//
|
||||||
function void assert_fatal(int expr, string message = "");
|
function void assert_fatal(int expr, string message = "");
|
||||||
num_assertions++;
|
num_assertions++;
|
||||||
assert (expr) else begin
|
assert (expr) else begin
|
||||||
@@ -192,7 +193,7 @@ package PkgTestExec;
|
|||||||
//
|
//
|
||||||
// expr: The expression value to be asserted
|
// expr: The expression value to be asserted
|
||||||
// message: String to report if the assertion fails
|
// message: String to report if the assertion fails
|
||||||
//
|
//
|
||||||
function void assert_warning(int expr, string message = "");
|
function void assert_warning(int expr, string message = "");
|
||||||
num_assertions++;
|
num_assertions++;
|
||||||
assert (expr) else begin
|
assert (expr) else begin
|
||||||
@@ -209,7 +210,7 @@ package PkgTestExec;
|
|||||||
// severity: Indicates the type of severity task that should be used if
|
// severity: Indicates the type of severity task that should be used if
|
||||||
// the assertion fails ($info, $warning, $error, $fatal).
|
// the assertion fails ($info, $warning, $error, $fatal).
|
||||||
// Default value is SEV_ERROR.
|
// Default value is SEV_ERROR.
|
||||||
//
|
//
|
||||||
function void assert_sev(
|
function void assert_sev(
|
||||||
int expr,
|
int expr,
|
||||||
string message = "",
|
string message = "",
|
||||||
@@ -249,8 +250,8 @@ package PkgTestExec;
|
|||||||
// used if the timeout expires. Default is SEV_ERROR.
|
// used if the timeout expires. Default is SEV_ERROR.
|
||||||
//
|
//
|
||||||
task start_timeout(
|
task start_timeout(
|
||||||
output timeout_t handle,
|
output timeout_t handle,
|
||||||
input realtime timeout_delay,
|
input realtime timeout_delay,
|
||||||
input string message = "Timeout",
|
input string message = "Timeout",
|
||||||
input severity_t severity = SEV_ERROR
|
input severity_t severity = SEV_ERROR
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user