同步FIFO的意思是说FIFO的读写时钟是同一个时钟,因此时钟频率是相同的,只是在相位上可能有差别,不同于异步FIFO,异步FIFO的读写时钟是完全异步的。同步FIFO的对外接口包括时钟,清零,读请求,写请求,数据输入总线,数据输出总线,空以及满信号。下面分别对同步FIFO的对外接口信号作一描述:
Ø 1. 时钟,用于同步FIFO的读和写,上升沿有效。
Ø 2. 清零,异步清零信号,低电平有效,该信号有效时,FIFO被清空。
Ø 3. 写请求,低电平有效,该信号有效时,表明外部电路请求向FIFO写入数据。
Ø 4. 读请求,低电平有效,该信号有效时,表明外部电路请求从FIFO中读取数据。
Ø 5. 数据输入总线,当写信号有效时,数据输入总线上的数据被写入到FIFO中。
Ø 6. 数据输出总线,当读信号有效时,数据从FIFO中被读出并放到数据输出总线上。
Ø 7. 空,当该信号为高电平,表明FIFO中没有任何数据,全部为空。
Ø 8. 满,当该信号为高电平,表明FIFO已经满了,没有空间可用来存贮数据。
为了更好的理解FIFO的工作方式,我们设定同步FIFO的数据宽度(bit位)为任意,深度为8。同步FIFO的难点主要是状态判断,下面就来看看如何对空状态和满状态来进行判断。
可以看出,当读指针read_pointer和写指针write_pointer的值一样的时候,FIFO的状态为空。比较麻烦的是对FIFO是否已经满的状态的判断,因为存在两种情况,第一种情况时写指针write_pointer比读指针read_pointer大,比如写指针writer_pointer = 7而读指针read_pointer = 0,还有一种情况时写指针writer_pointer比读指针read_pointer小,比如写指针writer_pointer = 2而读指针read_pointer = 3。由于读写电路在循环的读写RAM,所以在上面的两种情况下FIFO实际上都已经满了。那么如何对读写指针的判断比较容易的得出FIFO已经满了,同时这样的判断电路还要容易参数化?
附上verilog代码及相应test_bench,在modelsim上仿真通过!
fifo.v
module syn_fifo(
clock,
reset_n,
read_n,
write_n,
data_in,
data_out,
full,
empty
);
parameter DATA_WIDTH = 8 ;
parameter DATA_DEPTH = 8;
parameter DATA_PTR_WIDTH = 3 ;
input clock ;
input reset_n ;
input read_n ;
input write_n ;
input [DATA_WIDTH-1:0] data_in ;
output[DATA_WIDTH-1:0] data_out;
output full ;
output empty ;
wire clock ;
wire reset_n ;
wire read_n ;
wire write_n ;
wire[DATA_WIDTH-1:0] data_in ;
reg [DATA_WIDTH-1:0] data_out;
wire full ;
wire empty ;
reg[DATA_PTR_WIDTH :0] counter ;
reg[DATA_PTR_WIDTH-1:0] rd_pointer;
reg[DATA_PTR_WIDTH-1:0] wr_pointer;
reg[DATA_WIDTH -1:0] fifo_mem[0:DATA_DEPTH-1];
assign full = (counter == DATA_DEPTH) ? 1'b1 : 1'b0;
assign empty = (counter == 0) ? 1'b1 : 1'b0;
always @(posedge clock)begin
if(reset_n) begin
rd_pointer <= 0;
wr_pointer <= 0;
counter <= 0;
end
if(read_n && (~write_n) && (~empty)) begin
counter <= counter-1;
data_out <= fifo_mem[rd_pointer];
rd_pointer <= rd_pointer+1;
end
if((~read_n) && write_n && (~full)) begin
counter <= counter+1;
fifo_mem[wr_pointer] <= data_in;
wr_pointer <= wr_pointer+1;
end
end
endmodule
fifo_tb.v
//fifo testbench
`define DEL 1
module fifo_tb;
parameter DATA_WIDTH = 8 ;
parameter DATA_DEPTH = 16;
reg clock ;
reg reset_n ;
reg read_n ; // read data to data_out from fifo_mem
reg write_n ; // write data in fifo_mem from data_in
reg [DATA_WIDTH-1:0] data_in ;
wire[DATA_WIDTH-1:0] data_out;
wire full ;
wire empty ;
integer fifo_count;
//实例化 syn_fifo 模块
/*
syn_fifo syn_fifo_1(
.clock(clock),
.reset_n(reset_n),
.read_n(read_n),
.write_n(write_n),
.data_in(data_in),
.data_out(data_out),
.full(full),
.empty(empty)
);
*/
syn_fifo syn_fifo_2(
clock,
reset_n,
read_n,
write_n,
data_in,
data_out,
full,
empty
);
initial begin
data_in=255;
fifo_count=0;
read_n=0;
write_n=1;
clock=1;
reset_n=1;
#4 reset_n=0;
end
always #10 clock = ~clock;
always @(posedge clock && (~reset_n)) begin
if(write_n && ~read_n)begin
fifo_count <= fifo_count+1;
data_in <= data_in+1;end
else if(~write_n && read_n)begin
fifo_count <= fifo_count-1;
end
end
always@(negedge clock) begin //negedge
if (full)begin
read_n <= 1;
write_n <= 0;end
else if (empty)begin
read_n <= 0;
write_n <= 1;
end
end
//dump fsdb file for debussy
initial begin
$fsdbDumpfile("wave.fsdb");
$fsdbDumpvars;
end
endmodule