数字IC设计——异步FIFO的设计

  • afifo.v

module afifo #( parameter DEPTH = 16,
                parameter WIDTH = 8)(
        input                   wclk_i      ,
        input                   wrst_n_i    ,
        input                   wen_i       ,
        input   [WIDTH-1:0]     wdata_i     ,
        output                  wfull_o     ,
        input                   rclk_i      ,
        input                   rrst_n_i    ,
        input                   ren_i       ,
        output  [WIDTH-1:0]     rdata_o     ,
        output                  rempty_o          
        );
parameter ADDR_WID = $clog2(DEPTH) ;//address width 
//=============================write logic================================\
reg [ADDR_WID:0]  waddr;//write address register ,the MSB is for judge Write FULL or Read EMPTY
reg [ADDR_WID:0]  raddr_sync ;//read address from read clock domain,has been decoded
wire wen_ram ;//enable to write ram

always @(posedge wclk_i or negedge wrst_n_i)begin//write address  point
    if(!wrst_n_i)
        waddr <= 'd0;
    else if(wen_ram) 
        waddr <= waddr + 1'b1 ;
end 
assign wen_ram = wen_i & ~wfull_o;//no full and is enable to write  

assign wfull_o = (waddr[ADDR_WID]^raddr_sync[ADDR_WID])&&(waddr[ADDR_WID-1:0]==raddr_sync[ADDR_WID-1:0]);

//=============================write logic================================/


//=============================read logic================================\
reg [ADDR_WID:0]  raddr;//read address register ,the MSB is for judge Write FULL or Read EMPTY
reg [ADDR_WID:0]  waddr_sync ;//write address from write clock domain,has been decoded
wire ren_ram ;//enable to read ram

always @(posedge rclk_i or negedge rrst_n_i)begin//read address  point
    if(!rrst_n_i)
        raddr <= 'd0;
    else if(ren_ram) 
        raddr <= raddr + 1'b1 ;
end 
assign ren_ram = ren_i & ~rempty_o;//no empty and is enable to read  

assign rempty_o = (raddr[ADDR_WID:0]==waddr_sync[ADDR_WID:0]);

//=============================read  logic================================/

//============address cross clock domain ===============================\
//write to read 
reg [ADDR_WID:0] gray_waddr,gray_buf1_w2r,gray_buf2_w2r ;
always @(posedge wclk_i or negedge wrst_n_i)begin //binary 2 gray for waddr 
    if(~wrst_n_i)
        gray_waddr <= 'd0 ;
    else 
        gray_waddr <= waddr ^ (waddr >> 1'b1);
end 

always @(posedge rclk_i or negedge rrst_n_i)begin 
    if(~rrst_n_i) begin 
        gray_buf1_w2r <= 'd0;
        gray_buf2_w2r <= 'd0;
    end
    else begin 
        gray_buf1_w2r <= gray_waddr ;
        gray_buf2_w2r <= gray_buf1_w2r ;
    end 
end 
 
always @(posedge rclk_i or negedge rrst_n_i)begin:W2R//gray to binary 
    integer i ;
    if(~rrst_n_i)
        waddr_sync <= 'd0 ;
    else begin 
        for(i=0;i<=WIDTH;i=i+1)
            waddr_sync[i] <= ^(gray_buf2_w2r>>i);
    end 
end 

//read to write 
reg [ADDR_WID:0] gray_raddr,gray_buf1_r2w,gray_buf2_r2w ;
always @(posedge rclk_i or negedge rrst_n_i)begin //binary 2 gray for raddr 
    if(~rrst_n_i)
        gray_raddr <= 'd0 ;
    else 
        gray_raddr <= raddr ^ (raddr >> 1'b1);
end 

always @(posedge wclk_i or negedge wrst_n_i)begin 
    if(~wrst_n_i) begin 
        gray_buf1_r2w <= 'd0;
        gray_buf2_r2w <= 'd0;
    end
    else begin 
        gray_buf1_r2w <= gray_raddr ;
        gray_buf2_r2w <= gray_buf1_r2w ;
    end 
end 
    
always @(posedge wclk_i or negedge wrst_n_i)begin:R2W//gray to binary 
    integer i ;
    if(~wrst_n_i)
        raddr_sync <= 'd0 ;
    else begin 
        for(i=0;i<=WIDTH;i=i+1)
            raddr_sync[i] <= ^(gray_buf2_r2w>>i);
    end 
end 
//============address cross clock domain ===============================/

//inst for dpram
dpram #(    .DEPTH(DEPTH),
            .WIDTH(WIDTH) )
dpram_inst0(
        .wclk        (wclk_i            ),
        .wenc        (wen_ram           ),
        .waddr       (waddr[ADDR_WID-1:0]             ),   
        .raddr       (raddr[ADDR_WID-1:0]             ),   
        .wdata       (wdata_i           ),
        .rclk        (rclk_i            ),
        .renc        (ren_ram           ),
        .rdata       (rdata_o           ) 
        );


endmodule 

  •  dpram.v

module dpram #(parameter DEPTH = 16,
               parameter WIDTH = 8 )(
        input                       wclk        ,
        input                       wenc        ,
        input   [$clog2(DEPTH)-1:0] waddr       ,   
        input   [$clog2(DEPTH)-1:0] raddr       ,   
        input   [WIDTH-1:0]         wdata       ,
        input                       rclk        ,
        input                       renc        ,
        output reg [WIDTH-1:0]      rdata        
        );
reg [WIDTH-1:0] ram [0:DEPTH-1];

always @(posedge wclk)begin 
    if(wenc)
        ram[waddr] <= wdata;
end 

always @(posedge rclk)begin 
    if(renc)
        rdata <= ram[raddr] ;
end 

endmodule 
  • testbench

`timescale 1ns/1ns 
module tb_afifo();
parameter DEPTH = 256;
parameter WIDTH = 16;

reg wclk_i , wrst_n_i , rclk_i,rrst_n_i ;
reg wen_i,ren_i ;
reg [WIDTH-1:0] wdata_i ;
wire [WIDTH-1:0] rdata_o ;
wire wfull_o,rempty_o;
//=====================clock and reset=====================\
initial begin 
    wclk_i = 0 ;
    forever begin 
        #5 wclk_i  =~wclk_i ;//100MHz  
    end 

end 

initial begin 
    rclk_i = 0 ;
    forever begin 
        #10 rclk_i  =~rclk_i ;//50MHz  
    end 

end 

initial begin 
wrst_n_i = 0;  
rrst_n_i = 0;
#33 rrst_n_i =1 ;
#41 wrst_n_i = 1 ;
end 
//dump fsdb 
initial begin 
    $fsdbDumpfile("fifo.fsdb");
    $fsdbDumpvars(0);
end 

//==========================================================/
parameter  WID   = 3'b001 ;
parameter  WR    = 3'b010 ;
parameter  WST   = 3'b100 ;

parameter  RID   = 3'b001 ;
parameter  RD    = 3'b010 ;
parameter  RST   = 3'b100 ;

reg [2:0] wcs,rcs;

always @(posedge wclk_i or negedge wrst_n_i)begin 
    if(wrst_n_i==1'b0)begin 
        wen_i <=1'b0 ;
        wcs   <= WID;
        wdata_i <= 0;
    end 
    else begin 
        case(wcs)
            WID:begin 
                if(wfull_o == 1'b0)
                    wcs <= WR;
                wdata_i <= 0;
                wen_i   <= 0;
            end 
            WR:begin 
                wdata_i <= wdata_i + 1;
                wen_i   <= 1;
                if(wfull_o == 1'b1)begin 
                    wcs <= WST;
                    wen_i <= 0 ;
                end 
            end 
            WST:begin 
                wdata_i <= 0;
                wen_i   <= 0;
            end 
        endcase 

    end 

end 

always @(posedge rclk_i or negedge rrst_n_i)begin 
    if(rrst_n_i==1'b0)begin 
        ren_i <=1'b0 ;
        rcs   <= RID;
    end 
    else begin 
        case(rcs)
            RID:begin 
                if(wfull_o == 1'b1)
                    rcs <= RD;
                ren_i   <= 0;
            end 
            RD:begin 
                ren_i   <= 1;
                if(rempty_o== 1'b1)begin
                    rcs <= RST;
                    ren_i <= 0;
                end 
            end 
            RST:begin 
                ren_i   <= 0;
            end 
        endcase 

    end 

end 

always @(posedge rclk_i) begin 
    if(wcs[2]&&rcs[2])
        $finish;
end 

afifo #( .DEPTH(DEPTH),
         .WIDTH(WIDTH))
afifo_inst0(
        .wclk_i      (wclk_i      ),
        .wrst_n_i    (wrst_n_i    ),
        .wen_i       (wen_i       ),
        .wdata_i     (wdata_i     ),
        .wfull_o     (wfull_o     ),
        .rclk_i      (rclk_i      ),
        .rrst_n_i    (rrst_n_i    ),
        .ren_i       (ren_i       ),
        .rdata_o     (rdata_o     ),
        .rempty_o    (rempty_o    )      
        );

endmodule 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
SV小项目-异步FIFO是一个简单的项目,旨在让学生理解FIFO缓存的原理和实现方式。 FIFO缓存是一种常用的数据存储方式,可以用于解决数据传输时的不匹配问题。在异步FIFO中,数据的写入和读取是异步的,意味着数据可以在任何时候写入或读取。这种异步的方式可以增加FIFO的灵活性,并且允许数据的写入和读取在不同的时钟域上应用。 这个小项目的主要目标是实现一个基于Verilog的异步FIFO模块,包括以下功能: 1. 内部缓存的储存和检索 2. 空和满指示器的生成 3. 数据的写入和读取 对于写入操作,当FIFO未满时,它将数据存储在内部缓存中,并更新其指针以指向下一个空位置。当缓存已满时,写入操作将被忽略,并且FIFO满指示器将被设置为高电平。同样,读取操作从内部缓存中检索数据,并将其指针更新以指向下一个位置。当缓存为空时,读操作将被忽略,并且FIFO空指示器将被设置为高电平。 在设计过程中,需要考虑解决的问题包括时序和异步信号的同步。时序问题可以通过FIFO指针和状态机解决,而异步信号可以通过信号同步器进行同步。此外,还需要考虑FIFO的读写顺序和存储器的尺寸,并确保FIFO模块的有效性和可靠性。 总之,通过实现SV异步FIFO项目,学生可以加深对FIFO缓存的理解,并学习基于Verilog的设计和实现。此外,学生还可以通过在项目中遇到的挑战来提高他们的编程和设计技能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蜻蜓队长c

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值