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:
Andrew Moch
2020-06-18 09:09:34 -05:00
committed by Wade Fife
parent 8875582763
commit 55881469ac
19 changed files with 599 additions and 420 deletions
@@ -29,10 +29,11 @@ $(RFNOC_OOT_SRCS) \
#-------------------------------------------------
# Testbench Specific
#-------------------------------------------------
SIM_TOP = rfnoc_block_null_src_sink_tb
SIM_TOP = rfnoc_block_null_src_sink_all_tb
SIM_SRCS = \
$(abspath rfnoc_block_null_src_sink_tb.sv) \
$(abspath rfnoc_block_null_src_sink_all_tb.sv) \
# MODELSIM_USER_DO = $(abspath wave.do)
@@ -23,6 +23,8 @@
module noc_shell_null_src_sink #(
parameter [9:0] THIS_PORTID = 10'd0,
parameter CHDR_W = 64,
parameter ITEM_W = 32,
parameter NIPC = 2,
parameter [5:0] MTU = 10
) (
//---------------------
@@ -82,8 +84,8 @@ module noc_shell_null_src_sink #(
output wire axis_data_clk,
output wire axis_data_rst,
// Payload Stream to User Logic: sink
output wire [32*2-1:0] m_sink_payload_tdata,
output wire [2-1:0] m_sink_payload_tkeep,
output wire [ITEM_W*NIPC-1:0] m_sink_payload_tdata,
output wire [NIPC-1:0] m_sink_payload_tkeep,
output wire m_sink_payload_tlast,
output wire m_sink_payload_tvalid,
input wire m_sink_payload_tready,
@@ -94,8 +96,8 @@ module noc_shell_null_src_sink #(
output wire m_sink_context_tvalid,
input wire m_sink_context_tready,
// Payload Stream to User Logic: loop
output wire [32*2-1:0] m_loop_payload_tdata,
output wire [2-1:0] m_loop_payload_tkeep,
output wire [ITEM_W*NIPC-1:0] m_loop_payload_tdata,
output wire [NIPC-1:0] m_loop_payload_tkeep,
output wire m_loop_payload_tlast,
output wire m_loop_payload_tvalid,
input wire m_loop_payload_tready,
@@ -106,8 +108,8 @@ module noc_shell_null_src_sink #(
output wire m_loop_context_tvalid,
input wire m_loop_context_tready,
// Payload Stream from User Logic: source
input wire [32*2-1:0] s_source_payload_tdata,
input wire [1:0] s_source_payload_tkeep,
input wire [ITEM_W*NIPC-1:0] s_source_payload_tdata,
input wire [NIPC-1:0] s_source_payload_tkeep,
input wire s_source_payload_tlast,
input wire s_source_payload_tvalid,
output wire s_source_payload_tready,
@@ -118,8 +120,8 @@ module noc_shell_null_src_sink #(
input wire s_source_context_tvalid,
output wire s_source_context_tready,
// Payload Stream from User Logic: loop
input wire [32*2-1:0] s_loop_payload_tdata,
input wire [1:0] s_loop_payload_tkeep,
input wire [ITEM_W*NIPC-1:0] s_loop_payload_tdata,
input wire [NIPC-1:0] s_loop_payload_tkeep,
input wire s_loop_payload_tlast,
input wire s_loop_payload_tvalid,
output wire s_loop_payload_tready,
@@ -233,8 +235,8 @@ module noc_shell_null_src_sink #(
chdr_to_axis_pyld_ctxt #(
.CHDR_W (CHDR_W),
.ITEM_W (32),
.NIPC (2),
.ITEM_W (ITEM_W),
.NIPC (NIPC),
.SYNC_CLKS (1),
.CONTEXT_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_W (CHDR_W),
.ITEM_W (32),
.NIPC (2),
.ITEM_W (ITEM_W),
.NIPC (NIPC),
.SYNC_CLKS (1),
.CONTEXT_FIFO_SIZE ($clog2(2)),
.PAYLOAD_FIFO_SIZE ($clog2(2)),
@@ -303,8 +305,8 @@ module noc_shell_null_src_sink #(
axis_pyld_ctxt_to_chdr #(
.CHDR_W (CHDR_W),
.ITEM_W (32),
.NIPC (2),
.ITEM_W (ITEM_W),
.NIPC (NIPC),
.SYNC_CLKS (1),
.CONTEXT_FIFO_SIZE ($clog2(2)),
.PAYLOAD_FIFO_SIZE ($clog2(2)),
@@ -338,8 +340,8 @@ module noc_shell_null_src_sink #(
axis_pyld_ctxt_to_chdr #(
.CHDR_W (CHDR_W),
.ITEM_W (32),
.NIPC (2),
.ITEM_W (ITEM_W),
.NIPC (NIPC),
.SYNC_CLKS (1),
.CONTEXT_FIFO_SIZE ($clog2(2)),
.PAYLOAD_FIFO_SIZE ($clog2(2)),
@@ -4,30 +4,46 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: rfnoc_block_null_src_sink
//
// 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:
// 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:
module rfnoc_block_null_src_sink #(
parameter [9:0] THIS_PORTID = 10'd0,
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
input wire rfnoc_chdr_clk,
input wire rfnoc_ctrl_clk,
// RFNoC Backend Interface
// RFNoC Backend Interface
input wire [511:0] rfnoc_core_config,
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 [1:0] s_rfnoc_chdr_tlast,
input wire [1:0] s_rfnoc_chdr_tvalid,
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 [1:0] m_rfnoc_chdr_tlast,
output wire [1:0] m_rfnoc_chdr_tvalid,
@@ -72,22 +88,24 @@ module rfnoc_block_null_src_sink #(
reg ctrlport_resp_ack;
reg [31:0] ctrlport_resp_data;
wire [(32*NIPC)-1:0] src_pyld_tdata , loop_pyld_tdata ;
wire [NIPC-1:0] src_pyld_tkeep , loop_pyld_tkeep ;
wire src_pyld_tlast , snk_pyld_tlast , loop_pyld_tlast ;
wire src_pyld_tvalid, snk_pyld_tvalid, loop_pyld_tvalid;
wire src_pyld_tready, snk_pyld_tready, loop_pyld_tready;
wire [(ITEM_W*NIPC)-1:0] src_pyld_tdata , loop_pyld_tdata ;
wire [NIPC-1:0] src_pyld_tkeep , loop_pyld_tkeep ;
wire src_pyld_tlast , snk_pyld_tlast , loop_pyld_tlast ;
wire src_pyld_tvalid, snk_pyld_tvalid, loop_pyld_tvalid;
wire src_pyld_tready, snk_pyld_tready, loop_pyld_tready;
wire [CHDR_W-1:0] src_ctxt_tdata , loop_ctxt_tdata ;
wire [3:0] src_ctxt_tuser , loop_ctxt_tuser ;
wire src_ctxt_tlast , loop_ctxt_tlast ;
wire src_ctxt_tvalid, loop_ctxt_tvalid;
wire src_ctxt_tready, snk_ctxt_tready, loop_ctxt_tready;
wire [CHDR_W-1:0] src_ctxt_tdata , loop_ctxt_tdata ;
wire [3:0] src_ctxt_tuser , loop_ctxt_tuser ;
wire src_ctxt_tlast , loop_ctxt_tlast ;
wire src_ctxt_tvalid, loop_ctxt_tvalid;
wire src_ctxt_tready, snk_ctxt_tready, loop_ctxt_tready;
// NoC Shell
// ---------------------------
noc_shell_null_src_sink #(
.THIS_PORTID (THIS_PORTID),
.NIPC (NIPC),
.ITEM_W (ITEM_W),
.CHDR_W (CHDR_W),
.MTU (MTU)
) noc_shell_null_src_sink_i (
@@ -257,18 +275,17 @@ module rfnoc_block_null_src_sink #(
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_tlast = (lines_left == 12'd0);
assign src_pyld_tvalid = (state == ST_PYLD);
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);
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_tvalid = (state == ST_HDR && reg_src_en);
// Register Interface
// ---------------------------
always @(posedge rfnoc_chdr_clk) begin
@@ -294,7 +311,7 @@ module rfnoc_block_null_src_sink #(
if (ctrlport_req_rd) begin
case(ctrlport_req_addr)
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:
ctrlport_resp_data <= {20'h0, reg_src_lpp};
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
//
@@ -9,9 +9,15 @@
`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
`define TEST_EXEC_OBJ test
`include "test_exec.svh"
import PkgTestExec::*;
@@ -23,10 +29,10 @@ module rfnoc_block_null_src_sink_tb;
localparam NOC_ID = 32'h0000_0001;
localparam [9:0] THIS_PORTID = 10'h17;
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 LPP = ((SPP+1)/2);
localparam int LPP = SPP % NIPC == 0 ? SPP/NIPC : SPP/NIPC+1;
localparam int NUM_PKTS = 50;
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) s1_chdr (rfnoc_chdr_clk); // Optional data iface
TestExec test = new();
typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t;
// Bus functional model for a software block controller
@@ -58,29 +66,30 @@ module rfnoc_block_null_src_sink_tb;
rfnoc_block_null_src_sink #(
.THIS_PORTID (THIS_PORTID),
.CHDR_W (CHDR_W),
.NIPC (2),
.ITEM_W (ITEM_W),
.NIPC (NIPC),
.MTU (10)
) dut (
.rfnoc_chdr_clk (backend.chdr_clk),
.rfnoc_ctrl_clk (backend.ctrl_clk),
.rfnoc_core_config (backend.slave.cfg),
.rfnoc_core_status (backend.slave.sts),
.s_rfnoc_chdr_tdata ({m1_chdr.slave.tdata , m0_chdr.slave.tdata }),
.s_rfnoc_chdr_tlast ({m1_chdr.slave.tlast , m0_chdr.slave.tlast }),
.s_rfnoc_chdr_tvalid({m1_chdr.slave.tvalid , m0_chdr.slave.tvalid }),
.s_rfnoc_chdr_tready({m1_chdr.slave.tready , m0_chdr.slave.tready }),
.m_rfnoc_chdr_tdata ({s1_chdr.master.tdata , s0_chdr.master.tdata }),
.m_rfnoc_chdr_tlast ({s1_chdr.master.tlast , s0_chdr.master.tlast }),
.m_rfnoc_chdr_tvalid({s1_chdr.master.tvalid, s0_chdr.master.tvalid}),
.m_rfnoc_chdr_tready({s1_chdr.master.tready, s0_chdr.master.tready}),
.s_rfnoc_ctrl_tdata (m_ctrl.slave.tdata ),
.s_rfnoc_ctrl_tlast (m_ctrl.slave.tlast ),
.s_rfnoc_ctrl_tvalid(m_ctrl.slave.tvalid ),
.s_rfnoc_ctrl_tready(m_ctrl.slave.tready ),
.m_rfnoc_ctrl_tdata (s_ctrl.master.tdata ),
.m_rfnoc_ctrl_tlast (s_ctrl.master.tlast ),
.m_rfnoc_ctrl_tvalid(s_ctrl.master.tvalid),
.m_rfnoc_ctrl_tready(s_ctrl.master.tready)
.rfnoc_core_config (backend.cfg),
.rfnoc_core_status (backend.sts),
.s_rfnoc_chdr_tdata ({m1_chdr.tdata , m0_chdr.tdata }),
.s_rfnoc_chdr_tlast ({m1_chdr.tlast , m0_chdr.tlast }),
.s_rfnoc_chdr_tvalid({m1_chdr.tvalid , m0_chdr.tvalid }),
.s_rfnoc_chdr_tready({m1_chdr.tready , m0_chdr.tready }),
.m_rfnoc_chdr_tdata ({s1_chdr.tdata , s0_chdr.tdata }),
.m_rfnoc_chdr_tlast ({s1_chdr.tlast , s0_chdr.tlast }),
.m_rfnoc_chdr_tvalid({s1_chdr.tvalid, s0_chdr.tvalid}),
.m_rfnoc_chdr_tready({s1_chdr.tready, s0_chdr.tready}),
.s_rfnoc_ctrl_tdata (m_ctrl.tdata ),
.s_rfnoc_ctrl_tlast (m_ctrl.tlast ),
.s_rfnoc_ctrl_tvalid(m_ctrl.tvalid ),
.s_rfnoc_ctrl_tready(m_ctrl.tready ),
.m_rfnoc_ctrl_tdata (s_ctrl.tdata ),
.m_rfnoc_ctrl_tlast (s_ctrl.tlast ),
.m_rfnoc_ctrl_tvalid(s_ctrl.tvalid),
.m_rfnoc_ctrl_tready(s_ctrl.tready)
);
// ----------------------------------------
@@ -95,7 +104,7 @@ module rfnoc_block_null_src_sink_tb;
// 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
blk_ctrl = new(backend, m_ctrl, s_ctrl);
@@ -107,7 +116,7 @@ module rfnoc_block_null_src_sink_tb;
// Startup block (Software initialization)
// ----------------------------------------
test.start_test("Flush block then reset it");
test.start_test({TEST_NAME,"Flush block then reset it"});
begin
test.start_timeout(timeout, 10us, "Waiting for flush_and_reset");
#100; //Wait for GSR to deassert
@@ -118,7 +127,7 @@ module rfnoc_block_null_src_sink_tb;
// Run Tests
// ----------------------------------------
test.start_test("Read Block Info");
test.start_test({TEST_NAME,"Read Block Info"});
begin
test.start_timeout(timeout, 1us, "Waiting for block info response");
// Get static block info and validate it
@@ -130,19 +139,20 @@ module rfnoc_block_null_src_sink_tb;
// Read status register and validate it
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");
test.end_timeout(timeout);
end
test.end_test();
test.start_test("Stream Data Through Loopback Port");
test.start_test({TEST_NAME,"Stream Data Through Loopback Port m1->s1"});
begin
// Send and receive packets
repeat (NUM_PKTS) begin
chdr_word_t rx_data[$];
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++)
tx_dbuff.put($urandom());
test.start_timeout(timeout, 5us, "Waiting for pkt to loop back");
@@ -173,16 +183,16 @@ module rfnoc_block_null_src_sink_tb;
end
test.end_test();
test.start_test("Stream Data To Sink Port");
test.start_test({TEST_NAME,"Stream Data To Sink Port m0"});
begin
// Send packets
repeat (NUM_PKTS) begin
chdr_word_t rx_data[$];
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++)
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());
test.end_timeout(timeout);
end
@@ -208,11 +218,12 @@ module rfnoc_block_null_src_sink_tb;
end
test.end_test();
test.start_test("Stream Data From Source Port");
test.start_test({TEST_NAME,"Stream Data From Source Port s0"});
begin
// 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_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);
repeat ((NUM_PKTS / 10) * LPP) @(posedge rfnoc_chdr_clk);
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");
exp_data.delete();
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);
`ASSERT_ERROR(blk_ctrl.compare_data(exp_data, rx_data), "Data mismatch");
test.end_timeout(timeout);
@@ -236,7 +247,7 @@ module rfnoc_block_null_src_sink_tb;
end
test.end_test();
test.start_test("Clear Counts");
test.start_test({TEST_NAME,"Clear Counts"});
begin
test.start_timeout(timeout, 1us, "Waiting for clear and readbacks");
// Clear
@@ -266,7 +277,7 @@ module rfnoc_block_null_src_sink_tb;
// Finish Up
// ----------------------------------------
// Display final statistics and results
test.end_tb();
test.end_tb(.finish(0));
end
endmodule