FPGA开发:Verilog基础语法
逻辑值
- 逻辑0:逻辑低电平,条件为假;
- 逻辑1:逻辑高电平,条件为真;
- 逻辑 X:未知逻辑电平,可能是高电平,也可能是低电平;
- 逻辑 Z:表示高阻态,外部没有激励信号(无驱动),是一个悬空状态。
关于数字的表示
Verilog数字进制格式包括二进制('b)、八进制('o)、十进制('d)和十六进制('h)。
一般常用的二进制、十进制和十六进制。
数字表达的方式具体如下:
- 1、[位宽][进制][数字],这是一种全面的描述方式。
- 2、[进制][数字],位宽默认为至少32位,具体取决于机器系统。
- 3、[数字],默认采用十进制。
【注意】位宽是指转换为二进制后的位宽,例如8'ha2, 代表位宽为8位的十六进制数。
【注意】可用下划线"_"来分割开数字的表达,以提高程序的可读性。但不能用在进制与数字之间。
- 16'b1010_1011_1100_1111,合法的格式
- 16'b_1010_1011_1100_1111,非法的格式
- 关于x和z在数字中的表达
一个x可以用来表示十六进制中的4位或八进制中的3位或二进制中的1位的值是不确定的。同理,一个z可以用来表示十六进制中的4位或八进制中的3位或二进制中的1位的值是高阻态的,z的另一种表示方式为"?"。
- 4'b10x0 宽为4的二进制数,第3位为不定值;
- 4'b10z0 宽为4的二进制数,第3位为高阻态;
- 4'bz 宽为4的二进制数,其值为不定值;
- 4'b? 宽为4的二进制数,其值为不定值;
- 8'bax 宽为8的十六进制数,其低4位为不定值;
标识符
标识符(identifier)就是模块名、端口名、信号名等,可以类比为软件语言中各个变量、函数的名称(说白了就是取名字)。Verilog对命名标识符的过程做出了如下规定(必须遵守):
- 1、标识符可以是任意一组字母、数字、$(dollar符号)和_(下划线)符号的组合。
- 2、标识符的第一个字符必须是字母或者下划线。
- 3、标识符是区分大小写的。
参数型常量
在程序运行过程中,其值不能被改变的量称之为常量。在Verilog HDL中用"parameter"来定义一个标识符代表常量,称之为符号常量,即标识符形式的常量。
parameter型数据是一种常数型数据,格式如下:
- parameter 参数名1=表达式,参数名2=表达式,.....
例如:
parameter a=1; //定义参数a为常量7
parameter b=2,c=3; //定义两个常数参数
parameter a=1,b=a+1; //用表达式赋值
变量
变量是一种在程序运行过程中其值可以被改变的量,在Verilog HDL中变量的数据类型有很多种。
1、reg型
寄存器是数据存储单元的抽象,寄存器数据类型的关键字是reg。通过赋值语句可改变寄存器存储的值。
格式如下:
- 1、reg[n:1] 数据名1,数据名2,....数据名i;
- 2、reg[n-1:0] 数据名1,数据名2,....数据名i;
reg类型的数据只能在always语句和initial语句(较少)中被赋值,默认初始值为不定值x。值得注意的是,reg型变量并不对应物理(现实)上的寄存器,而是用于在仿真的过程中存储和更新数据。
【注意】若always块带有时钟信号(时序逻辑),则该寄存器变量对应为触发器;若always块不带有时钟信号(组合逻辑),则该寄存器变量对应为硬件连线。
2、wire型
wire类型表示模块之间的物理连接,所以线网类型的变量不能储存值,它的值是由驱动它的元件所决定的,且一旦有变化就会立即变化(组合逻辑)。若没有元件驱动到wire型信号上,则默认为高阻值z。
格式如下:
- 1、wire [n:1] 数据名1,数据名2,...,数据名i;
- 2、wire [n-1:0] 数据名1,数据名2,...,数据名i;
赋值
1、阻塞式赋值"="
可以理解为按顺序执行赋值。
假如我们声明3个变量a、b、c,其值如下:
a=1;
b=2;
c=3;
将其进行阻塞式赋值:
begin
a=b;
c=a;
end
则最后结果为:
a=2;
b=2;
c=2;
2、非阻塞式赋值"<="
对于非阻塞赋值,其里面的语句是并行执行的。
假如我们声明3个变量a、b、c,其值如下:
a=1;
b=2;
c=3;
将其进行阻塞式赋值:
begin
a<=b;
c<=a; //这两条语句是同时执行的
end
则最后结果为:
a=2;
b=2;
c=1;
运算符
1、算术运算符
在Verilog语言中,算术运算符又被称为二进制运算符,如下:
+ | 加法运算符 / 正值运算符 |
- | 减法运算符 / 负值运算符 |
× | 乘法运算符 |
/ | 除法运算符 |
% | 模运算符,或称为求余运算符,要求%两边均为整型 |
【注意】在进行整数的除法运算时,其结果会略去小数部分,只取整数部分。
【注意】在进行算术运算操作时,有一个操作数为不定值x,则整个结果也为不定值x。
【注意】在进行取模运算时,若考虑正数与负数,其结果的值的正负与模运算式里第一个操作数的正负相同。例如:
- 10%3 ---> 1 //余数为1
- -10%3 ---> -1 //余数为-1
- 10%-3 ---> 1 //余数为1
- 10%5 ---> 0 //余数为0,说明没有余数
2、位运算符
~ | 取反 |
& | 按位与 |
| | 按位或 |
^ | 按位异或 |
^~ | 按位同或 |
【注意】不同长度的数据进行按位运算时,系统会自动地将两者的右端对齐,位数少的操作数会在相应的高位用0填满。
该部分的运算与C语言基础里的位运算相同,此处不做赘述。
3、逻辑运算符
&& | 逻辑与 |
|| | 逻辑或 |
! | 逻辑非 |
其运算如下:
a | b | !a | !b | a&&b | a||b |
真 | 真 | 假 | 假 | 真 | 真 |
真 | 假 | 假 | 真 | 假 | 真 |
假 | 真 | 真 | 假 | 假 | 真 |
假 | 假 | 真 | 真 | 假 | 假 |
4、关系运算符
a<b | a小于b |
a>b | a大于b |
a<=b | a小于或等于b |
a>=b | a大于或等于b |
【注意】进行关系运算时,会有返回值:其声明的关系为假,返回值为0;声明关系为真,则返回1。
5、等式运算符
等于 | 不等于 | ||
== | === | != | !== |
对于 "==" 和 "!=" ,如果当操作数中包含x或z时,其运算的返回值均为x。而对于"==="和"!===",可将x和z也看作操作数,如下:
- 1===x,返回值为0;
- x===x,返回值为1;
- 1==x,返回值为x;
- x==x,返回值为x;
6、移位运算符
a << n | 左移位运算符 |
a >> n | 右移位运算符 |
其中a代表要进行移位的操作数,n代表要移位几位。且均使用0来填补移出的空位。例如:1001>>1,得到0100。
7、位拼接运算符
在Verilog语言中,用这个运算符可以将两个或多个信号的某些位拼接起来,形成一个新的信号,来进行位运算。使用格式如下:
- {信号1的某几位,信号2的某几位,...,信号n的某几位}
- 重复法:例如{4{w}},相当于{w,w,w,w}
- 嵌套法:例如{1,{3{0,1}}},相当于{1,0,1,0,1}