当前位置:   article > 正文

FPGA中IP核的调用——DCFIFO实验_dcfifo是什么,有什么作用

dcfifo是什么,有什么作用

1、FIFO IP 核简介
FIFO(First In First Out,即先入先出),是一种数据缓冲器,用来实现数据先入先出的读写方式。与 ROM 或 RAM 的按地址读写方式不同, FIFO 的读写遵循“先进先出”的原则,即数据按顺序写入 FIFO,先被写入的数据同样在读取的时候先被读出,所以 FIFO存储器没有地址线。 FIFO 有一个写端口和一个读端口外部无需使用者控制地址,使用方便。
FIFO 存储器主要是作为缓存,应用在同步时钟系统和异步时钟系统中,在很多的设计中都会使用,后面实例中如:多比特数据做跨时钟域的转换、前后带宽不同步等都用到了FIFO。 FIFO 根据读写时钟是否相同,分为 SCFIFO(同步 FIFO)和 DCFIFO(异步FIFO), SCFIFO 的读写为同一时钟,应用在同步时钟系统中; DCFIFO 的读写时钟不同,应用在异步时钟系统中。


2、如何调用FIFO

直接在vivado中,点击左上角IP catalog选项,输入FIFO进行搜索,选择FIFO Generator进入FIFO的配置。

SCFIFO(同步 FIFO)和 DCFIFO(异步FIFO)两者的调用方法基本一致,只是在于是使用“common Clock Block RAM”还是使用“Independent Clock Block RAM”,这里我们以DCFIFO的调用为例。

使用块 RAM 来实现异步 FIFO;其中 Independent Clock 表示是异步FIFO, Block RAM 表示的是块 RAM 资源。

依次进行DCFIFO的各个参数配置,之后再生成产品即可。

3、顶层调用代码编写

在.v文件中调用FIFO模块(FIFO模块可在其.voe文件中找到,直接复制过来)。

  1. `timescale 1ns / 1ps
  2. module IP_DCFIFO1(
  3. input wire wr_clk,
  4. input wire rd_clk,
  5. input wire rst_n,
  6. input wire [7:0] din,
  7. input wire wr_en,
  8. input wire rd_en,
  9. output wire [15:0] dout,
  10. output wire full,
  11. output wire empty,
  12. output [6:0] rd_da_cnt,
  13. output [7:0] wr_da_cnt
  14. );
  15. IP_dcfifo_8x256 ip_dcfifo1 (
  16. .wr_clk(wr_clk), // input wire wr_clk
  17. .rd_clk(rd_clk), // input wire rd_clk
  18. .din(din), // input wire [7 : 0] din
  19. .wr_en(wr_en), // input wire wr_en
  20. .rd_en(rd_en), // input wire rd_en
  21. .dout(dout), // output wire [15 : 0] dout
  22. .full(full), // output wire full
  23. .empty(empty), // output wire empty
  24. .rd_data_count(rd_da_cnt), // output wire [6 : 0] rd_data_count
  25. .wr_data_count(wr_da_cnt) // output wire [7 : 0] wr_data_count
  26. );
  27. endmodule

4、编写仿真代码

在仿真代码中给各个输入激励。

我们给予了两个异步的时钟信号,写时钟频率为50MHz,读时钟频率为25MHz。

在调用DCFIFO时,我们这里设置的是写入数据为8位宽,读出数据为16位宽,仿真时也这样设计,以便完整地显示出读出数。

下面将演示如何在跨时钟域工程中使用DCFIFO完成数据的写入读出。

  1. `timescale 1ns / 1ps
  2. module IP_DCFIFO_tb( );
  3. reg wr_clk;
  4. reg rd_clk;
  5. reg rst_n;
  6. reg [7:0] din;
  7. reg wr_en;
  8. reg rd_en;
  9. //reg [1:0] cnt_baud;
  10. reg full_reg0;
  11. reg full_reg1;
  12. wire [15:0] dout;
  13. wire full;
  14. wire empty;
  15. wire [6:0] rd_da_cnt;
  16. wire [7:0] wr_da_cnt;
  17. initial
  18. begin
  19. wr_clk <= 1'b1;
  20. rd_clk <= 1'b1;
  21. rst_n <= 1'b0;
  22. #20
  23. rst_n <= 1'b1;
  24. #100000
  25. rst_n <= 1'b0;
  26. end
  27. always #10 wr_clk = ~wr_clk;
  28. always #20 rd_clk = ~rd_clk;
  29. always @(posedge wr_clk or rst_n)
  30. if (rst_n == 1'b0)
  31. din <= 8'd0;
  32. else if ((din == 8'd255) && (wr_en == 1'd1))
  33. din <= 8'd0;
  34. else if (wr_en == 1'd1)
  35. din <= din + 8'd1;
  36. else
  37. ;
  38. always @(posedge wr_clk or rst_n)
  39. if (rst_n == 1'b0)
  40. wr_en <= 1'd0;
  41. else if ((full == 1'd1) && (rd_en <= 1'd1))
  42. wr_en <= 1'd0;
  43. else if((rd_en <= 1'd0)&& (empty <= 1'd1))
  44. wr_en <= 1'd1;
  45. else
  46. ;
  47. //读取数据激励
  48. always @(posedge rd_clk or rst_n)
  49. if (rst_n == 1'b0)
  50. begin
  51. full_reg0 <= 1'd0;
  52. full_reg1 <= 1'd0;
  53. end
  54. else //rd_clk打两拍,full仍然为高电平再进行读取
  55. begin
  56. full_reg0 <= full;
  57. full_reg1 <= full_reg0;
  58. end
  59. always @(posedge rd_clk or rst_n)
  60. if (rst_n == 1'b0)
  61. rd_en <= 1'd0;
  62. //如果 full 信号有效就立刻读,则不会看到 full 信号拉高,
  63. //所以此处使用 full 在 rd_clk 时钟下打两拍后的信号
  64. else if (full_reg1 == 1'd1)
  65. rd_en <= 1'd1;
  66. else if (empty == 1'b1)
  67. rd_en <= 1'd0;
  68. else
  69. ;
  70. IP_DCFIFO1 ip_dcfifo_tb(
  71. .wr_clk (wr_clk ),
  72. .rd_clk (rd_clk ),
  73. .rst_n (rst_n ),
  74. .din (din ),
  75. .wr_en (wr_en ),
  76. .rd_en (rd_en ),
  77. .dout (dout ),
  78. .full (full ),
  79. .empty (empty ),
  80. .rd_da_cnt (rd_da_cnt),
  81. .wr_da_cnt (wr_da_cnt)
  82. );
  83. endmodule

5、仿真结果

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/206794
推荐阅读
相关标签
  

闽ICP备14008679号