本文针对FPGA实践开发进程中,呈现毛病后定位困难、重复修正代码编译时刻过长、上板后毛病处理无法承认的问题,提出了一种选用仿真的办法来定位、处理毛病并验证毛病处理方案。能够大大的节省开发时刻,进步开发功率。
FPGA近年来在越来越多的领域中运用,许多大通讯体系(如通讯基站等)都用其做中心数据的处理。可是过长的编译时刻,在研制进程中使得处理毛病的环节十分令人头痛。本文介绍的便是一种用仿真办法处理毛病然后削减研制进程中的编译次数,终究到达精确定位毛病、缩短处理毛病时刻的意图。文例所用到的软件开发渠道为Altera公司的Quartus II,仿真东西为ModelSim。
问题的提出
体系开发在上板调试进程中,有时分呈现的bug是很极点的状况或很少呈现的状况,而现在一般的做法是:在毛病呈现的时分经过SignalTap把信号抓出来查找其问题的地点、修正程序;在改完版别后,先要对整个工程进行从头编译,然后再上板跑版别进行验证,看看毛病是否处理。
这样就会呈现三个问题:
①有时分毛病很难定位,只知道哪个模块犯错,很难定位到详细的信号上,给抓信号带来费事。假如毛病定位不精确,漏抓了要害信号,则需求从头在SignalTap里增加信号、编译版别并再次上板定位毛病,浪费时刻。
②毛病定位后,修正代码还需求再编译一次发生新版别的下载文件,修正后若还有问题则要重复这一进程,这样从毛病定位到修正完结需求许屡次编译。
③上板从头进行验证时,假如这个bug的呈现的几率很小,短时刻内不再复现,并不能阐明在极点状况下的毛病真的被处理了。
举例阐明:
图1 SignalTap抓出的bug呈现时的数据
图2 SignalTap抓信号界面
例如在一个基带体系的FPGA逻辑版别中,输出模块调用了一个异步FIFO,某一时刻FIFO已空的状况下多读了一个数据,发生了bug,如图1所示。
该输出模块的功用是判别FIFO中是否有大于4个数据可读出,若大于则接连输出4个数据作为一组。体系中选用异步FIFO的内部读数据指针来做判别,而异步FIFO读写数据需求跨时钟域,需求至少2个时钟周期的握手时刻,导致数据指针不精确。在判别的时钟沿,尽管显现有超越4个的数据可读,可是因为握手时刻的推迟实践上FIFO中或许只需3个数据。
图1中rdreq为FIFO的读使能信号,在4个时钟周期内有效,可是只读出了3个数(数据0D2086C9F被读了两次),因为FIFO在第4个时钟周期现已读空。这儿应该改成同步FIFO,因为同步FIFO数据的读写只在一个时钟域内进行,就没有这个握手时刻推迟的问题了。
定位这个毛病的时分咱们能够很简单知道是哪个模块出了问题,可是详细是其内部的哪个信号还需求下些功夫,假如犯错信号躲藏的很深,很难一次就抓到需求的信号;并且即便咱们抓到了正确的信号,假如毛病在改完之后没有处理,则还需求从头修正、再进行编译,消耗时刻;即便改正之后毛病不再复现,也有或许是因为bug呈现的条件严苛,无法证明毛病真的处理了。
针对这三个问题,笔者提出如下主意:
尽管定位详细的犯错信号很困难,可是定位是哪个模块犯错很简单,在bug呈现的时分咱们能够抓出这个模块的悉数输入信号,考虑是否能够运用这些信号在仿真环境下重建bug呈现的条件,运用仿真环境详细定位过错信号的方位。
定位好过错信号的详细方位后,修正代码,再用相同的条件进行仿真。这样能够经过对修正前后输出数据的比照,很直观的验证修正是否成功,然后在修正成功后只需编译一次即可,节省时刻。
上板后bug不复现也能够扫除是因为极点状况很难满意形成的,去除了后顾之虑,彻底处理了毛病。
仿真处理毛病的办法
经过对这个异步FIFO问题的处理,能够证明这种经过所抓信号树立bug存在条件,定位、铲除bug的办法是可行的。过程如下:
图3 SignalTap II List File界面
①将bug呈现时SignalTap抓的信号保存成文档文件
Quartus II 渠道用SignalTap抓到信号的界面如图2所示。
在信号称号上单击右键,挑选图2所示Create SignalTap II List File选项,生成如图3格局界面。
图3中界面上半部分显现的是list对信号个数及信号名的描绘,下半部分是采样点所对应的信号值,带h的表明是十六进制数值。
将list file另存为文本格局文件即可,如图4所示。
图4 “另存为”选项界面
尔后能够把这个文本文件中无用的描绘删掉,只留SignalTap抓出来的数据(空格、h等符号也要删掉),另存为.dat文件供仿真运用。
有了毛病呈现时的输入数据,咱们就能够在仿真环境下构建毛病呈现的条件。
②运用.dat文件树立bug呈现的条件
用verilog言语编写仿真文件(testbench),运用句子$readmemh或$readmemb将.dat文件中的数据存储到一个设定的ram中,如:$readmemh(“s.dat”,ram)。
留意$readmemh读取是依照十六进制数据进行(以为.dat文件中的数据都是十六进制数),会主动将其转换为4位二进制数存入ram中,所以设定的ram位宽要是.dat文件中数据位宽的4倍;运用$readmemb时,存储SignalTap所抓信号时,信号都要先设定为binary类型,ram位宽便是.dat文件数据的位宽。ram的深度为.dat文件中数据的个数。
然后在程序里把ram中数据依照所对应时钟沿输出到一个寄存器变量中,ram地址累加即可。
always@(posedgeclk)
begin
data<=ram[addr];
addr<=addr+1'b1;
end
复现bug存在条件时,需将模块的输入信号与ram中的数据位相对应,仿真文件调用模块时,将寄存器data对应位作为输入接入即可。
在仿真环境中复现bug波形如图5所示。
把图5和图1进行比较,可见经过这种办法咱们在仿真环境下树立了bug犯错时的环境,得到相同的输出犯错数据。
③修正程序后在仿真环境验证修正是否成功
修正程序后,咱们只需运用相同的环境进行仿真,并且有针对性的调查bug是否处理。本例中呈现bug的原因是运用了异步FIFO,改成同步FIFO后,问题应该就会处理,咱们能够经过仿真验证。修正程序后仿真的波形如图6所示。
由图6可见,修正后相同的条件FIFO读出4个数,阐明没有读空,符合要求,bug处理。图7为版别编译后上板运用SignalTap抓取的信号波形,以作比较。
图5 modelsim环境下复现的犯错数据
图6 修正程序后相同条件下的输出数据
图7 修正程序后SignalTap抓的信号
比较后易见,波形完全相同,阐明办法可行。
总结
文中描绘的办法可针对各种的毛病的处理。在毛病呈现时,只需定位犯错的模块,这些模块内嵌一些子模块也不妨;抓信号时将毛病模块的输入输出信号抓出即可;运用输入信号重建毛病环境,若仿真输出信号和所抓输出信号相同,阐明毛病环境树立正确;用这个仿真渠道就能够详细定位是哪个子模块、哪个信号犯错,而不需求在SignalTap中把这些信号抓出来;并且在修正代码后能够验证是否修正成功,节省时刻,很清晰的证明毛病真的被处理了,事半功倍。