同步FIFO--方法一:以计数原则判断FIFO空满
使用计数器对写入的数据个数进行计数,进而实现FIFO的空满判断。调用一个双端口RAM,以地址的方式对RAM深度进行编码。例如RAM深度为16,则地址为4位。
module sync_fifo_1(clk,rst,w_en,r_en,w_data,r_data,empty,full,Fcounter);
parameter DATA_WIDTH=8;
parameter ADDR_WIDTH=9;
input clk;
input rst;
input w_en;
input r_en;
input [DATA_WIDTH-1:0]w_data;
output [DATA_WIDTH-1:0]r_data;
output empty;
output full;
output [ADDR_WIDTH-1:0]Fcounter;
reg empty;
reg full;
reg [ADDR_WIDTH-1:0]Fcounter;
wire [DATA_WIDTH-1:0]r_data;
reg [ADDR_WIDTH-1:0]w_addr;
reg [ADDR_WIDTH-1:0]r_addr;
wire rd=(r_en && !empty);
wire we=(w_en && !full);
ram_dual u1(
//Input
.d(w_data),
.addr_in(w_addr),
.rd(rd),
.clk1(clk),
.clk2(clk),
.we(we),
//output
.addr_out(r_addr),
.r_data(r_data));
always @(posedge clk or negedge rst)
begin
if(!rst)
empty<=1'b1;
else
empty<=(!w_en && Fcounter[8:1]==8'h0)&&(r_en||Fcounter[0]==0);
end
always @(posedge clk or negedge rst)
begin
if(!rst)
full<=1'b0;
else
full<=(w_en || Fcounter[0]==1'b1)&&(!r_en && Fcounter[8:1]==8'hF);
end
always @(posedge clk or negedge rst)
begin
if(!rst)
w_addr<=9'b0;
else if(!full && w_en)
w_addr<=w_addr+1'b1;
end
always @(posedge clk or negedge rst)
begin
if(!rst)
r_addr<=9'b0;
else if(!empty && r_en)
r_addr<=r_addr+1'b1;
end
always @(posedge clk or negedge rst)
begin
if(!rst)
Fcounter<=9'b0;
else if((w_en && !r_en)||(!w_en && r_en))
begin
if(w_en)
Fcounter<=Fcounter+1'b1;
else
Fcounter<=Fcounter-1'b1;
end
end
endmodule
module ram_dual(
//Input
d,
addr_in,
rd,
clk1,
clk2,
we,
//output
addr_out,
r_data);
input [7:0]d;
input [8:0]addr_in;
input rd;
input clk1;
input clk2;
input we;
input [8:0]addr_out;
output [7:0]r_data;
reg [7:0]r_data;
reg [7:0]mem[511:0];
always @(posedge clk1)
begin
if(we && !rd)
mem[addr_in]<=d;
end
always @(posedge clk2)
begin
if(rd && !we)
r_data<=mem[addr_out];
end
endmodule
module sync_fifo_1_tb;
reg clk;
reg rst;
reg w_en;
reg r_en;
reg [7:0]w_data;
wire [7:0]r_data;
wire [8:0]Fcounter;
wire full;
wire empty;
sync_fifo_1 u2(clk,rst,w_en,r_en,w_data,r_data,empty,full,Fcounter);
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
r_en=0;
#650 w_en=0;r_en=1;
end
always #20 clk=~clk;
initial
begin
$vcdpluson;
end
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