跳转至

Verilog常见问题分析

勿以善小而不为,勿以恶小而为之。——《三国志·蜀志传》

在使用Vivado进行工程设计时,在设计的不同阶段都会出现各种各样的错误和警告。本节将会介绍一些常见的问题,希望能够帮助大家更好地进行工程设计。

1. Warning:位宽不匹配

[Synth 8-689] width (1) of port connection 'dout' does not match port width (4) of module 'mux2_1'

位宽不匹配是非常致命的错误(虽然它只是个warning),因为它会导致仿真中出现大量的z的x。例如上面这条错误,我们就理解为,例化mux2_1,本应是一个4位宽的接口dout却接上了一个位宽为1的线路。

这个问题的解决办法是 检查问题中描述的接口是否被正确连接了 。如果定位到了对应的代码具体某行,直接解决即可,否则需要查看该模块与外部模块连接时这个接口的情况。

位宽不匹配的类似错误

在RTL分析阶段,我们还会遇到信号未连接、信号未使用等问题,这些问题结局思路与位宽不匹配类似,都是回到代码中检查对应的接口即可。但切记:这些问题不应该被忽视,一定要在RTL分析阶段完全解决。

2. Warning:空载

[Synth 8-7071] port 'din2' of module 'mux2_1' is unconnected for instance 'decoder_input_mux'

空载是指在例化时忘记写某个模块的某个输入接口,这往往是因为接口太多导致的粗心错误。这里已经写的非常清楚:mux2_1模块的din2接口没有接上。

空载不一定是错误

有时候,我们会故意不接某个输入接口,这样就会出现空载的warning。这种情况下,如果你可以忍受不断的报警,那么可以不用管它。但是如果你想要消除这个warning,那么还是要给这个接口接一个不影响结果的常值。

3. Warning:值不可达

[Synth 8-151] case item 32'hffff is unreachable

这类问题一般出现在case语句中,表示某个case分支永远不会被执行,这一般意味着case括号中的信号位宽不足以到达这个数。

这个问题的解决方法是 根据定位的行数检查case括号中的变量是否位宽足够大 。如果不足则需要扩展位宽。

你有没有写错变量名?

有些时候,我们更容易把变量名拼写错误,而Vivado会默认把没有声明的变量当作1位宽的wire型信号,这时候也会出现值不可达的warning。

4. Warning:使用在声明之前

[Synth 8-333] identifier 'dout' is used before its declaration

这是一个在软件编程语言中必错的问题,但在Verilog中却是可以通过的。

这个问题产生的原因是,Verilog中的信号声明是可以放在任意位置的,但是如果你在声明之前使用了这个信号,那么Vivado就会给出警告。或许这个警告不会对正确性有任何影响,但它可能会加大资源使用量和综合电路的时间。

5. Warning:推断出锁存器

[Synth 8-373] inferring latch for variable 'psum_reg'

锁存器的产生一般代表着组合电路的case或if-else没有列举所有的情况,这时电路需要在某些情况下保持上一次的状态,这就需要锁存器来实现。可是, 锁存器的定义就已经违背了组合电路的原则 ,这个电路也不再是组合的了。

解决问题的办法就是给所有组合电路的case加上default分支,给所有if-else加上else分支。这样就可以保证所有情况都被列举到,不会产生锁存器。

锁存器一定代表错误

许多同学可能认为,锁存器不一定代表错误,因为那些没有被列举的情况永远不会发生。这种想法是错误的!在逻辑上确实是这样,但不要忘记上板之后会有信号的毛刺。一旦那些毛刺被捕捉到,那么这些没有被列举的情况就会发生,这时候锁存器就会被触发,导致电路状态直接锁死。

锁存器是“仿真通过上板不过”的重要原因之一。如果你通过了行为仿真而上板结果不正确,那么一定要打开电路图,看看是否有锁存器产生。

6. Critical Warning:多驱动

[Synth 8-6859] multi-driven net on pin d_OBUF[1] with 1st driver pin 'd_OBUF[1]_inst_i_1/O'

多驱动是指一个输出信号同时被多个输入信号驱动,这是一个非常严重的问题,因为这会导致电路的行为不确定。在编写代码时,以下两种情况会被Vivado认为存在多驱动情况:

  • 一个信号被多个always块赋值
  • 一个信号被多个assign语句赋值

在这条报错信息里,d这根wire型变量被作为了多个模块的输出,因此是错误的。

定位多驱动的信号

多驱动问题一般是在实现电路时被报出。由于Vivado在实现时会将信号重命名、元件重排(元件可能被移到另一个模块中),因此报错信息中说的信号名可能与代码中的信号名不一致,但大多数情况下都是给代码中的信号名加了一些后缀。

7. Critical Warning:组合环

[Synth 8-6859] Found Timing Loop

组合环是指一个信号经过组合电路后又回到了自己,例如;

assign a = b;
assign b = a;
由于Vivado本身的环路算法不是很好,组合环报错只能粗浅地具体到某个模块,而由于模块之间的互联,这个环路可能会跨越多个模块,因此这个报错信息并不一定能够准确地定位到环路的位置。

想要解决组合环,首先应该对简单的电路部分进行检查,排除问题后再检查复杂的电路部分。一般情况下,组合环都是由于接线错误、输入接入输出等问题导致的,因此需要我们在编写代码时就注意这些问题。

聪明反被聪明误

考虑这样的一个代码:

assign a = a & 1;
这是一个必出组合环的情况,可是聪明的Vivado却会在实现电路时想尽一切办法避免组合环,在实现电路时并没有报出错误。这就很容易导致“仿真通过,上板不过”的问题。因此,组合环是一个极难发现又难以找到的问题,我们应当在初期设计时梳理清楚,尽量避免出现这种情况。