同步fifo的设计不涉及异步问题,我们可以直接用计数器来保存存储器中数据的个数,这里要注意的是只读或者只写时count才有变化,并且在写满之后计数器的值不能再增加,读空同理。
基本步骤就是:1、添加写信号,读信号 2、设计计数器 3、设计写满、读空信号4、地址、数据处理
module syn_fifo(
input wire clk,
input wire rstn,
input wire r_en,
input wire w_en,
input wire [7:0] cin,
output wire w_full,
output wire r_empty,
output reg [7:0] q
);
reg [7:0] mem [255:0];
reg [7:0]count;
wire wr,rd;
reg [7:0] wr_addr;
reg [7:0] rd_addr;
//空满标志
assign w_full = (count == 8'd255) ?1'd1:1'd0;
assign r_empty = (count == 8'd0) ?1'd1:1'd0;
//读写标志
assign rd = r_en && (~r_empty);
assign wr = w_en && (~w_full);
//计数器
always @(posedge clk or negedge rstn)
if(!rstn)
count<=1'd0;
else if(wr && (~rd) && (count<=8'd255))
count<=count+1'd1;
else if(rd && (~wr) && (count>=1'd0))
count<=count-1'd1;
else
count<=count;
//写地址及写数据
always @(posedge clk or negedge rstn)
if(!rstn)
wr_addr<=1'd0;
else if(wr)begin
wr_addr<=wr_addr+1'd1;
mem[wr_addr]<=cin;
end
else begin
wr_addr<=wr_addr;
mem[wr_addr]<=mem[wr_addr];
end
//读地址及读数据
always @(posedge clk or negedge rstn)
if(!rstn)
rd_addr<=1'd0;
else if(rd)begin
rd_addr<=rd_addr+1'd1;
q<=mem[rd_addr];
end
else begin
rd_addr<=rd_addr;
q<=1'd0;
end
endmodule
下面是对应的tb文件及部分仿真结果:
同步fifo的设计不涉及异步问题,我们可以直接用计数器来保存存储器中数据的个数,这里要注意的是只读或者只写时count才有变化,并且在写满之后计数器的值不能再增加,读空同理。
基本步骤就是:1、添加写信号,读信号 2、设计计数器 3、设计写满、读空信号4、地址、数据处理
module syn_fifo(
input wire clk,
input wire rstn,
input wire r_en,
input wire w_en,
input wire [7:0] cin,
output wire w_full,
output wire r_empty,
output reg [7:0] q
);
reg [7:0] mem [255:0];
reg [7:0]count;
wire wr,rd;
reg [7:0] wr_addr;
reg [7:0] rd_addr;
//空满标志
assign w_full = (count == 8'd255) ?1'd1:1'd0;
assign r_empty = (count == 8'd0) ?1'd1:1'd0;
//读写标志
assign rd = r_en && (~r_empty);
assign wr = w_en && (~w_full);
//计数器
always @(posedge clk or negedge rstn)
if(!rstn)
count<=1'd0;
else if(wr && (~rd) && (count<=8'd255))
count<=count+1'd1;
else if(rd && (~wr) && (count>=1'd0))
count<=count-1'd1;
else
count<=count;
//写地址及写数据
always @(posedge clk or negedge rstn)
if(!rstn)
wr_addr<=1'd0;
else if(wr)begin
wr_addr<=wr_addr+1'd1;
mem[wr_addr]<=cin;
end
else begin
wr_addr<=wr_addr;
mem[wr_addr]<=mem[wr_addr];
end
//读地址及读数据
always @(posedge clk or negedge rstn)
if(!rstn)
rd_addr<=1'd0;
else if(rd)begin
rd_addr<=rd_addr+1'd1;
q<=mem[rd_addr];
end
else begin
rd_addr<=rd_addr;
q<=1'd0;
end
endmodule
下面是对应的tb文件及部分仿真结果:
`timescale 1ns/1ns
`define clk_period 20
module syn_fifo_tb;
reg clk;
reg rstn;
reg w_en;
reg r_en;
reg [7:0] cin;
wire w_full;
wire r_empty;
wire [7:0] q;
initial begin
clk=1'd0;
rstn=1'd0;
w_en=1'd0;
r_en=1'd0;
cin=1'd0;
#20;
rstn=1'd1;
write;
read;
end
task write;
integer i;
begin
for(i=0;i<257;i=i+1)begin
w_en = 1'd1;
@(posedge clk);
cin={$random}%256;
end
w_en=1'd0;
end
endtask
task read;
integer i;
begin
for(i=0;i<257;i=i+1)begin
r_en=1'd1;
@(posedge clk);
end
r_en=1'd0;
end
endtask
always #10 clk=~clk;
syn_fifo syn_fifo(
.clk ( clk ),
.rstn ( rstn ),
.r_en ( r_en ),
.w_en ( w_en ),
.cin ( cin ),
.w_full ( w_full ),
.r_empty ( r_empty ),
.q ( q )
);
endmodule