1//
2// Copyright 2020 Ettus Research, a National Instruments Brand
3//
4// SPDX-License-Identifier: LGPL-3.0-or-later
5//
6// Description:
7//   System Verilog wrapper for axis_width_conv that accepts a AxiStreamIfc
8//   with slave_user/master_user interface. This block requires that the
9//   bottom bits of user contain the number of bytes in the last word.
10//
11//   If TKEEP - tkeep contains byte_enables
12//   If USER_TRAILING_BYTES - tuser contains byte_enables
13//   Else everything is a full word
14//
15// Parameters:
16//   PIPELINE  - Add pipelining for timing.
17//   SYNC_CLKS - Input and output clock are the same.
18//   I_USER_TRAILING_BYTES - input byte_enable is set by user
19//   O_USER_TRAILING_BYTES - output byte_enable is set in user
20//
21
22module axi4s_width_conv #(
23         PIPELINE  = "NONE",
24  bit    I_USER_TRAILING_BYTES = 0,
25  bit    O_USER_TRAILING_BYTES = 0,
26  bit    SYNC_CLKS = 1
27) (
28   interface   i,  // AxiStreamIf or AxiStreamPacketIf
29   interface   o   // AxiStreamIf or AxiStreamPacketIf
30);
31
32  localparam IWIDTH =i.DATA_WIDTH;
33  localparam OWIDTH =o.DATA_WIDTH;
34
35  `include "axi4s.vh"
36  // Parameter Checks
37  initial begin
38    if(i.TKEEP) begin
39      assert (!I_USER_TRAILING_BYTES) else
40        $fatal("I_USER_TRAILING_BYTE set at the same time as TKEEP");
41      assert (!i.TUSER) else
42        $fatal("i.TUSER set- This module does not pass user");
43    end else if(I_USER_TRAILING_BYTES) begin
44      assert (i.USER_WIDTH >= i.TRAILING_WIDTH ) else
45        $fatal("i.USER_WIDTH does not match TRAILING_WIDTH");
46    end else begin
47      assert (!i.TUSER) else
48        $fatal("This module does not pass generic user_data");
49    end
50
51    if(o.TKEEP) begin
52      assert (!O_USER_TRAILING_BYTES) else
53        $fatal("O_USER_TRAILING_BYTE set at the same time as TKEEP");
54      assert (!o.TUSER) else
55        $fatal("O.TUSER set- This module does not pass user");
56    end else if(O_USER_TRAILING_BYTES) begin
57      assert (o.USER_WIDTH >= o.TRAILING_WIDTH) else
58        $fatal("o.USER_WIDTH does not match TRAILING_WIDTH");
59    end else begin
60      assert (!o.TUSER) else
61        $fatal("This module does not pass generic user_data");
62    end
63
64    assert (i.TLAST == 1) else
65      $fatal("i.TLAST not present");
66    assert (o.TLAST == 1) else
67      $fatal("o.TLAST not present");
68  end
69
70  AxiStreamPacketIf #(.DATA_WIDTH(i.DATA_WIDTH),.USER_WIDTH(i.USER_WIDTH),
71    .TDATA(i.TDATA),.TKEEP(i.TKEEP),.TUSER(i.TUSER),.TLAST(i.TLAST),
72    .MAX_PACKET_BYTES(i.MAX_PACKET_BYTES))
73    s0(i.clk,i.rst);
74  AxiStreamPacketIf #(.DATA_WIDTH(o.DATA_WIDTH),.USER_WIDTH(o.USER_WIDTH),
75    .TDATA(o.TDATA),.TKEEP(o.TKEEP),.TUSER(o.TUSER),.TLAST(o.TLAST),
76    .MAX_PACKET_BYTES(o.MAX_PACKET_BYTES))
77    s1(o.clk,o.rst);
78
79  // move from AxiStreamIfc to AxiStreamPacketIf
80  always_comb begin
81    `AXI4S_ASSIGN(s0,i)
82  end
83  // move from AxiStreamPacketIf to AxiStreamIfc
84  always_comb begin
85    `AXI4S_ASSIGN(o,s1)
86  end
87
88  logic [IWIDTH/8-1:0] s0_tkeep;
89
90  if (s0.TKEEP) begin
91    always_comb s0_tkeep = s0.tkeep;
92  end else if (I_USER_TRAILING_BYTES) begin
93    always_comb s0_tkeep = s0.get_trailing_bytes();
94  end else begin
95    always_comb s0_tkeep = '1;
96  end
97
98  logic [OWIDTH/8-1:0] s1_tkeep;
99  logic [15:0] s1_bytes;
100
101  if (s1.TKEEP) begin
102    always_comb s1.tkeep = s1_tkeep;
103    always_comb s1.tuser = 'X;
104  end else if (O_USER_TRAILING_BYTES) begin
105    always_comb  s1.tkeep = 'X;
106    always_comb begin : assign_s1_tuser
107      s1.tuser = 0;
108      // MODELSIM_BUG - deleting the s1_bytes assignment causes modelsim failures.
109      s1_bytes = s1.keep2trailing(s1_tkeep);
110      s1.set_trailing_bytes(s1_tkeep);
111    end
112  end else begin
113    always_comb s1.tkeep = 'X;
114    always_comb s1.tuser = 'X;
115  end
116
117  logic s0_ready, s1_valid, s1_last;
118  logic [s1.DATA_WIDTH-1:0] s1_data;
119  always_comb s0.tready = s0_ready;
120  always_comb s1.tvalid = s1_valid;
121  always_comb s1.tlast  = s1_last;
122  always_comb s1.tdata  = s1_data;
123
124  axis_width_conv #(
125    .IN_WORDS(IWIDTH/8), .OUT_WORDS(OWIDTH/8),
126    .SYNC_CLKS(SYNC_CLKS), .PIPELINE(PIPELINE)
127  ) axis_width_conv (
128    .s_axis_aclk(s0.clk), .s_axis_rst(s0.rst),
129    .s_axis_tdata(s0.tdata), .s_axis_tkeep(s0_tkeep), .s_axis_tlast(s0.tlast),
130    .s_axis_tvalid(s0.tvalid), .s_axis_tready(s0_ready),
131
132    .m_axis_aclk(s1.clk), .m_axis_rst(s1.rst),
133    .m_axis_tdata(s1_data), .m_axis_tkeep(s1_tkeep), .m_axis_tlast(s1_last),
134    .m_axis_tvalid(s1_valid), .m_axis_tready(s1.tready)
135  );
136
137endmodule : axi4s_width_conv
138