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:
@@ -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
|
||||
Reference in New Issue
Block a user