运算符
Verilog 提供了丰富的运算符用于描述硬件逻辑。本章详细介绍各类运算符的功能和用法。
算术运算符
基本算术运算
| 运算符 | 描述 | 示例 |
|---|---|---|
+ | 加法 | a + b |
- | 减法 | a - b |
* | 乘法 | a * b |
/ | 除法 | a / b |
% | 取模 | a % b |
wire [7:0] a = 8'd10;
wire [7:0] b = 8'd3;
wire [7:0] sum = a + b; // 13
wire [7:0] diff = a - b; // 7
wire [7:0] product = a * b; // 30
wire [7:0] quotient = a / b; // 3
wire [7:0] remainder = a % b; // 1
算术运算注意事项
位宽扩展
运算结果的位宽由操作数中最宽的操作数决定:
wire [3:0] a = 4'b1111; // 15
wire [7:0] b = 8'b00001000; // 8
wire [7:0] c = a + b; // 结果为 23,不会溢出
溢出处理
wire [3:0] a = 4'b1111; // 15
wire [3:0] b = 4'b0001; // 1
wire [3:0] c = a + b; // 结果为 0,溢出被丢弃
// 避免溢出:扩展位宽
wire [4:0] c_extended = {1'b0, a} + {1'b0, b}; // 结果为 16
有符号运算
reg signed [7:0] a = -10;
reg signed [7:0] b = 20;
wire signed [7:0] sum = a + b; // 结果为 10
一元运算符
wire [7:0] a = 8'd5;
wire [7:0] b = -a; // 一元负号
wire [7:0] c = +a; // 一元正号
位运算符
按位运算
| 运算符 | 描述 | 示例 |
|---|---|---|
~ | 按位取反 | ~a |
& | 按位与 | a & b |
| ` | ` | 按位或 |
^ | 按位异或 | a ^ b |
~^ 或 ^~ | 按位同或 | a ~^ b |
wire [3:0] a = 4'b1010;
wire [3:0] b = 4'b1100;
wire [3:0] not_a = ~a; // 0101
wire [3:0] and_ab = a & b; // 1000
wire [3:0] or_ab = a | b; // 1110
wire [3:0] xor_ab = a ^ b; // 0110
wire [3:0] xnor_ab = a ~^ b; // 1001
位运算真值表
按位与(&)
| a | b | a & b |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
按位或(|)
| a | b | a 或 b |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
按位异或(^)
| a | b | a ^ b |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
位运算应用
位掩码
wire [7:0] data = 8'hAB;
wire [7:0] masked = data & 8'h0F; // 提取低 4 位
wire [7:0] set_bits = data | 8'hF0; // 设置高 4 位
wire [7:0] toggle = data ^ 8'hFF; // 翻转所有位
奇偶校验
wire [7:0] data = 8'b10101010;
wire parity = ^data; // 异或归约,结果为 0(偶校验)
归约运算符
归约运算符将向量归约为单个位。
归约运算符列表
| 运算符 | 描述 | 示例 |
|---|---|---|
& | 归约与 | &a |
| ` | ` | 归约或 |
^ | 归约异或 | ^a |
~& | 归约与非 | ~&a |
| `~ | ` | 归约或非 |
~^ | 归约同或 | ~^a |
wire [3:0] a = 4'b1010;
wire and_reduce = &a; // 0 (1&0&1&0)
wire or_reduce = |a; // 1 (1|0|1|0)
wire xor_reduce = ^a; // 0 (1^0^1^0)
wire nand_reduce = ~&a; // 1
wire nor_reduce = ~|a; // 0
wire xnor_reduce = ~^a; // 1
归约运算应用
检测全零
wire [7:0] data;
wire is_zero = ~|data; // 所有位都为 0 时为 1
检测全一
wire [7:0] data;
wire is_all_ones = &data; // 所有位都为 1 时为 1
奇偶校验
wire [7:0] data;
wire even_parity = ^data; // 偶校验位
wire odd_parity = ~^data; // 奇校验位
逻辑运算符
逻辑运算符将操作数视为布尔值。
逻辑运算符列表
| 运算符 | 描述 | 示例 |
|---|---|---|
! | 逻辑非 | !a |
&& | 逻辑与 | a && b |
| ` | ` |
wire [3:0] a = 4'b0000;
wire [3:0] b = 4'b1010;
wire not_a = !a; // 1(a 为 0)
wire not_b = !b; // 0(b 非 0)
wire and_ab = a && b; // 0
wire or_ab = a || b; // 1
逻辑运算与位运算的区别
wire [3:0] a = 4'b1010;
wire [3:0] b = 4'b0101;
// 位运算:逐位运算
wire [3:0] bit_and = a & b; // 0000
// 逻辑运算:整体判断
wire logic_and = a && b; // 1(两者都非零)
短路求值
逻辑运算符支持短路求值:
// 如果 a 为假,不会计算 b
wire result = a && complex_function(b);
// 如果 a 为真,不会计算 b
wire result = a || complex_function(b);
关系运算符
关系运算符列表
| 运算符 | 描述 | 示例 |
|---|---|---|
> | 大于 | a > b |
< | 小于 | a < b |
>= | 大于等于 | a >= b |
<= | 小于等于 | a <= b |
wire [7:0] a = 8'd10;
wire [7:0] b = 8'd20;
wire gt = a > b; // 0
wire lt = a < b; // 1
wire ge = a >= b; // 0
wire le = a <= b; // 1
有符号比较
reg signed [7:0] a = -10;
reg signed [7:0] b = 5;
wire lt = a < b; // 1(有符号比较)
关系运算结果
关系运算的结果为 1 位:
- 条件为真:返回 1'b1
- 条件为假:返回 1'b0
- 操作数含 x 或 z:返回 1'bx
相等运算符
相等运算符列表
| 运算符 | 描述 | 示例 |
|---|---|---|
== | 逻辑相等 | a == b |
!= | 逻辑不等 | a != b |
=== | 全等 | a === b |
!== | 不全等 | a !== b |
wire [3:0] a = 4'b1010;
wire [3:0] b = 4'b1010;
wire [3:0] c = 4'b101x;
wire eq1 = a == b; // 1
wire eq2 = a == c; // x(含 x)
wire eq3 = a === c; // 0(精确比较)
wire eq4 = c === c; // 1(含 x 也相等)
== 与 === 的区别
| 运算符 | 处理 x 和 z | 可综合性 |
|---|---|---|
| == | 遇 x/z 返回 x | 可综合 |
| === | 精确比较 x/z | 仅仿真 |
wire [3:0] a = 4'b101x;
wire [3:0] b = 4'b101x;
wire eq1 = a == b; // x
wire eq2 = a === b; // 1
移位运算符
逻辑移位
| 运算符 | 描述 | 示例 |
|---|---|---|
<< | 逻辑左移 | a << n |
>> | 逻辑右移 | a >> n |
wire [7:0] a = 8'b0000_1010;
wire [7:0] left_shift = a << 2; // 0010_1000
wire [7:0] right_shift = a >> 2; // 0000_0010
逻辑移位规则:
- 左移:低位补 0
- 右移:高位补 0
算术移位
| 运算符 | 描述 | 示例 |
|---|---|---|
<<< | 算术左移 | a <<< n |
>>> | 算术右移 | a >>> n |
reg signed [7:0] a = 8'b1110_1010; // -22
wire [7:0] arith_right = a >>> 2; // 1111_1010(符号扩展)
wire [7:0] logic_right = a >> 2; // 0011_1010(零扩展)
算术移位规则:
- 算术左移:与逻辑左移相同,低位补 0
- 算术右移:高位用符号位填充
移位应用
乘除法优化
wire [7:0] a = 8'd10;
wire [7:0] mul_2 = a << 1; // a * 2
wire [7:0] mul_4 = a << 2; // a * 4
wire [7:0] div_2 = a >> 1; // a / 2
wire [7:0] div_4 = a >> 2; // a / 4
位提取
wire [31:0] data;
wire [7:0] byte1 = data >> 8; // 提取第 2 个字节
wire [7:0] byte2 = data >> 16; // 提取第 3 个字节
条件运算符
三元运算符
condition ? true_expr : false_expr
wire [7:0] a = 8'd10;
wire [7:0] b = 8'd20;
wire sel = 1'b1;
wire [7:0] result = sel ? a : b; // result = 10
条件运算符应用
多路选择器
module mux4(
input [1:0] sel,
input [7:0] in0,
input [7:0] in1,
input [7:0] in2,
input [7:0] in3,
output [7:0] out
);
assign out = (sel == 2'b00) ? in0 :
(sel == 2'b01) ? in1 :
(sel == 2'b10) ? in2 : in3;
endmodule
三态缓冲
module tri_state(
input enable,
input [7:0] data_in,
output [7:0] data_out
);
assign data_out = enable ? data_in : 8'bz;
endmodule
拼接运算符
基本拼接
{a, b, c, ...}
wire [3:0] a = 4'b1010;
wire [3:0] b = 4'b1100;
wire [7:0] c = {a, b}; // 1010_1100
重复拼接
{n{expression}}
wire [7:0] all_ones = {8{1'b1}}; // 1111_1111
wire [15:0] pattern = {4{4'b1010}}; // 1010_1010_1010_1010
wire [31:0] extended = {16{a}}; // 重复 a 16 次
拼接应用
符号扩展
wire [7:0] data;
wire [15:0] sign_extended = {{8{data[7]}}, data};
位重组
wire [7:0] byte_data;
wire [31:0] word_data = {4{byte_data}}; // 复制 4 次
构建复杂信号
wire [7:0] header = 8'hAA;
wire [7:0] length;
wire [31:0] payload;
wire [47:0] packet = {header, length, payload};
运算符优先级
从高到低排列:
| 优先级 | 运算符 |
|---|---|
| 1 | ! ~ + -(一元) |
| 2 | * / % |
| 3 | + -(二元) |
| 4 | << >> <<< >>> |
| 5 | < <= > >= |
| 6 | == != === !== |
| 7 | & ~& |
| 8 | ^ ~^ |
| 9 | ` |
| 10 | && |
| 11 | ` |
| 12 | ?: |
优先级示例
// 推荐使用括号明确优先级
wire result = (a & b) | (c & d); // 清晰
// 不推荐依赖默认优先级
wire result = a & b | c & d; // 等价,但不清晰
复杂表达式
wire [7:0] a, b, c, d;
// 复杂表达式使用括号
wire result = ((a > b) && (c < d)) ? (a + b) : (c - d);
表达式位宽
位宽规则
表达式结果的位宽由以下规则决定:
- 如果表达式有指定位宽的操作数,结果位宽取最大值
- 如果表达式是自决定的,结果位宽由表达式本身决定
wire [3:0] a = 4'b1111;
wire [7:0] b = 8'b00001111;
wire [7:0] c = a + b; // 结果位宽为 8 位
自决定表达式
某些表达式的位宽是自决定的:
wire [7:0] a = 8'b11111111;
wire [3:0] b = a[3:0]; // 自决定,位宽为 4
wire c = &a; // 归约运算,位宽为 1
位宽扩展示例
wire [3:0] a = 4'b1111; // 15
wire [3:0] b = 4'b0001; // 1
// 不扩展:溢出
wire [3:0] sum1 = a + b; // 0000
// 扩展:正确结果
wire [4:0] sum2 = a + b; // 10000 (16)
小结
本章介绍了 Verilog 的各类运算符:
- 算术运算符:+、-、*、/、%
- 位运算符:
、&、|、^、^ - 归约运算符:&、|、^、
&、|、~^ - 逻辑运算符:!、&&、||
- 关系运算符:
>、<、>=、<= - 相等运算符:
==、!=、===、!== - 移位运算符:
<<、>>、<<<、>>> - 条件运算符:?:
- 拼接运算符:
{}、{{}}
理解运算符的优先级和位宽规则对于编写正确的 Verilog 代码至关重要。下一章将介绍组合逻辑设计。