赞
踩
本文详细介绍了Verilog常用的运算符和表达式,特别是分享了处理“计算位宽溢出”和“负数”的可行方式,帮助读者更加轻松地理解和掌握Verilog语言的运算符。
算数运算符:加(+)、减(-)、乘(*)、除(/)、取余(%)
赋值运算符:非阻塞赋值(=)、阻塞赋值(<=);
关系运算符:大于(>)、小于(<)、等于(==)、不等于(!=)、大于等于(>=)、小于等于(<=)
逻辑运算符:与(&&)、或(||)、非(!);
条件运算符:(?:);
位运算符 : 取反(~)、或(|)、异或(^)、与(&);
移位运算符:左移(<<)、右移(>>);
拼接运算符:位拼接({}),复制{n{b}};
加(+)、减(-)、乘(*)、除(/)、取余(%)
- +:加法运算或者正值运算,a+b、+a
- — :减法运算或者负值运算:a—b、—a
- * :乘法运算:a*b
- / :除法运算:a/b,b不能等于0
- % :求余运算:a%b,%两侧的数据必须为整型数据,b不能等于0
非阻塞赋值(=)常用于组合逻辑,例如assign语句和always@(*)语句块。
- wire [5:0] data0;
- reg [6:0] data1;
-
- assign data0 = 'd6;
- always@(*) begin
- data1 = 'd10;
- end
阻塞赋值(<=)常用于时序逻辑,例如always@(posedge clk)语句块。
- reg [6:0] data1;
-
- always@(posedge clk) begin
- data1 <= 'd10;
- end
大于(>)、小于(<)、等于(==)
不等于(!=)、大于等于(>=)、小于等于(<=)
- a < b :a小于b
- a > b :a大于b
- a == b :a等于b
- a != b :a不等于b
- a <= b :a小于或等于b
- a >= b :a大于或等于b
(1)与(&&)
逻辑与:a&&b,a和b同时为真时才为真,否则为假
(2)或(||)
逻辑或:a||b,a和b同时为假时才为假,否则为真
(3)非(!)
a为真时,!a为假
条件表达式的值为真或假,如果为真,返回值1,否则返回值2。它主要用于简化if-else语句的书写和提高代码的可读性。
条件表达式 ? 值1 : 值2
assign a = (b) ? 'b1 : 'b0; 如果b为真,那么a = 'b1,否则a = 'b0。
(1)与(&)
对两个数的二进制形式进行“与”运算,只有两个相应位的值都为1时,结果才为1。
(2)或(|)
对两个数的二进制形式进行“或”运算,只要有一个相应位的值为1,结果就为1。
(3)异或(^)
对两个数的二进制形式进行“异或”运算,当两个相应位的值不同时,结果为1,否则为0。
(4)取反(~)
对一个数的二进制形式进行取反操作,即0变为1,1变为0。
- ~ :按位取反 a=1001 ~a=0110
- & :按位与 a=1001 b=0011 a&b=0001
- | :按位或 a=1001 b=0101 a|b=1101
- ^ :按位异或 a=1001 b=0101 a^b=1100
在Verilog中有两种移位运算符:<< (左移位运算符) 和 >>(右移位运算符)。其使用方法如下:a>>n或a<<n,a是操作数,n表示移动几位,这两种移位运算都用0填补移出的空位。
- reg [5:0] a,c;
- reg [7:0] b;
- a = 6'b101001;
- b = a<<2; 此时b=8'b10100100
- c = a>>2; 此时c=6'b1010
位拼接运算符可以把两个或多个信号的某些位拼接起来进行运算操作,或者把单个信号复制多份。其使用方法如下:
- wire [5:0] a, b;
- wire [1:0] c
- wire [4:0] d;
- wire [11:0] e;
-
- assign a = 6'b101101;
- assign b = 6'h111000;
- assign c = 2'h11;
- assign d = {a[5],b[2:0],c};//即d = 100011
- assign e = {2{b}}; //即e = {b,b} = 111000111000
-
-
- wire aa, bb, cc, dd;
- assign {aa, bb, cc, dd} = 4'b1011;
- //即 aa = 1,bb = 0,cc = 1,dd = 1;
加法和乘法的计算结果需要扩展位宽,如果定义的结果变量位宽未做扩展,则计算结果将丢失最高位,导致结果异常。
简单处理办法:结果赋值的寄存器或wire的位宽引入进位即可。
module test ( input clk, output reg [7:0] a,c,d, output reg [8:0] b ); reg [7:0] d0= 8'd145, d1= 8'd128; always @ (posedge clk) begin a <= d0+ d1; b <= d0+ d1; c <= (d0+ d1) >> 1; d <= (d0+ d1 + 0) >> 1; end endmodule
说明:
a <= d0+ d1,表达式中最大位宽是8bit,因此运算结果丢掉了进位,得到17;
b <= d0+ d1,整个表达式中最大位宽是9bit,因此运算结果保留了进位,得到273
c <= (d0+ d1) >> 1 ,表达式中最大位宽只有8bit,因此d0+ d1的中间结果也是8bit(丢掉进位后的17),这样不能起到保留最高有效位的效果。
d <= (d0+ d1+ 0) >> 1,表达式中多了一个未声明位宽的常数0,其默认位宽为32bit,这样加法的中间结果便不会丢掉进位。
表达式中如果有一个操作数是“负数”,整个表达式的运算需要特别考虑,其实处理起来也很简单。
(1)如果只涉及到加法和减法,负数与表达式中最大操作数的位宽必须保持一致,如下处理:
- reg [8:0] a = -128;
- reg [9:0] b = 512;
- reg [9:0] c;
- reg [10:0] d;
-
- assign c = {a[8], a} + b;
- assign d = {{2{a[8]}}, a} - {a[9], a}};
(2)如果涉及乘法,则将负数转换为绝对值与符号位。
- reg [8:0] a = -128;
- reg [9:0] b = 512;
- reg [17:0] c_abs;
- reg [18:0] c;
- reg a_sign;
- reg [7:0] a_abs;
-
- assign a_sign = a[8];
- assign a_abs = a[8] ? (~a[7:0] + 1'b1) : a[7:0];
- assign c_abs = a_abs*b;
- assign c = a_sign ? (~{1'b0, c_abs} + 1'b1') : {1'b0, c_abs};
本文将不断定期更新中,关注,收藏,不走丢哦
有任何问题,都可以在评论区和我交流哦
本文由FPGA入门到精通原创,公众号为“FPGA入门到精通”,github开源代码:“FPGA知识库”
您的支持是我持续创作的最大动力!如果本文对您有帮助,还请多多点赞、评论和收藏。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。