引言
Verilog HDL语言的运算符范围很广,其运算符按其功能可分为以下几类:
- 算术运算符(+,-,×,/,%)
- 赋值运算符(=,<=)
- 关系运算符(>,<,>=,<=)
- 逻辑运算符(&&,||,!)
- 条件运算符(?😃
- 位运算符(,|,^,&,^)
- 移位运算符(<<,>>)
- 拼接运算符({ })
- 其它
在Verilog HDL语言中运算符所带的操作数是不同的,按其所带操作数的个数运算符可分为三种: - 单目运算符(unary operator):可以带一个操作数,操作数放在运算符的右边。
- 二目运算符(binary operator):可以带二个操作数,操作数放在运算符的两边。
- 三目运算符(ternary operator):可以带三个操作,这三个操作数用三目运算符分隔开。
见下例:
clock = ~clock; // ~是一个单目取反运算符, clock是操作数。
c = a | b; // 是一个二目按位或运算符, a 和 b是操作数。
r = s ? t : u; // ?: 是一个三目条件运算符, s,t,u是操作数。
verilog运算符及表达式
1、算术运算符
算术运算符 | 作用 |
---|---|
a + b | a 加上b |
a - b | a减去b |
a * b | a乘以b |
a / b | a除以b |
a % b | 求余运算,a除b的余数 |
a ** b | a的b次方 |
仿真例子:
module exam;
reg [7:0] a;
reg [7:0] b;
initial begin
a = 45;
b = 9;
$display ("Add + = %d", a + b);
$display ("Sub - = %d", a - b);
$display ("Mul * = %d", a * b);
$display ("Div / = %d", a / b);
$display ("Mod %% = %d",a % b);
$display ("Pow ** = %d", a ** 2);
end
endmodule
仿真结果:
Add + = 54
Sub - = 36
Mul * = 149
Div / = 5
Mod % = 0
Pow ** = 81
- 注意: 在进行算术运算操作时,如果某一个操作数有不确定的值x,则整个结果也为不定值x
2、关系运算符
关系运算符 | 作用 |
---|---|
a < b | a 小于b |
a > b | a大于b |
a <= b | a小于等于b |
a >= b | a大于大等于b |
a === b | 实例相等,a等于b,包含x和z |
a !== b | 实例不相等,a不等于b,包含x和z |
a == b | 逻辑相等 ,只作用于0/1 |
a != b | 逻辑不相等 ,只作用于0/1 |
“===” 和 ==”的区别:
下面举一个例子说明“==”和“===”的区别。
例:
if(A==1’bx) $display(“AisX”); (当A等于X时,这个语句不执行)
if(A===1’bx) $display(“AisX”); (当A等于X时,这个语句执行)
===对运算符两边的变量相等要求更加严格!!
3、位运算符
位运算符 ( 缩位运算符):& 、| 、~、^ 、^~
两个长度不同的数据进行位运算时,系统会自动的将两者按右端对齐.位数少的操作数会在
相应的高位用0填满,以使两个操作数按位进行操作.
缩位运算符都是单目运算符,一般是将缩位运算符放置在操作数前面,
如 &A、|B、^C、^~D等等,注意千万不要放到后面去
~ :按位取反 a=1001 ~a=0110
& :按位与 a=1001 b=0001 a&b=0001 &a = 1&0&0&1 = 0;&b = 1&0&0&0 = 0
| :按位或 a=1001 b=0001 a|b=1001 |a = 1|0|0|1 = 0;|b = 1|0|0|0 = 0
^ :按位异或 a=1001 b=0001 a^b=1000 ^a = 1^0^0^1 = 0;^b = 1^0|0^0 = 1
^~ :按位同或(异或非) a=1001 b=0001 a^~b=0111 ^~a = ~(^a) = 1; ^~b = ~(b) = 0
4、逻辑运算符
逻辑与 &&(双目运算符) ;逻辑或 || (双目运算符);逻辑非 ! (单目运算符)
&&和||是双目运算符,用在两数之间: A && B 或者 A || B ;&&A 、|| A为非法。
! 是单目运算符,一般用在数字之前 : !A ; A!为非法。
逻辑运算的一个核心就是“ Z = A xx B ”,这里的A、B、Z都只有两个值:True or Fals ;而 true 和 false 在机器中常表示为 1 和 0;
一个为4bit二进制数为4'b0001是为真(True);只有当等于4'b0000是才为假(Fals);
逻辑运算符的关键在于逻辑运算符比较的量不在于值本身,而在于这个值的“真”与“假”
因此,两个不同位宽的变量也可以进行逻辑运算!!
5、条件运算符
条件运算符:?:
属于三目运算符,等价于if else语句
assign a = (b)?4'b1:4'b0; 如果b为真,那么a = 4'b1,否则a = 4'b0
嵌套的条件运算符可以实现多路选择。例如:
wire [1:0]y;
assign y = (a >= 1) ? ;1 (a < 0) ? 2 : 0;//当a>=2时,输出为1;当a<0时,输出为2,其余情况为0.
5、移位运算符
在Verilog HDL中有两种移位运算符:<< (左移位运算符) 和 >>(右移位运算符)。其使用方法如下:a>>n或a<<n,a是操作数,n表示移动几位,这两种移位运算都用0填补移出的空位。
reg [3:0] a,c;
reg [5:0] b;
a = 4'b1001;
b = a<<2; 此时b=6'b100100,原始a=9*4=36;
c = a>>2; 此时c=4'b0010,原始a=9/4=2余1,显示为2;不显示余数
此外,移位运算符也可理解为乘除法,<< (左移位运算符) 可以理解为乘法, >>(右移位运算符)可理解为除法,如左移一位相当于乘2,右移一位相当于除2;但此方法的乘除的数只能是2的倍数。
在实际运算中,经常通过不同移位数的组合来计算简单的乘法和除法。
例如:
实现s1*24,因为24=16+8,所以可以通过s1<<4+s1<<3来实现。
6、拼接运算符
为拼接运算符:{ }
将某些信号的某些位详细地列出来,中间用逗号隔开,最后用一个大括号表示一个整体信号。
a = 4'h1101;
b = 6'h111000;
c = 2'h11;
d = {a[3],b[2:0],c};此时d = 100011
e = {2{b}}; 此时e = {b,b} = 111000111000
f = {a,b,2{a,c}} 此时f = {a,b,a,c,a,c} = 11111100011011111011
在实际工程中,拼接运算受到了广泛使用,特别是在描述移位寄存器时。
例如:
reg [7:0]shiftreg;
always@(posedge clk)begin
shiftreg <= {shiftreg[6:0],data_in};
end
循环左/右移动:
reg [7:0]shiftregleft;
reg [7:0]shiftregright;
always@(posedge clk)begin
shiftregleft <= {shiftregleft[6:0],shiftregleft[7]};//循环左移
shiftregright <= {shiftregright[0],shiftregright[7:1]};//循环右移
end
- 在位拼接表达式中不允许存在没有指明位数的信号。这是因为在计算拼接信号的位宽的大小时必需知道其中每个信号的位宽。
verilog运算符优先级问题
逻辑运算符中"&&“和”||“的优先级别低于关系运算符,”!" 高于算术运算符。见下例:
(a>b)&&(x>y) 可写成: a>b && x>y
(a==b)||(x==y) 可写成:a==b || x==y
(!a)||(a>b) 可写成: !a || a>b
所有的关系运算符有着相同的优先级别。关系运算符的优先级别低于算术运算符的优先级别。见下例:
a < size-1 //这种表达方式等同于下面
a < (size-1) //这种表达方式。
size - ( 1 < a ) //这种表达方式不等同于下面
size - 1 < a //这种表达方式。
从上面的例子可以看出这两种不同运算符的优先级别。当表达式size-(1<a)进行运时,关系表达式先被运算,然后返回结果值0或1被size减去。而当表达式 size-1<a 进行运算时,size先被减去1,然后再同a相比。