blob: a8be9edb1eccb7f6c9cfa71b85f453a67befef79 [file] [log] [blame]
// description
// the multi_fifo is a sync fifo mmodule with some specified features
// features:
// 1. multi push at a time
// 2. multi pop at a time
// 3. parameterize push/pop number with arbitrary value
// 4. output all fifo data and sort them based on read pointer
// 5. output write pointer and read pointer
// constraints:
// 1. do not support push&pop when fifo is full
module multi_fifo
(
// global
clk,
rst_n,
// push side
push,
datain,
full,
almost_full,
// pop side
pop,
dataout,
empty,
almost_empty,
// fifo info
clear,
fifo_data,
wptr,
rptr,
entry_count
);
// ---parameter definition--------------------------------------------
parameter type T = logic [7:0]; // data structure
parameter M = 4; // push signal width
parameter N = 4; // pop signal width
parameter DEPTH = 16; // fifo depth
parameter POP_CLEAR = 1'b0; // clear data once pop
parameter ASYNC_RSTN = 1'b0; // reset data
parameter CHAOS_PUSH = 1'b0; // support push data disorderly
parameter DATAOUT_REG = 1'b0; // dataout signal register output.
localparam DEPTH_BITS = $clog2(DEPTH);
// ---port definition-------------------------------------------------
input logic clk;
input logic rst_n;
input logic [M-1:0] push; // M bits indicates M push operation(s).
input T [M-1:0] datain;
output logic full;
output logic [M-1:0] almost_full; // almost_full[0]==1 - full
// almost_full[1]==1 - The remaining free spaces <=1
// almost_full[M-1]==1 - The remaining free spaces <=M-1
input logic [N-1:0] pop; // N bits indicates N pop operation(s).
output T [N-1:0] dataout;
output logic empty;
output logic [N-1:0] almost_empty; // almost_empty[0]==1 - empty
// almost_empty[1]==1 - The remaining quantity of valid data <= 1
// almost_empty[N-1]==1 - The remaining quantity of valid data <= N-1
input logic clear;
output T [DEPTH-1:0] fifo_data; // sort based on rptr
output logic [DEPTH_BITS-1:0] wptr; // write pointer
output logic [DEPTH_BITS-1:0] rptr; // read pointer
output logic [DEPTH_BITS :0] entry_count; // the number of occupied entry.
// ---internal signal definition--------------------------------------
T mem[DEPTH-1:0];
logic entry_count_en;
logic [DEPTH_BITS :0] next_entry_count;
logic [DEPTH_BITS :0] push_count;
logic [DEPTH_BITS :0] pop_count;
logic [DEPTH_BITS-1:0] next_wptr;
logic [DEPTH_BITS-1:0] next_rptr;
logic [DEPTH_BITS-1:0] wind_rptr [DEPTH-1:0];
logic [DEPTH_BITS-1:0] wind_wptr [DEPTH-1:0];
logic [M-1:0] push_seq;
T [M-1:0] datain_seq;
// ---code start------------------------------------------------------
genvar i;
integer l,k;
// fifo status
// valid data count
assign next_entry_count = entry_count + push_count - pop_count;
assign entry_count_en = (|push) | (|pop);
cdffr #(.T(logic[DEPTH_BITS:0])) u_entry_count_reg (.q(entry_count), .c(clear), .e(entry_count_en), .d(next_entry_count), .clk(clk), .rst_n(rst_n));
// full
assign full = (entry_count == DEPTH);
assign almost_full[0] = full;
generate
for (i=1; i<M; i++) begin : gen_almost_full
assign almost_full[i] = (entry_count + i >= DEPTH);
end
endgenerate
// empty
assign empty = (entry_count == '0);
assign almost_empty[0] = empty;
generate
for (i=1; i<N; i++) begin : gen_almost_empty
assign almost_empty[i] = (entry_count <= i);
end
endgenerate
generate
for (i=0; i<DEPTH; i++) begin : gen_fifo_data
assign fifo_data[i] = mem[wind_rptr[i]];
end
endgenerate
// wind back rptr/wptr
generate
for (i=0; i<DEPTH; i++) begin : gen_wind_ptr
assign wind_rptr[i] = rptr+i;
assign wind_wptr[i] = wptr+i;
end
endgenerate
// dataout
always_comb begin
pop_count = pop[0];
for (int j=1; j<N; j++) pop_count = pop_count + pop[j];
end
assign next_rptr = rptr + pop_count;
cdffr #(.T(logic[DEPTH_BITS-1:0])) u_rptr_reg (.q(rptr), .c(clear), .e(|pop), .d(next_rptr), .clk(clk), .rst_n(rst_n));
generate
if(DATAOUT_REG) begin
logic [DEPTH_BITS:0] remain_count;
logic [N-1:0][DEPTH_BITS-1:0] current_rptr_mem; // pick data from fifo to output
logic [N-1:0][DEPTH_BITS-1:0] current_rptr_psh; // when fifo is empty, pick the pushing data
assign remain_count = entry_count-pop_count;
for (i=0; i<N; i++) begin : gen_rptr
assign current_rptr_mem[i] = next_rptr+i;
assign current_rptr_psh[i] = i-remain_count;
end
if (CHAOS_PUSH) begin
for (i=0; i<N; i++) begin : gen_dataout
always_ff @(posedge clk) begin
if ((i<remain_count)&(|pop))
dataout[i] <= mem[current_rptr_mem[i]];
else if ((push_seq[current_rptr_psh[i]]&(current_rptr_psh[i]<M))&((|pop)|(|push_seq)))
dataout[i] <= datain_seq[current_rptr_psh[i]];
end
end
end else begin
for (i=0; i<N; i++) begin : gen_dataout
always_ff @(posedge clk) begin
if ((i<remain_count)&(|pop))
dataout[i] <= mem[current_rptr_mem[i]];
else if ((push[current_rptr_psh[i]]&(current_rptr_psh[i]<M))&((|pop)|(|push)))
dataout[i] <= datain[current_rptr_psh[i]];
end
end
end
end
else begin
for (i=0; i<N; i++) begin : gen_dataout
assign dataout[i] = mem[wind_rptr[i]];
end
end
endgenerate
// datain
always_comb begin
push_count = push[0];
for (int j=1; j<M; j++) push_count = push_count + push[j];
end
assign next_wptr = wptr + push_count;
cdffr #(.T(logic[DEPTH_BITS-1:0])) u_wptr_reg (.q(wptr), .c(clear), .e(|push), .d(next_wptr), .clk(clk), .rst_n(rst_n));
generate
if (CHAOS_PUSH) begin
always_comb begin
push_seq = '0;
datain_seq = '0;
l = 0;
for (k=0; k<M; k++) begin
if (push[k]) begin
push_seq[l] = 1'b1;
datain_seq[l] = datain[k];
l++;
end
end
end
end else begin
assign push_seq = push;
assign datain_seq = datain;
end
endgenerate
generate
if (ASYNC_RSTN)
if (POP_CLEAR) begin
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n)
for (int j=0; j<DEPTH; j++) begin
mem[j] <= '0;
end
else begin
if (push_seq[0] && !full) mem[wptr] <= datain_seq[0];
for (int j=1; j<M; j++) begin
if (push_seq[j] && !almost_full[j]) mem[wind_wptr[j]] <= datain_seq[j];
end
if (clear) begin
for (int j=0; j<DEPTH; j++) begin
mem[j] <= '0;
end
end else begin
for (int j=0; j<N; j++) begin
if (pop[j]) mem[wind_rptr[j]] <= '0;
end
end
end
end
end else begin
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n)
for (int j=0; j<DEPTH; j++) begin
mem[j] <= '0;
end
else begin
if (push_seq[0] && !full) mem[wptr] <= datain_seq[0];
for (int j=1; j<M; j++) begin
if (push_seq[j] && !almost_full[j]) mem[wind_wptr[j]] <= datain_seq[j];
end
end
end
end
else
if (POP_CLEAR) begin
always_ff @(posedge clk) begin
if (push_seq[0] && !full) mem[wptr] <= datain_seq[0];
for (int j=1; j<M; j++) begin
if (push_seq[j] && !almost_full[j]) mem[wind_wptr[j]] <= datain_seq[j];
end
if (clear) begin
for (int j=0; j<DEPTH; j++) begin
mem[j] <= '0;
end
end else begin
for (int j=0; j<N; j++) begin
if (pop[j]) mem[wind_rptr[j]] <= '0;
end
end
end
end else begin
always_ff @(posedge clk) begin
if (push_seq[0] && !full) mem[wptr] <= datain_seq[0];
for (int j=1; j<M; j++) begin
if (push_seq[j] && !almost_full[j]) mem[wind_wptr[j]] <= datain_seq[j];
end
end
end
endgenerate
`ifdef ASSERT_ON
// test for overflow
assert property (@(posedge clk) disable iff (!rst_n) not ( push_seq[0] && full))
else $error("MULTI_FIFO: overflow of fifo when push_seq[0] and full");
generate
for (i=1; i<M; i++) begin
assert property (@(posedge clk) disable iff (!rst_n) not ( push_seq[i] && almost_full[i]))
else $error("MULTI_FIFO: overflow of fifo when push_seq[%d] and almost_full[%d]", i, i);
end
endgenerate
// test for underflow
assert property (@(posedge clk) disable iff (!rst_n) not ( pop[0] && empty))
else $error("MULTI_FIFO: underflow of fifo when pop[0] and empty");
generate
for (i=1; i<N; i++) begin
assert property (@(posedge clk) disable iff (!rst_n) not ( pop[i] && almost_empty[i]))
else $error("MULTI_FIFO: underflow of fifo when pop[%d] and almost_empty[%d]", i, i);
end
endgenerate
`endif
endmodule