一波三折——危险的“未分配”引脚


    第一折。半个月前,美国的同事对当前的一个工程进行了编译,并提交二进制文件(FPGA配置文件)给软件工程师进行集成。结果该二进制文件导致了整个系统的崩溃:FPGA二进制文件刚下载完毕,整个系统就不工作了。这一事件导致了美国FPGA工程师一整天的停工和系统恢复。Kevin给出的分析结果是,FPGA给出的中断信号有问题,该信号经过CPLD转发到CPU后导致CPU反复跳入中断,造成系统崩溃。后来,因为经过重新编译的二进制文件没有引发类似现象,该问题就被当作是一个偶然事件被忽略了。 riple



    第二折。上周的某一天,在我们这边,类似的现象“终于”也发生了。由于时差的关系,我们没能得到美国软件工程师的及时支持。眼瞅着手上仅有的两个系统陷入瘫痪,工作不能继续,没办法,只能自己硬着头皮调试一下看看。系统崩溃后,嵌入式Linux操作系统的响应异常缓慢,通过网络登陆无法进行调试和控制。幸好还有串口调试台,通过串口可以看到系统反复打印出对总线上特定地址范围的数据写入失败。由于该现象发生在FPGA文件下载完成后,我通过在系统启动后FPGA下载前杀掉相关进程的方法阻止了系统的崩溃:只要不下载FPGA文件,或者替换为旧文件,系统就不会崩溃。 riple

    接下来,我试图找出FPGA引发系统崩溃的原因。中断信号引发系统崩溃的说法首先被排除了,原因是FPGA的中断产生逻辑电路相当标准,不可能产生随机的错误行为。问题缩小到FPGA连接到CPU的双向数据总线上,这里是除中断外唯一一个由FPGA驱动到CPU的逻辑电路。我的推论是,由于该FPGA工程没有对CPU相关的输入输出引脚进行时序约束,两次编译会导致双向数据总线的输出使能信号的响应差异,这一差异进一步影响了FPGA驱动双向数据总线的速度差异,在某些情况下,FPGA或早或晚地驱动了总线,引发了总线驱动冲突,导致CPU对总线上其它设备的访问失败。经过对所有CPU相关的信号进行时序约束后,编译的二进制文件没有引发系统崩溃。 riple



    第三折。问题并没有这样得到解决。两天后,在又一次对该工程进行编译后,一模一样的问题又出现了。去除我先前给工程施加的时序约束后,问题反而没有了。不加约束会错,加了约束也会错,看来约束并没有作用到问题的本质上。唯一可以得到确认的结论是:两次FPGA编译的结果是有差异的,特定电路的编译结果并没有得到时序约束的有效控制;问题随机出现,但是表现一致。 riple

    这一次,为了定位导致问题的具体逻辑电路,我必须对出问题的编译结果进行分析和实验。二进制文件是最终的编译结果,时序分析报告也是编译结果,但是这两个结果要么不可分析,要么包含了太多的信息而无法分析。我唯一可以进行分析和实验的对象就是布局布线(P&R)之后的底层网表数据。 riple

    通过RTL视图,我逐个定位了CPU相关引脚在Chip Planner视图中的位置。通过在Resource Property Editor中修改特定LE的对外连接和内部逻辑关系,我把所有可能驱动CPU的相关逻辑都关闭了:中断信号被禁止了,双向数据总线的使能被禁止了。通过执行Check & Save All Netlist Changes,我在不影响所有其他逻辑的功能和时序特性的情况下,得到了一个完全不会驱动CPU总线相关信号的FPGA二进制文件。出乎意料的是,该二进制文件下载后,系统依然崩溃。 riple



    到了这一步,我找遍了“路灯下所有能找的地方”,只能向其他方向“胡乱”摸索了。我尝试了给来自CPU的控制输入信号,包括所有的地址线,增加上拉电阻的方法,也没有成功。 riple

    经过了类似的一系列摸索,最终我在Pin Planner视图中发现了蹊跷:在该工程中竟然存在没有分配布局位置的输出引脚,而这些输出引脚在该项目中并没有被实际的输入逻辑驱动,这些引脚被Analysis & Synthesis工具缺省地连接到了逻辑“0”上。通过比较成功和失败两次编译结果中给出的最终引脚分配报告,我发现,这些没有得到位置约束的引脚竟然可能随机出现在任意的空闲引脚上。 riple

    通过进一步分析,在导致系统崩溃的编译结果中我最终找到了答案:一个没有逻辑驱动,也忘了分配布局位置的输出引脚被Fitter工具随机分配到了FPGA没有用到(也没有位置约束)的一根CPU地址输入线上,这根地址线就被短路到了“0”电平上,进而导致CPU外部总线上特定地址范围不能被CPU访问到,最终引发了系统崩溃。 riple



    通过这一问题的解决,我获得了以下几点认识: riple

1. 没有约束位置的引脚是很危险的,尤其是输出引脚。随机分配的结果很可能是灾难性的。所以,PCB原理图上的所有引脚,即使在FPGA内部没有被用到,也最好如实地加以约束。 riple

2. Quartus II提供的ECO工具,即“增量式布局布线后网表修改功能”非常好用。既保留了上一次的全编译结果,还缩短了编译时间。用来做快速实验(quick and dirty)最合适不过了。 riple

3. Resource Property Editor中对输出使能信号的控制方法。(乍看起来,逻辑上的连接与示意图上的连接正好相反,其实不然。需要注意。) riple

4. 为什么会存在未分配的输出和输入引脚?这是因为该工程还存在尚未实现的后期功能。这些引脚就是给以后开发留下的,由于我们太专注于眼前要实现的功能而被忽视了。 riple

5. 为什么会存在未用到,却实际连接了的地址线?这是PCB设计上的“冗余设计”。这样的冗余设计在该项目中还有很多,有一些还真在关键时刻给了我们FPGA开发上的便利。 riple

6. 既然上述两个问题都有合理的解释,为什么还会出现这么不合理的错误?原因之一是在PCB和FPGA设计上缺乏完善的设计文档,PCB设计者的意图没有有效传达给FPGA设计者,而FPGA设计者之间也没能充分交流。原因之二是FPGA开发流程上缺乏被称之为“Peer Review”的设计评审和设计质量保证措施,一个显而易见的错误就被这样忽略并遗留了下来。 riple