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
136
137
138
139
140
141
142
143
144
145
146
|
/////////////////////////////////////////////////////////////////////
//
// Copyright 2018 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: chdr_framer_2clk
// Description:
// - Takes a sample stream in and uses the tuser input to frame
// a CHDR packet which is output by the module
// samples at the output
// - FIXME Currently only 32 / 64-bit input widths are supported.
//
/////////////////////////////////////////////////////////////////////
module chdr_framer_2clk #(
parameter SIZE = 10,
parameter WIDTH = 32, // 32 or 64 only! TODO: Extend to other widths.
parameter USE_SEQ_NUM = 0 // Use provided seq number in tuser
) (
input samp_clk, input samp_rst, input pkt_clk, input pkt_rst,
input [WIDTH-1:0] i_tdata, input [127:0] i_tuser, input i_tlast, input i_tvalid, output i_tready,
output [63:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
);
wire header_i_tvalid, header_i_tready;
wire [63:0] body_i_tdata;
wire body_i_tlast, body_i_tvalid, body_i_tready;
wire [127:0] header_o_tdata;
wire header_o_tvalid, header_o_tready;
wire [63:0] body_o_tdata;
wire body_o_tlast, body_o_tvalid, body_o_tready;
reg [15:0] length;
reg [11:0] seqnum;
assign i_tready = header_i_tready & body_i_tready;
assign header_i_tvalid = i_tlast & i_tvalid & i_tready;
assign body_i_tlast = i_tlast;
// Handle 32 and 64 widths
generate
if (WIDTH == 32) begin
reg even = 1'b0;
always @(posedge samp_clk)
if(samp_rst)
even <= 1'b0;
else
if(i_tvalid & i_tready)
if(i_tlast)
even <= 1'b0;
else
even <= ~even;
reg [31:0] held_i_tdata;
always @(posedge samp_clk) begin
if (i_tvalid & i_tready) held_i_tdata <= i_tdata;
end
assign body_i_tvalid = i_tvalid & i_tready & (i_tlast | even);
assign body_i_tdata = even ? { held_i_tdata, i_tdata } : {i_tdata, i_tdata}; // really should be 0 in bottom, but this simplifies mux
end else begin
assign body_i_tvalid = i_tvalid & i_tready;
assign body_i_tdata = i_tdata;
end
endgenerate
// FIXME handle lengths of partial 32-bit words
always @(posedge samp_clk)
if (samp_rst)
length <= (WIDTH == 32) ? 16'd4 : 16'd8;
else if(header_i_tready & header_i_tvalid)
length <= (WIDTH == 32) ? 16'd4 : 16'd8;
else if(i_tvalid & i_tready)
length <= (WIDTH == 32) ? length + 16'd4 : length + 16'd8;
// Extended reset signal to ensure longer reset on axi_fifo_2clk
// as recommended by Xilinx. It clears all partial packets seen
// after clearing the fifos.
// This pulse stretch ratio works in this case and may not work
// for all clocks.
wire samp_rst_stretch;
pulse_stretch #(.SCALE('d10)) samp_reset_i (
.clk(samp_clk),
.rst(1'b0),
.pulse(samp_rst),
.pulse_stretched(samp_rst_stretch)
);
axi_fifo_2clk #(.WIDTH(128), .SIZE(5)) hdr_fifo_i (
.i_aclk(samp_clk), .o_aclk(pkt_clk), .reset(samp_rst_stretch),
.i_tdata({i_tuser[127:112],length,i_tuser[95:0]}), .i_tvalid(header_i_tvalid), .i_tready(header_i_tready),
.o_tdata(header_o_tdata), .o_tvalid(header_o_tvalid), .o_tready(header_o_tready)
);
axi_fifo_2clk #(.WIDTH(65), .SIZE(SIZE)) body_fifo_i (
.i_aclk(samp_clk), .o_aclk(pkt_clk), .reset(samp_rst_stretch),
.i_tdata({body_i_tlast,body_i_tdata}), .i_tvalid(body_i_tvalid), .i_tready(body_i_tready),
.o_tdata({body_o_tlast,body_o_tdata}), .o_tvalid(body_o_tvalid), .o_tready(body_o_tready)
);
reg [1:0] chdr_state;
localparam [1:0] ST_IDLE = 0;
localparam [1:0] ST_HEAD = 1;
localparam [1:0] ST_TIME = 2;
localparam [1:0] ST_BODY = 3;
always @(posedge pkt_clk)
if(pkt_rst)
chdr_state <= ST_IDLE;
else
case(chdr_state)
ST_IDLE :
if(header_o_tvalid & body_o_tvalid)
chdr_state <= ST_HEAD;
ST_HEAD :
if(o_tready)
if(header_o_tdata[125]) // time
chdr_state <= ST_TIME;
else
chdr_state <= ST_BODY;
ST_TIME :
if(o_tready)
chdr_state <= ST_BODY;
ST_BODY :
if(o_tready & body_o_tlast)
chdr_state <= ST_IDLE;
endcase
always @(posedge pkt_clk)
if(pkt_rst)
seqnum <= 12'd0;
else
if(o_tvalid & o_tready & o_tlast)
seqnum <= seqnum + 12'd1;
wire [15:0] out_length = header_o_tdata[111:96] + (header_o_tdata[125] ? 16'd16 : 16'd8);
assign o_tvalid = (chdr_state == ST_HEAD) | (chdr_state == ST_TIME) | (body_o_tvalid & (chdr_state == ST_BODY));
assign o_tlast = (chdr_state == ST_BODY) & body_o_tlast;
assign o_tdata = (chdr_state == ST_HEAD) ? {header_o_tdata[127:124], (USE_SEQ_NUM == 1 ? header_o_tdata[123:112] : seqnum), out_length, header_o_tdata[95:64] } :
(chdr_state == ST_TIME) ? header_o_tdata[63:0] :
body_o_tdata;
assign body_o_tready = (chdr_state == ST_BODY) & o_tready;
assign header_o_tready = ((chdr_state == ST_TIME) | ((chdr_state == ST_HEAD) & ~header_o_tdata[125])) & o_tready;
endmodule
|