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
|