跳到主要内容

运算符

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

位运算真值表

按位与(&)

aba & b
000
010
100
111

按位或(|)

aba 或 b
000
011
101
111

按位异或(^)

aba ^ b
000
011
101
110

位运算应用

位掩码

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);

表达式位宽

位宽规则

表达式结果的位宽由以下规则决定:

  1. 如果表达式有指定位宽的操作数,结果位宽取最大值
  2. 如果表达式是自决定的,结果位宽由表达式本身决定
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 代码至关重要。下一章将介绍组合逻辑设计。