Files
b210-k7-fpga/lib/axi4s_sv/axi4s_width_conv.sv
T
Andrew Moch 23be04661f 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
2020-06-25 14:44:04 -05:00

138 lines
4.4 KiB
Systemverilog

//
// 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