11/*
22
3- Copyright (c) 2013-2017 Alex Forencich
3+ Copyright (c) 2013-2018 Alex Forencich
44
55Permission is hereby granted, free of charge, to any person obtaining a copy
66of this software and associated documentation files (the "Software"), to deal
@@ -32,90 +32,223 @@ THE SOFTWARE.
3232module 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+
60118reg [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;
61120reg [ADDR_WIDTH:0 ] wr_addr_reg = {ADDR_WIDTH+ 1 {1'b0 }};
62121reg [ADDR_WIDTH:0 ] rd_ptr_reg = {ADDR_WIDTH+ 1 {1'b0 }}, rd_ptr_next;
63122reg [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;
67126reg 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
75134wire 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
78139wire 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
81145reg write;
82146reg read;
83147reg 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
93179always @* 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
106223end
107224
108225always @(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
120253end
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
161294always @* 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
170303end
171304
172305always @(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
182315end
183316
0 commit comments