对于FPGA调试,主要以Intel FPGA为例,在win10 Quartus ii 17.0环境下进行仿真和调试,开发板类型EP4CE15F17。主要包括一下几个部分:
- FPGA的调试-虚拟JTAG(Virtual JTAG) - FPGA的调试-在线存储器内容编辑工具(In-system Memory Content Editor) - FPGA的调试-内嵌逻辑分析仪(SignalTap) - FPGA的调试-LogicLock - FPGA的调试-调试设计的指导原则 上述内容主要参考《通信IC设计》,有兴趣的可以自己购买书籍进行研读。 1、相关理论知识 1.1内嵌逻辑分析仪 为方便用户进行调试,FPGA通常会内置信号观察逻辑,Altera提供的是SignalTap,而xilinx提供的则是ChipScope。此外还有第三方调试工具,如Synopsys的Identify。这类工具的核心原理为:以预先设定的时钟速率实时采样FPGA的内部信号或者引脚状态,并存储于FPGA的内部RAM中,然后通过统一的ELA(Embedded Logic Analyzer)进行数据分析和管理。当预设的触发条件满足后,ELA通过JTAG将存储在片内RAM中的数据缓存数据传输至PC上。当PC获得JTAG回传数据后,通过本地计算将对应的逻辑分析结果展现出来。
因此,无论是GignalTap还是ChipScope,其实都是在工程中额外加一些特殊模块实现信号的采集,所付出的代价包括:逻辑单元、内部RAM以及ELA资源。逻辑分析仪的数据捕获原理如图2-53所示,所有存储单元都是与当前逻辑设计的RAM共享的。如果当前逻辑占用RAM较大,内嵌的逻辑分析仪功能将会有非常大的存储深度限制。
从图2-53很容易发现,逻辑触发的时刻可以动态调整,而且存储的数据长度与时间也很容易调整。此外由于FPGA内置可编程能力,所以触发条件可以依赖于其他的事件触发,这样可以多级触发,形成基于状态的数据捕获。 例如当A信号为高电平,且持续32周期后,如果此时B信号为低电平且C信号有一个低脉冲,则触发一个等待事件;当等待事件发生65536个时钟周期后,再捕获数据,并通过逻辑分析仪发送出来。这就是基于状态机触发的逻辑分析功能,类似于Verilog中的Assertion断言和FSM状态机的有机结合体,是传统逻辑分析仪无法完成的。由于现在的逻辑通常都比较复杂,基于传统的条件触发模式,往往耗时耗力,很难快速找到BUG;而状态触发往往能够帮助设计者快速定位错误并调试。 对于逻辑分析仪而言,除了触发条件外,还有一个存储位置的概念。正常情况下,FPGA会对需要CIA杨的数据一直采样,当数据放满后,将采用循环覆盖的方式存储,这类似于FIFO中的卷绕(WRAP)概念。当触发器触发后,通常缓冲器都是满的;如果采用预触发,将继续记录当前存储容量12%的数据后停止(有些厂商是不再记录,直接用当前记录数据);如果采用后触发,将继续记录当前存储容量的88%的数据后,停止记录(有些厂商是记录全部容量);如果是中间触发,将继续记录当前存储容量的1/2的数据。实际上什么时候开始记录,什么时候停止都可以通过状态触发实现。捕获数据的概念示意图如图2-54所示。
下面通过SignalTAP为例,简单讲述内嵌逻辑分析仪的调试技巧。 1.2 SignalTap SignalTAP是Altera内置的逻辑信号观测工具,内部实现结构如图所示。
根据前面的逻辑分析仪原理,很容易得知FPGA可以实现多个并行的ELA。通过FSM和条件判断支持多级触发,FPGA也能够支持复杂的状态机数据捕获。令触发条件加上一个计数器,就很容易使FPGA能在不同的起始时刻捕获数据。而Altera所设计的SignalTAP正好是按照上诉方式设计的,其特点如下:
1.2.1 SignalTap的界面 操作界面如图所示。
1.2.2 SignalTap的演示 演示放在实例里 1.2.3 SignalTap的基本触发模式 当启动逻辑分析仪后,SignalTAP会对被监视的信号进行不断的采样,一直到某个条件满足后停止,这个条件就是触发条件。在基本模式下,触发条件被设定为当前信号的逻辑组合。当逻辑组合满足某个值后,触发条件将被满足,数据将被采样保存并上传到PC。 下图是SignalTAP的基本触发模式示意图。
1.2.4 SignalTap的Advanced Trigger模式 在信号列表Trigger Conditions栏的顶端选择Advanced,Advanced会弹出逻辑编辑器,在这里可以设计一个复杂的触发表达式。 1.2.5 SignalTap基于状态触发的触发模式 基于状态触发的逻辑分析仪模式是FPGA内嵌分析仪的而核心技术,主要技巧在于任何通过状态触发语句实现状态机的触发。下图是状态机触发的工作界面。
在设定触发条件前,先需要确定基本的触发条件,具体如图所示。
在设定基本触发条件后,就可以启动状态机的脚本设计,下面通过几个例子来说明状态机触发的实现方法: 1)当条件condition1不满足,且持续时间超过5个时钟周期后,触发触发器,相关理想波形如图所示:
对应的状态机触发代码如下:
2)当条件condition1不满足情况发生,且不满足情况在不超过5个时钟周期内,又发生条件condition1满足的情况,则触发触发器,否则停止触发。一个典型的例子图下图所示。
上诉触发触发器的脚本如下:
3)当condition条件满足5次后,触发触发器,否则停止触发。该例子的脚本如下:
4)当condition1条件满足后,如果condition2能够满足,则立即触发触发器,否则停止触发。该例子的脚本如下:
5)当condition1条件满足后,如果5个采样时钟周期内,condition2能够满足,则立即触发触发器,否则停止触发。该例子的脚本如下:
由于任何复杂的条件都可以简化为顺序、分支和循环3种情况,通过计数器能够实现循环,通过条件判断可实现分支,而通过状态机可实现流程控制。因此任意复杂的条件触发,都能够通过上诉条件组合捕获。
前面所举的5个例子,就是上诉不同场景的组合,因此读者只需要将上诉5个例子进行组合就能基本掌握触发条件的实现,熟练进行FPGA调试。 2、简单实例 2.1 新建工程
首先新建一个工程,然后添加文件,文件内容如下:
module test ( input CLOCK, RESET, output [7:0]oData );
reg [7:0]C1;
always @ ( posedge CLOCK or negedge RESET )
if( !RESET )
C1 <= 8'd0;
else if( C1 == 32 -1 )
C1 <= 8'd0;
else
C1 <= C1 + 1'b1;
assign oData = C1;
endmodule
逻辑非常简单,其中,CLOCK是时钟引脚,RESET是复位引脚,这只模块的功能就是不断重复计数,然后将计数 内容经由 Data 输出。接下来综合,分配引脚后就可以设置SigalTAP了。 1.2 配置SignalTapII Logic Analyzer 如图所示,点击 Tool 菜单,然后选择 SignalTapII Logic Analyzer 便可启动该工具。
下图是 Signal Tap 的窗口,其中 4 处高亮的地方是比较重要的界面。 (一)JTAG Chain Configuration,JTAG 界面,主要是设置 USB Blaster。 (二)Instance Manager,调试界面,主要是启动,连续,结束等调试的活动。 (三)Signal Configuration,信号界面,主要是储存,触发等设置。 (四)Data,显示界面,主要是显示采集结果,时序活动。 (五)Setup,设置界面,主要是添加节点,设置触发事件/条件等。
① JTAG 界面 - 配置 JTAG 以及下载对象 如图所以,设备一旦上电,并且 USB Blaster 链接成功,那么 JTAG 界面就会进入绪状态。
如图 所示,SOF Manager 是小型下载管理器,读者也可以经由一般的下载管理器完成下载工作,不过一切下载活动必须在配置结束以后才执行(综合成功并且下载)。
② 信号界面 - 配置采集时钟,储存,触发: 一旦 JTAG 就绪以后,我们就可以开始执行信号相关的配置。如图 3.6 所示,默认下的信号界面都是这个样子,其中:
Clock 是采集时钟 Sample depth 是储存/采集深度 RAM Type 是储存资源 Storage Qualifier - type 是储存方式 首先,让我们设置采集时钟,所以请点击 Clock 选项右边的 < … >,完后会弹出节点界面。
图中 是节点界面,这点它和 Time Quest 非常相似: ① 请读者保持 Named:* 不变的情况下, ② Filter 选择为 <Pins: all>, ③ 注意 Look in 指向顶层模块 , ④ 然后点击右上角的 < List >。
如下图 所示,这是添加节点(采集时钟)的步骤: ① 点击 列出所有 demo 模块相关的端口。 ② 诸多端口之中,节点 CLOCK 将成为采集时钟,然后点击它。 ③ 点击 > 将该节点添加到右边。 ④ 点击 < OK > 生效设置。
如下图所示,采集时钟设置完毕以后,Clock 右边的文本框就会出现 CLOCK 的字眼。
如下图 所示,一般上储存相关的配置都会这样设定: ① Sample depth 储存深度按照感觉设置,这里是 256。 ② RAM type 储存资源,有 Auto 就设置,非常省事,不然就是 M4K/M9K,还是 Logic。 ③ Storage qualifier - type 储存方式选择 Continuous 连续性即可。 读者可能无法相信,高达 8 成的调试工作都是按照这样的设定与配置。
如图 3.11 所示,一般上触发相关的配置都是这样设定:
① Trigger flow control,触发条件流程,这里选择 Sequential 顺序性即可。 ② Trigger position,触发位置,这里选择 Pre trigger position 即可。 ③ Trigger conditions,触发条件数,这里选择一个即可。 同样,读者可能也无法相信,高达 8 成的调式工作也是按照这样的触发配置。到目前为 止,信号界面的配置工作总算告一段落。 ③ 配置界面 - 添加采集对象: 如图 3.12 所示,配置界面就是添加节点(采集对象)的地方,默认下它是空空如也,我们必须自行添加对象才行。 ① < 右键 > 调出菜单, ② 点击 < Add Nodes … > 添加节点。
完成上面两个步骤以后,它就会跳出节点界面。
如上图所示,同样的节点界面再次出现: ① 请保持 Named:* 不变, ② Filter 设为 < Pins: all >, ③ Look in 设为 顶层模块, ④ 点击 列出,demo 模块所有相关的端口。
如上图 所示,假设 oData 是采集对象: ① 点击 列出顶层模块 demo 的所有端口, ② 选择 oData, ③ 点击 > 将节点添加到右边去, ④ 点击 生效配置。 如下图所示,如果一切无误的话,那么节点(采集对象)oData 就会出现在配置界面之中。完后,我们可以开始配置触发事件。
④ 触发事件:
如上图所示,笔者曾在前面说过触发事件可以是单一或者复数,其中 Basic AND 与Basic OR 就是用来表达复数触发事件的关系。我们以同样的例子作为解释 …
如上图所示,假设信号 A 的下降沿是事件 1,信号 B 的低电平是事件 2,那么 Baisc AND的逻辑关系造成两者在成立的情况下才执行采集。反之,Basic OR 的逻辑关系造成,任一事件成立都会执行采集。在此,笔者选择 Basic AND 就好了 …
言归正题。笔者也说过,Signal Tap 有预设触发事件以及高级触发事件,后者必须将触发事件设为 Advance 才行,反之预设触发事件可以: ① 触发事件表框之处 <右键>, ② 选择 <Insert Value 数值>。 默认下,Signal Tap 自带 7 个预设触发事件,在此笔者选择数值的触发事件,随后会弹出相关的窗口。
如上图所示,这是配置数值触发事件的窗口: ① 选择格式,这里是 < Unsigned Decimal >,无符号位的十进制, ② 输入数值,这里是 5, ③ 点击 生效配置。
上图 是触发事件配置完毕的情况,其中 oData 为 5 执行采集。到目前为止,配置工作已经是完成八九十,余下再综合一起便可下载至设备,期间系统可能要求保存一切配置,例如 stp1.stp 什么的,读者可以保存在任一的地方。
如图一切无误的话,那么实验三层次关系与文件关系的结果如上图 所示,其中 sld_×× 就是 Signal Tap 模块的实例化,读者也可以认为那是调试模块(环境)。 ⑤ 采集界面:
如图 3.22 所示,程序下载以后,如果环境创建失败的话,那么它会呈现红色(左图)。反之,如果环境创建成功,那么它会打印 Ready to acquire 的字眼。一般上,调试环境创建失败有几个原因:
如图 3.23 所示,采集界面主要有 4 个选项控制整个采集过程。 ① Run Analysis 手动执行,触发事件诱发采集,达到采集次数自动停止。 ② Auto Analysis 自动执行,无视触发事件,采集次数,采集一切。 ③ Stop,停止执行,停止采集。 ④ Read Data,读取数据,读取缓冲空间的内容。 一般上,如果触发事件配置无误的话,我们只要按下手动执行,那么触发事件会诱发采集,当采集达到某个次数以后(根据储存深度),采集过程就会结束。读者没有看错,采集界面只有 4 个选项而已,其中手动执行最为有用,因为其它选项只有在采集失败的情况下(触发事件未达成)才会派上用场,真是讽刺。例如,停止执行要么强制停止失控的采集现场,要么配合自动执行一起使用。换之,读取数据也是在采集失控的情况下,强制从设备中(缓冲空间)读取数据。好了,我们稍微点击一下手动执行,然后悄悄采集结果。
根据 demo 模块,我们知道它重复计数 0~31。如图 3.24 所示,T0 表示触发事件的达成之际也是采集工作的开始,其中未来值 5 就是触发事件的达成条件 … 简单的调试工作也到此结束。 3 (补充)Signal Tap 标准调试流程 如图 3.25 所示,虽说这是是官方指定的标准流程,不过笔者还是建议看看就好,千万不要太认真,迷信“标准”这种东西很容易害死人。图 3.25 有一处值得说明的地方是,触发事件发生失败的时候,如果跟着流程游荡,它会要求手动停止分析,如果 Signal Tap显示结果就进行分析,反之就是从设备哪里强制读取结果。
最后,好事的笔者也为实验三的配置过程绘出一副流程图,结果如图 3.26 所示,读者自己看着办。
4 (补充)添加节点 笔者相信许多第一次接触的同学都会畏惧节点的过滤选项。如图 3.27 所示,不甘寂寞的官方为我们准备那么多选项,多少有些弄巧成拙的感觉,有关过滤选项基本上可以分为两大类以致缩小范围。其一是 Pin 端口类,其二就是 Reg 寄存器类,笔者喜欢的选项却只有 Pins:all 以及 Register : pre-synthesis 两个而已。
顾名思义 Pins:all 就是所有端口的意思,如果 Look in 指向模块 A,那么模块 A 的端口就会显示出来(不管有没有赋值驱动)。反之,Register:pre-synthesis 就是综合以后的寄存器,如果 Look in 指向模块 B,那么模块 B 的所有寄存器都会暴露出来。除此之外,发狂的笔者偶尔不顾其它直接选择 Design Entry,即不管什么鬼东西统统都给老子举例出来 …