同步fifo
框图
下图为深度为4的fifo写示意图。当wr_ptr = rd_ptr时,要么fifo为空(最开始状态),要么fifo为满(最后状态)
判断空满方法一
使用计数器(counter)记录读写操作,当(wr_en & !rd_end) == 1时,只写不读,计数器加1;当(!wr_en & rd_end) == 1时,只读不写,计数器加1;其他情况下,计数器的值不变。
判断fifo_full
当 counter 的值等于fifo的深度时,fifo为满。
判断fifo_empty
当 counter的值等于0时,fifo为空。
Verilog实现
module syn_fifo_1#(parameter WIDTH = 8, DEPTH = 8)(
input clk,
input rst_n,
input wr_en,
input [WIDTH-1 : 0] wr_data,
input rd_en,
output reg [WIDTH-1 : 0] rd_data,
output fifo_full,
output fifo_empty
);
reg [WIDTH-1 : 0] buffer [0 : DEPTH -1];
reg [$clog2(WIDTH)-1 : 0] rd_ptr;
reg [$clog2(WIDTH)-1 : 0] wr_ptr;
reg [$clog2(WIDTH) : 0] counter;
//keep track of counter
always @(posedge clk) begin
if(!rst_n)
counter <= 0;
else begin
if(wr_en && !rd_en)
counter <= counter + 1;
else begin
if(rd_en && !wr_en)
counter <= counter - 1;
else
counter <= counter;
end
end
end
//keep track of wr_ptr
always @(posedge clk) begin
if(!rst_n)
wr_ptr <= 0;
else begin
if(wr_en && !fifo_full) begin
if(wr_ptr == DEPTH-1)
wr_ptr <= 0;
else
wr_ptr <= wr_ptr + 1;
end
else
wr_ptr <= wr_ptr;
end
end
//keep track of rd_ptr
always @(posedge clk) begin
if(!rst_n)
rd_ptr <= 0;
else begin
if(rd_en && !fifo_empty) begin
if(rd_ptr == DEPTH-1)
rd_ptr <= 0;
else
rd_ptr <= rd_ptr + 1;
end
else
rd_ptr <= rd_ptr;
end
end
// write data into buffer when wr_en asserted at the posedege of clk
always @(posedge clk) begin
if(wr_en)
buffer[wr_ptr] <= wr_data;
end
//read data when rd_en asserted
always @(posedge clk) begin
if(rd_en)
rd_data <= buffer[rd_ptr];
else
rd_data <= 'hz;
end
//assign rd_data = rd_en? buffer[rd_ptr]:'hz;
assign fifo_full = (counter == DEPTH)? 1 : 0;
assign fifo_empty = (counter == 0)?1:0;
endmodule
TB实现
module tb();
parameter WIDTH = 8;
parameter DEPTH = 8;
reg clk;
reg rst_n;
//write port
reg wr_en;
reg [WIDTH - 1 : 0] wr_data;
wire fifo_full;
//read port
reg rd_en;
wire [WIDTH - 1 : 0] rd_data;
wire fifo_empty;
initial begin
clk = 0;
forever begin
#5 clk = ~clk;
end
end
initial begin
rst_n = 1;
wr_en = 0;
rd_en = 0;
@(negedge clk) rst_n = 0;
@(negedge clk) rst_n = 1;
//write 4 data to fifo
@(negedge clk) wr_en = 1;
wr_data = $random;
repeat(3) begin
@(negedge clk)
wr_data = $random;
end
@(negedge clk)
wr_en = 0;
rd_en = 1;
//read 3 data from fifo
repeat(3) begin
@(negedge clk);
end
//write 7 data to fifo
@(negedge clk)
rd_en = 0;
wr_en = 1;
wr_data = $random;
repeat(7) begin
@(negedge clk)
wr_data = $random;
end
#20 $finish;
end
initial begin
$fsdbDumpvars();
end
syn_fifo_1 #(.WIDTH(WIDTH),.DEPTH(DEPTH))
DUT(.clk (clk),
.rst_n (rst_n),
.wr_en (wr_en),
.wr_data (wr_data),
.fifo_full (fifo_full),
.rd_en (rd_en),
.rd_data (rd_data),
.fifo_empty (fifo_empty)
);
endmodule
波形
判断空满方法二
判断fifo_full
当为写操作,且写指针下一个时钟指向的地址等于目前的读指针时,fifo_full拉高
if(wr_en && (rd_ptr == wr_ptr +1))
fifo_full = 1
判断fifo_empty
当为读操作,且读指针下一个时钟指向的地址等于目前的写指针时,fifo_full拉高
if(rd_en && (wr_ptr == rd_ptr +1))
fifo_empty = 1
Verilog实现
module syn_fifo_2#(parameter WIDTH = 8, DEPTH = 8)(
input clk,
input rst_n,
input wr_en,
input [WIDTH-1 : 0] wr_data,
input rd_en,
output reg [WIDTH-1 : 0] rd_data,
output reg fifo_full,
output reg fifo_empty
);
reg [WIDTH-1 : 0] buffer [0 : DEPTH -1];
reg [$clog2(WIDTH)-1 : 0] rd_ptr;
reg [$clog2(WIDTH)-1 : 0] wr_ptr;
//keep track of wr_ptr
always @(posedge clk) begin
if(!rst_n)
wr_ptr <= 0;
else begin
if(wr_en && !fifo_full) begin
if(wr_ptr == DEPTH-1)
wr_ptr <= 0;
else
wr_ptr <= wr_ptr + 1;
end
else
wr_ptr <= wr_ptr;
end
end
//keep track of rd_ptr
always @(posedge clk) begin
if(!rst_n)
rd_ptr <= 0;
else begin
if(rd_en && !fifo_empty) begin
if(rd_ptr == DEPTH-1)
rd_ptr <= 0;
else
rd_ptr <= rd_ptr + 1;
end
else
rd_ptr <= rd_ptr;
end
end
// write data into buffer when wr_en asserted at the posedege of clk
always @(posedge clk) begin
if(wr_en)
buffer[wr_ptr] <= wr_data;
end
//read data when rd_en asserted
always @(posedge clk) begin
if(rd_en)
rd_data <= buffer[rd_ptr];
else
rd_data <= 'hz;
end
//assign rd_data = rd_en? buffer[rd_ptr]:'hz;
//assign fifo_full = (wr_en && (rd_ptr == wr_ptr +1))? 1 : 0;
always @(posedge clk) begin
if(!rst_n)
fifo_full <= 0;
else begin
if(wr_en && (rd_ptr == wr_ptr +1))
fifo_full <= 1;
else
fifo_full <= 0;
end
end
//assign fifo_empty = (rd_en && (wr_ptr == rd_ptr +1))?1:0;
always @(posedge clk) begin
if(!rst_n)
fifo_empty <= 0;
else
if(rd_en && (wr_ptr == rd_ptr +1))
fifo_empty<= 1;
else
fifo_empty <= 0;
end
endmodule
TB实现
module tb();
parameter WIDTH = 8;
parameter DEPTH = 8;
reg clk;
reg rst_n;
//write port
reg wr_en;
reg [WIDTH - 1 : 0] wr_data;
wire fifo_full;
//read port
reg rd_en;
wire [WIDTH - 1 : 0] rd_data;
wire fifo_empty;
initial begin
clk = 0;
forever begin
#5 clk = ~clk;
end
end
initial begin
rst_n = 1;
wr_en = 0;
rd_en = 0;
@(negedge clk) rst_n = 0;
@(negedge clk) rst_n = 1;
//write 4 data to fifo
@(negedge clk) wr_en = 1;
wr_data = $random;
repeat(3) begin
@(negedge clk)
wr_data = $random;
end
@(negedge clk)
wr_en = 0;
rd_en = 1;
//read 3 data from fifo
repeat(3) begin
@(negedge clk);
end
//write 7 data to fifo
@(negedge clk)
rd_en = 0;
wr_en = 1;
wr_data = $random;
repeat(7) begin
@(negedge clk)
wr_data = $random;
end
#20 $finish;
end
initial begin
$fsdbDumpvars();
end
syn_fifo_2 #(.WIDTH(WIDTH),.DEPTH(DEPTH))
DUT(.clk (clk),
.rst_n (rst_n),
.wr_en (wr_en),
.wr_data (wr_data),
.fifo_full (fifo_full),
.rd_en (rd_en),
.rd_data (rd_data),
.fifo_empty (fifo_empty)
);
endmodule
波形
判断空满方法三
拓展一位读写指针的位宽
判断fifo_full
当读写指针的最高位不同,其余为相同时,fifo_full为高。
判断fifo_empty
当读写指针的所有位都相同时,fifo_empty为高。
Verilog实现
module syn_fifo_3#(parameter WIDTH = 8, DEPTH = 8)(
input clk,
input rst_n,
input wr_en,
input [WIDTH-1 : 0] wr_data,
input rd_en,
output reg [WIDTH-1 : 0] rd_data,
output fifo_full,
output fifo_empty
);
reg [WIDTH-1 : 0] buffer [0 : DEPTH -1];
parameter P_WIDTH = $clog2(WIDTH);
reg [P_WIDTH : 0] rd_ptr;
reg [P_WIDTH : 0] wr_ptr;
//keep track of wr_ptr
always @(posedge clk) begin
if(!rst_n)
wr_ptr <= 0;
else begin
if(wr_en && !fifo_full) begin
wr_ptr <= wr_ptr + 1;
end
else
wr_ptr <= wr_ptr;
end
end
//keep track of rd_ptr
always @(posedge clk) begin
if(!rst_n)
rd_ptr <= 0;
else begin
if(rd_en && !fifo_empty) begin
rd_ptr <= rd_ptr + 1;
end
else
rd_ptr <= rd_ptr;
end
end
// write data into buffer when wr_en asserted at the posedege of clk
always @(posedge clk) begin
if(wr_en)
buffer[wr_ptr] <= wr_data;
end
//read data when rd_en asserted
always @(posedge clk) begin
if(rd_en)
rd_data <= buffer[rd_ptr];
else
rd_data <= 'hz;
end
//assign rd_data = rd_en? buffer[rd_ptr]:'hz;
assign fifo_full = ((rd_ptr[P_WIDTH] ^ wr_ptr[P_WIDTH]) && (rd_ptr[P_WIDTH-1 :0 ] == wr_ptr[P_WIDTH-1 : 0]))? 1 : 0;
assign fifo_empty = (rd_ptr == wr_ptr)? 1 : 0;
endmodule
TB实现
module tb();
parameter WIDTH = 8;
parameter DEPTH = 8;
reg clk;
reg rst_n;
//write port
reg wr_en;
reg [WIDTH - 1 : 0] wr_data;
wire fifo_full;
//read port
reg rd_en;
wire [WIDTH - 1 : 0] rd_data;
wire fifo_empty;
initial begin
clk = 0;
forever begin
#5 clk = ~clk;
end
end
initial begin
rst_n = 1;
wr_en = 0;
rd_en = 0;
@(negedge clk) rst_n = 0;
@(negedge clk) rst_n = 1;
//write 4 data to fifo
@(negedge clk) wr_en = 1;
wr_data = $random;
repeat(3) begin
@(negedge clk)
wr_data = $random;
end
@(negedge clk)
wr_en = 0;
rd_en = 1;
//read 3 data from fifo
repeat(3) begin
@(negedge clk);
end
//write 7 data to fifo
@(negedge clk)
rd_en = 0;
wr_en = 1;
wr_data = $random;
repeat(7) begin
@(negedge clk)
wr_data = $random;
end
#20 $finish;
end
initial begin
$fsdbDumpvars();
end
syn_fifo_3 #(.WIDTH(WIDTH),.DEPTH(DEPTH))
DUT(.clk (clk),
.rst_n (rst_n),
.wr_en (wr_en),
.wr_data (wr_data),
.fifo_full (fifo_full),
.rd_en (rd_en),
.rd_data (rd_data),
.fifo_empty (fifo_empty)
);
endmodule