有感:作为硅农,我们的世界不仅仅是0和1的苟且,还有x和z的恐惧。
前言
首先,来认识一下这几个符号的等于和不等的写法:
- 逻辑等(
==)和 逻辑不等(!=) - 全等(
===)和 不全等(!==) - 通配符等于(
==?)和 通配符不等(!=?)

其次,再复习一下基本的单比特与运算、或运算,其真值表如下:

乍一看,似乎还挺复杂的不是嘛,其实还是有规律可循的。首先由输出结果可知,四值逻辑运算的结果只有0、1和x,并且与常量0和1运算时,仍然满足逻辑代数的基本公式:0 · A = 0、1 · A = A、0 + A = A、1 + A = 1;以及满足公式:A · A = A、A + A = A。总结下来,最重要的就是两句话:
- 0与上任何值都等于0;
- 1或上任何值都等于1。
一、逻辑等(==)和 逻辑不等(!=)
逻辑等(==)和 逻辑不等(!=)是我们在开发中用的最多的,它的返回结果在SystemVerilog中有三种:0、1和x。
- 针对单比特的逻辑等和逻辑不等运算有如下表格:

- 针对多比特的逻辑等和逻辑不等运算有如下代码:
$display("%b == %b : %b", 4'b1010, 4'b1011, 4'b1010 == 4'b1011); // 0
$display("%b != %b : %b", 4'b1010, 4'b1011, 4'b1010 != 4'b1011); // 1
$display("%b == %b : %b", 4'b1010, 4'b10x0, 4'b1010 == 4'b10x0); // x
$display("%b == %b : %b", 4'b1010, 4'b10x1, 4'b1010 == 4'b10x1); // 0 注意!注意!注意!
$display("%b != %b : %b", 4'b1010, 4'b10x0, 4'b1010 != 4'b10x0); // x
$display("%b != %b : %b", 4'b1010, 4'b10x1, 4'b1010 != 4'b10x1); // 1
$display("%b == %b : %b", 4'b1x10, 4'b1x10, 4'b1x10 == 4'b1x10); // x
$display("%b == %b : %b", 4'b1z10, 4'b1x10, 4'b1z10 == 4'b1x10); // x
$display("%b != %b : %b", 4'b1x10, 4'b1x10, 4'b1x10 != 4'b1x10); // x
$display("%b != %b : %b", 4'b1z10, 4'b1x10, 4'b1z10 != 4'b1x10); // x
如何去理解逻辑等和逻辑不等运算呢?
- 我之前是这样理解的:只要比较中含有x或z,那么输出就是x。(注意,这是我之前错误的理解!)显然,这个理解可以直接用反例:
4'b1010 == 4'b10x1 // 输出0来打脸!
既然上述理解是错误的,那么应该如何正确理解呢?莫急,且听我娓娓道来!
- 实际上,多比特逻辑等和逻辑不等的运算规则很简单,都是逐位比较操作数(bit for bit)。对于逻辑等比较,对逐位“逻辑等”比较的结果再进行与运算;而对于逻辑不等比较,对逐位“逻辑不等”比较的结果再进行或运算。
- 比如:
4'b1010 == 4'b10x1,则等价于(1'b1 == 1'b1) & (1'b0 == 1'b0) & (1'b1 == 1'bx) & (1'b0 == 1'b1),即1'b1 & 1'b1 & 1'bx & 1'b0,所以结果为1'b0。 - 再比如:
4'b1010 != 4'b10x1,则等价于(1'b1 != 1'b1) | (1'b0 != 1'b0) | (1'b1 != 1'bx) | (1'b0 != 1'b1),即1'b0 | 1'b0 | 1'bx | 1'b1,所以结果为1'b1。
二、全等(===)和 不全等(!==)
全等,“全”顾名思义就是会去匹配四种状态值:0、1、x、z,它的返回结果有两种:0和1。
-
针对单比特的全等和不全等运算有如下表格:

-
针对多比特的全等和不全等运算有如下代码:
$display("%b === %b : %b", 4'b1010, 4'b1011, 4'b1010 === 4'b1011); // 0
$display("%b !== %b : %b", 4'b1010, 4'b1011, 4'b1010 !== 4'b1011); // 1
$display("%b === %b : %b", 4'b1010, 4'b10x0, 4'b1010 === 4'b10x0); // 0
$display("%b === %b : %b", 4'b1010, 4'b10x1, 4'b1010 === 4'b10x1); // 0
$display("%b !== %b : %b", 4'b1010, 4'b10x0, 4'b1010 !== 4'b10x0); // 1
$display("%b !== %b : %b", 4'b1010, 4'b10x1, 4'b1010 !== 4'b10x1); // 1
$display("%b === %b : %b", 4'b1x10, 4'b1x10, 4'b1x10 === 4'b1x10); // 1
$display("%b === %b : %b", 4'b1z10, 4'b1x10, 4'b1z10 === 4'b1x10); // 0
$display("%b !== %b : %b", 4'b1x10, 4'b1x10, 4'b1x10 !== 4'b1x10); // 0
$display("%b !== %b : %b", 4'b1z10, 4'b1x10, 4'b1z10 !== 4'b1x10); // 1
重要结论:对于=== 和 !==的输出多比特输出比较容易理解,只有0和1嘛,每一位都匹配上是1,否之为0!
对于全等和全不等,记住上述结论就够用了,但为了更加深刻的理解,这里稍稍引申一下。
- 实际上,不仅仅多比特逻辑等和逻辑不等的运算规则满足逐位比较,多比特全等和不全等的运算规则也满足逐位比较,即:对于全等比较,对逐位全等比较的结果再进行与运算;而对于不全等比较,对逐位不全等比较的结果再进行或运算。
- 比如:
4'b1010 === 4'b10x0,则等价于(1'b1 === 1'b1) & (1'b0 === 1'b0) & (1'b1 === 1'bx) & (1'b0 === 1'b0),即1'b1 & 1'b1 & 1'b0 & 1'b1,所以结果为1'b0。 - 再比如:
4'b1010 !== 4'b10x1,则等价于(1'b1 !== 1'b1) | (1'b0 !== 1'b0) | (1'b1 !== 1'bx) | (1'b0 !== 1'b1),即1'b0 | 1'b0 | 1'b1 | 1'b1,所以结果为1'b1。
三、匹配等(==?)和 匹配不等(!=?)
匹配等(==?)和 匹配不等(!=?)是同样也是逐位比较的,返回结果有三种:0、1和x。
需要特别注意的是:“匹配等”仅仅可以把右侧操作数中的 x和z 当做 0/1 来匹配左侧操作数中的 0/1,当然了右侧 x/z 可以对应匹配左侧的 x/z(无序)。说着可能有点拗口,看下面的表格便一目了然了!
- 针对单比特的“匹配等”和“匹配不等”运算有如下表格(注意:需要区分操作数在运算符的哪一侧!):

- 针对多比特的“匹配等”和“匹配不等”运算有如下代码:
$display("%b ==? %b : %b", 4'b1010, 4'b1011, 4'b1010 ==? 4'b1011); // 0
$display("%b !=? %b : %b", 4'b1010, 4'b1011, 4'b1010 !=? 4'b1011); // 1
$display("%b ==? %b : %b", 4'b1010, 4'b10x0, 4'b1010 ==? 4'b10x0); // 1
$display("%b ==? %b : %b", 4'b1010, 4'b10x1, 4'b1010 ==? 4'b10x1); // 0
$display("%b !=? %b : %b", 4'b1010, 4'b10x0, 4'b1010 !=? 4'b10x0); // 0
$display("%b !=? %b : %b", 4'b1010, 4'b10x1, 4'b1010 !=? 4'b10x1); // 1
$display("%b ==? %b : %b", 4'b1010, 4'b10x0, 4'b10x0 ==? 4'b1010 ); // x
$display("%b ==? %b : %b", 4'b1010, 4'b10x1, 4'b10x1 ==? 4'b1010 ); // 0
$display("%b !=? %b : %b", 4'b1010, 4'b10x0, 4'b10x0 !=? 4'b1010 ); // x
$display("%b !=? %b : %b", 4'b1010, 4'b10x1, 4'b10x1 !=? 4'b1010 ); // 1
$display("%b ==? %b : %b", 4'b1x10, 4'b1x10, 4'b1x10 ==? 4'b1x10); // 1
$display("%b ==? %b : %b", 4'b1z10, 4'b1x10, 4'b1z10 ==? 4'b1x10); // 1
$display("%b !=? %b : %b", 4'b1x10, 4'b1x10, 4'b1x10 !=? 4'b1x10); // 0
$display("%b !=? %b : %b", 4'b1z10, 4'b1x10, 4'b1z10 !=? 4'b1x10); // 0
同前面介绍的逻辑(不)等、(不)全等一样,匹配等也满足逐位比较的运算规则:
- 结论:对于“匹配等”比较,对逐位“匹配等”比较的结果再进行与运算;而对于“匹配不等”比较,对逐位“匹配不等”比较的结果再进行或运算。
- 比如:
4'b1010 ==? 4'b10x0,则等价于(1'b1 ==? 1'b1) & (1'b0 ==? 1'b0) & (1'b1 ==? 1'bx) & (1'b0 ==? 1'b0),即1'b1 & 1'b1 & 1'b1 & 1'b1,所以结果为1'b1。 - 再比如:
4'b10x0 !=? 4'b1010,则等价于(1'b1 !=? 1'b1) | (1'b0 !=? 1'b0) | (1'bx !=? 1'b1) | (1'b0 !=? 1'b0),即1'b0 | 1'b0 | 1'bx | 1'b0,所以结果为1'bx。 - 再比如:
4'b10x1 !=? 4'b1010,则等价于(1'b1 !=? 1'b1) | (1'b0 !=? 1'b0) | (1'bx !=? 1'b1) | (1'b1 !=? 1'b0),即1'b0 | 1'b0 | 1'bx | 1'b1,所以结果为1'b1。
四、总结
综上,无论是逻辑等(==)、全等(===)还是匹配等(==?),都遵循按位比较原则,即:对于相等比较,对逐位比较的结果再进行与运算;而对于不等比较,对逐位比较的结果再进行或运算。
参考
- 【数字IC验证快速入门】15、SystemVerilog学习之基本语法2(操作符、类型转换、循环、Task/Function…内含实践练习)
- Systemverilog中===、==与 !的区别
- SystemVerilog 中的相等运算符:== or === ?
附录
单比特运算测试代码(以“逻辑等”为例,其他运算类比替换即可):
logic v[4] = '{1'b0, 1'b1, 1'bz, 1'bx};
initial begin
foreach(v[i])
foreach(v[j])
$display("%b == %b : %b", v[i], v[j], v[i] == v[j]);
end
778

被折叠的 条评论
为什么被折叠?



