本帖最后由 正点原子运营 于 2023-11-18 16:40 编辑
第二十章 IP核之FIFO实验
1)实验平台:正点原子 ATK-DFPGL22G开发板
2) 章节摘自【正点原子】ATK-DFPGL22G之FPGA开发指南_V1.0
6)FPGA技术交流QQ群:435699340
FIFO的英文全称是First In First Out,即先进先出。FPGA使用的FIFO一般指的是对数据的存储具有先进先出特性的一个缓存器,常被用于数据的缓存,或者高速异步数据的交互也即所谓的跨时钟域信号传递。它与FPGA内部的RAM和ROM的区别是没有外部读写地址线,采取顺序写入数据,顺序读出数据的方式,使用起来简单方便,由此带来的缺点就是不能像RAM和ROM那样可以由地址线决定读取或写入某个指定的地址。本章我们将对PDS软件生成的FIFO IP核进行读写测试,来向大家介绍Pango FIFO IP核的使用方法。 本章包括以下几个部分: 1.1 FIFO IP核简介 1.2 实验任务 1.3 硬件设计 1.4 程序设计 1.5 下载验证
1.1 FIFO IP核简介根据FIFO工作的时钟域,可以将FIFO分为同步FIFO和异步FIFO。同步FIFO是指读时钟和写时钟为同一个时钟,在时钟沿来临时同时发生读写操作。异步FIFO是指读写时钟不一致,读写时钟是互相独立的。Pango的FIFO IP核可以被配置为同步FIFO或异步FIFO,其信号框图如下图所示。从图中可以了解到,当被配置为同步FIFO时,只使用wr_clk,所有的输入输出信号都同步于wr_clk信号。而当被配置为异步FIFO时,写端口和读端口分别有独立的时钟,所有与写相关的信号都是同步于写时钟wr_clk,所有与读相关的信号都是同步于读时钟rd_clk。 图20.1.1 Pango的FIFO IP核的信号框图 对于FIFO需要了解一些常见参数: FIFO的宽度:FIFO一次读写操作的数据位N。 FIFO的深度:FIFO可以存储多少个宽度为N位的数据。 将空标志:almost_empty。FIFO即将被读空。 空标志:rd_empty。FIFO已空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出。 将满标志:almost_full。FIFO即将被写满。 满标志:wr_full。FIFO已满或将要写满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出。 读时钟:读FIFO时所遵循的时钟,在每个时钟的上升沿触发。 写时钟:写FIFO时所遵循的时钟,在每个时钟的上升沿触发。 这里请注意,“almost_empty”和“almost_full”这两个信号分别被看作“empty”和“full”的警告信号,他们相对于真正的空(empty)和满(full)都会提前一个时钟周期拉高。
对于FIFO的基本知识先了解这些就足够了,可能有人会好奇为什么会有同步FIFO和异步FIFO,它们各自的用途是什么。之所以有同步FIFO和异步FIFO是因为各自的作用不同。同步FIFO常用于同步时钟的数据缓存,异步FIFO常用于跨时钟域的数据信号的传递,例如时钟域A下的数据data1传递给异步时钟域B,当data1为连续变化信号时,如果直接传递给时钟域B则可能会导致收非所送的情况,即在采集过程中会出现包括亚稳态问题在内的一系列问题,使用异步FIFO能够将不同时钟域中的数据同步到所需的时钟域中。
1.2 实验任务本节的实验任务是使用Pango生成FIFO IP核,并实现以下功能:当FIFO为空时,向FIFO中写入数据,写入的数据量和FIFO深度一致,即FIFO被写满;然后从FIFO中读出数据,直到FIFO被读空为止,以此向大家详细介绍一下FIFO IP核的使用方法。
1.3 硬件设计本章实验只用到了输入的时钟信号和按键复位信号,没有用到其它硬件外设。 本实验中,各端口信号的管脚分配如下表所示。
对应的FDC约束语句如下所示: - define_attribute{p:sys_clk} {PAP_IO_DIRECTION} {INPUT}
- define_attribute{p:sys_clk} {PAP_IO_LOC} {B5}
- define_attribute{p:sys_clk} {PAP_IO_VCCIO} {3.3}
- define_attribute{p:sys_clk} {PAP_IO_STANDARD} {LVCMOS12}
- define_attribute{p:sys_clk} {PAP_IO_NONE} {TRUE}
- define_attribute{p:sys_rst_n} {PAP_IO_DIRECTION} {INPUT}
- define_attribute{p:sys_rst_n} {PAP_IO_LOC} {G5}
- define_attribute{p:sys_rst_n} {PAP_IO_VCCIO} {1.5}
- define_attribute{p:sys_rst_n} {PAP_IO_STANDARD} {LVCMOS12}
- define_attribute {p:sys_rst_n}{PAP_IO_NONE} {TRUE}
复制代码
1.4 程序设计根据实验任务要求和模块化设计的思想,我们需要如下4个模块:fifo IP核、写fifo模块、读fifo模块以及顶层例化模块实现前三个模块的信号交互。由于FIFO多用于跨时钟域信号的处理,所以本实验我们使用异步FIFO来向大家详细介绍双时钟FIFO IP核的创建和使用。为了方便大家理解,这里我们将读/写时钟都用系统时钟来驱动。系统的功能框图如下图所示: 图 20.4.1 系统框图 首先在PDS软件中创建一个名为ip_fifo的工程,工程创建完成后,在PDS软件的上方的菜单栏中“Tools”栏中单击“IP Compiler”按钮后弹出的“IP Compiler”窗口如图 20.4.3所示。 本实验使用的IP核路径是Module→Memory→DRM→DRM Base FIFO,如下图所示。 图 20.4.4 DRM Base FIFO IP 点击上图中红框中的IP后如下图所示: 图 20.4.5 DRM Base FIFO详情页面 Pathname:新建IP核在工程所在路径,这里保持默认即可。 InstanceName:在这里给新建的FIFO IP命名,我们这里命名为“fifo_generator_0”。 接下来的IP框里面的内容是该IP的基础信息,例如名称、版本号与所属公司(Pango)。Part框中的信息为工程所使用的芯片的详细信息“PGL22G-6CMBG324”。 点击上图中的“Customize”按钮进入“Customize IP”窗口对FIFO IP的参数进行配置,“Customize IP”窗口界面如下图所示:图中的“Add IP”弹窗点击“Yes”后进入“CustomizeIP”界面进行异步FIFO的参数配置,“Customize IP”界面如图 20.4.7所示。 本实验我们主要进行如下配置: 图 20.4.8 DRM Base FIFO参数配置界 Customize IP界面主要包括如下选项: DRM Resource Usage:选项主要说明DRM资源使用情况。该选项下的“DRM Resource Type”是DRM资源类型,可以设置“AUTO”、“DRM9K”、“DRM18K”三种模式。三种模式可以根据你需要地址宽度与数据宽度来来设置,一般我们设置为“AUTO”模式。 Write/Read Port Use Same Data Widt:配置读写端口是否使用混合位宽模式(注:混合位宽时,关闭Address Strobe功能),本实验勾选该选项,使用混合位宽模式,只需要配置写入端口的地址位宽与数据位宽,读端口的地址位宽与数据位宽会与写入端口保持一致。 FIFO Type: FIFO可以配置的类型有两种,"ASYN_FIFO"异步FIFO和"SYNC_FIFO"同步FIFO,本实验配置的是异步FIFO类型。 Enable Byte Write:配置是否使能Byte Write功能,其含义是Byte写使能,也就是以字节为单位写入数据;Byte Write使能时,同时需要配置字节(Byte)的位宽(Byte Size)与字节个数(Byte Numbers),Byte Size可选择8或者9;Byte Numbers即配置所使用的Byte个数(注:Byte Write使能时,关闭Address Strobe功能。)举例说明:输入数据为32-bit,字节的位宽(Byte Size)设置为8bit,那么就需要4-bit Byte写使能信号,这个使能信号与输入数据各位的对应关系如下图所示。从图中不难看出,当we[3]有效时,只会将输入数据的高8-bit写入到目标地址;当we[0]有效时,只会将输入数据的低8-bit写入到目标地址。其实,也就是根据写使能来更新指定地址上原始数据的某些位,本实验不需要使能Byte Write功能即不需要勾选该配置。 图 20.4.9 Byte写使能与输入数据的对应关系
Write Port:对写入端口进行配置。AddressWidth配置地址位宽,Data Width配置数据位宽。地址位宽合法配置范围为5~20,数据位宽合法配置范围为1~1152,但是所占用的DRM9K或者DRM18K个数必须小于总资源个数。本实验我们配置的地址位宽为5,数据位宽为8位。 Read Port:对读出端口进行配置。Address Width配置地址位宽,Data Width配置数据位宽。地址位宽合法配置范围为5~20,数据位宽合法配置范围为1~1152,但是所占用的DRM9K或者DRM18K个数必须小于总资源个数。本实验我们配置使用了混合位宽模式,所以读端口的地址位宽与数据位宽会直接与写端口的配置保持一致。 Enable Almost Full Water Level:配置是否使能wr_water_level信号,使能wr_water_level信号可以对写端口数据进行计数,本实验配置使能写端口计数。 Enable Almost Empty Water Level:配置是否使能wr_empty_level信号,使能wr_empty_level信号可以对读端口数据进行计数,本实验配置使能读端口计数。 Almost Full Numbers:配置FIFO Almost Full个数,设置为该选项后面的允许的最大值。 Almost Empty Numbers:配置FIFO Almost Empty个数,设置为该选项后面的允许的最小值。 Enablerd_oce Signal:配置是否使能rd_oce(输出寄存器选项)信号,输出寄存使能信号为高时对应地址有效,读数据会寄存输出,若输出寄存使能信号为低时对应地址无效,读数据保持。并且使能rd_oce信号时,默认且必须使能读端口输出寄存“Enable Output Register”,本实验不需要使能读信号,所以不勾选该选项。 Enable Output Register:输出寄存器选项。如果勾选了“Enable rd_oce Signal”信号,输出寄存器默认是选中状态,作用是打开DRM内部位于输出数据总线之后的输出流水线寄存器,虽然在一般设计中为了改善时序性能会保持此选项的默认勾选状态,但是这会使得BRM输出的数据延迟一拍,这不利于我们在调试窗口中直观清晰地观察信号;而且在本实验中我们仅仅是把BRM的数据输出总线连接到了调试的探针端口上来进行观察,除此之外数据输出总线没有别的负载,不会带来难以满足的时序路径,因此这里取消勾选。 Enable Clock Polarity Invert for OutputRegister:配置是否使能读端口输出时钟极性反向,使能读端口输出时钟极性反向时,默认且必须使能读端口输出寄存(Enable Output Register),这里不需要使能读端口输出时钟极即不需要勾选该配置。 Enable Low Power Mode:配置是否使能低功耗模式,本实验不需要配置成低功耗模式,即不勾选使能低功耗模式。 Reset Type:配置复位方式:"ASYNC"异步复位,"SYNC"同步复位,"Sync_Internally "异步复位同步释放,本实验选择异步复位(低有效)。 至此本实验所需要的异步FIFO IP已配置完成,接下来点击“Customize IP”窗口左上角的“Generate”在弹出的“Question”对话框选择“OK”即可,如下图所示。 点击“OK”后打印如下左图信息,至此FIFO IP核配置成功,并生成fifo_generator_0_tmpl.v文件。例化FIFO IP时可以使用下图中fifo_generator_0_tmpl.v文件红框中的代码。 然后如下图所示,关闭“Customize IP”页面与“IP Compiler”页面。 之后我们就可以在“Sources”窗口的“Designs”一栏中出现了该IP核“fifo_generator_0”如下图所示。 我们创建一个verilog源文件,其名称为ip_fifo.v,作为顶层模块,其代码如下: - 1 module ip_fifo(
- 2 input sys_clk , // 时钟信号
- 3 input sys_rst_n // 复位信号
- 4 );
- 5
- 6 //wire define
- 7 wire fifo_wr_en ; // FIFO写使能信号
- 8 wire fifo_rd_en ; // FIFO读使能信号
- 9 wire [7:0 fifo_din ; // 写入到FIFO的数据
- 10 wire [7:0 fifo_dout ; // 从FIFO读出的数据
- 11 wire almost_full ; // FIFO将满信号
- 12 wire almost_empty ; // FIFO将空信号
- 13 wire fifo_full ; // FIFO满信号
- 14 wire fifo_empty ; // FIFO空信号
- 15 wire [7:0 fifo_wr_data_count ; //FIFO写时钟域的数据计数
- 16 wire [7:0 fifo_rd_data_count ; //FIFO读时钟域的数据计数
- 17
- 18 //*****************************************************
- 19 //** main code
- 20 //*****************************************************
- 21
- 22 reg almost_empty_d0 ; //almost_empty 延迟一拍
- 23 reg almost_empty_d1 ; //almost_empty 延迟两拍
- 24 reg almost_empty_syn ; //almost_empty延迟三拍
- 25
- 26 reg almost_full_d0 ; //almost_full 延迟一拍
- 27 reg almost_full_d1 ; //almost_full 延迟两拍
- 28 reg almost_full_syn ; //almost_full 延迟三拍
- 29
- 30 //因为almost_empty 信号是属于FIFO读时钟域的
- 31 //所以要将其同步到写时钟域中
- 32 always@( posedge sys_clk ) begin
- 33 if( !sys_rst_n ) begin
- 34 almost_empty_d0 <= 1'b0 ;
- 35 almost_empty_syn <= 1'b0 ;
- 36 almost_empty_d1 <= 1'b0 ;
- 37 end
- 38 else begin
- 39 almost_empty_d0 <= almost_empty ;
- 40 almost_empty_d1 <= almost_empty_d0 ;
- 41 almost_empty_syn <= almost_empty_d1 ;
- 42 end
- 43 end
- 44
- 45 //因为almost_full 信号是属于FIFO读时钟域的
- 46 //所以要将其同步到写时钟域中
- 47 always@( posedge sys_clk ) begin
- 48 if( !sys_rst_n ) begin
- 49 almost_full_d0 <= 1'b0 ;
- 50 almost_full_syn <= 1'b0 ;
- 51 almost_full_d1 <= 1'b0 ;
- 52 end
- 53 else begin
- 54 almost_full_d0 <= almost_full ;
- 55 almost_full_d1 <= almost_full_d0 ;
- 56 almost_full_syn <= almost_full_d1 ;
- 57 end
- 58 end
- 59
- 60 fifo_generator_0u_fifo_generator_0 (
- 61 .wr_clk (sys_clk ), //input
- 62 .wr_rst (~sys_rst_n ), //input
- 63 .wr_en (fifo_wr_en ), //input
- 64 .wr_data (fifo_din ), //input [7:0]
- 65 .wr_full (fifo_full ), //output
- 66 .wr_water_level (fifo_wr_data_count), // output [8:0]
- 67 .almost_full (almost_full ), //output
- 68 .rd_clk (sys_clk ), //input
- 69 .rd_rst (~sys_rst_n ), //input
- 70 .rd_en (fifo_rd_en ), //input
- 71 .rd_data (fifo_dout ), //output [7:0]
- 72 .rd_empty (fifo_empty ), //output
- 73 .rd_water_level (fifo_rd_data_count), // output [8:0]
- 74 .almost_empty (almost_empty ) //output
- 75 );
- 76
- 77 //例化写FIFO模块
- 78 fifo_wr u_fifo_wr(
- 79 .clk ( sys_clk ), //写时钟
- 80 .rst_n ( sys_rst_n ), //复位信号
- 81
- 82 .fifo_wr_en ( fifo_wr_en ), //fifo写请求
- 83 .fifo_wr_data ( fifo_din ), //写入FIFO的数据
- 84 .almost_empty ( almost_empty_syn ), // fifo空信号
- 85 .almost_full ( almost_full_syn ) //fifo满信号
- 86 );
- 87
- 88 //例化读FIFO模块
- 89 fifo_rd u_fifo_rd(
- 90 .clk ( sys_clk ), //读时钟
- 91 .rst_n ( sys_rst_n ), //复位信号
- 92
- 93 .fifo_rd_en ( fifo_rd_en ), //fifo读请求
- 94 .fifo_dout ( fifo_dout ), //从FIFO输出的数据
- 95 .almost_empty ( almost_empty_syn ), // fifo空信号
- 96 .almost_full ( almost_full_syn ) //fifo满信号
- 97 );
- 98
- 99 endmodule
复制代码顶层模块主要是对FIFOIP核、写FIFO模块、读FIFO模块进行例化。 写FIFO模块fifo_wr.v源文件的代码如下: - 1 module fifo_wr(
- 2 //mudule clock
- 3 input clk , // 时钟信号
- 4 input rst_n , // 复位信号
- 5 //FIFO interface
- 6 input almost_empty, //FIFO将空信号
- 7 input almost_full , //FIFO将满信号
- 8 output reg fifo_wr_en , // FIFO写使能
- 9 output reg [7:0 fifo_wr_data // 写入FIFO的数据
- 10 );
- 11
- 12 //reg define
- 13 reg [1:0 state ; //动作状态
- 14 reg [3:0 dly_cnt ; //延迟计数器
- 15 //*****************************************************
- 16 //** main code
- 17 //*****************************************************
- 18 //向FIFO中写入数据
- 19 always @(posedge clk ) begin
- 20 if(!rst_n) begin
- 21 fifo_wr_en <=1'b0;
- 22 fifo_wr_data <= 8'd0;
- 23 state <= 2'd0;
- 24 dly_cnt <= 4'd0;
- 25 end
- 26 else begin
- 27 case(state)
- 28 2'd0: begin
- 29 if(almost_empty) begin //如果检测到FIFO将被读空
- 30 state <= 2'd1; //就进入延时状态
- 31 end
- 32 else
- 33 state <= state;
- 34 end
- 35 2'd1: begin
- 36 if(dly_cnt == 10) begin //延时10拍
- 37 //原因是FIFO IP核内部状态信号的更新存在延时
- 38 //延迟10拍以等待状态信号更新完毕
- 39 dly_cnt <= 4'd0;
- 40 state <= 2'd2; //开始写操作
- 41 fifo_wr_en <= 1'b1; //打开写使能
- 42 end
- 43 else begin
- 44 dly_cnt <= dly_cnt + 4'd1;
- 45 end
- 46 end
- 47 2'd2: begin
- 48 if(almost_full) begin //等待FIFO将被写满
- 49 fifo_wr_en <=1'b0; //关闭写使能
- 50 fifo_wr_data <= 8'd0;
- 51 state <= 2'd0; //回到第一个状态
- 52 end
- 53 else begin //如果FIFO没有被写满
- 54 fifo_wr_en <=1'b1; //则持续打开写使能
- 55 fifo_wr_data <= fifo_wr_data + 1'd1; //且写数据值持续累加
- 56 end
- 57 end
- 58 default : state <= 2'd0;
- 59 endcase
- 60 end
- 61 end
- 62
- 63 endmodule
复制代码fifo_wr模块的核心部分是一个不断进行状态循环的小状态机,如果检测到FIFO为空,则先延时10拍,这里注意,由于FIFO的内部信号的更新比实际的数据读/写操作有所延时,所以延时10拍的目的是等待FIFO的空/满状态信号、数据计数信号等信号的更新完毕之后再进行FIFO写操作,如果写满,则回到状态0,即等待FIFO被读空,以进行下一轮的写操作。 读FIFO模块fifo_rd.v源文件的代码如下: - 1 module fifo_rd(
- 2 //system clock
- 3 input clk , // 时钟信号
- 4 input rst_n , // 复位信号
- 5 //FIFO interface
- 6 input [7:0 fifo_dout , // 从FIFO读出的数据
- 7 input almost_full , //FIFO将满信号
- 8 input almost_empty, //FIFO将空信号
- 9 output reg fifo_rd_en // FIFO读使能
- 10 );
- 11
- 12 //reg define
- 13 reg [1:0 state ; // 动作状态
- 14 reg almost_full_d0 ; // fifo_full 延迟一拍
- 15 reg almost_full_syn ; //fifo_full 延迟两拍
- 16 reg [3:0 dly_cnt ; //延迟计数器
- 17
- 18 //*****************************************************
- 19 //** main code
- 20 //*****************************************************
- 21
- 22 //因为fifo_full 信号是属于FIFO写时钟域的
- 23 //所以要将其同步到读时钟域中
- 24 always@( posedge clk ) begin
- 25 if( !rst_n ) begin
- 26 almost_full_d0 <= 1'b0 ;
- 27 almost_full_syn <= 1'b0 ;
- 28 end
- 29 else begin
- 30 almost_full_d0 <= almost_full ;
- 31 almost_full_syn <= almost_full_d0 ;
- 32 end
- 33 end
- 34
- 35 //读出FIFO的数据
- 36 always @(posedge clk ) begin
- 37 if(!rst_n) begin
- 38 fifo_rd_en <= 1'b0;
- 39 state <= 2'd0;
- 40 dly_cnt <= 4'd0;
- 41 end
- 42 else begin
- 43 case(state)
- 44 2'd0: begin
- 45 if(almost_full_syn) //如果检测到FIFO将被写满
- 46 state <= 2'd1; //就进入延时状态
- 47 else
- 48 state <= state;
- 49 end
- 50 2'd1: begin
- 51 if(dly_cnt == 4'd10) begin //延时10拍
- 52 //原因是FIFO IP核内部状态信号的更新存在延时
- 53 //延迟10拍以等待状态信号更新完毕
- 54 dly_cnt <= 4'd0;
- 55 state <=2'd2; //开始读操作
- 56 end
- 57 else
- 58 dly_cnt <= dly_cnt + 4'd1;
- 59 end
- 60 2'd2: begin
- 61 if(almost_empty) begin //等待FIFO将被读空
- 62 fifo_rd_en <= 1'b0; //关闭读使能
- 63 state <= 2'd0; //回到第一个状态
- 64 end
- 65 else //如果FIFO没有被读空
- 66 fifo_rd_en <= 1'b1; //则持续打开读使能
- 67 end
- 68 default : state <= 2'd0;
- 69 endcase
- 70 end
- 71 end
- 72
- 73 endmodule
复制代码读模块的代码结构与写模块几乎一样,也是使用一个不断进行状态循环的小的状态机来控制操作过程,读者参考着代码应该很容易能够理解,这里就不再赘述。 我们对代码进行仿真,TestBench中只要送出时钟的复位信号即可。TB文件如下: - 1 module tb_ip_fifo;
- 2
- 3 reg grs_n;
- 4 //GTP_GRS I_GTP_GRS(
- 5 GTP_GRS GRS_INST(
- 6 .GRS_N (grs_n)
- 7 );
- 8
- 9 initial begin
- 10 grs_n = 1'b0;
- 11 #5000 grs_n = 1'b1;
- 12 end
- 13
- 14 //Inputs
- 15 reg sys_clk;
- 16 reg sys_rst_n;
- 17
- 18 //Instantiate the Unit Under Test (UUT)
- 19 ip_fifo u_ip_fifo (
- 20 .sys_clk (sys_clk),
- 21 .sys_rst_n (sys_rst_n)
- 22 );
- 23
- 24 //Genaratethe clk
- 25 parameter PERIOD = 20;
- 26 always begin
- 27 sys_clk = 1'b0;
- 28 #(PERIOD/2) sys_clk = 1'b1;
- 29 #(PERIOD/2);
- 30 end
- 31
- 32 initial begin
- 33 // Initialize Inputs
- 34 sys_rst_n = 0;
- 35 // Wait 100 ns for global reset to finish
- 36 #100 ;
- 37 sys_rst_n = 1;
- 38 // Add stimulus here
- 39
- 40 end
- 41
- 42 endmodule
复制代码写满后转为读的仿真波形图如下图所示: 图 20.4.14仿真波形1 由波形图可知,当写满255个数据后,fifo_full满信号就会拉高。经过延时之后,fifo_rd_en写使能信号拉高,经过一拍之后就开始将fifo中的数据送到fifo_dout端口上。 写满后转为读的仿真波形图如下图所示: 图 20.4.15 仿真波形2 由波形图可知,当读完255个数据后,fifo_empty空信号就会拉高。经过延时之后,fifo_wr_en写使能信号拉高,经过一拍之后就开始向fifo中继续写入数据。
1.5 下载验证新建DebugCore,将fifo_wr_en、fifo_rd_en、fifo_din、fifo_dout、almost_full、almost_empty、fifo_full、fifo_empty、fifo_wr_data_count和fifo_rd_data_count这十个信号添加至观察列表中,新建DebugCore核的方法这里不再赘述。 编译工程并生成比特流.sbit文件后,此时将下载器一端连接电脑,另一端与开发板上的JTAG下载口连接,连接电源线,并打开开发板的电源开关。 点击PDS工具栏的下载按钮,在弹出的Fabric Configuration界面中双击“Boundary Scan”,我们将生成好的sbit流文件下载到开发板中去。 图 20.5.1 将探针信号添加到波形窗口中 同时我们在窗口将“fifo_rd_en”信号设置为上升沿触发。 单击左上角的触发按钮,如下图所示: 图 20.5.2 触发按钮 在FabricDebugger中观察的波形如下图所示: 图 20.5.3 捕获得到的波形图 从捕获得到的波形图中可以看出,其逻辑行为与仿真波形图中的一致,证明我们的代码正确地实现了预期的功能。 |