明德扬论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信扫一扫,快捷登录!

查看: 194979|回复: 1

【技巧分享】FPGA定位错误的方法

[复制链接]
发表于 2019-10-17 17:34:19 | 显示全部楼层 |阅读模式

马上注册,看完整文章,学更多FPGA知识。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
FPGA定位错误的方法

     FPGA设计过程中,任何人都难免写出错误的代码。代码出错不可怕,也非常正常,关键是要把错误找出来。对于工具问题、IP核使用问题,在论坛、QQ群里求助是一个非常好的方法。但对于设计问题,估计求助就非常困难了,因为没人凭着现象就知道是什么原因导致出现了错误,大神也是要去定位。求人不如求己,自己掌握定位方法自己定位。 FPGA说白了,核心就两种能力:设计能力和定位问题能力,理论上掌握了这两个能力,什么都能设计出来。
     
      检查思维不可取。当工程出现错误的时候,在寻找错误代码环节,大部分人会反复一行一行检查代码,如果是小实验,只有一百行代码还好;但是如果是完整的工程,这样的做法无异于大海捞针,往往耗费了巨大时间和精力但收效甚微。人是有思维惯性的,检查的时候很容易就把错误给漏过去。

        还存在一小部分工程师,在面对错误的时候抱有极大的消极态度,稍微定位一下,就认定是遇到了非常奇怪的现象,或者是软件有BUG。从内心不愿意认为是自己有问题,认为自己按照思路做的,不可能出错。
        
      可以很明确地说,出现奇怪现象,出现了错误,99%是自己的粗心大意,越是奇怪,越表明有多粗心,那么定位时就需要越仔细。有些同学对此不是很认可,但是根据多年的培训经验,不论是大小项目,很多同学最后找出的问题有芯片信号写错数完,有引脚配置错误的,甚至有的只是编写程序不习惯对齐,看漏、些少end的。在定位出这些错误之前,每一位同学都是不敢相信是这种小地方影响全局的。但是事实就是这样,这些由于粗心大意而产生的错误,并不是错误寻找环节可以被思考到的,所以需要大家可以更加细心的定位错误。
        
      希望这一小部分心态不好的工程师,可以调整心态,遇到问题先不要着急说是外部原因,要认定绝大情况都是自己代码写错的,认真寻找bug。

      有了好的心态才可以快速定位错误,这是一种科学的方法,方法很简单,就像破案一样需要一个个线索顺藤摸瓜的寻找。但是希望大家学习此方法前,一定调整好自己的心态,不要没有耐心半途而废,这样是无法得到想要的结果的。下面我们就一起来学习明德扬的错误定位方法。


一、明德扬错误定位方法解析
        在讲错误定位方法之前,先来思考一个问题:我们是如何确定代码中存在错误的?想必大家都知道答案,当输出结果与设计要求不一样的时候,说明代码中存在错误。思考了这个问题,我们可以得出错误定位的一个思路要点——从输出开始检查。(从错误现象中找出错误的信号)
VGA没有显示图像 VS 行场同步信号错误
        串口调试助手没有收到数据  VS 代码的串送发送信号uart_tx有没有变低
        串口收到的数据乱序  VS din和din_vld是不是乱序


        这也就引出了第二个问题:从输出开始检查什么?当然是查找产生这个输出结果的原因。可以总结出错误定位的第二个思路要点——查这个输出的赋值语句是怎么写的。
        
    总结了思路,我们就需要落实,要从赋值语句中查出错误,明德扬提出了一套定位错误的方法:
        1.  确定错误时刻:找到信号第一个错误时刻。关于错误时刻,一定要精确到某一时钟的上升沿,这是寻找错误的开始,如果连时刻都定位不准确,那么后续的一切都是无用功,所以找出错误时刻一定要找准时刻点;并且记住一定要寻找第一个错误时刻,只有将最开始的错误改正,后续的很多连锁错误可能就正确了。
        2.  找到代码:找到产生信号的代码。
        3.  排列信号:根据代码,将相关信号集中到一起,并按顺序排好(MODELSIM或者SIGNALTAP)。这里强调一下,一定要将相关信号按顺序排列好,如前面所说的,定位问题考验的是细心,越是奇怪的问题越是要细心,按顺序排列好,有助于逐个核对检查。
            当你找不到问题所在时,试试严格把信号排列好。世界上没有笨人只有懒人,这个地方不犯懒,认认真真排列好一个个来,比耍小聪明挑着检验可以更加快速方便的找出错误点。
        4.  代入信号数据:将这一错误时刻的信号数据代入代码以确定错误原因。关于这里代入数据检验,希望大家一定要认真细心,我们既然知道了这里极有可能存在错误,还想当然的按照内心预想计算,是无法得到结果的。错误的出现大多是一时的粗心与手误,那么检验的时候一定要按照代码的要求来,才可以发现错误的地方。
        5.三选一判断:a,此时的条件信号有错误;2.本ALWAYS代码有错误;3.本来的预想有错误。如果是条件有错误,按2~5的步骤重新定位错误的条件信号;如果是本ALWAYS代码,那就要修改代码;如果是原来的预想有错误,那就说明波形是正确的,那就修改原来的想法。
做三选一判断,逼着自己一定要做出一个选择,这是让自己认真仔细思考问题。思考此时此刻输入信号是不是正常,思考自己的设计有没有缺陷,或者是自己想法对不对。
        见过太多的例子,遇到这种困难问题时,需要思考,很多人就会打退堂鼓,就会放过,就会思维跟踪着去看其他信号,思维跳来跳去,但就是不解决问题。

        出理论上来说,本方法可以定位所有的问题,不管是测试文件问题、代码问题、模块结构问题、语法理解错误问题、甚至是您没学过的语法,使用本方法都能定位出来。所以希望大家遇到问题可以按照此方法静下心来定位错误,多进行几次尝试就会发现此方法的方便之处。
                (注:每次修正错误后,需要重新编译执行以检查修改后的结果)


二、错误定位案例
        下面通过对一个案例的详解,让大家能进一步弄清楚具体的方法:

案例

案例


modelsim.v
代码2.png

        设计思路:本设计使用了一个计数器,用来计算250个时钟周期,当达到250个时钟时,就让dout为1。也就是说cnt是0~249循环变化的,当cnt==249时,dout等于1。


test_modelsim.v
代码3.png


        测试文件思路:测试文件很简单,首先例化了设计文件,然后产生了时钟和复位信号。

        图一显示的结果没有满足250时钟周期输出1个周期高电平脉冲的功能要求,如何定位错误?

(一)  定位错误信号dout
        1.  确定错误时刻:找到信号第一个错误时刻(精确到某一时钟的上升沿)
1.png

图一modelsim.v仿真运行结果

        本设计是每250个时钟周期输出1个高电平脉冲。时钟是50M,周期是20ns,则预期是复位后第5000ns的时候dout输出一个高电平脉冲,但此时dout仍然为0。牢牢记住这个错误时刻。注意“5000ns”这个时刻,要精确到某时钟上升沿。

        2. 找到代码:找到产生信号的代码
        本信号dout有错,所以要找这个信号的代码。
        注意MOELSIM波形显示的信号,其全名为test_modelsim/dout,它与test_modelsim/uut/dout是不同的,不要认为相同,哪个信号错就看哪个(常见粗心点)。
        test_modelsim/dout产生的代码如下。从第11行可知,test_modelsim/dout产生自test_modelsim/uut/dout。
代码4.png


        3.  排列信号:根据代码,将相关信号集中到一起,并按顺序排好
        产生该信号的代码是.dout  (dout  )   ,也就是uut.dout一个信号给了dout。
        所以拉信号uut.dout和dout,并按顺序排列好。
2.png


        4.  代入数据:将这一错误时刻的数据代入代码以确定错误原因。
        在5000ns的时候,可以看到uut.dout的值为0.
3.png


        5.  三选一判断:a,此时的条件信号有错误;2.本ALWAYS代码有错误;3.本来的预想有错误。
        此时uut.dout的值为0,导致dout的值为0,预期为1.很明显,dout的错误来自于uut.dout。所以转而定位uut.dout。


(二)  定位错误信号uut.dout
        
     接下来重复定位步骤来定位错误信号uut.dout。
        
     1.确定错误时刻
        继续定位test_modelsim/uut/dout,但要牢记之前的错误时刻,也就是复位后的5000ns,在此时刻,预期test_modelsim/uut/dout输出为1,但实际为0。

      2.找到代码
        找到test_modelsim/uut/dout的代码,产生此信号的代码如下:
代码5.png

        3. 排列信号
        从第31~38行代码可以看出,产生test_modelsim/uut/dout的相关信号包括:clk,rst_n,cnt,都拉到波形窗口来看。

4.png

        按照时钟、复位、条件信号和输出信号的顺序排列好。

5.png


          注意:a.不要漏掉信号,一定要齐全,特别是时钟和复位;b.一定要按顺序排列好,越细心越好。(常见粗心点!!!最常用见!)
        
     4. 代入数据
        仍然要牢记之前我们认定的错误时刻:复位后约5000ns时,预期dout为1,实质为0。见图四。
6.png

图四250时钟周期上升沿时刻的uut波形

        我们光标放到此时刻。
7.png


        此时,rst_n为1,cnt==121,dout==1(上升沿前),并且查询到CNT_N==121。将此值代入代码,如下图。

代码6.png


        注意:一个数一个数代进入,然后看执行了哪一行代码。不要跳过看条件,例如不看32行的,直接看35行(常见粗心点)。
        从上面代码可以看出,第32行和第35行都不满足,所以执行了37行,因此dout为0。
        代码和波形保持一致,没有奇怪的现象!!!

        5. 三选一判断
        三选一判断:a. 条件信号有问题;b. 本逻辑代码有问题;c. 预期有问题。逼着自己做三选一判断,肯定是其中一个或者多个有问题。
        首先分析预期是否有问题:本设计的需求就是每隔250个时钟就输出一个高电平,这预期是没有错的。
        其次分析是不是本逻辑代码有问题。本逻辑代码是看cnt算到249时就变1,否则为0。从逻辑上“大概”是没错。
        最后再看条件,此时cnt为121,不是预期的249。这就是问题了,经过了这么多时间,cnt怎么才数到121呢?所以判断:条件信号cnt有问题。
        预期此时cnt为249,实际为121,所以cnt有问题,转成定位uut.cnt。

(三)定位错误信号uut.cnt
      
     1.确定错误时刻
        如前所述,预期这个时候uut.cnt的值为249,实际为121,我们来定位这个错误。
        按设计思路uut.cnt是0~249递增的。将cnt信号拉到波形窗口,看这个信号是不是递增的。发现第一个错误时刻如下图,当其为127时,预期下一个时钟为128,结果为0,也预期不符合,如下图。注意错误时刻改为2949ns。
8.png


        2.找到代码
        找到test_modelsim/uut/cnt的代码,产生此信号的代码如下:

代码7.png

        3. 排列信号
        从第19~29行代码可以看出,产生test_modelsim/uut/cnt的相关信号包括:clk,rst_n,cnt,都拉到波形窗口来看。全部都要拉进来(常见粗心点!)
        按照时钟、复位、条件信号和输出信号的顺序排列好。(常见粗心点!)
9.png


        4. 代入数据
        我们光标放到此错误时刻。
10.png


        此时,rst_n为1,cnt==127(上升沿前),并且查询到CNT_N==250。将此值代入代码,如下图。

代码8.png


        从上面代码可以看出,第20行和第23行都不满足,所以执行了27行,因此cnt加1。加1预期是128,但结果是0。
        代码和波形好像没有保持一致,很奇怪的现象?!!!

        5. 三选一判断
        三选一判断:a. 条件信号有问题;b. 本逻辑代码有问题;c. 预期有问题。逼着自己做三选一判断,肯定是其中一个或者多个有问题。
        首先分析预期是否有问题:本设计的预期就是cnt从0递增到249,用来计数250个时钟,所以预期应该是正确的。
        其次分析是不是本逻辑代码有问题。本逻辑代码的想法是:当cnt数到249时清0,否则就加1。从逻辑上“大概”是没错。
        最后再看条件,此时条件cnt为127,也是预期的值。
        很奇怪。但不要觉得很奇怪,一定是我们的问题,绝不是软件有问题。

        虽然很奇怪,但我们可以确定,一定是执行27行代码时出现了问题,也就是一定是cnt+1出现了问题。在什么情况下,cnt+1会变成0而不是128呢?如果稍微有经验的工程师,就大概知道是信号位宽问题了。
        这个时候,我们要把128转成二进制来看,128=8’b1000_0000。我们展开cnt这个信号,发现cnt没有cnt[7],也就是无法得到8’b1000_0000。
        没有cnt[7],就说明定义有问题,检查定义位宽。

代码9.png


        修改成:
代码10.png


        至此,问题解决。

        上面就是定位错误的完整步骤,本案例其实一共定位了三个信号,由最终的输出信号dout,再定位到uut.dout,最后再定位到uut.cnt。无论哪个信号的定位,都是遵循了明德扬的定位错误方法。
        
      常有人跟我说,这方法很简单我已经完全掌握了,但有问题又定位不出来,这种情况就是眼高手低惹的祸,说白了这些同学不愿意把定位工作做细。例如,明明都已经定位不出问题了,还不愿意把信号排列好,一个一个代值进去看;再或者代值的时候想当然,总是按照思路计算,不按照写的代码一点点代入。
        
      有同学觉得定位错误的能力不是一定需要掌握的,认为有问题了应该是老师指出来,而不是自己定位出来,所谓老师就是传道授业“解惑”也。遇到问题就要求老师直接告诉我哪里错了,我就专心学知识专心写代码。如果老师真这么服务了,这个学员的职业生涯也注定长远不了。老师可以帮助您走一段路,但是不可能这样携手一直走下去,总有一点同学们需要进入工作岗位,需要自己设计代码,走上工程师的道路,如果没有掌握定位错误的能力,这个时候谁又能来帮你“解惑”呢?
        
     工程师最重要的是两个能力:设计能力和定位问题能力。有这两个能力,理论上什么项目搞不定?这两个能力如果要分一个高低,你们说哪个能力更重要?很多人都认为是设计能力,而我却认为定位问题能力更重要,想一想职业发展就明白了。设计能力厉害的就发展成技术专家,定位问题并且解决问题厉害的,就发展成管理层,研发工作的日常,就是定位问题和解决问题。优秀的研发管理,往往会协助员工制定清晰的定位思路和步骤,综合运用排除法、假设法、替换法等,逐步把定位范围缩小,直至找到最后的那一个问题点。因此,在可以学习可以进步的阶段,希望每一位同学都可以学会定位错误的方法,成为更加优秀的工程师。
加QQ:1744527324,获取更多FPGA资料!

0

主题

2

帖子

93

积分

注册会员

Rank: 2

积分
93
发表于 2021-1-14 22:15:33 | 显示全部楼层
很实用,学习了
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|MDYBBS ( 粤ICP备16061416号 )

GMT+8, 2024-11-22 18:20 , Processed in 0.059218 second(s), 25 queries .

Powered by Discuz! X3.4

本论坛由广州健飞通信有限公司所有

© 2001-2019 Comsenz Inc.

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