首页 > 其他分享 >FPGA入门笔记013——嵌入式块RAM使用之FIFO

FPGA入门笔记013——嵌入式块RAM使用之FIFO

时间:2024-04-16 14:34:57浏览次数:19  
标签:FPGA RAM 写入 FIFO rdreq 013 信号 数据 时钟

1、FIFO概述

​ FIFO(First In First Out),即先进先出。FPGA 或者 ASIC 中使用到的 FIFO 一般指的是对数据的存储具有先进先出特性的一个缓存器,常被用于数据的缓存或者高速异步数据的交互。它与普通存储器的区别是没有外部读写地址线,这样使用起来相对简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加 1 完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。

2、FIFO相关知识

2.1、FIFO结构

​ FIFO 从大的情况来分,有两类结构:单时钟 FIFO(SCFIFO)和双时钟 FIFO(DCFIFO), 其中双时钟 FIFO 又可以分为普通双时钟( DCFIFO )和混合宽度双时钟 FIFO (DCFIFO_MIXED_WIDTHS)。

​ 图 1 为单时钟 FIFO 和双时钟 FIFO 的符号图。从图中可以看到,单时钟 FIFO 具有一个独立的时钟端口 Clock,因此所有输入信号的读取都是在 Clock 的上升沿进行的,所有 输出信号的变化也是在 Clock 信号的上升沿的控制下进行的,即单时钟 FIFO 的所有输入输出信号都是同步于 Clock 信号的。而在双时钟 FIFO 结构中,写端口和读端口分别有独立的时钟,所有与写相关的信号都是同步于写时钟 wrclk 的,所有与读相关的信号都是同步于读时钟 rdclk 的。在双时钟 FIFO 的符号图中,位于上部分的为与写相关的所有信号,位于中间部分的为与读相关的所有信号,位于下部的为异步清零信号。

微信截图_20240415165528

图1——单时钟 FIFO 与双时钟 FIFO 的符号图
2.2、单时钟 FIFO应用场景

​ 单时钟 FIFO 常用于片内数据交互。例如,在 FPGA 的控制下从外部传感器读取到的一 连串传感器数据,首先被写入 FIFO 中,然后再以 UART 串口波特率将数据依次发送出去。 由于传感器的单次读取数据可能很快,但并不是时刻都需要采集数据,例如某传感器使用 SPI 接口的协议,FPGA 以 2M 的 SPI 数据速率从该传感器中读取 20 个数据,然后以 9600 的波特率通过串口发送出去。因为 2M 的数据速率远高于串口 9600 的波特率,因此需要将 从传感器中采集到的数据首先用 FIFO 缓存起来,然后再以串口的数据速率缓慢发送出去。 这里,由于传感器数据的读取和串口数据的发送都是可以同步于同一个时钟的,因此可以使 用单时钟结构的 FIFO 来实现此功能。

2.3、FIFO常见参数
  • FIFO 的宽度:即 FIFO 一次读写操作的数据位;
  • FIFO 的深度:指的是 FIFO 可以存储多少个 N 位的数据(如果宽度为 N)。
  • 满标志:FIFO 已满或将要满时由 FIFO 的状态电路送出的一个信号,以阻止 FIFO 的写操作继续向 FIFO 中写数据而造成溢出。
  • 空标志:FIFO 已空或将要空时由 FIFO 的状态电路送出的一个信号,以阻止 FIFO 的读操作继续从 FIFO 中读出数据而造成无效数据的读出。
  • 读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。
  • 写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。

3、IP 核使用之 FIFO

3.1、单时钟 FIFO 实现

(1)新建一个以名为 fifo 的工程保存在 prj 下,然后单击 Tools→MegaWizard Plug-In Manager 按前面的方法搜索出 FIFO,并将输出目录修改为工程文件夹下的 ip 文件夹,并以 myscfifo 命名保存,单击 Next。

(2)这里首先创建一个单时钟 FIFO 也就是 SCFIFO,数据位宽为 16bits,数据深度为 256words。这里修改数据位宽及深度,观察界面左下角的资源使用情况,如下图所示。

微信截图_20240415171924

(3)在 IP 核 FIFO 中提供了很多接口,如下图,这里仅选择满、空、接近满、接近空以及异步清零。Almost_full:当 usedw 大于等于设置的值时该信号为高电平,是 full 的提前提示信号。Almost_empty:当 usedw 小于等于设置的值时该信号为低电平,是 empty 的提前 提示信号

(4)读操作请求确认信号,有两种模式:普通模式与前显(show-ahead)模式,如下图所示。

image-20240415205452596

(5)选择器件优化方式是面积优先还是速度优先,更换可以看到资源占用率是不一样的, 选择速度优先必然使用资源会上升,如下图所示。

image-20240415205528742

​ 然后确定配置信息后即可点击 Finish 完成配置。将生成的 IP 核加入工程,即可在工程 下看到加入的 IP 核文件并设置为顶层文件。

3.2、单时钟 FIFO 测试

(1)为了测试仿真编写测试激励文件,新建 myscfifo_tb.v 文件并输入以下内容再次进行分析和综合直至没有错误以及警告,保存到 testbench 文件夹下。除了实现例化需要仿真的文件以及时钟创建,还需实现写入 256 个数据后并依次读出。

`timescale 1ns/1ns
`define clk_period 20

module myscfifo_tb;

	reg	        Clk;
	reg[15:0]   data;
	reg	        rdreq;
	reg	        sclr;
	reg	        wrreq;

	wire	    almost_empty;
	wire	    almost_full;
	wire	    empty;
	wire	    full;
	wire[15:0]  q;
	wire[7:0]   usedw;

    integer i;

    myscfifo myscfifo(
        .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)
    );

    initial Clk = 1;
    always#(`clk_period/2) Clk = ~Clk;

    initial begin
        //初始化
        data = 0;
        rdreq = 0;
        wrreq = 0;
        sclr = 0;

        #(`clk_period * 20 + 1);
        for(i = 0;i < 256;i = i + 1)begin
            wrreq = 1;
            data = i;
            #`clk_period;
        end
        wrreq = 0;
        
        #(`clk_period * 20);
        for(i = 0;i < 256;i = i + 1)begin
            rdreq = 1;
            #`clk_period;
        end
        rdreq = 0;
        $stop;
    end

endmodule

(2)设置好仿真脚本后进行功能仿真,可以看到如下图所示的波形文件。可以看出 实现了数据的写入与读出。

image-20240415213751115

(3)放大写数据部分,可以看到每当时钟上升沿时均会写入对应的数据,且 empty 信号在写入一个数据后即置低,almost_empty 信号在写入两个数据后即置低。符合前面有关的配置,如下图所示。

image-20240415213942605

(4)在数据持续写入 254 个后 almost_full 信号置高,在写入 256 个后 full 信号置高。在 读取使能信号有效后,读出一个数据后 full 信号置低同样读出 2 个数据后 almost_full 信号置 低,如下图所示。

image-20240415215314362

(5)需指出这里 usedw 在写入 255 个数据后再写入第 256 个数据之所以变为 0,是因为 在前面设置中此数据的位宽是 8 位,因此最大计数到 255。这里可以同时判断 full 的状态来 判断实际剩余数据个数。同时选中 full 与 usedw,右键选择 Combine Signals,在弹出的界面 中将合并后的信号命名为 usedw2,如下图所示。

image-20240415220054594

(6)这样重启仿真即可看到下图所示的波形,这时 usedw2 即为真实 FIFO 中数据个数。

image-20240415220359251

(7)在读取 254 个信号后 almost_empty 信号置高,继续读取一个数据后 empty 信号置高。 如下图所示。

image-20240415220709861

​ 这样就完成了一个单时钟 FIFO 的配置以及仿真。

3.3、双时钟 FIFO 实现

(1)现在再新建一个 FIFO 并以 mydcfifo 保存。配置双时钟 FIFO 也就是 DCFIFO,且写入读取宽度分别为 16、8bits,如下图所示。

image-20240416122121759

(2)输入信号接口选择 empty 与 usedw,输出信号端口选择 full 与 usedw,这里可根据实际需求情况进行选择,如下图所示。

image-20240416123000406

(3)下图显示为 DCFIFO 的读请求信号 rdreq 的作为和存储器的实现方式。选则第一种普通方式rdreq 信号作为读请求信号当该信号有效时 FIFO 中的控制逻辑从存储器中读取一个数据输出到 q 端。如果选中 Show-ahead 方式,则 rdreq 信号作为读应答信号,即 rdreq 还没有有效时,q 端口上已经输出了一个有效的数据,rdreq 信号有效的时 候则相当于通知 FIFO 内部的控制逻辑 q 端口上的数据已经被读取,则 FIFO 内部的逻辑会 从 RAM 中再取出一个新的数据,在下一个时钟周期输出到 q 端口上。该模式在实际中应用也非常的普遍,因为 q 端口上的数据 与 rdreq 同时有效,没有读潜伏期。

image-20240416123158285

(4)下图为 FIFO 的溢出控制选项,可以设置忽略满溢出,忽略空溢出等。关于该设置的具体特性,可以通过阅读 IP 手册加仿真的方式验证。

image-20240416123342137

​ 然后预览汇总信息,确认后点击 Finish 来完成此 IP 的配置并将其加入工程中设置为顶层文件。

3.4、双时钟 FIFO 测试

​ 为了测试仿真编写测试激励文件,新建 mydcfifo_tb.v 文件并输入以下内容再次进行分析和综合直至没有错误以及警告,保存到 testbench 文件夹下。这里首先定义产生了不同的读写时钟频率且读时钟频率为写时钟频率的两倍,然后写使能即每当写时钟到来时就依次写入数据,写入 256 个数据后写失能,开始读使能即每当读时钟到来时依次读出数据,读出 512 个数据后读失能。这里由于写的数据为 16 位 256 个,因此也就相当于读出 8 位 512 个。

​ 在写入数据时人为加十进制数 1024,这样写入数据实际就是两个八进制数 0400、0401、 0402(MSB:先读低位,再读高位),读取时就是 2534\2544\2554。且读取 empty 正常显示。

`timescale 1ns/1ns

`define wrclk_period 20
`define rdclk_period 10

module mydcfifo_tb;

	reg[15:0]  data;
	reg	       rdclk;
	reg	       rdreq;
	reg	       wrclk;
	reg	       wrreq;

	wire[7:0]  q;
	wire	   rdempty;
	wire[8:0]  rdusedw;
	wire	   wrfull;
	wire[7:0]  wrusedw;

    integer i;

    mydcfifo mydcfifo(
        .data(data),
        .rdclk(rdclk),
        .rdreq(rdreq),
        .wrclk(wrclk),
        .wrreq(wrreq),

        .q(q),
        .rdempty(rdempty),
        .rdusedw(rdusedw),
        .wrfull(wrfull),
        .wrusedw(wrusedw)
    );

    initial wrclk = 1;
    always#(`wrclk_period/2) wrclk = ~wrclk;

    initial rdclk = 1;
    always#(`rdclk_period/2) rdclk = ~rdclk;

    initial begin
        //初始化
        data = 0;
        rdreq = 0;
        wrreq = 0;

        #(`wrclk_period * 20 + 1);
        for(i = 0; i < 256; i = i + 1)begin
            wrreq = 1;
            data = i + 1024;
            #`wrclk_period;
        end
        wrreq = 0;

        #(`rdclk_period * 20);
        for(i = 0; i < 512; i = i + 1)begin
            rdreq = 1;
            #`wrclk_period;
        end
        rdreq = 0;

        #(`rdclk_period * 20);
        $stop;
    end

endmodule

​ 设置好仿真脚本后进行功能仿真,可以看到如图 2 和图 3 所示的波形。可以看出:向 fifo 中写入的数据为 16 位,每写入一个 16 位数据,当其被读出时由于限定其位宽 是 8 位,所以只能分为两个 8 位的数据读出,相应读出时地址每次加 2 而不是加 1,与前面解释一致 。

image-20240416130537326

图 2 写数据部分仿真波形

​ 从图 3 可以看到,如果写入数据是 16’h04ff 分成两个 8 位十六进制数即为 8’h04、 8’hff,低位在前,符合设计。同样可以分析出读出数据规则。

image-20240416130625029

图 3 读数据部分仿真波形

​ 通过对以上的波形可以看出 FIFO 的工作状态正常。

标签:FPGA,RAM,写入,FIFO,rdreq,013,信号,数据,时钟
From: https://www.cnblogs.com/little55/p/18138044

相关文章

  • ASP.NET Core 8 EntityFrameworkCore 初体验
    介绍EntityFramework(EF)Core是轻量化、可扩展、开源和跨平台版的常用EntityFramework数据访问技术。EFCore可用作对象关系映射程序(O/RM),这可以实现以下两点:使.NET开发人员能够使用.NET对象处理数据库。无需再像通常那样编写大部分数据访问代码。先决条件V......
  • 基于直方图相似性的图像分类算法FPGA实现,包括tb测试文件和MATLAB辅助验证
    1.算法运行效果图预览MATLAB测试结果:    FPGA测试结果:   上述仿真图中,红色XX表示图像读取完毕。因此输出XX。当图像输出完成之后,最下面的相似性指标 same1输出为11226,same2输出为67584.即图1和图2相似性较强,图1和图3相似性较弱。 2.算法运行软件版本vi......
  • m基于FPGA的217卷积编码维特比译码verilog实现,包含testbench不使用IP核
    1.算法仿真效果Vivado2019.2   编码部分:   译码部分输出:   RTL图:   2.算法涉及理论知识概要2.1卷积编码       卷积编码是一种前向纠错编码方式,特别适用于无线通信和其他信道条件恶劣的应用场景。它主要通过卷积算子将信息序列映射成......
  • 3小时搞定DRF框架 | Django REST framework前后端分离框架实践
    DRF(全称DjangoRESTframework)是一个用于构建WebAPI的强力工具集,是一个基于Django的PythonWeb框架,它为开发人员提供了一套快速开发RESTfulAPI的工具,它能够自动化API可视化、文档化,实现接口的自动化测试以及自动化的API路由、序列化、视图、验证、分页、版本管理、认证等......
  • JSNice:Predicting Program Properties from “Big Code”
    发表:ACMSIGPLANNotices,2015,苏黎世联邦理工学院计算机科学系SoftwareReliabilityLab,AndreasKrause团队(https://scholar.google.com/citations?user=eDHv58AAAAAJ)(https://www.sri.inf.ethz.ch/research/plml)工具:http://jsnice.org内容概括  文章通过“大代码”......
  • nginx报错:bind() to 0.0.0.0:80 failed (10013: An attempt was made to access a soc
    问题:1.nginx启动失败2.在logs/error.log文件下,出现报错信息:bind()to0.0.0.0:80failed(10013:Anattemptwasmadetoaccessasocketinawayforbiddenbyitsaccesspermissions) 目录:1、cmd输入命令netstat-aon|findstr"80"2.、查看80端口7532对应的任务3、......
  • 阿里云消息队列升级全新品牌 ApsaraMQ丨阿里云云原生 3 月产品月报
    云原生月度动态云原生是企业数字创新的最短路径。《阿里云云原生每月动态》,从趋势热点、产品新功能、服务客户、开源与开发者动态等方面,为企业提供数字化的路径与指南。趋势热点......
  • iframe跨域,获取iframe中元素
    1.需求让iframe嵌入页面,并且没有滚动条,也就是相当于两个页面拼接在一起跨域解决,通过框架配置代理proxy:{'/medical':{target:'https://example.com',changeOrigin:true,pathRewrite:{'^/medical':'',},},}......
  • entity framework 锁
    entityframework锁在EntityFramework中,锁定是通过TransactionScope类或使用查询中的MergeOption来实现的。使用TransactionScope可以确保在事务期间对特定资源的锁定。例如:  using(varscope=newTransactionScope()){using(varcontext=newYourDbC......
  • Entity Framework 自定义外键关系
    EntityFramework自定义外键关系在EntityFramework中,你可以通过在模型类中使用属性来定义自定义外键关系。以下是一个简单的例子,展示了如何在两个实体之间创建一对一的关联关系:  publicclassUser{publicintUserId{get;set;}publicstringUsername......