首页计算机计算机工程EDA技术及数字系统的应用 06 第六章_硬件描述语言Verilog HDL.pptx

06 第六章_硬件描述语言Verilog HDL.pptx

页数:121页文件大小:1.24 MB来源: EDA技术及数字系统的应用ppt课件

本课件系统讲解Verilog HDL,涵盖语言特点与模块端口结构、关键字与标识符规范、数据类型与常量变量、九类运算符、赋值语句与块语句、条件与循环语句、always与initial等结构说明语句、任务与函数,以及不同抽象级别的建模与资源优化。

第六章Verilog HDL学习目标页,说明本章涵盖语言规则、不同抽象级别模型、语法与数字电路设计实例
Verilog HDL概念页,说明其用于数字逻辑电路设计的仿真验证、时序分析与逻辑综合并兼具行为与结构描述能力
Verilog HDL发展历史页,列出1983年GDA首创、1989年Cadence收购、1990年公开发表与1995年IEEE标准
查看本课件的文字版(共 121 页,供检索与复制)

第1页:Verilog HDL学习目标与要求

本章将介绍Verilog HDL设计的基础知识,包括Verilog HDL语言规则、不同抽象级别的Verilog HDL模型、Verilog HDL的语法,以及利用实例说明VerilogHDL进行数字电路设计的过程。第六章硬件描述语言Verilog HDL学习目标和要求:熟悉Verilog HDL的语言特点和语言规则;掌握Verilog HDL的设计流程和语句;掌握Verilog HDL实现各种类型数字电路的方法。

第2页:什么是Verilog HDL

Verilog概述一、什么是VerilogHDL

  • VerilogHDL是一种用于数字逻辑电路设计的硬件描述语言(HradwareDescriptionLanguage),可以用来进行数字电路的仿真验证、时序分析、逻辑综合。
  • 用VerilogHDL描述的电路设计就是该电路的VerilogHDL模型。
  • VerilogHDL既是一种行为描述语言也是一种结构描述语言。
  • 既可以用电路的功能描述,也可以用元器件及其之间的连接来建立VerilogHDL模型。

第3页:Verilog HDL的发展历史

二、VerilogHDL的发展历史

  • 1983年,由GDA(GateWayDesignAutomation)公司的PhilMoorby首创;
  • 1989年,Cadence公司收购了GDA公司;
  • 1990年,Cadence公司公开发表VerilogHDL;
  • 1995年,IEEE制定并公开发表VerilogHDL1364-1995标准;
  • 1999年,模拟和数字电路都适用的Verilog标准公开发表6.1 Verilog概述

第4页:不同层次的Verilog HDL抽象

三、不同层次的VerilogHDL抽象

  • VerilogHDL模型可以是实际电路的不同级别的抽象。抽象级别可分为五级:
  • 系统级(system level):用高级语言结构(如case语句)实现的设计模块外部性能的模型;
  • 算法级(algorithmic level):用高级语言结构实现的设计算法模型(写出逻辑表达式);
  • RTL级(register transfer level):描述数据在寄存器之间流动和如何处理这些数据的模型;
  • 门级(gate level):描述逻辑门(如与门、非门、或门、与非门、三态门等)以及逻辑门之间连接的模型;
  • 开关级(switch level):描述器件中三极管和储存节点及其之间连接的模型。6.1 Verilog概述

第5页:Verilog HDL的特点

四、VerilogHDL的特点

  • 语法结构上的主要特点:
  • 形式化地表示电路的行为和结构;
  • 借用C语言的结构和语句;
  • 可在多个层次上对所设计的系统加以描述,语言对设计规模不加任何限制;
  • 具有混合建模能力:一个设计中的各子模块可用不同级别的抽象模型来描述;
  • 基本逻辑门、开关级结构模型均内置于语言中,可直接调用;
  • 易创建用户定义原语(UDP,User Designed Primitive)。
  • 易学易用,功能强与C语言相似!6.1 Verilog概述

第6页:模块和端口

模块是Verilog HDL设计中的基本功能块,用于描述某个设计的功能或结构,以及它与其他模块进行通信的端口。 端口是模块与外部环境交互的接口和通道(例如IC芯片的输入输出引脚),对模块的调用只能通过其端口进行。6.1.2模块和端口例6.1.1一位全加器的Verilog HDL描述如下,其模块图如图6.1所示。图6.1一位全加器的模块图//定义一位全加器module fulladd(sum, c_out, a, b, c_in);//输入/输出端口声明output sum, c_out;input a, b, c_in;//内部线网声明wire s1, c1, c2;//调用(实例化)逻辑门级原语xor (s1, a, b);and (c1, a, b);xor (sum, s1, c_in);and (c2, s1, c_in);xor (c_out, c2, c1);endmodule

第7页:模块定义

.模块定义模块定义由关键字module开始,以endmodule结束。VerilogHDL结构完全嵌在module和endmodule定义语句之间。每个模块必须具有一个模块名,唯一地标识这个模块.如上例中模块的名称是fulladd。模块的端口列表则描述这个模块的输入和输出端口,上例中模块有5个端口:三个输入端口a、b和c_in,两个输出端口sum和c_out。6.1.2模块和端口需要注意的是,声明部分可以分散于模块的任何地方,但是变量、寄存器、线网和参数等声明必须在使用前出现,通常集中在模块前端一起声明,这样可增强程序的可读性。如果多种语句出现在同一个module中,其相互之间没有任何顺序关系,则它们在module中出现顺序的改变不会改变module的功能,这正是硬件的一大特点。可以想象一下绘制原理图的过程,先画哪个器件,后画哪个器件根本没有任何关系。

第8页:八位计数器设计示例

modulecounter8(out,cout,data,load,cin,clk);output[7:0]out;outputcout;input[7:0]data;inputload,cin,clk;reg[7:0]out;always@(posedgeclk)beginif(load)out<=data;//同步预置数据elseout<=out+1+cin;//加1计数endassigncout=&out&cin;//若out为8'hFF,cin为1,则cout为1endmoduleI/O说明端口定义功能描述信号类型声明缩减运算符位运算符6.1.2模块和端口2.简单的Verilog HDL例子:8位计数器模块名(文件名)

第9页:Verilog HDL程序结构特点

  • VerilogHDL程序是由模块构成的。每个模块嵌套在module和endmodule声明语句中。模块是可以进行层次嵌套的。
  • 每个VerilogHDL源文件中只准有一个顶层模块,其他为子模块。
  • 每个模块要进行端口定义,并说明输入输出端口,然后对模块的功能进行行为逻辑描述。
  • 程序书写格式自由,一行可以写几个语句,一个语句也可以分多行写。
  • 除了endmodule语句、begin_end语句和fork_join语句外,每个语句和数据定义的最后必须有分号。
  • 可用和//...对程序的任何部分作注释。加上必要的注释,以增强程序的可读性和可维护性。总结

第10页:关键字

Verilog HDL的语法1、关键字 关键字——事先定义好的确认符,用来组织语言结构;或者用于定义Verilog HDL提供的门元件(如and,not,or,buf)。 用小写字母定义!——如always,assign,begin,case,casex,else,end,for,function,if,input,output,repeat,table,time,while,wire用户程序中的变量、节点等名称不能与关键字同名!

第11页:Verilog HDL关键字表

VerilogHDL关键字edgeelseendendcaseendfunctionendprimitiveendmoduleendspecifyendtableendtaskeventforforceforeverforkfunctionhighz0highz1ififnoneinitialinoutinputintegerjoinlargemacromodulemediummodulenandnegedgenor notnotif0notif1nmosoroutputparameterpmosposedgeprimitivepulldownpulluppull0pull1andalwaysassignbeginbufbufif0bufif1casecasexcasezcmosdeassigndefaultdefparamdisable6.2 Verilog HDL的语法

第12页:Verilog HDL关键字(续)

VerilogHDL关键字(续)tri0tri1vectoredwaitwandweak0weak1whilewireworxnorxorrcmosrealrealtimeregreleaserepeatrnmosrpmosrtranrtranif0rtranif1scalaredsmallspecifyspecparamstrengthstrong0strong1supply0supply1tabletasktrantranif0tranif1timetritriandtriortrireg6.2 Verilog HDL的语法

第13页:标识符

、标识符

  • 任何用VerilogHDL语言描述的"东西"都通过其名字来识别,这个名字被称为标识符。
  • 如源文件名、模块名、端口名、变量名、常量名、实例名等。
  • 标识符可由字母、数字、下划线和$符号构成;但第一个字符必须是字母或下划线,不能是数字或$符号!
  • 在VerilogHDL中变量名是区分大小写的!
  • 合法的名字:
  • A_99_Z
  • Reset
  • _54MHz_Clock$
  • Module
  • 不合法的名字:
  • 123a
  • $data
  • module
  • 7seg.v标识符不能与关键字同名!6.2 Verilog HDL的语法

第14页:编写Verilog HDL源代码的标准

、编写VerilogHDL源代码的标准

  • 编写VerilogHDL源代码的标准分为两类:(1)语汇代码的编写标准规定了文本布局、命名和注释的约定,以提高源代码的可读性和可维护性。(2)综合代码的编写标准规定了Verilog风格,尽量保证能够综合,以避免常见的不能综合及综合结果存在缺陷的问题,并在设计流程中及时发现综合中存在的错误。
  • 综合:将用HDL语言或图形方式描述的电路设计转换为实际门级电路(如触发器、逻辑门等),得到一个网表文件,用于进行适配(在实际器件中进行布局和布线)。6.2 Verilog HDL的语法

第15页:数据类型

一、数据类型

  • 数据类型是用来表示数字电路中的数据存储和传送单元。
  • VerilogHDL中共有19种数据类型;
  • 其中4个最基本的数据类型为:①integer型②parameter型③reg型④wire型
  • 其它数据类型:large型、medium型、scalared型、small型、time型、tri型、tri0型、tri1型、triand型、trior型、trireg型、vectored型、wand型、wor型等二、常量
  • 在程序运行过程中,其值不能被改变的量,称为常量。①数字(包括整数,x和z值,负数)②parameter常量(或称符号常量)4.数据类型及常量、变量

第16页:整数型常量与进制表示

数据类型及常量、变量

  • 整常数的3种表达方式:举例说明表达方式8'b11000101或8'hc5完整的表达方式<位宽>'<进制> <数字>hc5缺省位宽,则位宽由机器系统决定,至少32位<进制> <数字>197缺省进制为十进制,位宽默认为32位<数字>(1)整数型常量(即整常数)的4种进制表示形式:
  • 二进制整数(b或B);
  • 十进制整数(d或D);
  • 十六进制整数(h或H);
  • 八进制整数(o或O)。
  • 注:这里位宽指对应二进制数的宽度。

第17页:x和z值

数据类型及常量、变量(2)x和z值

  • x表示不定值,z表示高阻值;8'b1001xxxx或8'h9x8'b1010zzzz或8'haz
  • 每个字符代表的二进制数的宽度取决于所用的进制;
  • 当用二进制表示时,已标明位宽的数若用x或z表示某些位,则只有在最左边的x或z具有扩展性!为清晰可见,最好直接写出每一位的值!
  • [例]8'bzx=8'bzzzz_zzzx
  • [例]8'b1x=8'b0000_001x
  • "?"是z的另一种表示符号,建议在case语句中使用?表示高阻态z
  • [例]casez(select)4'b???1:out=a;4'b??1?:out=b;4'b?1??:out=c;4'b1???:out=d;endcase

第18页:负数与下划线

(3)负数

  • 在位宽前加一个减号,即表示负数
  • 如:-8'd5//5的补数,=8'b11111011
  • 减号不能放在位宽与进制之间,也不能放在进制与数字之间!
  • 8'd-5//非法格式
  • 为提高可读性,在较长的数字之间可用下划线_隔开!但不可以用在<进制>和<数字>之间。如:16'b1010_1011_1100_1111//合法8'b_0011_1010//非法
  • 当常量未指明位宽时,默认为32位。
  • 10=32'd10=32'b1010
  • -1=-32'd1=32'b1111……1111=32'hFFFFFFFF

第19页:parameter常量

(4)parameter常量(符号常量)

  • 用parameter来定义一个标识符,代表一个常量——称为符号常量。参数型数据的确认符parameter参数名1=表达式,参数名2=表达式,……;
  • 每个赋值语句的右边必须为常数表达式,即只能包含数字或先前定义过的符号常量!parameteraddrwidth=16;//合法格式parameteraddrwidth=datawidth*2;//非法格式
  • 常用参数来定义延迟时间和变量宽度。
  • 可用字符串表示的任何地方,都可以用定义的参数来代替。
  • 参数是本地的,其定义只在本模块内有效。
  • 在模块或实例引用时,可通过参数传递改变在被引用模块或实例中已定义的参数!赋值语句表格式

第20页:变量与nets型变量

数据类型及常量、变量三、变量

  • 在程序运行过程中,其值可以改变的量,称为变量。
  • 其数据类型有19种,常用的有3种:
  • 网络型(netstype)
  • 寄存器型(registertype)
  • 数组(memorytype)1. nets型变量定义——输出始终随输入的变化而变化的变量。表示结构实体(如门)之间的物理连接。
  • 常用nets型变量:
  • wire,tri:连线类型(两者功能一致)
  • wor,trior:具有线或特性的连线(两者功能一致)
  • wand,triand:具有线与特性的连线(两者功能一致)
  • tri1,tri0:上拉电阻和下拉电阻
  • supply1,supply0:电源(逻辑1)和地(逻辑0)nets型变量不能储存值!

第21页:wire型变量

wire型变量 最常用的nets型变量,常用来表示以assign语句赋值的组合逻辑信号。 模块中的输入/输出信号类型缺省为wire型。 可用做任何方程式的输入,或"assign"语句和实例元件的输出。wire数据名1,数据名2,……,数据名n;wire[n-1:0]数据名1,数据名2,……,数据名m;或wire[n:1]数据名1,数据名2,……,数据名m;每条总线位宽为n共有m条总线wire型向量(总线)格式:

第22页:register型变量

定义——对应具有状态保持作用的电路元件(如触发器、寄存器等),常用来表示过程块语句(如initial,always,task,function)内的指定信号。 常用register型变量: reg:常代表触发器 integer:32位带符号整数型变量 real:64位带符号实数型变量 time:无符号时间变量纯数学的抽象描述2. register型变量

第23页:register型与nets型的区别

  • register型变量与nets型变量的根本区别是:register型变量需要被明确地赋值,并且在被重新赋值前一直保持原值。
  • register型变量必须通过过程赋值语句赋值!不能通过assign语句赋值!
  • 在过程块内被赋值的每个信号必须定义成register型!

第24页:reg型变量

数据类型及常量、变量 reg型变量 定义——在过程块中被赋值的信号,往往代表触发器,但不一定就是触发器(也可以是组合逻辑信号)!reg数据名1,数据名2,……,数据名n;reg[n-1:0]数据名1,数据名2,……,数据名m;或reg[n:1]数据名1,数据名2,……,数据名m;每个向量位宽为n共有m个reg型向量 [例]reg[4:1]regc,regd;//regc,regd为4位宽的reg型向量reg型向量(总线)格式

第25页:用reg型变量生成组合逻辑

用reg型变量生成组合逻辑举例:module rw1( a, b, out1, out2 );input a, b;output out1, out2;reg out1;wire out2;assign out2 = a;always @(b)out1 <= ~b;endmoduleaout2BUFFbINVout1过程赋值语句连续赋值语句电平触发Verilog中reg与wire的区别reg型变量既可生成触发器,也可生成组合逻辑;wire型变量只能生成组合逻辑。

第26页:用reg型变量生成触发器

用reg型变量生成触发器举例:module rw2( clk, d, out1, out2 );input clk, d;output out1, out2;reg out1;wire out2;assign out2 = d & ~out1 ;always @(posedge clk)beginout1 <= d ;endendmodule过程赋值语句连续赋值语句dout2AND2i1clkout1DQDFF沿触发

第27页:运算符的分类

  • 运算符按功能分为9类:
  • 算术运算符
  • 逻辑运算符
  • 关系运算符
  • 等式运算符
  • 缩减运算符
  • 条件运算符
  • 位运算符
  • 移位运算符
  • 位拼接运算符
  • 运算符按操作数的个数分为3类:
  • 单目运算符——带一个操作数逻辑非!,按位取反~,缩减运算符,移位运算符
  • 双目运算符——带两个操作数算术、关系、等式运算符,逻辑、位运算符的大部分
  • 三目运算符——带三个操作数条件运算符6.4.2表达式及运算符

第28页:算术运算符

一、算术运算符说明算术运算符加减乘除求模+-*/%双目运算符

  • 进行整数除法运算时,结果值略去小数部分,只取整数部分;
  • %称为求模(或求余)运算符,要求%两侧均为整型数据;
  • 求模运算结果值的符号位取第一个操作数的符号位;[例]-11%3结果为-2
  • 进行算术运算时,若某操作数为不定值x,则整个结果也为x。表达式及运算符

第29页:除法与求模运算的区别

; [例]除法和求模运算的区别注意/和%的区别!表达式及运算符

第30页:除法和求模运算仿真波形

/4 = 29%4 =1arithmetic.vwf表达式及运算符

第31页:逻辑运算符

二、逻辑运算符

  • 逻辑运算符把它的操作数当作布尔变量:
  • 非零的操作数被认为是真(1'b1);
  • 零被认为是假(1'b0);
  • 不确定的操作数如4'bxx00,被认为是不确定的(可能为零,也可能为非零)(记为1'bx);但4'bxx11被认为是真(记为1'b1,因为它肯定是非零的)。说明逻辑运算符逻辑与逻辑或逻辑非&&(双目)||(双目)!(单目)
  • 进行逻辑运算后的结果为布尔值(为1或0或x)!表达式及运算符

第32页:逻辑运算符的优先级

  • "&&"和"||"的优先级除高于条件运算符外,低于关系运算符、等式运算符等几乎所有运算符;
  • 逻辑非"!"优先级最高。
  • [例](a>b)&&(b>c)可简写为:a>b&&b>c(a==b)||(x==y)可简写为:a==b||x==y(!a)||(a>b)可简写为:!a||a>b为提高程序的可读性,明确表达各运算符之间的优先关系,建议使用括号!表达式及运算符

第33页:位运算符

三、位运算符说明位运算符按位取反按位与按位或按位异或按位同或~&|^^~,~^双目运算符单目运算符

  • 位运算其结果与操作数位数相同。位运算符中的双目运算符要求对两个操作数的相应位逐位进行运算。
  • 两个不同长度的操作数进行位运算时,将自动按右端对齐,位数少的操作数会在高位用0补齐。[例]若A=5'b11001,B=3'b101,则A&B=(5'b11001)&(5'b00101)=5'b000015.表达式及运算符

第34页:&&运算符与按位与的区别

; [例]&&运算符和&(按位与)的区别&&运算的结果为1位的逻辑值注意&&和&的区别!被认为是1'b1被认为是1'bx逻辑与结果为1'bx表达式及运算符

第35页:关系运算符

四、关系运算符说明关系运算符小于小于或等于大于大于或等于<<=>>=双目运算符括号内先运算!算术运算先运算!

  • 运算结果为1位的逻辑值1或0或x。关系运算时,若关系为真,则返回值为1;若声明的关系为假,则返回值为0;若某操作数为不定值x,则返回值为x。
  • 所有的关系运算符优先级别相同。
  • 关系运算符的优先级低于算术运算符。
  • [例]a<size-1等同于:a<(size-1)size-(1<a)不等同于:size-1<a表达式及运算符

第36页:等式运算符

五、等式运算符说明等式运算符等于不等于全等不全等==!====!==双目运算符

  • 运算结果为1位的逻辑值1或0或x。
  • 等于运算符(==)和全等运算符(===)的区别:
  • 使用等于运算符时,两个操作数必须逐位相等,结果才为1;若某些位为x或z,则结果为x。
  • 使用全等运算符时,若两个操作数的相应位完全一致(如同是1,或同是0,或同是x,或同是z),则结果为1;否则为0。
  • 所有的等式运算符优先级别相同。
  • ===和!==运算符常用于case表达式的判别,又称为"case等式运算符"。Quartus II都不支持!表达式及运算符

第37页:等于与全等运算符示例

; [例]if(A==1'bx)$display("AisX");//当A为不定值时,式(A==1'bx)的运算结果为x,则该语句不执行if(A===1'bx)$display("AisX");//当A为不定值时,式(A===1'bx)的运算结果为1,该语句执行0 1 x z==10 x x01x xx x x xx x x x01xz0 1 x z===10 0 0010 00 0100 0 0101xz表3-1 "= ="的真值表表3-2 "= = ="的真值表等于运算的结果可能为1或0或x全等于运算的结果只有1或0表达式及运算符

第38页:缩减运算符

六、缩减运算符说明缩减运算符与与非或或非异或同或&~&|~|^^~,~^单目运算符

  • 运算法则与位运算符类似,但运算过程不同!
  • 对单个操作数进行递推运算,即先将操作数的最低位与第二位进行与、或、非运算,再将运算结果与第三位进行相同的运算,依次类推,直至最高位。
  • 运算结果缩减为1位二进制数。
  • [例]reg[3:0]a;b=|a;//等效于b=((a[0]|a[1])|a(2))|a[3]注意缩减运算符和位运算符的区别!表达式及运算符

第39页:移位运算符

七、移位运算符说明移位运算符右移左移>><<单目运算符左移会扩充位数!

  • 用法:A>>n或A<<n将操作数右移或左移n位,同时用n个0填补移出的空位。
  • [例]4'b1001>>3=4'b0001;4'b1001>>4=4'b00004'b1001<<1=5'b10010;4'b1001<<2=6'b100100;1<<6=32'b1000000
  • 将操作数右移或左移n位,相当于将操作数除以或乘以2n。右移位数不变,但右移的数据会丢失!表达式及运算符

第40页:条件运算符

八、条件运算符三目运算符in1outMUXin0sel信号=条件?表达式1:表达式2

  • 条件运算符为?:
  • 用法:
  • [例]数据选择器assignout=sel?in1:in0;当条件为真,信号取表达式1的值;为假,则取表达式2的值。sel=1时out=in1;sel=0时out=in0表达式及运算符

第41页:位拼接运算符

九、位拼接运算符 位拼接运算符为{} 用于将两个或多个信号的某些位拼接起来,表示一个整体信号。 用法:{信号1的某几位,信号2的某几位,……,信号n的某几位} 例如在进行加法运算时,可将进位输出与和拼接在一起使用。[例1]output[3:0]sum;//和outputcout;//进位输出input[3:0]ina,inb;inputcin;assign{cout,sum}=ina+inb+cin;//进位与和拼接在一起[例2]{a,b[3:0],w,3'b101}={a,b[3],b[2],b[1],b[0],w,1'b1,1'b0,1'b1}5.表达式及运算符

第42页:位拼接的简化写法

  • 可用重复法简化表达式,如:{4{w}}//等同于{w,w,w,w}
  • 还可用嵌套方式简化书写,如:{b,{3{a,b}}}//等同于{b,{a,b},{a,b},{a,b}},也等同于{b,a,b,a,b,a,b}用于表示重复的表达式必须为常数表达式!
  • 在位拼接表达式中,不允许存在没有指明位数的信号,必须指明信号的位数;若未指明,则默认为32位的二进制数!
  • 如{1,0}=64'h00000001_00000000,注意{1,0}不等于2'b10表达式及运算符

第43页:运算符的优先级

十、运算符的优先级优先级运算符类别高低! ~逻辑、位运算符* / %算术运算符+-<< >>移位运算符< <= > >=关系运算符= = ! = === !==等式运算符& ~&缩减、位运算符^ ^~| ~|&&逻辑运算符||?:条件运算符表3-3运算符的优先级

  • 为提高程序的可读性,建议使用括号来控制运算的优先级!
  • [例](a>b)&&(b>c)(a= =b)||(x= = y)(!a)||(a>b)5.表达式及运算符

第44页:Verilog HDL语句概览

描述形式(语句)内容概要连续赋值语句赋值语句过程赋值语句begin_end语句块语句if_else语句条件语句case语句forever语句循环语句repeat语句while语句for语句always语句结构说明语句task语句function语句'define语句编译预处理语句有4种语句(fork_join,initial,'include,'timescale)是Quartus II不支持的,它们通常用在测试模块中(ModelSim软件支持)。

第45页:赋值语句

一、赋值语句 分为两类:(1)连续赋值语句——assign语句,用于对wire型变量赋值,是描述组合逻辑最常用的方法之一。[例]assignc=a&b;//a、b、c均为wire型变量(2)过程赋值语句——用于对reg型变量赋值,有两种方式: 非阻塞(non-blocking)赋值方式:赋值符号为<=,如b<=a; 阻塞(blocking)赋值方式:赋值符号为=,如b=a;6.5.1赋值语句和块语句

第46页:非阻塞赋值

赋值语句和块语句二、非阻塞赋值与阻塞赋值的区别1.非阻塞赋值方式always @(posedge clk)beginb <= a ;c <= b;endclkDFFcDQDQabDFF非阻塞赋值在块结束时才完成赋值操作!注:c的值比b的值落后一个时钟周期!

第47页:阻塞赋值

赋值语句和块语句2.阻塞赋值方式always @(posedge clk)beginb = a ;c = b;end阻塞赋值在该语句结束时就完成赋值操作!clkDFFcDQab注:在一个块语句中,如果有多条阻塞赋值语句,在前面的赋值语句没有完成之前,后面的语句就不能被执行,就像被阻塞了一样,因此称为阻塞赋值方式。这里c的值与b的值一样.

第48页:非阻塞与阻塞赋值的区别

赋值语句和块语句

  • 非阻塞(non-blocking)赋值方式( b<= a):
  • b的值被赋成新值a的操作,并不是立刻完成的,而是在块结束时才完成;
  • 块内的多条赋值语句在块结束时同时赋值;
  • 硬件有对应的电路。
  • 阻塞(blocking)赋值方式( b = a):
  • b的值立刻被赋成新值a;
  • 完成该赋值语句后才能执行下一句的操作;
  • 硬件没有对应的电路,因而综合结果未知。非阻塞赋值与阻塞赋值方式的主要区别:
  • 建议在初学时只使用一种方式,不要混用!
  • 建议在可综合风格的模块中使用非阻塞赋值!

第49页:块语句

赋值语句和块语句三、块语句

  • 用来将两条或多条语句组合在一起,使其在格式上更像一条语句,以增加程序的可读性。
  • 块语句有两种:
  • begin_end语句——标识顺序执行的语句
  • fork_join语句——标识并行执行的语句用begin_end标识的块Quartus II不支持,通常用在测试文件中1.顺序块特点
  • 块内的语句是顺序执行的;
  • 每条语句的延迟时间是相对于前一条语句的仿真时间而言的;
  • 直到最后一条语句执行完,程序流程控制才跳出该顺序块。

第50页:顺序块的格式

赋值语句和块语句begin语句1;语句2;…语句n;endbegin:块名块内声明语句;语句1;语句2;…语句n;end注:块内声明语句可以是参数声明、reg型变量声明、integer型变量声明、real型变量声明语句。或顺序块的格式

第51页:顺序块举例

赋值语句和块语句[例1]beginb = a ;c = b;//c的值为a的值end[例2]beginb = a ;#10c = b;//在两条赋值语句间延迟10个时间单位end注:这里标识符"#"表示延迟;在模块调用中"#"表示参数的传递举例

第52页:并行块

.并行块用fork_join标识的块特点

  • 块内的语句是同时执行的;
  • 块内每条语句的延迟时间是相对于程序流程控制进入到块内时的仿真时间而言的;
  • 延迟时间用于给赋值语句提供时序;
  • 当按时间排序在最后的语句执行完或一个disable语句执行时,程序流程控制跳出该并行块。fork语句是不可综合的!

第53页:并行块的格式

fork语句1;语句2;…语句n;joinfork:块名块内声明语句;语句1;语句2;…语句n;join或注:块内声明语句可以是参数声明、reg型变量声明、integer型变量声明、real型变量声明语句、time型变量声明语句和事件(event)说明语句。并行块的格式

第54页:用并行块产生时序波形

[例4]用并行块和延迟控制组合产生一个时序波形。reg[7:0] r;fork//由一系列延迟产生的波形# 50 r='h35;# 100 r='hE2;# 150 r='h00;# 200 r='hF7;# 250–> end_wave;//触发事件end_wavejoin波形同例3注:在fork_join块内,各条语句不必按顺序给出!但为增加可读性,最好按被执行的顺序书写!

第55页:条件语句内容概要

.2条件语句一、if-else语句二、case语句三、使用条件语句注意事项内容概要

第56页:if-else语句

一、if-else语句

  • 判定所给条件是否满足,根据判定的结果(真或假)决定执行给出的两种操作之一。
  • if-else语句有3种形式
  • 其中"表达式"为逻辑表达式或关系表达式,或一位的变量。
  • 若表达式的值为0、或z,则判定的结果为"假";若为1,则结果为"真"。
  • 语句可为单句,也可为多句;多句时一定要用"begin_end"语句括起来,形成一个复合块语句。对于每个判定只有两个分支
  • 条件语句分为两种:if-else语句和case语句;
  • 它们都是顺序语句,应放在"always"块内!6.5.2条件语句

第57页:if表达式的简写方式

条件语句

  • 允许一定形式的表达式简写方式,如:
  • if(expression)等同于if(expression==1)
  • if(!expression)等同于if(expression!=1)if(表达式)语句1;if(表达式1)语句1;else语句2;if(表达式1)语句1;elseif(表达式2)语句2;…elseif(表达式n)语句n;方式1:方式2:方式3:适于对不同的条件,执行不同的语句

第58页:if语句的嵌套

if语句可以嵌套; 若if与else的数目不一样,注意用"begin_end"语句来确定if与else的配对关系!if(表达式1)if(表达式2)语句1;else语句2;elseif(表达式3)语句3;else语句4;if(表达式1)beginif(表达式2)语句1;endelse语句2;当if与else的数目不一样时,最好用"begin_end"语句将单独的if语句括起来:if语句的嵌套:

第59页:模60 BCD码加法计数器

条件语句 [例]模为60进制的BCD码加法计数器counter60.valways块语句和assign语句是并行执行的!在always块内的语句是顺序执行的!

第60页:六十进制计数器仿真波形

条件语句 cin为来自下一级计数器的进位 always与assign语句是并行执行的!count60.vwf置数进位输出当cin=1则加1计数

第61页:case语句

条件语句二、case语句多分支语句case(敏感表达式)值1:语句1;值2:语句2;…值n:语句n;default:语句n+1;endcase1.case语句

  • 当敏感表达式取不同的值时,执行不同的语句。
  • 功能:当某个(控制)信号取不同的值时,给另一个(输出)信号赋不同的值。常用于多条件译码电路(如译码器、数据选择器、状态机、微处理器的指令译码)!
  • case语句有3种形式:case,casez,casex适于对同一个控制信号取不同的值时,输出取不同的值!case语句与if-else语句有什么区别呢?

第62页:case语句的使用说明

  • 说明:
  • 其中"敏感表达式"又称为"控制表达式",通常表示为控制信号的某些位。
  • 值1~值n称为分支表达式,用控制信号的具体状态值表示,因此又称为常量表达式。
  • default项可有可无,一个case语句里只能有一个default项!
  • 值1~值n必须互不相同,否则矛盾。
  • 值1~值n的位宽必须相等,且与控制表达式的位宽相同。

第63页:casez与casex语句

.casez与casex语句是case语句的两种变体

  • 在case语句中,分支表达式每一位的值都是确定的(或者为0,或者为1);
  • 在casez语句中,若分支表达式某些位的值为高阻值z,则不考虑对这些位的比较;
  • 在casex语句中,若分支表达式某些位的值为z或不定值x,则不考虑对这些位的比较。
  • 在分支表达式中,可用"?"来标识x或z。

第64页:casez实现数据选择器

module mux_z(out,a,b,c,d,select);output out;input a,b,c,d;input[3:0] select;reg out; 

第65页:if语句的正确使用

如何正确使用if语句?生成了不想要的锁存器:不会生成锁存器:always@ (al or d)beginif(al) q<=d;enddDFFDQalqalways@ (al or d)beginif(al) q<=d;else q<=0;end0dalqmultiplexer当al为0时,q保持原值!当al为0时,q等于0![例]设计一个数据选择器

第66页:case语句的正确使用

always@ (sel[1:0] or a or b)case(sel[1:0])2'b00: q<=a;2'b11: q<=b;endcase生成了不想要的锁存器:always@ (sel[1:0] or a or b)case(sel[1:0])2'b00: q<=a;2'b11: q<=b;default: q<='b0;endcase不会生成锁存器:如何正确使用case语句?当sel为00或11以外的值时,q保持原值! 避免生成锁存器的原则: 如果用到if语句,最好写上else项; 如果用到case语句,最好写上default项。[例]设计一个数据选择器

第67页:循环语句

  • 循环语句分为4种:
  • for语句:通过3个步骤来决定语句的循环执行:
  • (1)给控制循环次数的变量赋初值。
  • (2)判定循环执行条件,若为假则跳出循环;若为真,则执行指定的语句后,转到第(3)步。
  • (3)修改循环变量的值,返回第(2)步。
  • repeat语句:连续执行一条语句n次
  • while语句:执行一条语句,直到循环执行条件不满足;若一开始条件即不满足,则该语句一次也不能被执行!
  • Forever:语句—无限连续地执行语句,可用disable语句中断!6.5.3循环语句

第68页:for语句

一、for语句for(表达式1;表达式2;表达式3)语句for(循环变量赋初值;循环执行条件;循环变量增值)执行语句两条语句8条语句一般形式:简单应用形式: ; 相当于采用while语句建立的循环结构:begin循环变量赋初值;while(循环执行条件)begin<执行语句>循环变量增值;endendfor语句比while语句简洁!

第69页:for语句应用示例

[例]用for语句初始化memory。注:当执行语句有多条时,可用begin_end语句将其括起来!begin:init_memreg[7:0]tempi;//存储器的地址变量for(tempi=0;tempi<memsize;tempi=tempi+1)memory[tempi]=0;end[例]用for语句实现两个8位二进制数乘法

第70页:八位乘法器mult_for

mult_for.v等同于if(b[i]= =1)a左移(i-1)位,同时用(i-1)个0填补移出的位a为被乘数,b为乘数

第71页:乘法器功能仿真波形

mult_for.vwf(功能仿真)建议用无符号十进制表示,直观!

第72页:repeat语句

二、repeat语句 ; 连续执行一条或多条语句n次。repeat(循环次数表达式)语句repeat(循环次数表达式)begin……end执行语句为多条语句或格式只有部分综合工具可以综合此语句!

第73页:用repeat语句实现乘法

循环语句[例]用repeat语句和移位操作实现两个8位二进制数乘法:注:不如采用for语句简单!

第74页:while和forever语句

循环语句三、while和forever语句1.while语句

  • 有条件地执行一条或多条语句。
  • 首先判断循环执行条件表达式是否为真。若为真,则执行后面的语句或语句块;然后再回头判断循环执行条件表达式是否为真,若为真,再执行一次后面的语句;如此不断,直到条件表达式不为真。

while(循环执行条件表达式)语句while(循环执行条件表达式)begin……end或格式注1:首先判断循环执行条件表达式是否为真,若不为真,则其后的语句一次也不被执行!注2:在执行语句中,必须有一条改变循环执行条件表达式的值的语句!注3:while语句只有当循环块有事件控制(即@(posedgeclock))时才可综合!

第75页:while语句计数示例

modulecount1s_while(count,rega,clk);output[3:0]count;input[7:0]rega;inputclk;reg[3:0]count;always@(posedgeclk)begin:count1reg[7:0]tempreg;//用作循环执行条件表达式count=0;//count初值为0tempreg=rega;//tempreg初值为regawhile(tempreg)//若tempreg非0,则执行以下语句beginif(tempreg[0])count=count+1;//只要tempreg最低位为1,则count加1tempreg=tempreg>>1;//右移1位endendendmodule[例]用while语句对一个8位二进制数中值为1的位进行计数。改变循环执行条件表达式的值如何用for语句改写此程序呢?

第76页:用for语句统计1的个数

[例]用for语句对一个8位二进制数中值为1的位进行计数。简单!

第77页:计数仿真波形

count1s_for_good.vwf

第78页:forever语句

.forever语句 无条件连续执行forever后面的语句或语句块。forever语句foreverbegin……end或 常用在测试模块中产生周期性的波形,作为仿真激励信号。 常用disable语句跳出循环!注:不同于always语句,不能独立写在程序中,一般用在initial语句块中!格式initialbegin:Clockingclk=0;#10forever#10clk=!clk;endinitialbegin:Stimulus……disableClocking;//停止时钟end一般情况下是不可综合的!常用在测试文件中

第79页:结构说明语句

  • initial说明语句——只执行一次
  • always说明语句——不断重复执行,直到仿真结束
  • task说明语句——可在程序模块中的一处或多处调用
  • function说明语句——可在程序模块中的一处或多处调用结构说明语句分为4种一、always块语句
  • 包含一个或一个以上的声明语句(如:过程赋值语句、任务调用、条件语句和循环语句等),在仿真运行的全过程中,在定时控制下被反复执行。6.5.3结构说明语句

第80页:always块语句

在always块中被赋值的只能是register型变量(如reg,integer,real,time)。 每个always块在仿真一开始便开始执行,当执行完块中最后一个语句,继续从always块的开头执行。always<时序控制><语句>注1:如果always块中包含一个以上的语句,则这些语句必须放在begin_end或fork_join块中!格式规则always@(posedgeclkornegedgeclear)beginif(!clear)qout=0;//异步清零elseqout=1;end6.5.3结构说明语句

第81页:always语句与时序控制

[例]生成一个0延迟的无限循环跳变过程——形成仿真死锁!alwaysareg=~areg; [例]在测试文件中,用于生成一个无限延续的信号波形——时钟信号注2:always语句必须与一定的时序控制结合在一起才有用!如果没有时序控制,则易形成仿真死锁!'definehalf_period50modulehalf_clk_top;regreset,clk;//输入信号wireclk_out;//输出信号always#half_periodclk=~clk;……endmodule

第82页:用always块产生触发器与计数器

; [例]用always块语句产生T'FF和8位二进制计数器。

第83页:敏感信号表达式

.4结构说明语句always@(<敏感信号表达式>)begin//过程赋值语句// if语句// case语句// while,repeat,for循环// task,function调用end一般为输入

  • 敏感信号表达式又称事件表达式或敏感表,当其值改变时,则执行一遍块内语句;
  • 在敏感信号表达式中应列出影响块内取值的所有信号!
  • 敏感信号可以为单个信号,也可为多个信号,中间需用关键字or连接!
  • 敏感信号不要为x或z,否则会阻挡进程!always块语句模板一个变量不能在多个always块中被赋值!

第84页:沿触发与电平触发

always的时间控制可以为沿触发,也可为电平触发。 关键字posedge表示上升沿;negedge表示下降沿。常用于描述时序逻辑常用于描述组合逻辑always@ (posedge clock or posedge reset)begin……endalways@ (a or b or c)begin……end由两个沿触发的always块由多个电平触发的always块

第85页:可综合性问题

always块语句是用于综合过程的最有用的语句之一,但又常常是不可综合的。为得到最好的综合结果,always块程序应严格按以下模板来编写:模板1可综合性问题always@(Inputs)//所有输入信号必须列出,用or隔开begin……//组合逻辑关系end模板2always@(Inputs)//所有输入信号必须列出,用or隔开if(Enable)begin……//锁存动作end

第86页:always块编写模板

模板3always@(posedgeClock)//Clockonlybegin……//同步动作end模板4always@(posedgeClockornegedgeReset)//ClockandResetonlybeginif(!Reset)//测试异步复位电平是否有效……//异步动作else……//同步动作end//可产生触发器和组合逻辑

第87页:多个敏感信号的处理

(1)当always块有多个敏感信号时,一定要采用if-elseif语句,而不能采用并列的if语句!否则易造成一个寄存器有多个时钟驱动,将出现编译错误。注意always@posedgemin_clkornegedgereset)beginif(reset)min<=0;elseif(min=8'h59)//当reset无效且min=8'h59时beginmin<=0;h_clk<=1;endend(2)通常采用异步清零!只有在时钟周期很小或清零信号为电平信号时(容易捕捉到清零信号)采用同步清零。千万别写成if

第88页:initial语句

二、initial语句initialbegin语句1;语句2;……语句n;end格式[例]利用initial语句生成激励波形。initialbegininputs='b000000;#10inputs='b011001;#10inputs='b011011;#10inputs='b011000;#10inputs='b001000;end不可综合!常用在测试文件中用途 在仿真的初始状态对各变量进行初始化; 在测试文件中生成激励波形作为电路的仿真信号。

第89页:task和function语句

task和function语句

  • task和function语句分别用来由用户定义任务和函数。
  • 任务和函数往往是大的程序模块中在不同地点多次用到的相同的程序段。
  • 利用任务和函数可将一个很大的程序模块分解为许多较小的任务和函数,便于理解和调试。
  • 输入、输出和总线信号的值可以传入、传出任务和函数。6.5.5任务和函数

第90页:任务task

  • 当希望能够对一些信号进行一些运算并输出多个结果(即有多个输出变量)时,宜采用任务结构。
  • 常常利用任务来帮助实现结构化的模块设计,将批量的操作以任务的形式独立出来,使设计简单明了。1.任务(task)task<任务名>;端口及数据类型声明语句;其他语句;endtask<任务名>(端口1,端口2,……);任务定义任务调用包含定时控制语句的任务是不可综合的!

第91页:任务的定义与调用

[例]任务的定义与调用。taskmy_task;inputa,b;inoutc;outputd,e;……<语句>//执行任务工作相应的语句……c=foo1;d=foo2;//对任务的输出变量赋值e=foo3;endtaskmy_task(v,w,x,y,z);任务定义任务调用

  • 当任务启动时,由v、w和x传入的变量赋给了a、b和c;
  • 当任务完成后,输出通过c、d和e赋给了x、y和z。注1:任务的定义与调用必须在一个module模块内!注2:任务被调用时,需列出端口名列表,且必须与任务定义中的I/O变量一一对应!注3:一个任务可以调用其他任务和函数。

第92页:冒泡排序任务

[例]通过任务调用完成4个4位二进制输入数据的冒泡排序。任务的定义任务的调用

第93页:sort4测试文件

sort4.v的测试文件

  • $random为系统任务,返回一个32位的带符号的随机数;
  • 一般用法为:$random%b其中b>0,它给出了一个范围在-b+1~b-1之间的随机数。
  • {$random}%15通过位拼接操作,产生一个0~14之间的随机数。

第94页:sort4仿真波形

sort4.v的仿真波形按从小到大的顺序排序

第95页:函数function

.函数(function)

  • 函数的目的是通过返回一个用于某表达式的值,来响应输入信号。适于对不同变量采取同一运算的操作。
  • 函数在模块内部定义,通常在本模块中调用,也能根据按模块层次分级命名的函数名从其他模块调用。而任务只能在同一模块内定义与调用!function<返回值位宽或类型说明>函数名;端口声明;局部变量定义;其他语句;endfunction缺省则返回1位reg型数据函数定义可以综合!

第96页:函数的调用

<函数名>(<表达式><表达式>)注1:函数的调用是通过将函数作为调用函数的表达式中的操作数来实现的!与函数定义中的输入变量对应!注2:函数在综合时被理解成具有独立运算功能的电路,每调用一次函数,相当于改变此电路的输入,以得到相应的计算结果。function[7:0]gefun;//函数的定义input[7:0]x;……<语句>//进行运算gefun=count;//赋值语句endfunctionassignnumber=gefun(rega);//对函数的调用函数调用内部寄存器

第97页:函数的使用规则

  • 函数的定义不能包含任何时间控制语句——用延迟#、事件控制@或等待wait标识的语句。
  • 函数不能启动(即调用)任务!
  • 定义函数时至少要有一个输入参量!且不能有任何输出或输入/输出双向变量。
  • 在函数的定义中必须有一条赋值语句,给函数中的一个内部寄存器赋以函数的结果值,该内部寄存器与函数同名。函数的使用规则

第98页:统计0的位数函数

[例]利用函数对一个8位二进制数中为0的位数进行统计。只有输入变量内部寄存器对应函数的输入变量

第99页:函数统计仿真波形

count0s_function.vwf

第100页:阶乘运算函数

; [例]阶乘运算函数内部寄存器clk的上升沿触发同步运算函数的调用函数名被赋予的值就是函数的返回值!函数定义

第101页:函数与任务的比较

函数(function)任务(task)通过返回一个值,来响应输入信号可计算多个结果值目的或用途至少有一个输入变量,但不能有任何output或inout型变量可为各种类型(包括inout型)输入与输出可作为表达式中的一个操作数来调用,在过程赋值和连续赋值语句中均可调用只可在过程赋值语句中调用,不能在连续赋值语句中调用被调用函数可调用其他函数,但不可调用其他任务任务可调用其他任务和函数调用其他任务和函数向调用它的表达式返回一个值不向表达式返回值返回值任务与函数的区别

第102页:编译预处理与define语句

.6编译预处理语句一、‵define语句

  • 宏定义语句——用一个指定的标志符(即宏名)来代表一个字符串(即宏内容)。‵define标志符(即宏名)字符串(即宏内容)
  • [例]‵defineINina+inb+inc+ind
  • 宏展开——在编译预处理时将宏名替换为字符串的过程。
  • "编译预处理"是VerilogHDL编译系统的一个组成部分。编译预处理语句以西文符号"‵"开头——注意,不是单引号"'".
  • 在编译时,编译系统先对编译预处理语句进行预处理,然后将处理结果和源程序一起进行编译。格式

第103页:宏定义的使用说明

  • 宏名可以用大写字母,也可用小写字母表示;但建议用大写字母,以与变量名相区别。
  • ‵define语句可以写在模块定义的外面或里面。宏名的有效范围为定义命令之后到源文件结束。
  • 在引用已定义的宏名时,必须在其前面加上符号"‵".
  • 使用宏名代替一个字符串,可简化书写,便于记忆,易于修改。
  • 预处理时只是将程序中的宏名替换为字符串,不管含义是否正确。只有在编译宏展开后的源程序时才报错。
  • 宏名和宏内容必须在同一行中进行声明.关于宏定义的说明
  • 宏定义的作用:
  • 以一个简单的名字代替一个长的字符串或复杂表达式;
  • 以一个有含义的名字代替没有含义的数字和符号。

第104页:宏定义常见错误

[例]moduletest;rega,b,c,d,e,out;‵defineexpressiona+b+c+d;assignout=‵expression+e;……经过宏展开后,assign语句为:assignout=a+b+c+d;+e;//出现语法错误! 宏定义不是VerilogHDL语句,不必在行末加分号! 如果加了分号,会连分号一起置换!错误!

第105页:宏定义的层层置换

[例] module test;rega,b,c;wireout;‵defineaaa+b‵defineccc+‵aa//引用已定义的宏名‵aa来定义宏ccassignout=‵cc;……经过宏展开后,assign语句为:assignout=c+a+b; 在进行宏定义时,可引用已定义的宏名,实现层层置换。

第106页:include文件包含语句

二、‵include语句 ; 文件包含语句:一个源文件可将另一个源文件的全部内容包含进来。‵include"文件名"预处理后‵include"file2.v"Afile1.vBfile2.vABfile1.vQuartus Ⅱ不支持!通常用在测试文件中。将file2.v中全部内容复制插入到‵include"file2.v"命令出现的地方格式

第107页:顺序执行与并行执行概要

语句的顺序执行与并行执行一、语句的顺序执行二、语句的并行执行内容概要

第108页:语句的顺序执行

一、语句的顺序执行

  • 在"always"模块内,逻辑按书写的顺序执行。
  • 顺序语句——"always"模块内的语句。
  • 在"always"模块内,若随意颠倒赋值语句的书写顺序,可能导致不同的结果
  • 注意阻塞赋值语句当本语句结束时即完成赋值操作!6.6语句的顺序执行与并行执行

第109页:顺序执行模块示例

语句的顺序执行与并行执行[例6.1]顺序执行模块1。module serial1(q,a,clk);output q,a;input clk;reg q,a;always @(posedge clk)beginq=~q;//阻塞赋值语句a=~q;endendmodule[例6.2]顺序执行模块2。module serial2(q,a,clk);output q,a;input clk;reg q,a;always @(posedge clk)begina=~q;q=~q;endendmodule对前一时刻的q值取反对当前时刻的q值取反对前一时刻的q值取反对前一时刻的q值取反a和q的波形反相!a和q的波形完全相同!

第110页:顺序执行仿真波形对比

serial1.vwfserial2.vwfa和q的波形反相!a和q的波形完全一样!q=~q;a=~q;a=~q;q=~q;

第111页:语句的并行执行

语句的顺序执行与并行执行二、语句的并行执行

  • "always"模块、"assign"语句、实例元件都是同时(即并行)执行的!
  • 它们在程序中的先后顺序对结果并没有影响。
  • 下面[例6.3]、[例6.4]将两条赋值语句分别放在两个"always"模块中,尽管两个"always"模块顺序相反,但仿真波形完全相同。parall1.vwf对前一时刻的q值取反对前一时刻的q值取反

第112页:并行执行模块示例

[例6.3]并行执行模块1。module parall1(q,a,clk);output q,a;input clk;reg q,a;always @(posedge clk)beginq=~q;endalways @(posedge clk)begina=~q;endendmodule[例6.4]并行执行模块2。module parall2(q,a,clk);output q,a;input clk;reg q,a;always @(posedge clk)begina=~q;endalways @(posedge clk)beginq=~q;endendmodule

第113页:不同抽象级别的Verilog模型

  • 一个复杂电路的完整VerilogHDL模型由若干个VerilogHDL模块构成,每个模块由若干的子模块构成——可分别用不同抽象级别的VerilogHDL描述。
  • 在同一个VerilogHDL模块中可有多种级别的描述。
  • 系统级(system level):用高级语言结构(如case语句)实现的设计模块外部性能的模型;
  • 算法级(algorithmic level):用高级语言结构实现的设计算法模型(写出逻辑表达式);
  • RTL级(register transfer level):描述数据在寄存器之间流动和如何处理这些数据的模型;
  • 门级(gate level):描述逻辑门(如与门、非门、或门、与非门、三态门等)以及逻辑门之间连接的模型;
  • 开关级(switch level):描述器件中三极管和储存节点及其之间连接的模型。三、Verilog HDL模型的不同描述

第114页:门级描述

、VerilogHDL的门级描述门类型关键字<例化的门名称>(<端口列表>);

  • 门级描述即直接调用门原语进行逻辑的结构描述。
  • 以门级为基础的结构描述所建立的硬件模型不仅是可仿真的,也是可综合的;
  • 一个逻辑网络由许多逻辑门和开关组成,用逻辑门的模型来描述逻辑网络最直观!
  • 门类型的关键字有26个,常用的有9个:not,and,nand,or,nor,xor,xnor,buf,bufif1,bufif0,notif1,notif0(各种三态门)
  • 调用门原语的句法:结构描述,最直观!可省略!注1:在端口列表中输出信号列在最前面;注2:门级描述不适于描述复杂的系统;

第115页:门原语实现四选一数据选择器

  • [例6.5]调用门原语实现4选1数据选择器
  • 注:首先必须根据逻辑功能画出逻辑电路图输出输入outcntrl1 cntrl2in1in2in3in40 00 11 01 1真值表

第116页:门级描述的例化说明

注:这里省略了所有的例化门元件名称

第117页:行为级描述:逻辑表达式

、VerilogHDL的行为级描述包括系统级,算法级,RTL级1)逻辑功能描述——算法级注:首先必须根据逻辑功能写出逻辑表达式![例3.12.2]用逻辑表达式实现4选1数据选择器module mux4_1(out,in1,in2,in3,in4,cntrl1,cntrl2);output out;input in1,in2,in3,in4,cntrl1,cntrl2;assign out=(in1 & ~cntrl1 & ~cntrl2) |(in2 & ~cntrl1 & cntrl2) |(in3 & cntrl1 & ~cntrl2) |(in4 & cntrl1 & cntrl2) ;endmodule三、Verilog HDL模型的不同描述

第118页:行为级描述:case语句

)case语句描述——系统级只需知道输入与输出间的真值表!比调用门原语和采用逻辑功能描述都简洁![例]用case语句描述4选1数据选择器module mux4_1(out,in1,in2,in3,in4,cntrl1,cntrl2);output out;input in1,in2,in3,in4,cntrl1,cntrl2;reg out;always @(in1 or in2 or in3 or in4 or cntrl1 or cntrl2)case({cntrl1,cntrl2})2'b00:out=in1;2'b01:out=in2;2'b10:out=in3;2'b11:out=in4;default :out=1'bx;endcaseendmodulecase语句应放在always块内

第119页:行为级描述:条件运算符

)条件运算符描述——算法级只需知道输入与输出间的真值表注:比调用门原语,采用逻辑表达式或case语句描述代码更简单!但也更抽象!且耗用器件资源更多![例]用条件运算符描述4选1数据选择器module mux4_1(out,in1,in2,in3,in4,cntrl1,cntrl2);output out;input in1,in2,in3,in4,cntrl1,cntrl2;assignout= cntrl1? (cntrl2? in4 :in3) : (cntrl2? in2 :in1) ;endmodule当cntrl1=1时执行当cntrl1=0时执行

第120页:描述级别的选用原则

  • 采用的描述级别越高,设计越容易,程序代码越简单;但耗用器件资源更多。对特定综合器,可能无法将某些抽象级别高的描述转化为电路!
  • 基于门级描述的硬件模型不仅可以仿真,而且可综合,且系统速度快。
  • 所有VerilogHDL编译软件只是支持该语言的一个子集。
  • 尽量采用编译软件支持的语句来描述设计;或多个软件配合使用。
  • 一般用算法级(写出逻辑表达式)或RTL级来描述逻辑功能,尽量避免用门级描述,除非对系统速度要求比较高的场合才采用门级描述。小结

第121页:描述级别与资源优化小结

(1)采用什么描述级别更合适?

  • 系统级描述太抽象,有时无法综合成具体的物理电路;门级描述要求根据逻辑功能画出逻辑电路图,对于复杂的数字系统很难做到;
  • 而算法级和RTL级描述级别适中,代码不是很复杂,且一般容易综合成具体的物理电路,故建议尽量采用算法级和RTL级来描述。(2)怎样减少器件逻辑资源的耗用?
  • 当器件容量有限时,为减少器件逻辑资源的耗用,建议少用if-else语句和case语句,尽量直接使用逻辑表达式来描述系统的逻辑功能;
  • 或者用case语句取代if-else语句。思考