页数:121页文件大小:1.24 MB来源: EDA技术及数字系统的应用ppt课件
本课件系统讲解Verilog HDL,涵盖语言特点与模块端口结构、关键字与标识符规范、数据类型与常量变量、九类运算符、赋值语句与块语句、条件与循环语句、always与initial等结构说明语句、任务与函数,以及不同抽象级别的建模与资源优化。
本章将介绍Verilog HDL设计的基础知识,包括Verilog HDL语言规则、不同抽象级别的Verilog HDL模型、Verilog HDL的语法,以及利用实例说明VerilogHDL进行数字电路设计的过程。第六章硬件描述语言Verilog HDL学习目标和要求:熟悉Verilog HDL的语言特点和语言规则;掌握Verilog HDL的设计流程和语句;掌握Verilog HDL实现各种类型数字电路的方法。
Verilog概述一、什么是VerilogHDL
二、VerilogHDL的发展历史
三、不同层次的VerilogHDL抽象
四、VerilogHDL的特点
模块是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.模块定义模块定义由关键字module开始,以endmodule结束。VerilogHDL结构完全嵌在module和endmodule定义语句之间。每个模块必须具有一个模块名,唯一地标识这个模块.如上例中模块的名称是fulladd。模块的端口列表则描述这个模块的输入和输出端口,上例中模块有5个端口:三个输入端口a、b和c_in,两个输出端口sum和c_out。6.1.2模块和端口需要注意的是,声明部分可以分散于模块的任何地方,但是变量、寄存器、线网和参数等声明必须在使用前出现,通常集中在模块前端一起声明,这样可增强程序的可读性。如果多种语句出现在同一个module中,其相互之间没有任何顺序关系,则它们在module中出现顺序的改变不会改变module的功能,这正是硬件的一大特点。可以想象一下绘制原理图的过程,先画哪个器件,后画哪个器件根本没有任何关系。
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位计数器模块名(文件名)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用户程序中的变量、节点等名称不能与关键字同名!VerilogHDL关键字edgeelseendendcaseendfunctionendprimitiveendmoduleendspecifyendtableendtaskeventforforceforeverforkfunctionhighz0highz1ififnoneinitialinoutinputintegerjoinlargemacromodulemediummodulenandnegedgenor notnotif0notif1nmosoroutputparameterpmosposedgeprimitivepulldownpulluppull0pull1andalwaysassignbeginbufbufif0bufif1casecasexcasezcmosdeassigndefaultdefparamdisable6.2 Verilog HDL的语法VerilogHDL关键字(续)tri0tri1vectoredwaitwandweak0weak1whilewireworxnorxorrcmosrealrealtimeregreleaserepeatrnmosrpmosrtranrtranif0rtranif1scalaredsmallspecifyspecparamstrengthstrong0strong1supply0supply1tabletasktrantranif0tranif1timetritriandtriortrireg6.2 Verilog HDL的语法
、标识符
、编写VerilogHDL源代码的标准
一、数据类型
数据类型及常量、变量
数据类型及常量、变量(2)x和z值
(3)负数
(4)parameter常量(符号常量)
数据类型及常量、变量三、变量
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型向量(总线)格式:定义——对应具有状态保持作用的电路元件(如触发器、寄存器等),常用来表示过程块语句(如initial,always,task,function)内的指定信号。 常用register型变量: reg:常代表触发器 integer:32位带符号整数型变量 real:64位带符号实数型变量 time:无符号时间变量纯数学的抽象描述2. register型变量数据类型及常量、变量 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型向量(总线)格式用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型变量只能生成组合逻辑。用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沿触发一、算术运算符说明算术运算符加减乘除求模+-*/%双目运算符
; [例]除法和求模运算的区别注意/和%的区别!表达式及运算符
/4 = 29%4 =1arithmetic.vwf表达式及运算符
二、逻辑运算符
三、位运算符说明位运算符按位取反按位与按位或按位异或按位同或~&|^^~,~^双目运算符单目运算符
; [例]&&运算符和&(按位与)的区别&&运算的结果为1位的逻辑值注意&&和&的区别!被认为是1'b1被认为是1'bx逻辑与结果为1'bx表达式及运算符
四、关系运算符说明关系运算符小于小于或等于大于大于或等于<<=>>=双目运算符括号内先运算!算术运算先运算!
五、等式运算符说明等式运算符等于不等于全等不全等==!====!==双目运算符
; [例]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表达式及运算符
六、缩减运算符说明缩减运算符与与非或或非异或同或&~&|~|^^~,~^单目运算符
七、移位运算符说明移位运算符右移左移>><<单目运算符左移会扩充位数!
八、条件运算符三目运算符in1outMUXin0sel信号=条件?表达式1:表达式2
九、位拼接运算符 位拼接运算符为{} 用于将两个或多个信号的某些位拼接起来,表示一个整体信号。 用法:{信号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.表达式及运算符十、运算符的优先级优先级运算符类别高低! ~逻辑、位运算符* / %算术运算符+-<< >>移位运算符< <= > >=关系运算符= = ! = === !==等式运算符& ~&缩减、位运算符^ ^~| ~|&&逻辑运算符||?:条件运算符表3-3运算符的优先级
描述形式(语句)内容概要连续赋值语句赋值语句过程赋值语句begin_end语句块语句if_else语句条件语句case语句forever语句循环语句repeat语句while语句for语句always语句结构说明语句task语句function语句'define语句编译预处理语句有4种语句(fork_join,initial,'include,'timescale)是Quartus II不支持的,它们通常用在测试模块中(ModelSim软件支持)。一、赋值语句 分为两类:(1)连续赋值语句——assign语句,用于对wire型变量赋值,是描述组合逻辑最常用的方法之一。[例]assignc=a&b;//a、b、c均为wire型变量(2)过程赋值语句——用于对reg型变量赋值,有两种方式: 非阻塞(non-blocking)赋值方式:赋值符号为<=,如b<=a; 阻塞(blocking)赋值方式:赋值符号为=,如b=a;6.5.1赋值语句和块语句赋值语句和块语句二、非阻塞赋值与阻塞赋值的区别1.非阻塞赋值方式always @(posedge clk)beginb <= a ;c <= b;endclkDFFcDQDQabDFF非阻塞赋值在块结束时才完成赋值操作!注:c的值比b的值落后一个时钟周期!赋值语句和块语句2.阻塞赋值方式always @(posedge clk)beginb = a ;c = b;end阻塞赋值在该语句结束时就完成赋值操作!clkDFFcDQab注:在一个块语句中,如果有多条阻塞赋值语句,在前面的赋值语句没有完成之前,后面的语句就不能被执行,就像被阻塞了一样,因此称为阻塞赋值方式。这里c的值与b的值一样.
赋值语句和块语句
赋值语句和块语句三、块语句
赋值语句和块语句begin语句1;语句2;…语句n;endbegin:块名块内声明语句;语句1;语句2;…语句n;end注:块内声明语句可以是参数声明、reg型变量声明、integer型变量声明、real型变量声明语句。或顺序块的格式
赋值语句和块语句[例1]beginb = a ;c = b;//c的值为a的值end[例2]beginb = a ;#10c = b;//在两条赋值语句间延迟10个时间单位end注:这里标识符"#"表示延迟;在模块调用中"#"表示参数的传递举例.并行块用fork_join标识的块特点
fork语句1;语句2;…语句n;joinfork:块名块内声明语句;语句1;语句2;…语句n;join或注:块内声明语句可以是参数声明、reg型变量声明、integer型变量声明、real型变量声明语句、time型变量声明语句和事件(event)说明语句。并行块的格式
[例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块内,各条语句不必按顺序给出!但为增加可读性,最好按被执行的顺序书写!
.2条件语句一、if-else语句二、case语句三、使用条件语句注意事项内容概要
一、if-else语句
条件语句
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语句的嵌套:条件语句 [例]模为60进制的BCD码加法计数器counter60.valways块语句和assign语句是并行执行的!在always块内的语句是顺序执行的!条件语句 cin为来自下一级计数器的进位 always与assign语句是并行执行的!count60.vwf置数进位输出当cin=1则加1计数条件语句二、case语句多分支语句case(敏感表达式)值1:语句1;值2:语句2;…值n:语句n;default:语句n+1;endcase1.case语句
.casez与casex语句是case语句的两种变体
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语句。思考
下载地址:{{downurl}}
{{{a}}}
{{#b}}{{{b}}}
{{/b}} {{/title}} {{#nolog}}登陆注册
{{/nolog}} {{#djsx}}点我刷新
{{/djsx}} {{#gocz}} {{/gocz}} {{#ffqr}} {{/ffqr}}