反斜线 ( ) 用于对确认的特别字符转义。
n 换行符
t 制表符
\ 字符自身
字符
206 八进制数206对应的字符
3.7 数据类型
Verilog HDL 有两大类数据类型。
1) 线网类型。net type 标明Verilog结构化元件间的物理连线。它的值由驱动元件的值决议,例如接连赋值或门的输出。假如没有驱动元件衔接到线网,线网的缺省值为z。
2) 寄存器类型。register type标明一个笼统的数据存储单元,它只能在always句子和initial句子中被赋值,而且它的值从一个赋值到另一个赋值被保存下来。寄存器类型的变量具有x 的缺省值。
3.7.1 线网类型
线网数据类型包括下述不同品种的线网子类型。
* wire
* tri
* wor
* trior
* wand
* triand
* trireg
* tri1
* tri0
* supply0
* supply1
简略的线网类型阐明语法为:
net_kind [msb:lsb] net1, net2, . . . , netN;
net_kind 是上述线网类型的一种。msb和lsb 是用于界说线网规模的常量表达式;规模界说是可选的;假如没有界说规模,缺省的线网类型为1位。下面是线网类型阐明实例。
wire Rdy, Start; //2个1位的连线。
wand [2:0] Addr; //Addr是3位线与。
当一个线网有多个驱动器时,即对一个线网有多个赋值时,不同的线网发生不同的行为。例如,
wor Rde;
. . .
assign Rde = Blt Wyl;
. . .
assign Rde = Kbl | Kip;
本例中,Rde有两个驱动源,别离来自于两个接连赋值句子。因为它是线或线网,Rde的有效值由运用驱动源的值(右边表达式的值)的线或(wor)表(拜见后面线或网的有关章节)决议。
1. wire和tri线网
用于衔接单元的连线是最常见的线网类型。连线与三态线(tri)网语法和语义共同;三态线能够用于描绘多个驱动源驱动同一根线的线网类型;而且没有其他特别的含义。
wire Reset;
wire [3:2] Cla, Pla, Sla;
tri [ MSB-1 : LSB +1] Art;
假如多个驱动源驱动一个连线(或三态线网),线网的有效值由下表决议。
wire (或 tri) 0 1 x z
0 0 x x 0
1 x 1 x 1
x x x x x
z 0 1 x z
下面是一个具体实例:
assign Cla = Pla Sla;
. . .
assign Cla = Pla ^ Sla;
在这个实例中,Cla有两个驱动源。两个驱动源的值(右侧表达式的值)用于在上表中索引,以便决议Cla的有效值。因为Cla是一个向量,每位的计算是相关的。例如,假如榜首个右侧表达式的值为01x, 而且第二个右测表达式的值为11z,那么Cla 的有效值是x1x (榜首位0和1在表中索引到x, 第二位1和1在表中索引到1,第三位x 和z在表中索引到x)。
2. wor和trior线网
线或指假如某个驱动源为1,那么线网的值也为1。线或和三态线或(trior)在语法和功能上是共同的。
wor [MSB:LSB] Art;
trior [MAX-1: MIN-1] Rdx, Sdx, Bdx;
假如多个驱动源驱动这类网,网的有效值由下表决议。
wor (或 trior) 0 1 x z
0 0 1 x 0
1 1 1 1 1
x x 1 x x
z 0 1 x z
3. wand和triand线网
线与(wand)网指假如某个驱动源为0,那么线网的值为0。线与和三态线与(triand)网在语法和功能上是共同的。
wand [-7 : 0] Dbus;
triand Reset, Clk;
假如这类线网存在多个驱动源,线网的有效值由下表决议。
wand (或 triand) 0 1 x z
0 0 0 0 0
1 0 1 x 1
x 0 x x x
z 0 1 x z
4. trireg线网
此线网存储数值(类似于寄存器),而且用于电容节点的建模。当三态寄存器(trireg)的一切驱动源都处于高阻态,也就是说,值为z时,三态寄存器线网保存效果在线网上的最终一个值。此外,三态寄存器线网的缺省初始值为x。
trireg [1:8] Dbus, Abus;
5. tri0和tri1线网
这类线网可用于线逻辑的建模,即线网有多于一个驱动源。tri0(tri1)线网的特征是,若无驱动源驱动,它的值为0(tri1的值为1)。
tri0 [-3:3] GndBus;
tri1 [0:-5] OtBus, ItBus;
下表显现在多个驱动源状况下tri0或tri1网的有效值。
tri0 (tri1) 0 1 x z
0 0 x x 0
1 x 1 x 1
x x x x x
z 0 1 x 0(1)
6. supply0和supply1线网
supply0用于对“地”建模,即低电平0;supply1网用于对电源建模,即高电平1;例如:
supply0 Gnd, ClkGnd;
supply1 [2:0] Vcc;
3.7.2 未阐明的线网
在Verilog HDL中,有或许不用声明某种线网类型。在这样的状况下,缺省线网类型为1位线网。
能够运用`default_nettype编译器指令改动这一隐式线网阐明办法。运用办法如下:
`default_nettype net_kind
例如,带有下列编译器指令:
`default_nettype wand
任何未被阐明的网缺省为1位线与网。
3.7.3 向量和标量线网
在界说向量线网时可选用关键词scalared 或vectored。假如一个线网界说时运用了关键词vectored, 那么就不答应位挑选和部分挑选该线网。换句话说,有必要对线网全体赋值(位挑选和部分挑选鄙人一章中解说)。例如:
wire vectored [3:1] Grb;
//不答应位挑选Grb[2]和部分挑选Grb [3:2]
wor scalared [4:0] Best;
//与wor [4:0] Best相同,答应位挑选Best [2]和部分挑选Best [3:1]。
假如没有界说关键词,缺省值为标量。
3.7.4 寄存器类型
有5种不同的寄存器类型。
* reg
* integer
* time
* real
* realtime
1. reg寄存器类型
寄存器数据类型reg是最常见的数据类型。reg类型运用保留字reg加以阐明,办法如下:
reg [ msb: lsb] reg1, reg2, . . . regN;
msb和lsb 界说了规模,而且均为常数值表达式。规模界说是可选的;假如没有界说规模,缺省值为1位寄存器。例如:
reg [3:0] Sat; //Sat为4 位寄存器。
reg Cnt; //1位寄存器。
reg [1:32] Kisp, Pisp, Lisp;
寄存器能够取恣意长度。寄存器中的值通常被解释为无符号数, 例如:
reg [1:4] Comb;
. . .
Comb = -2; //Comb 的值为14(1110),1110是2的补码。
Comb = 5; //Comb的值为15(0101)。
2. 存储器
存储器是一个寄存器数组。存储器运用如下办法阐明:
reg [ msb: 1sb] memory1 [ upper1: lower1],
memory2 [upper2: lower2],. . . ;
例如:
reg [0:3 ] MyMem [0:63]
//MyMem为64个4位寄存器的数组。
reg Bog [1:5]
//Bog为5个1位寄存器的数组。
MyMem和Bog都是存储器。数组的维数不能大于2。留意存储器归于寄存器数组类型。线网数据类型没有相应的存储器类型。
单个寄存器阐明既能够用于阐明寄存器类型,也能够用于阐明存储器类型。
parameter ADDR_SIZE = 16 , WORD_SIZE = 8;
reg [1: WORD_SIZE] RamPar [ ADDR_SIZE-1 : 0], DataReg;
RamPar是存储器,是16个8位寄存器数组,而DataReg是8位寄存器。
在赋值句子中需求留意如下差异:存储器赋值不能在一条赋值句子中完结,可是寄存器能够。因此在存储器被赋值时,需求界说一个索引。下例阐明它们之间的不同。
reg [1:5] Dig; //Dig为5位寄存器。
. . .
Dig = 5’b11011;
上述赋值都是正确的, 但下述赋值不正确:
reg BOg[1:5]; //Bog为5个1位寄存器的存储器。
. . .
Bog = 5’b11011;
有一种存储器赋值的办法是别离对存储器中的每个字赋值。例如:
reg [0:3] Xrom [1:4]
. . .
Xrom[1] = 4’hA;
Xrom[2] = 4’h8;
Xrom[3] = 4’hF;
Xrom[4] = 4’h2;
为存储器赋值的另一种办法是运用体系使命:
1) $readmemb (加载二进制值)
2) $readmemb (加载十六进制值)
这些体系使命从指定的文本文件中读取数据并加载到存储器。文本文件有必要包括相应的二进制或许十六进制数。例如:
reg [1:4] RomB [7:1] ;
$ readmemb (ram.patt, RomB);
Romb是存储器。文件“ram.patt”有必要包括二进制值。文件也能够包括空白空间和注释。下面是文件中或许内容的实例。
1101
1110
1000
0111
0000
1001
0011
体系使命$readmemb促进从索引7即Romb最左面的字索引,开端读取值。假如只加载存储器的一部分,值域能够在$readmemb办法中显式界说。例如:
$readmemb (ram.patt, RomB, 5, 3);
在这种状况下只要Romb[5],Romb[4]和Romb[3]这些字从文件头开端被读取。被读取的值为1101、1100和1000。
文件能够包括显式的地址办法。
@hex_address value
如下实例:
@5 11001
@2 11010
在这种状况下,值被读入存储器指定的地址。
当只界说开端值时,接连读取直至抵达存储器右端索引鸿沟。例如:
$readmemb (rom.patt, RomB, 6);
//从地址6开端,而且继续到1。
$readmemb ( rom.patt, RomB, 6, 4);
//从地址6读到地址4。
3. Integer寄存器类型
整数寄存器包括整数值。整数寄存器能够作为一般寄存器运用,典型应用为高层次行为建模。运用整数型阐明办法如下:
integer integer1, integer2,. . . intergerN [msb:1sb] ;
msb和lsb是界说整数数组边界的常量表达式,数组边界的界说是可选的。留意容许无位边界的状况。一个整数最少包容32位。可是具体完结可供给更多的位。下面是整数阐明的实例。
integer A, B, C; //三个整数型寄存器。
integer Hist [3:6]; //一组四个寄存器。
一个整数型寄存器可存储有符号数,而且算术操作符供给2的补码运算成果。
整数不能作为位向量拜访。例如,关于上面的整数B的阐明,B[6]和B[20:10]是不合法的。一种截取位值的办法是将整数赋值给一般的reg类型变量,然后从中选取相应的位,如下所示:
reg [31:0] Breg;
integer Bint;
. . .
//Bint[6]和Bint[20:10]是不答应的。
. . .
Breg = Bint;
/*现在,Breg[6]和Breg[20:10]是答应的,而且从整数Bint获取相应的位值。*/
上例阐明了怎么经过简略的赋值将整数转化为位向量。类型转化主动完结,不用运用特定的函数。从位向量到整数的转化也能够经过赋值完结。例如:
integer J;
reg [3:0] Bcq;
J = 6; //J的值为32’b0000…00110。
Bcq = J; // Bcq的值为4’b0110。
Bcq = 4’b0101.
J = Bcq; //J的值为32’b0000…00101。
J = -6; //J 的值为 32’b1111…11010。
Bcq = J; //Bcq的值为4’b1010。
留意赋值总是从最右端的位向最左面的位进行;任何剩余的位被切断。假如你能够回忆起整数是作为2的补码位向量标明的,就很简单了解类型转化。
4. time类型
time类型的寄存器用于存储和处理时刻。time类型的寄存器运用下述办法加以阐明。
time time_id1, time_id2, . . . ,time_idN [ msb:1sb];
msb和lsb是标明规模边界的常量表达式。假如未界说边界,每个标识符存储一个至少64位的时刻值。时刻类型的寄存器只存储无符号数。例如:
time Events [0:31]; //时刻值数组。
time CurrTime; //CurrTime 存储一个时刻值。
5. real和realtime类型
实数寄存器(或实数时刻寄存器)运用如下办法阐明:
//实数阐明:
real real_reg1, real_reg2, . . ., real_regN;
//实数时刻阐明:
realtime realtime_reg1, realtime_reg2, . . . ,realtime_regN;
realtime与real类型完全相同。例如:
real Swing, Top;
realtime CurrTime;
real阐明的变量的缺省值为0。不答应对real声明值域、位边界或字节边界。
当将值x和z赋予real类型寄存器时,这些值作0处理。
real RamCnt;
. . .
RamCnt = ‘b01x1Z;
RamCnt在赋值后的值为’b01010。
3.8 参数
参数是一个常量。参数常常用于界说时延和变量的宽度。运用参数阐明的参数只被赋值一次。参数阐明办法如下:
parameter param1 = const_expr1, param2 = const_expr2, . . . ,
paramN = const_exprN;
下面为具体实例:
parameter LINELENGTH = 132, ALL_X_S = 16’bx;
parameter BIT = 1, BYTE = 8, PI = 3.14;
parameter STROBE_DELAY = ( BYTE + BIT) / 2;
parameter TQ_FILE = /home/bhasker/TEST/add.tq;
参数值也能够在编译时被改动。改动参数值能够运用参数界说句子或经过在模块初始化句子中界说参数值(这两种机制将在第9章中具体解说)。
习题
1. 下列标识符哪些合法,哪些不合法?
COunT, 1_2 Many, **1, Real?, wait, Initial
2. 体系使命和体系函数的榜首个字符标识符是什么?
3. 举例阐明文本替换编译指令?
4. 在Verilog HDL中是否有布尔类型?
5. 下列表达式的位形式是什么?
7’o44, ‘Bx0, 5’bx110, ‘hA0, 10’d2, ‘hzF
6. 赋值后存储在Qpr中的位形式是什么?
reg [1:8*2] Qpr;
. . .
Qpr = ME ;
7. 假如线网类型变量阐明后未赋值,其缺省值为多少?
8. Verilog HDL 答应没有显式阐明的线网类型。假如是这样,怎样决议线网类型?
9. 下面的阐明错在哪里?
integer [0:3] Ripple;
10. 编写一个体系使命从数据文件“memA.data”中加载32×64字存储器。
11. 写出在编译时掩盖参数值的两种办法。