Verilog 位运算符也是主要由与、或、非等逻辑运算构成,但与逻辑运算符不同。逻辑运算符主要是对关系运算及等式运算后的值进行操作。而位运算是针对变量进行运算。运算的操作数可以取0,1,x,z四种,运算的结果包含0,1,x 三种情况的值。位运算符也叫按位操作符,是二元操作符(除~是一元操作符外),操作符对应的操作数是按照对应位一一运算的。
- 按位操作符:
按位操作符包括取反(~),与(&),或(|),异或(^),同或(~^)。其中同或也可以理解为两个操作数先异或操作,再对异或的结果取反。
按位操作符对 2 个操作数的位进行按位操作。如果 2 个操作数位宽不相等,则用‘0’ 向左扩展补充较短的操作数。
如 c[3:0] = a[3:0] & b[0] 相当于 c[3:0] = a[3:0] & {3’b0, b[0]},
即
c[3] = a[3] & 1’b0,
c[2] = a[2] & 1’b0,
c[1] = a[1] & 1’b0,
c[0] = a[0] & b[0]。
- 取反操作符:
取反操作符只有一个操作数,它对操作数的每 bit 数据进行取反操作。
操作数的类型不限,可以为输入、输出端口,也可以是wire类型数据,reg类型数据,甚至integer类型数据。
操作符决断函数表
1) ~
| 操作符 ~ | |
| 输入 | 输出 |
| a | y |
| 0 | 1 |
| 1 | 0 |
| x | x |
| z | x |
2) &
| 操作符& | ||
| 输入 | 输出 | |
| a | b | y |
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 0 | x | 0 |
| 0 | z | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
| 1 | x | x |
| 1 | z | x |
| x | 0 | 0 |
| x | 1,x,z | x |
| z | 0 | 0 |
| z | 1 | x |
| z | x | x |
| z | z | x |
3) |
| 操作符| | ||
| 输入 | 输出 | |
| a | b | y |
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 0 | x | x |
| 0 | z | x |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
| 1 | x | 1 |
| 1 | z | 1 |
| x | 1 | 1 |
| x | 0,x,z | x |
| z | 0 | x |
| z | 1 | 1 |
| z | x | x |
| z | z | x |
4) ^
| 操作符^ | ||
| 输入 | 输出 | |
| a | b | y |
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 0 | x | x |
| 0 | z | x |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
| 1 | x | x |
| 1 | z | x |
| x | 0 | x |
| x | 1,x,z | x |
| z | 0 | x |
| z | 1 | x |
| z | x | x |
| z | z | x |
5) ~^
| 操作符~^ | ||
| 输入 | 输出 | |
| a | b | y |
| 0 | 0 | 1 |
| 0 | 1 | 0 |
| 0 | x | x |
| 0 | z | x |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
| 1 | x | x |
| 1 | z | x |
| x | 0 | x |
| x | 1,x,z | x |
| z | 0 | x |
| z | 1 | x |
| z | x | x |
| z | z | x |
例:
module bit_op
(
input [3:0] a,
input [3:0] b,
output [3:0] na,
output [3:0] a_and_b,
output [3:0] a_and_b0,
output [3:0] a_or_b,
output [3:0] a_or_b0,
output [3:0] a_xor_b,
output [3:0] a_xor_b0,
output [3:0] a_nxor_b,
output [3:0] a_nxor_b0,
output [3:0] y
);
integer i = 3;
assign na = ~a;
assign a_and_b = a & b;
assign a_and_b0 = a & b[0];
assign a_or_b = a | b;
assign a_or_b0 = a | b[0];
assign a_xor_b = a ^ b;
assign a_xor_b0 = a ^ b[0];
assign a_nxor_b = a ~^ b;
assign a_nxor_b0 = a ~^ b[0];
assign y = ~i;
endmodule
Modelsim testbench tb.v
`timescale 1 ns/1 ps
module tb
(
);
reg [3:0] a,b;
wire [3:0] na;
wire [3:0] a_and_b, a_and_b0;
wire [3:0] a_or_b, a_or_b0;
wire [3:0] a_xor_b, a_xor_b0;
wire [3:0] a_nxor_b, a_nxor_b0;
wire [3:0] y;
initial
begin
a = 4'b0000;
b = 4'b0000;
#10
b = 4'b0001;
#10
a = 4'b0010;
#10
b = 4'b01x0;
#10
a = 4'b0x10;
b = 4'b1x00;
#10
a = 4'bz110;
b = 4'bx0z1;
#10
a = 4'b0111;
b = 4'bz1x0;
#10
a = 4'b1111;
b = 4'b0110;
#10
a = 4'b111x;
b = 4'b0110;
#10
a = 4'b111x;
b = 4'b011z;
#10
a = 4'b1111;
b = 4'b011z;
end
bit_op bit_op_dut
(
.a (a),
.b (b),
.na (na),
.a_and_b (a_and_b),
.a_and_b0 (a_and_b0),
.a_or_b (a_or_b),
.a_or_b0 (a_or_b0),
.a_xor_b (a_xor_b),
.a_xor_b0 (a_xor_b0),
.a_nxor_b (a_nxor_b),
.a_nxor_b0 (a_nxor_b0),
.y (y)
);
endmodule

图1
根据决断函数表很容易分析表中的结果,这里需要单独解释的是当整数运算时,首先将整数按照32bit的方式展开,与其它参与运算的变量按照右对齐的方式,截取需要的位参与运算。
例:
integer i = 3;
wire [3:0] y;
assign y = ~i;
第一步:将i展开成 i = 32’b0000_0000_0000_0000 _0000_0000_0000_0011;
第二步: 按位取反 ~i = 32’b1111_1111_1111_1111_1111_1111_1111_1100;
第三步:右对齐按照被赋值的变量位宽截取: y = ~i = 4’b1100;
这个结果和modelsim的仿真结果一致。
关于多变量运算及赋值问题,参见赋值语句。
对应视频:
学习本节后有几点收获,1、按位操作符包括取反(~),与(&),或(|),异或(^),同或(~^);2、如果 2 个操作数位宽不相等,则用‘0’ 向左扩展补充较短的操作数;3、当整数运算时,首先将整数按照32bit的方式展开,与其它参与运算的变量按照右对齐的方式,截取需要的位参与运算;
文章针对位运算符进行了全面总结,并配有真值表、相应实例以及仿真图形,同时,文章也对整型数如何参与运算,做了详细介绍!