aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/rfnoc/utils/chdr_pad_packet.v
blob: 14d63fe7458585a202b0ddd4fdd94a6723d52aae (plain)
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 2019 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: chdr_pad_packet
// Description:
//  This module pads extra data on the AXI-Stream bus
//  to the requested packet size. This module is for
//  creating len-sized packets, for DMA engines that
//  do not support partial transfers.
//
// Parameters:
//  - CHDR_W: Width of the CHDR tdata bus in bits
//
// Signals:
//  - s_axis_* : Input AXI-Stream CHDR bus
//  - m_axis_* : Output AXI-Stream CHDR bus
//  - len      : Requested number of CHDR_W lines in the packet (must be > 1)

`default_nettype none
module chdr_pad_packet #(
  parameter CHDR_W = 256
)(
  input  wire              clk,
  input  wire              rst,
  input  wire [15:0]       len,
  input  wire [CHDR_W-1:0] s_axis_tdata,
  input  wire              s_axis_tlast,
  input  wire              s_axis_tvalid,
  output reg               s_axis_tready,
  output wire [CHDR_W-1:0] m_axis_tdata,
  output reg               m_axis_tlast,
  output reg               m_axis_tvalid,
  input  wire              m_axis_tready
);

  localparam [1:0] ST_HEADER = 2'd0;
  localparam [1:0] ST_BODY   = 2'd1;
  localparam [1:0] ST_PAD    = 2'd2;
  localparam [1:0] ST_DROP   = 2'd3;

  reg [1:0]   state;
  reg [15:0]  lines_left;

  always @(posedge clk) begin
    if (rst || (len <= 16'd1)) begin
      state <= ST_HEADER;
    end else begin
      case(state)
        ST_HEADER: begin
          lines_left <= len - 16'd1;
          if (s_axis_tvalid && m_axis_tready) begin
              if (!s_axis_tlast) begin
                // Packet is more than one line and length not reached
                state <= ST_BODY;
              end else begin
                // Packet is only one line and length not reached
                state <= ST_PAD;
              end
          end
        end
        ST_BODY: begin
          if (s_axis_tvalid && m_axis_tready) begin
            lines_left <= lines_left - 16'd1;
            if (s_axis_tlast && (lines_left == 16'd1)) begin
              // End of input and reached length
              state <= ST_HEADER;
            end else if (s_axis_tlast && (lines_left != 16'd1)) begin
              // End of input, but length not reached
              state <= ST_PAD;
            end else if (!s_axis_tlast && (lines_left == 16'd1)) begin
              // Reached length, but input continues...
              state <= ST_DROP;
            end
          end
        end
        ST_PAD: begin
          if (m_axis_tready) begin
            lines_left <= lines_left - 16'd1;
            if (lines_left == 16'd1) begin
              state <= ST_HEADER;
            end
          end
        end
        ST_DROP: begin
          if (s_axis_tvalid && s_axis_tlast) begin
            state <= ST_HEADER;
          end
        end
        default: begin
          // We should never get here
          state <= ST_HEADER;
        end
      endcase
    end
  end

  assign m_axis_tdata  = s_axis_tdata;

  always @(*) begin
    case(state)
      ST_HEADER: begin
        if (len <= 16'd1) begin
          s_axis_tready <= 1'b0;
          m_axis_tvalid <= 1'b0;
        end else begin
          s_axis_tready <= m_axis_tready;
          m_axis_tvalid <= s_axis_tvalid;
        end
        m_axis_tlast <= 1'b0;
      end
      ST_BODY: begin
        s_axis_tready <= m_axis_tready;
        m_axis_tvalid <= s_axis_tvalid;
        m_axis_tlast  <= (lines_left == 16'd1);
      end
      ST_PAD: begin
        s_axis_tready <= 1'b0;
        m_axis_tvalid <= 1'b1;
        m_axis_tlast  <= (lines_left == 16'd1);
      end
      ST_DROP: begin
        s_axis_tready <= 1'b1;
        m_axis_tvalid <= 1'b0;
        m_axis_tlast  <= 1'b0;
      end
    endcase
  end

endmodule // chdr_pad_packet
`default_nettype wire