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 |
例:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
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
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
`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的仿真结果一致。
关于多变量运算及赋值问题,参见赋值语句。
对应视频: