FPGA学习verilog基础运算符

verilog基础运算符

在编写程序之前,我们先学习Verilog语法知识,我们之前写的程序用到了运算符,例如我们用Verilog描述1个非门,我们就用到了 取反运算符‘~’,我们写求和模块用到了求和运算符’+’ , 那还有没有别的运算符呢?这里我们要拓展这方面的知识。在实际项目中边学边练是最好的方式。

Verilog HDL语言的运算符范围应用很广,其运算符按照功能可分为以下几类:
(1)算术运算符( + , - , *, /, %)
(2)赋值运算符 ( = , <=)
(3)关系运算符 (>, <, >=, <= )
(4)逻辑运算符 (&&, ||, ! )
(5)条件运算符 ( ?: )
(6)位运算符 (~, |, ^, &, ~^)
(7)移位运算符 ( <<, >> )
(8)拼接运算符( {} )
(9)缩减运算符 / 归约运算符(|, ^, &, ~^)

在Verilog HDL 语言中运算符所能带的操作数是不同的,按照运算符所带的操作数的个数,运算符可分为3种。
(1)单目运算符:可以带1个操作数,操作数放在运算符的右边。
(2)双目运算符:可以带2个操作数,操作数放在运算符的两边。
(3)三目运算符:可以带3个操作数,

示例:
assign OUT = ~A; // 这个语句是将A取反并赋值给OUT, ‘~’就是一个取反运算符,’A’是1个被这个运算符操作的数,被操作的只有1个, 因此’~’是1个单目运算符。

assign OUT = A + B;// ’+’是加法运算符,它能让两个数相加,因此’+’是双目运算符

assign r = s ? t:u ; // ?: 是三目运算符, s, t, u是操作数,这条语句的意思是当s成立时,将t赋给r, 当s不成立时,将u赋值给r,?:是条件运算符,因此我们就知道了’?:’运算符是可以实现选择的功能。

基本的算术运算符

在Verilog HDL语言中,共有下面几种:
(1)+ (加法运算符)
示例:assign Y = A + B ; //将A与B相加,计算结果赋值给Y
(2)- (减法运算符)
示例:assign Y = A - B; //将A的值减去B的值,计算结果赋值给Y
(3)* (乘法运算符)
示例:assign Y = A * B;//将A与B乘积的结果赋值给Y
(4)/ (除法运算符)
示例:assign Y = A / B; //将变量A的值除以B结果赋值给Y
(5)% (模运算符, 或者称为求余运算符,要求%两侧均为整型数据,例如7%3的值为1)

位运算符

Verilog HDL作为一种硬件描述语言,是针对硬件电路而言的,在硬件电路中信号有4种状态值,即:0 1 x z 在电路中信号进行与、或、非运算时,反应在Verilog HDL中则是相应的操作数的位运算, Verilog提供了以下5种位运算符。

(1)~ //取反
(2)& //按位与操作
(3)| //按位或
(4)^ //按位异或
(5)^~ //按位同或(异或非)

说明:位运算符中除了~是单目运算符之外,其他均为双目运算符,即要求运算符两边各有1个操作数。

示例说明:
(1)取反运算符 ~ :
assign Y = ~A;//若A = 4’b1011; 则Y的值为4’b0100, 即按照每个bit位进行取反操作。

(3)按位与操作 & :
assign Y = A & B; //若A的值为4’b1011, B的值为4’b0101, 则Y的值为4’b0001

(4)按位或操作 | :
assign Y = A | B; //若A的值为4’b1011, B的值为4’b0101, 则Y的值为4’b1111

(5)按位异或 ^ :
assign Y = A ^ B;//若A的值为4’b1011, B的值为4’b0101, 则Y的值为4’b1110

(6)按位同或 ^~
assign Y = A ^~ B;//若A的值为4’b1011, B的值为4’b0101, 则Y的值为4’b0001

关系运算符

Verilog HDL语法中表示关系运算的有:大于(>); 小于(<); 大于等于(>=); 小于等于(<=)
程序示例:
大于(>):
Y = (a>b) ? 8’d0:8’d1; //如果a的值大于b, 则将8’d0赋值给Y, 否则将8’d1赋值给Y
Y = (a>b) ? c:d; //如果a的值大于b,则将变量c的值赋给Y,否则将变量d的值赋给Y

小于(<):
Y = (a<b) ? 8’d0:8’d1; //如果a的值小于b, 则将8’d0赋值给Y, 否则将8’d1赋值给Y
Y = (a<b) ? c:d; //如果a的值小于b,则将变量c的值赋给Y,否则将变量d的值赋给Y

大于等于(>=):
Y = (a>=b) ? 8’d0:8’d1; //如果a的值大于等于b, 则将8’d0赋值给Y, 否则将8’d1赋值给Y
Y = (a>=b) ? c:d; //如果a的值大于等于b,则将变量c的值赋给Y,否则将变量d的值赋给Y

小于等于(<=):
Y = (a<=b) ? 8’d0:8’d1; //如果a的值小于等于b, 则将8’d0赋值给Y, 否则将8’d1赋值给Y
Y = (a<=b) ? c:d; //如果a的值小于等于b,则将变量c的值赋给Y,否则将变量d的值赋给Y

逻辑运算符

Verilog HDL语法中的逻辑运算符有 逻辑与(&&), 逻辑或(||), 逻辑非(!)
程序示例

逻辑与 && 用法:
//当a>b并且c>d都成立的时候,将1’b0赋值给Y, 否则将1’b1赋值给Y, 我们可以看出逻辑与在这里表示2个条件都成立,例如,有车 && 有房 才能找到媳妇
assign Y = ((a>b) && (c>d))? 1’b0 : 1’b1 ;

逻辑或 || 用法:
//当a>b或者c>d成立,将1’b0赋值给Y, 否则(这2个条件都不成立)将1’b1赋值给Y, 例如,有车 || 有房 才能找到媳妇
assign Y = ((a>b) || (c>d))? 1’b0 : 1’b1 ;

逻辑非 !的用法
//当a<b不成立的时候,将1’b1赋给Y, 否则将1’b0赋给Y
// !(银行卡里低于5000) 等价于 (余额大于等于5000)
assign Y = (!(a<b)) ? 1’b1 : 1’b0;

条件运算符

如果在条件语句中,只执行单个的赋值语句时,用条件表达式会更方便。条件运算符
为“ ? : ”,它是一个三元运算符,即有三个参与运算的量。
由条件运算符组成的条件表达式的一般形式为:表达式 1 ? 表达式 2 : 表达式 3
执行过程是:当表达式 1 为真,则表达式 2 作为条件表达式的值,否则以表达式 3 作
为条件表达式的值。例如:当 a = 6, b = 7,条件表达式(a > b) ? a : b 的结果为 7。
注意:
(1) 使用条件表达式时“?”和“:”是一对,不可以只是用一个;
(2) 条件运算符从右向左结合,例如:
a > b ? a : c > d ? c : d
等价于
a > b ? a : (c > d ? c : d)
虽然后面要讲到的 if-else 也可以实现这种功能,但是 if-else 只能在 always 块中使用,
不能在 assign 中使用,如果我们想在 assign 中使用就需要用到条件运算符。

移位运算符

移位运算符是二元运算符,左移符号为“<<”,右移符号为“>>”,将运算符左边的
操作数左移或右移指定的位数,用 0 来补充空闲位。如果右边操作数的值为 x 或 z,则移位结果为未知数 x。在应用以为运算符的时候一定要注意它的这个特性,那就是空闲位用 0来填充,也就是说,一个二进制数不管原数值是多少,只要一直移位,最终全部会变为0。例如:4’b1000 >> 3 后的结果为 4’b0001,4’b1000 >> 4 的结果为 4’b0000。

移位运算符在使用时,左移一位可以看成是乘以 2,右移一位可以看成是除以 2。所以
移位运算符用在计算中,代替乘法和除法。尤其是除法,使用移位的方式,可以节省资
源。但使用的前提是数据位宽要进行拓展,否则就会出现移位后全为 0 的情况。

在Verilog HDL中有2种移位运算符, 左移运算符 << , 右移运算符 >> ,其使用方法如下:

a >> n //表示将变量a右移n位
a <<n //表示将变量a左移n位

代码示例:
若A = 4’b0010, 变量A的值换算成十进制为4’d2。 Y的位宽为4,

Y = (A<<1); //此时Y的值为4’b0100, 此时Y的值换算成十进制为4’d4
Y = (A<<2);//此时Y的值为4’b1000, 此时Y的值换算成十进制为4’d8
Y = (A<<3);//此时Y的值为4’b0000, 此时Y的值换算成十进制为4’d0,如果将Y的位宽改成8位,则此时Y的值为8’d16

Y = (A>>1); //此时Y的值为4’b0001,此时Y的值换算成十进制为4’d1

结论:
(1)左移1位,结果是原来的2倍
(2)左移2位,结果是原来的2*2倍,
(3)左移3位,结果是原来的2*2*2倍,以此类推。
(4)在编写程序的时候如果需要将1个数乘以2倍,4倍,8倍…。可以使用移位运算符(左移运算符);如果需要将1个数除以2倍,4倍,8倍…。可以使用右移运算符
(5)注意移位后的结果需要使用位宽足够的变量来表示

拼接运算符

在Verilog HDL语言中有1个特殊的运算符:位拼接运算符 {} ,用这个运算符可以把两个或者是多个信号的某些位拼接起来进行运算操作。其使用方法如下:

{信号1的某几位,信号2的某几位,…, …, 信号n的某几位}

即把某些信号的某些位详细地列出来,中间必须用逗号分开,最后用大括号括起来表示1个整体信号。 B[3:0] B[2:1]=01

在这里插入图片描述
作用:
1、 实现增长位宽的作用
如果需要将 8bit 的 a、3bit 的 b、5bit 的按顺序拼接成一个 16 位的 d,表示方法为:
wire [15:0] d;
d = {a, b, c};
2、 实现移位的作用
din 是 1bit 的串行数据,假如刚开始传来的数据是 1,后面的数据都是 0,则第一个时
钟时 4bit dout 的值为 4’b1000,第二个时钟时 dout 的高三位放到最后,新来的 0 放到 dout的最高位,变为 4’b0100,从而实现了数据的右移功能。

always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
dout <= 4'b0;
else
dout <= {din, dout[3:1]}; //右移

左移同理,din 是 1bit 的串行数据,假如刚开始传来的数据是 1,后面的数据都是 0,
则第一个时钟时 4bit dout 的值为 4’b0001,第二个时钟时 dout 的低三位放到最前面,新来的 0 放到 dout 的最低位,变为 4’b0010,从而实现了数据的左移功能。

always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
dout <= 4'b0;
else
dout <= {dout[2:0], din}; //左移

缩减运算符/归约运算符

缩减运算符(reduction operator)是单目运算符,也有与、或、非运算。
其与、或、非运算规则类似于位运算符的与、或、非运算规则,但其运算过程不同。位运算是对操作数的相应位进行与、或、非运算,操作数是几位数则运算结果也是几位数。而缩减运算则不同,缩减运算是对单个操作数进行或、与、非递推运算,最后的运算结果是1位的二进制数。缩减运算的具体运算过程是这样的:第一步先将操作数的第1位与第2位进行或、与、非运算;第二步将运算结果与第3位进行或、与、非运算,依次类推,直至最后1位。

例如:
reg [3:0] B;
reg C;
C=&B;
B = 4’b1011
相当于:
C =( (B[0]&.B[1]) & B[2]) & B[3];
&B == 1 B==4’b1111
缩减运算的与、或、非运算规则类似于位运算符与、或非运算规则。

优先级

总的优先级关系为:归约运算符 > 算数运算符 > 移位运算符 > 关系运算符 > “= =”
和“!=”> 按位运算符 > “&&”和“||”> 条件运算符,总的来说是一元运算符 > 二元运
算符 > 三元运算符。
如果在编写代码的时候对这些关系容易混淆,最好的方式就是使用“( )”增加优先
级。

  • 4
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值