异步FIFO设计(2)—— 简单代码实现

异步FIFO设计(2)—— 简单代码实现

在阅读Clifford的相关文章后(详见上一篇: 异步FIFO设计(1))后,我根据自己的理解,简单编写了一下FIFO的FPGA实现代码。注意,此代码不能用于综合!!! 仅适用于学习以及验证实际FIFO的正确性。

具体代码

说明:本代码testbench抓取波形部分仅适用于在线仿真器

1.Top view

`timescale 1ns/1ps
module top_module ();

    parameter D_WIDTH = 16;
	parameter A_WIDTH = 4;
	parameter D_Depth = 8;
    
    wire w_en,r_en;
    reg f_flag, e_flag;
    reg [A_WIDTH-1:0] w_addr,r_addr;
    reg [D_WIDTH-1:0] BUF [D_Depth-1:0];
    wire [D_WIDTH-1:0] buf0,buf1,buf7;
    
	reg w_clk=0;
    reg r_clk=0;
	always #5 w_clk = ~w_clk;  // Create clock with period=10
    always #2.5 r_clk = ~r_clk;
	initial `probe_start;   // Start the timing diagram
    
	// A testbench
    reg [D_WIDTH-1:0] din=0;
    reg [D_WIDTH-1:0] dout;
    reg w_nrst=1, r_nrst=1;
    reg winc=0, rinc=0;
    
	initial begin
        #7 w_nrst <= 1'b0; r_nrst <= 1'b0;
        #3 w_nrst <= 1'b1; r_nrst <= 1'b1;winc=1;
		#5 din <= 'h01;
		#10 din <= 'h02;
		#10 din <= 'h03;
		#10 din <= 'h04;
        #10 din <= 'h05;
       	#10 din <= 'h06;
        #10 din <= 'h07;
        #10 din <= 'h08;
        #10 din <= 'h09;
        #10 din <= 'h0A;
        #10 din <= 'h0B;
        #10 din <= 'h0C;
        #10 din <= 'h0D;
        #10 din <= 'h0E;
        #10 din <= 'h0F;
        #10 din <= 'h10;
		#10 din <= 'h11;
		#10 din <= 'h12;
		#10 din <= 'h13;rinc=1;
		#10 din <= 'h14;winc=0;
        #10 din <= 'h15;
       	#10 din <= 'h16;
        #10 din <= 'h17;
        #10 din <= 'h18;
        #10 din <= 'h19;
        #10 din <= 'h1A;
        #10 din <= 'h1B;
        #10 din <= 'h1C;
        #10 din <= 'h1D;
        #10 din <= 'h1E;
        #10 din <= 'h1F;
		#5000 $finish;            // Quit the simulation
	end

//module instantiation
	FIFO #(
        .D_WIDTH(D_WIDTH),
        .A_WIDTH(A_WIDTH),
        .D_Depth(D_Depth)
    ) FIFO1 (
        .din(din),
        .w_clk(w_clk),
        .r_clk(r_clk),
        .w_nrst(w_nrst),
        .r_nrst(r_nrst),
        .winc(winc),
        .rinc(rinc),
        .dout(dout),
        .w_en(w_en),
        .r_en(r_en),
        .f_flag(f_flag),
        .e_flag(e_flag),
        .w_addr(w_addr),
        .r_addr(r_addr),
        .buf0(buf0),
        .buf1(buf1),
        .buf7(buf7)
    );   // Sub-modules work too.
    
    `probe(w_clk);        // Probe signal "clk"
    `probe(r_clk); 
    `probe(w_nrst); 
    `probe(r_nrst);
    `probe(winc);
    `probe(rinc);
    `probe(din);
    `probe(dout);
    `probe(w_en);
    `probe(r_en);
    `probe(f_flag);
    `probe(e_flag);
    `probe(w_addr);
    `probe(r_addr);
    `probe(buf0);
    `probe(buf1);
    `probe(buf7);
 
endmodule

2. FIFO模块

module FIFO # (
parameter D_WIDTH = 16,
parameter A_WIDTH = 4,
parameter D_Depth = 8 )( 
input [D_WIDTH-1:0] din,
input w_clk,
input r_clk,
input w_nrst,
input r_nrst,
input winc,
input rinc,
output reg [D_WIDTH-1:0] dout,
    
	output w_en,r_en,
	output reg f_flag, e_flag,
    output reg [A_WIDTH-1:0] w_addr,r_addr,
    output [D_WIDTH-1:0] buf0,buf1,buf7
);

//reg [A_WIDTH-1:0] w_addr;
//reg [A_WIDTH-1:0] r_addr;
//reg f_flag, e_flag;
//wire w_en, r_en;
wire r_addr_i;
reg [D_WIDTH-1:0] BUF [D_Depth-1:0];
    assign {buf0,buf1,buf7} = {BUF[0],BUF[1],BUF[7]};
    
assign r_addr_i = !r_addr[A_WIDTH-1];
    
//write addr
always @(posedge w_clk or negedge w_nrst)
begin 
    if(!w_nrst | w_addr == {(A_WIDTH){1'b1}})
	w_addr <= 'b0;
    else if(!w_en)
	w_addr <= w_addr;
	else 
	w_addr <= w_addr +1'b1;
end

//read addr 
always @(posedge r_clk or negedge r_nrst)
begin 
    if(!r_nrst | r_addr == {(A_WIDTH){1'b1}})
	r_addr <= 'b0;
    else if(!r_en)
	r_addr <= r_addr;
	else 
	r_addr <= r_addr +1'b1;
end

//full flag
/*always @(posedge w_clk or negedge w_nrst)
begin
	if(!w_nrst )
	f_flag <= 1'b0;
    else if (w_addr == {!r_addr[A_WIDTH-1], r_addr[A_WIDTH-2:0]})
	f_flag <= 1'b1;
    else 
    f_flag <= 1'b0;
end
//empty flag
always @(posedge r_clk or negedge r_nrst)
begin
    if(!r_nrst )
	e_flag <= 1'b0;
	else if (w_addr == r_addr)
	e_flag <= 1'b1;
    else
    e_flag <= 1'b0;
end
*/
    assign f_flag = (w_addr == {!r_addr[A_WIDTH-1], r_addr[A_WIDTH-2:0]})?1'b1:1'b0;
    assign e_flag = (w_addr == r_addr)?1'b1:1'b0;
	assign w_en = winc & !f_flag;
	assign r_en = rinc & !e_flag;

//write data
always @(posedge w_clk)
begin
	if(w_en)
        BUF[w_addr[A_WIDTH-2:0]] <= din;
end

//read data
always @(posedge r_clk)
begin
	if(r_en)
        dout <= BUF[r_addr[A_WIDTH-2:0]];//mention that only N-2 LSBits are addr
    else
        dout <= 'bx;
end

endmodule

仿真结果

仿真环境:在线仿真器
时钟频率:w_clk=100-MHz, r_clk=200-MHz
仿真思路:通过修改testbench中winc和rinc的激励值,进行不同功能的测试。

写入功能仿真

读取功能仿真

同步读写仿真

异步读写仿真(写>读)

异步读写仿真(读>写)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值