赞
踩
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文件中找到,直接复制过来)。
`timescale 1ns / 1ps module IP_DCFIFO1( input wire wr_clk, input wire rd_clk, input wire rst_n, input wire [7:0] din, input wire wr_en, input wire rd_en, output wire [15:0] dout, output wire full, output wire empty, output [6:0] rd_da_cnt, output [7:0] wr_da_cnt ); IP_dcfifo_8x256 ip_dcfifo1 ( .wr_clk(wr_clk), // input wire wr_clk .rd_clk(rd_clk), // input wire rd_clk .din(din), // input wire [7 : 0] din .wr_en(wr_en), // input wire wr_en .rd_en(rd_en), // input wire rd_en .dout(dout), // output wire [15 : 0] dout .full(full), // output wire full .empty(empty), // output wire empty .rd_data_count(rd_da_cnt), // output wire [6 : 0] rd_data_count .wr_data_count(wr_da_cnt) // output wire [7 : 0] wr_data_count ); endmodule
4、编写仿真代码
在仿真代码中给各个输入激励。
我们给予了两个异步的时钟信号,写时钟频率为50MHz,读时钟频率为25MHz。
在调用DCFIFO时,我们这里设置的是写入数据为8位宽,读出数据为16位宽,仿真时也这样设计,以便完整地显示出读出数。
下面将演示如何在跨时钟域工程中使用DCFIFO完成数据的写入读出。
`timescale 1ns / 1ps module IP_DCFIFO_tb( ); reg wr_clk; reg rd_clk; reg rst_n; reg [7:0] din; reg wr_en; reg rd_en; //reg [1:0] cnt_baud; reg full_reg0; reg full_reg1; wire [15:0] dout; wire full; wire empty; wire [6:0] rd_da_cnt; wire [7:0] wr_da_cnt; initial begin wr_clk <= 1'b1; rd_clk <= 1'b1; rst_n <= 1'b0; #20 rst_n <= 1'b1; #100000 rst_n <= 1'b0; end always #10 wr_clk = ~wr_clk; always #20 rd_clk = ~rd_clk; always @(posedge wr_clk or rst_n) if (rst_n == 1'b0) din <= 8'd0; else if ((din == 8'd255) && (wr_en == 1'd1)) din <= 8'd0; else if (wr_en == 1'd1) din <= din + 8'd1; else ; always @(posedge wr_clk or rst_n) if (rst_n == 1'b0) wr_en <= 1'd0; else if ((full == 1'd1) && (rd_en <= 1'd1)) wr_en <= 1'd0; else if((rd_en <= 1'd0)&& (empty <= 1'd1)) wr_en <= 1'd1; else ; //读取数据激励 always @(posedge rd_clk or rst_n) if (rst_n == 1'b0) begin full_reg0 <= 1'd0; full_reg1 <= 1'd0; end else //rd_clk打两拍,full仍然为高电平再进行读取 begin full_reg0 <= full; full_reg1 <= full_reg0; end always @(posedge rd_clk or rst_n) if (rst_n == 1'b0) rd_en <= 1'd0; //如果 full 信号有效就立刻读,则不会看到 full 信号拉高, //所以此处使用 full 在 rd_clk 时钟下打两拍后的信号 else if (full_reg1 == 1'd1) rd_en <= 1'd1; else if (empty == 1'b1) rd_en <= 1'd0; else ; IP_DCFIFO1 ip_dcfifo_tb( .wr_clk (wr_clk ), .rd_clk (rd_clk ), .rst_n (rst_n ), .din (din ), .wr_en (wr_en ), .rd_en (rd_en ), .dout (dout ), .full (full ), .empty (empty ), .rd_da_cnt (rd_da_cnt), .wr_da_cnt (wr_da_cnt) ); endmodule
5、仿真结果
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。