同步(单时钟)、异步(双时钟)FIFO的Verilog HDL实现(含Testbench仿真代码) 您所在的位置:网站首页 同步fifo代码 同步(单时钟)、异步(双时钟)FIFO的Verilog HDL实现(含Testbench仿真代码)

同步(单时钟)、异步(双时钟)FIFO的Verilog HDL实现(含Testbench仿真代码)

2023-07-21 21:20| 来源: 网络整理| 查看: 265

目录

一、FIFO的定义和应用场景

二、FIFO的结构

三、FIFO的应用场景

3.1 单时钟(同步)FIFO

3.2 双时钟(异步)FIFO

四、FIFO的结构

五、FIFO常见参数

六、实现 FIFO 的方法

6.1 IP核的使用——FIFO

6.1.1 单时钟 FIFO 实现与测试

6.1.2 混合宽度异步(双时钟) FIFO 实现与测试

6.2 纯编程实现同步FIFO

6.2.1 顶层模块

6.2.2 FIFO控制模块

 6.2.3 双端口RAM模块

 6.2.4 RTL视图

 6.2.5 TestBench代码

 6.2.6 仿真结果

6.3 纯编程实现异步混合宽度FIFO

参考资料: 《FPGA自学笔记——设计与验证》;《硬件架构的艺术》;《Verilog HDL数字集成电路高级程序设计》等

链接:https://pan.baidu.com/s/1dKOXQMg3M3vHmVIx9KdMxg  提取码:kqy9  --来自百度网盘超级会员V6的分享

一、FIFO的定义和应用场景

FIFO(First in First Out)是一种先进先出的数据缓冲器,通常用于接口电路的数据缓存。与普通存储器的区别是没有外部读写地址线,可以使用两个时钟分别进行读和写操作。

FIFO只能顺序写入数据和顺序读出数据,其数据地址由内部读、写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。

二、FIFO的结构

FIFO从读/写端口和同步时钟关系来分,有两类结构:单时钟FIFO(Single Clock FIFO,SCFIFO)和双时钟(Dual Clock FIFO,DCFIFO),其中DCFIFO又可以分为普通双时钟(DCFIFO)和混合宽度双时钟FIFO(DCFIFO_MIXED_WIDTHS)。分别如下图所示:

从图中可以看到,单时钟FIFO具有一个独立的时钟端口 Clock,因此所有输入信号的读取都是在Clock的上升沿进行的,所有输出信号的变化也是在Clock信号的上升沿的控制下进行的,即单时钟 FIFO 的所有输入输出信号都是同步于 Clock 信号的。

而在双时钟 FIFO 结构中,写端口和读端口分别有独立的时钟,所有与写相关的信号都是同步于写时钟 wrclk 的,所有与读相关的信号都是同步于读时钟 rdclk 的。在双时钟 FIFO 的符号图中,位于上部分的为与写相关的所有信号,位于中间部分的为与读相关的所有信号,位于下部的为异步清零信号。

三、FIFO的应用场景 3.1 单时钟(同步)FIFO 单时钟 FIFO 常用于片内数据交互。 例如,在 FPGA 的控制下从外部传感器读取到的一连串传感器数据,首先被写入 FIFO 中,然后再以 UART 串口波特率将数据依次发送出去。由于传感器的单次读取数据可能很快,但并不是时刻都需要采集数据,例如某传感器使用SPI 接口的协议, FPGA 以 2M 的 SPI 数据速率从该传感器中读取 20 个数据,然后以 9600的波特率通过串口发送出去。因为 2M 的数据速率远高于串口 9600 的波特率,因此需要将从传感器中采集到的数据首先用 FIFO 缓存起来,然后再以串口的数据速率缓慢发送出去。这里,由于传感器数据的读取和串口数据的发送都是可以同步于同一个时钟的,因此可以使用单时钟结构的 FIFO 来实现此功能。 3.2 双时钟(异步)FIFO 双时钟 FIFO 的一个典型应用就是异步数据的收发,所谓异步数据是指数据的发送端和接收端分别使用不同的时钟域。使用双时钟 FIFO 能够将不同时钟域中的数据同步到所需的时钟域系统中。 例如,在一个高速数据采集系统中,实现将高速 ADC 采集的数据通过千兆以太网发送到 PC 机。 ADC 的采样时钟 (CLK1) 由外部专用锁相环芯片产生,则高速 ADC 采样得到的数据就是同步于该 CLK1 时钟信号,在 FPGA 内部,如果 FPGA 工作时钟 (CLK2)是由独立的时钟芯片加片上锁相环产生的,则 CLK1 和 CLK2 就是两个不同域的时钟,他们的频率和相位没有必然的联系,假如 CLK1 为 65M , CLK2 为 125M ,那么就不能使用 125M的数据来直接采集 65M 速率的数据,因为两者数据速率不匹配,在采集过程中会出现包括亚稳态问题在内的一系列问题,所以这里就可以使用一个具备双时钟结构的 FIFO 来进行异步数据的收发。下图 为使用 FIFO 进行异步数据收发的简易系统框图。

在此系统中,由于 ADC 的数据位宽为 8 位,基于 UDP 协议的以太网发送模块所需的数据也是 8 位,因此使用的是非混合宽度的双时钟 FIFO 结构。假如 CLK1 的频率为 20M ,ADC 的数据位宽为 16 位,则可以使用混合宽度的双时钟 FIFO ,在实现异步时钟域数据收发的同时,实现数据位宽的转换。通过设置双时钟 FIFO 的写入位宽为 16 位,读取位宽为 8 位,则可以实现将 16 位的 ADC 数据转换为以太网支持的 8 位发送数据,然后通过以太网发送到 PC 机。 四、FIFO的结构

一个FIFO的组成一般包括两个部分:地址控制部分和存储数据的DPRAM(双端口RAM)部分,如下图所示:

 地址控制部分可以根据读写指令生成RAM地址。RAM用于存储堆栈数据,并根据控制部分生成的地址信号进行数据的存储和读取操作。

五、FIFO常见参数 FIFO 的宽度:即 FIFO 一次读写操作的数据位; FIFO 的深度:指的是 FIFO 可以存储多少个 N 位的数据(如果宽度为 N); 满标志:FIFO 已满或将要满时由 FIFO 的状态电路送出的一个信号,以阻止 FIFO 的 写操作继续向 FIFO 中写数据而造成溢出; 空标志:FIFO 已空或将要空时由 FIFO 的状态电路送出的一个信号,以阻止 FIFO 的 读操作继续从 FIFO 中读出数据而造成无效数据的读出; 读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据; 写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。 六、实现 FIFO 的方法 在 Altera FPGA 中使用 FIFO 实现用户功能设计主要有三种实现方式。 第一种为用户根据需求自己编写 FIFO 逻辑(自己编写FIFO控制模块和RAM存储模块),当对于 FIFO 的功能有特殊需求时,可以使用此种方式实现。 第二种方式为使用FIFO的  IP 核, Quartus Prime 软件为用户提供了友好的图形化界面方便用户对 FIFO 的各种参数和结构进行配置,生成的 FIFO IP 核针对 Altera 不同系列的器件,还可以实现结构上的优化。该 FIFO IP 核也是通过Verilog 语言进行描述的,在 Quartus Prime 软件中,该 IP 核源码存放于 Quartus Prime软件安装目录 quartus\eda\sim_lib 下的 altera_mf.v 文件中的第 51101 行( scfifo ) (dcfifo 结构较多,因此代码内容很多,与之相关的代码有几千行,可以在文件中搜索 dcfifo 即可找到 ) 。 由于该 FIFO IP 核已经提供了大部分设计所需的所有功能,因此在系统设计中,推荐使用该FIFO IP 核进行系统设计。 第三种调用RAM的IP核,自己写FIFO的控制模块。 下面就这三种方法分别进行编程和仿真。 6.1 IP核的使用——FIFO 6.1.1 单时钟 FIFO 实现与测试

1、创建IP核 

2、将生成的IP核文件设为顶层文件

3、自动生成了my_fifo.v文件,打开查看一下端口,方便写激励文件

// megafunction wizard: %FIFO% // GENERATION: STANDARD // VERSION: WM1.0 // MODULE: scfifo // ============================================================ // File Name: myfifo.v // Megafunction Name(s): // scfifo // // Simulation Library Files(s): // altera_mf // ============================================================ // ************************************************************ // THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! // // 13.1.0 Build 162 10/23/2013 SJ Full Version // ************************************************************ // synopsys translate_off `timescale 1 ps / 1 ps // synopsys translate_on module myfifo ( clock, data, rdreq, sclr, wrreq, almost_empty, almost_full, empty, full, q, usedw); input clock; input [7:0] data; input rdreq; input sclr; input wrreq; output almost_empty; output almost_full; output empty; output full; output [7:0] q; output [3:0] usedw; wire [3:0] sub_wire0; wire sub_wire1; wire sub_wire2; wire [7:0] sub_wire3; wire sub_wire4; wire sub_wire5; wire [3:0] usedw = sub_wire0[3:0]; wire empty = sub_wire1; wire full = sub_wire2; wire [7:0] q = sub_wire3[7:0]; wire almost_empty = sub_wire4; wire almost_full = sub_wire5; scfifo scfifo_component ( .clock (clock), .sclr (sclr), .wrreq (wrreq), .data (data), .rdreq (rdreq), .usedw (sub_wire0), .empty (sub_wire1), .full (sub_wire2), .q (sub_wire3), .almost_empty (sub_wire4), .almost_full (sub_wire5), .aclr ()); defparam scfifo_component.add_ram_output_register = "OFF", scfifo_component.almost_empty_value = 2, scfifo_component.almost_full_value = 14, scfifo_component.intended_device_family = "Cyclone IV GX", scfifo_component.lpm_numwords = 16, scfifo_component.lpm_showahead = "OFF", scfifo_component.lpm_type = "scfifo", scfifo_component.lpm_width = 8, scfifo_component.lpm_widthu = 4, scfifo_component.overflow_checking = "ON", scfifo_component.underflow_checking = "ON", scfifo_component.use_eab = "ON"; endmodule

 4、编写和添加仿真激励文件fifo_tb.v

`timescale 1ns/1ps `define clk_period 20 module fifo_tb; //source define reg Clk; reg [7:0] data; reg rdreq; reg sclr; reg wrreq; //probe define wire almost_empty; wire almost_full; wire empty; wire full; wire [7:0] q; wire [3:0] usedw; //instant user module myfifo my_fifo( .clock(Clk), .data(data), .rdreq(rdreq), .sclr(sclr), .wrreq(wrreq), .almost_empty(almost_empty), .almost_full(almost_full), .empty(empty), .full(full), .q(q), .usedw(usedw) ); //generater clock initial Clk = 1; always #(`clk_period/2)Clk = ~Clk; integer i; initial begin wrreq = 0; data = 0; rdreq = 0; sclr = 0; #(`clk_period*20 + 1); for (i=0;i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有