操作符类型
下表以优先级顺序列出了 Verilog 操作符。注意 “与” 操作符的优先级总是比相同类型的 “或” 操作符高。本文将对每个操作符用一个例子作出解释。

Verilog 中的大小(size)与符号
- Verilog 根据表达式中变量的长度对表达式的值自动地进行调整。
- Verilog 自动截断或扩展赋值语句中右边的值以适应左边变量的长度。
- 当一个负数赋值给无符号变量如 reg 时,Verilog 自动完成二进制补码计算。
module sign_size;
reg [3:0] a, b;
reg [15:0] c;
initial begin
a = -1; // a 是无符号数,因此其值为 1111
b = 8; c = 8; // b = c = 1000
#10 b = b + a; // 结果 10111 截断, b = 0111
#10 c = c + a; // c = 10111
end
endmodule
算术操作符
| + | 加 |
|---|---|
| - | 减 |
| * | 乘 |
| / | 除 |
| % | 模 |
module arithops ();
parameter five = 5;
integer ans, int;
reg [3: 0] rega, regb;
reg [3: 0] num;
initial begin
rega = 3;
regb = 4'b1010;
int = -3; //int = 1111……1111_1101
end
initial fork
#10 ans = five * int; // ans = -15
#20 ans = (int + 5) / 2; // ans = 1
#30 ans = five / int; // ans = -1
#40 num = rega + regb; // num = 1101
#50 num = rega + 1; // num = 0100
#60 num = int; // num = 1101
#70 num = regb % rega; // num = 1
#80 $finish;
join
endmodule
- 注意 integer 和 reg 类型在算术运算时的差别。integer 是有符号数,而 reg 是无符号数。
- 将负数赋值给 reg 或其它无符号变量使用 2 的补码算术。
- 如果操作数的某一位是 x 或 z,则结果为 x。
- 在整数除法中,余数舍弃。
- 模运算中使用第一个操作数的符号。
按位操作符
| ~ | not |
|---|---|
| & | and |
| I | or |
| ^ | xor |
| ~ ^ | xnor |
| ^ ~ | xnor |
module bitwise ();
reg [3: 0] rega, regb, regc;
reg [3: 0] num;
initial begin
rega = 4'b1001;
regb = 4'b1010;
regc = 4'b11x0;
end
initial fork
#10 num = rega & 0; // num = 0000
#20 num = rega & regb; // num = 1000
#30 num = rega | regb; // num = 1011
#40 num = regb & regc; // num = 10x0
#50 num = regb | regc; // num = 1110
#60 $finish;
join
endmodule
- 按位操作符对矢量中相对应位运算。
regb = 4’b1 0 1 0
regc = 4’b1 x 1 0
num = regb & regc = 1 0 1 0 ; - 位值为 x 时不一定产生 x 结果。如 #50 时的 or计算。
- 当两个操作数位数不同时,位数少的操作数零扩展到相同位数。
a = 4’b1011;
b = 8’b01010011;
c = a | b; // a 零扩展为 8’b00001011
一元归约操作符
| & | and |
|---|---|
| I | or |
| ^ | xor |
| ~ ^ | xnor |
| ^ ~ | xnor |
module reduction();
reg val;
reg [3: 0] rega, regb;
initial begin
rega = 4'b0100;
regb = 4'b1111;
end
initial fork
#10 val = & rega ; // val = 0
#20 val = | rega ; // val = 1
#30 val = & regb ; // val = 1
#40 val = | regb ; // val = 1
#50 val = ^ rega ; // val = 1
#60 val = ^ regb ; // val = 0
#70 val = ~| rega; // (nor) val = 0
#80 val = ~& rega; // (nand) val = 1
#90 val = ^rega && ®b; // val = 1
$finish;
join
endmodule
- 归约操作符的操作数只有一个。
- 对操作数的所有位进行位操作。
- 结果只有一位,可以是 0, 1, x。
逻辑操作符
| ! | not |
|---|---|
| && | and |
| II | or |
module logical ();
parameter five = 5;
reg ans;
reg [3: 0] rega, regb, regc;
initial begin
rega = 4'b0011; // 逻辑值为 “1”
regb = 4'b10xz; // 逻辑值为 “1”
regc = 4'b0z0x; // 逻辑值为 “x”
end
initial fork
#10 ans = rega && 0; // ans = 0
#20 ans = rega || 0; // ans = 1
#30 ans = rega && five; // ans = 1
#40 ans = regb && rega; // ans = 1
#50 ans = regc || 0; // ans = x
#60 $finish;
join
endmodule
- 逻辑操作符的结果为一位 1,0 或 x。
- 逻辑操作符只对逻辑值运算。
- 如操作数为全 0,则其逻辑值为 false
- 如操作数有一位为 1,则其逻辑值为 true
- 若操作数只包含 0、x、z,则逻辑值为 x
- 逻辑反操作符将操作数的逻辑值取反。例如,若操作数为全 0,则其逻辑值为 0,逻辑反操作值为 1。
逻辑反与位反的对比
| ! | logical not | 逻辑反 |
|---|---|---|
| ~ | bit-wise not | 位反 |
module negation();
reg [3: 0] rega, regb;
reg [3: 0] bit;
reg log;
initial begin
rega = 4'b1011;
regb = 4'b0000;
end
initial fork
#10 bit = ~rega; // num = 0100
#20 bit = ~regb; // num = 1111
#30 log = !rega; // num = 0
#40 log = !regb; // num = 1
#50 $finish;
join
endmodule
- 逻辑反的结果为一位 1,0 或 x。
- 位反的结果与操作数的位数相同。
- 逻辑反操作符将操作数的逻辑值取反。例如,若操作数为全 0,则其逻辑值为 0,逻辑反操作值为 1。
移位操作符
| >> | 逻辑右移 |
|---|---|
| << | 逻辑左移 |
module shift ();
reg [9: 0] num, num1;
reg [7: 0] rega, regb;
initial rega = 8'b00001100;
initial fork
#10 num <= rega << 5; // num = 01_1000_0000
#10 regb <= rega << 5; // regb = 1000_0000 左移先补后移
#20 num <= rega >> 3; // num = 00_0000_0001 右移先移后补
#20 regb <= rega >> 3; // regb = 0000_0001
#30 num <= 10'b11_1111_0000;
#40 rega <= num << 2; // rega = 1100_0000
#40 num1 <= num << 2; // num1 = 11_1100_0000
#50 rega <= num >> 2; // rega = 1111_1100
#50 num1 <= num >> 2; // num1 = 00_1111_1100
#60 $finish;
join
endmodule
- 移位操作符对其左边的操作数进行向左或向右的位移位操作。
- 第二个操作数(移位位数)是无符号数。
- 若第二个操作数是 x 或 z 则结果为 x。
- “<<” 将左边的操作数左移右边操 作数指定的位数。
- “>>” 将左边的操作数右移右边操 作数指定的位数。
- 在赋值语句中,如果右边(RHS)的结果:
位宽大于左边,则把最高位截去。
位宽小于左边,则零扩展。 - 建议:表达式左右位数一致。
关系操作符
| > | 大于 |
|---|---|
| < | 小于 |
| >= | 大于等于 |
| <= | 小于等于 |
module relationals ();
reg [3: 0] rega, regb, regc;
reg val;
initial begin
rega = 4'b0011;
regb = 4'b1010;
regc = 4'b0x10;
end
initial fork
#10 val = regc > rega ; // val = x rega 和 regc 的关系取决于 x
#20 val = regb < rega ; // val = 0
#30 val = regb >= rega ; // val = 1
#40 val = regb > regc ; // val = 1 无论 x 为何值,regb > regc
#50 $finish;
join
endmodule
- 其结果是 1’b1、1’b0 或 1’bx。
相等操作符
= 赋值操作符,将等式右边表达式的值拷贝到左边。
== 逻辑等

a = 2'b1x;
b = 2'b1x;
if (a == b)
$display(" a is equal to b");
else
$display(" a is not equal to b");
/*
2'b1x == 2'b0x
值为 0,因为不相等
2'b1x == 2'b1x
值为 x,因为可能不相等,也可能相等
*/
=== case等

a = 2'b1x;
b = 2'b1x;
if (a === b)
$display(" a is identical to b");
else
$display(" a is not identical to b");
/*
2'b1x === 2'b0x
值为 0,因为不相同
2'b1x === 2'b1x
值为 1,因为相同
*/
- case等只能用于行为描述,不能用于 RTL 描述。
| == | 逻辑等 |
|---|---|
| != | 逻辑不等 |
module equalities1();
reg [3: 0] rega, regb, regc;
reg val;
initial begin
rega = 4'b0011;
regb = 4'b1010;
regc = 4'b1x10;
end
initial fork
#10 val = rega == regb; // val = 0
#20 val = rega != regc; // val = 1
#30 val = regb != regc; // val = x
#40 val = regc == regc; // val = x
#50 $finish;
join
endmodule
- 其结果是 1’b1、1’b0 或 1’bx。
- 如果左边及右边为确定值并且相等,则结果为 1。
- 如果左边及右边为确定值并且不相等,则结果为 0。
- 如果左边及右边有值不能确定的位,但值确定的位相等,则结果为 x。
- != 的结果与 == 相反。
- 值确定是指所有的位为 0 或 1。不确定值是有值为 x 或 z 的位。
| === | 相同(case等) |
|---|---|
| !== | 不相同(case不等) |
module equalities2();
reg [3: 0] rega, regb, regc;
reg val;
initial begin
rega = 4'b0011;
regb = 4'b1010;
regc = 4'b1x10;
end
initial fork
#10 val = rega === regb; // val = 0
#20 val = rega !== regc; // val = 1
#30 val = regb === regc; // val = 0
#40 val = regc === regc; // val = 1
#50 $finish;
join
endmodule
- 其结果是 1’b1、1’b0 或 1’bx。
- 如果左边及右边的值相同(包括 x、z),则结果为 1。
- 如果左边及右边的值不相同,则结果为 0。
- !== 的结果与 === 相反。
- 综合工具不支持
条件操作符
| ? : | 条件 |
|---|
module likebufif (in, en, out);
input in;
input en;
output out;
assign out = (en == 1) ? in : 'bz;
endmodule
module like4to1 (a, b, c, d, sel, out);
input a, b, c, d;
input [1: 0] sel;
output out;
assign out = sel == 2'b00 ? a :
sel == 2'b01 ? b :
sel == 2'b10 ? c : d;
endmodule

- 如果条件值为x或z,则结果可能为 x 或 z。
条件操作符的语法为:
< LHS > = < condition > ? < true_expression > : < false_expression >
其意思是:if condition is TRUE, then LHS = true_expression, else LHS = false_expression
每个条件操作符必须有三个参数,缺少任何一个都会产生错误。
最后一个操作数作为缺省值。
registger = condition ? true_value : false_value;
上式中,若 condition 为真则 register 等于 true_value;若 condition 为假则 register 等于 false_value。一个很有意思的地方是,如果条件值不确定,且 true_value 和 false_value 不相等,则输出不确定值。
例如:assign out = (sel == 0) ? a : b;
若 sel 为 0 则 out = a;若 sel 为 1 则 out = b。如果 sel 为 x 或 z,若 a = b = 0,则 out = 0;若
a ≠ b,则 out 值不确定。
级联操作符
| { } | 级联 |
|---|
module concatenation;
reg [7: 0] rega, regb, regc, regd;
reg [7: 0] new;
initial begin
rega = 8'b0000_0011;
regb = 8'b0000_0100;
regc = 8'b0001_1000;
regd = 8'b1110_0000;
end
initial fork
#10 new = {regc[4:3], regd[7:5], regb[2], rega[1:0]}; // new = 8'b11111111
#20 $finish;
join
endmodule
- 可以从不同的矢量中选择位并用它们组成一个新的矢量。用于位的重组和矢量构造。
- 在级联和复制时,必须指定位数,否则将产生错误。下面是类似错误的例子:
a[7:0] = {4{´b10}};
b[7:0] = {2{5}};
c[3:0] = {3´b011, ´b0}; - 级联时不限定操作数的数目。在操作符符号 { } 中,用逗号将操作数分开。例如:
{A, B, C, D}
复制操作符
| { { } } | 复制 |
|---|
module replicate ();
reg [3: 0] rega;
reg [1: 0] regb, regc;
reg [7: 0] bus;
initial begin
rega = 4'b1001;
regb = 2'b11;
regc = 2'b00;
end
initial fork
#10 bus <= {4{regb}};
// bus = 11111111. regb is replicated 4 times.
#20 bus <= {{2{regb}}, {2{regc}}};
// bus = 11110000. regc and regb are each replicated, and the resulting vectors are concatenated together
#30 bus <= {{4{rega[1]}}, rega};
// bus = 00001001. rega is sign-extended
#40 $finish;
join
endmodule
- 复制一个变量或在 { } 中的值。
- 前两个 { 符号之间的正整数指定复制次数。
4522

被折叠的 条评论
为什么被折叠?



