Skip to content

Commit fc25907

Browse files
committed
Update AXI stream FIFO
1 parent 5a1fd48 commit fc25907

File tree

3 files changed

+309
-103
lines changed

3 files changed

+309
-103
lines changed

rtl/axis_fifo.v

Lines changed: 170 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
3-
Copyright (c) 2013-2017 Alex Forencich
3+
Copyright (c) 2013-2018 Alex Forencich
44
55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal
@@ -32,90 +32,223 @@ THE SOFTWARE.
3232
module axis_fifo #
3333
(
3434
parameter ADDR_WIDTH = 12,
35-
parameter DATA_WIDTH = 8
35+
parameter DATA_WIDTH = 8,
36+
parameter KEEP_ENABLE = (DATA_WIDTH>8),
37+
parameter KEEP_WIDTH = (DATA_WIDTH/8),
38+
parameter LAST_ENABLE = 1,
39+
parameter ID_ENABLE = 0,
40+
parameter ID_WIDTH = 8,
41+
parameter DEST_ENABLE = 0,
42+
parameter DEST_WIDTH = 8,
43+
parameter USER_ENABLE = 1,
44+
parameter USER_WIDTH = 1,
45+
parameter PIPELINE_OUTPUT = 1,
46+
parameter FRAME_FIFO = 0,
47+
parameter USER_BAD_FRAME_VALUE = 1'b1,
48+
parameter USER_BAD_FRAME_MASK = 1'b1,
49+
parameter DROP_BAD_FRAME = 0,
50+
parameter DROP_WHEN_FULL = 0
3651
)
3752
(
3853
input wire clk,
3954
input wire rst,
40-
55+
4156
/*
4257
* AXI input
4358
*/
44-
input wire [DATA_WIDTH-1:0] input_axis_tdata,
45-
input wire input_axis_tvalid,
46-
output wire input_axis_tready,
47-
input wire input_axis_tlast,
48-
input wire input_axis_tuser,
49-
59+
input wire [DATA_WIDTH-1:0] s_axis_tdata,
60+
input wire [KEEP_WIDTH-1:0] s_axis_tkeep,
61+
input wire s_axis_tvalid,
62+
output wire s_axis_tready,
63+
input wire s_axis_tlast,
64+
input wire [ID_WIDTH-1:0] s_axis_tid,
65+
input wire [DEST_WIDTH-1:0] s_axis_tdest,
66+
input wire [USER_WIDTH-1:0] s_axis_tuser,
67+
5068
/*
5169
* AXI output
5270
*/
53-
output wire [DATA_WIDTH-1:0] output_axis_tdata,
54-
output wire output_axis_tvalid,
55-
input wire output_axis_tready,
56-
output wire output_axis_tlast,
57-
output wire output_axis_tuser
71+
output wire [DATA_WIDTH-1:0] m_axis_tdata,
72+
output wire [KEEP_WIDTH-1:0] m_axis_tkeep,
73+
output wire m_axis_tvalid,
74+
input wire m_axis_tready,
75+
output wire m_axis_tlast,
76+
output wire [ID_WIDTH-1:0] m_axis_tid,
77+
output wire [DEST_WIDTH-1:0] m_axis_tdest,
78+
output wire [USER_WIDTH-1:0] m_axis_tuser,
79+
80+
/*
81+
* Status
82+
*/
83+
output wire status_overflow,
84+
output wire status_bad_frame,
85+
output wire status_good_frame
5886
);
5987

88+
// check configuration
89+
initial begin
90+
if (FRAME_FIFO && !LAST_ENABLE) begin
91+
$error("Error: FRAME_FIFO set requires LAST_ENABLE set");
92+
$finish;
93+
end
94+
95+
if (DROP_BAD_FRAME && !FRAME_FIFO) begin
96+
$error("Error: DROP_BAD_FRAME set requires FRAME_FIFO set");
97+
$finish;
98+
end
99+
100+
if (DROP_WHEN_FULL && !FRAME_FIFO) begin
101+
$error("Error: DROP_WHEN_FULL set requires FRAME_FIFO set");
102+
$finish;
103+
end
104+
105+
if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin
106+
$error("Error: Invalid USER_BAD_FRAME_MASK value");
107+
$finish;
108+
end
109+
end
110+
111+
localparam KEEP_OFFSET = DATA_WIDTH;
112+
localparam LAST_OFFSET = KEEP_OFFSET + (KEEP_ENABLE ? KEEP_WIDTH : 0);
113+
localparam ID_OFFSET = LAST_OFFSET + (LAST_ENABLE ? 1 : 0);
114+
localparam DEST_OFFSET = ID_OFFSET + (ID_ENABLE ? ID_WIDTH : 0);
115+
localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0);
116+
localparam WIDTH = USER_OFFSET + (USER_ENABLE ? USER_WIDTH : 0);
117+
60118
reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
119+
reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_cur_next;
61120
reg [ADDR_WIDTH:0] wr_addr_reg = {ADDR_WIDTH+1{1'b0}};
62121
reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
63122
reg [ADDR_WIDTH:0] rd_addr_reg = {ADDR_WIDTH+1{1'b0}};
64123

65-
reg [DATA_WIDTH+2-1:0] mem[(2**ADDR_WIDTH)-1:0];
66-
reg [DATA_WIDTH+2-1:0] mem_read_data_reg = {DATA_WIDTH+2{1'b0}};
124+
reg [WIDTH-1:0] mem[(2**ADDR_WIDTH)-1:0];
125+
reg [WIDTH-1:0] mem_read_data_reg;
67126
reg mem_read_data_valid_reg = 1'b0, mem_read_data_valid_next;
68-
wire [DATA_WIDTH+2-1:0] mem_write_data;
69127

70-
reg [DATA_WIDTH+2-1:0] output_data_reg = {DATA_WIDTH+2{1'b0}};
128+
wire [WIDTH-1:0] s_axis;
71129

72-
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
130+
reg [WIDTH-1:0] m_axis_reg;
131+
reg m_axis_tvalid_reg = 1'b0, m_axis_tvalid_next;
73132

74133
// full when first MSB different but rest same
75134
wire full = ((wr_ptr_reg[ADDR_WIDTH] != rd_ptr_reg[ADDR_WIDTH]) &&
76135
(wr_ptr_reg[ADDR_WIDTH-1:0] == rd_ptr_reg[ADDR_WIDTH-1:0]));
136+
wire full_cur = ((wr_ptr_cur_reg[ADDR_WIDTH] != rd_ptr_reg[ADDR_WIDTH]) &&
137+
(wr_ptr_cur_reg[ADDR_WIDTH-1:0] == rd_ptr_reg[ADDR_WIDTH-1:0]));
77138
// empty when pointers match exactly
78139
wire empty = wr_ptr_reg == rd_ptr_reg;
140+
// overflow within packet
141+
wire full_wr = ((wr_ptr_reg[ADDR_WIDTH] != wr_ptr_cur_reg[ADDR_WIDTH]) &&
142+
(wr_ptr_reg[ADDR_WIDTH-1:0] == wr_ptr_cur_reg[ADDR_WIDTH-1:0]));
79143

80144
// control signals
81145
reg write;
82146
reg read;
83147
reg store_output;
84148

85-
assign input_axis_tready = ~full;
149+
reg drop_frame_reg = 1'b0, drop_frame_next;
150+
reg overflow_reg = 1'b0, overflow_next;
151+
reg bad_frame_reg = 1'b0, bad_frame_next;
152+
reg good_frame_reg = 1'b0, good_frame_next;
153+
154+
assign s_axis_tready = FRAME_FIFO ? (!full_cur || full_wr || DROP_WHEN_FULL) : !full;
86155

87-
assign output_axis_tvalid = output_axis_tvalid_reg;
156+
generate
157+
assign s_axis[DATA_WIDTH-1:0] = s_axis_tdata;
158+
if (KEEP_ENABLE) assign s_axis[KEEP_OFFSET +: KEEP_WIDTH] = s_axis_tkeep;
159+
if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast;
160+
if (ID_ENABLE) assign s_axis[ID_OFFSET +: ID_WIDTH] = s_axis_tid;
161+
if (DEST_ENABLE) assign s_axis[DEST_OFFSET +: DEST_WIDTH] = s_axis_tdest;
162+
if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = s_axis_tuser;
163+
endgenerate
88164

89-
assign mem_write_data = {input_axis_tlast, input_axis_tuser, input_axis_tdata};
90-
assign {output_axis_tlast, output_axis_tuser, output_axis_tdata} = output_data_reg;
165+
assign m_axis_tvalid = m_axis_tvalid_reg;
166+
167+
assign m_axis_tdata = m_axis_reg[DATA_WIDTH-1:0];
168+
assign m_axis_tkeep = KEEP_ENABLE ? m_axis_reg[KEEP_OFFSET +: KEEP_WIDTH] : {KEEP_WIDTH{1'b1}};
169+
assign m_axis_tlast = LAST_ENABLE ? m_axis_reg[LAST_OFFSET] : 1'b1;
170+
assign m_axis_tid = ID_ENABLE ? m_axis_reg[ID_OFFSET +: ID_WIDTH] : {ID_WIDTH{1'b0}};
171+
assign m_axis_tdest = DEST_ENABLE ? m_axis_reg[DEST_OFFSET +: DEST_WIDTH] : {DEST_WIDTH{1'b0}};
172+
assign m_axis_tuser = USER_ENABLE ? m_axis_reg[USER_OFFSET +: USER_WIDTH] : {USER_WIDTH{1'b0}};
173+
174+
assign status_overflow = overflow_reg;
175+
assign status_bad_frame = bad_frame_reg;
176+
assign status_good_frame = good_frame_reg;
91177

92178
// Write logic
93179
always @* begin
94180
write = 1'b0;
95181

182+
drop_frame_next = 1'b0;
183+
overflow_next = 1'b0;
184+
bad_frame_next = 1'b0;
185+
good_frame_next = 1'b0;
186+
96187
wr_ptr_next = wr_ptr_reg;
188+
wr_ptr_cur_next = wr_ptr_cur_reg;
97189

98-
if (input_axis_tvalid) begin
99-
// input data valid
100-
if (~full) begin
101-
// not full, perform write
190+
if (s_axis_tready && s_axis_tvalid) begin
191+
// transfer in
192+
if (!FRAME_FIFO) begin
193+
// normal FIFO mode
102194
write = 1'b1;
103195
wr_ptr_next = wr_ptr_reg + 1;
196+
end else if (full_cur || full_wr || drop_frame_reg) begin
197+
// full, packet overflow, or currently dropping frame
198+
// drop frame
199+
drop_frame_next = 1'b1;
200+
if (s_axis_tlast) begin
201+
// end of frame, reset write pointer
202+
wr_ptr_cur_next = wr_ptr_reg;
203+
drop_frame_next = 1'b0;
204+
overflow_next = 1'b1;
205+
end
206+
end else begin
207+
write = 1'b1;
208+
wr_ptr_cur_next = wr_ptr_cur_reg + 1;
209+
if (s_axis_tlast) begin
210+
// end of frame
211+
if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & s_axis_tuser == USER_BAD_FRAME_VALUE)) begin
212+
// bad packet, reset write pointer
213+
wr_ptr_cur_next = wr_ptr_reg;
214+
bad_frame_next = 1'b1;
215+
end else begin
216+
// good packet, update write pointer
217+
wr_ptr_next = wr_ptr_cur_reg + 1;
218+
good_frame_next = 1'b1;
219+
end
220+
end
104221
end
105222
end
106223
end
107224

108225
always @(posedge clk) begin
109226
if (rst) begin
110227
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
228+
wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}};
229+
230+
drop_frame_reg <= 1'b0;
231+
overflow_reg <= 1'b0;
232+
bad_frame_reg <= 1'b0;
233+
good_frame_reg <= 1'b0;
111234
end else begin
112235
wr_ptr_reg <= wr_ptr_next;
236+
wr_ptr_cur_reg <= wr_ptr_cur_next;
237+
238+
drop_frame_reg <= drop_frame_next;
239+
overflow_reg <= overflow_next;
240+
bad_frame_reg <= bad_frame_next;
241+
good_frame_reg <= good_frame_next;
113242
end
114243

115-
wr_addr_reg <= wr_ptr_next;
244+
if (FRAME_FIFO) begin
245+
wr_addr_reg <= wr_ptr_cur_next;
246+
end else begin
247+
wr_addr_reg <= wr_ptr_next;
248+
end
116249

117250
if (write) begin
118-
mem[wr_addr_reg[ADDR_WIDTH-1:0]] <= mem_write_data;
251+
mem[wr_addr_reg[ADDR_WIDTH-1:0]] <= s_axis;
119252
end
120253
end
121254

@@ -127,9 +260,9 @@ always @* begin
127260

128261
mem_read_data_valid_next = mem_read_data_valid_reg;
129262

130-
if (store_output | ~mem_read_data_valid_reg) begin
263+
if (store_output || !mem_read_data_valid_reg) begin
131264
// output data not valid OR currently being transferred
132-
if (~empty) begin
265+
if (!empty) begin
133266
// not empty, perform read
134267
read = 1'b1;
135268
mem_read_data_valid_next = 1'b1;
@@ -161,23 +294,23 @@ end
161294
always @* begin
162295
store_output = 1'b0;
163296

164-
output_axis_tvalid_next = output_axis_tvalid_reg;
297+
m_axis_tvalid_next = m_axis_tvalid_reg;
165298

166-
if (output_axis_tready | ~output_axis_tvalid) begin
299+
if (m_axis_tready || !m_axis_tvalid) begin
167300
store_output = 1'b1;
168-
output_axis_tvalid_next = mem_read_data_valid_reg;
301+
m_axis_tvalid_next = mem_read_data_valid_reg;
169302
end
170303
end
171304

172305
always @(posedge clk) begin
173306
if (rst) begin
174-
output_axis_tvalid_reg <= 1'b0;
307+
m_axis_tvalid_reg <= 1'b0;
175308
end else begin
176-
output_axis_tvalid_reg <= output_axis_tvalid_next;
309+
m_axis_tvalid_reg <= m_axis_tvalid_next;
177310
end
178311

179312
if (store_output) begin
180-
output_data_reg <= mem_read_data_reg;
313+
m_axis_reg <= mem_read_data_reg;
181314
end
182315
end
183316

0 commit comments

Comments
 (0)