fpga: lib: Add synthesizable AXI4-Stream SV components

Components are connected together with AxiStreamIfc. Some features
include:
  (1) Add bytes to the start of a packet
  (2) Remove bytes from a packet
  (3) Wrappers for some older components
      a.  fifo - buffer but imediately pass a packet
      b.  packet_gate - buffer and hold till end of packet
      c.  width_conv - cross clock domains and change width of axi bus

The AxiStreamIf was moved from PkgAxiStreamBfm to its own file. It can
be used to connect to ports with continuous assignment.
AxiStreamPacketIf must be used procedurally but allows the following
new methods:
  - reached_packet_byte - notify when tdata contains a paritcular byte
  - get_packet_byte/get_packet_field - extract a byte or field from axi
  - put_packet_byte/put_packet_field - overwrite a byte or field onto axi


Original-commit: c3bca6c87700054c96320de119a58f6a688dbd5a
This commit is contained in:
Andrew Moch
2020-06-25 14:44:04 -05:00
committed by Wade Fife
parent 6940db90e3
commit 23be04661f
20 changed files with 4197 additions and 80 deletions
+47
View File
@@ -0,0 +1,47 @@
#
# Copyright 2020 Ettus Research, A National Instruments Brand
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#
#-------------------------------------------------
# Top-of-Makefile
#-------------------------------------------------
# Define BASE_DIR to point to the "top" dir
BASE_DIR = $(abspath ../../../top)
# Include viv_sim_preamble after defining BASE_DIR
include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak
#-------------------------------------------------
# Design Specific
#-------------------------------------------------
# Include makefiles and sources for the DUT and its dependencies
include $(BASE_DIR)/../lib/axi4s_sv/Makefile.srcs
DESIGN_SRCS = $(abspath \
$(AXI4S_SV_SRCS) \
)
#-------------------------------------------------
# Testbench Specific
#-------------------------------------------------
# Define only one toplevel module
TB_TOP_MODULE = axi4s_add_bytes_all_tb
SIM_TOP = $(TB_TOP_MODULE)
SIM_SRCS = \
$(abspath $(TB_TOP_MODULE).sv )\
$(abspath axi4s_add_bytes_tb.sv )
# supressing the following worthless reminder.
#* Warning: M:/usrp4-hw/oss-repo/fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes.sv(228): (vlog-2583) [SVCHK] -
# Extra checking for conflicts with always_comb and always_latch variables is done at vopt time
SVLOG_ARGS = -suppress 2583
#-------------------------------------------------
# Bottom-of-Makefile
#-------------------------------------------------
# Include all simulator specific makefiles here
# Each should define a unique target to simulate
# e.g. xsim, vsim, etc and a common "clean" target
include $(BASE_DIR)/../tools/make/viv_simulator.mak
@@ -0,0 +1,53 @@
//
// Copyright 2020 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: axi4s_add_bytes_all_tb
//
// Description: Testbench for axi_add_bytes
// Exercise corner cases parameters for adding bytes to the front of a packet
//
module axi4s_add_bytes_all_tb;
// actual use cases
// Add Ethernet header from a packet includes a preamble
axi4s_add_bytes_tb #(.TEST_NAME("ENET_64_HADD"),.WIDTH(64),.ADD_START(0),.ADD_BYTES(48))
ENET_64_HADD48 ();
axi4s_add_bytes_tb #(.TEST_NAME("ENET_128_HADD"),.WIDTH(128),.ADD_START(0),.ADD_BYTES(48))
ENET_128_HADD48 ();
axi4s_add_bytes_tb #(.TEST_NAME("ENET_256_HADD"),.WIDTH(256),.ADD_START(0),.ADD_BYTES(48))
ENET_256_HADD48 ();
axi4s_add_bytes_tb #(.TEST_NAME("ENET_512_HADD"),.WIDTH(512),.ADD_START(0),.ADD_BYTES(48))
ENET_512_HADD48 ();
// Add Preamble header from a packet
axi4s_add_bytes_tb #(.TEST_NAME("ENET_64_PADD"),.WIDTH(64),.ADD_START(0),.ADD_BYTES(6))
ENET_64_PADD6 ();
axi4s_add_bytes_tb #(.TEST_NAME("ENET_128_PADD"),.WIDTH(128),.ADD_START(0),.ADD_BYTES(6))
ENET_128_PADD6 ();
axi4s_add_bytes_tb #(.TEST_NAME("ENET_256_PADD"),.WIDTH(256),.ADD_START(0),.ADD_BYTES(6))
ENET_256_PADD6 ();
axi4s_add_bytes_tb #(.TEST_NAME("ENET_512_PADD"),.WIDTH(512),.ADD_START(0),.ADD_BYTES(6))
ENET_512_PADD6 ();
// START cases - removal starts at LSB of word
axi4s_add_bytes_tb #(.TEST_NAME("SSTART_32_0:0"),.WIDTH(32),.ADD_START(0),.ADD_BYTES(1))
SSTART_32_0to0 ();
axi4s_add_bytes_tb #(.TEST_NAME("SSTART_32_1:0"),.WIDTH(32),.ADD_START(0),.ADD_BYTES(2))
SSTART_32_0to1 ();
axi4s_add_bytes_tb #(.TEST_NAME("SSTART_32_2:0"),.WIDTH(32),.ADD_START(0),.ADD_BYTES(3))
SSTART_32_0to2 ();
axi4s_add_bytes_tb #(.TEST_NAME("EXACT_32_3:0"), .WIDTH(32),.ADD_START(0),.ADD_BYTES(4))
EXACT_32_0to3 ();
axi4s_add_bytes_tb #(.TEST_NAME("MSTART_32_4:0"),.WIDTH(32),.ADD_START(0),.ADD_BYTES(5))
MSTART_32_0to4 ();
axi4s_add_bytes_tb #(.TEST_NAME("MSTART_32_5:0"),.WIDTH(32),.ADD_START(0),.ADD_BYTES(6))
MSTART_32_0to5 ();
axi4s_add_bytes_tb #(.TEST_NAME("MSTART_32_6:0"),.WIDTH(32),.ADD_START(0),.ADD_BYTES(7))
MSTART_32_0to6 ();
axi4s_add_bytes_tb #(.TEST_NAME("EXACT_32_7:0"), .WIDTH(32),.ADD_START(0),.ADD_BYTES(8))
EXACT_32_0to7 ();
endmodule
@@ -0,0 +1,171 @@
//
// Copyright 2020 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: axi4s_add_bytes_tb
//
// Description: Testbench for axi_add_bytes
//
module axi4s_add_bytes_tb #(
parameter TEST_NAME = "axi_add_bytes",
WIDTH=32,ADD_START=0,ADD_BYTES=7
);
// Include macros and time declarations for use with PkgTestExec
// To change the name of the TestExec object being used by the assertion
// macros, `define TEST_EXEC_OBJ before including this file and `undef it at
// the end of your testbench. Otherwise, it defaults to the shared object
// "PkgTestExec::test".
`define TEST_EXEC_OBJ test
`include "test_exec.svh"
import PkgAxiStreamBfm::*;
import PkgTestExec::*;
import PkgEthernet::*;
//---------------------------------------------------------------------------
// Local Parameters
//---------------------------------------------------------------------------
localparam UWIDTH = $clog2((WIDTH/8)+1);
localparam MAX_PACKET_BYTES = 16*1024;
//---------------------------------------------------------------------------
// Clocks
//---------------------------------------------------------------------------
bit clk;
bit reset;
sim_clock_gen #(.PERIOD(5.0), .AUTOSTART(1))
clk_gen (.clk(clk), .rst(reset));
//---------------------------------------------------------------------------
// Bus Functional Models
//---------------------------------------------------------------------------
TestExec test = new();
AxiStreamIf #(.DATA_WIDTH(WIDTH),.USER_WIDTH(UWIDTH),.TKEEP(0),
.MAX_PACKET_BYTES(MAX_PACKET_BYTES))
i (clk, reset);
AxiStreamIf #(.DATA_WIDTH(WIDTH),.USER_WIDTH(UWIDTH),.TKEEP(0),
.MAX_PACKET_BYTES(MAX_PACKET_BYTES))
o (clk, reset);
// Bus functional model for a axi_stream controller
AxiStreamBfm #(.DATA_WIDTH(WIDTH),.USER_WIDTH(UWIDTH),.TKEEP(0),
.MAX_PACKET_BYTES(MAX_PACKET_BYTES))
axis = new(.master(i), .slave(o));
//----------------------------------------------------
// Instantiate DUT
//----------------------------------------------------
axi4s_add_bytes #(.ADD_START(ADD_START),.ADD_BYTES(ADD_BYTES))
DUT (.*);
//---------------------------------------------------------------------------
// Reset
//---------------------------------------------------------------------------
task test_reset();
test.start_test("Wait for Reset", 10us);
clk_gen.reset();
wait(!reset);
repeat (10) @(posedge clk);
test.end_test();
endtask : test_reset
//---------------------------------------------------------------------------
// Ethernet to CPU test
//---------------------------------------------------------------------------
typedef AxiStreamPacket #(WIDTH, UWIDTH) AxisPacket_t;
typedef XportStreamPacket #(WIDTH) XportPacket_t;
task test_samples(int num_samples);
raw_pkt_t raw;
localparam PKTS_TO_SEND = 10;
automatic XportPacket_t send[$];
automatic XportPacket_t expected[$];
test.start_test({TEST_NAME,"::Remove Bytes"}, 10us);
for (int i= 0 ; i < PKTS_TO_SEND; i++) begin
expected[i] = new;
send[i] = new;
get_ramp_raw_pkt(.num_samps(num_samples),.ramp_start((i*num_samples)%256),.ramp_inc(1),.pkt(raw),.SWIDTH(8));
send[i].push_bytes(raw);
// Add the bytes to the raw packet to build expected.
for (int i = 0 ; i < ADD_BYTES; ++i) begin
raw.insert(ADD_START,0);
end
expected[i].push_bytes(raw);
send[i].tkeep_to_tuser(.ERROR_PROB(10));
expected[i].tkeep_to_tuser();
if (send[i].has_error()) expected[i].set_error();
end
fork
begin // Send Thread
foreach(send[i])begin
axis.put(send[i]);
end
end
begin // Expected Thread
foreach(expected[i]) begin
automatic string str;
automatic AxisPacket_t actual_a = new();
automatic XportPacket_t actual = new();
axis.get(actual_a);
actual.import_axis(actual_a);
actual.tuser_to_tkeep();
str = $sformatf("ADD_START=%3d ADD_BYTES=%3d",ADD_START,ADD_BYTES);
`ASSERT_ERROR(!actual.compare_w_error(expected[i]),str);
end
end
join
test.end_test();
endtask : test_samples
//----------------------------------------------------
// Main test loop
//----------------------------------------------------
initial begin : tb_main
integer min_length;
test.tb_name = TEST_NAME;
min_length = ADD_START+1;
axis.run();
test_reset();
// Test with default holdoff.
for (int i=1 ; i < (WIDTH/8)*3 ; ++i) begin
test_samples(min_length+i);
end
// repeat back to back
axis.set_slave_stall_prob(0);
axis.set_master_stall_prob(0);
for (int i=1 ; i < (WIDTH/8)*3 ; ++i) begin
test_samples(min_length+i);
end
// End the TB, but don't $finish, since we don't want to kill other
// instances of this testbench that may be running.
test.end_tb(0);
// Kill the clocks to end this instance of the testbench
clk_gen.kill();
end // initial begin
endmodule
`undef TEST_EXEC_OBJ