Verilog 操作符

操作符类型

下表以优先级顺序列出了 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
Ior
^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
Ior
^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 && &regb; // val = 1
		$finish;
	join
endmodule
  • 归约操作符的操作数只有一个。
  • 对操作数的所有位进行位操作。
  • 结果只有一位,可以是 0, 1, x。

逻辑操作符

not
&&and
IIor
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
  • 复制一个变量或在 { } 中的值。
  • 前两个 { 符号之间的正整数指定复制次数。
### Verilog 中按位操作符与逻辑操作符的区别 在 Verilog 中,按位操作符和逻辑操作符虽然名称相似,但在功能上存在显著差异。 #### 操作对象不同 - **按位操作符**作用于每一位数据独立执行相应的运算。例如 `A & B` 将 A 和 B 的对应二进制位分别做 AND 运算[^1]。 - **逻辑操作符**则用于处理整个表达式的真假判断,通常返回单一的真 (1) 或假 (0),适用于条件语句控制流程[^2]。 #### 返回值类型各异 对于相同的操作数: - 若采用按位与 (`&`) ,当两个多位信号逐位比较时,只要某一位均为高电平,则该位置结果为 1;反之为 0 。这会产生一个多比特宽度的结果向量[^4]。 - 而使用逻辑与(`&&`) 只要任意一方整体非零即视为 true(1), 整体都为零才判定为 false(0)[^3]。 #### 应用实例展示 下面给出一段简单的代码来直观感受两者的差别: ```verilog module testbench; reg [7:0] a = 8'b1010_1010, b = 8'b1111_0000; initial begin $display("a=%b,b=%b",a,b); // 按位与(&) $display("Bitwise and result:%b",(a & b)); // 逻辑与(&&) if(a && b) $display("Logical and is True"); else $display("Logical and is False"); #10 $finish; end endmodule ``` 这段程序会打印出如下信息: ``` a=10101010,b=11110000 Bitwise and result:10100000 Logical and is True ``` 可以看到,在此例子中由于变量'a'和'b'都不是全零所以逻辑与的结果为True;而按位与则是按照各自对应的位进行AND操作得到新的八位二进制串作为输出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值