微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > FPGA,CPLD和ASIC > 异步fifo程序问题 求大神指导

异步fifo程序问题 求大神指导

时间:10-02 整理:3721RD 点击:
为什么要同步wptr、rptr? 就是20-27行的程序则怎么解释?

  1. module fifo1(rdata, wfull, rempty, wdata, winc, wclk, wrst_n,rinc, rclk, rrst_n);
  2. parameter DSIZE = 8; parameter ASIZE = 4;
  3. output [DSIZE-1:0] rdata;
  4. output wfull;
  5. output rempty;
  6. input [DSIZE-1:0] wdata;
  7. input winc, wclk, wrst_n;
  8. input rinc, rclk, rrst_n;
  9. reg wfull,rempty;
  10. reg [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr, wq1_rptr,rq1_wptr;
  11. reg [ASIZE:0] rbin, wbin;
  12. reg [DSIZE-1:0] mem[0:(1<<ASIZE)-1]; //定义存储器宽度为8,深度为16
  13. wire [ASIZE-1:0] waddr, raddr; //读写地址
  14. wire [ASIZE:0] rgraynext, rbinnext,wgraynext,wbinnext; //读写的格雷码与二进制码
  15. wire rempty_val,wfull_val;
  16. //-----------------双口RAM存储器--------------------
  17. assign rdata=mem[raddr];
  18. always@(posedge wclk)
  19. if (winc && !wfull) mem[waddr] <= wdata;
  20. //-------------同步rptr 指针-------------------------
  21. always @(posedge wclk or negedge wrst_n)
  22. if (!wrst_n) {wq2_rptr,wq1_rptr} <= 0;
  23. else {wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr}; //这里采用了位拼接操作符
  24. //-------------同步wptr指针---------------------------
  25. always @(posedge rclk or negedge rrst_n)
  26. if (!rrst_n) {rq2_wptr,rq1_wptr} <= 0;
  27. else {rq2_wptr,rq1_wptr} <= {rq1_wptr,wptr}; //
  28. //-------------rempty产生与raddr产生-------------------
  29. always @(posedge rclk or negedge rrst_n) // GRAYSTYLE2 pointer
  30. begin
  31. if (!rrst_n) {rbin, rptr} <= 0;
  32. else {rbin, rptr} <= {rbinnext, rgraynext};
  33. end
  34. // Memory read-address pointer (okay to use binary to address memory)
  35. assign raddr = rbin[ASIZE-1:0];
  36. assign rbinnext = rbin + (rinc & ~rempty);
  37. assign rgraynext = (rbinnext>>1) ^ rbinnext; //产生读格雷码
  38. // FIFO empty when the next rptr == synchronized wptr or on reset
  39. assign rempty_val = (rgraynext == rq2_wptr);
  40. always @(posedge rclk or negedge rrst_n)
  41. begin
  42. if (!rrst_n) rempty <= 1'b1;
  43. else rempty <= rempty_val;
  44. end
  45. //---------------wfull产生与waddr产生------------------------------
  46. always @(posedge wclk or negedge wrst_n) // GRAYSTYLE2 pointer
  47. if (!wrst_n) {wbin, wptr} <= 0;
  48. else {wbin, wptr} <= {wbinnext, wgraynext};
  49. // Memory write-address pointer (okay to use binary to address memory)
  50. assign waddr = wbin[ASIZE-1:0];
  51. assign wbinnext = wbin + (winc & ~wfull);
  52. assign wgraynext = (wbinnext>>1) ^ wbinnext; //产生写格雷码
  53. assign wfull_val = (wgraynext=={~wq2_rptr[ASIZE:ASIZE-1], wq2_rptr[ASIZE-2:0]}); //:ASIZE-1]
  54. always @(posedge wclk or negedge wrst_n)
  55. if (!wrst_n) wfull <= 1'b0;
  56. else wfull <= wfull_val;
  57. endmodule

复制代码

你这个是异步FIFO...wclk和rclk频率又不同....
异步时钟域的信号同步常规做法啊,打两拍....避免亚稳态的传播..
基础知识....

同步到当前时钟域,否则做比较的时候可能异常,亚稳态之类。



    能给详细说说吗,我是菜鸟,不是很理解



    我看的有关异步fifo里面都提到过这个亚稳态的问题,不说是用格雷码来消除吗?难道不是吗?那几句代码为什么采用了非阻塞赋值?能给详细解答一下吗?



    写端要判断fifo是否full,要将写地址和读地址做比较,如果直接用读时钟下的读地址信号,有可能在写时钟上升沿时读地址正在跳变,比较器的结果也在跳变造成full信号的建立/保持时间不够,产生亚稳态。
将读地址同步到写时钟域下,就保证了后面比较结果的建立/保持时间。
---
但 在用写时钟采用读地址时,也可能因为建立/保持时间不够而造成亚稳态,得到错误的值,因此要先将读地址转换成格雷码,这样即使采错,也只是前一个地址的值,可以通过其他逻辑来防止写溢出。
--
写地址同步到读时钟的原因相同。

这个回答差不多了...小编你问说的格雷码避免亚稳态这种情况只针对连续变化的多位异步输入信号(比如地址信号,001->010->011.....)等等,通过格雷码,各地址线之间保证一个时钟周期只会有一个bit变化,就算产生了亚稳态,也只有一个亚稳态信号,再通过其他逻辑手段处理下,对不敏感电路,还是可以使用的。

   用非阻塞赋值就是一种逻辑处理,加两个寄存器“等”两个clk,你没发现两边的连接符所包含的信号正好是Z字型赋值的么....



    {wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr};
   这句可不可以等效于wq2_rptr<=wq1_rptr;wq1_rptr<=rptr;为什么是两个周期呢?

五个字符。
写错删除。



    你把这几个信号的波形画出来就知道为什么是2个clock了

   朋友,不明白你的意思..

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top