aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/axi4s_sv/axi4s_width_conv.sv
blob: c2bd0c3a2acb8da506e6295c9f26061a5b152059 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//
// 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.slave   i,  // AxiStreamIf or AxiStreamPacketIf
   interface.master  o   // AxiStreamIf or AxiStreamPacketIf
);

  `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 [i.DATA_WIDTH/8-1:0] s0_tkeep;
  always_comb begin
    if (s0.TKEEP) begin
      s0_tkeep = s0.tkeep;
    end else if (I_USER_TRAILING_BYTES) begin
      s0_tkeep = s0.get_trailing_bytes();
    end else begin
      s0_tkeep = '1;
    end
  end

  logic [o.DATA_WIDTH/8-1:0] s1_tkeep;
  logic [15:0] s1_bytes;

  always_comb begin
    if (s1.TKEEP) begin
      s1.tkeep = s1_tkeep;
      s1.tuser = 'X;
    end else if (O_USER_TRAILING_BYTES) begin
      s1.tuser = 0;
      s1_bytes = s1.keep2trailing(s1_tkeep);
      s1.set_trailing_bytes(s1_tkeep);
    end else begin
      s1.tkeep = 'X;
      s1.tuser = 'X;
    end
  end

  logic s0_ready, s1_valid, s1_last;
  logic [o.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(i.DATA_WIDTH/8), .OUT_WORDS(o.DATA_WIDTH/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