小梅哥Xilinx FPGA学习笔记22——ip核之FIFO

目录

一:章节说明

1.1 FIFO IP简介

1.2 FIFO Generato IP 核信号框图

1.3 实验任务

二:FIFO 写模块设计

2.1 简介     

2.2 模块框图

2.3 模块端口与功能描述

2.4 写模块代码

三 FIFO 读模块设计

3.1 简介  

3.2 模块框图

3.3 模块端口与功能描述

3.4 读模块代码

四: 顶层模块设计

4.1 概述

4.2 模块端口与功能描述

4.3 代码编写

五 仿真测试验证实现

5.1 仿真验证代码

5.2 仿真结果


一:章节说明

1.1 FIFO IP简介

       FIFO 本质上是由 RAM 加读写控制逻辑构成的一种先进先出的数据缓冲器,其与普通存储器 RAM 的区别在于 FIFO 没有外部读写地址线,使用起来非常简单,但 FIFO 只能顺序写入数据,并按顺序读出数据, 其数据地址由内部读写指针自动加 1 完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定 的地址,不过也正是因为这个特性,使得 FIFO 在使用时并不存在像 RAM 那样的读写冲突问题。
       根据 FIFO 工作的时钟域,可以将 FIFO 分为同步 FIFO 和异步 FIFO 。同步 FIFO 是指读时钟和写时钟 为同一个时钟,在时钟沿来临时同时发生读写操作,常用于两边数据处理带宽不一致的临时缓冲。异步 FIFO 是指读写时钟不一致,读写时钟是互相独立的,一般用于数据信号跨时钟阈处理。
对于 FIFO 我们还需要了解一些常见参数:
1FIFO 的宽度: FIFO 一次读写操作的数据位宽 N
2FIFO 的深度: FIFO 可以存储多少个宽度为 N 位的数据。
3、将空标志: almost_empty FIFO 即将被读空。
4、空标志: empty FIFO 已空时由 FIFO 的状态电路送出的一个信号,以阻止 FIFO 的读操作继续从 FIFO 中读出数据而造成无效数据的读出。
5、将满标志: almost_full FIFO 即将被写满。
6、满标志: full FIFO 已满时由 FIFO 的状态电路送出的一个信号,以阻止 FIFO 的写操作继续向 FIFO 中写数据而造成溢出。
7 、写时钟: FIFO 时所遵循的时钟,在每个时钟的上升沿触发。
8 、读时钟: FIFO 时所遵循的时钟,在每个时钟的上升沿触发。
这里还有两点需要大家注意:
1、“ almost_empty ”和“ almost_full ”这两个信号分别被看作“ empty ”和“ full ”的警告信号,他们相对于真正的空( empty )和满( full )都会 提前一个时钟周期拉高
2 FIFO 中,先写入的数据被置于高位,后写入的数据被置于低位,由于其先入先出的特性,所以读出的数据也是高位在前,低位在后。这一点在读写数据位宽不对等时尤为重要,例如我们写数据位宽为 8 ,读数据位宽为 2 ,当写入的数据为 11000111 时,读出的数据依次为 11、00、01、11

1.2 FIFO Generato IP 核信号框图

       首先说明下,上图中黑色箭头表示此信号为必要信号;蓝色箭头表示此信号为可选信号;灰色箭头表示此信号为可选的边带信号。从图中我们可以了解到,当被配置为同步 FIFO 时,只使用 wr_clk ,所有的输入输出信号都同步于 wr_clk 信号。而当被配置为异步 FIFO 时,写端口和读端口分别有独立的时钟,所有与写相关的信号都是同步于写 时钟 wr_clk ,所有与读相关的信号都是同步于读时钟 rd_clk

        这里我们对框图中的常用信号端口做一下讲解,其他很少用到的信号如果大家感兴趣的话也可以在课后打开 IP 核的数据手册进行学习,各常用端口的功能描述如下:

1.3 实验任务

       本节的实验任务是使用 Vivado 生成一个异步 FIFO ,并实现以下功能:当 FIFO 为空时,向 FIFO 中写入数据,直至将 FIFO 写满后停止写操作;当 FIFO 为满时,从 FIFO 中读出数据,直到 FIFO 被读空后停 止读操作,以此向大家详细介绍一下 FIFO IP 核的使用方法。
1.4 配置FIFO步骤
       详细步骤可以参考正点原子 领航者ZYNQ 之 FPGA 开发指南 P584
       网盘链接如下:

      https://pan.baidu.com/s/1vXxmhg_mZm_OVg4xQeiCVQ  提取码:zdyz

二:FIFO 写模块设计

2.1 简介     

       首先介绍下 FIFO 写模块的设计,在 FIFO 写模块中,我们的输入信号主要有系统时钟信号(写时钟域的时钟)、系统复位信号;因为 FIFO 的写操作需要在 FIFO 完成复位后进行,所以我们还需要输入 wr_rst_busy (写复位忙)信号来判断 FIFO 是否结束了复位状态;实验任务中我们提到了 FIFO 为空时进行写操作,因 此还需要引入一个空相关的信号,这里我们引入的是 empty (空)信号;实验任务中我们还提到了写满了要 停止写操作,所以这里我们引入了 almost_full (将满)信号,因为将满信号表示 FIFO 还能再进行最后一次 写操作,使用这个信号的话我们正好可以在写入最后一次数据后关闭写使能,当然引入 full(满)信号也是可以,区别只是在于这么做会在写使能关断前执行一次无效的写操作。

2.2 模块框图

2.3 模块端口与功能描述

2.4 写模块代码

module fifo_wr(
//mudule clock
    input wr_clk , // 时钟信号
    input rst_n , // 复位信号
//FIFO接口 
    input wr_rst_busy , // 写复位忙信号
    input empty , // FIFO 空信号
    input almost_full , // FIFO 将满信号
    output reg fifo_wr_en , // FIFO 写使能
    output reg [7:0] fifo_wr_data // 写入 FIFO 的数据
 );   
 
reg empty_d0;
reg empty_d1;    
//因为 empty信号是和读信号的时钟同步的,对于写始终来说他是异步信号,所以要进行打拍处理   
always@(posedge wr_clk or negedge rst_n)   
    if(!rst_n)begin
        empty_d0 <= 0;      
        empty_d1 <= 0;
    end
    else begin
        empty_d0 <= empty;
        empty_d1 <= empty_d0;
    end
//fifo写使能信号赋值,当 FIFO 为空时开始写入,写满后停止写    
always@(posedge wr_clk or negedge rst_n)   
    if(!rst_n)  
        fifo_wr_en <= 0;
    else if(!wr_rst_busy)begin
        if(empty_d1)
            fifo_wr_en <= 1;          
        else if(almost_full)
            fifo_wr_en <= 0;       
        else 
            fifo_wr_en <= fifo_wr_en; 
    end
    else
        fifo_wr_en <= 0;
    
//对 fifo_wr_data 赋值,0~254   
always@(posedge wr_clk or negedge rst_n)   
    if(!rst_n)  
        fifo_wr_data <= 0;
    else if(fifo_wr_en && fifo_wr_data < 254)
        fifo_wr_data <= fifo_wr_data + 1;
    else
        fifo_wr_data <= 0;
        
endmodule

FIFO 读模块设计

3.1 简介  

       首先介绍下 FIFO 读模块的设计,在 FIFO 读模块中,我们的输入信号主要有系统时钟信号(读时钟域时钟)和系统复位信号;因为 FIFO 的读操作需要在 FIFO 完成复位后进行,所以我们还需要输入 rd_rst_busy(读复位忙)信号来判断 FIFO 是否结束了复位状态;实验任务中我们提到了 FIFO 为满时进行读操作,因 此还需要引入一个满相关的信号,这里我们引入的是 full (满)信号;实验任务中我们还提到了读空了要停 止读操作,所以这里我们引入了 almost_empty (将空)信号,因为将空信号表示 FIFO 还能再进行最后一次读操作,使用这个信号的话我们正好可以在读出最后一个数据后关闭读使能,当然引入 empty (空)信号也 是可以,区别只是在于这么做会在读使能关断前执行一次无效的读操作。

3.2 模块框图

3.3 模块端口与功能描述

3.4 读模块代码

module fifo_rd(
//system clock
    input rd_clk , //时钟信号
    input rst_n , //复位信号
//FIFO接口
    input rd_rst_busy , //读复位忙信号
    input [7:0] fifo_rd_data, //从 FIFO 读出的数据
    input full , //FIFO 满信号
    input almost_empty, //FIFO 将空信号
    output reg fifo_rd_en //FIFO 读使能
    );
    
    reg full_d0;
    reg full_d1;
    
//因为 full 信号是属于 FIFO 写时钟域的,所以对 full 打两拍同步到读时钟域下  
always@(posedge rd_clk or negedge rst_n)   
    if(!rst_n)begin
        full_d0 <= 0;      
        full_d1 <= 0;
    end
    else begin
        full_d0 <= full;
        full_d1 <= full_d0;
    end    
    
//对 fifo_rd_en 进行赋值,FIFO 写满之后开始读,读空之后停止读    
always@(posedge rd_clk or negedge rst_n)   
    if(!rst_n)   
        fifo_rd_en <= 0;
    else if(!rd_rst_busy)begin
        if(full_d1)
            fifo_rd_en <= 1;    
        else if(almost_empty)
            fifo_rd_en <= 0;  
    end
    else
        fifo_rd_en <= 0; 
       
endmodule

四: 顶层模块设计

4.1 概述

       本次实验的目的是为了将 Xilinx FIFO Generato IP 核配置成一个异步 FIFO 并对其进行读写操作,因此可以给模块命名为 ip_fifo ;因为我们做的是异步 FIFO ,所以我们需要一个 PLL IP 核来输出 50MHz 的写时 钟和 100MHz 的读时钟,当然输出其它频率的时钟也是可以的;然后我们还需要一个写模块( fifo_wr )和 一个读模块( fifo_rd ),写模块通过 FIFO 的状态来判断是否给出写请求信号和写数据,读模块通过 FIFO 的状态来判断是否给出读请求信号,并接收从 FIFO 中读出的数据;系统时钟和系统复位是一个完整的工 程中必不可少的输入端口信号,这里就不再多讲了。经过上述分析我们可以画出一个大致的模块框图,如 下图所示:

            

4.2 模块端口与功能描述

4.3 代码编写

module ip_fifo(
    input sys_clk,
    input sys_rst_n
);
    
wire  locked;    
wire  clk_50M;    
wire  clk_100M;    
wire  rst_n;
wire  wr_rst_busy;
wire  empty;
wire  almost_full;
wire  [7 : 0]fifo_wr_data;
wire  rd_rst_busy;
wire  [7 : 0]fifo_rd_data;
wire  fifo_rd_en;
wire  fifo_wr_en;
wire  almost_empty;
wire  [7 : 0]rd_data_count;
wire  [7 : 0]wr_data_count;
wire  full;

//通过系统复位信号和时钟锁定信号来产生一个新的复位信号,代表当输出频率时钟稳定后,且复位完成后才能执行
assign rst_n = sys_rst_n & locked;
//例化 PLL IP 核   
clk_wiz_0 clk_wiz_0
(
    .clk_out1(clk_50M),     // output clk_out1
    .clk_out2(clk_100M),     // output clk_out2
    .locked(locked),       // output locked
    .clk_in1(sys_clk)  // input clk_in1 
);        
//例化 FIFO IP 核    
fifo_generator_0 your_instance_name (
  .rst(~rst_n),                      // input wire rst
  .wr_clk(clk_50M),                // input wire wr_clk
  .rd_clk(clk_100M),                // input wire rd_clk
  .din(fifo_wr_data),                      // input wire [7 : 0] din
  .wr_en(fifo_wr_en),                  // input wire wr_en
  .rd_en(fifo_rd_en),                  // input wire rd_en
  .dout(fifo_rd_data),                    // output wire [7 : 0] dout
  .full(full),                    // output wire full
  .almost_full(almost_full),      // output wire almost_full
  .empty(empty),                  // output wire empty
  .almost_empty(almost_empty),    // output wire almost_empty
  .rd_data_count(rd_data_count),  // output wire [7 : 0] rd_data_count
  .wr_data_count(wr_data_count),  // output wire [7 : 0] wr_data_count
  .wr_rst_busy(wr_rst_busy),      // output wire wr_rst_busy
  .rd_rst_busy(rd_rst_busy)      // output wire rd_rst_busy
);    
    
    
//例化写 FIFO 模块    
fifo_wr fifo_wr(
    .wr_clk(clk_50M)              , // 时钟信号
    .rst_n(rst_n)                 , // 复位信号
    .wr_rst_busy(wr_rst_busy)     , // 写复位忙信号
    .empty(empty)                 , // FIFO 空信号
    .almost_full(almost_full)     , // FIFO 将满信号
    .fifo_wr_en(fifo_wr_en)                 ,
    .fifo_wr_data(fifo_wr_data)     // 写入 FIFO 的数据
);       
       
//例化读 FIFO 模块  
fifo_rd fifo_rd(
    .rd_clk          (clk_100M)     , //时钟信号
    .rst_n           (rst_n)        , //复位信号
    .rd_rst_busy     (rd_rst_busy)  , //读复位忙信号
    .fifo_rd_data    (fifo_rd_data) , //从 FIFO 读出的数据
    .full            (full)         , //FIFO 满信号
    .almost_empty    (almost_empty) , //FIFO 将空信号
    .fifo_rd_en      (fifo_rd_en)     //FIFO 读使能
); 
    
endmodule
        可以看出 ip_fifo 顶层模块只是例化了 FIFO IP 核( fifo_generator_0 )、 PLL IP clk_wiz_0 )、读模块( fifo_rd )和写模块( fifo_wr ),其中写模块负责产生 FIFO IP 核写操作所需的所有数据、写请求等信 号;读模块负责产生 FIFO IP 核读操作所需读请求信号,并将读出的数据也连接至读模块。 因为读写模块的时钟皆来自 PLL IP 核,而 PLL IP 核需要一定的时间才能输出稳定的时钟,所以在第29 行代码中我们通过系统复位和时钟锁定来产生一个信号复位信号,使读 / 写模块及 FIFO IP 核在时钟稳定 后才进入工作状态。

五 仿真测试验证实现

5.1 仿真验证代码

`timescale 1ns / 1ps
module ip_fifo_tb();

parameter CLK_PERIOD = 20; //时钟周期 20ns
//reg define
reg sys_clk;
reg sys_rst_n;

//信号初始化
    initial begin
    sys_clk = 1'b0;
    sys_rst_n = 1'b0;
    #200;
    sys_rst_n = 1'b1;
    //模拟按下复位
    #10000 ;
    sys_rst_n = 0;
    #160 ;
    sys_rst_n = 1;
    end
   
    //产生时钟
    always #(CLK_PERIOD/2) sys_clk = ~sys_clk;
    
ip_fifo u_ip_fifo (
    .sys_clk (sys_clk ),
    .sys_rst_n (sys_rst_n)
);

endmodule

5.2 仿真结果

从仿真中可见FIFO读取设计正确。
因为RAM以及FIFO在FPGA中较为重要,所以后面还会有学习RAM以及FIFO的相关案例,敬请期待。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/305699.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32-04-STM32时钟树

STM32时钟树 什么是时钟&#xff1f; 时钟是具有周期性的脉冲信号&#xff0c;最常用的是占空比50%的方波。&#xff08;时钟是单片机的脉搏&#xff0c;搞懂时钟走向及关系&#xff0c;对单片机使用至关重要&#xff09;。 时钟树 时钟源 2个外部时钟源 高速外部振荡器(HSE…

Go采集1688网站数据对比商品价格

最近看了下多多和1688的一些商品价格&#xff0c;发现好多店铺都是无货源拿货一件发货&#xff0c;这就导致层层叠加价格翻了不知道几倍&#xff0c;真所谓多花钱办的事还是一样&#xff0c;因此&#xff0c;今天我就通过一个爬虫程序监控对应商品价格&#xff0c;了解行业龙头…

Python从入门到网络爬虫(OS模块详解)

前言 本章介绍python自带模块os&#xff0c;os为操作系统 operating system 的简写&#xff0c;意为python与电脑的交互。os 模块提供了非常丰富的方法用来处理文件和目录。通过使用 os 模块&#xff0c;一方面可以方便地与操作系统进行交互&#xff0c;另一方面页可以极大增强…

HCIA-Datacom题库(自己整理分类的)_15_VRP平台多选【9道题】

1.VRP操作平台存在哪些命令行视图? 用户视图 接口视图 协议视图 系统视图 2.以下哪些存储介质是华为路由器常用的存储介质 SDRAM NVRAM Flash Hard Disk SD Card 解析&#xff1a;Hard Disk是硬盘&#xff0c;一般网络设备没有。 3.VRP支持通过哪几种方式对路由器…

Influxdb2修改管理员密码

通过恢复管理员令牌来重置InfluxDB2管理员的密码 1.找到数据库的配置文件 一般为config.json 2.配置文件的的blod文件配置 3.在这个混合文本和二进制json文件中搜索已知的用户名或token之类的字符串。 例如&#xff1a; "id":"0bd73badf2941000","…

DES算法(Python实现)

一、具体描述 基于计算机高级语言&#xff08;如C语言&#xff09;实现DES算法 二、名词术语与相关知识 DES算法 DES&#xff08;Data Encryption Standard&#xff09;是一种对称加密算法&#xff0c;被广泛应用于数据加密领域。它使用64位密钥和64位明文&#xff0c;通过…

2707. 字符串中的额外字符

牛客网&#xff1a;https://leetcode.cn/problems/extra-characters-in-a-string/description/?envTypedaily-question&envId2024-01-09 官方解题思路为动态规划或字典数优化&#xff1b; 这里引入Up主的解题思路&#xff08;递归&#xff09; 哔哩哔哩&#xff1a;https…

【书影观后感 十五】被讨厌的勇气

年底的闲暇时间阅读了此书&#xff0c;书虽然是老婆买的&#xff0c;但她也是一页没看&#xff0c;便宜我了。都说哲学是用来回答人生问题的&#xff0c;我想慢慢的是有了一些这方面的体悟了。这里摘一些书中的经典观点吧&#xff0c;大多数中国90后的一代可能都遇到过类似的问…

c++实现支持动态扩容的栈(stack)

1.在栈容量满时自动扩容: 支持自动扩容栈实现: // // myStack.hpp // algo_demo // // Created by Hacker X on 2024/1/9. //#ifndef myStack_hpp #define myStack_hpp #include <stdio.h> #include <string.h> //栈实现 //1.入栈 //2.出栈 //3.空栈 //4.满栈 …

Python算法例34 寻找丢失的数

1. 问题描述 给一个由1~n的整数随机组成的一个字符串序列&#xff0c;其中丢失了一个整数&#xff0c;本例将找到它。 2. 问题示例 给出n20&#xff0c;str19201234567891011121314151618&#xff0c;丢失的数是17。 3. 代码实现 def find_missing_number(n, string):nums…

PLSQL启动错误,缺失oci.dll文件如何解决

Oracle数据库启动的时候报错&#xff0c;无法打开 报错显示缺失dll文件 第一步&#xff1a;在网上找到可靠的下载文件地址&#xff1a; 官方网站下载对应版本的oci.dll 链接如下&#xff1a;https://www.oracle.com/database/technologies/instant-client/winx64-64-downloa…

2023年,To B资本航船走向哪了?

国内To B领域在去掉泡沫、结束资本狂欢之后&#xff0c;投资决策愈加理性。但与此同时&#xff0c;下滑的步伐正在放慢&#xff0c;交易数量和金额的降低逐渐放缓&#xff0c;市场逐渐走向稳定。 作者|斗斗 编辑|皮爷 出品|产业家 2023年&#xff0c;在一众业内人士的眼中&…

Java后端开发——SSM整合实验

文章目录 Java后端开发——SSM整合实验一、常用方式整合SSM框架二、纯注解方式整合SSM框架 Java后端开发——SSM整合实验 一、常用方式整合SSM框架 1.搭建数据库环境&#xff1a;MySQL数据库中创建一个名称为ssm的数据库&#xff0c;在该数据库中创建一个名称为tb_book的表 …

CentOS找回root密码

很悲伤&#xff0c;你忘记了root密码。。。 那就来重置它吧~ 1、在启动时选择操作系统&#xff1a;在引导过程中&#xff0c;选择CentOS操作系统并按下键盘上的任意键来停止引导。 2、 进入编辑模式&#xff1a;在启动菜单中&#xff0c;找到并选择要编辑的CentOS条目&…

Android14之解决刷机报错:Can not load Android system. Your data may be corrupt(一百七十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

银联扫码第三方支付接口申请:开启便捷支付新时代

随着移动支付的普及&#xff0c;越来越多的商家开始接受微信、支付宝等第三方支付平台的付款方式。然而&#xff0c;作为国内最大的银行卡组织&#xff0c;银联也在不断拓展其业务范围&#xff0c;推出了自己的扫码支付接口。本文将为您详细介绍银联扫码第三方支付接口的申请流…

Unity Editor实用功能:Hierarchy面板的对象上绘制按按钮并响应

目录 需求描述上代码打个赏吧 需求描述 现在有这样一个需求&#xff1a; 在Hierarchy面板的对象上绘制按钮点击按钮&#xff0c;弹出菜单再点击菜单项目响应自定义操作在这里的响应主要是复制对象层级路路径 看具体效果请看动图&#xff1a; 注&#xff1a; 核心是对Edito…

书生·浦语大模型实战营第二次课堂笔记

文章目录 什么是大模型&#xff1f;pip&#xff0c;conda换源模型下载 什么是大模型&#xff1f; 人工智能领域中参数数量巨大、拥有庞大计算能力和参数规模的模型 特点及应用&#xff1a; 利用大量数据进行训练拥有数十亿甚至数千亿个参数模型在各种任务重展现出惊人的性能 …

CHS_02.1.4+操作系统体系结构 二

CHS_02.1.4操作系统体系结构 二 操作系统的结构 上篇文章我们只介绍过宏内核 也就是大内核以及微内核分层结构的操作系统模块化是一种很经典的程序设计思想宏内核和微内核外核 操作系统的结构 上篇文章我们只介绍过宏内核 也就是大内核以及微内核 今年大纲又增加了分层结构 模块…

126.(leaflet篇)leaflet松散型arcgis缓存切片加载

地图之家总目录(订阅之前必须详细了解该博客) arcgis缓存切片数据格式如下: 完整代码工程包下载,运行如有问题,可“私信”博主。效果如下所示: leaflet松散型arcgis缓存切片加载 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYP