马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
本帖最后由 羽无芯 于 2021-3-9 20:43 编辑
verilog case,if语句情况不全包含会生成锁存器 数字电路中应避免产生不必要的锁存器 Latch
锁存器(Latch)是数字逻辑电路中很重要的一种基本电路,常见的锁存器包括三个端口:数据输入口、数据输出口、使能端。当使能端为高电平时,输入口的数据直接送到输出口,此时输入输出口可以看成是直接连通的;当使能端为低电平时,输出口的数据保持之前的数据不变,无论输入口的数据怎么变化,输出都保持不变,就是把原来的状态锁存下来了(所以才叫锁存器)。锁存器与触发器的区别在于:锁存器是电平触发,而触发器是边沿触发。锁存器在不锁存数据时,输出随输入变化;但一旦数据锁存时,输入对输出不产生任何影响。 在FPGA电路设计中,不规范的描述语言可能会产生意想不到的锁存器,而设计者往往并没有注意到自己的设计会被综合出锁存器,导致综合出的电路出现逻辑错误。 在数字电路中,产生意外的锁存器的情况一般有以下两种: 1.if……else……结构中缺少else 先看一个实际的例子:
用quartus综合一下这两个电路,看看产生的RTL图是怎样的: 左边的电路:
右边的电路:
由RTL视图可以直观的看出,左边的电路没有生成锁存器,而右边的电路生成了一个我们不想要的锁存器(q1$latch)。左边的电路是时序逻辑,生成触发器,而触发器是有使能端(en)的,使能端无效时就可以保存数据,无需锁存器。右边的电路是组合逻辑,在en为低电平时,输出q1要保持不变,而组合逻辑没有存储元件,只能生成锁存器来保持数据。所以在时序逻辑中,不完整的 if…else… 结构并不会生成锁存器,而组合逻辑中不完整的 if…else… 结构就会生成锁存器。为了避免我们设计的组合逻辑中出现不想要的锁存器,在使用 if…else… 结构时一定要写完整。把刚才例子中右边的电路写完整,并查看其RTL视图如下:
写完整后,就没有生成锁存器,而是生成了一个二选一的选择器,这正是我们想要设计的。
2. case结构中的分支没有包含所有情况且没有default语句
case结构中一般要加上default语句,以保证出现意外情况也可以作出相应的反应。如果没有加default并且case分支不完整,当出现case分支中没有列出的情况时,电路状态保持原来的状态不变,于是就会生成锁存器来保存状态,如下图的电路所示:
图中case分支中只写了(se=0)的情况,而(se=1)的情况未给出,且没有写default,于是当(se=1)时,q1保持原来的值不变,这样就产生了锁存器(q1$latch)。 如果将case分支补全,或者加上default语句,则如下图所示:
补全case分支后,就不会生成锁存器了。 同样,只有在组合逻辑中的case结构才有可能产生锁存器,而在时序逻辑电路中,即使case结构中的分支不完整,也不会产生锁存器,如下图所示:
因此,在设计组合逻辑电路时,要注意将 if…else… 结构中的else写完整,case结构中一定要加上default语句,这样可以减少综合出锁存器的可能性。 3.推荐使用assign语法替代if-else和case语法 verilog中的if-else和case语法存在两大缺点。 1)不能传播不定态。 2)会产生优先级的选择电路而非并行选择电路,从而不利于时序和面积 例子:if (sel1) out = in1[3:0]; else if (sel2) out = in2[3:0]; else if (sel3) out = in3[3:0]; else out = 4'b0; 如果此处确实希望生成一种优先级选择的逻辑,则推荐使用assign语法等效编写成如下形式,以规避x不定状态传播的问题: assign out = sel1 ? in1[3:0] : sel2 ? in2[3:0] : sel3 ? in3[3:0] : 4'b0; 而如果此处本来是希望生成一种并行选择的逻辑,则推荐使用assign语法明确地使用“与”-“或”逻辑,编写如下: assign out = ({4{sel1}} & in1[3:0]) | ({4{sel2}} & in2[3:0]) | ({4{sel3}} & in3[3:0]) ;
|