软件版本:无
操作系统:WIN10 64bit
硬件平台:适用所有系列FPGA
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!
1概述
本节主要讲解Verilog的数据类型和表达式。
2数据类型
Verilog中主要有两种数据类型:变量(variable)和线网(net)。这两种数据类型主要区别在于它们的赋值(assign)和保持(hold)方式,它们代表了不同的硬件结构。
2.1 线网(net)
线网(net)用于表示结构体(如逻辑门)之间的连接。除了trireg之外,所有其他的线网类型都不能保存值,线网的值是由driver决定的,例如由连续赋值驱动或者由逻辑门驱动。如果driver没有驱动线网,那么线网的值是z,但是tri0、tri1、trireg除外,tri0将是0,tri1将是1,而trireg将保持之前driver驱动的值。
wire线网,仅建立连接,而没有逻辑行为或功能,用于逻辑门的驱动或者连续赋值的驱动。例:
wire [15:0] input_net;
wire reg_flag;
wire是最常用的线网,当然还存在其他的线网。比如:
当多个驱动源驱动同一根线的线网,各真值表如下所示:
2.2 reg寄存器
数据类型reg寄存器是硬件存储单元的一种抽象模型,但它并不直接与物理存储器直接对应。一个reg变量有一个默认的初始值x。寄存器变量的默认大小是一个比特。例:
reg [7:0] reg_ff;//八比特的寄存器变量
reg flag; //单比特寄存器变量
2.3 integer整数
数据类型integer支持过程赋值语句中的数值计算。整数可用来表示主机的字长。负整数是用补码的形式存储,而且integer变量默认值为0。integer类型也是一种寄存器数据类型。
Verilog运算符是以补码算术形式在整数上进行运算,并且最高位是表示值的符号。例:
wire [15:0] data_out; //十六比特的寄存器变量
reg [15:0] data_reg; //十六比特的寄存器变量
integer i;
always@(*)
begin
for(i=0;i<15;i=i+1) //循环15次
begin
data_reg[i] = data_out[15 - i]; //依次赋值
end
end
2.4 real实数
实数用关键字 real 来声明,是用双精度存储,典型的一个64位值,也可用十进制或科学计数法来表示。实数默认值为 0。不能把实数类型的变量连接在模块的端口上,如果将一个实数赋值给一个整数,则只有实数的整数部分会赋值给整数。例:
real data;
integer data_reg;
initial begin
data = 30.5; //赋值
end
initial begin
data_reg = data; //赋值
end
data_reg等于30。
2.5 time时间
数据类型time支持Verilog模型程序中关于时间的计算,time变量存储为无符号64位的量值。可以使用系统函数$time获取当前仿真时间。例:
time first_time;
initial begin
#1000;
first_time = $time; //获取仿真时间
end
2.6 数组
reg类型的一维数组称为存储器,可以理解为数组。这种构造是寄存器变量声明的扩展,用来提供存储器,比如相同字长的多个可寻址的单元。
数组维数没有限制。线网数组也可以用于连接实例模块的端口。数组中的每个元素都可以作为一个标量或者向量,以同样的方式来使用,形如:<数组名>[<下标>]。对于多维数组来讲,用户需要说明其每一维的索引。例:
integer data_1[7:0];
reg [3:0] data_2[3:0];
wire [7:0] data_3[3:0];
wire data_4[6:0][5:0];
reg [31:0] data_5[1:0][5:0][8:0][15:0];
2.7 字符串
对于字符串,Verilog没有专门的数据类型对应。一个字符串必须通过一条过程赋值语句存入一个大小合适的寄存器中。一个大小合适的寄存器数组为要保存的字符串的每个字符留有8个比特的存储空间。例:
reg [8*num_char-1:0] string; //预留8比特的数据
这个例子表明num_char个字符中的每一个字符都用8个比特来存储编码。如果“hello”被赋给string,那么num_char至少为5才可以保存字符串。如果给一个数组的赋值比将要处理的数组的字符数少,那么从最高位开始使用在未使用的位置上赋值0。
2.8 常量
Verilog中的常量可用关键词parameter来声明,它在声明的同时还可以对其进行常量赋值。一个常量的值在仿真过程中是不会改变的,常量表达式可以用于对一个常量值进行声明。例:
paramter data_1 = 31;
paramter data_2 = 131;
paramter data_3 = 231;
paramter data_4 = data_3*3-data_2;
paramter data_5 = 34,data_6 = data_4 - data_1;
还有一个常量localparam,它与paramter的区别是只作用于某一个模块内部,且为常量,而paramter可以通过调用进行赋值。
3表达式
Verilog的表达式是将操作符合操作数结合起来产生一个结果,我们先来介绍操作符和操作数。
3.1 操作数
操作数可以为上一小节讲到的所有数据类型声明的数。比如,常数、整数、线网、寄存器、时间等。
3.2 操作符
3.2.1算术运算符
算术运算符是双目操作符,对2个操作数进行算术运算,包括加(+)、减(-)、乘(*)、除(/)、求幂(**)、取模(%)。这些操作数的数值可以是二进制、八进制、十进制和十六进制的形式。例:
reg [3:0] A,B;
wire [4:0] sum,diff1,diff2,neg;
wire [7:0] mult;
assign sum =A+B;
assign diff1=A-B;
assign diff2=B-A;
assign neg=-B;
assign mult = A*B;
负数的表示在十进制下直接在前面添加“-”号,二进制中使用补码进行表示负数。
3.2.2按位运算符
按位运算符有按位取反(~)、按位与(&)、按位或(|)、按位异或(^)和按位异或非(^~或~^)。
按位操作符对 2 个操作数的每 1bit 数据进行按位操作。如果 2 个操作数位宽不相等,则用 0 向左扩展补充较短的操作数。取反操作符只有一个操作数,它对操作数的每 1bit 数据进行取反操作。例:
wire [3:0] A=4'b1101,B=4'b1001,C=4'b0001,D=4'b1111;
~A -> 4'b0010
A&B-> 4'b1001
A|D-> 4'b1111
C^D-> 4'b1110
B^~C->4'b1000
3.2.3缩减运算符
缩减运算符包含缩减与(&)、缩减与非(~&)、缩减或(|)、缩减或非(~|)、缩减异或(^)、缩减异或非(^~或~^)。缩减运算符是单目运算符,通过在一个数据上运算可以得到单个位的结果值。例:
wire [3:0] A=4'b1101;
&A -> 1'b0
~&A -> 1'b1
|A -> 1'b1
~|A -> 1'b0
^A -> 1'b1
^~A -> 1'b0
3.2.4逻辑运算符
逻辑运算符有逻辑非(!)、逻辑与(&&)、逻辑或(||)、逻辑相等(==)、逻辑不等(!=)、情形相等(===)、情形不等(!==)。
Verilog逻辑运算符作为逻辑连接,对布尔操作数进行运算得到布尔结果。该操作数可以是线网、寄存器或是可以得到布尔结果的表达式。
情形相等(===)用来确定两个操作数的对应位上是否完全一致,其中包括了值为X和Z的比较。
3.2.5关系运算符
关系运算符包括小于(<)、大于(>)、小于等于(<=)、大于等于(>=)。它用来比较两个操作数得到一个布尔值。如果操作数是线网或者寄存器类型的,其值可按无符号字对待。如果任何一个位是未知的,或者关系不明确的,则返回的结果是X。
3.2.6移位运算符
移位操作符包括左移(<<),右移(>>),算术左移(<<<),算术右移(>>>)。
移位操作符是双目操作符,两个操作数分别表示要进行移位的向量信号(操作符左侧)与移动的位数(操作符右侧)。算术左移和逻辑左移时,右边低位会补 0。逻辑右移时,左边高位会补 0;而算术右移时,左边高位会补充符号位,以保证数据缩小后值的正确性。例:
A = 4'b1100 ;
B = 4'b0010 ;
A = A >> 2 ; //结果为 4'b0011
A = A << 1; //结果为 4'b1000
A = A <<< 1 ; //结果为 4'b1000
C = B + (A>>>2); //结果为 2 + (-4/4) = 1, 4'b0001
3.2.7条件运算符
Verilog条件赋值运算符根据一个condition_expression的值选择一个表达式用于求值。条件运算符的语法格式如下:
condition_expression ? true_expression : false_expression
如果 condition_expression 为真(逻辑值为 1),则运算结果为 true_expression;如果 condition_expression 为假(逻辑值为 0),则计算结果为 false_expression。例:
assign sel = (data[1:0] == 2'b00) ? sel_1 : sel_2 ;//data为00时,选择sel_1,否则为sel_2
条件运算符可以进行嵌套,完成一个多次选择的逻辑。例:
assign hsel = (data[1:0] == 2'b00) ? sel_1 : //data为00时,选择sel_1
(data[1:0] == 2'b01) ? sel_2 : //data为01时,选择sel_2
(data[1:0] == 2'b10) ? sel_3 : //data为10时,选择sel_3
(data[1:0] == 2'b11) ? sel_4 ; //data为11时,选择sel_4
3.2.8拼接运算符
拼接运算符可以将两个或多个的操作数形成一个单字。这个运算在形成逻辑总线的时候特别有用,拼接的结果仍然按照所给的字的顺序排列。拼接运算可以用到循环和任意程序的嵌套中。例:
{4{a}}={a,a,a,a}
{2{a},{{2'b01},{3'b110}}}
3.2.9运算符的优先级
Verilog是从左向右计算表达式的。布尔表达式的计算过程中,如果可以判断最终值为真或假,则马上结束运算。
优先级由高到低,同一行优先级相同。