实现同步FIFO,FIFO的位宽和深度可配置。

       同步fifo的设计比异步fifo简单,不需要进行跨时钟域处理,主要难点在于空、满信号的判断;

       首先,我们需要先了解一下fifo的读写:可以通俗的理解为装水与取水,wr_addr便是向罐子里装水,而rd_addr便是取水,如果wr_addr的速度大于rd_addr速度,则一段时间后罐子便会装满,即fifo写满,反之,fifo读空,一般而言,装水与取水不同时进行,当罐子装满后,full信号拉高,通知rd_addr进行取水,当罐子里没水后,empty信号拉高,在装水;

                                                

       现在是如何判断空,满呢,我们可以将rd_addr,er_addr位宽增加一位,利用最高位是否相等来判断,如果最高位不相等,是否可以理解为开始之前fifo处于满状态?由此,我们可以得到fifo剩余量为(fifo的深度 - rd_addr + wr_addr) ,如果最高位相等,那fifo剩余量 = (wr_addr - rd_addr)

完整代码如下:

`timescale 1ns/1ns
/**********************************RAM************************************/
module dual_port_RAM #(parameter DEPTH = 16,
                       parameter WIDTH = 8)(
     input wclk
    ,input wenc
    ,input [$clog2(DEPTH)-1:0] waddr  //深度对2取对数,得到地址的位宽。
    ,input [WIDTH-1:0] wdata          //数据写入
    ,input rclk
    ,input renc
    ,input [$clog2(DEPTH)-1:0] raddr  //深度对2取对数,得到地址的位宽。
    ,output reg [WIDTH-1:0] rdata         //数据输出
);

reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];

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

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

endmodule  

/**********************************SFIFO************************************/
module sfifo#(
    parameter    WIDTH = 8,
    parameter     DEPTH = 16
)(
    input                     clk        , 
    input                     rst_n    ,
    input                     winc    ,
    input                      rinc    ,
    input         [WIDTH-1:0]    wdata    ,

    output reg                wfull    ,
    output reg                rempty    ,
    output wire [WIDTH-1:0]    rdata
);
    parameter           addr = $clog2(DEPTH);
    
    reg         [addr:0]         waddr;
    reg         [addr:0]         raddr;
    wire        [addr:0]         cnt;
    
    always@(posedge clk or negedge rst_n)
        if(rst_n == 1'b0)
            waddr <= 'd0;
    else  if((winc == 1'b1)&&(wfull == 1'b0))
        waddr <= waddr + 1'b1;
    
    always@(posedge clk or negedge rst_n)
        if(rst_n == 1'b0)
            raddr <= 'd0;
    else if((rinc == 1'b1)&&(rempty == 1'b0))
        raddr <= raddr + 1'b1;
    
    assign cnt = (waddr[addr] == raddr[addr])?
                 (waddr[addr:0] - raddr[addr:0]):
                 (DEPTH + waddr[addr-1:0] - raddr[addr-1:0]);
    
    always@(posedge clk or negedge rst_n)
        if(rst_n == 1'b0)
            begin
                wfull <= 1'b0;
                rempty <= 1'b0;
            end
    else if(cnt == 'd0)
        rempty <= 1'b1;
    else if(cnt == DEPTH)
        wfull <= 1'b1;
    else
        begin
            rempty <= 1'b0;
            wfull <= 1'b0;
        end

    
    wire                 wen;
    wire                 ren;
    
    assign         wen = ((winc == 1'b1)&&(wfull == 1'b0));
    assign         ren = ((rinc == 1'b1)&&(rempty == 1'b0));
    
 dual_port_RAM 
    #(.DEPTH (DEPTH),
      .WIDTH (WIDTH))
    dual_port_RAM_inst
    (
        .wclk                    (clk ), 
        .wenc                    (wen),
        .waddr                   (waddr[addr-1:0]),  //深度对2取对数,得到地址的位宽。
        .wdata                   (wdata),          //数据写入
        .rclk                    (clk),
        .renc                    (ren),
        .raddr                   (raddr[addr-1:0]),  //深度对2取对数,得到地址的位宽。
        .rdata                   (rdata)        //数据输出
);

   
endmodule

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值