首页 > 其他分享 >设计一个异步fifo?

设计一个异步fifo?

时间:2023-08-03 14:46:46浏览次数:29  
标签:bin 异步 wire gray fifo reg 设计 PTR

请设计一个异步fifo?宽度为8bit,深度为4bit。

异步fifo:从硬件的观点来看,就是一块数据内存。它有两个端口,一个用来写数据,就是将数据存入FIFO;另一个用来读数据,也就是将数据从FIFO当中取出。与FIFO操作相关的有两个指针,写指针指向要写的内存部分,读指针指向要读的内存部分。FIFO控制器通过外部的读写信号控制这两个指针移动,并由此产生FIFO空信号或满信号。来自异步FIFO_百度百科 (baidu.com)

异步fifo作用:用于将数据从一个时钟域安全的传送到另一个时钟域。

异步fifo设计的关键:生成fifo读写指针,fifo空/满状态。

异步fifo框图如下:整体分为五个小模块:1、写指针同步至读时钟域。2、读指针同步至写时钟域。3、双端口ram。4、写指针、写地址、满信号的产生。5、读指针、读地址、空信号的产生。

二进制编码在传递中容易产生亚稳态,故采用格雷码传递。格雷码具有良好的对称性。

使用格雷码判断空满状态:

 

异步fifo的设计代码&激励&仿真波形:

module  asyn_fifo
#(
parameter           DATA_WIDTH  = 8     ,
parameter           DATA_DEPTH  = 16    ,
parameter           PTR         = 4         //2^4=16

)
(
//写时钟域
input                           w_clk               ,
input                           w_rst_n             ,
input                           w_en                ,
input       [DATA_WIDTH-1:0]    data_in             ,
output         reg              full                ,

//读时钟域
input                            r_clk              ,
input                            r_rst_n            ,
input                            r_en               ,
output     [DATA_WIDTH-1:0]     data_out           ,
output          reg              empty               
);

reg [DATA_WIDTH-1:0] DPRAM [DATA_DEPTH-1:0];          //双端口RAM

//写时钟域
reg   [PTR:0]        w_bin            ;
wire  [PTR:0]        w_bin_next       ;
reg   [PTR:0]        w_gray           ;
wire  [PTR:0]        w_gray_next      ;    
reg   [PTR:0]        w_gray_ff0       ;
reg   [PTR:0]        w_gray_ff1       ;    //wq2_rptr 
wire  [PTR-1:0]      w_addr           ;
wire                 full_flag        ;
//读时钟域
reg   [PTR:0]        r_bin            ;
wire  [PTR:0]        r_bin_next       ;
reg   [PTR:0]        r_gray           ;
wire  [PTR:0]        r_gray_next      ;
reg   [PTR:0]        r_gray_ff0       ;
reg   [PTR:0]        r_gray_ff1       ;    //rq2_wptr
wire  [PTR-1:0]      r_addr           ;
wire                 empty_flag       ;


//读时钟域下 
// 产生读地址计数(r_bin) 读指针(r_gray)  需要打一拍
always@(posedge r_clk or negedge r_rst_n)  begin 
    if(!r_rst_n)  begin   
       r_bin<='d0; 
       r_gray<='d0;
    end  
    else  begin 
       r_bin<=r_bin_next; 
       r_gray<=r_gray_next;
    end    
end 

assign  r_bin_next =r_bin+(r_en&&(!empty));       //在读使能有效 且未空 读地址+1
assign  r_gray_next = (r_bin_next>>1)^r_bin_next; //二进制码转格雷码
assign  r_addr=r_bin[PTR-1:0] ;                   //读地址

always@(posedge r_clk or negedge r_rst_n)  begin  //打两拍 将写指针同步至读时钟域下
    if(!r_rst_n) begin  
       r_gray_ff0<='d0;
       r_gray_ff1<='d0;
    end 
    else  begin 
       r_gray_ff0<=w_gray;
       r_gray_ff1<=r_gray_ff0;    //rq2_wptr
    end 
end 

//空信号标志产生      这里比较的是同步至读时钟域下写指针  和下一读指针比较  重点
assign   empty_flag=(r_gray_ff1==r_gray_next)?1'b1:1'b0;

//上面空信号标志产生  提前一个读时钟周期 产生真的空信号 需要打一拍
always@(posedge r_clk or negedge r_rst_n) begin
    if(!r_rst_n)
        empty<=1'b0;
    else 
        empty<=empty_flag;
end 

//开始读取双端口RAM中的数据 
assign   data_out = DPRAM[r_addr];     //需要注意的地方 与写入数据不同



//写时钟域下 
// 产生写地址计数(w_bin) 写指针(w_gray) 需要打一拍
always@(posedge w_clk or negedge w_rst_n)  begin  
    if(!w_rst_n) begin 
       w_bin<='d0;
       w_gray<='d0;
    end 
    else begin 
       w_bin<=w_bin_next;
       w_gray<=w_gray_next;
    end    
end                                                  
assign  w_gray_next =(w_bin_next>>1)^w_bin_next  ;  //在写使能有效 且未满 写地址+1
assign  w_bin_next  = w_bin +(w_en&&!full)       ;  //二进制码转格雷码
assign  w_addr      = w_bin[PTR-1:0]             ;  //读地址


//打两拍 将读指针同步至写时钟域下
always@(posedge w_clk or negedge w_rst_n)  begin 
    if(!w_rst_n) begin  
       w_gray_ff0<='d0;
       w_gray_ff1<='d0;
    end 
    else  begin 
       w_gray_ff0<=r_gray;
       w_gray_ff1<=w_gray_ff0;     //wq2_rptr
    end 
end 

//满信号标志产生      这里比较的是同步至写时钟域下读指针  和下一写指针比较  重点
assign   full_flag=(w_gray_next=={~w_gray_ff1[PTR:PTR-1],w_gray_ff1[PTR-2:0]})?1'b1:1'b0;
//上面满信号标志产生  提前一个写时钟周期 产生真的空信号 需要打一拍
always@(posedge w_clk or negedge w_rst_n) begin
    if(!w_rst_n)
        full<=1'b0;
    else 
        full<=full_flag;
end 

//开始写入双端口RAM中的数据 在写使能有效 且非满下写入
always@(posedge w_clk or negedge w_rst_n) begin
    if(!w_rst_n)
        DPRAM[w_addr]<='d0;
    else if (w_en&&!full)
        DPRAM[w_addr] <= data_in;
    else 
        DPRAM[w_addr]<='d0;
end

endmodule 
`timescale  1ns/1ns 
module tb_asyn_fifo();
reg        w_clk                ;                 
reg        w_rst_n              ;  
reg        w_en                 ;  
reg  [7:0] data_in              ;  
wire       full                 ; 
reg        r_clk                ;                 
reg        r_rst_n              ;  
reg        r_en                 ;  
wire [7:0] data_out             ;  
wire       empty                ; 

initial begin 
    w_clk<=1'b0             ;   //模拟激励产生
    r_clk<=1'b0             ;
    w_rst_n<=1'b0           ;
    r_rst_n<=1'b0           ;
    w_en<=1'b0              ;
    r_en<=1'b0              ;
    data_in<='d0            ;
    #20
    w_rst_n<=1'b1           ;
    r_rst_n<=1'b1           ;
    #10
    w_en<=1'b1              ;
    #200
    r_en<=1'b1              ;
    #10
    w_en<=1'b0              ;
    #200
    r_en<=1'b0              ;
    #10
    w_en<=1'b1              ;
    #300
    w_en<=1'b0              ;
    #10
    r_en<=1'b1              ;
    #400
    r_en<=1'b0              ;
    #10
    w_en<=1'b1              ;
    #500
    w_en<=1'b0              ;
    #10
    r_en<=1'b1              ;
    #100
    w_en<=1'b1              ;
    #30
    r_en<=1'b0              ;
    #10
    w_en<=1'b0              ;
    #20
    r_en<=1'b1              ;
    #20
    w_en<=1'b1              ;
    #50
    r_en<=1'b0              ;
    #10
    w_en<=1'b0              ;
    #20
    r_en<=1'b1              ;
    
end          


always@(posedge w_clk or negedge w_rst_n) begin
    if(!w_rst_n)
        data_in<='d0;
    else if(w_en&&(!full))
        data_in<=data_in+1'b1;
    else 
        data_in<=data_in;
end 
always  #10  w_clk<= ~w_clk       ;
always  #20  r_clk<= ~r_clk       ;

asyn_fifo
#(
.DATA_WIDTH(8 )    ,
.DATA_DEPTH(16)    ,
.PTR       (4 )        //2^4=16

)
asyn_fifo_inst
(
//写时钟域
.w_clk     (w_clk   )          ,
.w_rst_n   (w_rst_n )          ,
.w_en      (w_en    )          ,
.data_in   (data_in )          ,
.full      (full    )          ,
//读时钟域
.r_clk     (r_clk   )          ,
.r_rst_n   (r_rst_n )          ,
.r_en      (r_en    )          ,
.data_out  (data_out)          ,
.empty     (empty   )           
);


endmodule 

若有不对的地方,敬请指正,万分感谢。

参考资料:

1、Simulation and Synthesis Techniques for Asynchronous FIFO Design

 

标签:bin,异步,wire,gray,fifo,reg,设计,PTR
From: https://www.cnblogs.com/yhm1314/p/17603273.html

相关文章

  • 瓴羊QuickBI为企业提供定制化的可视化设计,满足个性化需求。
    在目前的阶段,大数据技术已经成为企业缩小与竞争对手之间差距的重要手段。许多企业选择使用瓴羊QuickBI等工具来处理和分析内部数据,以保持持续的竞争优势。在过去,国内企业更倾向于使用进口的BI工具,但随着国内数据处理工具(如瓴羊QuickBI)的兴起,特别是可视化大屏设计的全面提升,更符合国......
  • 系统架构设计师笔记第42期:云原生架构相关技术
    云原生架构涉及许多相关的技术和工具,以下是一些与云原生架构相关的常见技术:容器技术:容器技术是云原生架构的基础,其中最流行的容器技术是Docker。容器技术提供了隔离性和可移植性,使得应用程序可以以一致的方式在不同的环境中运行。容器编排:容器编排技术用于管理和编排大规模容器集群......
  • Restful API设计规范
    01-02 Restful接口规范1.简介 2000年RoyFielding博士在其博士论文中提出REST(RepresentationalStateTransfer)风格的软件架构模式后,REST就基本上迅速取代了复杂而笨重的SOAP,成为WebAPI的标准了。RESTful作为目前最流行的API设计规范,一定有着它独有的魅力:强大、简介......
  • API接口的设计思路
    ​API接口设计是软件开发中非常重要的一环,良好的设计规范能够提高开发效率、减少问题和错误,并增强系统的可维护性和可扩展性。本文从程序员的视角,讨论一些常见的API接口设计规范。一、遵循RESTful原则REST(RepresentationalStateTransfer)是一种架构风格,基于HTTP协议提供了一组......
  • Canvas好难,如何让研发低成本实现Web端流程图设计功能
    摘要:本文由葡萄城技术团队于博客园原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。前言相信大家在职场中经常会用到流程图,在互联网行业,绘制流程图不论在产品的设计阶段,还是后期优化业务流程的阶段,都有着巨大的价值。事实上,......
  • PHP设计模式汇总
    PHP设计模式汇总没想到啊,没想到。自己竟然坚持了下来,完成了设计模式深入的学习,并且输出了23篇用php演示的设计模式的文章。但这不是最主要的,更深层次的收获是顺便背下了这些模式的定义及类图。在深入学习了设计模式之后,对Laravel等框架的架构理解也更清楚明了了。就像我在很多模式......
  • zt,UPF与低功耗设计实现实例 -- 附UPF与DC综合脚本
    https://blog.csdn.net/hungtaowu/article/details/120703931UPF与低功耗设计实现实例--附UPF与DC综合脚本sunvally已于 2022-11-1517:40:44 修改6059 收藏 98分类专栏: 低功耗设计与验证 文章标签: 硬件工程版权低功耗设计与验证专栏收录该内容29......
  • 中国石油大学软件工程课程设计
    需要作业答案搜扣扣,530986209交文件要求首先按照自己的个人兴趣在题目列表选择一个题目或者自拟题目,然后根据软件工程开发流程,完成这个题目从需求分析到系统测试的各个阶段环节目标,并按照附件里面给出的各种文档格式,撰写相关文档。请注意本课程ᨀ交的内容,应该包括软件工程中各......
  • 中国石油大学软件工程课程设计答案
    需要作业答案搜扣扣,530986209交文件要求首先按照自己的个人兴趣在题目列表选择一个题目或者自拟题目,然后根据软件工程开发流程,完成这个题目从需求分析到系统测试的各个阶段环节目标,并按照附件里面给出的各种文档格式,撰写相关文档。请注意本课程ᨀ交的内容,应该包括软件工程中各......
  • 编辑员工_需求分析和设计
         ......