ZYNQ之FPGA学习----FIFO IP核使用实验
创始人
2024-02-14 14:55:55

1 FIFO IP核介绍

FIFO 的英文全称是 First In First Out, 即先进先出。与 FPGA 内部的 RAM 和 ROM 的区别是没有外部读写地址线, 采取顺序写入数据, 顺序读出数据的方式,使用起来简单方便,缺点就是不能像 RAM 和 ROM 那样可以由地址线决定读取或写入某个指定的地址

根据 FIFO 工作的时钟域,可以将 FIFO 分为同步 FIFO 和异步 FIFO:

  • 同步 FIFO 是指读时钟和写时钟为同一个时钟,在时钟沿来临时同时发生读写操作
  • 异步 FIFO 是指读写时钟不一致,读写时钟是互相独立的

FIFO常用参数:

  • FIFO 的宽度,FIFO 一次读写操作的数据位 N
  • FIFO 的深度,FIFO 可以存储多少个宽度为 N 位的数据
  • 将空标志(almost_empty),FIFO 即将被读空
  • 空标志(empty),FIFO 已空时由 FIFO 的状态电路送出的一个信号,以阻止 FIFO 的读操作继续从 FIFO中读出数据而造成无效数据的读出
  • 将满标志(almost_full),FIFO 即将被写满
  • 满标志(full),FIFO 已满时由 FIFO 的状态电路送出的一个号,以阻止 FIFO 的写操作继续向 FIFO 中写数据而造成溢出
  • 读时钟,读 FIFO 时所遵循的时钟,在每个时钟的上升沿触发
  • 写时钟,写 FIFO 时所遵循的时钟,在每个时钟的上升沿触发

2 实验任务

使用 Vivado 生成 FIFO IP 核,并实现以下功能:当 FIFO 为空时,向 FIFO 中写入数据,写入的数据量和 FIFO 深度一致,即 FIFO 被写满;然后从 FIFO 中读出数据,直到 FIFO 被读空为止,系统框图如下:
在这里插入图片描述
图片来自《领航者ZYNQ之FPGA开发指南》

3 实验设计

3.1 创建工程

新建工程,操作如图所示:

在这里插入图片描述

输入工程名和工程路径,如图所示:

在这里插入图片描述

选择创建RTL工程,如图所示:

在这里插入图片描述

直接点击Next:

在这里插入图片描述

继续点击Next:

在这里插入图片描述

添加芯片型号,操作如图所示:

在这里插入图片描述

完成工程创建:

在这里插入图片描述

3.2 设计输入

点击IP Catalog,搜索fifo,如图所示:

在这里插入图片描述

双击打开后,弹出窗口如下,Interface Type 选项用于选择 FIFO 接口的类型,选择默认的 Native;Fifo Implementation 选项用于选择是同步 FIFO 还是异步 FIFO 以及使用哪种资源实现 FIFO,选择 Independent Clocks Block RAM,即使用块 RAM 来实现的异步 FIFO:

在这里插入图片描述

Read Mode 选项用于设置读 FIFO时的读模式,选择默认的Standard FIFO。Data Port Parameters 选型用于设置读写端口的数据总线的宽度以及 FIFO 的深度,写宽度 Write Width 设置为 8 位,写深度 Write Depth 设置为 256。Reset Pin 不使用,取消勾选:

在这里插入图片描述

Status Flags窗口,用于设置用户自定义接口或者用于设定专用的输入口,勾选 即将写满 和 即将读空 这两个信号:

在这里插入图片描述

Data Counts 窗口用于设置 FIFO 内数据计数的输出信号,此信号表示当前在 FIFO 内存在多少个有效数据。为了更加方便地观察读/写过程,设置如图所示:

在这里插入图片描述

设置完成:

在这里插入图片描述

弹出如下窗口,直接点击Generate:

在这里插入图片描述

点击OK:

在这里插入图片描述

继续添加ILA(集成逻辑分析器) IP核,即在线逻辑分析仪的功能,操作如图所示:

在这里插入图片描述

进行如下设置,Number of Probes 用于设置所需的探针数量;Sample Data Depth 用于设置采样深度:

在这里插入图片描述

如下进行设置每个探针的参数:

在这里插入图片描述

设置完成,点击OK:

在这里插入图片描述

创建工程顶层文件,操作如图所示:

在这里插入图片描述

创建文件ip_fifo,作为顶层模块:

在这里插入图片描述

创建完成:

在这里插入图片描述

双击打开,输入代码如下:

module ip_fifo( input    sys_clk ,  // 时钟信号 input    sys_rst_n  // 复位信号 
); //wire define 
wire         fifo_wr_en         ;  // FIFO 写使能信号 
wire         fifo_rd_en         ;  // FIFO 读使能信号 
wire  [7:0]  fifo_din           ;  // 写入到 FIFO 的数据 
wire  [7:0]  fifo_dout          ;  // 从 FIFO 读出的数据 
wire         almost_full        ;  // FIFO 将满信号 
wire         almost_empty       ;  // FIFO 将空信号 
wire         fifo_full          ;  // FIFO 满信号
wire         fifo_empty         ;  // FIFO 空信号 
wire  [7:0]  fifo_wr_data_count ;  // FIFO 写时钟域的数据计数 
wire  [7:0]  fifo_rd_data_count ;  // FIFO 读时钟域的数据计数 
//例化 FIFO IP 核 
fifo_generator_0  fifo_generator_0 ( .wr_clk        ( sys_clk             ),  // input wire wr_clk .rd_clk        ( sys_clk             ),  // input wire rd_clk .wr_en         ( fifo_wr_en          ),  // input wire wr_en .rd_en         ( fifo_rd_en          ),  // input wire rd_en .din           ( fifo_din            ),  // input wire [7 : 0] din .dout          ( fifo_dout           ),  // output wire [7 : 0] dout .almost_full   (almost_full          ),  // output wire almost_full .almost_empty  (almost_empty         ),  // output wire almost_empty .full          ( fifo_full           ),  // output wire full .empty         ( fifo_empty          ),  // output wire empty .wr_data_count ( fifo_wr_data_count  ),  // output wire [7 : 0] wr_data_count     .rd_data_count ( fifo_rd_data_count )   // output wire [7 : 0] rd_data_count 
);
//例化写 FIFO 模块 
fifo_wr  u_fifo_wr( .clk            ( sys_clk     ),   // 写时钟 .rst_n          ( sys_rst_n   ),   // 复位信号 .fifo_wr_en     ( fifo_wr_en )  , // fifo 写请求 .fifo_wr_data   ( fifo_din    ) , // 写入 FIFO 的数据 .almost_empty   ( almost_empty  ), // fifo 将空信号 .almost_full    ( almost_full  )  // fifo 将满信号 
); //例化读 FIFO 模块 
fifo_rd  u_fifo_rd( .clk          ( sys_clk     ),      // 读时钟 .rst_n        ( sys_rst_n   ),      // 复位信号 .fifo_rd_en   ( fifo_rd_en  ),      // fifo 读请求 .fifo_dout    ( fifo_dout   ),      // 从 FIFO 输出的数据 .almost_empty ( almost_empty  ),    // fifo 将空信号 .almost_full  ( almost_full  )     // fifo 将满信号 
); 
//例化 ILA IP 核 
ila_0  ila_0 ( .clk    ( sys_clk             ), // input wire clk .probe0 ( fifo_wr_en          ), // input wire [0:0]  probe0   .probe1 ( fifo_rd_en          ), // input wire [0:0]  probe1  .probe2 ( fifo_din            ), // input wire [7:0]  probe2  .probe3 ( fifo_dout           ), // input wire [7:0]  probe3  .probe4 ( fifo_empty          ), // input wire [0:0]  probe4  .probe5 ( almost_empty        ), // input wire [0:0]  probe5  .probe6 ( fifo_full           ), // input wire [0:0]  probe6 .probe7 ( almost_full         ), // input wire [0:0]  probe7  .probe8 ( fifo_wr_data_count  ), // input wire [7:0]  probe8  .probe9( fifo_rd_data_count  )  // input wire [7:0]  probe9 
); endmodule

如图所示:

在这里插入图片描述

继续创建fifo_wr文件,即写FIFO模块,如图所示:

在这里插入图片描述

双击打开,输入代码如下:

module fifo_wr( input                  clk    ,          // 时钟信号 input                  rst_n  ,          // 复位信号 input                  almost_empty,     // FIFO 将空信号 input                  almost_full ,     // FIFO 将满信号 output     reg          fifo_wr_en ,      // FIFO 写使能 output     reg  [7:0]   fifo_wr_data      // 写入 FIFO 的数据 
); //reg define 
reg  [1:0]  state            ;  //动作状态
reg         almost_empty_d0  ;  //almost_empty 延迟一拍 
reg         almost_empty_syn ;  //almost_empty 延迟两拍 
reg  [3:0]  dly_cnt          ;  //延迟计数器//因为 almost_empty 信号是属于 FIFO 读时钟域的 
//所以要将其同步到写时钟域中 
always @(  posedge clk )  begin if( !rst_n )  begin almost_empty_d0   <= 1'b0 ; almost_empty_syn  <= 1'b0 ; end else  begin almost_empty_d0   <= almost_empty ; almost_empty_syn  <= almost_empty_d0 ; end 
end //向 FIFO 中写入数据 
always  @( posedge clk )  begin if (!rst_n)  begin fifo_wr_en    <= 1'b0; fifo_wr_data  <= 8'd0; state         <= 2'd0; dly_cnt       <= 4'd0; end else  begin case(state) 2'd0:  begin  if(almost_empty_syn)  begin  //如果检测到 FIFO 将被读空(下一拍就会空) state  <= 2'd1;          //就进入延时状态 end  else state  <= state; end  2'd1:  begin if(dly_cnt  == 4'd10)  begin  //延时 10 拍 //原因是 FIFO IP 核内部状态信号的更新存在延时 //延迟 10 拍以等待状态信号更新完毕dly_cnt     <= 4'd0;      state       <= 2'd2;        //开始写操作 fifo_wr_en  <= 1'b1;        //打开写使能 end else dly_cnt  <= dly_cnt + 4'd1; end              2'd2:  begin if(almost_full)  begin      //等待 FIFO 将被写满(下一拍就会满) fifo_wr_en    <= 1'b0;  //关闭写使能 fifo_wr_data  <= 8'd0; state         <= 2'd0;  //回到第一个状态 end else  begin                 //如果 FIFO 没有被写满 fifo_wr_en    <= 1'b1;  //则持续打开写使能 fifo_wr_data  <= fifo_wr_data + 1'd1;  //且写数据值持续累加 end end  default : state  <= 2'd0; endcase end 
end endmodule          

如图所示:

在这里插入图片描述

继续创建fifo_rd文件,即读FIFO模块,如图所示:

在这里插入图片描述

双击打开,输入代码如下:

module fifo_rd( input               clk          ,   // 时钟信号 input               rst_n        ,   // 复位信号 input        [7:0]  fifo_dout    ,   // 从 FIFO 读出的数据 input               almost_full  ,   // FIFO 将满信号 input               almost_empty ,   // FIFO 将空信号 output   reg         fifo_rd_en       // FIFO 读使能 
); //reg define 
reg  [1:0]  state           ;  //状态 
reg         almost_full_d0  ;  //almost_full 延迟一拍 
reg         almost_full_syn ;  //almost_full 延迟两拍 
reg  [3:0]  dly_cnt         ;  //延迟计数器 //因为 fifo_full 信号是属于 FIFO 写时钟域的 
//所以要将其同步到读时钟域中 
always @(  posedge clk )  begin if( !rst_n )  begin almost_full_d0   <= 1'b0 ; almost_full_syn  <= 1'b0 ; end else  begin almost_full_d0   <= almost_full ; almost_full_syn  <= almost_full_d0 ; end 
end //读出 FIFO 的数据 
always  @( posedge clk )  begin if (!rst_n)  begin fifo_rd_en  <= 1'b0; state       <= 2'd0; dly_cnt     <= 4'd0; end else  begin case(state) 2'd0:  begin                      if(almost_full_syn)        //如果检测到 FIFO 被写满 state  <= 2'd1;         //就进入延时状态 else state  <= state; end  2'd1:  begin if(dly_cnt  == 4'd10)  begin //延时 10 拍 //原因是 FIFO IP 核内部状态信号的更新存在延时 //延迟 10 拍以等待状态信号更新完毕 dly_cnt  <= 4'd0;state    <= 2'd2;          //开始读操作 end else dly_cnt  <= dly_cnt + 4'd1; end 2'd2:  begin if(almost_empty)  begin     //等待 FIFO 将被读空(下一拍就会空) fifo_rd_en  <= 1'b0;    //关闭读使能 state       <= 2'd0;    //回到第一个状态 end else                       //如果 FIFO 没有被读空 fifo_rd_en  <= 1'b1;    //则持续打开读使能 end  default : state  <= 2'd0; endcase end 
end endmodule

如图所示:

在这里插入图片描述

3.3 分析与综合

对设计进行分析,操作如图所示:

在这里插入图片描述

分析后的设计,Vivado自动生成顶层原理图,如图所示:

在这里插入图片描述

对设计进行综合,操作如图所示:

在这里插入图片描述

综合完成后,弹出窗口如下,直接关闭:

在这里插入图片描述

3.4 约束输入

创建约束文件,操作如图所示:

在这里插入图片描述

创建约束文件,输入文件名:

在这里插入图片描述

双击打开,输入约束代码:

create_clock -period 20.000 -name clk [get_ports sys_clk] 
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk] 
set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports sys_rst_n] 

如图所示:

在这里插入图片描述

3.5 设计实现

点击 Flow Navigator 窗口中的 Run Implementation,如图所示:

在这里插入图片描述

点击OK:

在这里插入图片描述

完成后,关闭即可:

在这里插入图片描述

3.6 功能仿真

创建TestBench,操作如图所示:

在这里插入图片描述

创建激励文件,输入文件名:

在这里插入图片描述

创建完成:

在这里插入图片描述

双击打开,输入TestBench(激励)代码:

`timescale 1ns / 1ps 
module tb_ip_fifo(  ); 
// Inputs reg sys_clk; reg sys_rst_n; // Instantiate the Unit Under Test (UUT) 
ip_fifo  u_ip_fifo  ( .sys_clk         (sys_clk ),  .sys_rst_n       (sys_rst_n) 
); //Genarate the clk 
parameter PERIOD = 20; 
always  begin sys_clk = 1'b0; #(PERIOD/2) sys_clk = 1'b1; #(PERIOD/2 ); 
end  
initial  begin // Initialize Inputs sys_rst_n = 0; // Wait 100 ns for global reset to finish #100  ; sys_rst_n = 1; // Add stimulus here  
end 
endmodule 

如图所示:

在这里插入图片描述

开始进行仿真,操作如下:

在这里插入图片描述

选择HDL仿真对象:

在这里插入图片描述

点击Restart,波形窗口中的当前仿真时刻点回归到0ns:

在这里插入图片描述

写满数据后,fifo_full信号拉高:

在这里插入图片描述

读完数据后,fifo_empty信号拉高:

在这里插入图片描述

3.7 下载验证

由于疫情,一直无法去实验室,故ZYNQ开发板不在身边,该步骤内容待更新

致谢领航者ZYNQ开发板,开启FPGA学习之路!

希望本文对大家有帮助,上文若有不妥之处,欢迎指正

分享决定高度,学习拉开差距

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...