verilog实现异步FIFO代码总结
一、概述
前面的文章总结了FIFO的基本原理和整体设计框图,下面将具体的verilog实现FIFO的代码总结如下。
参考之前的设计框图,主要分成了w_fifo_ctrl、r_fifo_ctrl和sig_dp_ram三个文件(模块)。
二、写FIFO控制模块
w_fifo_ctrl模块的verilog实现代码如下:
//写FIFO控制模块
module w_fifo_ctrl(
input wire w_clk,
input wire rst_n,
input wire w_en, //写使能
input wire [8:0] r_gaddr,//接收到的读FIFO地址的格雷编码
output reg [8:0] w_addr, //写FIFO地址
output reg [8:0] w_gaddr,//写FIFO地址的格雷编码
output reg w_full //写满信号
);
wire [8:0] w_addr_line;
wire [8:0] w_gaddr_line;
reg [26:0] r_gaddr_delay;
//接收到的读FIFO地址的格雷编码再打两拍,降低亚稳态
always@(posedge w_clk or negedge rst_n)
begin
if(rst_n==1'b0)
r_gaddr_delay[26:0]<=27'd0;
else
r_gaddr_delay[26:0]<={r_gaddr_delay[17:0],r_gaddr[8:0]};
end
//assign w_full=({~r_gaddr_delay[26],~r_gaddr_delay[25],r_gaddr_delay[24:18]}==w_gaddr[8:0])?1:0;
always@(posedge w_clk or negedge rst_n)
begin
if(rst_n==1'b0)
w_full<=1'b0;
//通过对比读写FIFO的格雷码,生成写满标识。
else if({~r_gaddr_delay[26],~r_gaddr_delay[25],r_gaddr_delay[24:18]}==w_gaddr[8:0])
w_full<=1'b1;
else
w_full<=1'b0;
end
assign w_addr_line=((~w_full)&w_en)+w_addr;
always@(posedge w_clk or negedge rst_n)
begin
if(rst_n==1'b0)
w_addr<=9'd0;
else
w_addr<=w_addr_line;
end
//写FIFO地址的格雷编码的组合逻辑
assign w_gaddr_line=w_addr_line^(w_addr_line>>1);
always@(posedge w_clk or negedge rst_n)
begin
if(rst_n==1'b0)
w_gaddr<=9'd0;
else
w_gaddr<=w_gaddr_line;
end
endmodule
三、读FIFO控制模块
r_fifo_ctrl模块的verilog实现代码如下:
//读FIFO控制模块
module r_fifo_ctrl(
input wire r_clk,
input wire rst_n,
input wire r_en, //读使能
input wire [8:0] w_gaddr,//接收到的写FIFO地址的格雷编码
output reg [8:0] r_addr, //读FIFO地址
output reg [8:0] r_gaddr, //读格雷码地址
output reg r_empty //读空信号
);
wire [8:0] r_addr_line;
wire [8:0] r_gaddr_line;
reg [26:0] w_gaddr_delay;
//接收到的写FIFO地址的格雷编码再打两拍,降低亚稳态
always@(posedge r_clk or negedge rst_n)
begin
if(rst_n==1'b0)
w_gaddr_delay[26:0]<=27'd0;
else
w_gaddr_delay[26:0]<={w_gaddr_delay[17:0],w_gaddr[8:0]};
end
//assign r_empty=(w_gaddr_delay[26:18]==r_gaddr[8:0])?1:0;
//通过对比读写FIFO的格雷码,生成读空标识。
always@(posedge r_clk or negedge rst_n)
begin
if(rst_n==1'b0)
r_empty<=1'b0;
else if(w_gaddr_delay[26:18]==r_gaddr[8:0])
r_empty<=1'b1;
else
r_empty<=1'b0;
end
assign r_addr_line=((~r_empty)&r_en)+r_addr;
always@(posedge r_clk or negedge rst_n)
begin
if(rst_n==1'b0)
r_addr<=9'd0;
else
r_addr<=r_addr_line;
end
//读FIFO地址的格雷编码组合逻辑
assign r_gaddr_line=r_addr_line^(r_addr_line>>1);
always@(posedge r_clk or negedge rst_n)
begin
if(rst_n==1'b0)
r_gaddr<=9'd0;
else
r_gaddr<=r_gaddr_line;
end
endmodule
四、XILINX的simple dual port RAM模块
//XILINX的simple dual port RAM模块
module sig_dp_ram(
input wire w_clk,
input wire w_ram_en,
input wire [7:0] w_addr,
input wire [7:0] w_data,
input wire r_clk,
input wire [7:0] r_addr,
output wire [7:0] r_data
);
blk_mem_gen_0 blk_mem_gen_0_inst(
.clka(w_clk), // input wire clka
.ena(1'b1), // input wire ena
.wea(w_ram_en), // input wire [0 : 0] wea
.addra(w_addr), // input wire [7 : 0] addra
.dina(w_data), // input wire [7 : 0] dina
.clkb(r_clk), // input wire clkb
.enb(1'b1), // input wire enb
.addrb(r_addr), // input wire [7 : 0] addrb
.doutb(r_data) // output wire [7 : 0] doutb
);
五、顶层模块
module fifo_design_top(
input wire w_clk,
input wire r_clk,
input wire rst_n,
input wire [7:0] w_data,
output wire [7:0] r_data,
input wire w_en,
input wire r_en,
output wire w_full,
output wire r_empty
);
wire [8:0] r_gaddr;
wire [8:0] w_gaddr;
wire [8:0] r_addr;
wire [8:0] w_addr;
wire w_ram_en_wire;
//写RAM的使能信号
assign w_ram_en_wire=(~w_full)&w_en;
w_fifo_ctrl w_fifo_ctrl_inst(
.w_clk (w_clk),
.rst_n (rst_n),
.w_en (w_en),
.r_gaddr(r_gaddr),
.w_addr (w_addr),
.w_gaddr(w_gaddr),
.w_full (w_full)
);
r_fifo_ctrl r_fifo_ctrl_inst(
.r_clk (r_clk),
.rst_n (rst_n),
.r_en (r_en),
.w_gaddr (w_gaddr),
.r_addr (r_addr),
.r_gaddr (r_gaddr),
.r_empty (r_empty)
);
sig_dp_ram sig_dp_ram_inst(
.w_clk (w_clk),
.w_ram_en (w_ram_en_wire),
.w_addr (w_addr[7:0]),
.w_data (w_data),
.r_clk (r_clk),
.r_addr (r_addr[7:0]),
.r_data (r_data)
);
endmodule
六、testbench
`timescale 1ns/1ns
module tb_fifo_degin_top;
reg w_clk,r_clk,rst_n,w_en,r_en;
reg [7:0] w_data;
wire [7:0] r_data;
wire w_full,r_empty;
initial
begin
w_clk=0;
r_clk=0;
rst_n=0;
#140 rst_n=1;
end
initial
begin
w_en=0;
r_en=0;
w_data=0;
#300 wdata(257);
#123 rdata(257);
end
always #15 w_clk=~w_clk;
always #15 r_clk=~r_clk;
task wdata(len);
integer i;
begin
for(i=0;i<256;i=i+1)
begin
@(posedge w_clk)
w_data=i;
w_en=1;
end
@(posedge w_clk)
w_data=0;
w_en=0;
end
endtask
task rdata(len);
integer i;
begin
for(i=0;i<256;i=i+1)
begin
@(posedge r_clk)
r_en=1;
end
@(posedge r_clk)
r_en=0;
end
endtask
fifo_design_top fifo_design_top_inst(
.w_clk (w_clk),
.r_clk (r_clk),
.rst_n (rst_n),
.w_data (w_data),
.r_data (r_data),
.w_en (w_en),
.r_en (r_en),
.w_full (w_full),
.r_empty (r_empty)
);
endmodule
七、仿真波形
写满:
读空: