文章简介
本系列文章主要针对FPGA初学者编写,包括FPGA的模块书写、基础语法、状态机、RAM、UART、SPI、VGA、以及功能验证等。将每一个知识点作为一个章节进行讲解,旨在更快速的提升初学者在FPGA开发方面的能力,每一个章节中都有针对性的代码书写以及代码的讲解,可作为读者参考。
第六章:运算符号
Verilog HDL 中的运算符号基本和 c 语言中的运算符号相同,本章讲解常用的几种运算符。
算数运算符(+、-、x、\、%)是非常熟悉的运算符,只拿%作介绍。在测试文件中我们有时候会想要产生 0~N 之间的数据,那么就可以用求余加上随机函数得到,假设我们实现 0~9 之间的随机数,我们可以按照如下代码示例所示实现。
代码示例 1:
reg [3:0] a;
always #5 a = {$random}%10;
代码解析 1:
① 第 1 行定义一个能表示 0 到 15 的变量;
② 第 2 行对随机数取 10 的余数,得到的值为 0~9。
关系运算符有(>、<、>=、<=、==、!=),关系运算符得到的结果要么为真(1)要么为假(0)。但是在运用中很多人会犯一些错误,比如 b 的结果根据 a 是否在 5~9 来决定,现有如下两种代码示例情况。
代码示例 2:
代码解析 2:
①当 a=2 时,(1)中可写成 5<2<9,此时 5<2 的结果为假(0),2<9 的结果为真(1),所以此时 b=1;同理可知无论 a 为任何值,b 均为 1。所以这种 写法虽然语法无错误,但是实现不了我们想要的功能。
②当 a=2 时,(2)中可写成 5<2&&2<9,此时此时 5<2 的结果为假(0), 2<9 的结果为假(0),假(0)与(&)假(0)的结果为假(0),所以此时 b=0。此种写法才能满足我们的逻辑功能。
逻辑运算符(&&、||、!)运算的结果只有真(1)和假(0)。对于&&来 说,运算的两个数据有一个为 0,其结果就为 0,否则为 1。对于||来说,只有 运算的两个数据都有 0 时,其结果才为 0,否则为 1。任何数据取 !,逻辑结果则取反。具体举例如下所示。
代码示例 3:
wire[1:0] a;
wire[2:0] b;
assign c = a && b;
assign c = a || b;
assign c = ! a;
代码解析 3:
①第 1、2 行定义两个变量,假设 a=2,b=3;
②第 3 行求 a&&b 的结果,由于 a、b 都不为 0,所以运算结果为 1;
③第 4 行求 a||b 的结果,由于 a、b 不同时为 0,所以运算结果为 1;
④第 5 行求!a 的结果,由于 a 不为 0,所以运算结果为 1。
位运算符(&、|、~)是按照运行数据的每一位分别进行运算的。
对于 & 来说,运算的两个数据的对应位进行相与,结果为每一位相与的值。
对于 | 来说, 运算的两个数据的对应位进行相或,结果为每一位相或的值。
对于 ~ 来说,是将参与运算的数据按位取反。需要注意按位运算是需要将参与运算的数据转变成二进制,然后再运算。举例如下所示。
代码示例 4:
wire[1:0] a = 2'b10;
wire[2:0] b = 3'd3;
assign c = a & b;
assign c = a | b;
assign c = ~ a;
assign c = & a;
代码解析 4:
①第 1、2 行定义两个赋有初始值的变量;
②第 3 行实现 a & b,此时需要将 a 和 b 都转换成二进制,a=2’b10,b=3’b011, 此 时 a 和 b 的 位 宽 不 一 样 , 位 宽 少 的 需 要 在 高 位 补 0 , 最 后 运 算 为 3’b010 & 3’b011 = 3’b010;
③第 4 行实现 a | b,此时需要将 a 和 b 都转换成二进制,a=2’b10,b=3’b011, 此 时 a 和 b 的 位 宽 不 一 样 , 位 宽 少 的 在 高 位 补 0 , 最 后 运 算 为 3’b010 | 3’b011 = 3’b011;
④第5行实现 ~ a,最后运算为~2’b10 =2’b01;
⑤第6行实现&a,最后运算为 a[1]&a[0]=1&0=0。
条件运算符(()?:),assign 语句后面只能跟一条语句,有时候可能会需要在条件不一样时对某变量赋不同的值,所以用条件运算符可以很方便的满足该要求, 示例如下。
代码示例 5:
assign a = (b>6) ? 1'b1 : 1'b0 ;
代码解析 5:
当 b 大于 6 为真时将顿号前面的值(1'b1)赋值给 a,否则将顿号后面的值(1'b0)赋值给 a。
赋值运算符(=、<=),阻塞赋值运算符(=)用在组合逻辑中,非阻塞赋值运算符(<=)用在时序逻辑中,非阻塞赋值运算符与小于等于号比较像,但是非阻塞赋值运算符是赋值号,小于等于号是判断符,所以非常好区分。
移位运算符(>>、<<),>>为右移运算符,每次右移一位,数据的高位补 0;<<为左移运算符,每次左移一位,数据的低位补 0。示例如下所示。
代码示例 6:
reg[3:0] a = 4'b0110;
always @ (posedge clk)
b <= a >> 1'b1;
always @ (posedge clk)
c <= a << 1'b1;
代码分析 6:
①第 1 行定义一个寄存器变量 a,其值为 4’b0110;
②第 2、3 行描述了将 a 右移一位赋值给 b,当遇到 clk 沿时,b=4’b0011;
③第 4、5 行描述了将 a 左移一位赋值给 c,当遇到 clk 沿时,c=4’b1100。
位拼接运算符({})可以将不同数据的位拼接成一个新的数据,示例如下所示。
代码示例 7:
reg[3:0] a= 4'b0110;
reg[4:0] b= 5'b10110;
always @ (posedge clk)
c <= { b[1], a[1:0], b[3], b[1] };
代码解析 7:
①第 1、2 行定义了 a、b 两个 reg 型变量,值分别为 4’b0110、 5’b10110;
②第 3、4 行描述了将 a、b 不同的位拼接成一个新的变量 c,结果 c = 5’b11001。
在第七章中将对Verilog HDL 中的判断语句进行讲解。
FPGA入门系列1--模块书写&电路综合
FPGA入门系列2--仿真验证
FPGA入门系列3--wire与reg
FPGA入门系列4--赋值语句