Verilog运算符
Verilog 中的运算符是构成表达式的基础,用于对变量进行操作。Verilog 提供了非常丰富的运算符,其中一些与软件编程语言(如 C 语言)类似,但也有一些是专门为硬件描述而设计的。
以下是 Verilog 运算符的详细分类和说明:
一、运算符
1. 算术运算符
这些运算符执行算术计算。如果操作数中有 x 或 z,则整个结果也是 x。
| 运算符 | 描述 | 示例 |
|---|---|---|
+ | 加法 | c = a + b; |
- | 减法 | c = a - b; |
* | 乘法 | c = a * b; |
/ | 除法 | c = a / b; // 整数除法 |
% | 取模 | c = a % b; // 求余数 |
** | 幂运算 | c = a ** 2; // a 的平方 |
注意:
-
对于
reg和wire类型,操作通常被视为无符号整数。 -
除法和对 2 的幂次取模可以被综合,但一般的除法和取模运算通常不可综合,或者会生成非常复杂的电路。
2. 关系运算符
比较两个值的大小关系,返回一个布尔值(1‘b1 表示真,1’b0 表示假)。如果操作数中有 x 或 z,则结果为 x。
| 运算符 | 描述 | 示例 |
|---|---|---|
> | 大于 | a > b |
< | 小于 | a < b |
>= | 大于等于 | a >= b |
<= | 小于等于 | a <= b |
== | 逻辑相等 | a == b |
!= | 逻辑不等 | a != b |
3. 等式运算符
比关系运算符更严格,它们会比较所有的位,包括 x 和 z。
| 运算符 | 描述 | 示例 |
|---|---|---|
=== | 逻辑相等(Case Equality) | a === b |
!== | 逻辑不等(Case Inequality) | a !== b |
== vs === 的区别:
-
a == b:如果a或b中有x或z,结果为x。 -
a === b:会逐位精确比较,0,1,x,z都必须完全一致才返回 1。例如1‘bx === 1’bx的结果是1‘b1,而1’bx == 1'bx的结果是1'bx。
综合注意: === 和 !== 通常不可综合,主要用于仿真和测试平台。
4. 逻辑运算符
对操作数进行逻辑运算,操作数被视为布尔值(非零为真,零为假)。返回一位的真假值。
| 运算符 | 描述 | 示例 |
|---|---|---|
! | 逻辑非 | if (!enable) ... |
&& | 逻辑与 | if (a && b) ... |
| || | 逻辑或 | if (a || b) ... |
5. 按位运算符
对操作数的每一位进行独立的逻辑运算。如果操作数长度不同,较短的会在高位补零。
| 运算符 | 描述 | 示例(设 a=4‘b1100, b=4’b1010) | ||
|---|---|---|---|---|
~ | 按位取反 | ~a 得到 4'b0011 | ||
& | 按位与 | a & b 得到 4'b1000 | ||
| | | 按位或 | a | b 得到 4’b1110 | ||
^ | 按位异或 | a ^ b 得到 4’b0110 | ||
^~ | 按位同或 | a ^~ b 得到 4’b1001 | ||
6. 缩减运算符
对单个操作数的所有位进行运算,最终产生一位的结果。可以看作是一系列按位运算的累积。
| 运算符 | 描述 | 示例(设 a=4‘b1100) |
|---|---|---|
& | 缩减与 | &a 等价于 1 & 1 & 0 & 0,结果为 1‘b0 |
~& | 缩减与非 | ~&a 结果为 1’b1 |
| | | 缩减或 | |a等价于1 | 1 | 0 | 0,结果为 1‘b1 |
| ~| | 缩减或非 | ~|a结果为1’b0 |
^ | 缩减异或 | ^a 等价于 1 ^ 1 ^ 0 ^ 0,结果为 1‘b0 |
^~ | 缩减同或 | ~^a 结果为 1’b1 |
7. 移位运算符
将操作数向左或向右移动指定的位数。空出的位用 0 填充。
| 运算符 | 描述 | 示例(设 a=4‘b1101) |
|---|---|---|
<< | 逻辑左移 | a << 2 得到 4’b0100 |
>> | 逻辑右移 | a >> 1 得到 4’b0110 |
<<< | 算术左移 | 与逻辑左移 << 相同 |
>>> | 算术右移 | 空出的位用符号位填充。 对于有符号数 $signed(a) >>> 1,结果为 4’b1110 |
注意: 算术移位要求操作数被声明为有符号数(例如 reg signed [3:0] a;)或使用 $signed() 系统函数。
8. 条件运算符
这是一个三目运算符,根据条件选择两个表达式中的一个。
| 运算符 | 描述 | 示例 |
|---|---|---|
?: | 条件运算符 | assign out = sel ? a : b; // 2选1 MUX |
这非常有用,可以直接综合成一个多路选择器。
9. 连接运算符
用于将多个操作数的位连接起来,形成一个新的、更宽的向量。
| 运算符 | 描述 | 示例 |
|---|---|---|
{} | 连接 | c = {a[3:0], b[1:0]}; // 将 a 的低 4 位和 b 的低 2 位连接成一个 6 位向量 |
{{}} | 复制 | d = {4{a}}; // 等价于 {a, a, a, a} |
10. 赋值运算符
主要用于过程赋值(在 always 或 initial 块中)。
| 运算符 | 描述 | 示例 |
|---|---|---|
= | 阻塞赋值 | b = a; // 立即执行 |
<= | 非阻塞赋值 | b <= a; // 在块结束时才执行 |
关键区别(非常重要!):
-
阻塞赋值
=:顺序执行。语句执行完毕后才执行下一条语句。常用于组合逻辑建模。 -
非阻塞赋值
<=:并行执行。所有右边的表达式同时求值,在always块结束时才同时赋值给左边。必须用于时序逻辑(寄存器)的建模。
好的编码风格:
-
在描述组合逻辑的
always @(*)块中,使用 阻塞赋值=。 -
在描述时序逻辑的
always @(posedge clk)块中,使用 非阻塞赋值<=。
二、运算符优先级总结
从最高到最低排列:
| 优先级 | 运算符类型 | 运算符 | 描述 |
|---|---|---|---|
| 最高 | 单目运算符 | + - ! ~ & ~& | ~| ^ ~^ ** | 一元加、一元减、逻辑非、按位非、缩减与、缩减与非、缩减或、缩减或非、缩减异或、缩减同或、幂运算 |
| 乘除取模 | * / % | 乘法、除法、取模 | |
| 加减 | + - | 加法、减法 | |
| 移位 | << >> <<< >>> | 逻辑左移/右移、算术左移/右移 | |
| 关系 | < <= > >= | 小于、小于等于、大于、大于等于 | |
| 等式 | == != === !== | 逻辑相等、逻辑不等、 case 相等、 case 不等 | |
| 缩减与 | & ~& | 按位与、按位与非 | |
| 缩减异或 | ^ ~^ | 按位异或、按位同或 | |
| 缩减或 | | ~| | 按位或、按位或非 | |
| 逻辑与 | && | 逻辑与 | |
| 逻辑或 | || | 逻辑或 | |
| 最低 | 条件 | ?: | 条件运算符(三目运算符) |
最佳实践: 为了代码清晰并避免错误,强烈建议使用括号 () 来明确指定运算的优先级,而不是依赖记忆。
希望这个全面的总结能帮助你更好地理解和使用 Verilog 运算符!
