同步与异步FIFO IP核功能测试详解 FIFO原理、分类与FPGA实现测试摘要本文系统介绍了 FIFOFirst In First Out的基本原理、与 ROM/RAM 的区别、分类方式并通过 Quartus 调用实例和 Verilog 代码演示了同步与异步 FIFO 的功能测试。文章涵盖 FIFO 的环状存储特性、握手信号机制、时钟分类同步/异步、工作模式标准/先出并提供了完整的测试代码与仿真波形分析适合 FPGA 初学者和数字电路设计者参考。目录一、FIFO 简介1.1 与 ROM 和 RAM 的区别1.2 基本单元1.3 基本应用二、FIFO 的分类2.1 按时钟分类2.2 按工作模式分类三、FIFO 的调用四、FIFO 的功能测试4.1 同步FIFO测试4.2 异步FIFO测试一、FIFO简介1.1与ROM和RAM的区别FIFOFirst In First Out 先进先出没有地址信号依赖于读写指针类似环状存储而 ROM 和 RAM 类似于管状存储需要依赖地址信号。FIFO 在读出数据的时候读的是数据本身所以读出数据之后数据会消失但是 RAM 因为是随机存取存储器读出的只是数据的映射所以数据依然保留。FIFO 的靠的是指针的偏移去指向存储空间有数据量信号因为每隔一个存储空间做一次切换与格雷码相似所以存储空间的编码一般采用格雷码。FIFO 具有很多的握手信号1.2基本单元构成资源LUT M9k D触发器不同系列芯片的构成不同1.3 基本应用连续数据、跨时钟域传输。二、FIFO的分类2.1 按时钟分类同步FIFO单时钟异步 FIFO双时钟读写各用一个时钟双时钟又分为普通双时钟和异步双时钟2.2 按工作模式分类标准模式读使能打开之后经过一个时钟周期读出数据先出模式先准备好数据等读使能打开之后更新数据三、FIFO 的调用这里以同步为例异步的调用大家可以参考同步去理解之后再尝试快捷键 Ctrl7 调出 IP 搜索栏搜索 FIFO 点开选择你的 HDL 语言以及 IP 核文件存放位置由于我们选择的是同步 FIFO 所以不能调整读输出的位宽在异步 FIFO 里可以进行修改本次异步测试使用的是 50MHz 和 100MHz 的时钟若输入 16 位宽输出 8 位宽则可以在理论上形成读写动态平衡同时读写的速率会一致。* 勾选配置 FIFO 各类可选状态控制信号握手信号与清零模式可根据需求勾选后面因为目前还没涉及到所以都默认点击next到最后一页选择inst仿真例化文件后finish就完成调用了四、FIFO 的功能测试4.1 同步FIFO测试测试代码//同步FIFO module top ( input wire clk , input wire rst_n ); //fifo8*256 //写 reg [7:0] data ;//输入数据 reg wrreq ;//写使能 //读 reg rdreq ;//读使能 wire [7:0] q ;//读出的数据 //握手信号 wire almost_empty ;//将空信号 wire almost_full ;//将满信号 wire empty ;//空信号读写指针在同一圈重合出现空溢出数据断裂 wire full ;//满信号写指针超过读指针一圈且重合出现满溢出数据丢失 wire [7:0] usedw ;//数据量 reg [9:0] cnt ;//0--1023计数器 //生成数据以及使能信号的转变 //0-1023 always (posedge clk or negedge rst_n) if(rst_n 0) cnt 0; else cnt cnt 1;//因为位宽限制这里就不用再写清零条件了 //写 always (posedge clk or negedge rst_n) if(rst_n 0)begin wrreq 0; data 0; end else if(cnt 512)begin wrreq 1; data data 1;//前512个周期开始写数据 end else begin wrreq 0; data 0; end //读 always (posedge clk or negedge rst_n) if(rst_n 0) rdreq 0; else if(cnt 512) rdreq 1; else rdreq 0; fifo fifo_inst ( .aclr ( !rst_n ), .clock ( clk ), .data ( data ), .rdreq ( rdreq ), .wrreq ( wrreq ), .almost_empty ( almost_empty ), .almost_full ( almost_full ), .empty ( empty ), .full ( full ), .q ( q ), .usedw ( usedw ) ); endmodule仿真代码timescale 1ns/1ps module tb (); reg clk ; reg rst_n ; initial begin clk 0; rst_n 0; #20 rst_n 1; #100000 $stop ; end always #10 clk ~clk ;//产生 50MHz 时钟信号 top top_inst( . clk (clk ), . rst_n (rst_n) ); endmodule测试仿真波形4.2 异步FIFO测试测试代码//异步FIFO module top ( input wire clk , input wire rst_n ); //pll :两路时钟 wire clk_50 , clk_100 ; //FIFO8*256 //写 reg [7:0] data ; //输入数据 reg wrreq ; //写使能 //读 reg rdreq ; //读使能 wire [7:0] q ; //读出的数据 // 握手信号 wire rdempty; //读空信号 wire rdfull ; //读满信号 wire wrempty; //写空信号 wire wrfull ; //写满信号 // 数据量 wire [7:0] wrusedw; //写数据量 wire [7:0] rdusedw; //读数据量 // 与同步 FIFO 的代码同理 reg [9:0] cnt ; //0--1023计数器 //生成数据以及使能信号的转变 //0-1023 always (posedge clk_50 or negedge rst_n) if(rst_n 0) cnt 0; else cnt cnt 1; //因为位宽限制这里就不用再写清零条件了 //写 always (posedge clk_50 or negedge rst_n) if(rst_n 0)begin wrreq 0; data 0; end else if(cnt 512)begin wrreq 1; data data 1; //前512个周期开始写数据 end else begin wrreq 0; data 0; end //读 always (posedge clk_100 or negedge rst_n) if(rst_n 0) rdreq 0; else if(cnt 512) rdreq 1; else rdreq 0; clock clock_inst ( .areset ( !rst_n ), .inclk0 ( clk ), .c0 ( clk_50 ), .c1 ( clk_100 ) ); dfifo dfifo_inst ( .aclr ( !rst_n ), .data ( data ), .rdclk ( clk_100 ), .rdreq ( rdreq ), .wrclk ( clk_50 ), .wrreq ( wrreq ), .q ( q ), .rdempty ( rdempty ), .rdfull ( rdfull ), .rdusedw ( rdusedw ), .wrempty ( wrempty ), .wrfull ( wrfull ), .wrusedw ( wrusedw ) ); endmodule仿真代码与同步fifo一致测试仿真波形(可以看到大致规律和同步差不多波形也很整齐漂亮大家可以修改测试代码查看在不同条件下的波形如上文所说产生的动态平衡)