本文分为两部分,前一部分用于介绍signal tap基本功能,如果是初学者,看完这部分就可以用signal tap抓取一些简单的波形数据了。第二部分用于介绍一些特殊要求时的软件设置,比如连续触发,自定义触发条件等等。Signal Tap Logic Analyzer 采集并显示 FPGA 设计中的实时信号行为,从而无需额外的 I/O 管脚或外部实验室设备即可检查正常器件操作期间内部信号的行为。
原理:利用FPGA剩余的存储资源,对想要采集的信号进行存储,并且判断触发条件是否满足,当触发条件满足并且采集完指定数据后,就把存储的数据通过JTAG传输到Quartus软件的signal tap界面显示,如果是单次采样,则停止采样,如果是连续采样,则会继续对这些信号进行采样,继续检测触发条件。如果在采样过程中,手动停止采样,依旧会将这段时间存储模块存储的数据通过JTAG传输给软件进行显示,只是这些数据并不是想要的数据。
由此初步可以判断几个很重要的参数,多久采样一次?与采样时钟频率有关,原则上可以使用任何信号作为采样的时钟信号,要注意满足采样定理,否则无法采集正确数据。什么时候触发?触发条件可以设置,如果没有设置触发条件,则数据采集完就通过JATG接口传输到软件界面显示,不需要判断触发条件。能采集多少个数据?这与这颗FPGA芯片做完设计后剩余RAM容量有关,也与需要观察信号的位宽以及采样点有关,需要观察的信号越多,位宽越大,采样点越多,需要消耗的RAM容量越大,当超过剩余RAM容量时,quartus在布局布线时会报错。
所以设置触发条件相当重要,由于RAM的限制,很可能只能观察很短一段时间的波形数据,触发条件设置的号,就可能采集到相关的错误,改善设计。注意:在新版本的 Intel Quartus Prime 软件中打开一个在旧版软件中创建的.stp 文件后,此.stp 文件就不能在先前版本的 Intel Quartus Prime 软件中打开了。一般的调试流程如下所示:
一、基本用法
1、打开Signal Tap
首先通过Tools->Signal Tap Logic Analyzer打开Signal Tap。
2、Signal tap 页面介绍
Signal Tap Logic Analyzer页面布局如下所示:
页面分布时钟及触发方式设置,选项卡相当重要,但是在基本使用时,只需要关注4个点,其余的每个选项卡的含义在后面详细讲解。
①、采样时钟的设置
逻辑分析仪在采集时钟的每个正(上升)边沿进行数据采样,逻辑分析仪不支持在采集时钟的负(下降)边沿上进行数据采样。理论上设计中的任何信号都可用作采集时钟,正常情况下会选择设计中合适频率的时钟信号作为采样信号,该信号的频率必须大于等于待采样信号最高频率的2倍,否则无法还原待采样信号。
②、采样深度的设置样本深度范围为[0,128K],在器件存储器资源有限的情况下,由于所选的样本缓存容量不够,设计可能无法编译,尝试降低样本深度以减少资源使用。
③、RAM type使用何种资源存储数据可以设置为M9K,MLAB等等资源,一般默认选择自动即可,由软件分配。
④、采样点位于采样得到波形的位置
用于设置触发点位于整段数据的什么位置,可以定义三种,Pre—保存出现在触发之后的信号活动(12%预触发,88%后触发),Center—保存 50%预触发和 50%后触发数据,Post—保存出现在触发之前的信号活动(88%预触发,12%后触发)。如果想观察触发点之后的一段波形,那么设置为Pre可能更好,如果想观察触发点之前一段时间采集的波形,那么选择Post会更好,默认设置为Pre。
3、添加信号
在setup页面,双击空白处,添加待观察信号。
在Node Finder页面首先点击1处箭头,之后Filter处选择Design Entry(all names),这个选项基本上可以找到所有信号,即使一些已经被优化掉的信号。之后点击3处的list查找信号,页面4就会出现设计中的信号,选择待观察信号双击,加入页面5,当待观察信号都选择后,点击Insert,完成添加。
Trigger Conditions这一栏用于对信号触发条件的设置,选中信号鼠标右击,可以选择触发形式,此处选择motor_busy信号的上升沿触发采集。当有多个信号设置触发方式时,可以选择触发条件的关系,默认为Basic AND,即所有触发条件同时满足时,才认为采样被触发,还可以选择或的关系,自定义触发关系用于后续提升部分详解。
为防止信号触发分析,请在.stp 文件中禁用信号的 Trigger Enable 选项,当只查看信号的采集数据时,此选项很有用。
图8 Signal Tap Logic Analyzer设置触发类型
通过禁用 stp 文件中的 Data Enable 列来关闭查看一个信号的数据的功能,当要触发一个信号但又对查看此信号的数据不感兴趣时,此选项很有用。
二、可能遇到的问题
有时候使用Signal Tap 添加信号可能会遇到下面这种情况,添加一个模块内的信号,结果显示该信号为红色,如图9所示:
这是因为Quartus在综合时将这些信号优化掉了,没有留出节点,导致Signal Tap设置信号失败,解决这种问题有两种方式,方法一可以将信号作为模块输出信号引出,第二就是添加一些约束。根据信号种类不同,添加约束共有2种情况:
①、需要保留的信号类型是 wire
在定义的时候在后面增加/* synthesis keep */,例如:wire wire_name/*synthesis keep */。
另外如果大家使用我之前提供的vscode的Verilog模板,那么直接输入wire,选择有wire_keep提示的指令即可,这样可以免去其它输入。
②、需要保留的信号类型是 reg
跟reg相关的synthesis attribute,共有两种,分别是/synthesis noprune/和/synthesis preserve/。
两者的差别如下:/synthesis noprune/ 避免 Quartus II 优化掉没output的reg,/synthesis preserve/避免 Quartus II 將reg优化为常数,或者合并重复的reg。
定义的时候在后面增加相关的约束语句。 例如:reg r_name/synthesis noprune/; 或者 reg r_name/*synthesis preserve */。类似keep,直接输入reg,选择对应的指令,就可以快速生成约束,如下所示:
將/synthesis noprune/等synthesis attribute 语句放在module后面,这样整个module的所有reg将不被优化。
另外还要注意:以上所提到的使用语言为verilog。synthesis attribute必须写在结束分号前面, 写在分号后面只相当于注释:
正确:reg r_name/* synthesis preserve */;
错误:reg r_name;/* synthesis preserve */;
三、进阶使用
1、多次触发
其实可以将signal tap的存储资源看做FIFO结构,在运行时,逻辑分析器将数据存储在缓存中,直到缓存填满为止,之后新数据将覆盖最旧的数据,直到发生特定的触发事件。
前面的应用时都是将存储资源当作一个FIFO(非分段存储)在使用,其实是可以分为多个FIFO(分段存储)的,每个FIFO还可以设置成不同的触发事件。
用处:比如某项目 FPGA驱动电机,在连接模块1处,电机先要完成交接,然后在运送,还可能会有补步阶段,并且这几个阶段中间间隔的时间对人来说是比较短的,但是对于FPGA来说又太长了。如果采用单FIFO的模式,单次触发,则无法抓取到运送和补步阶段的波形,如果采用多次触发,那么无法查看前面两次运动的波形。
此时就可以用到分段存储了,由于分段数目只能设置为2的n次方。所以分为4段,每次电机结束运动时触发,就可以同时观察连续4次电机停止运动时的波形。
如果每次触发的条件相同,如图所示,勾选Segmened,选择4 16K Sample segments即可,其中4代表将存储体分为容量相等的4段,16表示每段存储体有16000个点,16K*4也等于设置的总容量64K,之后点击单次触发就可以抓取波形了,当触发条件满足四次之后,就会显示波形,如果两次触发之间的点少于16k,那抓到的波形可能很怪异。
Pipeline factor 设置表明 Quartus软件能够添加的流水线寄存器的数量,以提升Signal Tap 的 fMAX,在 0 到 5 之间取值,默认值为0。因为 pipeline register 可能不在关键路径上,所以设置 pipeline factor 不能保证 fMAX 的增加。
2、多次不同触发条件的触发
前面的多次触发,每次触发的条件都必须是相同的,有时候需要抓取不同条件触发后的数据,这个时候就需要其他设置了。首先在Trigger flow control处选中触发方式为顺序触发Sequential。之后在Trigger conditions处设置触发级数,此处设置为四次。在波形后面就会出现相应的四个触发方式的选项,需要对齐进行设置,需要注意程序运行后,要先后满足对应的触发条件后,才会显示抓取的波形数据。
3、过滤采集的无关数据
通过使用采集缓存进行分析,可以捕捉到所选信号集中的大多数功能错误,前提是要有足够的触发条件和足够的样本深度进行采集。但是,每个数据窗口都可能有大量不必要的数据。例如,数据突发(data burst)之间有很长的空闲信号。Signal Tap 中的默认行为不会丢弃冗余采样位。Storage Qualifier 能够建立一个条件,在数据采集的每个时钟周期内将其作为对缓存的写使能,从而在更长的分析时间内更有效地利用采集存储器,该功能只能与未分段缓存一起使用。
Storage Qualifier 允许使用限定条件创建的每个分段定义自定义采样窗口,因此可能支持更大的覆盖时间范围。
如图 Storage Qualifier 功能下有六种存储限定符类型:
- Continuous (默认),此模式关闭 Storage Qualifier。
- Input port
- Transitional
- Conditional
- Start/Stop
- State-based
图13 Storage Qualifier的五种功能
3.1、Input port模式
采集期间,如果Input port选择的信号(图中为dout_vld)在时钟上升沿为高电平,那么 Signal Tap 将数据储存,在时钟上升沿为低电平,那么 Signal Tap会忽略数据样本。
显示数据不连续性(Record data discontinuities):勾选后,Signal Tap标记从存储限定符中暂停采集的样本,采集完成后,该标记将显示在波形查看器中。
禁用存储限定符(Disable Storage Qualifier):勾选后,快速关闭存储限定符,执行连续采集。此选项是运行时可重配置的,从 Type 域更改存储限定符模式需要重新编译工程。
输入端口模式与连续模式的对比。
上图就只采集了data_out[7]为高电平时的数据,为低电平的数据都被丢弃了,这对于只关注某种情况下的数据是很有作用的。
3.2、Transitional 模式
在 Transitional 模式中,Signal Tap监控一种信号中的变化,并仅在检测到变化后才将新数据写入采集缓存中,使用 Storage Qualifier 列中的复选框选择用于监控的信号。下图中是设置当dout信号发生变化时才采集数据。
Transitional 模式与连续采集模式对比:
相比连续模式,Transitional 模式可以将持续不变的信号丢弃,从而采集更多的有用数据,比如状态机可能长期处于空闲状态,然而这些状态并不是我们关心的,我们关心的是状态跳变时各个信号的状态,采用Transitional模式就可以使用更少的资源采集更多的有效数据。
3.3、Conditional模式
连续模式与Conditional 模式在配置上基本一致,连续模式是在Trigger Conditions处配置各信号需要满足的触发条件,而Conditional 模式是在Storage Qualiffer处配置触发条件。但两种模式存储数据的方式不相同,连续模式是在某时刻满足触发条件后,就会将该触发点前后一段时间内观察的所有信号的数据进行存储。而Conditional 模式只存储满足触发条件时的数据,不满足触发条件的数据均被忽略。Conditional 模式配置如下图:
触发条件都设置为data_out[6]和data_out[7]为高电平,下面为Conditional 模式与连续采集模式采集的数据:
连续模式当data_out[6]和data_out[7]都为高电平时,连续采集之后一段时间的数据,采集到指定数据个数后停止,而Conditional模式只采集data_out[6]和data_out[7]都为高电平时的数据,其余数据忽略。
3.4、Start/Stop 模式
Start/Stop 模式使用两组条件,一组条件用于开始数据采集,一组条件用于停止数据采集。如果开始条件的值为 TRUE,那么 Signal Tap 在每个时钟周期都存储缓存数据,直到停止条件的值为 TRUE,然后暂停数据采集。Signal Tap会忽略数据采集开始后接收到的其他开始信号。如果开始和停止条件的值同时为 TRUE,Signal Tap会采集一个周期的数据。
注意:如果缓存因停止条件而无法填满,可以按 Stop 按钮来强制一个触发。
下面为Start/Stop 模式与连续采集模式采集的数据:
这种配置方式相比其他几种用的少一点。
3.5、基于状态(State-Based)
这种比较复杂,需要与Trigger flow control的state-based连用,目前还没有使用过,需要自己通过一种语言编写类似状态机的状态跳转。
4、触发类型
4.1、基本的与、或逻辑
如果选择 Basic AND 或 Basic OR 触发类型,必须对添加到.stp 中的每个信号指定触发码型。右键单击 Trigger Conditions 列,然后点击所需码型。将触发码型设置为以下任何条件:无条件(Don’t Care)、Low(低电平)、High(高电平)、Falling Edge(下降沿)、Rising Edge(上升沿)、Either Edge(双沿触发)。
对于总线,右键单击并选择 Insert Value 以其他数字格式输入码型,可以输入 X 以在十六进制或二进制字符串中指定一组“don’t care”值。
基本的触发条件就Basic OR或者Basic AND,还可以对信号进行分组,选中几个信号右击选择Group即可,可以对这几个信号的触发方式进行设置。
4.2、Comparison 触发条件
有时候,可能需要对一个区间的信号进行采集,当dout大于10,小于30的时候触发采集数据,这个时候依靠Basic OR或者Basic AND就不行了,此时就可以采用Comparison设置触发条件了。
按照以下步骤指定 Comparison 触发条件:
1. 在 Setup 选项卡上,在 Trigger Conditions 下选择 Comparison。
2. 在触发器编辑器中右键单击节点,然后选择 Compare 。
3. 从 Compare 窗口中选择 Comparison type。— 如果选择 Single-value comparison 作为比较类型,请指定操作数和值。— 如果选择 Interval check 作为比较类型,请提供间隔的上下限值,还可以指定是否要包括或排除边界值。
4.3、自定义触发条件
有时候需要的触发条件可能并不是单个简单的与、或、比较关系,比如需要观察v_r_temp_out >= 5000并且motor_busy上升沿满足时个信号的波形,这个时候自定义触发条件就很重要了。在 Trigger Conditions 下拉菜单中选择 Advanced,然后打开 Advanced Trigger 选项卡。
如下图所示,首先需要了解一下窗口信息,触发信号列表里面包含待观察的所有信号,可以将这些信号拖到右边窗口中编辑触发条件。其次就是Object Library包含会用到的与、或、比较、总线值及单信号值,高级触发条件编辑窗口中的Resylt表示触发信号。
要实现v_r_temp_out >= 5000并且motor_busy上升沿这个条件,首先将v_r_temp_out 和motor_busy信号从Node List放置到编辑窗口,直接拖动信号即可,最终结果如下图所示:
之后要时间v_r_temp_out >= 5000并且motor_busy上升沿,5000是一个总线信号(多bit信号)的值,所以需要添加一个Input Objects类器件下的Bus Value,另外还需要添加一个大于等于的比较器,一个逻辑与门,和一个检测信号上升沿的器件,添加如下图所示:
之后就是对这些器件连线,以及一些逻辑器件的设置,比如总线值需要设置具体的参数,双击Variable,进入后如下图所示,General选项卡是对器件类型进行设置的,也就是说这个时候你还是可以改变该器件的类型,而对本器件参数设置在Parameters选项卡里面,选中Bus Value之后,就可以在Setting处设置具体的值了,而Bus Value Radix是设置进制的,默认是十进制。之后点击ok即可,其余选项卡起提示或者清楚作用。
而对边沿的设置,可以查看下图中Description的描述,当输入R后表示对信号的上升沿进行检测,所以在Setting处填写R即可。
设置完成后,编辑框变为下图所示:
接下来最后一步,就是对各个器件进行连线了,首先将v_r_temp_out连接到比较器的a端口,将5000连接到比较器b端口,将motor_busy连接到上升沿检测的输入端口,将比较器的输出端口和边沿检测的输出端口都连接到与门的输入端口,最后将与门输出端口连接到Result即可,连接完成后如下图所示:
上图红框就是下面器件实现的表达式,由此可见,与预想一致,自定义触发条件并不难,首先要清楚想要的触发条件是什么,把表达式写出来,最后直接选中对应的器件进行设置即可。有人可能会有新的疑问,要是没有相应的基本器件怎么办?其实基本器件也是可以自定义的,在Object Library里面有Custom Trigger HDL选项可以自定义基本器件。
具体需要用到是可查看手册,一般不会用到。
5、Power-Up模式
有时候可能需要通过signal tap抓取FPGA对其他芯片的初始化数据,而这类初始化代码大多在FPGA程序下载后就完成了,下载程序后在手动打开采集选项,很可能采集不到任何数据,因为初始化部分已经完成了,可以通过一些设置来完成此类数据的抓取。
示例代码如下:
module top(
input clk ,
input rst_n ,
output reg flag
);
reg [7:0] cnt/*synthesis preserve*/;
wire add_cnt;
wire end_cnt;
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin//
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1;
end
end
assign add_cnt = ~flag;
assign end_cnt = add_cnt && cnt == 254 - 1;
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin//
flag <= 0;
end
else if(end_cnt)begin
flag <= 1'b1;
end
end
endmodule
显然当程序下载进FPGA中,flag信号只会产生一个上升沿,除非复位,本项目不考虑复位情况。
Signal tap初始界面设置如下:
选中signal tap项目右击 Signal Tap PowerUp Trigger 功能,Signal Tap Logic Analyzer 在器件初始化后能够立即采集数据。如下图所示:
之后点击全编译结果如下所示:
然后将sof文件下载到FPGA,下载完成后,等5S在点击采样,得到如下结果:
由于该信号在下载完后经过253个系统时钟,系统时钟周期40ns,约为10us左右,而下载完成后,我们时5S之后才点击的采样数据,如果此时才开始采集数据,则不可能会触发采样条件。而根据结果知道,这种设置是在FPGA完成下载后,signal tap内部设置的电路就会自动采集数据,当触发条件满足时,就会采集并且保存512个数据,当我们在GUI界面上打开采集按钮时,FPGA就会将之前保存的数据通过JATG数据线传输给signal tap软件,在GUI界面显示出对应的波形。并且这样采集的数据波形的背景会显示为蓝色,当之后我们在次点击采样时,采样的数据波形背景会显示为白色。
基于上述分析,如果要采集到所有初始化数据,要保证signal tap采集的数据深度足够,否则多余的深度的数据将无法采集。
另外要禁用 Power-Up Trigger,右键点击实例,然后点击 Disable Power-Up Trigger,如下图所示:
四、总结
这次内容有点多,主要是方便我以后自己查看各个模式的含义,里面介绍的也是目前我最常用的。还有一些细节内容,想要详细了解的推荐查看手册,在公众号后台回复”Signal Tap手册“获取。
Conditional模式经常使用,由于Signal Tap是要消耗资源的,比如CPU与FPGA通信,想要抓取这段时间内CPU发送的读写指令以及数据,如果使用常规模式,肯定完成不了的,这段时间内的无效数据可能会特别多,那么就可以使用Conditional模式外加自定义触发方式,抓取这段时间读写的所有指令及数据。
要读写指令都能抓取,此时就只有自定义触发方式了,默认的几种触发方式也不可能实现。