FPGA设计复习资料2013

更新时间:2024-04-23 21:44:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

FPGA设计复习资料

目录

零、考试题型: ............................................................................................................................... 4 一、名词概念 ................................................................................................................................... 4 二、Verilog HDL语法的基本概念 ................................................................................................. 9

(一)模块 ............................................................................................................................... 9 (二)标识符、转义标识符、关键字、注释、格式 ......................................................... 10 (三)数据类型及其常量和变量 ......................................................................................... 11 (四)运算符及表达式 ......................................................................................................... 16 (五) 赋值语句和块语句 ........................................................................................................ 19 (六)条件语句(if_else语句) ......................................................................................... 21 (七)case语句 ..................................................................................................................... 22 (八)循环语句 ..................................................................................................................... 23 (九)结构说明语句 ............................................................................................................. 24 (十)常用的系统任务 ......................................................................................................... 27 (十一)编译指令 ................................................................................................................. 32 (十二)延时(delay) ........................................................................................................ 35 四、verilog hdl建模方法 .............................................................................................................. 35

(一)数据流描述方式 .............................................................................................................. 35 (二)行为描述方式 ............................................................................................................. 36 (三)结构化描述形式 ......................................................................................................... 37 (四)混合设计描述方式 ..................................................................................................... 39 五、Testbench仿真测试................................................................................................................ 39 六、有限状态机 ............................................................................................................................. 42

例一:用格雷码 ..................................................................................................................... 43 例二、用可综合的Verilog模块设计、用独热码表示状态机 ........................................... 44 (推荐)例三:用可综合的Verilog模块设计、由输出指定的码表示状态的状态机 ... 44 (推荐)例四、用可综合Verilog模块设计复杂的多输出状态机时常用的方法 ........... 45 七、modelsim简介 ........................................................................................................................ 47 八、用Modelsim进行功能仿真和时序仿真 ............................................................................... 48 九、Quartus II 与ModelSim联合仿真 ........................................................................................ 57 十、必须读懂的范例 ..................................................................................................................... 60

基本门电路的几种描述方法 ................................................................................................. 60 行为描述的4位全加器 ......................................................................................................... 61 数据流描述的4位全加器 ..................................................................................................... 61 结构描述的4位级连全加器 ................................................................................................. 62 4位全加器的仿真程序 .......................................................................................................... 62 行为描述的1位全加器 ......................................................................................................... 63 三态双向驱动器 ..................................................................................................................... 63 用assign语句描述的三态门 ................................................................................................. 64

1

用bufif1关键字描述的三态门 ............................................................................................. 64 用always过程块产生两个时钟信号 .................................................................................... 64 用fork-join并行块产生信号波形 ......................................................................................... 64 用begin-end串行块产生信号波形 ....................................................................................... 65 激励波形的描述 ..................................................................................................................... 65 延迟定义块举例 ..................................................................................................................... 66 8位加法器的仿真程序 .......................................................................................................... 66 8位乘法器的仿真程序 .......................................................................................................... 67 基本D触发器 ........................................................................................................................ 68 带异步清0、异步置1的D触发器 ..................................................................................... 68 带同步清0、同步置1的D触发器 ..................................................................................... 68 电平敏感的1位数据锁存器 ................................................................................................. 69 带置位和复位端的1位数据锁存器 ..................................................................................... 69 8位数据锁存器 ...................................................................................................................... 69 8位数据寄存器 ...................................................................................................................... 70 8位移位寄存器 ...................................................................................................................... 70 4位计数器 .............................................................................................................................. 70 4位计数器的仿真程序 .......................................................................................................... 71 可变模加法/减法计数器 ........................................................................................................ 71 8位计数器的仿真 .................................................................................................................. 72 4位Johnson计数器(异步复位) ....................................................................................... 72 模为60的BCD码加法计数器 ............................................................................................. 73 阻塞赋值方式定义的2选1多路选择器 ............................................................................. 73 连续赋值方式定义的2选1多路选择器 ............................................................................. 74 2选1多路选择器的仿真 ...................................................................................................... 74 用case语句描述的4选1数据选择器 ................................................................................ 74 用if-else语句描述的4选1 MUX ....................................................................................... 75 同步置数、同步清零的计数器 ............................................................................................. 75 3-8译码器 .............................................................................................................................. 76 8-3优先编码器 ...................................................................................................................... 76 用函数定义的8-3优先编码器 ............................................................................................. 77 任务举例 ................................................................................................................................. 77 同一循环的不同实现方式 ..................................................................................................... 78 用repeat实现8位二进制数的乘法 ..................................................................................... 79 用for语句实现2个8位数相乘 .......................................................................................... 79 用for语句描述的七人投票表决器 ...................................................................................... 80 七段数码管译码器 ................................................................................................................. 80 非流水线方式8位全加器 ..................................................................................................... 81 4级流水方式的8位全加器 .................................................................................................. 81 两个加法器和一个选择器的实现方式 ................................................................................. 82 奇偶校验位产生器 ................................................................................................................. 83 两个选择器和一个加法器的实现方式 ................................................................................. 83 十一、综合实验参考程序 ............................................................................................................. 83

状态机设计的例子(略,见上文) ..................................................................................... 83

2

交通灯控制器 ......................................................................................................................... 83 自动转换量程频率计控制器 ................................................................................................. 86 用组合电路实现的ROM ....................................................................................................... 87 256×8 RAM模块 ................................................................................................................... 88 256×16 RAM块 ..................................................................................................................... 88 存储器在仿真程序中的应用 ................................................................................................. 89 4位串并转换器 ...................................................................................................................... 89 用函数实现简单的处理器 ..................................................................................................... 89 微处理器的测试代码 ............................................................................................................. 90 乘累加器(MAC)代码 ........................................................................................................ 91 乘累加器的测试代码 ............................................................................................................. 91 多功能数字钟 ......................................................................................................................... 92 电话计费器程序 ..................................................................................................................... 96 “梁祝”乐曲演奏电路 ......................................................................................................... 98

3

零、考试题型:

一、单项选择题(30分,每题2分)

二、EDA名词解释或简答题(10分,每题2分) 三、程序填空题(20分,每空2分) 四、程序改错题(10分) 五、程序设计题(2-3题)(30分) 祝同学们考试顺利!

一、名词概念

1、ASICs:application-specific integrated circuits专用集成电路

是指应特定用户要求和特定电子系统的需要而设计、制造的集成电路。ASIC分为全定制和半定制。

ASIC的特点是面向特定用户的需求,ASIC在批量生产时与通用集成电路相比具有体积更小、功耗更低、可靠性提高、性能提高、保密性增强、成本降低等优点。全定制设计需要设计者完成所有电路的设计,因此需要大量人力物力,灵活性好但开发效率低下。如果设计较为理想,全定制能够比半定制的ASIC芯片运行速度更快。半定制使用库里的标准逻辑单元(Standard Cell),设计时可以从标准逻辑单元库中选择SSI(门电路)、MSI(如加法器、比较器等)、数据通路(如ALU、存储器、总线等)、存储器甚至系统级模块(如乘法器、微控制器等)和IP核,这些逻辑单元已经布局完毕,而且设计得较为可靠,设计者可以较方便地完成系统设计。

2、ALU:arithmetic an logic unit算术逻辑单元

是中央处理器(CPU)的执行单元,是所有中央处理器的核心组成部分,由“And Gate”(与门) 和“Or Gate”(或门)构成的算术逻辑单元,主要功能是进行二位元的算术运算,如加减乘(不包括整数除法)。基本上,在所有现代CPU体系结构中,二进制都以补码的形式来表示。

3、BCD:binary-coded decimal BCD码或二-十进制代码,亦称二进码十进数 是一种二进制的数字编码形式,用二进制编码的十进制代码。这种编码形式利用了四个位元来储存一个十进制的数码,使二进制和十进制之间的转换得以快捷的进行。

4、CLBs:configurable logic blocks可配置逻辑模块。

包含一个可配置开关矩阵,此矩阵有选型电路(多路复用器),触发器和4或6个输入组成。在Xilinx公司的FPGA器件中,CLB由多个(一般为4个或2个)相同的slice和附加逻辑构成。每个CLB模块不仅可以用于实现组合逻辑和时序逻辑,还可以配置为分布式RAM和分布式ROM。

5、CPLDs:complex programmable logic devices复杂可编程逻辑器件

是从PAL和GAL器件发展出来的器件,相对而言规模大,结构复杂,属于大规模集成电路范围。主要是由可编程逻辑宏单元(MC,Macro Cell)围绕中心的可编程互连矩阵单元组成。是一种用户根据各自需要而自行构造逻辑功能的数字集成电路。

6、DSP:digital signal processing数字信号处理

4

就是用数值计算的方式对信号进行加工的理论和技术。 7、EDA:electronic design automation电子设计自动化 在20世纪60年代中期从计算机辅助设计(CAD)、计算机辅助制造(CAM)、计算机辅助测试(CAT)和计算机辅助工程(CAE)的概念发展而来的。EDA技术就是以计算机为工具,设计者在EDA软件平台上,用硬件描述语言VHDL完成设计文件,然后由计算机自动地完成逻辑编译、化简、分割、综合、优化、布局、布线和仿真,直至对于特定目标芯片的适配编译、逻辑映射和编程下载等工作。

8、TOP_DOWN:自顶向下或自上而下

是一种层次化和结构化的现代集成电路设计方法。先用高抽象级构造系统,然后再设计下层单元。

自下而上的设计流程:一种先构建底层单元,然后由底层单元构造更大的系统的设计方法

9、FPGA:field-programmable gate array现场可编程门阵列

它是在PAL、GAL、CPLD等可编程器件的基础上进一步发展的产物。它是作为专用集成电路(ASIC)领域中的一种半定制电路而出现的,既解决了定制电路的不足,又克服了原有可编程器件门电路数有限的缺点。

FPGA采用了逻辑单元阵列LCA(Logic Cell Array)的概念,内部包括可配置逻辑模块CLB(Configurable Logic Block)、输入输出模块IOB(Input Output Block)和内部连线(Interconnect)三个部分。FPGA利用小型查找表(LUT)(16×1RAM)来实现组合逻辑,每个查找表连接到一个D触发器的输入端,触发器再来驱动其他逻辑电路或驱动I/O,由此构成了既可实现组合逻辑功能又可实现时序逻辑功能的基本逻辑单元模块,这些模块间利用金属连线互相连接或连接到I/O模块。FPGA的逻辑是通过向内部静态存储单元加载编程数据来实现的,存储在存储器单元中的值决定了逻辑单元的逻辑功能以及各模块之间或模块与I/O间的联接方式,并最终决定了FPGA所能实现的功能,FPGA允许无限次的编程。

全球知名的FPGA生产厂商有: (1)Altera,开发平台是Quartus II;(2)Xilinx 开发平台是ISE;(3)Actel,开发平台是Libero;(4)Lattice;(5)Atmel

FPGA与CPLD的区别

CPLD:乘积项丰富而触发器少—适用组合逻辑;延时固定;掉电后重新上电还能保持编程信息;

FPGA:触发器资源丰富;适用时序逻辑;延时时间不可预测(容易产生竞争冒险或误码等);掉电后重新上电不能保持编程信息,需使用配置芯片

10、FSM:finite-state machine 有限状态机

有限状态机是指输出取决于过去输入部分和当前输入部分的时序逻辑电路。一般来说,除了输入部分和输出部分外,有限状态机还含有一组具有“记忆”功能的寄存器,这些寄存器的功能是记忆有限状态机的内部状态,它们常被称为状态寄存器。在有限状态机中,状态寄存器的的下一个状态不仅与输入信号有关,而且还与该寄存器的当前状态有关,因此有限状态机又可以认为是组合逻辑和寄存器逻辑的一种组合。其中,寄存器逻辑的功能是存储有限状态机的内部状态;而组合逻辑有可以分为次态逻辑和输出逻辑两部分,次态逻辑的功能是确定有限状态机的下一个状态,输出逻辑的功能是确定有限状态机的输出。

根据有限状态机是否使用输入信号,设计人员经常将其分为Moore型有限状态机和Mealy型有限状态机两种类型。

11、FIFO:first-in,first-out memory先入先出队列

是一种传统的顺序执行方法,先进入的指令先完成并引退,接着才执行第二条指令。是

5

一种先进先出的数据缓存器

12、HDL:hardware description language硬件描述语言

具有特殊结构能够对硬件逻辑电路的功能进行描述的一种高级编程语言。这种特殊结构的功能如下:描述电路的连接、描述电路的功能、在不同抽象级上描述电路、描述电路的时序、表达具有并行性。

13、LUT:lookup table查找表

本质上就是一个RAM。它把数据事先写入RAM后,每当输入一个信号就等于输入一个地址进行查表,找出地址对应的内容,然后输出。

14、Mealy-type FSM: Mealy型有限状态机

其输出信号不仅与当前状态有关,而且还与所有的输入信号有关,即可以把Mealy型有限状态机的输出看成是当前状态和所有输入信号的函数。

15、Moore-type FSM: Moore型有限状态机

其输出信号仅与当前状态有关,即可以把Moore型有限状态的输出看成是当前状态的函数。

16、PAL:programmable array logic可编程阵列逻辑 17、PLA:programmable logic array可编程逻辑阵列 18、IP core:知识产权核

是一段具有特定电路功能的硬件描述语言程序,该程序与集成电路工艺无关,可以移植到不同的半导体工艺中去生产集成电路芯片。通常是用HDL文本形式提交给用户,它经过RTL级设计优化和功能验证,但其中不含有任何具体的物理信息。IP核的重用是设计人员赢得迅速上市时间的主要策略。

与工艺无关的程序(IP core)称为软核。

把在某一种专用集成电路工艺器件上实现的、经验证是正确的、总门数在5000门以上的具有特定电路功能的集成电路版图掩膜称为硬核。尽管硬核由于缺乏灵活性而可移植性差,但由于无须提供寄存器转移级(RTL)文件,因而更易于实现IP保护。

固核是指在某一种FPGA器件上实现的、经验证是正确的、总门数在5000门以上的电路结构编码文件,是软核和硬核的折衷。

19、SoC:system-on-a-chip芯片级系统,也称片上系统,是一个有专用目标的集成电路,其中包含完整系统并有嵌入软件的全部内容。

20、RTL:register transfer level寄存器传输级

用于设计的可综合的一种抽象级。在RTL级,IC是由一组寄存器以及寄存器之间的逻辑操作构成。

RTL级和门级简单的区别在于,RTL是用硬件描述语言(Verilog 或VHDL)描述电路所要达到的功能,门级则是用具体的逻辑单元(依赖厂家的库)来实现电路所要达到的功能,门级最终可以在半导体厂加工成实际的硬件,即RTL和门级是设计实现上的不同阶段,RTL经过逻辑综合后,就得到门级。

21、syntax error: 语法或句法错误。提示你必须检查所写代码的语法问题。 22、UDP:user-defined primitive用户定义的原语

是指用户自己设计的基本逻辑元件的功能,即可以利用UDP来定义自己特色的用于仿真的基本逻辑元件模块并建立相应的原语库,并进行仿真。其结构模块与一般模块类似,以primitive关键词开始,用endprimitive关键词结束。

23、时序逻辑:由多个触发器和多个组合逻辑块组成的网络。常用的有:计数器、复杂的数据流动控制逻辑、运算控制逻辑、指令分析和操作控制逻辑。同步时序逻辑是设计复杂的数字逻辑系统的核心。时序逻辑借助于状态寄存器记住它目前所处的状态。在不同的状态

6

下,即使所有的输入都相同,其输出也不一定相同。

24、组合逻辑:是指在任何时刻,输出状态只决定于同一时刻各输入状态的组合,而与电路以前状态无关,与其他时间的状态无关。

25、LAB :Logic Array Blocks逻辑阵列块

26、PIA:Programmable Interconnect Array可编程连线阵列 负责信号传递,连接所有的宏单元。

27、IEEE:Institute of Electrical and Electronics Engineers美国电气和电子工程师协会 28、primitive:原语

是指verilog hdl中预先定义的逻辑单元。这些内置的原语可以转化为更大型的设计实例,形成一个结构更为复杂的部件。这些原语包括:and、nand、or、nor、xor、xnor、not、buf等。

29、抽象级(Levels of Abstraction):

描述风格的详细程度,如行为级和门级。Verilog既是一种行为描述的语言也是一种结构描述语言。Verilog模型可以是实际电路的不同级别的抽象。这些抽象的级别包括:

30、利用Quartus ii进行FPGA的开发流程:

(1)设计输入:图形输入、状态图输入、波形图输入、原理图输入、HDL文本输入 (2)综合 (3)适配

(4)仿真:时序仿真、功能仿真 (5)编程下载 (6)硬件测试 31、 数字系统建模。

被建模的数字系统对象既可以是简单的门,也可以是完整的数字电子系统。硬件描述语言的主要功能是编写设计文件,建立电子系统行为级的仿真模型,然后利用高性能的计算机对用Verilog HDL或VHDL建模的复杂数字逻辑进行仿真,然后再对它进行自动综合以生成符合要求且在电路结构上可以实现的数字逻辑网表(Netlist),然后根据网表和适合某种工艺的器件自动生成具体电路,最后生成该工艺条件下具体电路的延时模型。仿真验证无误后用于制造ASIC芯片或写入FPGA和CPLD中。

32、目前最主要的硬件描述语言是VHDL和Verilog HDL。Verilog起源于C语言,因此非常类似于C语言,容易掌握。Verilog HDL语言最初是于1983年由Gateway Design Automation公司为其模拟器产品开发的硬件建模语言。Verilog 语言于1995年成为IEEE标准,称为IEEE Std 1364-1995。

VHDL起源于ADA语言,格式严谨,语法严格,不易学习。VHDL出现较晚,但标准化早。IEEE 1706-1985标准。

33、HDL有两种用途:系统仿真和硬件实现。 如果程序只用于仿真,那么几乎所有的语法和编程方法都可以使用。但如果我们的程序是用于硬件实现(例如:用于FPGA设计),

7

那么我们就必须保证程序\可综合\(程序的功能可以用硬件电路实现)。不可综合的HDL语句在软件综合时将被忽略或者报错。我们应当牢记一点:\所有的HDL描述都可以用于仿真,但不是所有的HDL描述都能用硬件实现。

34、硬件描述语言开发流程

用VHDL/VerilogHD语言开发PLD/FPGA的完整流程为:

(1)文本编辑:用任何文本编辑器都可以进行,也可以用专用的HDL编辑环境。通常VHDL文件保存为.vhd文件,Verilog文件保存为.v文件

(2)功能仿真:将文件调入HDL仿真软件进行功能仿真,检查逻辑功能是否正确(也叫前仿真,对简单的设计可以跳过这一步,只在布线完成以后,进行时序仿真)

(3)逻辑综合:将源文件调入逻辑综合软件进行综合,即把语言综合成最简的布尔表达式和信号的连接关系。逻辑综合软件会生成.edf(edif)的EDA工业标准文件。

(4)布局布线:将.edf文件调入PLD厂家提供的软件中进行布线,即把设计好的逻辑安放到PLD/FPGA内。

(5)时序仿真:需要利用在布局布线中获得的精确参数,用仿真软件验证电路的时序。(也叫后仿真)

(6)编程下载:确认仿真无误后,将文件下载到FPGA中。

35、VHDL:Very High Speed Integerated Circuit Hardware Description Language:甚高速集成电路的硬件描述语言。

36、Verilog HDL较为适合系统级(System)、算法级(Alogrithem)、寄存器传输级(RTL)、逻辑级(Logic)、门级(Gate)、电路开关级(Switch)设计,而对于特大型(几百万门级以上)的系统级(System)设计,则VHDL更为适合,由于这两种HDL语言还在不断地发展过程中,它们都会逐步地完善自己。

37、层次管理

复杂数字逻辑电路和系统的层次化、结构化设计隐含着硬件设计方案的逐次分解。在设计过程中的任意层次,硬件至少有一种描述形式。硬件的描述特别是行为描述通常称为行为建模。在集成电路设计的每一层次,硬件可以分为一些模块,该层次的硬件结构由这些模块的互连描述,该层次的硬件的行为由这些模块的行为描述。这些模块称为该层次的基本单元。而该层次的基本单元又由下一层次的基本单元互连而成。如此下去,完整的硬件设计就可以由图2-6-1所示的设计树描述。在这个设计树上,节点对应着该层次上基本单元的行为描述,树枝对应着基本单元的结构分解。在不同的层次都可以进行仿真以对设计思想进行验证。EDA工具提供了有效的手段来管理错综复杂的层次,即可以很方便地查看某一层次某模块的源代码或电路图以改正仿真时发现的错误。

38、具体模块的设计编译和仿真的过程

8

从上图可以看出,模块设计流程主要由两大主要功能部分组成:

设计开发:即从编写设计文件-->综合到布局布线-->投片生成这样一系列步骤。

设计验证:也就是进行各种仿真的一系列步骤,如果在仿真过程中发现问题就返回设计输入进行修改。

二、Verilog HDL语法的基本概念

(一)模块

模块是Verilog 的基本描述单位,用于描述某个设计的功能或结构及其与其他模块通信的外部端口。一个设计的结构可使用开关级原语、门级原语和用户定义的原语方式描述; 设计的数据流行为使用连续赋值语句进行描述; 时序行为使用过程结构描述。一个模块可以在另一个模块中使用。

一个模块的基本语法如下:

module module_name (port_list);//module是模块的起始关键字

//module_name是模块名称,port_list是端口列表;

(Declarations:) //声明主要包括以下类型: reg, wire, parameter, //模块描述中使用的寄存器、连线型线网和参数 input, output, inout, //模块的输入、输出、双向端口(相当于引脚) function, task, . . . //函数,任务 (Statements:) //功能描述包括以下类型的内容:

9

initial statement //初始化块 always statement //总是执行块 module instantiation //模块的实例化 gate instantiation //门实例 UDP instantiation //用户自定义原语实例 continuous assignment //连续任务 endmodule //endmodule是模块的结束关键字

声明部分和语句可以散布在模块中的任何地方;但是变量、寄存器、线网和参数等的说明部分必须在使用前出现。为了使模块描述清晰和具有良好的可读性, 最好将所有的声明部分放在语句前。

以下为建模一个半加器电路的模块的简单实例。

module HalfAdder (A, B, Sum, Carry); //模块的名字是HalfAdder,模块有4个端口,以分号结束

input A, B; /* 输入端口A和B。由于没有定义端口的位数, 所有端口大小都为1位;同时, 由于没有各端口的数据类型说明, 这四个端口都是线网数据类型 */

output Sum, Carry; //输出端口Sum和Carry

assign #2 Sum = A ^ B; //描述半加器数据流行为的连续赋值语句 assign #5 Carry = A & B; //描述半加器数据流行为的连续赋值语句 endmodule //

/*这些语句在模块中出现的顺序无关紧要,这些语句是并发的。每条语句的执行顺序依赖于发生在变量A和B上的事件。 */

在模块中,可用下述方式描述一个设计: 1) 数据流方式; 2) 行为方式; 3) 结构方式;

4) 上述描述方式的混合。

(二)标识符、转义标识符、关键字、注释、格式

Verilog HDL中的标识符(identifier)可以是任意一组字母、数字、$符号和_(下划线)符号的组合,但标识符的第一个字符必须是字母或者下划线。另外,标识符是区分大小写的。以下是标识符的几个例子:

Count

COUNT //与Count不同。 _R1_D2 R56_68 FIVE$

转义标识符(escaped identifier )可以在一条标识符中包含任何可打印字符。转义标识符以\\ (反斜线)符号开头,以空白结尾(空白可以是一个空格、一个制表字符或换行符)。下面例举了几个转义标识符:

\\7400 \\.*.$

\\{******} \\~Q

\\OutGate 与OutGate相同。

10

最后这个例子解释了在一条转义标识符中,反斜线和结束空格并不是转义标识符的一部分。也就是说,标识符\\OutGate 和标识符OutGate恒等。

Verilog HDL定义了一系列保留字,叫做关键词,它仅用于某些上下文中。 附录A列出了语言中的所有保留字。注意只有小写的关键词才是保留字。例如,标识符always(这是个关键词)与标识符ALWAYS(非关键词)是不同的。

另外,转义标识符与关键词并不完全相同。标识符\\initial 与标识符initial(这是个关键词)不同。注意这一约定与那些转义标识符不同。

注释。在Verilog HDL中有两种形式的注释。 /*第一种形式:可以扩展至 多行 */

//第二种形式:在本行结束。 格式。Verilog HDL区分大小写。也就是说大小写不同的标识符是不同的。此外,Verilog HDL是自由格式的,即结构可以跨越多行编写,也可以在一行内编写。白空(新行、制表符和空格)没有特殊意义。下面通过实例解释说明。

initial begin Top = 3'' b001; #2 Top = 3'' b011; end 和下面的指令一样: initial begin

Top = 3'' b001; #2 Top = 3'' b011; end (三)

(三)数据类型及其常量和变量

1、值类型:

Verilog HDL有下列四种基本的值: 1) 0:逻辑0或“假” 2) 1:逻辑1或“真” 3) x:未知 4) z:高阻

注意这四种值的解释都内置于语言中。如一个为z的值总是意味着高阻抗,一个为0的值通常是指逻辑0。

在门的输入或一个表达式中的为“z”的值通常解释成“x”。此外,x值和z值都是不分大小写的,也就是说,值0x1z与值0X1Z相同。Verilog HDL中的常量是由以上这四类基本值组成的。

2、Verilog HDL中有三类常量: 1) 整型 2) 实数型 3) 字符串型

下划线符号(_)可以随意用在整数或实数中,它们就数量本身没有意义。它们能用来提高易读性;唯一的限制是下划线符号不能用作为首字符。

(1)整型数

? 整数常量:

11

? 1) 二进制整数(b或B) ? 2) 十进制整数(d或D) ? 3) 十六进制整数(h或H) ? 4) 八进制整数(o或O)

? x和z(?)值: 不定值和高阻值

如:4'b10x0、4'b101z、12'dz、12'd?、8'h4x

? 负数: 位宽前加-号,内部是补码

如:-1=-32'1=32’hFFFFFFFF

? 下划线: 仅增加可读性

如:16'b10x0_0000_0000_1111

“AB”=16’b01000001_01000010

整型数可以按如下两种方式书写: 简单的十进制数格式

这种形式的整数定义为带有一个可选的 “+”(一元)或 “-”(一元)操作符的数字序列。下面是这种简易十进制形式整数的例子。

32 十进制数32 -15 十进制数-15

这种形式的整数值代表一个有符号的数。负数可使用两种补码形式表示。因此32在5位的二进制形式中为10000,在6位二进制形式中为110001;-15在5位二进制形式中为10001,在6位二进制形式中为110001。

基数格式:[size ] 'base value

size 定义以位计的常量的位长;base为o或O(表示八进制),b或B(表示二进制),d或D(表示十进制),h或H(表示十六进制)之一;value是基于base的值的数字序列。值x和z以及十六进制中的a到f不区分大小写。

下面是一些具体实例: 5'O37 5位八进制数 4'D2 4位十进制数 4'B1x_01 4位二进制数

7'Hx 7位x(扩展的x), 即xxxxxxx 4'hZ 4位z(扩展的z) , 即zzzz 4'd-4 非法:数值不能为负

8'h 2 A 在位长和字符之间,以及基数和数值之间允许出现空格 3'b001 非法:’和基数b之间不允许出现空格 (2+3) 'b10 非法:位长不能够为表达式

注意,x(或z)在十六进制值中代表4位x(或z),在八进制中代表3位x(或z),在二进制中代表1位x(或z)。

基数格式计数形式的数通常为无符号数。这种形式的整型数的长度定义是可选的。如果没有定义一个整数型的长度,数的长度为相应值中定义的位数。下面是两个例子:

'o721 //9位八进制数 'hAF //8位十六进制数

如果定义的长度比为常量指定的长度长,通常在左边填0补位。但是如果数最左边一位为x或z,就相应地用x或z在左边补位。例如:

10'b10 左边添0占位, 0000000010 10'bx0x1 左边添x占位,xxxxxxx0x1

12

如果长度定义得更小,那么最左边的位相应地被截断。例如: 3'b1001_0011与3'b011 相等 5'H0FFF 与5'H1F 相等

?字符在数中可以代替值z,在值z被解释为不分大小写的情况下提高可读性 2、实数

实数可以用下列两种形式定义: (1) 十进制计数法;例如 2.0 5.678 11572.12 0.1

2. //非法:小数点两侧必须有1位数字

(2)科学计数法; 这种形式的实数举例如下: 23_5.1e2 其值为23510.0; 忽略下划线 3.6E2 360.0 (e与E相同) 5E-4 0.0005

Verilog语言定义了实数如何隐式地转换为整数。实数通过四舍五入被转换为最相近的整数。

42.446, 42.45 转换为整数42 92.5, 92.699 转换为整数93 -15.62 转换为整数-16 -26.22 转换为整数-26 3、字符串

字符串是双引号内的字符序列。字符串不能分成多行书写。例如: \ \->HERE\

用8位ASCII值表示的字符可看作是无符号整数。因此字符串是8位ASCII值的序列。为存储字符串“INTERNAL ERROR”,变量需要8*14位。

reg [1 : 8*14] Message; . . .

Message = \

反斜线 (\\ ) 用于对确定的特殊字符转义。 \\n 换行符 \\t 制表符 \\\\ 字符\\本身 \\\字符\

\\206 八进制数206对应的字符 数据类型

4、网络数据类型:表示结构实体之间的物理连接

wire型:用来表示单个门驱动或连续赋值语句驱动的网络型数据,默认值为z,常用assign语句或实例元件的输出赋值。

tri型:用来表示多驱动器驱动的网络型数据 reg型:寄存器类型是数据储存单元的抽象。

memory型:通过对reg 型变量建立数组来对存储器建模,可以描述RAM 型存储器,

13

ROM 存储器和reg文件。数组中的每一个单元通过一个数组索引进行寻址。如:reg [3:0] mm [7:0];

有5种不同的寄存器类型。 reg、integer、time、real、realtime (1) reg寄存器类型

寄存器数据类型reg是最常见的数据类型。reg类型使用保留字reg加以说明,通过赋值语句可以改变寄存器储存的值,其作用与改变触发器储存的值相当,默认值为x。在always 块内被赋值的每一个变量必须是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)。

存储器是一个寄存器数组。存储器使用如下方式说明: 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;

有一种存储器赋值的方法是分别对存储器中的每个字赋值。例如:

14

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 (加载十六进制值) (2)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的补码位向量表示的,就很容易理解类型转换。

(3) time类型

time类型的寄存器用于存储和处理时间。time类型的寄存器使用下述方式加以说明。 time time_id1, time_id2, . . . ,time_idN [ msb:1sb];

15

msb和lsb是表明范围界限的常量表达式。如果未定义界限,每个标识符存储一个至少64位的时间值。时间类型的寄存器只存储无符号数。例如:

time Events [0:31]; //时间值数组。

time CurrTime; //CurrTime 存储一个时间值。 (4)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。 5、参数

参数是一个常量。参数经常用于定义时延和变量的宽度。使用参数说明的参数只被赋值一次。参数说明形式如下:

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 = \参数值也可以在编译时被改变。改变参数值可以使用参数定义语句或通过在模块初始化语句中定义参数值。

(四)运算符及表达式

运算符按其功能可分为以下几类:

? 算术运算符(+,-,×,/,%) ? 赋值运算符(=,<=)

? 关系运算符(>,<,>=,<=) ? 逻辑运算符(&&,||,!) ? 条件运算符(?:)

? 位运算符(~,|,^,&,^~) ? 移位运算符(<<,>>) ? 拼接运算符({ })

16

按其所带操作数的个数运算符可分为三种:

? 单目运算符:可以带一个操作数,操作数放在运算符的右边。 ? 二目运算符:可以带二个操作数,操作数放在运算符的两边。

? 三目运算符:可以带三个操作,这三个操作数用三目运算符分隔开。 例:

clock=~clock; //~是一个单目取反运算符,clock是操作数 c=a|b; //是一个二目按位或运算符,a和b是操作数

r=s?t:u; //?:是一个三目条件运算符,s,t,u是操作数 逻辑运算符(&&,||,!) a 真 真 假 假

b 真 假 真 假

!a 假 假 真 真

!b 假 真 假 真

a&&b 真 假 假 假

a||b 真 真 真 假

逻辑运算符中“&&”和“||”的优先级别低于关系运算符,“!”高于算术运算符。见下例: (a>b)&&(x>y) 可写成:a>b&&x>y (a==b)||(x==y) 可写成:a==b|| x==y (!a)||(a>b) 可写成:!a || a>b

为了提高程序的可读性,明确表达各运算符间的优先关系,建议使用括号。 关系运算符共有以下4种: (1) ab a大于b

(3) a<=b a小于或等于b

(4) a>=b a大于或等于b

关系为假(flase),则返回值是0;关系为真(true),则返回值是1;如果某个操作数的值不定,则关系是模糊的,返回值是不定值x。

所有的关系运算符有着相同的优先级别。关系运算符的优先级别低于算术运算符的优先级别。见下例:

a “==”和“!=”又称为逻辑等式运算符,其结果由两个操作数的值决定。由于操作数中某些位可能是不定值x和高阻值z,结果可能为不定值x。

“===”和“!==”运算符在对操作数进行比较时对不定值x和高阻值z也进行比较,两个操作数必须完全一致,其结果才是1,否则为0。“===”和“!==”运算符常用于case表达式的判别,所以又称为“case等式运算符”。

if(A==1’bx) $display(“A is X”); (当A等于x时,这个语句不执行)

17

if(A===1’bx) $display(“A is X”); (当A等于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 == 0 1 x z 0 1 0 x x 1 0 1 x x x x x x x z x x x x 在Verilog HDL中有两种移位运算符:“<<”(左移位运算符)和“>>”(右移位运算符)。其使用方法如下:

a>>n 或 a<

a代表要进行移位的操作数,n代表要移几位。这两种移位运算都用0来填补移出的空位。下面举例说明:

module shift;

reg [3:0] start,result; initial begin

start =1; //start在初始时刻设为值0001

result=(start<<2); //移位后,start的值0100,然后赋给result end endmodule

进行移位运算时应注意移位前后变量的位数,下面将给出一例: 4’b1001<<1=5’b10010; 4’b1001<<2=6’b100100; 1<<6=32’b1000000; 4’b1001>>1=4’b0100; 4’b1001>>4=4’b0000;

在Verilog HDL语言中有一个特殊的运算符:{ } 即:位拼接运算符(concatenation)

用这个运算符可以把两个或多个信号的某些位拼接起来进行运算操作。其使用方法如下:

{信号1的某几位,信号2的某几位,……信号n的某几位} 即把某些信号的某些位详细地列出来,中间用逗号分开,最后用大括号括起来表示一个整体信号。见下例:

{a,b[3:0],w,3’b101} 也可以写成为: {a,b[3],b[2],b[1],b[0],w,1’b1,1’b0,1’b1} 位拼接还可以用重复法来简化表达式。见下例:

{ 4 { w } } 等同于 {w,w,w,w} 位拼接还可以用嵌套的方式来表达。见下例:

{b,{3{a,b}}} 等同于 {b,a,b,a,b,a,b} 注意:在位拼接表达式中不允许存在没有指明位数的信号。因为在计算拼接信号位宽的大小时必须知道其中每个信号的位宽。

wire [3:0] a; wire [3:0] b;

a和b可表达的十进制数范围均为0~15,而{a,b}可表示0~255范围的十进制数

缩减运算符(reduction operator)是单目运算符,也有与、或、异或、同或等运算。运算规则类似于位运算符的运算规则,但其运算过程不同。位运算是对操作数的相应位进行与、或、

18

非运算,操作数是几位数则运算结果也是几位数。而缩减运算是对单个操作数进行与、或、异或、同或等的递推运算,最后的运算结果是1位的二进制数。

缩减运算的具体运算过程是这样的:

第一步先将操作数的第1位与第2位进行与、或等运算;

第二步将运算结果与第3位进行与、或等运算,依次类推,直至最后1位。 例如:reg [3:0] B;

reg C; C=&B; 相当于:

C=( ( B[0] & B[1]) & B[2]) & B[3];

在Verilog HDL中,所有的关键词是事先定义好的确认符,用来组织语言结构。关键词是用小写字母定义的,因此在编写源程序时要注意关键词的书写,以避免出错。

always,and,assign,begin,buf,bufif0,bufif1,case,casex,casez,cmos,deassign,default,defparam,disable,edge,else,end,endcase,endmodule,endfunction,endprimitive,endspecify,endtable,endtask,event,for,force,forever,fork,function,highz0,highz1,if,lnitial,inout,input,integer,join,large,macromodule,medium,module,nand,negedge,nmos,nor,not,notif0,nodf1,or,output,parameter,pmos,posedge,primitive,pull0,pull1,pullup,pulldown,rcmos,reg,releses,repeat,mmos,rpmos,rtran,rtranif0,rtranif1,scalared,small,specify,specparam,strength,strong0,strong1,supply0,supply1,table,task,time,tran,tranif0,tranif1,tri,tri0,trl1,triand,trior,trireg,vectored,wait,wand,weak0,weak1,while,wire,wor, xnor,xor

(五) 赋值语句和块语句

在Verilog HDL语言中,信号有两种赋值方式:

(1)非阻塞(non_blocking)赋值方式(如b<=a;):

●在语句块中,上面语句所赋的变量值不能立即就为下面的语句所用; ●块结束后才完成赋值操作,块结束前被赋值的变量保持上一次所赋的值;

●在编写可综合的时序逻辑模块时,这是最常用的赋值方法。意即,在always块中经常使用。

(2)阻塞(blocking)赋值方式(如b=a;): ●赋值语句执行完后,块才结束;

●b的值在赋值语句执行完后立刻就改变;

●在时序逻辑中使用时(在沿触发的always块中使用时),综合后可能会产生意想

19

不到的结果。

前面所举的例子中的“always”模块内的reg型信号都是采用下面的非阻塞赋值方式: b<=a;//这种方式的赋值不是立刻执行的,也就是说“always”块内的下一条语句执行后,b并不等于a,而是保持原来的值,“always”块结束后,才进行赋值。 而阻塞赋值方式,如:

b=a;// 这种赋值方式是立刻执行的,也就是说执行下一条语句时,b已等于a。

对这两种赋值方式,使用不正确则会得到错误的电路结构。下面举例说明: reg b; reg c;

always @(posedge clk) begin

b<=a; c<=b; end

块语句通常用来将两条或多条语句组合在一起,使其在格式上看更像一条语句。块语句有两种:

20

顺序块的特点:

●块内的语句是按顺序执行的,即只有上面一条语句执行完后下面的语句才能执行。 ●每条语句的延迟时间是相对于前一条语句的仿真时间而言的。 ●直到最后一条语句执行完,程序流程控制才跳出该语句块。

并行块的特点:

(1)块内语句是同时执行的,即程序流程控制一进入到该并行块,块内语句则开始同时并行地执行。

(2)块内每条语句的延迟时间是相对于程序流程控制进入到块内的仿真时间。 (3)延迟时间是用来给赋值语句提供执行时序的。

(4)当按时间时序排序在最后的语句执行完后或一个disable语句执行时,程序流程控制跳出该程序块。

在并行块和顺序块中都有一个起始时间和结束时间的概念。 对于顺序块,起始时间就是第一条语句开始被执行的时间,结束时间就是最后一条语句执行完的时间; 对于并行块,起始时间对于块内所有的语句是相同的,即程序流程控制进入该块的时间,其结束时间是按时间排序在最后的语句执行结束的时间。

当一个块嵌入另一个块时,块的起始时间和结束时间是很重要的。跟在块后面的语句在该块的结束时间到了才能开始执行,也就是说,只有该块完全执行完后,后面的语句才可以执行。

在fork_join块内,各条语句不必按顺序给出,因此在并行块里,各条语句在前还是在后是无关紧要的。

(六)条件语句(if_else语句)

if语句是用来判定所给定的条件是否满足,根据判定的结果(真或假)决定执行给出的两种操作之一。if语句在生成电路时具有优先级!因此,类似优先级编码器的电路可用if语句描述。

条件语句必须在过程块语句中使用。所谓过程块语句是指由initial和always语句引导的执行语句集合。除了这两种块语句引导的begin end块中可以编写条件语句外,模块中的其他地方都不能编写。

Verilog HDL提供了3种形式得if语句。3种形式的if语句在if后面都有“表达式”,一般为逻辑表达式或关系表达式。系统对表达式的值进行判断,若为0,x,z,按“假”处理;若为1,按“真”处理,执行指定的语句。

在if和else后面可以包含一个内嵌的操作语句,也可以有多个操作语句,此时用begin和end这两个关键词将几个语句包含起来成为一个复合块语句。如:

if(a>b) begin out1<=int1; out2<=int2; end else begin out1<=int2; out2<=int1;

21

end

if语句的嵌套。在if语句中又包含一个或多个if语句称为if语句的嵌套。一般形式如下:

if(epression1)

if(expression2) 语句1;(内嵌if) else 语句2; else

if(expression3) 语句3;(内嵌if) else 语句4;

应当注意if与else的配对关系,else总是与它上面最近的if配对。如果if与else的数目不一样,为了实现程序设计者的目的,可以用begin_end块语句来确定配对关系。

(七)case语句

一般形式如下:

(1) case (表达式) endcase (2) casez (表达式) endcase (3) casex (表达式) endcase case分支项的一般格式如下:

分支表达式: 语句; 默认项(default项): 语句; 说 明:

(1)case括弧内的表达式称为控制表达式,case分支项中的表达式称为分支表达式。 (2)当控制表达式的值与分支表达式的值相等时,执行分支表达式后面的语句。如果所有的分支表达式的值都没有与控制表达式的值相匹配,就执行default后面的语句。

(3)一个case语句里只准有一个default项。对于default项:

若分支表达式将所有情况列出,可不写default项;若有未列出的可能值,应写default项。

(4)每一个case分项的分支表达式的值必须互不相同,否则就会出现矛盾(对表达式的同一个值,有多种执行方案)。

(5)执行完case分项后的语句,则跳出该case语句结构,终止case语句的执行。(注:与C语言不同,Verilog中的case语句不需要写break)

(6)在用case语句表达式进行比较的过程中,只有当信号的对应位的值能明确进行比较时,比较才能成功。因此,要注意详细说明case分项的分支表达式的值。

(7)case语句的所有表达式值的位宽必须相等,只有这样,控制表达式和分支表达式才能进行对应位的比较。一个经常犯的错误是用’bx,’bz来替代n’bx,n‘bz,这是不对的,因为信号x,z的默认宽度是机器的字节宽度,通常是32位(此处n是case控制表达式的位宽)。

下面将给出 case, casez, casex 的真值表:

22

case语句与if_else_if语句的区别主要有两点:

(1)与case语句中的控制表达式和多分支表达式这种比较结构相比,if_else_if结构中的条件表达式更为直观一些。

(2)对于那些分支表达式中存在不定值x和高阻值z的位时,case语句提供了处理这种情况的手段。

(3)if语句具有优先级,可用于描述具有优先级的电路;case语句不具有优先级,只能用于描述无优先级的电路。

为避免产生不必要的锁存器,应遵循下面两个原则: 1、如果用到if语句,最好写上else项; 2、如果用case语句,最好写上default项。

(八)循环语句

forever语句的格式如下:

forever 语句; 或

forever begin

多条语句 end

forever循环语句常用于产生周期性的波形,作为仿真测试信号。它与always语句不同之处在于它不能独立写在程序中,而必须写在initial块中。

repeat语句的格式如下:

repeat(表达式) 语句; 或

repeat(表达式) begin

多条语句 end

在repeat语句中,其表达式通常为常量表达式。repeat 循环语句执行指定循环数,如果循环计数表达式的值不确定,即为 x 或z 时,那么循环次数按 0 处理。

while语句的格式如下: while(表达式) 语句 或 while(表达式)

begin

多条语句

23

end for语句的一般形式为: for(表达式1;表达式2;表达式3) 语句; 它的执行过程为: (1)先求解表达式1。

(2)再求解表达式2,若其值为真(非0),则执行for语句中指定的内嵌语句,然后执行下面的第3步;若为假(0),则结束循环,转到第(5)步。 ‘

(3)若表达式2为真,在执行指定的语句后,求解表达式3。 (4)转回第(2)步继续执行。 (5)执行for语句下面的语句。

for语句最简单的应用形式是很容易理解的,其形式如下: for(循环变量赋初值;循环结束条件;循环变量增值) 执行语句;

(九)结构说明语句

Verilog语言中的任何过程模块都从属于以下4种结构的说明语句: initial说明语句 always说明语句 task说明语句 function说明语句

一个程序模块可以有多个initial和always过程块。每个initial和always语句在仿真的一开始同时立即开始执行。initial语句只执行一次,而always语句则是不断地重复活动着,直到仿真过程结束。

always语句后跟着的过程块是否运行,要看它的触发条件是否满足,如满足则运行过程块一次,再次满足则再运行一次,直至仿真过程结束。

(注:无条件的always语句是不允许的,将造成仿真死锁!如:always clock=~clock;) 在一个模块中,使用initial和always语句的次数是不受限制的。 task和function语句可以在程序模块中的一处或多处调用。 1、initial语句的格式如下: initial begin

语句1; 语句2; …… 语句n; end

用initial 块对存储器变量赋初始值:在这个例子中则是用initial语句在仿真开始时对各变量进行初始化,注意这个初始化过程不需要任何时间,即在0ns时间内,便可以完成存储器的初始化工作。

initial begin

areg=0; //初始化寄存器areg

for(index=0;index

24

memory[index]=0; /*初始化一个memory,即memory[0]=0,memory[1]=0,memory[2]=0……,直到memory[size-1]=0*/

end

用initial语句来生成激励波形。 initial

begin

inputs=’b000000; //初始时刻为0 #10 inputs=’b011001; #10 inputs=’b011011; #10 inputs=’b011000; #10 inputs=’b001000; end

从这个例子中,我们可以看到initial语句的另一用途,即用initial语句来生成激励波形作为电路的测试仿真信号。注意:一个模块中可以有多个initial块,它们都是并行运行的。initial块常用于测试文件的编写,用来产生仿真测试信号和设置信号记录等仿真环境。

2、always语句 声明格式如下: always <时序控制> <语句>

always语句在仿真过程中是不断活动着的,但always语句后跟着的过程块是否执行,则要看它的触发条件是否满足,如满足则运行过程块一次;如不断满足,则不断地循环执行。

always语句由于其不断重复执行特性,只有和一定的时序控制结合在一起才有用。如果一个always语句没有时序控制(条件或延时),则这个always语句将会生成一个仿真死锁。例如:

always areg=~areg;

这个always语句将会生成一个0延迟的无限循环跳变过程,这时会发生仿真死锁。但如果加上时序控制,则将变为一条非常有用的描述语句,如:

always #half_period areg=~areg; 上面的语句生成了一个周期为:period=2*half_period的无限延续的信号波形。常用这种方法描述时钟信号,并作为激励信号来测试所设计的电路。

reg [7:0] counter; reg tick;

always @(posedge areg) begin

tick=~tick;//每当areg信号的上升沿出现时则把tick信号反相 counter=counter+1;//产生计数器电路 end

always的时间控制可以是边沿触发也可以是电平触发;沿触发的always块用于描述时序逻辑,如有限状态机;电平触发的always块用来描述组合逻辑。

可以是单个信号也可以是多个信号,当有多个信号时中间需要用关键字or连接。关键词“or”也可以用“,”代替。当需要将所有输入信号列入敏感列表时,可以使用两种方法简化书写: @* 和 @(*)

一个模块中可以有多个always块,它们都是并行运行的,多个always块没有前后之分。 关键字wait表示等待电平敏感的条件为真。

Always wait (count_enable) #20 count=count+1;

25

3、函数和任务

task和function说明语句的不同点:

(1)函数只能与主模块共用同一个仿真时间单位,而任务可以定义自己的仿真时间单位。 (2)函数不能启动任务,而任务能启动其他任务和函数。

(3)函数至少要有一个输入变量,而任务可以没有或有多个任何类型的输入变量。 (4)函数返回一个值,而任务则不返回值。 task和function的调用方法不同,例如:

定义一任务或函数对一个16位的字进行操作,让高字节与低字节互换,把它变为另一个字(假定这个任务或函数名为:switch_bytes)。

任务返回的结果是通过输出端口的变量,因此,16位字字节互换任务的调用为: switch_bytes(old_word,new_word);

任务switch_bytes把输入old_word的字的高、低字节互换放入new_word端口输出,而函数返回的新字是通过函数本身的返回值,因此,16位字字节互换函数的调用为:

new_word=switch_bytes(old_word); (1)任务的定义。定义任务的语法如下: task <任务名>;

<端口及数据类型声明语句> <语句1> <语句2> …… <语句n> endtask (2)任务的调用及变量的传递

启动任务并传递输入,输出变量的声明语句的语法如下: 任务的调用:

<任务名> (端口1,端口2,…,端口n); (3)函数的目的是返回一个用于表达式的值。 定义函数的语法:

function <返回值的类型或范围> (函数名); <端口说明语句> <变量类型说明语句> begin <语句> …… end endfunction

注意:<返回值的类型或范围>这一项是可选项,如缺省则返回值为一位寄存器类型数据。

函数的调用:

函数的调用是通过将函数作为表达式中的操作数来实现的。其调用格式如下: 变量=<函数名> (<表达式>, <表达式>, ……); 其中,函数名作为确认符。

下面的例子中通过对两次调用函数getbyte的结果进行位拼接运算来生成一个字:

26

word=control?{getbyte(msbyte),getbyte(lsbyte)}:0; 函数的使用规则:

与任务相比较,函数的使用有较多的约束。下面给出的是函数的使用规则: ●函数的定义不能包含有任何的时间控制语句,即任何用#、@或wait 来标识的语句;

●函数不能启动任务;

●定义函数时至少要有一个输入参数;

●在函数的定义中必须有一条赋值语句给函数的一个内部变量赋结果值,该内部变量和函数同名。

(十)常用的系统任务

在Verilog HDL语言中,每个系统函数和任务前面都用一个标识符$来确认。这些系统函数和任务提供了非常强大的功能。下面对一些常用的系统函数和任务逐一加以介绍。 1、 $display和$write任务 格式:

$display(p1,p2,…,pn); $write(p1,p2,…,pn);

这两个函数和系统任务是用来输出信息,即将参数p2~pn按参数p1给定的格式输出。参数p1通常称为“格式控制”,参数p2~pn通常称为“输出表列”。这两个任务的作用基本相同。

$display自动地在输出后进行换行,$write则不进行自动换行。如果想在一行里输出多个信息,可以使用$write。在$display和$write中,其输出格式控制是用双引号括起来的字符串。

普通字符,即需要原样输出的字符。其中一些特殊的字符可以通过下表给出的转换序列来输出。表中的字符形式用于格式字符串参数中,用来显示特殊的字符。

27

在$display和$write的参数列表中,“输出列表”是需要输出的一些数据,可以是表达式。下面举几个例子加以说明。

module disp; initial begin

$display(“\\\\\\t%%\\n\\”\\123”); end

endmodule; 输出结果为: \ % “S

从上面的这个例子中可以看到一些特殊字符的输出形式(八进制数123就是字符S)。 module disp;

reg [31:0] rval; pulldown(pd); initial begin

rval=101;

$display(“rval=%h hex %d declmal”,rval,rval); $display(“rval=%o otal %b binary”,rval,rval); $displsy(“rval has%c ASCII character value”,rval); $display(“current scop is %m”);

$display(“%s is ascii value for 101”,101); $display(“simulation time is %t”,$time); end endmodule 其输出结果为:

rval=00000065 hex 101 decimal

rval=00000000145 octal 00000000000000000000000001100101 binary rval has e ascii character Value current scope is disp e is ascii value for 101 simulation time is 0 又如:

module printval; reg [11:0] r1; lnitial begin

r1=10;

$display(“Printing with maximum size=%d=%h”,r1,r1); $display(“Printing with minimum size=%0d=%0h”,r1,r1); end

endmodule 输出结果为:

28

Printing with maximum size=10=00a: Printing with minimum size =10=a;

如果输出列表中表达式的值包含有不确定的值或高阻值,其结果输出遵循以下规则。 (1)在输出格式为十进制的情况下:

●如果表达式值的所有位均为不定值,则输出结果为小写的x, ●如果表达式值的所有位均为高阻值,则输出结果为小写的z; ●如果表达式值的部分位为不定值,则输出结果为大写的X; ●如果表达式值的部分位为高阻值,则输出结果为大写的Z。 (2)在输出格式为十六进制和八进制的情况下:

●每4位二进制数为一组代表1位十六进制数,每3位二进制数为一组代表1位八进制数。

●如果表达式值相对应的某进制数的所有位均为不定值,则该位进制数的输出的结果为小写的x。

●如果表达式值相对应的某进制数的所有位均为高阻值,则该位进制数的输出结果为小写的z。

●如果表达式值相对应的某进制数的部分位为不定值,则该位进制数输出结果为大写的X。

●如果表达式值相对应的某进制数的部分位为高阻值,则该位进制数输出结果为大写的Z。

对于二进制输出格式,表达式值的每一位的输出结果为0、1、x、z。下面举例说明:

$display(‘‘%d”,1’bx); //输出结果为: x $display(“%h”,14’bx0_1010); //输出结果为:xxXa

$display(“%h%o”,12’b001x_xx10_1x01,12’b001_xxx_101_x01);//输出结果为:XXX 1x5X 因为$write在输出时不换行,要注意它的使用。可以在$write中加入换行符\n,以确保明确的输出显示格式。

2、$strobe系统任务与$display使用方法相同。它们之间的区别在于:如果许多其他语句与$display任务在同一个时间单位执行,那么这些语句与$display任务的执行顺序是不确定的。而$strobe总是在同时刻的其他赋值语句执行完成后才执行。

3、系统任务$monitor 格式:

$monitor(p1,p2,…,pn); $monitor; $monltoron; $monitoroff;

作用:监控和输出参数列表中的表达式或变量值。其参数列表的规则和$display一样。 当启动一个带有一个或多个参数的$monitor任务时,每当参数列表中变量或表达式的值发生变化时,整个参数列表中变量或表达式的值都将输出显示。如果同一时刻,两个或多个参数的值发生变化,则在该时刻只输出显示一次。但在$monitor中,参数可以是$time系统函数。这样,参数列表中变量或表达式的值同时发生变化的时刻可以通过标明同一时刻的多行输出来显示。如:

$monitor($time,,“rxd=%b txd=%b”,rxd,txd); 注:,,表示空参数,显示为空格。

$monitoron和$monitoroff这两个任务的作用是通过打开和关闭监控标志来控制、监控任

29

务$monitor的启动和停止。

$monitor与$display的不同之处还在于$monitor往往在initial块中调用,只要不调用$monitoroff,$monitor便不间断地对其所设定的信号进行监视。

4、系统函数$time

$time可以返回一个以64位的整数来表示当前的仿真时刻值。该时刻是以模块的仿真时间尺度为基准的。下面举例说明。

[例7.1]

`timescale 10 ns/1ns module test; reg set;

parameter p=1.6; initial begin

$monitor($time,,“set=”,set); #p set=0; #p set=1; end endmodule 输出结果为: 0 set=x 2 set=0 3 set=1

在这个例子中,模块test想在时刻为16 ns时将寄存器set设置为0,在时刻为32ns时将寄存器设置set为1。但是由$time记录的set变化时刻却和预想的不一样。这是由下面两个原因引起的:

(1)$time显示时刻受时间尺度比例的影响。在例7.1中,时间尺度是10 ns,因为$time输出的时刻总是时间尺度的倍数,这样将16 ns和32ns输出为1.6和3.2。

(2)因为$time总是输出整数,所以在输出经过尺度比例变换的数字输出时,要先进行取整。在例7.1中,1.6和3.2经取整后为2和3输出。在这里,时间的精确度并不影响数字的取整。

5、$realtime系统函数

$realtime和$time的作用是一样的,只是$realtime返回的时间数字是一个实型数,该数字也是以时间尺度为基准的。下面举例说明:

[例7.2]

`timescale 10ns/1ns module test; reg set;

parameter p=1.55; initial begin

$monitor($realtime,,“set=”,set); #p set=0: #p set=1; end

30

endmodule

从这个例子可以看出,$realtime将仿真时刻经过尺度变换以后即输出,不需进行取整操作。所以,$realtime返回的时刻是实型数。

6、系统任务$finish 格式: $finish; $finish(n);

系统任务$finish的作用是退出仿真器,返回主操作系统,也就是结束仿真过程。任务$finish可以带参数,根据参数的值输出不同的特征信息。如果不带参数,默认$finish的参数值为1。下面给出了对于不同的参数值,系统输出的特征信息:

0——不输出任何信息;

1——输出当前仿真时刻和位置;

2——输出当前仿真时刻,位置和在仿真过程中所用memory及CPU时间的统计。 7、系统任务$stop 格式: $stop; $stop(n);

$stop任务的作用是把EDA工具(例如仿真器)置成暂停模式,在仿真环境下给出一个交互式的命令提示符,将控制权交给用户。这个任务可以带有参数表达式。根据参数值(0,1或2)的不同,输出不同的信息。参数值越大,输出的信息越多。

8、系统任务$readmemb和$readmemh(了解) 9、系统任务random

这个系统函数提供了一个产生随机数的手段。当函数被调用时返回一个32位的随机数。它是一个带符号的整型数。

$random一般的用法是:$random%b,其中b>O。它给出了一个范围在(-b+1):(b-1)中的随机数。下面给出一个产生随机数的例子:

reg [23:0]rand; rand=$random%60;

上面的例子给出了一个范围在-59到59之间的随机数,下面的例子通过位拼接操作产生一个值在0~59之间的数。

reg[23:0]rand;

rand={$random}%60;

利用这个系统函数可以产生随机脉冲序列或宽度随机的脉冲序列,以用于电路的测试。例7.3中的Verilog HDL模块可以产生宽度随机的随机脉冲序列的测试信号源,在电路模块的设计仿真时非常有用。可以根据测试的需要,模仿下例,灵活使用$random系统函数编制出与实际情况类似的随机脉冲序列。

[例7.3]

`timescale 1ns/1ns

31

module random_pulse(dout); output [9:0] dout; reg [9:0] dout;

integer delay1,delay2,k; initial begin

#10 dout=0;

for(k=0;k<100;k=k+1) begin

delay1=20 * ({$random}%6); //delay1在0到100 ns间变化 delay2=20 * (1+{$random}%3); //delay2在20到60 ns间变化 #delay1 dout=1<<({$random)%10);/*dout的0~9位中随机出现1,并出现的时间

在0~100 ns间变化*/

#delay2 dout=0; //脉冲的宽度在在20到60 ns间变化 end end endmodule

(十一)编译指令

以`(反引号或称着重号)开始的某些标识符是编译器指令。在Verilog 语言编译时,特定的编译器指令在整个编译过程中有效(编译过程可跨越多个文件),直到遇到其它的不同编译程序指令。

1、宏定义`define

用一个指定的标识符(即名字)来代表一个字符串,它的一般形式为: `define标识符(宏名) 字符串(宏内容) 如:

`define signal string

它的作用是指定用标识符signal来代替string这个字符串,在编译预处理时,把程序中在该命令以后所有的signal都替换成string。这种方法使用户能以一个简单的名字代替一个长的字符串,也可以用一个有含义的名字来代替没有含义的数字和符号,因此把这个标识符(名字)称为“宏名”。在编译预处理时将宏名替换成字符串的过程称为“宏展开”。`define是宏定义命令。

`undef 指令取消前面定义的宏。例如: `define WORD 16 //建立一个文本宏替代。 . . .

wire [ `WORD : 1] Bus; . . .

`undef WORD // 在`undef编译指令后, WORD的宏定义不再有效.

2、“文件包含”处理`include

所谓“文件包含”处理是一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包含到本文件之中。Verilog HDL语言提供了`include命令来实现“文件包含”的

32

操作。其一般形式为:

`include“文件名”

`include文件既可以用相对路径名定义,也可以用全路径名定义, 例如: `include \

编译时,这一行由文件“../../primitives.v” 的内容替代。

3、时间尺度timescale

`timescale命令用来说明跟在该命令后的模块的时间单位和时间精度。使用'timescale命令可以在同一个设计里包含采用了不同的时间单位的模块。例如,一个设计中包含了两个模块,其中一个模块的时间延迟单位为ns,另一个模块的时间延迟单位为ps。EDA工具仍然可以对这个设计进行仿真测试。

`timescale命令的格式如下; `timescale<时间单位>/<时间精度> 在这条命令中,时间单位参量是用来定义模块中仿真时间和延迟时间的基准单位的。时间精度参量是用来声明该模块的仿真时间的精确程度的,该参量被用来对延迟时间值进行取整操作(仿真前),因此该参量又可以被称为取整精度。如果在同一个程序设计里,存在多个’timescale命令,则用最小的时间精度值来决定仿真的时间单位。另外时间精度至少要和时间单位一样精确,时间精度值不能大于时间单位值。

在`timescale命令中,用于说明时间单位和时间精度参量值的数字必须是整数,其有效数字为1,10,100,单位为s,ms,us,ns,ps,fs。

例如:

`timescale 1ns/100ps

表示时延单位为1ns, 时延精度为100ps。`timescale 编译器指令在模块说明外部出现, 并且影响后面所有的时延值。例如:

`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/10 ns(100 ps)。因此,时延值5.22对应5.2 ns, 时延6.17对应6.2 ns。如果用如下的`timescale程序指令代替上例中的编译器指令,

`timescale 10ns/1ns

那么5.22对应52ns, 6.17对应62ns。

在编译过程中,`timescale指令影响这一编译器指令后面所有模块中的时延值,直至遇到另一个`timescale指令或`resetall指令。当一个设计中的多个模块带有自身的`timescale编译指令时将发生什么?在这种情况下,模拟器总是定位在所有模块的最小时延精度上,并且所有时延都相应地换算为最小时延精度。例如,

`timescale 1ns/ 100ps

module AndFunc (Z, A, B); output Z; input A, B;

and # (5.22, 6.17 ) Al (Z, A, B);

33

endmodule

`timescale 10ns/ 1ns 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

AndFunc AF1(GetO, PutA, PutB); endmodule

在这个例子中,每个模块都有自身的`timescale编译器指令。`timescale编译器指令第一次应用于时延。因此,在第一个模块中,5.22对应5.2 ns, 6.17对应6.2 ns; 在第二个模块中5.21对应52 ns, 10.4对应104 ns, 15对应150 ns。如果仿真模块TB,设计中的所有模块最小时间精度为100 ps。因此,所有延迟(特别是模块TB中的延迟)将换算成精度为100 ps。延迟52 ns现在对应520*100 ps,104对应1040*100 ps,150对应1500*100 ps。更重要的是,仿真使用100 ps为时间精度。如果仿真模块AndFunc,由于模块TB不是模块AddFunc的子模块,模块TB中的`timescale程序指令将不再有效。

4、条件编译命令`ifdef、`else、`endif

一般情况下,Verilog HDL源程序中所有的行都将参加编译。但是有时希望对其中的一部分内容只有在满足条件时才进行编泽,也就是对一部分内容指定编译的条件,这就是“条件编译”。有时,希望当满足条件时对一组语句进行编译,而当条件不满足是则编译另一部分。

条件编译命令有以下几种形式。 (1)`ifdef 宏名(标识符): 程序段1 `else 程序段2 `endif

它的作用是当宏名已经被定义过(用'define命令定义),则对程序段1进行编译,程序段2将被忽略;否则编译程序段2,程序段1被忽略。

(2)`ifdef 宏名(标识符): 程序段1 `endif

这里的“宏名”是一个Verilog HDL的标识符,“程序段”可以是Verilog语句组,也可以是命令行。这些命令可以出现在源程序的任何地方。注意:被忽略掉不进行编译的程序段部分也要符合Verilog程序的语法规则。

通常在Verilog HDL程序中用到`ifdef、`else、`endif编译命令的情况有以下几种: ●选择一个模块的不同代表部分; ●选择不同的时序或结构信息;

34

●对不同的EDA工具,选择不同的激励。

(十二)延时(delay)

Verilog HDL模型中的所有时延都根据时间单位定义。 下面是带时延的连续赋值语句实例。

assign #2 Sum = A ^ B; //#2指2个时间单位。

使用编译指令将时间单位与物理时间相关联。这样的编译器指令需在模块描述前定义,如下所示:

` timescale 1ns /100ps /* 说明时延时间单位为1ns并且时间精度为100ps (时间精度是指所有的时延必须被限定

在0.1ns内)。如果此编译器指令所在的模块包含上面的连续赋值语句, #2 代表2ns。如果没有这样的编译器指令, Verilog HDL 模拟器会指定一个缺省时间单位。IEEE Verilog HDL 标准中没有规定缺省时间单位。*/

四、verilog hdl建模方法

(一)数据流描述方式

用数据流描述方式对一个设计建模的最基本的机制就是使用连续赋值语句。连续赋值语句是并发执行的,也就是说各语句的执行顺序与其在描述中出现的顺序无关。连续赋值语句的语法为:

assign [delay] LHS_net = RHS_ expression;

右边表达式使用的操作数无论何时发生变化, 右边表达式都重新计算, 并且在指定的时延后变化值被赋予左边表达式的线网变量。时延定义了右边表达式操作数变化与赋值给左边表达式之间的持续时间。如果没有定义时延值, 缺省时延为0。

下面的例子显示了使用数据流描述方式对2-4解码器电路的建模的实例模型。

`timescale 1ns/ 1ns //编译器指令, 编译器指令`timescale 将模块中所有时延的单位设置为1 ns,时间精度为1 ns module Decoder2x4 (A, B, EN, Z); input A, B, EN;// 3个输入端口A,B,EN output [3:0] Z;// 1个4位输出端口Z

wire Abar, Bbar;// 线网类型说明了两个连线型变量Abar和Bbar assign #1 Abar = ~ A; // 语句 1。 assign #1 Bbar = ~ B; // 语句 2。

assign #2 Z[0] = ~ (Abar & Bbar & EN) ; // 语句 3。 assign #2 Z[1] = ~ (Abar & B & EN) ; // 语句 4。 assign #2 Z[2] = ~ (A & Bbar & EN) ; // 语句 5。 assign #2 Z[3] = ~ (A & B & EN) ; // 语句 6。 endmodule

假设:当EN在第5 ns变化,A在第15 ns变化时,则:

(1)第5ns时,语句3、4、5和6执行。这是因为EN是这些连续赋值语句中右边表达式的操作数。

(2)Z[0]在第7 ns时被赋予新值0。

35

(3)第15ns时,语句1、5和6执行。

(4)执行语句5和6不影响Z[0]和Z[1]的取值。执行语句5导致Z[2]值在第17 ns变为0。执行语句1导致Abar在第16 ns被重新赋值。由于Abar的改变,反过来又导致Z[0]值在第18 ns变为1。

(二)行为描述方式

设计的行为功能使用下述过程语句结构描述: 1) initial语句:此语句只执行一次。

2) always语句:此语句总是循环执行, 或者说此语句重复执行。

只有寄存器类型数据能够在这两种语句中被赋值。寄存器类型数据在被赋新值前保持原有值不变。所有的初始化语句和always语句在0时刻并发执行。

下例为always语句对1位全加器电路建模的示例。 module FA_Seq (A, B, Cin, Sum, Cout); input A, B, Cin; output Sum, Cout; reg Sum, Cout; reg T1, T2, T3;

always @ ( A or B or Cin )

begin

Sum = (A ^ B) ^ Cin; T1 = A & Cin; T2 = B & Cin; T3 = A & B;

Cout = (T1| T2) | T3; end endmodule

模块FA_Seq 有三个输入和两个输出。由于Sum、Cout、T1、T2和T3在always 语句中被赋值,它们被说明为 reg 类型(reg 是寄存器数据类型的一种)。always 语句中有一个与事件控制(紧跟在字符@ 后面的表达式)。相关联的顺序过程(begin-end对)。这意味着只要A、B或Cin 上发生事件,即A、B或Cin之一的值发生变化,顺序过程就执行。在顺序过程中的语句顺序执行,并且在顺序过程执行结束后被挂起。顺序过程执行完成后,always 语句再次等待A、B或Cin上发生的事件。

在顺序过程中出现的语句是过程赋值模块化的实例。模块化过程赋值在下一条语句执行前完成执行。过程赋值可以有一个可选的时延。

延时可以细分为两种类型:

1) 语句间时延: 这是时延语句执行的时延。

2) 语句内时延: 这是右边表达式数值计算与左边表达式赋值间的时延。 下面是语句间时延的示例: Sum = (A ^ B) ^ Cin; #4 T1 = A & Cin;

在第二条语句中的时延规定赋值延迟4个时间单位执行。就是说,在第一条语句执行后等待4个时间单位,然后执行第二条语句。下面是语句内时延的示例。

Sum = #3 (A^ B) ^ Cin;

36

这个赋值中的时延意味着首先计算右边表达式的值, 等待3个时间单位,然后赋值给Sum。

如果在过程赋值中未定义时延,缺省值为0时延,也就是说,赋值立即发生。 下面是initial语句的示例: `timescale 1ns / 1ns module Test (Pop, Pid); output Pop, Pid; reg Pop, Pid;

initial//begin至end语句块内的所有语句是顺序执行的 begin

Pop = 0; //在0 ns时,Pop被赋值为0 Pid = 0; //在0 ns时,Pid被赋值为0

Pop = #5 1; //在5 ns时,Pop被赋值为1

Pid = #3 1; //在5 ns+3ns即第8ns时,Pid被赋值为1

Pop = #6 0; //在5 ns+3ns+6ns即第14ns时,Pop被赋值为0 Pid = #2 0; //在5 ns+3ns+6ns+2ns即第16ns时,Pid被赋值为0 end//本条语句执行后,initial语句永远被挂起(即begin_end语句块结束) endmodule

在行为级模型中,逻辑功能描述采用高级语言结构,如@, while,wait,if, case。

Testbench(test fixture)通常采用行为级描述。所有行为级结构在testbench描述中都可以采用。

RTL模型中数据流都是基于时钟的。任何时钟元件在时钟沿处的行为都要精确描述。RTL级描述是行为级Verilog的子集。

(三)结构化描述形式

在Verilog HDL中可使用如下方式描述结构: 1) 内置门原语(在门级); 2) 开关级原语(在晶体管级);

3) UDP,用户定义的原语(在门级);(不支持综合!) 4) 模块实例 (创建层次结构)。

通过使用线网来相互连接。结构级Verilog适合开发小规模元件,如ASIC和FPGA的单元。综合产生的结果网表通常是结构级的。下面的结构描述形式使用内置门原语描述的全加器电路实例。

下面是MUX的结构级描述,采用Verilog基本单元(门)描述。描述中含有传输延时。 module twomux (out, a, b, sl); input a, b, sl; output out;

not u1 (nsl, sl );

and #1 u2 (sela, a, nsl); and #1 u3 (selb, b, sl);

or #2 u4 (out, sela, selb); endmodule

在这一实例中,模块包含门的实例语句,也就是说包含内置门not、and和or 的实例语

37

句。门实例由线网类型变量nsl、sela、selb互连。由于没有指定的顺序, 门实例语句可以以任何顺序出现;not、and和or是内置门原语;X1、X2、A1等是实例名称。紧跟在每个门后的信号列表是它的互连。

下面的结构描述形式使用内置门原语描述的全加器电路实例。 module FA_Str (A, B, Cin, Sum, Cout); input A, B, Cin; output Sum, Cout; wire S1, T1, T2, T3; xor

X1 (S1, A, B), X2 (Sum, S1, Cin); and

A1 (T3, A, B), A2 (T2, B, Cin), A3 (T1, A, Cin), or

O1 (Cout, T1, T2, T3); endmodule

在这一实例中,模块包含门的实例语句,也就是说包含内置门xor、and和or 的实例语句。门实例由线网类型变量S1、T1、T2和T3互连。由于没有指定的顺序, 门实例语句可以以任何顺序出现;图中显示了纯结构;xor、and和or是内置门原语;X1、X2、A1等是实例名称。紧跟在每个门后的信号列表是它的互连;列表中的第一个是门输出,余下的是输入。例如,S1与xor 门实例X1的输出连接,而A和B与实例X1的输入连接。

4位全加器可以使用4个1位全加器模块描述。下面是4位全加器的结构描述形式。 module FourBitFA (FA, FB, FCin, FSum, FCout ); parameter SIZE = 4; input [SIZE:1] FA, FB; output [SIZE:1] FSum input FCin; input FCout;

wire [ 1: SIZE-1] FTemp; FA_Str

FA1( .A (FA[1]), .B(FB[1]), .Cin(FCin), .Sum(FSum[1]), .Cout(FTemp[2])),

FA2( .A (FA[2]), .B(FB[2]), .Cin(FTemp[1]), .Sum(FSum[2]), .Cout(FTemp[2])),

FA3(FA[3], FB[3], FTemp[2], FSum[3], FTemp[3], FA4(FA[4], FB[4], FTemp[3], FSum[4], FCout); endmodule

在这一实例中,模块实例用于建模4位全加器。在模块实例语句中,端口可以与名称或位置关联。前两个实例FA1和FA2使用命名关联方式,也就是说,端口的名称和它连接的线网被显式描述(每一个的形式都为“.port_name (net_name))。最后两个实例语句,实例FA3和FA4使用位置关联方式将端口与线网关联。这里关联的顺序很重要,例如,在实例FA4中,第一个FA[4]与FA_Str 的端口A连接,第二个FB[4]与FA_Str 的端口B连接,余

38

下的由此类推。

(四)混合设计描述方式

在模块中,结构的和行为的结构可以自由混合。也就是说,模块描述中可以包含实例化的门、模块实例化语句、连续赋值语句以及always语句和initial语句的混合。它们之间可以相互包含。来自always语句和initial语句(切记只有寄存器类型数据可以在这两种语句中赋值)的值能够驱动门或开关,而来自于门或连续赋值语句(只能驱动线网)的值能够反过来用于触发always语句和initial语句。

下面是混合设计方式的1位全加器实例。 module FA_Mix (A, B, Cin, Sum, Cout); input A,B, Cin; output Sum, Cout; reg Cout;

reg T1, T2, T3; wire S1;

xor X1(S1, A, B); // 门实例语句。

always @ ( A or B or Cin ) begin // always 语句。 T1 = A & Cin; T2 = B & Cin; T3 = A & B;

Cout = (T1| T2) | T3; end

assign Sum = S1 ^ Cin; // 连续赋值语句。 endmodule

只要A或B上有事件发生,门实例语句即被执行。只要A、B或Cin上有事件发生,就执行always 语句,并且只要S1或Cin上有事件发生,就执行连续赋值语句。

五、Testbench仿真测试

Verilog HDL不仅提供描述设计的能力,而且提供对激励、控制、存储响应和设计验证的建模能力。激励和控制可用初始化语句产生。验证运行过程中的响应可以作为“变化时保存”或作为选通的数据存储。最后,设计验证可以通过在初始化语句中写入相应的语句自动与期望的响应值比较完成。

下面是测试模块Top的例子。该例子测试上述P.36中讲到的FA_Seq模块。 `timescale 1ns/1ns

module Top; // 一个模块可以有一个空的端口列表。 reg PA, PB, PCi; wire PCo, PSum;

// 正在测试的实例化模块:

FA_Seq F1(PA, PB, PCi, PSum, PCo); // 定位。 initial

39

begin: ONLY_ONCE

reg [3:0] Pal; //需要4位, Pal才能取值8。 for (Pal = 0; Pal < 8; Pal = Pal + 1) begin

{PA, PB, PCi} = Pal;

#5 $display (“PA, PB, PCi = %b%b%b”, PA, PB, PCi, “ : : : PCo, PSum=%b%b”, PCo, PSum); end end

endmodule

在测试模块描述中使用位置关联方式将模块实例语句中的信号与模块中的端口相连接。也就是说,PA连接到模块FA_Seq的端口A,PB连接到模块FA_Seq的端口B,依此类推。注意初始化语句中使用了一个for循环语句,在PA、PB和PCi上产生波形。for 循环中的第一条赋值语句用于表示合并的目标。自右向左,右端各相应的位赋给左端的参数。初始化语句还包含有一个预先定义好的系统任务。系统任务$display将输入以特定的格式打印输出。

系统任务$display调用中的时延控制规定$display任务在5个时间单位后执行。这5个时间单位基本上代表了逻辑处理时间。即是输入向量的加载至观察到模块在测试条件下输出之间的延迟时间。

这一模型中还有另外一个细微差别。Pal在初始化语句内被局部定义。为完成这一功能,初始化语句中的顺序过程(begin-end)必须标记。在这种情况下, ONLY_ONCE是顺序过程标记。如果在顺序过程内没有局部声明的变量,就不需要该标记。下面是测试模块产生的输出。

PA, PB, PCi = 000 ::: PCo, PSum = 00 PA, PB, PCi = 001 ::: PCo, PSum = 01 PA, PB, PCi = 010 ::: PCo, PSum = 01 PA, PB, PCi = 011 ::: PCo, PSum = 10 PA, PB, PCi = 100 ::: PCo, PSum = 01 PA, PB, PCi = 101 ::: PCo, PSum = 10 PA, PB, PCi = 110 ::: PCo, PSum = 10 PA, PB, PCi = 111 ::: PCo, PSum = 11

验证与非门交叉连接构成的RS_FF模块的测试模块如下例所示。 `timescale 10ns/1ns

module RS_FF (Q, Qbar, R, S); output Q, Qbar; input R, S;

nand #1 (Q, R, Qbar); nand #1 (Qbar, S, Q,);

//在门实例语句中,实例名称是可选的。 endmodule module Test; reg TS, TR; wire TQ, TQb;

40

//测试模块的实例语句:

RS_FF NSTA (.Q(TQ), .S(TS), .R(TR), .Qbar(TQb)); //采用端口名相关联的连接方式。 // 加载激励: initial begin: TR = 0; TS = 0; #5 TS = 1; #5 TS = 0; TR = 1; #5 TS = 1; TR = 0; #5 TS = 0; #5 TR = 1; end

//输出显示: initial

$monitor (\TQb);

endmodule

RS_FF模块描述了设计的结构。在门实例语句中使用门时延;例如,第一个实例语句中的门时延为1个时间单位。该门时延意味着如果R或Qbar假定在T时刻变化,Q将在T+1时刻获得计算结果值。

模块Test是一个测试模块。测试模块中的RS_FF用实例语句说明其端口用端口名关联方式连接。在这一模块中有两条初始化语句。第一个初始化语句只简单地产生TS和TR上的波形。这一初始化语句包含带有语句间时延的程序块过程赋值语句。

第二条初始化语句调用系统任务$monitor。这一系统任务调用的功能是只要参数表中指定的变量值发生变化就打印指定的字符串。下面是测试模块产生的输出。请注意`timescale指令在时延上的影响。

At time 0, TR=0, TS=0, TQ=x, TQb= x At time 10, TR=0, TS=0, TQ=1, TQb= 1 At time 50, TR=0, TS=1, TQ=1, TQb= 1 At time 60, TR=0, TS=1, TQ=1, TQb= 0 At time 100, TR=1, TS=0, TQ=1, TQb= 0 At time 110, TR=1, TS=0, TQ=1, TQb= 1 At time 120, TR=1, TS=0, TQ=0, TQb= 1 At time 150, TR=0, TS=1, TQ=0, TQb= 1 At time 160, TR=0, TS=1, TQ=1, TQb= 1 At time 170, TR=0, TS=1, TQ=1, TQb= 0 At time 200, TR=0, TS=0, TQ=1, TQb= 0 At time 210, TR=0, TS=0, TQ=1, TQb= 1 At time 250, TR=1, TS=0, TQ=1, TQb= 1 At time 260, TR=1, TS=0, TQ=0, TQb= 1

41

六、有限状态机

有限状态机(Finite State Machine)是由寄存器组和组合逻辑构成的硬件时序电路; - 其状态(即由寄存器组的1和0的组合状态所构成的有限个状态)只能在同一时钟跳变沿的情况下才能从一个状态转向另一个状态;

- 究竟转向哪一状态不但取决于各个输入值,还取决于当前状态。

- 状态机可用于产生在时钟跳变沿时刻开关的复杂的控制逻辑,是数字逻辑的控制核心。

图12.1表示的是时钟同步状态机的结构。

状态寄存器是由 一组触发器组成,用来记忆状态机当前所处的状态。如果状态寄存器由n个触发器组成,这个状态机最多可以记忆2n个状态。 所有的触发器的时钟端都连接在—个共同的时钟信号上,所以状态的改变只可能发生在时钟的跳变沿时刻。可能发生的状态的改变由正跳变还是由负跳变触发,取决于触发器的类型。状态是否改变、怎样改变还将取决于产生下一状态的组合逻辑F的输出,F是当前状态和输入信号的函数。状态机的输出是由输出组合逻辑G提供的,G也是当前状态和输入信号的函数。

图中的F和G两部分都是纯组合逻辑,它们的逻辑函数表达式如下:

下一个状态=F(当前状态,输入信号); 输出信号=G(当前状态,输入信号);

举例:

42

图中所示的状态转移图表示了一个4状态的有限状态机,它的同步时钟是Clock,输入信号是A和Reset,输出信号是K2和K1。状态的转移只能在同步时钟(Clock)的上升沿时发生,往哪个状态的转移则取决于目前所在的状态和输入的信号(Reset和A)。

例一:用格雷码

module fsm(Clock,Reset,A,K2,K1); input Clock,Reset,A; output K2,K1; reg K2,K1; reg [1:0] state;

parameter Idle=2'b00,Start=2'b01,Stop=2'b10,Clear=2'b11;//状态编码,格雷码方式 //

always @(posedge Clock)) //该进程定义起始状态 if(!Reset) begin

state<=Idle;K2<=0;K1<=0; end

else//状态转换 case(state)

Idle: if(A) begin

state<=Start; K1<=0; end else begin state<=Idle; K2<=0;K1<=0; end Start:if(!A) state<=Stop; else state<=Start; Stop:if(A) begin state<=Clear; K2<=1; end else state<=Stop; Clear:if(!A) begin state<=Idle; K2<=0; K1<=1; end else state<=Clear; endcase

endmodule Quartus ii仿真状态图如下:

43

例二、用可综合的Verilog模块设计、用独热码表示状态机

将上文中的parameter一行改为:

parameter Idle=4'b0001,Start=4'b0010, Stop=4'b0100,Clear=4'b1000;

对于用FPGA实现的有限状态机建议采用独热码,因为虽然独热编码多用了两个触发器,但所用组合电路可省一些,因而使电路的速度和可靠性有显著提高,而总的单元数并无显著增加。采用独热编码后出现多余的状态,即一些不可到达的状态,为此.在case语句的最后需要增加default分支项。这可以用默认项表示该项,也可以用确定项表示,以确保回到Idle状态。一般综合器都可以通过综合指令的控制来合理地处理默认项。 如果采用普通的二进制编码,其特点在于从一个状态到相邻状态时,有可能有多个比特位发生变化,如01到10有2比特发生变化,瞬变次数多,容易产生毛刺,引起逻辑错误。

(推荐)例三:用可综合的Verilog模块设计、由输出指定的码表示状态的状态机

例三采用了另一种方法,即在状态机结构部分讲过的,把输出直接指定为状态码。也就是把状态码的指定与状态机控制的输出联系起来,把状态的变化直接用作输出,这样做可以提高输出信号的开关速度并节省电路器件。这种设计方法常用在高速状态机中,建议大家在设计高速状态机时采用例12.3的风格。例中state[3]和state[0]分别表示前面两个例子中的输出K2和K1。

module fsm(Clock,Reset,A,K2,K1); input Clock,Reset,A; output K2,K1; reg [4:0] state;

assign K2=state[3]; assign K1=state[0]; parameter

//----------K2-i---j--K1--输出编码状态分配 Zero= 4’b0_0_0_0,

44

Idle = 4’b0_0_0_1, Start= 4’b0_1_0_0, Stop= 4’b0_0_1_0, Clear=4’b1_0_0_0;

always @(posedge Clock) if(!Reset) begin

state<=Zero; end else

case(state)

Idle,Zero: begin

if(A) begin state<=Start; end

else state<=Idle; end Start: begin if(!A) begin

state<=Clear; end

else state<=Stop; end

Clear: begin if(!A) begin state<=Idle; end

else state<=Clear; end

default: state<=Zero;//避免锁存器的产生 endcase endmodule

(推荐)例四、用可综合Verilog模块设计复杂的多输出状态机时常用的方法

在比较复杂的状态机设计过程中,一般把状态的变化与输出开关的控制分成两部分来考虑,就像前面讲过的Mealy状态机输出部分的组合逻辑。为了调试方便,还常常把每一个输出开关写成一个个独立的always组合块,这样做比较容易发现问题和改正模块编写中出现的问题。建议大家在设计复杂的多输出状态机时采用例12.4所列程序,说明如下。 module fsm(Clock,Reset,A. K2,K1); input Clock,Reset,A; output K2,K1; reg K2,K1; reg [1:0] state;

45

parameter

ldle=2’b00, Start=2’b01, Stop=2’b10, Clear=2’b11;

/*也可用`define语句定义,如`define idle 2’b00 `define start 2’b00 `define stop 2’b00 `define clear 2’b00 */ always @(posedge Clock) if (! Reset) state<=Idle; else

case(state)

Idle: begin if(A) begin state<=start; end

else state<=Idle; end

start:begin if(!A) state<=Stop; else state<= Start; end

Stop:begin if(A) state<=Clear; else state<=Stop; end

Clear:begin if(! A) state<=Idle; else state<=Clear; end

default :state<=2’bxx; endcase

always @(state or Reset or A) //产生输出K2的组合逻辑 if (!Reset) K2=0; else

if ((state==Clear)&&A) K2=1: else K2=0;

always @(state or Reset) //产生输出K1的组合逻辑 if(!Reset) K1=0; else

if((state==Idle) && !A) K1=1; else K1=0; endmodule

有限状态机设计的一般步骤:

46

(1)逻辑抽象,得出状态转换图:就是把给出的一个实际逻辑关系表示为时序逻辑函数。可以用状态转换表来描述,也可以用状态转换图来描述。这就需要:

●分析给定的逻辑问题,确定输入变量、辅出变量以及电路的状态数。通常是取原因(或条件)作为输入变量,取结果作为输出变量。

●定义输入、输出逻辑状态的含义,并将电路状态顺序编号。 ●按照要求列出电路的状态转换表或画出状态转换图。

这样,就把给定的逻辑问题抽象到一个时序逻辑函数了。

(2)状态化简:如果在状态转移图中出现这样两个状态:它们在相同的输入下转换到同一状态去,并得到相同的输出,则称它们为等价状态。显然等价状态是重复的,可以合并为一个。电路的状态数越少,存储电路也就越简单。状态化简的目的就在于将等价状态尽可能地合并,以得到最简的状态转换图。

(3)状态分配:状态分配又称状态编码。通常有很多编码方法,编码方案选择得当,设计的电路可以简单;反之.选得不好,则设计的电路就会复杂许多。在实际设计时,须综合考虑电路复杂度与电路性能这两个因素。在触发器资源丰富的FPGA或ASIC设计中,采用独热编码(one-hot-coding)既可以使电路性能得到保证又可充分利用其触发器数量多的优势,也可以采取输出编码的状态指定来简化电路结构,并提高状态机的运行速度。 (4)选定触发器的类型并求出状态方程、驱动方程和输出方程。 (5)按照方程得出逻辑图。

用Verilog HDL来描述有限状态机,可以充分发挥硬件描述语言的抽象建模能力,使用always块语句和case,if等条件语句及赋值语句即可方便实现。具体的逻辑化简、逻辑电路和触发器映射均可由计算机自动完成上述设计步骤中的第(2)步及(4)、(5)步不再需要很多的人为干预,使电路设计工作得到简化,效率也有很大的提高。

七、modelsim简介

Mentor公司的ModelSim是业界最优秀的HDL语言仿真软件,它能提供友好的仿真环境,是业界唯一的单内核支持VHDL和Verilog混合仿真的仿真器。它采用直接优化的编译技术、Tcl/Tk技术、和单一内核仿真技术,编译仿真速度快,编译的代码与平台无关,便于保护IP核,个性化的图形界面和用户接口,为用户加快调错提供强有力的手段,是FPGA/ASIC设计的首选仿真软件。

主要特点:

· RTL和门级优化,本地编译结构,编译仿真速度快,跨平台跨版本仿真; · 单内核VHDL和Verilog混合仿真; · 源代码模版和助手,项目管理;

· 集成了性能分析、波形比较、代码覆盖、数据流ChaseX、Signal Spy、虚拟对象Virtual Object、Memory窗口、Assertion窗口、源码窗口显示信号值、信号条件断点等众多调试功能;

· C和Tcl/Tk接口,C调试

· 对SystemC的直接支持,和HDL任意混合 · 支持SystemVerilog的设计功能;

· 对系统级描述语言的最全面支持,SystemVerilog,SystemC,PSL · ASIC Sign off。

47

ModelSim分几种不同的版本:SE、PE、LE和OEM,其中SE是最高级的版本,而集成在 Actel、Atmel、Altera、Xilinx以及Lattice等FPGA厂商设计工具中的均是其OEM版本。SE版和OEM版在功能和性能方面有较大差别,比如对于大家都关心的仿真速度问题,以Xilinx公司提供的OEM版本ModelSim XE为例,对于代码少于40000行的设计,ModelSim SE 比ModelSim XE要快10倍;对于代码超过40000行的设计,ModelSim SE要比ModelSim XE快近40倍。ModelSim SE支持PC、UNIX和LINUX混合平台;提供全面完善以及高性能的验证功能;全面支持业界广泛的标准;Mentor Graphics公司提供业界最好的技术支持与服务。

八、用Modelsim进行功能仿真和时序仿真

仿真过程是正确实现设计的关键环节,用来验证设计者的设计思想是否正确,及在设计实现过程中各种分布参数引入后,其设计的功能是否依然正确无误。仿真主要分为功能仿真和时序仿真。功能仿真是在设计输入后进行; 时序仿真是在逻辑综合后或布局布线后进行。

1. 功能仿真 ( 前仿真 )

功能仿真是指在一个设计中, 在设计实现前对所创建的逻辑进行的验证其功能是否正确的过程。 布局布线以前的仿真都称作功能仿真, 它包括综合前仿真( Pre-Synthesis Simulation )和综合后仿真( Post-Synthesis Simulation )。 综合前仿真主要针对基于原理框图的设计 ; 综合后仿真既适合原理图设计 , 也适合基于 HDL 语言的设计。

2. 时序仿真(后仿真)

时序仿真使用布局布线后器件给出的模块和连线的延时信息, 在最坏的情况下对电路的行为作出实际地估价。 时序仿真使用的仿真器和功能仿真使用的仿真器是相同的, 所需的流程和激励也是相同的; 惟一的差别是为时序仿真加载到仿真器的设计包括基于实际布局布线设计的最坏情况的布局布线延时, 并且在仿真结果波形图中,时序仿真后的信号加载了时延, 而功能仿真没有。

3.2.2 仿真工具

1. ModelSim 总体概览

ModelSim 仿真工具是工业上最流行、 最通用的仿真器之一, 可支持 Verilog 、 VHDL 或是 VHDL/ Verilog 混合输入的仿真, 它的 OEM 版本允许 Verilog 仿真或 VHDL 仿真。Model 技术公司共开发了 ModelSim/VHDL 和 ModelSim/Verilog 两 种 ModelSim 产品, 但它又分为不同的版本: OEM 版本 —— ModelSim/LNL 支持 Verilog 或者 VHDL , 但是不同时支持; ModelSim/PLUS 版本 支持混合仿真 Verilog 和 VHDL ; ModelSim/SE 版本支持 PLUS 的所有功能连同附加功能。

1)ModelSim 的仿真实现方式

(1) 交互式的命令行(Cmd)的方式 —— 惟一的界面是控制台的命令行,没有用户界面。

(2) 用户界面UI的方式——可以接受菜单输入和命令行输入的仿真方式。 (3) 批处理模式——从 DOS 或 UNIX 命令行运行批处理文件的仿真方式。 2) ModelSim 基本仿真步骤 (1) 建立数据库。

(2) 映射数据库到物理层目录。

(3) 编译源代码 —— 所有的 HDL 代码必须被编译; Verilog 和 VHDL必须有不

48

同的编译器支持。

(4) 启动仿真器, 执行仿真。 也可以从其他软件上直接调用, 启动内嵌的仿真器执行仿真。

3) ModelSim 的用户界面

ModelSim 仿真器有 9 个窗口: 窗口(main)、结构窗口(structure)、 源窗口(source)、 信号窗口(signals)、 处 理窗口(process)、变量窗口(variables)、 数据流窗口(dataflow)、 波形窗口(wave) 和列表窗口(list)。这些窗口可以通过主窗口中的视窗(View)菜单来打开。由于大部分窗口只是对设计仿真起一个辅助的作用,不是经常用到的, 因 此下面主要介绍的是 main 主窗口和 wave 波形窗口。 ModelSim 的 完整用户界面如图3-6 所示。

4) ModelSim 窗口模块介绍

Main 主窗口 —— 在主窗口中, 可以通过 ModelSim> 提示符来浏览帮助文件、 编辑库、 编辑源代码, 而不用调用一个设计。 启动窗口 Design Menu → Load New Design 可用于选择要加载的设计和其他用于仿真的选项。 Wave 窗口 —— 在波形窗口中, 可通过波形浏览仿真结果的图形记录。 多个波形窗口可用于更多的逻辑信号观察; 可改变信号和向量的数 量, 以改善波形的显示; 可打印波形等。

Structure 窗口 —— 可实现设计的结构多层浏览, 使源窗口( Source )和信号窗口( Signals )等成为当前层。

Source 窗口 —— 可从 Structure 窗口选择, 进行注释、 关键字、 字符串、 数字、 执行行、 标识符、 系统任务、 文本等完全的编辑; 显示所选的 HDL 项的信息; 检查显示所选 HDL 项当前仿真值。

Process 窗口 —— 显示外部和内部的处理功能。 Signals 窗口 —— 紧接结构窗口( Structure ), 显示 Structure 窗口的当前层 HDL 项的名称和值等。

Dataflow 窗口 —— VHDL 信号或 Verilog 信号网络的图形描绘。 List 窗口 —— 用表格显示仿真结果。

Variables 窗口 —— 列出 HDL 项的名称, 显示到当前过程的路径等。

图 3-6 ModelSim 完整用户界面

3.2.3 ModelSim 仿真过程

前面是对ModelSim的一个整体介绍,下面将通过一个具体实例来介绍 ModelSim 的具体使用方法和仿真的过程。 1. 创建一个项目

49

(1) 启动 ModelSim

图 3-7 项目设立对话框

(2) 在主窗口通过选择 File → New → Project → Create a Project 打开项目对话框。

(3) 在项目对话框中键入 test 作为项目的名字, 并选择一个 项目存储的目录位置, 如 Actelprj , 并且缺省的库名设置为 work 。 设置完后的项目对话框如图 4-85 所示。

(4) 点击 OK 按键, 将会看到带有空白 Project 和 Library 标签 的主窗口, 以及 Add itemsto the Project 对话框, 同时项目名称 也在工作空间下面的状态栏中出现。 项目选择页面如图 3-8 所示。

图 3-8 项目选择页面

(5) 加设包含设计内容的源文件到项目中。 在 Add items to the Project 对话框中点击 Add Existing File , 在此以加一个VHDL文件为例。 点击 Browse 按键, 打开 ModelSim 安装目录下的实例目录, 从中选择 counter.vhd , 然后选中 Reference from current location 选项并且点击 OK 按键, 如图3-9所示。

50

本文来源:https://www.bwwdw.com/article/1g8p.html

Top