aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/packet_proc/chdr_chunker.v
blob: 434919466bd249f535f198a35df6520cc93ac5e4 (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
133
134
135
//
// Copyright 2013 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
// Copyright 2019 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//

// Quantize chdr packets to a configurable quantum value. o_tlast and
// i_tready will be held off until the entire quantized packet is xferred.
// If quantum is changed, it is the responsibility of the client to clear
// this module. error is asserted if a packet is larger than the quantum
// error can be reset by asserting reset or clear.

`default_nettype none
module chdr_chunker # (
   parameter PAD_VALUE = 64'hFFFFFFFF_FFFFFFFF,
             HOLD_ERROR = 1'b1 // If high, hold error until reset, else pulse
) (
   input wire          clk,
   input wire          reset,
   input wire          clear,
   input wire [15:0]   frame_size,

   input wire [63:0]   i_tdata,
   input wire          i_tlast,
   input wire          i_tvalid,
   output reg          i_tready,

   output wire [63:0]  o_tdata,
   output wire         o_tlast,
   output reg          o_tvalid,
   input  wire         o_tready,

   output wire         error
);

   localparam ST_HEADER  = 2'd0;
   localparam ST_DATA    = 2'd1;
   localparam ST_PADDING = 2'd2;
   localparam ST_ERROR   = 2'd3;

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

   // axi_len = ceil(length / 8)
   wire [15:0] chdr_len_ceil = i_tdata[31:16] + 16'd7;
   wire [15:0] axi_len = {3'b000, chdr_len_ceil[15:3]};

   always @(posedge clk) begin
      if (reset | clear) begin
         state <= ST_HEADER;
         frame_rem <= 16'd0;
      end else if ((state == ST_ERROR) & i_tlast & i_tvalid & !HOLD_ERROR) begin
         state <= ST_HEADER;
         frame_rem <= 16'd0;
      end else if (o_tready) begin
         case (state)
            ST_HEADER: begin
               if (i_tvalid) begin
                  if ((axi_len > frame_size) | (axi_len == 16'd0))
                     state <= ST_ERROR;
                  else if (i_tlast)
                     state <= ST_PADDING;
                  else
                     state <= ST_DATA;

                  frame_rem <= frame_size - 16'd1;
               end
            end

            ST_DATA: begin
               if (i_tvalid) begin
                  if (i_tlast) begin
                     state   <= o_tlast ? ST_HEADER : ST_PADDING;
                     frame_rem <= o_tlast ? 16'd0 : (frame_rem - 16'd1);
                  end else begin
                     state <= ST_DATA;
                     frame_rem <= frame_rem - 16'd1;
                  end
               end
            end

            ST_PADDING: begin
               if (o_tlast) begin
                  state   <= ST_HEADER;
                  frame_rem <= 16'd0;
               end else begin
                  state   <= ST_PADDING;
                  frame_rem <= frame_rem - 16'd1;
               end
            end

         endcase
      end
   end

   always @(*) begin
      case (state)
         ST_HEADER: begin
            i_tready = o_tready;
            o_tvalid = (axi_len <= frame_size) & (axi_len > 16'd0) & i_tvalid;
         end

         ST_DATA: begin
            i_tready = o_tready;
            o_tvalid = i_tvalid;
         end

         ST_PADDING: begin
            i_tready = 1'b0;
            o_tvalid = 1'b1;
         end

         ST_ERROR: begin
            i_tready = 1'b1;
            o_tvalid = 1'b0;
         end

         default: begin
            i_tready = 1'b0;
            o_tvalid = 1'b0;
         end
      endcase
   end

   assign o_tlast = (frame_rem != 16'd0) ? (frame_rem == 16'd1) : (axi_len == 16'd1);
   assign o_tdata = (state == ST_PADDING) ? PAD_VALUE : i_tdata;

   assign error = (state == ST_ERROR);

endmodule // chdr_chunker

`default_nettype wire