全书课件:VerilogHDL与数字系统设计简明教程_第1页
全书课件:VerilogHDL与数字系统设计简明教程_第2页
全书课件:VerilogHDL与数字系统设计简明教程_第3页
全书课件:VerilogHDL与数字系统设计简明教程_第4页
全书课件:VerilogHDL与数字系统设计简明教程_第5页
已阅读5页,还剩995页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Verilog HDL的基本概念和结构1.1 什么是Verilog HDL Verilog HDL是一种硬件描述语言,可以在算法级、门级到开关级的多种抽象设计层次上对数字系统建模。 Verilog HDL可以描述设计的行为特性、数据流特性、结构组成以及包含响应监控和设计验证方面的时延和波形产生机制,用这种语言编写的模型能够使用Verilog HDL仿真器进行验证。 Verilog HDL从C语言中继承了多种操作符和结构,所以从形式上看Verilog HDL和C语言有很多相似之处。1.2 主要功能 Verilog HDL的主要特点和功能有: 描述基本逻辑门,如and、or和nand等基本逻辑门都

2、内置在语言中,可以直接调用。 描述基本开关模型,如nmos 、pmos和cmos等基本开关都可以直接调用。 允许用户定义基元(UDP),这种方式灵活而有效,用户定义的基元既可以是组合逻辑也可以是时序逻辑。 可以指定设计中的端口到端口的时延、路径时延和设计的时序检查。 可采用多种方式进行建模。这些方式包括顺序行为描述方式使用过程化结构建模,数据流行为方式使用连续赋值语句方式建模,结构化方式使用门和模块实例语句描述建模。 Verilog HDL中有两类数据类型,线网数据类型和寄存器数据类型。线网类型表示构件间的物理连线,而寄存器类型表示抽象的数据存储元件。 能够描述层次设计,可使用模块实例结构描述

3、任何层次。 设计的规模可以是任意的,语言不对设计的规模(大小)施加任何限制。 Verilog HDL是IEEE标准而不再是某些公司的专有语言,语言标准都是公开的。人和机器都可阅读Verilog HDL 语言,因此它可作为EDA的工具和设计者之间的交互语言。1.3 设计流程设计流程1.4 基本结构 Verilog HDL程序文件的后缀都是“.v”,假如为加法器建模时创建了一个名为adder的文件,那么这个文件就是adder.v。每个.v文件里可以有一个或几个模块的描述程序。 1.4.1 模块的概念模块的概念 模块在语言形式上是以关键词module开始,以关键词endmodule结束的一段程序;

4、模块的实际意义是代表硬件电路上的逻辑实体(即实现特定逻辑功能的一组电路),其范围可以从简单的门到整个大的系统,比如计数器、存储子系统、微处理器等; 每个模块都实现特定的功能(一般来说最底层模块的功能都比较简单); 模块的描述方式有行为建模和结构建模(或二者结合)之分; 模块之间是并行运行的; 模块是分层的,高层模块通过调用、连接低层模块的实例来实现复杂功能; 各模块连接完成整个系统需要用一个顶层模块(Top-module)。 系统的设计可以按下面3个步骤进行: (1)把系统划分成模块; (2)规划各模块的接口; (3)对模块编程并连接各模块完成系统设计。模块的结构是这样的: module();

5、 Endmodule 其中: 是模块惟一的标识符(模块的名称); 是输入、输出和双向端口的列表,这些端口用来与其他模块进行连接(不妨理解为集成电路的引脚,是用来和其他电路连接的); 是一段程序,用来指定数据对象为寄存器型、存储器型、线型以及过程块,诸如函数块和任务块(说明这个模块内部都有什么); 是说明这个模块要做什么的语句; 标识模块结束的endmodule之后没有分号。 例1-1这是一个NAND与非门模块的建模程序,输出out是输入in1和in2相与后求反的结果。图1-2所示为本例示意图。 module NAND(in1, in2, out); /NAND模块 input in1, in2

6、; /两个输入端口in1和in2 output out; /一个输出端口out assign out = (in1 & in2); /连续赋值语句 endmodule /NAND模块结束图图1-2 NAND模块模块 1.4.2 模块调用模块调用 在做模块划分时经常会出现这种情形:某个大的模块中包含了一个或多个功能子模块。Verilog HDL是通过“模块调用”或称为“模块实例化”的方式实现这些子模块与高层模块的连接的。 例1-2 为与门建模。通过将一个NAND门的输出连到另一个NAND门的两个输入上可得到一个与门,可以把这个与门看作“顶层”模块,例1-1中的NAND模块可以看作是本例的

7、子模块。图1-3所示为本例示意图。图图1-3 AND模块模块module AND(in1, in2, out); / AND模块 input in1, in2; / 两个输入端口in1和in2 output out; / 一个输出端口out wire w1; / 一个模块内部连线wire NAND NAND1(in1, in2, w1); /调用(实例化)一个NAND子模块 NAND NAND2(w1, w1, out); /再调用(实例化)一个NAND子模块endmodule / AND模块结束 这个AND模块含有两个NAND模块实例,分别是NAND1和NAND2,通过内部连线w1连接起来,

8、就可以实现与门的逻辑功能。 调用模块实例的一般形式为: (); 其中,是要调用子模块的名称,本例中要调用的是NAND;是传输到子模块的参数值,参数传递的典型应用是定义门级时延,但是本例并未使用;是把子模块调用过来后对它的命名,本例分别给两个子模块命名为NAND1和NAND2;是实现子模块连接并实现高层模块功能的关键,如图1-3所示,AND模块的两个输入in1和in2分别作为子模块NAND1的两个输入,AND模块内部连线w1成为子模块NAND1的一个输出和NAND2的两个输入,AND模块的输出端out作为子模块NAND2的输出。 1.4.3 测试模块测试模块 完成程序描述之后为了确认这个模型是否

9、正确,应当对模块进行测试,即从模块输入端输入信号,再从输出端得到输出信号,对这些输入输出信号进行分析可以检查模型是否正确。Verilog HDL提供了一种灵活有效的产生输入信号波形的方式写测试程序(testbench),就是用一段程序产生激励信号,用语言描述信号的变化。testbench应当是被测模块的高层模块,它没有I/O端口,而且内部有被测模块的实例。 例1-3 检查所设计的与门模块是否能实现与门的功能。把激励信号的变化送入AND模块的输入端,再把处理过的信号从AND模块的输出端取出,通过对这些输入输出信号进行分析(主要是分析波形)可以检查模块的功能是否满足设计要求。图1-4所示为本例示意

10、图。module test_AND; reg a, b; /定义两个寄存器变量a和b wire out1, out2; /定义两个线网out1和out2 initial /产生测试数据(激励信号) begin a=0; b=0; #1 a=1; #1 b=1; #1 a=0; end initial /监测功能 begin $monitor(“Time=%0d a=%b b=%b out1=%b out2=%b”, $time, a, b, out1, out2); end AND gate1(a, b, out2); /*模块AND实例,激励信号通过a和b端进入AND模块, 测试结果从out

11、2输出*/ NAND gate2(a, b, out1); /*模块NAND实例,激励型号通过a和b端进入NAND模块, 测试结果从out1输出*/ endmodule图图1-4 test_AND模块模块 上述程序仿真后将产生如下结果: Time=0 a=0 b=0 out1=1 out2=0 Time=1 a=1 b=0 out1=1 out2=0 Time=2 a=1 b=1 out1=0 out2=1 Time=3 a=0 b=1 out1=1 out2=01.5 程序设计基础1.5.1 程序格式程序格式Verilog HDL是一种书写格式非常自由的语言,可以把一段程序写在一行之内,形式

12、如下: initial begin Top=3b001; #2 Top=3b011; end也可以跨越多行编写,形式如下:initial begin Top=3b001; #2 Top=3b011; end 请注意,在Verilog HDL程序中,语句间的空格是没有任何意义的。在Verilog HDL中,只有出现在字符串中的空格才是有意义的,如字符串“Verilog HDL”中的空格会被当作一个字符对待,但是所有其他的空格都是被Verilog HDL仿真器忽略的无意义符号,这些空格一般只是用来提高程序的可读性。 另外,Verilog HDL是区分大小写的,如果定义的变量是sum,但是引用变量时

13、写成Sum的话,程序会出错。1.5.2 注释语句Verilog HDL的注释语句有两种形式:(1)单行注释。用符号“/”表示注释的开始,从这个符号开始到本行的结束都被认为是注释,而且它只能注释到本行结束。如:reg a, b; /定义两个寄存器变量a和b(2)多行注释。以起始符“/*”开始,到终止符“*/”结束,可以跨越多行,在一对起始符与终止符之间的所有内容都被认为是注释。如:AND gate1(a, b, out2); /*模块AND实例,激励信号通过a和b端进入AND模块,测试结果从out2输出*/1.5.3 标识符和关键词标识符是用户定义的各种名称,可以是模块、端口、寄存器、线网、实例

14、和程序块等元素的名称,比如语句“module adder;”就定义了一个标识符adder,而语句“reg abc;”则定义了标识符abc。标识符可以是字母、数字和下划线“_”等符号的任意组合序列,但首字符不能是数字,而且单个标识符的总字符数不能多于1024。关键词是语言的保留字,有其特定的和专有的语法作用,用户不能再对这些关键词做新的定义。Verilog HDL共有102个关键词。注意:关键词必须是小写的,如“module”是关键词,而“Module”不是。1.5.4 参数声明程序中经常多次出现某些数字,如延迟时间或变量的宽度,有时(如调用任务或实例化模块时)可能要改变这些值,这种情况下经常要

15、用到参数。参数一经声明,就视其为一个常量,在整个仿真过程中不再改变。其声明形式如下:parameter param1=const_expr1, param2 = const_expr2, ., paramN = const_exprN;parameter是用于声明参数的关键词;param1、param2paramN是标识符;const_expr1、const_expr2const_exprN分别是标识符要代表的数字,它们可以不仅仅是数字,也可以是计算表达式。 。下面是3条参数声明语句: parameter LINELENGTH=132, ALL_X_S=16bx; parameter BIT=

16、1, BYTE=8, PI=3.14; parameter STROBE_DELAY=(BYTE + BIT)/2; 使用参数可以提高程序的可读性,也利于修改,尤其是延迟时间和变量宽度这些在调试中可能经常修改的值。1.5.5 预处理指令 和C语言类似,Verilog HDL也有预处理指令,预处理指令是以反引号“”开始的某些标识符,它们指示编译器执行某些操作。预处理指令通常应当出现在Verilog HDL文件的最开始几行。 Verilog HDL共有8组预处理指令: define, undef ifdef, else, endif include timescale resetall defau

17、lt_nettype unconnected_drive, nounconnected_drive celldefine, endcelldefine 1define和和undef define指令和C语言中的#define指令功能相同,是用一个指定的标识符来代表一个字符串,它的一般形式为: define 标识符 字符串 如: define MAX_BUS_SIZE 32 . . . reg MAX_BUS_SIZE - 1:0 AddReg;一旦define 指令被编译,那么它在整个编译过程中都有效,除非遇到undef 指令。undef 指令用于取消前面define指令所做的定义。例如:de

18、fine WORD 16 /指定WORD的值为16. . .wire WORD : 1 Bus; /16:1 Bus. . .undef WORD /在undef编译指令执行后, WORD不再代表16 2ifdef、else和和endif 这3个编译器指令通常一起出现,和普通的if-else结构类似,这些编译指令用于条件编译,如下例所示: ifdef WINDOWS parameter WORD_SIZE = 16 else parameter WORD_SIZE = 32 endif 3include include指令用于嵌入“内嵌文件”的内容,这里的“内嵌文件”一般也是Verilog H

19、DL文件。如下所示,假如在某个Verilog HDL文件adder.v中有如下内容: include . . / . . /halfadder.v /双引号内是要内嵌的文件的路径和文件名 module adder; endmodule 假设halfadder.v这个文件中的内容如下: module halfadder; endmodule 那么编译时,adder.v中的include这一行将由文件“ . . / . . / primitives.v” 的内容替代,adder.v的内容变成下面这样: module halfadder; endmodule module adder; endmod

20、ule 4timescale 在Verilog HDL模型中,所有时延都用单位时间表示。timescale编译器指令定义时延单位和时延精度,其格式为: timescale time_unit / time_precision 其中,time_unit和time_precision由值1、10、和100以及单位s、ms、s、ns、ps和fs组成,time_unit定义时延单位,time_precision定义时延精度。例如: timescale 1ns / 100ps 表示时延单位为1ns, 时延精度为100ps。 timescale编译器指令在模块外部出现, 并且影响后面所有的时延值。下面用一

21、个带有时延定义的例子说明。 例1-4 timescale 1ns/100ps module AndFunc (Z,A,B) ; output Z; input A, B; and #(5.22, 6.17 ) Al(Z,A,B); /规定了上升及下降时延值。 endmodule 编译器指令定义时延以ns为单位,并且时延精度为1/10ns(100ps)。因此,时延值5.22对应5.2ns(受精度限制,只精确到0.1ns),时延6.17对应6.2ns。如果把例1-4中的timescale指令替换成下面这句: timescale 10ns /1ns 那么5.22对应52ns, 6.17对应62ns。

22、 在编译过程中,timescale指令影响这一编译器指令后面所有模块中的时延值,直至遇到另一个timescale指令或resetall指令。 当设计中多个模块带有自身的timescale编译指令时将发生什么?在这种情况下,模拟器总是定位在所有模块的最小时延精度上,并且所有时延都相应地换算为最小时延精度。 例1-5本例有两个模块定义,每个模块定义都有自己的timescale编译指令。 timescale 1ns/ 100ps /第一个timescale编译指令 module AndFunc (Z, A, B) ; output Z; input A, B; and # (5.22, 6.17 )

23、 Al (Z,A,B) ; /第一个模块的时延 endmodule timescale 10ns/ 1ns /第二个timescale编译指令 module TB; reg PutA, PutB; wire GetO; initial begin PutA = 0; PutB = 0; #5.21 PutB=1; /第二个模块的时延 #10.4 PutA=1; /第二个模块的时延 #15 PutB=0; /第二个模块的时延 end AndFuncAF1(GetO, PutA, PutB) ; endmodule 这两个模块都有各自的timescale编译器指令,仿真器将选取其中最小的时延精度作

24、为仿真标准。因此第一个模块的timescale指令指定的精度被选中,即时延单位为1ns,精度为100ps。那么在第一个模块中的5.22对应5.2ns、6.17对应6.2 ns,第二个模块中的5.21对应52ns、10.4对应104ns、15对应150ns,并且在整个仿真过程中使用100 ps作为时延精度。模块TB的timescale指令将不再有效。 Verilog HDL提供了丰富的数据类型,本章把Verilog HDL的数据分为常量和变量两类,并分别介绍其特点和使用方法。 表达式是操作符、操作数和标点符号序列,其目的是用来说明一个计算过程。程序中的大部分语句是由表达式构成的,因此表达式是Ve

25、rilog HDL的重要部分。本章将给出操作符和操作数的种类及正确用法。2.1 数据类型 2.1.1 常量常量 在程序运行过程中,其值不能被改变的量称为常量。Verilog HDL有整型、实数型、字符串型3种常量。 在整型或实数型常量的任意位置可以随意插入下划线“_”(但是不能当作首符号),这些下划线对数本身并没有意义,但是当数字很长时使用下划线可以提高可读性。 Verilog HDL有4种基本值: 0 表示逻辑0或“假”; 1 表示逻辑1或“真”; x 表示未知; z 表示高阻。 注意:x值和z值都是不分大小写的,也就是说,值0 x1z与值0X1Z相同。 Verilog HDL的常量是由以上

26、这4种基本值组成的。 1整型常量整型常量 整型常量即整数,Verilog HDL的整数有两种书写格式: 十进制数格式; 基数格式。 (1)十进制数格式是一个可以带正负号的数字序列,代表一个有符号数,如下例: 32 /十进制数32 -15 /十进制数-15(2)基数格式的数通常是无符号数,形式如下:sizebase valuesize定义常量的位数(长度),这是可选项;base是基数,规定这个数据的进制,可以是o或O(表示八进制),b或B(表示二进制),d或D(表示十进制),h或H(表示十六进制)之一;value是一个数字序列,其形式应与base定义的形式相符。这个数字序列中出现的值x和z以及十

27、六进制中的af不区分大小写,“?”字符可以代替值z。 下面给出一些典型书写方法,有正确的也有错误的。 5O37 /5位八进制数 4D2 /4位十进制数 4B1x_01 /4位二进制数 7Hx /7位x(扩展的x), 即xxxxxxx 4hZ /4位z(扩展的z) , 即zzzz 2h1? /2位十六进制数,与2h1z相同 8h 2 A /在位数和字符之间,以及基数和数值之间允许出现空格 4d-4 /非法:数值不能为负 3 b001 /非法:和基数b之间不允许出现空格 (2+3)b10 /非法:位数不能够为表达式 如果没有定义常量的位数,那么这个数的长度就是相应值的位数,例如: o721 /9位

28、八进制数 hAF /8位十六进制数 如果定义的长度大于数字序列的实际长度,通常在数据序列的高位(左侧)补0。但是如果这个数字序列最左边一位为x或z,就用x或z在左边补位,例如: 10b10 /左边补0, 0000000010 10bx0 x1 /左边补x, xxxxxxx0 x1 如果定义的长度小于数字序列的实际长度,这个数字序列最左边超出的位将被截断,例如: 3b1001_0011 /与3b011相等 5H0FFF /与5H1F相等2实数型常量实数型常量在Verilog HDL中,实数就是浮点数,实数的定义方式有两种:(1)十进制格式,由数字和小数点组成(必须有小数点),例如:2.05.67

29、811572.120.12. / 非法:小数点右侧必须有数字 2)指数格式,由数字和字符e(E)组成,e(E)的前面必须要有数字而且后面必须为整数,例如: 23_5.1e2 /其值为23510.0,忽略下划线 3.6E2 /其值为360.0 ( e与E相同) 5E4 /其值为0.0005 3字符串型常量字符串型常量 字符串常量是由一对双引号括起来的字符序列。出现在双引号内的任何字符(包括空格和下划线)都将被作为字符串的一部分。如下例: INTERNAL ERROR R E A C H E D H E R E /空格出现在双引号内,所以是字符串的组成部分 12345_6789_0 /下划线出现在

30、双引号内,所以是字符串的组成部分实际上,字符都会被转换成二进制数,而且这种二进制数是按特定规则编码的。现在普遍都采用ASCII码,这种代码把每个字符用一个字节(8位)的二进制数表示。所以字符串实际就是若干个8位ASCII码的序列。例如字符串“INTERNAL ERROR”共有14个字符,存储这个字符串的变量就需要8*14位的存储空间,如下:reg 1:8*14 Message; /定义变量Message并分配存储空Message = INTERNAL ERROR /给变量Message赋值为字符串常量2.1.2 变量 Verilog HDL有线网和寄存器两种类型的变量,每种类型都有其在电路中的

31、实际意义。 1线网型变量线网型变量 线网表示元件之间的物理连线,它不能存储数据。线网是被“驱动”的,可以用连续赋值或把元件的输出连接到线网等方式给线网提供“驱动”,给线网提供驱动的赋值和元件就是“驱动源”,线网的值由驱动源决定。如果没有驱动源连接到线网,线网的缺省值为z。 Verilog HDL共有11种线网类型:wire、tri、wor、trior、wand、triand、trireg、tri1、tri0、supply0、supply1。 线网的声明语法形式如下: net_kindmsb:lsbnet1, net2, . . . , netN; net_kind是线网类型;msb:lsb定义

32、线网宽度的最高位和最低位,这一项是可选的,如果没有定义宽度,那么认为线网宽度是1位;net1,net2netN是线网变量的名称。 可以在同一个定义中声明多个变量,例如: wire Rdy, Start; /Rdy和Start是2个1位的连线 wand 2:0 Addr; /Addr是3位线与型线网 线网可以有多个驱动源(多条语句对同一个线网进行赋值),每个驱动源都会给线网赋值,出现这种情况时,线网的取值由线网类型决定。wor Rde; /定义Rde为线或类型的线网assign Rde = Blt & Wyl; /第一个连续赋值语句是Rde的第1个驱动源assign Rde = Kbl

33、| Kip; /第二个连续赋值语句是Rde的第2个驱动源本例中,Rde有两个驱动源,它们分别来自于两个连续赋值语句。由于Rde是“线或”类型的线网,所以Rde的有效值由驱动源的值(右边表达式的值)的线或表决定,具体做法是:把这两个驱动源赋给线网的两个值作为索引去线或表中查询,就可以得到线网真正的有效值。在这11种线网中,经常用到的是前6种,下面给出其详细的(1)wire和tri线网wire 连线。tri 三态线。wire和tri型线网都是用于连接单元的连线,是最常见的线网类型。二者语法和语义一致,不同的是三态线可以用于描述多个驱动源驱动同一根线的线网类型。用法举例. 下面是定义这两种线网的实例

34、: wire Reset; /1位连线Reset wire 3:2 Cla, Pla, Sla; /Cla,Pla和Sla都是2位连线 tri MSB1:LSB+1 Art; /三态线Art,位宽由表达式确定如果多个驱动源驱动同一个连线(或三态线网),这如果多个驱动源驱动同一个连线(或三态线网),这个线网的有效值由表个线网的有效值由表2-1决定。决定。下面的例子:assign Cla = Pla & Sla; /第1个驱动源.assign Cla = Pla Sla; /第2个驱动源在这个例子中,Cla有两个驱动源。两个驱动源的值用于在上表中进行索引,以便决定Cla的有效值。Cla是一

35、个向量,在查表确定其有效值时应按位操作。例如,如果第1个驱动源的值为01x,第2个驱动源的值为11z,那么Cla的有效值是x1x(两个值的第一位0和1在表中索引到x,第2位1和1在表中索引到1,第3位x和z在表中索引到x)。 (2)wor和trior线网 wor 线或。 trior 三态线或。 线或的含义是只要这类线网的某个驱动源值是1,那么线网的值就是1。线或和三态线或在语法和功能上是一致的。例如: wor MSB:LSB Art; trior MAX1: MIN1 Rdx, Sdx, Bdx;如果多个驱动源驱动这类线网,其有效值由表如果多个驱动源驱动这类线网,其有效值由表2-2决决定。定。

36、 (3)wand和triand线网 wand 线与。 triand 三态线与。 线与的含义是只要这类线网的某个驱动源值是0,那么线网的值就是0。线与和三态线与在语法和功能上是一致的。例如: wand -7:0 Dbus; triand Reset, Clk;如果这类线网存在多个驱动源,线网的有效值由表如果这类线网存在多个驱动源,线网的有效值由表2-3决定。决定。 (4)trireg线网 trireg 三态寄存器。 这种线网可以存储数值(类似于寄存器),可用于电容节点的建模。当没有驱动源时,三态寄存器线网的缺省初始值为x。当它的所有驱动源都处于高阻态(值都为z)时,三态寄存器保存的值是作用在该线

37、网上的最后一个值。例如:(5)tri0和tri1线网tri0 三态0。tri1 三态1。这两类线网可以用于线逻辑的建模,即线网有多于一个驱动源。tri0(tri1)线网的特征是,若无驱动源驱动,它的值为0(tri0)或1(tri1)。例如:tri0 3:3 GndBus; tri1 0 :5 OtBus, ItBus;在有多个驱动源情况下,在有多个驱动源情况下,tri0或或tri1的有效值由表的有效值由表2-4得到。得到。 (6)supply0和supply1线网 supply0用于对“地”建模,即低电平0。 supply1用于对电源建模,即高电平1。 例如: supply0 Gnd, Clk

38、Gnd; supply1 2:0 Vcc; (7)未说明的线网在Verilog HDL中,可以不必声明某种线网的类型。在这样的情况下,缺省线网类型为1位连线(wire)。wire是Verilog HDL内置的默认线网类型,可以使用编译器指令default_nettype改变这一默认线网类型。使用方法如下:default_nettype net_kind这里的net_kind就成为系统默认的线网类型,例如:default_nettype wand带有这条编译器指令的程序中,任何未被说明类型的线网都被设置为1位线与。 (8)scalared线网和vectored线网 scalared 标量线网。

39、vectored 向量线网。 scalared和vectored是声明线网时的可选项。如果没有定义这一项,那么缺省值是标量线网(scalared),前面所有程序中的线网都是这样的。如果某个线网声明时使用了vectored,那么就不允许对该线网做位选择(只选择线网值中的1位)和部分选择(选择线网值中的部分位),必须对线网整体赋值。 例如: wire vectored3:1 Grb; / /使用了vectored不允许位选择(如Grb2)和部分选择(如Grb3:2) wor scalared 4:0 Best; / /使用了scalared,效果与“wor 4:0 Best;”相同,允许位选择(如

40、Best2)和部分选择(如Best3:1) 2寄存器型变量寄存器型变量 寄存器表示一个抽象的数据存储单元,可以通过赋值语句改变寄存器内存储的值。寄存器只能在always语句和initial语句中赋值,always语句和initial语句是Verilog HDL提供的功能强大的结构语句,设计者可以在这两个结构语句中有效地控制对寄存器的赋值是否进行。在未被赋值时,寄存器的缺省值为x。 Verilog HDL共有5种寄存器类型: reg integer time real realtime(1)reg寄存器类型reg是最常用的寄存器类型,这种寄存器中只能存储无符号数。其声明形式如下:reg msb:

41、 lsb reg1, reg2, . . . regN;msb和lsb定义了该寄存器型变量的位宽范围,这个定义是可选的,如果没有定义范围,缺省值为1。例如:reg 3:0 Sat; /Sat为4 位寄存器。reg Cnt; /Cnt为1位寄存器。reg 1:32 Kisp, Pisp, Lisp; /定义了3个32位寄存器 reg寄存器中的值通常被认为是无符号数,如果给reg中存入一个负数,通常会被视为正数。例如: reg 1:4 Comb; /定义了1个4位寄存器Comb . Comb=5; /这条赋值语句给Comb赋值5(0101) Comb=-2; /* 这条赋值语句给Comb赋值-2(

42、补码形式1110)Comb的值为14(1110),但是会被认为是无符号数而被当作14(1110) */(2)用reg声明存储器在Verilog HDL中不能直接声明存储器,存储器是通过寄存器数组声明的,即用reg声明。可以说,存储器是由若干个寄存器组成的,通过定义单个寄存器的位宽和寄存器的个数可以决定存储器的大小。存储器声明形式如下:reg msb: lsb memory1 upper1:lower1 ,memory2 upper2:lower2 ,.;其中msb、lsb定义了存储器中单个寄存器的位宽;memory1和memory2是存储器名;upper1、lower1和upper2、lowe

43、r2分别定义了这两个存储器的大小(有多少个寄存器)。 下面是两个存储器声明实例: reg 0:3 MyMem 0:63 / /MyMem是由64个4位寄存器组成的存储器 reg Bog 1:5 / /Bog是由5个1位寄存器组成的数组可以在同一个reg声明中既定义存储器又定义寄存器,如下所示:parameter ADDR_SIZE = 16 , WORD_SIZE = 8;reg 1:WORD_SIZERamPar ADDR_SIZE1:0, DataReg;上例中,RamPar是存储器,由16个8位寄存器组成,而DataReg是8位寄存器。注意:可以只用一条赋值语句就完成对一个寄存器的赋值,

44、但是不能只用一条赋值语句就完成对整个存储器的赋值,应当对存储器中的每个寄存器单独赋值。如下所示:reg 1:5 Dig; /Dig为一个5位寄存器。.Dig = 5b11011; /可以在一条赋值语句中完成整个寄存器的赋值下面对存储器的赋值方法是错误的:reg Bog1:5; /Bog为5个1位寄存器的存储器。.Bog = 5b11011; /不能在一条语句内对存储器赋值 对存储器赋值的正确方法如下: reg 0:3 Xrom 1 : 4 /Xrom是由4个4位寄存器组成的存储器 . Xrom1 = 4hA; /对其中一个寄存器赋值 Xrom2 = 4h8; /对其中一个寄存器赋值 Xrom3

45、 = 4hF; /对其中一个寄存器赋值 Xrom4 = 4h2; /对其中一个寄存器赋值 还有一种为存储器赋值的方法:使用系统任务$readmemb从指定的文本文件中读取数据并加载到存储器,该文本文件必须包含相应的二进制或者十六进制数。 例如: reg 1:4 RomB 7:1 ; $readmemb (ram.patt, RomB); RomB是存储器名,ram.patt是包含数据的文本文件,ram.patt必须包含二进制值,也可以包含空白和注释。假如ram.patt中的数据是这样的:1 1 0 11 1 1 01 0 0 00 1 1 10 0 0 01 0 0 10 0 1 1那么系统任

46、务$readmemb促使RomB从索引7开始读取数据,先读取第一行数据1101给RomB7,然后读取1110给RomB6。 如果只想给存储器的一部分赋值,可以这样写: $readmemb (ram.patt, RomB, 5, 3); 上式中的5和3指定了要被赋值的存储器范围的开始值和结束值,这样只有Romb5、Romb4和Romb3这3个寄存器被赋值,被读取的值是数据文件中的前3行:1101、1110和1000。如果只定义了开始值,那么将从这个值开始连续读取数据直至到达存储器右端索引边界。例如:$readmemb (rom.patt, RomB, 6);/ /从地址6开始为存储器RomB读取

47、数据,并且持续到1数据文件中可以包含地址,用于表示该数据的赋值目标。形式如下:hex_address value其中,value是二进制数据,hex_address表示这个数据的赋值目标地址,例如:5 110012 11010 其中,value是二进制数据,hex_address表示这个数据的赋值目标地址,例如: 5 11001 2 11010 上例中,值被读入存储器中指定的地址,即RomB5被赋值为11001,RomB2被赋值为11010。(3)integer寄存器类型integer是整数寄存器,也是Verilog HDL中最常用的变量类型,这种寄存器中存储整数值。整数型寄存器可以存储带符号

48、数。定义integer寄存器形式如下:integer integer1, integer2 ,. intergerN msb:lsb ;其中,integer1,integer2,integerN是整数寄存器名;msb和lsb是定义整数数组界限的常量,数组界限的定义是可选的。例如:integer A, B, C; /声明了三个整数型寄存器 integer Hist 3:6; /声明了一组寄存器,其名称为别是Hist 3、Hist 4、Hist 5、Hist 6整数寄存器中最少可以容纳一个32位的数,但是不能作为位向量访问。例如,对于上面的整数B,B6(位选择)和B20:10(部分选择)是非法的。

49、如果想得到integer中的位,可以将integer赋值给一般的reg类型变量,然后从中选取相应的位,如下所示:reg 31:0 Breg;integer Bint; /Bint 6 和Bint 20:10 是不允许Breg = Bint; /*把Bint的值赋给Breg之后,Breg 6 和Breg 20:10 是允许的,这样就可以从整数Bint获取相应的位*/ 上例说明了如何通过简单的赋值将整数转换为位向量,从位向量到整数的转换也可以通过赋值完成。例如: integer J; /声明整数J reg 3:0 Bcq; /声明寄存器Bcq J=6; / J的值为32b0000.00110 Bc

50、q=J; / Bcq的值为4b0110 Bcq=4b0101; /把Bcq赋值为0101 J=Bcq; /把Bcq的值赋给J之后,J的值为32b0000.00101 J=6; /J 的值为32b1111.11010 Bcq=J; /Bcq的值为4b1010 从上例可以看出,赋值总是从最低位(最右侧)开始向最高位(最左侧)进行,而且任何多余的位都会被截断。 (4)time寄存器类型 time类型寄存器用于存储和处理时间,通常用在系统函数$time中。其声明形式如下: time time_id1, time_id2 , . . ., time_idN msb:lsb ; 其中,time_id1,t

51、ime_id2,time_idN是寄存器名;msb和lsb是规定范围界限的常量,这个范围将决定寄存器内能存储时间值的个数,如果未定义界限,默认值为1,那么每个寄存器只能存储一个至少64位的时间值。time类型的寄存器只存储无符号数。例如: time Events 0:31; /时间值数组,存储32个时间值 time CurrTime; /CurrTime可以存储一个时间值 (5)real和realtime寄存器类型 real(实数型寄存器)和realtime(实数型时间寄存器)一般用于在测试模板中存储仿真时间,二者声明形式完全相同,如下: real real_reg1, real_reg2,

52、. . ., real_regN; realtime realtime_reg1, realtime_reg2,., realtime_regN;下面是两个声明实例:real Swing, Top; realtime CurrTime;real变量的缺省值为0,当将值x和z赋予real类型寄存器时,这些值被当作0,如下所示:real RamCnt;.RamCnt = b01x1Z; /RamCnt在赋值后的值为b010102.2 表达式2.2.1 操作数操作数操作数就是运算对象,位于操作符左右两侧。操作数有如下8种类型:常数参数线网寄存器位选择部分选择存储器单元函数调用 1常数常数 表达式中经

53、常有常数出现,一般是做运算或赋值。常数的形式多种多样,例如: 256,7 /非定长的十进制数。 4b10_11, 8h0A /定长的整型常量。 b1, hFBA /非定长的整数常量。 90.00006 /实数型常量。 BOND /串常量;每个字符作为8位A S C I I值存储。表达式中的整数值可以是有符号数或无符号数。如果表达式中的整数形式是十进制整数(如12),就会被当作有符号数。如果整数形式是基数型整数(定长或非定长),那么该整数会被当作无符号数对待。例如:12 /是01100的5位向量形式(有符号)12 /是10100的5位向量形式(有符号)5b01100 /是十进制数12(无符号)5

54、b10100 /是十进制数20(无符号)4d12 /是十进制数12(无符号) 2参数参数 参数类似于常量,表达式中出现的参数都作为常数对待。参数是用某标识符代表某个数字的,所以定义参数时要给它赋值,程序中出现这个参数时将被替换为它所代表的值。例如: parameter LOAD = 4d12, STORE = 4d10; 参数LOAD和参数STORE分别被赋值为12和10,那么在程序中,所有的标识符LOAD和STORE都被当作数字12和10。 3线网线网 1位和多位线网都可以作为表达式中的操作数。例如: wire 0:3 Prt; /Prt为4位线网 wire Bdq; /Bbq是1位线网 注

55、意,线网中的值会被当作无符号数,如果赋给线网负值,通常会被系统当作正值对待。 例如: assign Prt = -3; /Prt被赋于位向量1101(-3的补码),被视为十进制数13 assign Prt = 4HA; /Prt被赋于位向量1010,即十进制数10 4寄存器寄存器 寄存器是在表达式中出现次数最多的操作数,许多程序语句都是通过对寄存器中存储的值进行转换和传输实现设计目的的。 在使用寄存器时请注意:整型寄存器中的值被视为有符号的二进制补码数;而reg寄存器或时间寄存器中的值被视为无符号数;实数和实数时间类型寄存器中的值被视为有符号浮点数。例如:integer TemA, TemB;

56、reg 1:5 Stat e; TemA = -10; /TemA值为位向量10110,是10的二进制补码TemB = b1011; / TemB值为十进制数11State = -10; / State值为位向量10110,即十进制数22State = b1011; / State值为位向量01011,是十进制值115位选择位选择表达式的操作数可以是线网或寄存器的某个位,即位选择。位选择是从线网(或寄存器)中选择特定的某个位。形式如下:net_or_reg_vector bit_select_expr其中,net_or_reg_vector是向量线网或寄存器名,bit_select_expr是

57、要选择位的编号。例如:State1 & State 4 /寄存器位选择,让State1和State4做逻辑与操作Prt 0 | Bbq /线网位选择,让Prt0和Bbq做位或操作 上例中,State是多位寄存器,Prt多位线网,Bbq是1位线网,可见通过使用位选择可以对线网和寄存器中的某个位进行操作。 注意,如果bit_select_expr的值为x、z或越界,那么位选择得到的值为x,如State x值为x。 6部分选择部分选择 和位选择类似,线网或寄存器的部分连续位也可以作为表达式中的操作数。部分选择是在线网或寄存器中选择某几个连续的位。形式如下: net_or_reg_vector

58、 msb:lsb 其中,net_or_reg_vector是向量线网或寄存器名,msb和lsb声明了要选择的位的编号范围。 例如: State 1:4 / State是多位寄存器,寄存器部分选择,选择了State中编号从1到4的4个位 Prt 1:3 / Prt是多位线网,线网部分选择,选择了Prt中编号从1到3的3个位 注意,在部分选择中若msb或lsb的值为x、z或它们标定的范围超出了向量的实际范围时,部分选择的值为x。 7存储器单元存储器单元 存储器建模是使用reg声明寄存器组,不能在一条语句内就完成对存储器内所有寄存器单元的赋值,必须对其中的存储器单元(即单个寄存器)进行赋值。形式如下

59、: memory word_address 其中,memory是存储器名,word_address是要选择单元的编号(即某个寄存器的编号)。例如:reg 1:8 Ack, Dram 0:63 ; /*定义了一个8位寄存器Ack和一个有84个8位寄存器组成的存储器*/. . .Ack = Dram 60; /把存储器Dram的编号为60的存储单元的值赋给Ack注意,虽然存储器单元就是寄存器,但不允许对存储器单元做位选择或部分选择。例如:Dram 60 2 /位选择不允许 Dram 60 2:4 /部分选择也不允许 如果想从存储器中读取一个位或部分位,可以先把存储器单元赋值给某个寄存器变量,然后对

60、该寄存器变量进行位选择或部分选择操作。如在上例中做了Ack=Dram60之后,Ack 2和Ack 2:4就能够取出存储器单元Dram60的某个位或部分位。 8函数调用函数调用 Verilog HDL中的函数和C语言中的函数没有什么大的区别,都用来实现某个计算过程或完成某个事件处理。函数可以被随意调用,函数调用也可以作为表达式中的操作数。调用的函数可以是系统函数(以字符“$”开始)或用户定义的函数。如下例: $time + SumOfEvents (A, B) / * $time是系统函数,而SumOfEvents是用户自定义函数。* /2.2.2 操作符Verilog HDL的操作符有如下9种类型:算术操作符关系操作符相等

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论