OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 9487|回复: 0
打印 上一主题 下一主题

[XILINX] 【正点原子FPGA连载】第十八章 IP核之FIFO实验--摘自【正点原子】超越者之FPGA开发指南 V1.1

[复制链接]

1424

主题

1440

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
6074
金钱
6074
注册时间
2019-5-8
在线时间
1739 小时
跳转到指定楼层
楼主
发表于 2021-1-14 11:56:04 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 正点原子运营 于 2021-1-18 16:16 编辑

1)实验平台:正点原子超越者FPGA开发板
2)平台购买地址:https://item.taobao.com/item.htm?&id=631660290421
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz-chaoyuezhe.html
4)本章实例源码下载: 第十八章 IP核之FIFO实验.zip (3.15 MB, 下载次数: 5)
5)正点原子FPGA交流群:905624739 点击加入:
6)关注正点原子公众号,获取最新资料更新



第十八章 IP核之FIFO实验

FIFO的英文全称是First In First Out,即先进先出。FPGA使用的FIFO一般指的是对数据的存储具有先进先出特性的一种缓存器,常被用于数据的缓存,或者高速异步数据的交互(即跨时钟域信号传递)。FIFO与FPGA内部的RAM和ROM的区别是FIFO没有外部读写地址线,采取顺序写入数据,顺序读出数据的方式,使用起来简单方便,由此带来的缺点就是不能像RAM和ROM那样可以由地址线决定读取或写入某个指定的地址。本章将通过对ISE软件自带的FIFO IP核进行读写测试,来向大家介绍Xilinx FIFO IP核的使用方法。
本章包括以下几个部分:
1            
1.1             简介
1.2             实验任务
1.3             硬件设计
1.4             程序设计
1.5             下载验证


1.1       简介
根据FIFO工作的时钟域,可以将FIFO分为同步FIFO和异步FIFO。同步FIFO是指读时钟和写时钟为同一个时钟,在时钟沿来临时同时发生读写操作。异步FIFO是指读写时钟不一致,读写时钟是互相独立的。Xilinx的FIFO IP核可以被配置为同步FIFO或异步FIFO,其信号框图如下图所示。从图中可以了解到,当被配置为同步FIFO时,只使用WR_CLK,所有的输入输出信号都同步于WR_CLK信号。而当被配置为异步FIFO时,写端口和读端口分别有独立的时钟,所有与写相关的信号都是同步于写时钟WR_CLK,所有与读相关的信号都是同步于读时钟RD_CLK。

图18.1.1 FIFO IP核示意图
对于FIFO需要了解一些常见参数。
FIFO的宽度:FIFO一次读写操作的数据位宽N。
FIFO的深度:FIFO可以存储多少个宽度为N位的数据。
空标志:empty。FIFO已空时由FIFO的状态电路送出的一个信号,用以阻止FIFO的读操作继续从FIFO中读出数据从而造成无效数据的读出。
将空标志:almost_empty。FIFO即将被读空。
满标志:full。FIFO已满时由FIFO的状态电路送出的一个信号,用以阻止FIFO的写操作继续向FIFO中写数据从而造成溢出。
将满标志:almost_full。FIFO即将被写满。
读时钟:读FIFO时所遵循的时钟,读操作在时钟的上升沿触发。
请注意,“almost_empty”和“almost_full”这两个信号分别被看作“empty”和“full”的警告信号,它们距离真正的空(empty)和满(full)都会提前一个时钟周期拉高。本实验将使用这两个信号。
写时钟:写FIFO时所遵循的时钟,写操作在每个时钟的上升沿触发。
对于FIFO的基本知识先了解这些就足够了,可能有人会好奇为什么会有同步FIFO和异步FIFO,它们各自的用途是什么。之所以有同步FIFO和异步FIFO是因为各自的作用不同,同步FIFO常用于同步时钟的数据缓存,异步FIFO常用于跨时钟域的数据信号的传递。例如时钟域A下的数据data1传递给异步时钟域B,当data1为连续变化信号时,如果直接传递给时钟域B则可能会导致所收非所送的情况(即在采集过程中会出现包括亚稳态问题在内的一系列问题),使用异步FIFO能够将不同时钟域中的数据同步到所需的时钟域中。
1.2       实验任务
本节的实验任务是使用ISE生成FIFO IP核,并实现以下功能:当FIFO为空时,向FIFO中写入数据,写入的数据量和FIFO深度一致,即FIFO被写满;然后从FIFO中读出数据,直到FIFO被读空为止,以此向大家详细介绍一下FIFO IP核的使用方法。
1.3       硬件设计
本章实验只用到了输入的时钟信号和按键复位信号,没有用到其它硬件外设。本实验中各端口信号的管脚分配如下表所示:
表18.3.1 引脚分配表
对应的UCF约束语句如下所示:
  1. <font size="4">NETsys_clk                       TNM_NET = sys_clk_pin;
  2. TIMESPECTS_sys_clk_pin = PERIOD sys_clk_pin 50000 kHz;
  3. NETsys_clk                       LOC =N8  | IOSTANDARD = "LVCMOS33";
  4. NETsys_rst_n                     LOC = G16 |IOSTANDARD = "LVCMOS33";</font>
复制代码
1.4       程序设计
根据实验任务要求和模块化的设计思想,我们需要4个模块:fifo IP核、写fifo模块、读fifo模块以及顶层例化模块,其中顶层例化模块主要用来实现前三个模块的信号交互。由于FIFO多用于跨时钟域信号的处理,所以本实验使用异步FIFO来向大家详细介绍双时钟FIFO IP核的创建和使用。为了方便大家理解,这里将读/写时钟都用系统时钟来驱动。系统的功能框图如下图所示:

图18.4.1系统框图
首先创建一个名为ip_fifo的工程,接下来创建fifo IP核。在ISE软件的左侧“Design”栏中右击工程名按钮,打开添加新文件选项栏,我们选择New Source,如下图所示:

图18.4.2 “New Source”按钮
打开NewSource之后选择IP(COREGenerator&Architecture Wizard),然后将FIFOIP核命名为fifo(也可以命名成别的名字,但是必须是英文命名),路径放在工程文件夹下,ISE会自动创建一个ipcore_dir文件夹用来存放IP核文件,如下图所示:

图18.4.3 创建FIFO IP核
如上图所示步骤设置完成后点击Next,进入IP核选择界面。在SearchIP Catalog搜索栏中搜索fifo,然后选择FIFO Generator,如下图所示:

图18.4.4创建FIFO IP核
按上图所示步骤操作之后点击Next进入Summary界面,如下图所示:

图18.4.5 Summary界面
在Summary界面直接点击Finish,接下来就是配置IP核参数的过程,如下图所示:

图18.4.6 参数配置
在上图中:
Component Name:FIFOIP核的命名,这里会直接显示之前创建IP时的命名。
Interface Type:Native本机接口FIFO,可以利用区块RAM、分布式RAM或内置的FIFO资源;AX14除了支持Native的应用功能外,还可以用于AX14系统总线和点对点高速应用程序,但是AX14FIFO不支持内置的FIFO与移位寄存器的FIFO设置。
选择Native类型然后点击Next,进入下一页参数设置,如下图所示:

图18.4.7参数配置
上图中:
BlockRAM:FPGA内部硬件存在的块RAM资源。
DistributeRAM:分布式RAM资源,使用FPGA内部的寄存器和查找表搭建起来的RAM,当深度要求小于32的时候可以使用。
ShiftRegister:使用FIFO产生一个移位寄存器。
Commonclock:同步时钟。
Independentclock:异步时钟。
选择Independent clocks选项并使用Block RAM资源,然后点击Next进入下一页参数设置,如下图所示:

图18.4.8参数配置
上图中:
Read Mode:选择StandardFIFO,标准FIFO模型。
Write Width:写数据位宽。
Write Depth:写数据深度,可以理解为FIFO的数据容量。
Read Width:读数据位宽。
这里按照上图所示设置好后,点击Next进入下一个参数页面设置,如下图所示:

图18.4.9参数配置
上图中:
Almost Full Flag:将满标志。
Almost Empty Flag:将空标志。
Write Acknowledge Flag:写应答标志,可以在其下方设置高电平有效(ActiveHigh)还是低电平有效(ActiveLow)。
Overflow Flag:当写指针追到了读指针,然后还继续写就会给出OverflowFlag标志,可以在其下方设置高电平有效(ActiveHigh)或低电平有效(ActiveLow)用来表示写错误。
Vaild Flag:读有效,可以在其下方设置高电平有效(ActiveHigh)还是低电平有效(ActiveLow)。
Underflow Flag:当读指针追到了写指针,然后还继续读就会给出underflowFlag标志,可以在其下方设置高电平有效(ActiveHigh)或低电平有效(ActiveLow)用来表示读错误。
按照上图所示设置后,点击Next进入下一参数设置页面,如下图所示:

图18.4.10参数配置
上图所示的这一页主要是复位的设置,这里我们不用作修改,保持默认,直接点击Next进入下一参数设置页面,如下图所示:

图18.4.11参数配置
上图所示把WriteData Count和ReadData Count读写计数器选上,主要用来观察写进去了多少个数据,还剩多少个数据可读。注意读写计数器的位宽要足够大,保证计数器的最大值大于fifo的深度,否则计数器会溢出。之后点击Next进入下一参数设置页面,如下图所示:

图18.4.12参数配置
上图所示的是要创建的FIFOIP核的Summary界面,检查一下设置,如果有问题就点击Back返回重新设置参数,如果没问题就点击Generate生成FIFO IP核。
回到Design工具栏下可以看到创建的FIFO IP核已经出现在工程栏下了,如下图所示:

图18.4.13 FIFO创建完成
现在就可以添加设计源文件了。本次是对FIFOIP核进行读写,所以需要一个读模块、一个写模块还要一个顶层例化模块。下面先来看顶层例化模块:
  1. <font size="4">module fifo_top(
  2.     input   sys_clk   ,// 时钟信号
  3.     input   sys_rst_n   // 复位信号   

  4.     );

  5. wire [7:0 fifo_din                  ;
  6. wire fifo_wr_en                      ;
  7. wire fifo_rd_en                      ;
  8. wire [7:0 fifo_dout                 ;
  9. wire fifo_full                       ;
  10. wire almost_full                     ;
  11. wire wr_ack                          ;
  12. wire overflow                        ;
  13. wire fifo_empty                      ;
  14. wire almost_empty                    ;
  15. wire valid                           ;
  16. wire underflow                       ;
  17. wire [7:0fifo_wr_data_count        ;
  18. wire [7:0fifo_rd_data_count        ;

  19. fifo u_fifo        (
  20.    .wr_clk            (sys_clk            ), // input wr_clk
  21.    .rd_clk           (sys_clk            ), // input rd_clk
  22.    .din               (fifo_din           ), // input [7 : 0] din
  23.    .wr_en             (fifo_wr_en         ), // input wr_en
  24.    .rd_en             (fifo_rd_en         ), // input rd_en
  25. .dout              (fifo_dout         ),// output [7 : 0] dout
  26.    .full             (fifo_full          ), // output full
  27.    .almost_full      (almost_full        ), // output almost_full
  28.    .wr_ack            (wr_ack             ), // output wr_ack
  29.    .overflow          (overflow           ), // output overflow
  30.    .empty             (fifo_empty         ), // output empty
  31.    .almost_empty     (almost_empty       ), // output almost_empty
  32.    .valid             (valid              ), // output valid
  33.    .underflow         (underflow          ), // output underflow
  34.    .rd_data_count     (fifo_wr_data_count ),// output [7 : 0] rd_data_count
  35.    .wr_data_count     (fifo_rd_data_count )  //output [7 : 0] wr_data_count
  36. );

  37. fifo_wr  u_fifo_wr (
  38.    .clk            ( sys_clk           ), // 写时钟
  39.    .rst_n          ( sys_rst_n         ), // 复位信号
  40.         
  41.    .fifo_wr_en     ( fifo_wr_en        ), // fifo写请求
  42.    .fifo_wr_data   (fifo_din          ), // 写入FIFO的数据
  43.    .almost_empty   (almost_empty      ), // fifo空信号
  44.    .almost_full    ( almost_full       )  // fifo满信号
  45. );     

  46. fifo_rd  u_fifo_rd (
  47.    .clk            ( sys_clk           ), // 读时钟
  48.    .rst_n          ( sys_rst_n         ), // 复位信号

  49.    .fifo_rd_en     ( fifo_rd_en        ), // fifo读请求
  50.    .fifo_dout      ( fifo_dout         ), // 从FIFO输出的数据
  51.    .almost_empty   (almost_empty      ), // fifo空信号
  52.    .almost_full    ( almost_full       )  // fifo满信号
  53. );

  54. endmodule</font>
复制代码
顶层模块主要是对FIFOIP核、写FIFO模块和读FIFO模块进行例化。需要注意的是从整个顶层来看,工程对外没有任何输出,所有的数据读写都是在FPGA内部进行的,编译器会认为我们的代码端口对外界不起作用,所以ISE会编译报错,不过没关系,我们可以将需要观察的信号设置成output型,这样既可以防止在Chipscope中信号被综合优化,又可以使工程编译通过。当然你也可以不设置为输出,创建一个Chipscope的在线调试文件(可以参考软件使用篇),将待观察信号接到在线调试IP核上,这样编译也可以编译通过,然后通过Chipscope观察信号。(特别注意:刚拿到我们的例程是没有对端口作处理的,直接编译会报错)。
顶层模块完成后,接着看看例化的子模块代码。fifoip核模块就不用看了,因为fifoip核是我们配置参数后软件自动生成的,主要来看看读写模块的代码。下面是写FIFO模块(fifo_wr.v)源文件的代码:
  1. <font size="4">module fifo_wr(
  2.      input                 clk    ,          // 时钟信号
  3.      input                  rst_n ,          // 复位信号
  4.      
  5.      input                 almost_empty,     //FIFO将空信号
  6.      input                 almost_full ,     //FIFO将满信号
  7.      output    reg         fifo_wr_en ,      // FIFO写使能
  8.      output    reg  [7:0   fifo_wr_data      // 写入FIFO的数据
  9. );

  10. //reg define
  11. reg  [1:0  state            ;  //动作状态
  12. reg        almost_empty_d0  ;  //almost_empty 延迟一拍
  13. reg        almost_empty_syn ;  //almost_empty延迟两拍
  14. reg  [3:0  dly_cnt          ;  //延迟计数器
  15. //*****************************************************
  16. //**                   main code
  17. //*****************************************************

  18. //因为almost_empty 信号是属于FIFO读时钟域的
  19. //所以要将其同步到写时钟域中
  20. always@( posedge clk ) begin
  21. if( !rst_n ) begin
  22.       almost_empty_d0  <= 1'b0 ;
  23.       almost_empty_syn <= 1'b0 ;
  24. end
  25. else begin
  26.       almost_empty_d0  <= almost_empty ;
  27.       almost_empty_syn <= almost_empty_d0 ;
  28. end
  29. end

  30. //向FIFO中写入数据
  31. always @(posedge clk ) begin
  32.     if(!rst_n) begin
  33.          fifo_wr_en   <=1'b0;
  34.          fifo_wr_data <= 8'd0;
  35.          state        <= 2'd0;
  36.       dly_cnt      <= 4'd0;
  37.      end
  38.      else begin
  39.          case(state)
  40.              2'd0: begin
  41.                  if(almost_empty_syn) begin  //如果检测到FIFO将被读空(下一拍就会空)
  42.                      state <= 2'd1;          //就进入延时状态
  43.                  end
  44.                  else
  45.                      state <= state;
  46.              end
  47.           2'd1: begin
  48.                  if(dly_cnt == 4'd10) begin  //延时10拍
  49.                                              //原因是FIFO IP核内部状态信号的更新存在延时
  50.                                              //延迟10拍以等待状态信号更新完毕                  
  51.                   dly_cnt    <= 4'd0;     
  52.                   state      <= 2'd2;        //开始写操作
  53.                   fifo_wr_en <= 1'b1;        //打开写使能
  54.               end
  55.               else
  56.                   dly_cnt <= dly_cnt + 4'd1;
  57.              end            
  58.           2'd2: begin
  59.                  if(almost_full) begin      //等待FIFO将被写满(下一拍就会满)
  60.                      fifo_wr_en   <=1'b0;  //关闭写使能
  61.                      fifo_wr_data <= 8'd0;
  62.                      state        <= 2'd0;  //回到第一个状态
  63.                  end
  64.                  else begin                 //如果FIFO没有被写满
  65.                      fifo_wr_en   <=1'b1;  //则持续打开写使能
  66.                      fifo_wr_data <= fifo_wr_data + 1'd1;  //且写数据值持续累加
  67.                  end
  68.              end
  69.           default : state <= 2'd0;
  70.          endcase
  71.      end
  72. end

  73. endmodule</font>
复制代码
fifo_wr模块的核心部分是一个不断进行状态循环的状态机,如果检测到FIFO为空,则先延时10拍,这里注意,由于FIFO的内部信号的更新比实际的数据读/写操作有所延时,所以延时10拍的目的是等待FIFO的空/满状态信号、数据计数信号等信号更新完毕之后再进行FIFO写操作。如果写满,则回到状态0,即等待FIFO被读空,进行下一轮的写操作。
读FIFO模块fifo_rd.v源文件的代码如下:
  1. <font size="4">module fifo_rd(
  2.      input               clk          ,   //时钟信号
  3.      input              rst_n        ,   // 复位信号

  4.      input        [7:0 fifo_dout    ,   // 从FIFO读出的数据
  5.      input              almost_full  ,   // FIFO将满信号
  6.      input              almost_empty ,   //FIFO将空信号
  7.      output  reg        fifo_rd_en       // FIFO读使能
  8. );

  9. //reg define
  10. reg  [1:0  state           ;  //动作状态
  11. reg        almost_full_d0  ;  //almost_full延迟一拍
  12. reg        almost_full_syn ;  //almost_full延迟两拍
  13. reg  [3:0  dly_cnt         ;  //延迟计数器

  14. //*****************************************************
  15. //**                   main code
  16. //*****************************************************

  17. //因为fifo_full 信号是属于FIFO写时钟域的
  18. //所以要将其同步到读时钟域中
  19. always@( posedge clk ) begin
  20. if( !rst_n ) begin
  21.       almost_full_d0  <= 1'b0 ;
  22.       almost_full_syn <= 1'b0 ;
  23. end
  24. else begin
  25.       almost_full_d0  <= almost_full ;
  26.       almost_full_syn <= almost_full_d0 ;
  27. end
  28. end

  29. //读出FIFO的数据
  30. always @(posedge clk ) begin
  31.      if(!rst_n) begin
  32.          fifo_rd_en <= 1'b0;
  33.          state      <= 2'd0;
  34.          dly_cnt    <= 4'd0;
  35.      end
  36.      else begin
  37.          case(state)
  38.              2'd0: begin                     
  39.                  if(almost_full_syn)        //如果检测到FIFO被写满
  40.                      state <= 2'd1;         //就进入延时状态
  41.                  else
  42.                      state <= state;
  43.              end
  44.           2'd1: begin
  45.                  if(dly_cnt == 4'd10) begin //延时10拍
  46.                                             //原因是FIFO IP核内部状态信号的更新存在延时
  47.                                             //延迟10拍以等待状态信号更新完毕
  48.                      dly_cnt <= 4'd0;
  49.                   state   <=2'd2;          //开始读操作
  50.               end
  51.               else
  52.                   dly_cnt <= dly_cnt + 4'd1;
  53.              end
  54.           2'd2: begin
  55.                  if(almost_empty) begin     //等待FIFO将被读空(下一拍就会空)
  56.                      fifo_rd_en <= 1'b0;    //关闭读使能
  57.                      state     <= 2'd0;    //回到第一个状态
  58.                  end
  59.                  else                      //如果FIFO没有被读空
  60.                      fifo_rd_en <= 1'b1;    //则持续打开读使能
  61.              end
  62.           default : state <= 2'd0;
  63.         endcase
  64.      end
  65. end

  66. endmodule</font>
复制代码
读模块的代码结构与写模块几乎一样,也是使用一个不断进行状态循环的状态机来控制操作过程,代码比较简单,这里就不再赘述。
下面我们来对写好的工程进行仿真验证一下功能,在仿真前我们先对顶层文件(fifo_top)做一下处理如下图所示:

图18.4.14 对顶层模块做处理
将需要观察的信号全部重新定义一遍,并加上后缀为“_tb”,然后使用assign语句把原信号赋值给重新定义的待观察信号,最后把所有带后缀“_tb”的待观察信号当作输出端口输出,这样无论是写Tsetbench仿真文件还是使用Chipscope在线调试都比较方便,编译不会报错,抓取信号也不会被综合优化。
将顶层文件处理好后就可以生成Testbench文件了(不会生成Testbench文件的可以参考软件使用篇),模板生成完后写激励如下所示:
  1. <font size="4">`timescale 1ns / 1ps

  2. module fifo_top_tb;
  3.     // Inputs
  4.     regsys_clk;
  5.     regsys_rst_n;
  6.    
  7.     wire [7:0 fifo_din_tb                   ;//仿真在线调试专用
  8.     wire fifo_wr_en_tb                      ;
  9.     wire fifo_rd_en_tb                      ;
  10.     wire [7:0 fifo_dout_tb                  ;
  11.     wire fifo_full_tb                       ;   
  12.     wire almost_full_tb                     ;
  13.     wire wr_ack_tb                          ;
  14.     wire overflow_tb                        ;   
  15.     wire fifo_empty_tb                      ;
  16.     wire almost_empty_tb                    ;   
  17.     wire valid_tb                           ;   
  18.     wire underflow_tb                       ;   
  19.     wire [7:0 fifo_wr_data_count_tb         ;   
  20.     wire [7:0 fifo_rd_data_count_tb         ;      
  21.   
  22.     // Instantiate the Unit Under Test (UUT)
  23.     fifo_top uut (
  24.         .sys_clk                (sys_clk                ),
  25.         .sys_rst_n              (sys_rst_n              ),
  26.         .fifo_din_tb           (fifo_din_tb            ),
  27.         .fifo_wr_en_tb         (fifo_wr_en_tb          ),  
  28.         .fifo_rd_en_tb         (fifo_rd_en_tb          ),  
  29.         .fifo_dout_tb          (fifo_dout_tb           ),
  30.         .fifo_full_tb          (fifo_full_tb           ),  
  31.         .almost_full_tb        (almost_full_tb         ),      
  32.         .wr_ack_tb             (wr_ack_tb              ),  
  33.         .overflow_tb           (overflow_tb            ),  
  34.         .fifo_empty_tb         (fifo_empty_tb          ),  
  35.         .almost_empty_tb       (almost_empty_tb        ),  
  36.         .valid_tb              (valid_tb               ),   
  37.         .underflow_tb          (underflow_tb           ),  
  38.         .fifo_wr_data_count_tb (fifo_wr_data_count_tb  ),
  39.         .fifo_rd_data_count_tb (fifo_rd_data_count_tb  )      
  40.         
  41.     );
  42.   
  43.     initial begin
  44.         // Initialize Inputs
  45.         sys_clk =0;
  46.         sys_rst_n =0;
  47.   
  48.         // Wait 100 ns for global reset to finish
  49.         #100;
  50.         sys_rst_n=1;
  51.         // Add stimulus here
  52.   
  53.     end
  54.     always #10sys_clk=~sys_clk;
  55. endmodule</font>
复制代码
Testbench文件完成后点击保存,然后点击Modelsim仿真按钮,调用Modelsim进行仿真(不熟悉的可以参考Modelsim章节)。
仿真波形如下图所示:

图18.4.15 仿真波形图
上图是整体波形,从图中可以看到读写是交替进行的,处于写状态时写使能打开(fifo_wr_en_tb)、写数据跳变(fifo_din_tb)、写有效标志拉高(wr_ack_tb)、写数据计数器计数(fifo_wr_data_count_tb)、没有出现写错误,写错误信号保持低电平(overflow_tb),当数据写结束时先提前一个时钟拉高将满信号(almost_full_tb),再拉高写满信号(fifo_full_tb);读也是一样的,处于读状态时读使能打开(fifo_rd_en_tb)、读数据读出(fifo_dout_tb)、读有效标志拉高(valid_tb)、读数据计数器计数(fifo_rd_data_count_tb)、没有出现读错误,读错误信号保持低电平(underflow_tb)、当数据读结束时先提前一个时钟拉高将空信号(almost_empty_tb),再拉高读空信号(fifo_empty_tb);
我们放大波形图来看一下细节如下图所示:

图18.4.16仿真波形细节图
上图是处于写状态时的细节,可以看到一共写了255个数(0~254),在快写满时确实是先拉高将满信号,再拉高写满信号;看完了写状态的细节我们再看看读状态的细节,如下图所示:

图18.4.17仿真波形细节图
读状态也可以看到它读出的数据跟写入的一模一样,也是先拉高将空信号,再拉高读空信号。这就说明我们的FIFOIP核工程目前仿真功能是完全正常的,接下来就可以添加UCF文件进行管脚分配和时序约束了(不熟悉的可以参考软件使用篇),最后我们使用Chipscope工具进行下板子实际验证一下功能是否正确。
1.5       下载验证
首先将下载器与超越者开发板上的JTAG接口连接,下载器另外一端与电脑连接,然后连接开发板的电源,并打开电源开关。
打开Chipscope工具,将刚刚生成好的逻辑分析仪IP核下载到板子上去,然后运行如下图所示:

图18.5.1在线调试波形图
上图中可以看到波形与仿真的波形是一样的,为了进一步确认功能,可以将波形放大看一下细节如下图所示:

图18.5.2在线调试波形细节图
上图是写数据时的细节,跟我们仿真图是一样的,说明写数据没有问题,我们再看看读数据时的波形细节,如下图所示:

图18.5.3在线调试波形细节图
可以看到读状态波形的细节也是符合预期,到此就可以说明本次FIFO IP核的功能是正常的,本次例程实验成功。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

如发现本坛存在违规或侵权内容, 请点击这里发送邮件举报 (或致电020-38271790)。请提供侵权说明和联系方式。我们将及时审核依法处理,感谢配合。

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2026-10-21 09:02

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表