因為FIFO的特點為先入先出,則寫入FIFO的起始地址均為0,讀取地址也從0開始,當讀地址與寫地址相同時,則可判斷FIFO為空,當讀地址與寫地址除最高位相反,其他位相同時,則可判斷FIFO為滿 -- 假設RAM深度為8,擴展后的地址為4位。開始寫入4個數據,此時寫地址為0100,讀地址此時為0000;然后開始讀數據,讀完4個數據后,讀地址此時為0100,此時可判斷FIFO為空,后對FIFO進行寫數據,連續寫入8個數據,此時寫地址為1100,已知深度為8,判斷FIFO為滿,此時的寫讀地址比較發現:最高位相反,其余位相同。
module sync_fifo_2(clk,rst,w_en,r_en,w_data,r_data,full,empty);
input clk;
input rst;
input w_en;
input r_en;
input [7:0]w_data;
output [7:0]r_data;
output full;
output empty;
wire full,empty;
reg [7:0]r_data;
reg [7:0]mem[15:0];
wire [3:0]w_addr_a,r_addr_a;
reg [4:0]w_addr_e,r_addr_e;
assign w_addr_a=w_addr_e[3:0];
assign r_addr_a=r_addr_e[3:0];
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
r_addr_e<=5'b0;
end
else
begin
if(empty==0 && r_en==1)
begin
r_data<=mem[r_addr_a];
r_addr_e<=r_addr_e+1;
end
end
end
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
w_addr_e<=5'b0;
end
else
begin
if(full==0 && w_en==1)
begin
mem[w_addr_a]<=w_data;
w_addr_e<=w_addr_e+1;
end
end
end
assign empty=(r_addr_e==w_addr_e)?1:0;
assign full=(r_addr_e[4]!=w_addr_e[4] && r_addr_e[3:0]==w_addr_e[3:0])?1:0;//空信號較易判斷,滿信號需要判斷最高位和其他位
endmodule
tb:
`timescale 1ns/1ps
module sync_fifo_2_tb;
reg clk;
reg rst;
reg w_en;
reg r_en;
reg [7:0]w_data;
wire [7:0]r_data;
wire full;
wire empty;
sync_fifo_2 u1(clk,rst,w_en,r_en,w_data,r_data,full,empty);
initial
begin
rst=1;
clk=0;
#1 rst=0;
#5 rst=1;
end
initial
begin
w_en=0;
#1 w_en=1;
end
initial
begin
$vcdpluson;
end
initial
begin
r_en=0;
#650 r_en=1;w_en=0;
end
always #20 clk=~clk;
initial
begin
w_data=8'h0;
#40 w_data=8'h1;
#40 w_data=8'h2;
#40 w_data=8'h3;
#40 w_data=8'h4;
#40 w_data=8'h5;
#40 w_data=8'h6;
#40 w_data=8'h7;
#40 w_data=8'h8;
#40 w_data=8'h9;
#40 w_data=8'ha;
#40 w_data=8'hb;
#40 w_data=8'hc;
#40 w_data=8'hd;
#40 w_data=8'he;
#40 w_data=8'hf;
#700 $finish;
end
endmodule