• 异步FIFO设计的仿真与综合技术(6)


    概述

            本文主体翻译自C. E. Cummings and S. Design, “Simulation and Synthesis Techniques for Asynchronous FIFO Design 一文,添加了笔者的个人理解与注释,文中蓝色部分为笔者注或意译。前文链接:

    异步FIFO设计的仿真与综合技术(5)icon-default.png?t=N7T8https://blog.csdn.net/apple_53311083/article/details/132974327?spm=1001.2014.3001.5501

    6.0 FIFO设计的RTL代码(RTL code for FIFO Style #1)

            本节中列出了FIFO样式#1模型的Verilog RTL代码。

    6.1 fifo1.v - FIFO top-level module

            顶层的FIFO模块是一个参数化的FIFO设计,所有的子块都使用推荐的执行命名端口连接的方式进行实例化。另一种常见的编码方式是为顶层模块实例化提供与模块名称相同的名称。这样做是为了方便调试,因为如果实例名称与模块名称匹配,那么在层次路径中引用模块名称将是直接的。

     

    1. module fifo1 #(
    2. parameter DSIZE = 8,
    3. parameter ASIZE = 4)
    4. (output [DSIZE-1:0] rdata,
    5. output wfull,
    6. output rempty,
    7. input [DSIZE-1:0] wdata,
    8. input winc, wclk, wrst_n,
    9. input rinc, rclk, rrst_n);
    10. wire [ASIZE-1:0] waddr, raddr;
    11. wire [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr;
    12. sync_r2w sync_r2w (.wq2_rptr(wq2_rptr), .rptr(rptr),
    13. .wclk(wclk), .wrst_n(wrst_n));
    14. sync_w2r sync_w2r (.rq2_wptr(rq2_wptr), .wptr(wptr),
    15. .rclk(rclk), .rrst_n(rrst_n));
    16. fifomem #(DSIZE, ASIZE) fifomem
    17. (.rdata(rdata), .wdata(wdata),
    18. .waddr(waddr), .raddr(raddr),
    19. .wclken(winc), .wfull(wfull),
    20. .wclk(wclk));
    21. rptr_empty #(ASIZE) rptr_empty
    22. (.rempty(rempty),
    23. .raddr(raddr),
    24. .rptr(rptr), .rq2_wptr(rq2_wptr),
    25. .rinc(rinc), .rclk(rclk),
    26. .rrst_n(rrst_n));
    27. wptr_full #(ASIZE) wptr_full
    28. (.wfull(wfull), .waddr(waddr),
    29. .wptr(wptr), .wq2_rptr(wq2_rptr),
    30. .winc(winc), .wclk(wclk),
    31. .wrst_n(wrst_n));
    32. endmodule

    6.2 fifomem.v - FIFO memory buffer

            FIFO存储器缓冲区通常是一个实例化的ASIC或FPGA双端口,同步存储器设备。内存缓冲区也可以使用这个模块中的RTL代码合成到ASIC或FPGA寄存器。关于实例化的供应商RAM与verilog声明的RAM,同步系统设计团队进行了内部分析,发现对于高达256位的大小,与实例化的供应商RAM相比,使用verilog声明的RAM不会损失区域或性能。如果已实例化了供应商RAM,则强烈建议使用已命名的端口连接进行实例化。

    1. module fifomem #(parameter DATASIZE = 8, // Memory data word width
    2. parameter ADDRSIZE = 4) // Number of mem address bits
    3. (output [DATASIZE-1:0] rdata,
    4. input [DATASIZE-1:0] wdata,
    5. input [ADDRSIZE-1:0] waddr, raddr,
    6. input wclken, wfull, wclk);
    7. `ifdef VENDORRAM
    8. // instantiation of a vendor's dual-port RAM
    9. vendor_ram mem (.dout(rdata), .din(wdata),
    10. .waddr(waddr), .raddr(raddr),
    11. .wclken(wclken),
    12. .wclken_n(wfull), .clk(wclk));
    13. `else
    14. // RTL Verilog memory model
    15. localparam DEPTH = 1<
    16. reg [DATASIZE-1:0] mem [0:DEPTH-1];
    17. assign rdata = mem[raddr];
    18. always @(posedge wclk)
    19. if (wclken && !wfull) mem[waddr] <= wdata;
    20. `endif
    21. endmodule

    6.3 sync_r2w.v - Read-domain to write-domain synchronizer

            这是一个简单的同步器模块,用于通过由FIFO写入时钟时钟的一对寄存器,将n位指针从读取时钟域传递到写入时钟域。请注意,将两个寄存器连接在一起以进行重置和移位的总是块的简单性。同步器always块只有三行代码。所有模块输出都被注册为使用时间预算进行简化合成。该模块的所有输出都与wclk完全同步,而该模块的所有异步输入都来自rclk域,所有信号都使用“r”前缀命名,这使得很容易在所有“r*”信号上设置错误路径,以便简化静态定时分析。
    1. module sync_r2w #(parameter ADDRSIZE = 4)
    2. (output reg [ADDRSIZE:0] wq2_rptr,
    3. input [ADDRSIZE:0] rptr,
    4. input wclk, wrst_n);
    5. reg [ADDRSIZE:0] wq1_rptr;
    6. always @(posedge wclk or negedge wrst_n)
    7. if (!wrst_n) {wq2_rptr,wq1_rptr} <= 0;
    8. else {wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr};
    9. endmodule

    6.4 sync_w2r.v - Write-domain to read-domain synchronizer

            这是一个简单的同步器模块,用于通过FIFO读时钟时钟的一对寄存器,从写时钟域传递到读时钟域。请注意将两个寄存器连接在一起以进行重置和移动的总是块的简单性。同步器always块只有三行代码。所有模块输出都被注册为使用时间预算进行简化合成。该模块的所有输出都与rclk完全同步,而该模块的所有异步输入都来自wclk域,所有信号都使用“w”前缀命名,这使得很容易在所有“w*”信号上设置错误路径,以便简化静态定时分析。
    1. module sync_w2r #(parameter ADDRSIZE = 4)
    2. (output reg [ADDRSIZE:0] rq2_wptr,
    3. input [ADDRSIZE:0] wptr,
    4. input rclk, rrst_n);
    5. reg [ADDRSIZE:0] rq1_wptr;
    6. always @(posedge rclk or negedge rrst_n)
    7. if (!rrst_n) {rq2_wptr,rq1_wptr} <= 0;
    8. else {rq2_wptr,rq1_wptr} <= {rq1_wptr,wptr};
    9. endmodule

    6.5 rptr_empty.v - Read pointer & empty generation logic

            此模块包含在读取时钟域内生成的所有FIFO逻辑(同步器除外)。读取指针是一个双n位格雷码计数器。n位指针(rptr)通过sync_r2w模块传递到写时钟域。(n-1)位指针(raddr)用于寻址FIFO缓冲区。当下一个rptr值等于同步的wptr值时,注册FIFO空输出并在下一个上升沿生效。所有模块输出都被注册为使用时间预算进行简化合成。这个模块与rclk完全同步,以简化静态定时分析。
    1. module rptr_empty #(parameter ADDRSIZE = 4)
    2. (output reg rempty,
    3. output [ADDRSIZE-1:0] raddr,
    4. output reg [ADDRSIZE :0] rptr,
    5. input [ADDRSIZE :0] rq2_wptr,
    6. input rinc, rclk, rrst_n);
    7. reg [ADDRSIZE:0] rbin;
    8. wire [ADDRSIZE:0] rgraynext, rbinnext;
    9. //-------------------
    10. // GRAYSTYLE2 pointer
    11. //-------------------
    12. always @(posedge rclk or negedge rrst_n)
    13. if (!rrst_n) {rbin, rptr} <= 0;
    14. else {rbin, rptr} <= {rbinnext, rgraynext};
    15. // Memory read-address pointer (okay to use binary to address memory)
    16. assign raddr = rbin[ADDRSIZE-1:0];
    17. assign rbinnext = rbin + (rinc & ~rempty);
    18. assign rgraynext = (rbinnext>>1) ^ rbinnext;
    19. //---------------------------------------------------------------
    20. // FIFO empty when the next rptr == synchronized wptr or on reset
    21. //---------------------------------------------------------------
    22. assign rempty_val = (rgraynext == rq2_wptr);
    23. always @(posedge rclk or negedge rrst_n)
    24. if (!rrst_n) rempty <= 1'b1;
    25. else rempty <= rempty_val;
    26. endmodule

    6.6 wptr_full.v - Write pointer & full generation logic

            此模块包含在写入时钟域内生成的所有FIFO逻辑(同步器除外)。写指针是一个双n位格雷码计数器。n位指针(wptr)通过sync_w2r模块传递到读取时钟域。(n-1)位指针(waddr)用于处理FIFO缓冲区。当下一个修改的wgnext值等于同步和修改的wrptr2值(MSBs除外)时,注册FIFO完整输出并在下一个wclk上升沿生效。所有模块输出都被注册为使用时间预算进行简化合成。该模块与wclk完全同步,以简化静态定时分析。
    1. module wptr_full #(parameter ADDRSIZE = 4)
    2. (output reg wfull,
    3. output [ADDRSIZE-1:0] waddr,
    4. output reg [ADDRSIZE :0] wptr,
    5. input [ADDRSIZE :0] wq2_rptr,
    6. input winc, wclk, wrst_n);
    7. reg [ADDRSIZE:0] wbin;
    8. wire [ADDRSIZE:0] wgraynext, wbinnext;
    9. // GRAYSTYLE2 pointer
    10. always @(posedge wclk or negedge wrst_n)
    11. if (!wrst_n) {wbin, wptr} <= 0;
    12. else {wbin, wptr} <= {wbinnext, wgraynext};
    13. // Memory write-address pointer (okay to use binary to address memory)
    14. assign waddr = wbin[ADDRSIZE-1:0];
    15. assign wbinnext = wbin + (winc & ~wfull);
    16. assign wgraynext = (wbinnext>>1) ^ wbinnext;
    17. //------------------------------------------------------------------
    18. // Simplified version of the three necessary full-tests:
    19. // assign wfull_val=((wgnext[ADDRSIZE] !=wq2_rptr[ADDRSIZE] ) &&
    20. // (wgnext[ADDRSIZE-1] !=wq2_rptr[ADDRSIZE-1]) &&
    21. // (wgnext[ADDRSIZE-2:0]==wq2_rptr[ADDRSIZE-2:0]));
    22. //------------------------------------------------------------------
    23. assign wfull_val = (wgraynext=={~wq2_rptr[ADDRSIZE:ADDRSIZE-1],
    24. wq2_rptr[ADDRSIZE-2:0]});
    25. always @(posedge wclk or negedge wrst_n)
    26. if (!wrst_n) wfull <= 1'b0;
    27. else wfull <= wfull_val;
    28. endmodule
  • 相关阅读:
    字节流和处理流的对象反序列化问题
    大数据是什么?可以做什么?
    SEO外语网站批量翻译软件
    判断序列是否为正确的出栈序列
    1688平台商品详情api接口
    如何用 Java 写一个 Java 虚拟机
    JavaScript 布尔类型(boolean) 和为定义类型(undefined)
    654. 最大二叉树
    蒋鑫鸿:9.10国际黄金原油最新外盘行情趋势点评附解一套技术指导
    java126-throw向上抛出异常
  • 原文地址:https://blog.csdn.net/apple_53311083/article/details/133042985