逻辑值
Verilog-1995 有两种基本的数据类型:变量和线网。它们各自都可以取值:0,1,X和Z。
- 逻辑 0 :表示低电平,对应到电路中的GND;
- 逻辑 1 :表示高电平,对应到电路中的VCC;
- 逻辑 X:表示信号值未知,意味着信号数值的不确定,即在实际电路里,信号可能为 1,也可能为 0;
- 逻辑 Z:表示高阻状态,常见于信号(input, reg)没有驱动时的逻辑结果。例如一个 pad 的 input 呈现高阻状态时,其逻辑值和上下拉的状态有关系。上拉则逻辑值为 1,下拉则为 0 ;
数值的进制与表示格式
-
数值的表示包括:符号、位宽、进制、数值四部分
4'b1001 //表示位宽为4 符号为正 的二进制数 1001 -32'h3022c0de //表示位宽为32 符号为负 的十六进制数
注:位宽和进制之间的
'
不能省略,'
与进制之间不能有空格 -
二进制的表示
二进制缩写为b
或B
,数值部分仅由0
和1
组成。例如:2'b01
、4'1011
等 -
八进制的表示
八进制缩写为o
或O
,数值部分由0~7
8个数字组成。(不常用) -
十进制的表示
十进制缩写为d
或D
,数值部分由0~9
10个数字组成。例如:4'd2
等同于4'b0010
(未指明进制时默认为十进制) -
十六进制的表示
十六进制缩写为h
或H
,数值部分由0~9
和a~f
16个字符组成。例如:'ha0bc10b8
等同于32'ha0bc_10b8
(未指明位宽时默认32位,添加_
可以增强代码的可读性)
数据类型
-
线网类型
wire 类型表示硬件单元之间的物理连线,由其连接的器件输出端连续驱动,如果没有驱动元件连接到 wire 型变量,缺省值一般为Z
(高阻态)。wire interrupt ; //声明wire型变量 interrupt wire[n-1:0] flag1, flag2 ; //声明两个位宽为n的wire型变量 flag1和flag2 wire gnd = 1'b0 ; //声明wire型变量gnd并赋初值为 0
线网类型除了
wire
以外还有:wand,wor,wri,triand,trior,trireg
(不常用) -
寄存器类型
表示一个抽象的数据存储单元,只能在always
和initial
语句中赋值 ,它会保持数据原有的值,直到被改写。寄存器类型在always
块语句中可能被综合成边沿触发器,在组合逻辑中可能被综合成wire
类型变量。reg a; //声明一个1位宽寄存器变量 reg[9:0] b; //声明一个10位宽的寄存器变量
寄存器的值可在任意时刻通过赋值操作进行改写,例如:
reg a; initial begin a = 1'b0; #100; a = 1'b1; end
reg
型变量一般为无符号数,若将一个负数赋给一个reg
型变量,则自动转换成其二进制补码的形式。例如:reg signed[3:0] rega; rega = -2; //此时reag的值为 1110 (14),是2的补码
-
存储器型
存储器型变量可以描述RAM型、ROM型存储器以及reg
文件。其一般声明方式为:reg <range1> name <range2>;
range1:
表示存储器中寄存器的位宽;
range2:
表示寄存器的个数;
name:
表示存储器名字,一次定义多个存储器是中间用,
隔开。
range1
和range2
均为可选项,缺省时默认为1
例1:
reg[7:0]mem1[255:0]; //定义一个有255个8位寄存器的存储器mem1,地址范围:0~255 reg[15:0]mem2[127:0],reg1,reg2; //定义一个有127个16位寄存器的存储器mem2和两个16位寄存器reg1和reg2
例2:
reg[n-1:0] a; //表示一个n位的寄存器 a reg mem1[n-1:0]; //表示一个由n个1位寄存器构成的存储器mem1
-
抽象类型
抽象数据类型主要包括整型integer
、时间型time
、实型real
及参数型parameter
。integer index; //简单的32位有符号整数 integer i[31:0]; //定义整型数组i,有32个元素 time a,b; //定义两个64位的时间型变量 real stime; //定义一个实数型数据 parameter length=32,weight=16;//定义两个参数
关键字
Verilog语言内部已经使用的词称为关键字或保留字,用来组织语言结构,这些关键字用户不能随便使用。注意:所有 关键字均为小写。
例如:ALWAYS
不是关键字,它只是标识符,与always
(关键字)是不同的。
常用关键字如下:
关键字 | 含义 |
---|---|
module | 模块开始定义 |
input | 输入端口定义 |
output | 输出端口定义 |
inout | 双向端口定义 |
parameter | 信号的参数定义 |
wire | wire 信号定义 |
reg | reg信号定义 |
always | 产生reg信号语句的关键字 |
assign | 产生wire信号语句的关键字 |
begin | 语句的起始标志 |
end | 语句的结束标志 |
posedge/negedge | 时序电路的标志 |
case | case语句起始标记 |
default | case语句的默认分支标志 |
endcase | case语句结束标记 |
if | if/else语句标记 |
else | if/else语句标记 |
for | for语句标记 |
endmodule | 模块结束定义 |
运算符
-
算术运算符
算数运算符包括:加法+
、减法-
、乘法*
、除法/
、取模%
算术表达式结果的长度由最长的操作数决定。在赋值语句下,算术操作结果的长度由操作左端目标长度决定。
例1:reg[3:0] A,B,C; reg[5:0] D; A = B + C; //结果为4位 D = B + C; //结果为6位
例2:
module arith_tb; reg[3:0]a; reg[2:0]b; initial begin a = 4'b1111; //a = 15 b = 3'b011; //b = 3 $display("%b",a*b); //乘法运算,结果为4'b1101(高位被舍去,等于45的低四位) $display("%b",a/b); //除法运算,结果为4'b0101 $display("%b",a+b); //加法运算,结果为4'b0010(舍去高位) $display("%b",a-b); //减法运算,结果为4'b1100 $display("%b",a%b); //取模运算,结果为4'b0000 end endmodule
-
关系操作符
关系操作符包括:大于>
、小于<
、大于等于>=
和小于等于<=
。module rela_tb; reg[3:0]a,b,c,d; initial begin a=3; b=6; c=1; d=4'hx; $display(a<b); //结果为真1 $display(a>b); //结果为假0 $display(a<=c); //结果为假0 $display(d<=a); //结果为未知数x end endmodule
-
相等关系操作符
相等操作符包括:等于==
、不等于!=
、全等===
、非全等!==
;==
的比较的结果有三种,即真1
、假0
和不定值x
,而===
的比较结果只有真1
和假0
。==
运算符的真值表:== 0 1 x z 0 1 0 x x 1 0 1 x x x x x x x z x x x x ===
运算符的真值表:=== 0 1 x z 0 1 0 0 0 1 0 1 0 0 x 0 0 1 0 z 0 0 0 1 例:
module equal_tb; reg[3:0]a,b,c,d; initial begin a=4'b0xx1; b=4'bOxx1; c=4'b0011; d=2'b11; $display(a==b); //结果为不定值x $display(c==d); //结果为真1 $display(a===b); //结果为真1 $display(c===d); //结果为假0 end endmodule
-
逻辑运算符
逻辑运算符包括:逻辑与运算符&&
、逻辑或运算符||
、逻辑非运算符!
。
如果一个操作数不为0
,它等价于逻辑1
;如果一个操作数等于0
,它等价于逻辑0
。如果它任意一位为x
或z
,它等价于x
。a b !a !b a&&b a||b 1 1 0 0 1 1 1 0 0 1 0 1 0 1 1 0 0 1 0 0 1 1 0 0 例1:寄存器变量a,b的初值分别为4’b1110和4’b0000,则:!a=0,!b=1,a&&b=0; a||b=1。
例2: a的初值分别为4’b1100,b的初值分别为4’b01x0,则:!a=0,!b=x,a&&b=x,a||b=x。
注:1. 操作数中存在不定态x,则逻辑运算的结果也是不定态。2. 逻辑运算操作的结果均为一位。 -
按位运算符
按位运算符包括:按位取反~
、按位与&
、按位或|
、按位异或^
、按位同或^~
。按位操作符对 2 个操作数的每1bit
数据进行按位操作。如果 2 个操作数位宽不相等,则用0
向左扩展补充较短的操作数。取反操作符只有一个操作数,它对操作数的每1bit
数据进行取反操作。
例:module bit_tb; reg[2:0]a; reg[4:0]b; initial begin a = 5'b101; //运算的时候a自动变为5’b00101 b = 5'b11101; $display("%b",~a); //结果为5'b11010 $display("%b",~b); //结果为5'b00010 $display("%b",a&b); //结果为5'b00101 $display("%b",a|b); //结果为5'b11101 $display("%b",a^b); //结果为5'b11000 end endmodule
-
归约运算符(缩位运算符)
归约操作符包括:归约与&
,归约与非~&
,归约或|
,归约或非~|
,归约异或^
,归约同或~^
。归约操作符只有一个操作数,它对这个向量操作数逐位进行操作,最终产生一个
1bit
结果。注:逻辑操作符、按位操作符和归约操作符都使用相同的符号表示,区分这些操作符的关键是分清操作数的数目,和计算结果的规则。
例:module cut_tb; reg[5:0]a; initial begin a=6'b101011; $display("%b",&a); //结果为1'b0 $display("%b",|a); //结果为1'b1 $display("%b",^a); //结果为1'b0 end endmodule
-
移位操作符
移位操作符包括左移<<
,右移>>
,算术左移<<<
,算术右移>>>
。移位操作符是双目操作符,两个操作数分别表示要进行移位的向量信号(操作符左侧)与移动的位数(操作符右侧)。算术左移和逻辑左移时,右边低位会补 0。逻辑右移时,左边高位会补 0;而算术右移时,左边高位会补充符号位,以保证数据缩小后值的正确性。
例:
module shift_tb; reg[5:0]a,b,c,d; reg[7:0]e; initial begin a=6'b101101; b=a<<2; c=a>>3; d=a<<7; e=a<<2; $display("%b",b); //结果为6'b110100 $display("%b",c); //结果为6'b000101 $display("%b",d); //结果为6'b000000 $display("%b",e); //结果为8'b10110100 end endmodule
-
条件运算符
<条件表达式>?<表达式1>:<表达式2>
条件表达式的计算结果有真
1
、假0
和未知态x
三种,当条件表达式的结果为真1
时,执行表达式1
,当条件表达式的结果为假0
时,执行表达式2
。例:
module mux2(in1,in2,sel,out); input [3:0]in1,in2; input sel; output [3:0]out; reg [3:0]out; assign out=(!sel)?in1:in2; //sel为0时out等于in1,反之out等于in2 endmodule
-
拼接运算符
拼接运算符包括:连接运算符{}
和复制运算符{{}}
连接操作符{}
:{信号1的某几位,信号2的某几位,- - -,信号n的某几位}
重复操作符{{}}
:将一个表达式放入双重花括号中,复制因子放在第一层括号中。
注:拼接符操作数必须指定位宽,常数的话也需要指定位宽。例:
module con_rep_tb; reg [2:0]a; reg [3:0]b; reg [7:0]c; reg [4:0]d; reg [5:0]e; initial begin a=3'b101; b=4'b1110; c={a,b}; //连接操作 d={a[2:1],b[2:0]}; //连接操作 e={2{a}}; //复制操作符 $display("%b",c); //结果8'b01011110 $display("%b",d); //结果5'b10110 $display("%b",e); //结果6'b101101 end endmodule