diff options
author | Andrew Moch <Andrew.Moch@ni.com> | 2020-06-22 17:13:36 +0100 |
---|---|---|
committer | Wade Fife <wade.fife@ettus.com> | 2020-06-25 14:44:04 -0500 |
commit | c3bca6c87700054c96320de119a58f6a688dbd5a (patch) | |
tree | 5caa6aca23b6ea84335ea22398698aa1ea3569ea /fpga/usrp3/lib/axi4s_sv/axi4s_width_conv.sv | |
parent | 8661f46df66329511ccb3cf083830e19d65ea402 (diff) | |
download | uhd-c3bca6c87700054c96320de119a58f6a688dbd5a.tar.gz uhd-c3bca6c87700054c96320de119a58f6a688dbd5a.tar.bz2 uhd-c3bca6c87700054c96320de119a58f6a688dbd5a.zip |
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
Diffstat (limited to 'fpga/usrp3/lib/axi4s_sv/axi4s_width_conv.sv')
-rw-r--r-- | fpga/usrp3/lib/axi4s_sv/axi4s_width_conv.sv | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/axi4s_sv/axi4s_width_conv.sv b/fpga/usrp3/lib/axi4s_sv/axi4s_width_conv.sv new file mode 100644 index 000000000..f05f70438 --- /dev/null +++ b/fpga/usrp3/lib/axi4s_sv/axi4s_width_conv.sv @@ -0,0 +1,137 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Description: +// System Verilog wrapper for axis_width_conv that accepts a AxiStreamIfc +// with slave_user/master_user interface. This block requires that the +// bottom bits of user contain the number of bytes in the last word. +// +// If TKEEP - tkeep contains byte_enables +// If USER_TRAILING_BYTES - tuser contains byte_enables +// Else everything is a full word +// +// Parameters: +// PIPELINE - Add pipelining for timing. +// SYNC_CLKS - Input and output clock are the same. +// I_USER_TRAILING_BYTES - input byte_enable is set by user +// O_USER_TRAILING_BYTES - output byte_enable is set in user +// + +module axi4s_width_conv #( + PIPELINE = "NONE", + bit I_USER_TRAILING_BYTES = 0, + bit O_USER_TRAILING_BYTES = 0, + bit SYNC_CLKS = 1 +) ( + interface i, // AxiStreamIf or AxiStreamPacketIf + interface o // AxiStreamIf or AxiStreamPacketIf +); + + localparam IWIDTH =i.DATA_WIDTH; + localparam OWIDTH =o.DATA_WIDTH; + + `include "axi4s.vh" + // Parameter Checks + initial begin + if(i.TKEEP) begin + assert (!I_USER_TRAILING_BYTES) else + $fatal("I_USER_TRAILING_BYTE set at the same time as TKEEP"); + assert (!i.TUSER) else + $fatal("i.TUSER set- This module does not pass user"); + end else if(I_USER_TRAILING_BYTES) begin + assert (i.USER_WIDTH >= i.TRAILING_WIDTH ) else + $fatal("i.USER_WIDTH does not match TRAILING_WIDTH"); + end else begin + assert (!i.TUSER) else + $fatal("This module does not pass generic user_data"); + end + + if(o.TKEEP) begin + assert (!O_USER_TRAILING_BYTES) else + $fatal("O_USER_TRAILING_BYTE set at the same time as TKEEP"); + assert (!o.TUSER) else + $fatal("O.TUSER set- This module does not pass user"); + end else if(O_USER_TRAILING_BYTES) begin + assert (o.USER_WIDTH >= o.TRAILING_WIDTH) else + $fatal("o.USER_WIDTH does not match TRAILING_WIDTH"); + end else begin + assert (!o.TUSER) else + $fatal("This module does not pass generic user_data"); + end + + assert (i.TLAST == 1) else + $fatal("i.TLAST not present"); + assert (o.TLAST == 1) else + $fatal("o.TLAST not present"); + end + + AxiStreamPacketIf #(.DATA_WIDTH(i.DATA_WIDTH),.USER_WIDTH(i.USER_WIDTH), + .TDATA(i.TDATA),.TKEEP(i.TKEEP),.TUSER(i.TUSER),.TLAST(i.TLAST), + .MAX_PACKET_BYTES(i.MAX_PACKET_BYTES)) + s0(i.clk,i.rst); + AxiStreamPacketIf #(.DATA_WIDTH(o.DATA_WIDTH),.USER_WIDTH(o.USER_WIDTH), + .TDATA(o.TDATA),.TKEEP(o.TKEEP),.TUSER(o.TUSER),.TLAST(o.TLAST), + .MAX_PACKET_BYTES(o.MAX_PACKET_BYTES)) + s1(o.clk,o.rst); + + // move from AxiStreamIfc to AxiStreamPacketIf + always_comb begin + `AXI4S_ASSIGN(s0,i) + end + // move from AxiStreamPacketIf to AxiStreamIfc + always_comb begin + `AXI4S_ASSIGN(o,s1) + end + + logic [IWIDTH/8-1:0] s0_tkeep; + + if (s0.TKEEP) begin + always_comb s0_tkeep = s0.tkeep; + end else if (I_USER_TRAILING_BYTES) begin + always_comb s0_tkeep = s0.get_trailing_bytes(); + end else begin + always_comb s0_tkeep = '1; + end + + logic [OWIDTH/8-1:0] s1_tkeep; + logic [15:0] s1_bytes; + + if (s1.TKEEP) begin + always_comb s1.tkeep = s1_tkeep; + always_comb s1.tuser = 'X; + end else if (O_USER_TRAILING_BYTES) begin + always_comb s1.tkeep = 'X; + always_comb begin : assign_s1_tuser + s1.tuser = 0; + // MODELSIM_BUG - deleting the s1_bytes assignment causes modelsim failures. + s1_bytes = s1.keep2trailing(s1_tkeep); + s1.set_trailing_bytes(s1_tkeep); + end + end else begin + always_comb s1.tkeep = 'X; + always_comb s1.tuser = 'X; + end + + logic s0_ready, s1_valid, s1_last; + logic [s1.DATA_WIDTH-1:0] s1_data; + always_comb s0.tready = s0_ready; + always_comb s1.tvalid = s1_valid; + always_comb s1.tlast = s1_last; + always_comb s1.tdata = s1_data; + + axis_width_conv #( + .IN_WORDS(IWIDTH/8), .OUT_WORDS(OWIDTH/8), + .SYNC_CLKS(SYNC_CLKS), .PIPELINE(PIPELINE) + ) axis_width_conv ( + .s_axis_aclk(s0.clk), .s_axis_rst(s0.rst), + .s_axis_tdata(s0.tdata), .s_axis_tkeep(s0_tkeep), .s_axis_tlast(s0.tlast), + .s_axis_tvalid(s0.tvalid), .s_axis_tready(s0_ready), + + .m_axis_aclk(s1.clk), .m_axis_rst(s1.rst), + .m_axis_tdata(s1_data), .m_axis_tkeep(s1_tkeep), .m_axis_tlast(s1_last), + .m_axis_tvalid(s1_valid), .m_axis_tready(s1.tready) + ); + +endmodule : axi4s_width_conv |