文档详情

Verilog数字设计基础

汽***
实名认证
店铺
PPT
3.66MB
约295页
文档ID:593052011
Verilog数字设计基础_第1页
1/295

第一部分 Verilog数字设计基础第一章第一章 VerilogVerilog的基本知识的基本知识第二章第二章 VerilogVerilog语法的基本概念语法的基本概念第三章第三章 模块的结构、数据类型、变量和基本运算符号模块的结构、数据类型、变量和基本运算符号第四章第四章 运算符、赋值语句和结构说明语句运算符、赋值语句和结构说明语句第五章第五章 条件语句、循环语句、块语句与生成语句条件语句、循环语句、块语句与生成语句第六章第六章 结构语句、系统任务、函数语句和显示系统任务结构语句、系统任务、函数语句和显示系统任务第七章第七章 调试用系统任务和常用编译预处理语句调试用系统任务和常用编译预处理语句第八章第八章 语法概念总复习练习语法概念总复习练习第一部分第一部分 Verilog数字设计基础数字设计基础 第1章 Verilog的基本知识l1.1 1.1 硬件描述语言硬件描述语言HDLHDLl1.2 1.2 VerilogVerilog HDL HDL的历史的历史l1.3 1.3 VerilogVerilog HDL HDL和和VHDLVHDL的比较的比较l1.4 1.4 VerilogVerilog的应用情况和适用的设计的应用情况和适用的设计l1.5 1.5 采用采用VerilogVerilog HDL HDL设计复杂数字电路的优点设计复杂数字电路的优点l1.6 1.6 采用采用VerilogVerilog HDL HDL的设计流程简介的设计流程简介第第1章章 Verilog的基础知识的基础知识 1.1 硬件描述语言HDL概念:硬件描述语言硬件描述语言HDL(Hardware Description Language)是一种形式化方法来描述数字电路和系统的语言。

IEEE标准标准Verilog HDLVHDLHDL两种国际标准:HDL功能功能数字系统仿真、验证(全部语法支持)数字系统仿真、验证(全部语法支持)数字系统设计、综合(部分语法支持)数字系统设计、综合(部分语法支持)HDL功能:§1.1 硬件描述语言硬件描述语言HDL 1.2 Verilog HDL的历史1.2.1 什么是Verilog HDL Verilog HDL是硬件描述语言的一种,用于数字系统设计是硬件描述语言的一种,用于数字系统设计设计者可用它进行各种级别的逻辑设计,可用它进行数字逻辑系统的仿真验证仿真验证、时序分析时序分析、逻辑综合逻辑综合 注:它是目前应用最广泛的一种硬件描述语言 目前在美国使用Verilog HDL进行设计的工程师大约有10万多人,全美国有200多所大学讲授Verilog语言的设计方法在台湾地区几乎所有著名大学的电子和计算机工程系都讲授与Verilog有关的课程1.2.1 什么是Verilog HDL§1.2 VerilogHDL的历史的历史 图图1.1 Verilog的发展历史的发展历史§1.2.2 VerilogHDL的产生及发展的产生及发展 1.3 Verilog HDL和VHDL的比较§1.3 Verilog HDL和和VHDL的比较的比较共同点共同点能形式化的抽象表示电路的行为和结构;能形式化的抽象表示电路的行为和结构;支持逻辑设计中层次与范围的描述;支持逻辑设计中层次与范围的描述;可借用高级语言的精巧结构来简化电路行为的描述;可借用高级语言的精巧结构来简化电路行为的描述;具有电路仿真与验证机制以保证设计的正确性;具有电路仿真与验证机制以保证设计的正确性;支持电路描述由高层到低层的综合转换;支持电路描述由高层到低层的综合转换;硬件描述与实现工艺无关;硬件描述与实现工艺无关;便于文档管理;易于理解和设计重用。

便于文档管理;易于理解和设计重用VHDLVHDL ------- -------V VHSIC HSIC H Hardware ardware D Description escription L Language, anguage, VHSICVHSIC则是则是Very High Speed Very High Speed IntegeratedIntegerated Circuit Circuit的缩写词的缩写词 VerilogVerilog拥有更广泛的设计群体,成熟的资源也比拥有更广泛的设计群体,成熟的资源也比VHDLVHDL丰富;丰富;20052005年以前,年以前,VerilogVerilog在系统级抽象方面比在系统级抽象方面比VHDLVHDL略差一略差一些,而在门级开关电路描述方面比些,而在门级开关电路描述方面比VHDLVHDL强的多20052005年后,系统抽象能力得到彻底改变年后,系统抽象能力得到彻底改变与与VHDLVHDL相比,相比,VerilogVerilog HDL HDL容易掌握,与容易掌握,与C C语言类似语言类似不同点不同点 图图1.2 Verilog HDL与与VHDL建模能力的比较建模能力的比较2005年公布的年公布的System Verilog IEEE1800-2005标标准使准使Verilog的可综合性能的可综合性能和系统仿真性能得到大幅和系统仿真性能得到大幅度提高,度提高,IP重用有了重大重用有了重大突破。

突破 VHDL VITAL开关电路级开关电路级逻辑门级逻辑门级寄存器传输级寄存器传输级算法级算法级系统级系统级VerilogSystem Verilog§1.3 Verilog HDL和和VHDL的比较的比较 1.4 Verilog的应用情况和适用的设计 在高层次数字系统设计领域,Verilog已经取得压倒性的优势—— Verilog在门级描述的底层,比VHDL有更强的功能—— 支持数字逻辑和模拟电路的描述—— IEEE1800-2005标准公布,在综合、仿真验证和IP核 重用方面都有大幅度提高拓宽了发展前景 语言输入与原理图输入方式相比的优点:1 1、容易把设计移植到不同厂家的不同芯片中去;、容易把设计移植到不同厂家的不同芯片中去;2 2、信号位数容易修改,可以很方便的适应不同规模的应用;、信号位数容易修改,可以很方便的适应不同规模的应用;3 3、、与实现工艺无关;与实现工艺无关;VerilogVerilog HDL HDL综合器生成标准的电子设计综合器生成标准的电子设计互换格式(互换格式(EDIFEDIF)文件,方便文档交换与保存;)文件,方便文档交换与保存;1.5 采用Verilog HDL设计复杂数字电路的优点电路的两种基本入方式:原理图输入(原理图输入(传统设计方法)硬件描述语言输入硬件描述语言输入 采用采用VerilogVerilog语言,设计的可重用性好。

语言,设计的可重用性好 由于VerilogHDL不断更新改进,最新标准为IEEE1800-2005,使得该语言具有更广阔的发展前景,目前最新的EDA工具都进行了更新以支持最新的Verilog标准§1.5 采用采用VerilogHDL设计复杂数字电路的优点设计复杂数字电路的优点lIP核重用核重用 lIP--------完成某种功能的设计模块完成某种功能的设计模块 IP核l概念:l软核软核((Soft Core)):功能经过验证的、可综合的、实现后电路结构总门数在5000门以上的Verilog HDL模型由软核构成的器件称为虚拟器件三者中灵活性最高l固核固核((Firm Core)):指在某一种现场可编程门阵列(FPGA)器件上实现的、经验证是正确的、总门数在5000门以上电路结构编码文件l硬核硬核((Hard Core)):指在某一种专用集成电路(ASIC)工艺的器件上实现的、经验证是正确的、总门数在5000门以上的电路结构版图掩膜 1.6 Verilog HDL的设计流程方法:Top-DownTop-Down(自顶向下)设计思想自顶向下)设计思想图图1.3 Top-Down设计思想设计思想§1.6 Verilog HDL的设计流程的设计流程 图图 1.4 HDL设计流程图设计流程图没问题没问题有问题有问题有问题有问题没问题没问题没问题没问题有问题有问题有问题有问题 前仿真前仿真:: 即即 RTLRTL级仿真,检查有关模块级仿真,检查有关模块 逻辑执行步骤是否正确。

逻辑执行步骤是否正确后仿真后仿真::用门级模型做验证,检查由门用门级模型做验证,检查由门的互连构成的逻辑其功能是否的互连构成的逻辑其功能是否正确布局布线后仿真布局布线后仿真::在门级模型的基础上在门级模型的基础上加上了布线延时加上了布线延时, ,与真实的电与真实的电路最接近的验证路最接近的验证§1.6 Verilog HDL的设计流程的设计流程 小结小结:小结:1 1)采用)采用VerilogVerilog HDL HDL设计方法比采用电路图输入的方法更有优越性;设计方法比采用电路图输入的方法更有优越性;2 2)在两种符合)在两种符合IEEEIEEE标准的硬件描述语言中,标准的硬件描述语言中,VerilogVerilog HDL HDL与与VHDLVHDL相比更加相比更加基础、更易掌握;基础、更易掌握;3 3))VerilogVerilog HDL HDL可用于复杂数字逻辑电路和系统的总体仿真、子系统仿真可用于复杂数字逻辑电路和系统的总体仿真、子系统仿真和具体电路综合等各个设计阶段;和具体电路综合等各个设计阶段;4 4))Top-DownTop-Down的设计方法方便了从系统级划分和管理整个项目,使得超大的设计方法方便了从系统级划分和管理整个项目,使得超大规模的复杂数字电路的设计成为可能,并可减少设计人员,避免不必要的规模的复杂数字电路的设计成为可能,并可减少设计人员,避免不必要的重复设计,提高了设计的一次成功率。

重复设计,提高了设计的一次成功率第第1章章 Verilog的基础知识的基础知识 第2章 Verilog语法的基本概念概念:用Verilog HDL描述的电路设计就是该电路的Verilog HDL模型,也称为模块——module概念:Verilog HDL既是一种行为描述行为描述的语言也是一种结构描结构描述述的语言 也就是说,无论描述电路功能行为的模块或描述元件或较大部件互连的模块都可以用Verilog语言来建立电路模型第第2章章 Verilog语法的基本概念语法的基本概念 概念:Verilog模型可以是实际电路的不同级别的抽象这些抽象的级别和它们所对应的模型类型共有以下5种: (1)系统级系统级(system(system--level)level)::用语言提供的高级结构能够实现所设计模块的外部性能的模型 (2)算法级算法级(algorithm(algorithm--level)level)::用语言提供的高级结构能够实现算法运行的模型 (3)RTLRTL级级(Register Transfer Level)(Register Transfer Level)::描述数据在寄存器之间的流动和如何处理、控制这些数据流动的模型。

以上三种都属于行为描述,只有RTL级才与逻辑电路有明确的对应关系 (4)门级门级(gate(gate——level)level)::描述逻辑门以及逻辑门之间连接的模型 与逻辑电路有确定的连接关系,以上四种数字系统设计工程师必须掌握 (5)开关级开关级(switch(switch——level)level)::描述器件中三极管和储存节点以及它们之间连接的模型 系统级(系统级(System)) 算法级算法级((Alogrthem))寄存器传输级寄存器传输级((RTL))门级(门级(Gate))电路开关级电路开关级((Switch)) 2.1 Verilog模块的基本概念abslout图图 2.1 二选一多路器(一)二选一多路器(一)【例2.1】module muxtwo(out,a,b,sl); input a,b,sl; //信号属性信号属性 output out; //信号属性信号属性 reg out; //信号属性信号属性 //实现功能描述功能描述 always @(sl or a or b) if(!sl) out=a; else out=b;endmodule§2.1 Verilog模块的基本概念模块的基本概念 我们并不关心它的电路结构,而关心的是如何从逻辑上来描述它。

【例2.2】abslout&&1nslselaselbmodule muxtwo(out,a,b,sl); input a,b,sl; output out; wire nsl,sela,selb; assign nsl=~sl; assign sela=a&nsl; assign selb=b&sl; assign out=sela|selb;endmodule基于逻辑表达式基于逻辑表达式的描述的描述图图 2.2 二选一多路器逻辑图二选一多路器逻辑图§2.1 Verilog模块的基本概念模块的基本概念 【例2.3】absloutu1u2u3u4nslselaselbmodule muxtwo(out,a,b,sl); input a,b,sl; output out;not u1(ns1,sl);and u2(sela,a,nsl);and u3(selb,b,sl);or u4(out,sela,selb);endmodule结构描述结构描述图图 2.3 多路选择器(二)多路选择器(二)参考返回§2.1 Verilog模块的基本概念模块的基本概念 编写编写编写编写VerilogVerilogVerilogVerilog HDL HDL HDL HDL模块的练习模块的练习模块的练习模块的练习请在下面的空格中填入适当的符号请在下面的空格中填入适当的符号 使其成为右图的使其成为右图的Verilog 模块模块 :: module block1(a, b, —, —, — ); input —, —, —; —— d, — ; assign d = a | ( b & ~c) ; assign e = ( b & ~c ); _______abcde§2.1 Verilog模块的基本概念模块的基本概念 概念:综合综合——Synthesis Verilog模块(程序)通过计算机上运行的综合软件工具(属EDA软件)把行为描述通过逻辑表达式的中间形式自动转换为结构描述的模块,这个过程叫做综合(Synthesis)。

Synthesis 综合综合absloutabsloutu1u2u3u4nslselaselb§2.1 Verilog模块的基本概念模块的基本概念 概念: 1 1))并行性并行性;; 2 2))层次结构性;层次结构性; 3 3))可综合性;可综合性; 4 4))测试平台测试平台( (TestbenchTestbench) )下面再看几个简单的模块,目的是初步了解Verilog语法最重要的几个基本概念:§2.1 Verilog模块的基本概念模块的基本概念 module adder(cout,sum,a,b,cin); input [2:0] a,b; input cin; output cout; output [2:0] sum; assign {cout,sum} = a+b+cin;endmodule【例2.4】说明:此程序通过连续赋值语句描述了一个名为adder的3位加法器。

它可以根据两个3位数a、b和进位(cin)计算出和(sum)及向上进位(cout)整个Verilog HDL程序是位于module和endmodule声明语句之间的连续赋值连续赋值语句语句信号定义信号定义模块开始模块开始与结束与结束外部端外部端口信号口信号定义定义§2.1 Verilog模块的基本概念模块的基本概念 【例2.5】说明:这个程序通过连续赋值语句描述了一个名为compare的比较器对2比特数a、b进行比较,如a与b相等,则输出equal为高电平,否则为低电平/*……*/和//……表示注释部分module compare(equal,a,b); output equal; //声明声明输出信号出信号equal input [1:0] a,b; //声明声明输入信号入信号a,,b assign equal= (a==b) ? 1:0; /*a,b相等,相等,输出出为1;否;否则为0*/endmodule程序程序注释注释§2.1 Verilog模块的基本概念模块的基本概念 【例2.6】说明:这个程序描述了一个名为trist2的三态驱动器。

通过调用Verilog语言提供的原语库中的三态驱动器元件bufif1来实现其逻辑功能在trist2模块中所用到的三态驱动器bufif1的具体名字叫做mybuf,这种引用现成元件或模块的方这种引用现成元件或模块的方法叫做实例化或实例引用法叫做实例化或实例引用,是表示电路构造的一种常用语法现象module trist2(out,in,enable); output out; input in,enable; bufif1 mybuf(out,in,enable);endmodule元件例化元件例化instanceinenableout§2.1 Verilog模块的基本概念模块的基本概念 【例2.7】module trist1(sout,sin,ena); output sout; input sin,ena; mytri tri_inst(.out(sout), .in(sin), .enable(ena));endmodulemodule mytri(out,in,enable); output out; input in,enable; assign out=enable ? in: ‘bz;endmodule底层底层子模块子模块顶层顶层说明:在实例部件tri_inst中,带“.”表示被引用模块的端口,名称必须与被引用模块的端口一致; 小括号中名称为本模块信号,表示与被调用模块的连接关系。

参考返回§2.1 Verilog模块的基本概念模块的基本概念 说明: 上面这些例子都是可以综合的,通过综合工具可以自动转换为由与门、或门和非门组成的加法器、比较器和三态门等组合逻辑 这个例子中存在着两个模块:模块这个例子中存在着两个模块:模块trist1 调用模块调用模块 mytri 的实例元件的实例元件 tri_inst模块模块 trist1 是上层模块模块是上层模块模块 mytri 则被称为子模块则被称为子模块通过这种结构性模块构造可构成特大型模块通过这种结构性模块构造可构成特大型模块§2.1 Verilog模块的基本概念模块的基本概念 2.2 Verilog用于模块的测试概念:描述测试信号的变化和测试过程的模块叫做测试平台描述测试信号的变化和测试过程的模块叫做测试平台(Testbench或或Testfixture) 测试平台可以对上面介绍的电路模块(无论是行为的或结构的)进行动态的全面测试 通过观测被测试模块的输出信号是否符合要求,可以调试和验证逻辑系统的设计系统和结构正确与否,并发现问题及时修改§2.2 Verilog用于模块的测试用于模块的测试 图图 2.5 Verilog用于模块测试用于模块测试测试信号 ain和测试条 select件的控制 binabsloutu1u2u3u4nslselaselb被测试模块对测试信号的响应outw返回元件例化§2.2 Verilog用于模块的测试用于模块的测试 【例2.8】Verilog测试模块,对例2.1~2.3的多路器进行全面的测试。

`include “muxtwo.v” always #50 clock=~clock; module t; always @(posedge clock) reg ain,bin,select; begin reg clock; #1 ain={$random}%2; wire outw; #3 bin={$random}%2; initial end begin always #10000 select=!select;ain=0; muxtwo m(.out(outw),.a(ain),.b(bin),.sl(select));bin=0; endmoduleselect=0;clock=0; end§2.2 Verilog用于模块的测试用于模块的测试 程序说明:initial begin ain=0; bin=0; select=0;clock=0;endinitial块只执行一次把寄存器型变量初始化为确定值,即0时刻值。

信号的初始化信号的初始化§2.2 Verilog用于模块的测试用于模块的测试 always #50 clock=~clock;always块循环执行产生一个不断重复的、周期为100个单位时间的时钟信号clockclock5050时钟信号的产生方法时钟信号的产生方法§2.2 Verilog用于模块的测试用于模块的测试 always @(posedge clock)posedge 上升沿negedge 下降沿clock时钟信号的上升沿触发时钟信号的上升沿触发§2.2 Verilog用于模块的测试用于模块的测试 always @(posedge clock)begin ain={$random}%2;#3 bin={$random}%2;end延时3个时间单位$random-产生随机数{$random}%2为产生0-1的随机数随机信号产生与信号延时随机信号产生与信号延时§2.2 Verilog用于模块的测试用于模块的测试 元件的调用元件的调用muxtwo m(.out(outw),.a(ain),.b(bin),.sl(select));被调用元件名元件例化名本模块信号名本模块信号名被调用模块原有信号名被调用模块原有信号名说明:m表示在本测试模块中有一个名为m的muxtwo的模块;其四个端口分别为:.out() , .a() , .b() , .sl();“.”表示端口,后面为端口名,名称必须与muxtwo模块定义的端口名一致;小括号内的信号名为与该端口连接的信号线名,必须在本模块中定义,说明其类型。

参考§2.2 Verilog用于模块的测试用于模块的测试 §2.2 Verilog用于模块的测试用于模块的测试 §2.2 Verilog用于模块的测试用于模块的测试module myadder(clock, reset, a, b, sum); input clock, reset; input [7:0] a, b; output [7:0] sum; reg [7:0] sum; reg [reg [7 7:0] :0] a_reg,a_reg, b_reg; b_reg;always @(posedge clock or negedge reset) if (!reset) begin sum<= ’b0, a_reg <=a_reg <= ’ ’b0; b_reg <= b0; b_reg <= ’ ’b0b0; end else begin a_reg <= a; a_reg <= a; b_reg <= b; b_reg <= b; s sumum <= a_reg <= a_reg + + b_reg ; b_reg ; end end endmodule `include “myadder.v”module t; wire [8:0] sumout; reg [7:0] ain, bin; reg rst, clk; myadder u1(.clock(clk), .reset(rst), .a(ain), .b(bin), .sum(sumout)); initial begin rst = 1;;clk = 0; ain = 0; bin=3; #70 rst=0;; # 70 rst = 1;; end always #50 clk = ~clk; always @(posedge clk) begin #2 ain = ain + 2; #3 bin = bin +5; endendmodule§2.2 Verilog用于模块的测试用于模块的测试 t t 模块中模块中VerilogVerilog HDL HDL语句的功能语句的功能 可以对可以对myadder 模块进行模块进行测试,测试,myadder 模块输入了必须的信号:模块输入了必须的信号: rst,,clk,,ain,,bin 观测该模块的输出:观测该模块的输出:sumout 看一看它是否符合设计要求。

看一看它是否符合设计要求§2.2 Verilog用于模块的测试用于模块的测试 2.3 2.3 小结小结(1)Verilog HDL程序由模块构成每个模块的内容都位于module和endmodule两个语句之间每个模块实现特定的功能2)模块是可以进行层次嵌套的因此,可以将大型的数字电路设计分割成不同的小模块来实现特定的功能3)如果每个模块都是可以综合的,则通过综合工具可以把它们的功能描述全都转换为最基本的逻辑单元描述,最后可以用一个顶层模块通过实例引用把这些模块连接起来,整合成一个很大的复杂逻辑系统4)Verilog模块可以分为两种类型:一种是为了让模块最终能生成电路的类型,另一种只是为了测试所设计电路的逻辑功能是否正确5)每个模块要进行端口定义,并说明它是输入口还是输出口,然后对模块的功能进行描述第第2章章 Verilog语法的基本概念语法的基本概念 (6)Verilog HDL程序的书写格式自由,一行可以写几个语句,一个语句也可以分写多行7)除了endmodule语句外,每个语句和数据定义的最后必须有分号8)可以用/*……*/和//……对Verilog HDL程序的任何部分作注释。

一个好的、有使用价值的源程序都应当加上必要的注释,以增强程序的可读性和可维护性第第2章章 Verilog语法的基本概念语法的基本概念 第第2章章 Verilog语法的基本概念语法的基本概念思考题1、构成模块的关键词是什么?2、是否任意抽象的符合语法的Verilog模块都可以通过综合工具转变为电路结构?3、什么叫综合?通过综合产生的是什么?产生的结果有什么用处?4、仿真是什么?为什么要进行仿真?5、模块的端口是如何描述的?6、在引用实例模块的时候,如何在主模块中连 接信号线?7、如何产生连续的周期性测试时钟?8、如果不用initial块,能否产生测试时钟? 第第3章章 模块的结构、数据类型、变量和基本模块的结构、数据类型、变量和基本运算符号运算符号l3.1 模块的结构l3.2 数据类型及其常量和变量l3.3 运算符及表达式第第3章章 模块的结构、数据类型、变量和基本运算符号模块的结构、数据类型、变量和基本运算符号 Verilog的基本设计单元是“模块” 其组成有两部分一部分描述接口,另一部分描述逻辑功能,即定义输入是如何影响输出的3.1 模块的结构接口描述逻辑功能描述Module block(a,b,c,d); input a,b; output c,d; assign c=a|b; assign d=a&b;endmoduleabcd图图 3.1 模块结构的组成模块结构的组成§3.1 模块的结构模块的结构 每个Verilog程序包括4个主要部分:程序组成端口定义端口定义I/O说明说明内部信号声明内部信号声明功能定义功能定义 程序中的接口描述就是用来说明电路图符号的引脚名称及其信号流向;逻辑功能描述说明了该电路符号的具体逻辑功能。

§3.1 模块的结构模块的结构 3.1.1 模块的端口定义语法:语法:模块的端口声明了模块的输入输出口其格式如下: module 模块名模块名(口口1,口,口2,口,口3,口,口4,,……);;说明:说明: 模块的端口表示的是模块的输入和输出口名,也就是与其它模块联系端口的标识在模块被引用时,在引用的模块中,有些信号要输入到被引用的模块中,有些信号需要从被引用的模块中取出来§3.1 模块的结构模块的结构 语法:在引用模块时其端口的两种连接方法:(1)按顺序引用按顺序引用 在引用时,严格按照模块定义的端口顺序来连接,不用标明原模块定义时规定的端口名,例如: 模块名模块名(连接端口连接端口1信号名,连接端口信号名,连接端口2信号名,连接端口信号名,连接端口3信号名,信号名,……,,);;(2)按名称引用按名称引用在引用时用“.”符号,标明原模块定义时规定的端口名,例如: 模块名模块名(.端口.端口1名名(连接信号连接信号1名名),端口,端口2名名(连接信号连接信号2名名),,……,,);;参考程序参考程序§3.1 模块的结构模块的结构 3.1.2 模块内容1..I//O说明的格式说明的格式语法:语法:输入口: input 端口名端口名1;;//一位宽信号定义一位宽信号定义 input [信号位宽信号位宽-1::0] 端口名端口名1;; input [信号位宽信号位宽-1::0] 端口名端口名2;; …… input [信号位宽信号位宽-1::0] 端口名端口名i;;//(共有共有i个输入口个输入口)语法:语法:输出口:output 端口名端口名1;; //一位宽信号定义一位宽信号定义 output [信号位宽信号位宽-1::0] 端口名端口名1;; output [信号位宽信号位宽-1::0] 端口名端口名2;; …… output [信号位宽信号位宽-1::0] 端口名端口名j;;//(共有共有j个输出口个输出口)§3.1 模块的结构模块的结构 语法:语法:I/O说明也可以写在端口声明语句里。

其格式如下: module module_name(input port1,,input port2,,… output port1,,output port2…);;语法:语法:输入/输出口: inout 端口名端口名1;; //一位一位宽信号定信号定义 inout [信号位信号位宽-1::0] 端口名端口名1;; inout [信号位信号位宽-1::0] 端口名端口名2;; …… inout [信号位信号位宽-1::0] 端口名端口名k;; //(共有共有k个双向个双向总线端口端口)§3.1 模块的结构模块的结构 2.内部信号说明.内部信号说明在模块内用到的和与端口有关的两种变量类型:wire、、reg语法:语法:wire 变量量1,,变量量2…::wire [ width-1::0 ] 变量量1,,变量量2…::reg 变量量1,,变量量2…;;reg [ width-1::0 ] 变量量1,,变量量2…;; 说明:用input定义的端口信号没有类型说明,只有output定义的信号和内部信号具有wire、reg类型声明要求。

信号定义为信号定义为intput类型时默认隐含为类型时默认隐含为wire型§3.1 模块的结构模块的结构 3.功能定义.功能定义 模块中最重要的部分是逻辑功能定义部分有3种方法可在模块中产生逻辑用用“assign”连续赋值语句连续赋值语句用元件例化方法(即元件调用)用元件例化方法(即元件调用)用用“always”块块注意: 前面程序中出现的initial块,只能用于测试平台程序§3.1 模块的结构模块的结构 1))用"assign"声明语句 这种方法的句法很简单,只需写一个“assign”,后面再加一个方程式即可如:assign a==b & c;;例中的方程式描述了一个有两个输入的与门§3.1 模块的结构模块的结构注1. assign 语句被赋值的变量必须是wire型,操作数可以是 wire型、reg型2.总是处于激活状态3.可用于描述一个完整的设计4.必须放在initial、always块外 2)用元件例化方法(即元件调用))用元件例化方法(即元件调用) 采用实例元件的方法像在电路图输人方式下调入库元件一样,键入元件的名字和相连的引脚即可,如:and #2 u1(q,,a,,b);; §3.1 模块的结构模块的结构 3)用)用“always”块块 采用“assign”语句是描述组合逻辑最常用的方法之一。

而而“always”块既可用于描述组合逻辑也可描述时序逻辑块既可用于描述组合逻辑也可描述时序逻辑 “always”块可用很多种描述手段来表达逻辑,例如下面的程序中就用了if…else语句来表达逻辑关系带异步清零端的D触发器”的描述always @(posedge clk or posedge clr) begin if (clr) q<=0;; else q<==d:: end “与门”的描述: always @(a or b) begin if ((a==1)&&(b==1)) c=‘b1; else c=‘b0; end赋值运算赋值运算符符§3.1 模块的结构模块的结构 3.1.3理解要点要点: 上面的例子分别采用了“assign”语句、实例元件和“always”块这这3个例子描述的逻辑功能是同时执行的个例子描述的逻辑功能是同时执行的也就是说,如果把这3项写到一个Verilog模块文件中去,它们的位置顺序不会影响实现的功能这3项是同时执行的,也就是并发的。

要点:在在“always”模块内,逻辑是按照指定的顺序执行的模块内,逻辑是按照指定的顺序执行的always”块中的语句称为“顺序语句顺序语句”但是,两个或更多的“always”模块之间是同时执行的,但是模块内部的语句是顺序执行的§3.1 模块的结构模块的结构 l module ex (…………);l input …………………;l output ……………….;l reg …………………..;l assign a=b&c;l always @(…………….)l beginl …l endl and u1(a,b,c);l always @(…………….)l endmodule 并发执行并发执行顺序执行 3.1.4 要点总结牢记:(1)在在Verilog模块中所有过程块模块中所有过程块(initial块、块、always块块)、连续赋值语、连续赋值语 句、实例引用都是并行的;句、实例引用都是并行的;(2)在同一模块中这三者出现的先后顺序没有关系;在同一模块中这三者出现的先后顺序没有关系;(3)实例引用表示的是一种通过变量名实现互相连接的关系;实例引用表示的是一种通过变量名实现互相连接的关系;(4)只有连续赋值语句只有连续赋值语句assign和实例引用语句可以独立于过程块而存在和实例引用语句可以独立于过程块而存在 于模块的功能定义部分。

于模块的功能定义部分§3.1 模块的结构模块的结构 3.2 数据类型及其常量和变量数据类型及其常量和变量Verilog HDL中总共有19种数据类型数据类型是用来表示数字电路硬件中的数据储存和传送元素的需要掌握的常用类型有4种: reg wire integer parameter 另外,Verilog HDL语言中也有常量常量和变量变量之分它们分别属于以上这些类型§3.2 数据类型及其常量和变量数据类型及其常量和变量其他: large、medium、small、tri、trio、tri1、triand、trior、trireg、vectored scalared、time、 wand和wor这些数据类型除time型外都与基本逻辑单元建库有关 3.2.1 常 量概念: 在程序运行过程中,其值不能被改变的量称为常量在程序运行过程中,其值不能被改变的量称为常量数字常量数字常量符号常量符号常量常量常量§3.2 数据类型及其常量和变量数据类型及其常量和变量 1.数字.数字 整型常量有4种进制表示形式: 二进制整数(b或B);十进制整数(d或D);十六进制整数(h或H);八进制整数(o或O)。

进制进制(1)整数§3.2 数据类型及其常量和变量数据类型及其常量和变量 数字表达方式有以下3种:1) <位宽位宽><进制进制><数字数字> 这是一种全面的描述方式§3.2 数据类型及其常量和变量数据类型及其常量和变量例:例:8’ha28’ha2、、 8’HA28’HA2 // //字母不区分大小写字母不区分大小写 4’d2 4’d2 // 4 // 4位十进制数位十进制数 6’o27 6’o27 // 6 // 6位八进制位八进制 8’b101011008’b10101100注注注注::::“ ’ ” “ ’ ” 是单引号是单引号是单引号是单引号, , 位宽只能用十进制数位宽只能用十进制数位宽只能用十进制数位宽只能用十进制数 位宽 位宽指明了数字的精确位数。

例如:一个4位二进制数的位宽为4,一个4位十六进制数的位宽为16 位宽始终表示的是二进制位数,与进制符号无关位宽始终表示的是二进制位数,与进制符号无关 如定义位宽比实际位数长,左边补“0” “X” “Z” 10’b10 = 10’b0000000010 10’bx0x1 = xxxxxxx0x1 如定义位宽比实际位数短,最左边截断 3’b10010111 = 3’b111 注:错误格式 i . 3’ b000 …… // “ ’ ” 和进制之间不能空格 ii .(3+2)’b10 …….// 位宽不能为表达式 iii. 4'd-4 //非法:数值不能为负 2) <进制进制><数字数字> 数字的位宽采用缺省位宽(这由具体的机器系统决定,但至少32位)3) <数字数字>采用缺省进制(十进制),位宽采用缺省位宽。

§ §例例 ’ ’ha12 32ha12 32位十六进制数位十六进制数 15 == ‘b111115 == ‘b1111 x代表不定值,z代表高阻值一个x可以用来定义十六进制数的4位二进制数的状态,八进制数的3位,二进制数的1位z的表示方式同x类似 z的另一种表达方式是“?”在使用case表达式时建议使用这种写法,以提高程序的可读性,见下例:(2)x和z值4’b10x0 //位宽为4的二进制数,从低位数起第2位为不定值4'b101z //位宽为4的二进制数,从低位数起第1位为高阻值12’dz //位宽为12的十进制数,其值为高阻值(第1种表达方式)12’d? //位宽为12的十进制数,其值为高阻值(第2种表达方式)8‘h4x //位宽为8的十六进制数,其低4位值为不定值§3.2 数据类型及其常量和变量数据类型及其常量和变量 在位宽表达式前加负号来表示负数。

负号必须写在数字定义表达式的最前面 注意,负号不可以放在位宽和进制之间,也不可以放在进制和具体的数之间见下例:(3)负数-8‘d5 //这个表达式代表5的补数(用八位二进制数表示) 11111011 -5 // - ’d5 -32’d58‘d-5 //错误格式§3.2 数据类型及其常量和变量数据类型及其常量和变量 下画线可以用来分隔数的表达以提高程序可读性,但不可以用在位宽和进制处,只能用在具体的数字之间见下例:(4)下画线(underscore)16’b1010_1011_1111_1010 //正确格式8’b_0011_1010 //错误格式§3.2 数据类型及其常量和变量数据类型及其常量和变量 当常量不说明位数时,默认值是32位,每个字母用8位的ASCII值表示例:10=32’d10=32’b10101=32’d1=32’b1-1=-32’d1=32’hFFFFFFFF’BX=32’BX=32’BXXXXXXX…X“AB“=16’B01000001_01000010 //字符串AB为十六进制数16’h4142§3.2 数据类型及其常量和变量数据类型及其常量和变量 2.参数.参数(parameter)型型概念:在Verilog HDL中用parameter来定义常量,即用parameter来定义一个标识符代表一个常量,称为符号常量符号常量,即标识符形式的常量。

parameter型数据说明格式如下:parameter 参数名参数名1=表达式,表达式,……,参数名,参数名n=表达式;表达式;§3.2 数据类型及其常量和变量数据类型及其常量和变量 parameter是参数型数据的确认符确认符后跟着一个用逗号分隔开的赋值语句表达式在每一个赋值语句的右边必须是一个常数表达式,即该表达式该表达式只能包含数字或先前已定义过的参数只能包含数字或先前已定义过的参数见下列: parameter msb=7;; //定义参数msb为常量7 parameter e=25,,f=29;; //定义两个常数参数 parameter r=5.7;; //声明r为一个实型参数 parameter byte_size=8,,byte_msb=byte_size-1;;//用常数表达式赋值 parameter average_delay=(r+f)//2;; //用常数表达式赋值§3.2 数据类型及其常量和变量数据类型及其常量和变量 参数的定义是局部的,只在当前模块中有效。

参数的定义是局部的,只在当前模块中有效 作用:作用: 参数型常数经常用于定义延迟时间和变量宽度 在模块或实例引用时,可通过参数传递改变被引用模块或实例中已定义的参数 module Decode(A,F); parameter Width=1,Polarity=1; … endmodule module Top(…); wire [3:0] A4; wire [4:0] A5; wire [15:0] F16; wire [31:0] F32; Decode #(4,0) D1(A4,F16); Decode #(5) D2(A5,F32); endmodule【例3.1】§3.2 数据类型及其常量和变量数据类型及其常量和变量使用#次序与原说明相同因为#说明延时的时候只能用于gate或过程语句,不能用于模块实例gate(primitives)在实例化时只能有延时,不能有模块参数为什么编译器认为什么编译器认为这是参数而不为这是参数而不是延时呢?是延时呢? 【例3.2】 下面是一个由多层次模块构成的电路。

在一个模块中改变另一在一个模块中改变另一个模块的参数时,使用个模块的参数时,使用defparam命令AnnotateTestTTopBlockBlockB1B2实例名实例名实例名实例名实例名实例名图图 3.2 多层次模块构成的电路多层次模块构成的电路§3.2 数据类型及其常量和变量数据类型及其常量和变量 `include “Top.v” `include “Block.v” `include “Annotate.v” module Test; wire W; Top T( … ); endmodulemodule Top; wire w; Block B1( … ); Block B2( … );endmodulemodule Block; parameter P=0; endmodule module Annotate;defparamTest.T.B1.P=2, //多层次多层次模块中,参数变量的命名规则,模块中,参数变量的命名规则,用点号来表示不同的模块层次用点号来表示不同的模块层次 Test.T.B2.P=3;endmodule 通过参数传递改变已定义的参数值 使用 defparam 改变参数值 3.2.2 变 量 变量即在程序运行过程中其值可以改变的量变量即在程序运行过程中其值可以改变的量,在Verilog HDL中变量的数据类型有很多种,这里只对常用的几种进行介绍。

多驱动源情况略1..wire型型说明:(1)wire网络数据类型表示结构实体(例如门)之间的物理连接2)网络类型的变量不能储存值,而且它必须受到驱动器(例如门或连续赋值语句assign)的驱动如果没有驱动器连接到网络类型的变量上,则该变量就是高阻的,即其值为z (3)wire型数据常用来表示以assign关键字指定的组合逻辑信号4)VerilogVerilog程序模块中输出信号类型默认时自动定义为程序模块中输出信号类型默认时自动定义为wirewire型wirewire型型信号可以用做任何方程式的输入,也可以用做信号可以用做任何方程式的输入,也可以用做““assignassign””语句或语句或实例元件实例元件的输出§3.2 数据类型及其常量和变量数据类型及其常量和变量 wire型信号的格式如下:wire [n-1::0] 数据名数据名1,数据名,数据名2,,……数据名数据名i;;或 wire [n::1] 数据名数据名1,数据名,数据名2,,……数据名数据名i;;例: wire a; //定义了一个1位的wire型数据, wire [7::0] b;; //定义了一个8位的wire型数据b wire [4::1] c,,d;; //定义了二个4位的wire型数据c和d§3.2 数据类型及其常量和变量数据类型及其常量和变量 2..reg型型说明:(1)reg型是寄存器数据类型寄存器数据类型。

2)reg类型数据的默认初始值为不定值x3)reg型数据常用来表示“always”模块内的指定信号,常代常代表触发器表触发器4)在在"always”块内被赋值的每一个信号都必须定义成块内被赋值的每一个信号都必须定义成reg型§3.2 数据类型及其常量和变量数据类型及其常量和变量用来表示存储单元,具有状态保持作用,通过赋值语句可改变寄存器存储单元的值在Verilog中有许多结构语句来控制何时或是否执行这些赋值语句这些控制构造可用来描述硬件的触发条件如时钟的上升沿,多路选择器并不是说并不是说reg型信号一定是寄存器或触发器的输出型信号一定是寄存器或触发器的输出,它只表它只表示被定义的信号将用在示被定义的信号将用在“always”块内 reg型数据的格式如下: reg [n-1::0] 数据名数据名1,数据名,数据名2,,……数据名数据名i;;或 reg [n::1] 数据名数据名1,数据名,数据名2,,……数据名数据名i;;看下面的几个例子: reg rega; //定义了一个1位的名为rega的reg型数据 reg [3:0] regb; //定义了一个4位的名为regb的reg型数据 reg [4:1] regc,regd //定义了二个4位的名为regc和regd的reg型 数据说明: reg是reg型数据的确认标识符;[n-1:0]和[n:1]代表该数据的位宽,即该数据有几位(bit);最后是数据的名称。

如果一次定义多个数据,数据名之间用逗号隔开声明语句的最后要用分号表示语句结束§3.2 数据类型及其常量和变量数据类型及其常量和变量 说明l reg型数据的缺省初始值是不定值xlreg型数据可以赋正值,也可以赋负值l但当一个reg型数据是一个表达式中的操作数时,它的值被当作是无符号值,即正值l 例如:当一个4位的寄存器用做表达式中的操作数时,如果开始寄存器被赋以值 -1,则在表达式中进行运算时,其值被认为是+15 选择正确的数据类型选择正确的数据类型in1in2OABY输入端口可以由输入端口可以由wire/reg驱动驱动,但输入端口只能是,但输入端口只能是wire输出端口可以是输出端口可以是wire/regr类型,类型,输出输出端口只能驱动端口只能驱动wier双向端口输入双向端口输入/输出只输出只能是能是wire类型类型l信号类型确定方法总结如下:信号类型确定方法总结如下:l信号可以分为端口信号和内部信号出现在端口列表中的信号是端口信号,其它的信号为内部信号l对于端口信号,输入端口只能是wire类型输出端口可以是wire类型,也可以是reg类型若输出端口在过程块中赋值则为reg类型;若在过程块外赋值(包括实例化语句),则为wire类型。

l内部信号类型与输出端口相同,可以是wire或reg类型判断方法也与输出端口相同若在过程块中赋值,则为reg类型;若在过程块外赋值,则为wire类型ABC 选择正确的数据类型选择正确的数据类型lmodule top;l wire y; l reg a, b;lDUT u1 (y, a, b) ;l initial l beginla = 0;l b = 0;l#5 a = 1;l endlendmodulelmodule DUT (Y, A, B);loutput Y;linput A, B;lwire Y, A, B;land a1(Y, A, B) ;lendmodule在过程块中只能给在过程块中只能给reg类型赋值类型赋值若若Y,,A,,B说明为说明为reg则会产生错误则会产生错误 选择数据类型时常犯的错误举例选择数据类型时常犯的错误举例修改前修改前::module example(o1, o2, a, b, c, d); input a, b, c, d; output o1, o2; reg c, d; reg o2 and u1(o2, c, d); always @(a or b) if (a) o1 = b; else o1 = 0;endmodule修改后:修改后:module example(o1, o2, a, b, c, d); input a, b, c, d; output o1, o2;// reg c, d;// reg o2 reg o1; and u1(o2, c, d); always @(a or b) if (a) o1 = b; else o1 = 0;endmodule 3..memory型型说明:(1)memory型即存储器类型;(2)Verilog HDL通过对reg型变量建立数组来对存储器建模,可以描述RAM型存储器,ROM存储器和reg文件。

3)数组中的每一个单元通过一个数组索引进行寻址4)在Verilog语言中没有多维数组存在memory型数据的格式如下: reg [n-1::0] 存存储器名器名 [m-1::0] ;;或 reg [n-1::0] 存存储器名器名 [m::1];;说明: reg [n-1:0]定义了存储器中每一个存储单元的大小,即该存储单元是一个n位的寄存器,存储器名后的[m-1:0]或[m:1]则定义了该存储器中有多少个这样的寄存器,最后用分号结束定义语句……m-100n-11……1m-2§3.2 数据类型及其常量和变量数据类型及其常量和变量 另外,在同一个数据类型声明语句里,可以同时定义存储器型数据和reg型数据见下例: parameter wordsize=16, //定定义两个参数两个参数 memsize=256;; reg [wordsize-1::0] mem[memsize-1::0],,writereg,,readreg;;下面举例说明: reg [7::0] mema [255::0];说明: 这个例子定义了一个名为mema的存储器,该存储器有256个8位的存储器。

该存储器的地址范围是0到255 注意:对存储器进行地址索引的表达式必须是常数表达式Mem256*16bit RAMWritereg16bitreadreg16bit§3.2 数据类型及其常量和变量数据类型及其常量和变量 说明: 一个由一个由n个个1位寄存器构成的存储器组不同于一个位寄存器构成的存储器组不同于一个n位的寄存器的位的寄存器的见下例: reg [n-1::0] rega;; //一个n位的寄存器 reg mema [n-1::0];;//一个由n个1位寄存器构成的存储器组 一个一个n位的寄存器可以在一条赋值语句里进行赋值,而一个完整的存储位的寄存器可以在一条赋值语句里进行赋值,而一个完整的存储器则不行器则不行见下例: rega==0;; //正确赋值语句 mema==0;; //错误的赋值语句 如果想对memory中的存储单元进行读写操作,必须指定该单元在存储器中的地址。

下面的写法是正确的: mema[3]==0;; //给memory中的第3个存储单元赋值为0§3.2 数据类型及其常量和变量数据类型及其常量和变量 module myrom (read_data, addr, read_en); input read_en; input [3:0] addr; output [3:0] read_data; reg [3:0] read_data; reg [3:0] mem [0:15]; always @( addr or read_en) if (! read_en) read_data = mem[addr];endmodulemodule mymem (data, addr, read, write); inout [3:0] data; input [3:0] addr; input read, write; reg [3:0] mem [0:15]; // 16*4// 读读 assign data = read ? memory[addr] : 4'bz;// 写写 always @( posedge write) memory[addr] = data;endmodule ROMRAM 3.3 运算符及表达式按功能分类可分为按功能分类可分为算术运算符(+,-,X,/,%)赋值运算符(=,<=)关系运算符(>,<,>=,<=)逻辑运算符(&&,||,!)条件运算符(? :)位运算符(~,|,^,&,^~)移位运算符(<<,>>)拼接运算符({ })§3.3 运算符及表达式运算符及表达式 按所带操作数按所带操作数个数可分为个数可分为单目运算符双目运算符三目运算符例: clock=~=~clock;; c==a | b;; r==s ? T : u;;§3.3 运算符及表达式运算符及表达式 3.3.1 基本的算术运算符在Verilog HDL语言中,算术运算符又称为二进制运算符,共有下面几种: (1) + (加法运算符,或正值运算符,如rega+regb,+3); (2) - (减法运算符,或负值运算符,如rega-3,-3); (3) * (乘法运算符,如rega*3); (4) / (除法运算符,如5/3); (5) % (模运算符,或称为求余运算符,要求%两侧均为整型数据。

如7%3的值为1)§3.3 运算符及表达式运算符及表达式 规则:规则:在进行整数除法运算时,结果值要略去小数部分,只取整数部分;在进行整数除法运算时,结果值要略去小数部分,只取整数部分; 7/4 =1 -7/4 =-1 7/-4 =-1模运算表达式 结果 说明 10%3 1 余数为1 11%3 2 余数为2 12%3 0 余数为0,即无余数 -10%3 -1 结果取第一个操作数的符号位,所以余数为-1 11%-3 2 结果取第一个操作数的符号位,所以余数为2§3.3 运算符及表达式运算符及表达式 1、进行、进行取模运算取模运算时,结果值的符号位采用模运算式里时,结果值的符号位采用模运算式里第一个操第一个操作数作数的符号位。

的符号位 2、%两侧都应为整数 lVerilog根据表达式中变量的长度对表达式的值自动地进行调整根据表达式中变量的长度对表达式的值自动地进行调整lVerilog自动截断或扩展赋值语句中右边的值以适应左边变量的长度自动截断或扩展赋值语句中右边的值以适应左边变量的长度l当一个负数赋值给无符号变量如当一个负数赋值给无符号变量如reg时,时,Verilog自动完成二进制补码计算自动完成二进制补码计算module sign_size; reg [3:0] a, b; reg [15:0] c; initial begin a = -1; // a是无符号数,因此其值为1111 b = 8; c= 8; // b = c = 1000 #10 b = b + a; // 结果10111截断, b = 0111 #10 c = c + a; // c = 10111 endendmodule 例 parameter five = 5;l integer ans, int; l reg [3: 0] rega, regb; l reg [3: 0] num;l initial beginl rega = 3; l regb = 4'b1010;l int = -3; //int = 1111……1111_1101l endl initiall forkl #1 ans = five * int; // ans = -15l #2 ans = (int + 5)/ 2; // ans = 1l #3 ans = five/ int; // ans = -1l #4 num = rega + regb; // num = 1101l #5 num = rega + 1; // num = 0100l #6 num = int; // num = 1101l #7 num = regb % rega; // num = 1l join注意:在进行算术运算操在进行算术运算操作时,如果某一个操作数作时,如果某一个操作数有不确定的值有不确定的值x,则整个,则整个结果也为不定值结果也为不定值x。

§ §'b10x1 + 'b01111 'b10x1 + 'b01111 结果为结果为不确定数不确定数' ' b bx x x x x x x x x x 3.3.2 位运算符 Verilog HDL作为一种硬件描述语言,是针对硬件电路而言的在硬件电路中信号有4种状态值,即 1,,0,,x,,zVerilog HDL提供了以下5种位运算符: 1) ~ //取反 2) & //按位与 3) | //按位或 4) ^ //按位异或 5) ^~ //按位同或(异或非)§3.3 运算符及表达式运算符及表达式 (1)“取反”运算符~:~是一个单目运算符,用来对一个操作数进行按位取反运算~~结果结果1 10 00 01 1x xx x表表3.2((a)) 取反运算符的运算规则取反运算符的运算规则例如:rega=‘b1010; //rega的初值为’b1010rega=~rega; //rega的值进行取反运算后变为’b0101§3.3 运算符及表达式运算符及表达式 (2)“按位与”运算符&:按位与运算就是将两个操作数的相应位进行与运算。

&0 01 1x x0 00 00 00 01 10 01 1x xx x0 0x xx x表表3.2((b)) “按位与按位与”运算规则运算规则§3.3 运算符及表达式运算符及表达式rega = 4'b1001; regb = 4'b1010; rega & regb= (3)“按位或”运算符|:按位或运算就是将两个操作数的相应位进行或运算 |0 01 1x x0 00 01 1x x1 11 11 11 1x xx x1 1x x表表3.2((c)) “按位或按位或”运算规则运算规则§3.3 运算符及表达式运算符及表达式rega = 4'b1001; regb = 4'b1010; rega I regb= (4)“按位异或”运算符^(也称之为XOR运算符):按位异或运算就是将两个操作数的相应位进行异或运算^ ^0 01 1x x0 00 01 1x x1 11 10 0x xx xx xx xx x表表3.2((d)) “按位异或按位异或”运算规则运算规则§3.3 运算符及表达式运算符及表达式rega = 4'b1001; regb = 4'b1010; rega ^ regb= (5)“按位同或”运算符^~:按位同或运算就是将两个操作数的相应位先进行异或运算再进行非运算。

^~^~0 01 1x x0 01 10 0x x1 10 01 1x xx xx xx xx x表表3.2((e)) “按位同或按位同或”运算规则运算规则 注意: 不同长度的数据进行位运算: 系统自动的将两者按右端对齐右端对齐位数少的操作数会在相应的高位用高位用0填满填满,以使两个操作数按位进行操作 a=5’b10001 b=2’b10 a | b=5’b10001 | 5’b00010=5’b10011 §3.3 运算符及表达式运算符及表达式位值为位值为x时不一定产生时不一定产生x结果结果 regb = 4'b1010; regc = 4'b11x0; num = regb | regc; // num = 1110 3.4 小 结(1)在Verilog模块中所有过程块(如:initiaI块、always块)、连续赋值语句、实例引用都是并行的;(3)在同一模块中各个过程块、各条连续赋值语句和各条实例引用语句这三者出现的先后顺序没有关系;(4)只有连续赋值语句(即用关键词assign引出的语句)和实例引用语句(即用已定义的模块名引出的语句),可以独立于过程块而存在于模块的功能定义部分。

5)被实例引用的模块,其端口可以通过不同名的连线或寄存器类型变量连接到别的模块相应的输出、输入信号端;(6)在“always”块内被赋值的每一个信号都必须定义成reg型2)实例引用表示的是一种通过变量名互相连接的关系;§3.4 小结小结 思考题1、模块由几个部分组成?2、端口分为几种?3、为什么端口要说明信号的位宽?4、能否说模块相当于电路图中的功能模块,端口相当于功能模块的引脚?5、模块中的功能描述可以由哪几类语句或语句块组成?它们出现的顺序会不会影响功能的描述?6、这几类描述中哪一种直接与电路结构有关?7、最基本的Verilog变量有几种类型?8、reg型和wire型变量的差别是什么?9、由连续赋值语句(assign)赋值的变量能否是reg类型的?10、在always块中被赋值的变量能否是wire类型的?如果不能是wire类型,那么必须是什么类型的?它们表示的一定是实际的寄存器吗?11、参数类型的变量有什么用处?12、Verilog语法规定的参数传递和重新定义功能有什么直接的应用价值?13、逻辑比较运算符小于等于“<=”和非阻塞赋值“<=”的表示是完全一样的,为什么Verilog在语句解释和编译时不会搞错?14、是否可以说实例引用的描述实际上就是严格意义上的电路结构描述?第第3章章 模块的结构、数据类型、变量和基本运算符号模块的结构、数据类型、变量和基本运算符号 第四章 运算符、赋值语句和结构说明语句4.1 4.1 逻辑运算符逻辑运算符4.2 4.2 关系运算符关系运算符4.3 4.3 等式运算符等式运算符4.4 4.4 移位运算符移位运算符4.5 4.5 位拼接运算符位拼接运算符4.6 4.6 缩减运算符缩减运算符4.7 4.7 优先级别优先级别4.8 4.8 关键词关键词4.9 4.9 赋值语句和块语句赋值语句和块语句第第4章章 运算符、赋值语句和结构说明语句运算符、赋值语句和结构说明语句 4.1 逻辑运算符逻辑运算符在Verilog HDL语言中存在3种逻辑运算符: (1) && 逻辑与 是二目运算符,它要求有两个操作数 (2) || 逻辑或 (3) ! 逻辑非 是单目运算符,它要求有一个操作数 a ab b!a!a!b!ba&&ba&&ba||ba||b真真真真假假假假真真真真真真假假假假真真假假真真假假真真真真假假假假真真假假假假真真真真假假假假表表4.1 逻辑运算真值表逻辑运算真值表§4.1 逻辑运算符逻辑运算符 逻辑运算符中“&&”和“||”的优先级别低于关系运算符,“!”高于算术运算符。

(a>b)&&(x>y) 可写成:可写成:a>b&&x>y (a= =b)||(x====y) 可写成:可写成:a====b|| x====y (!a)||(a>b) 可写成:可写成:!a || a>b 为了提高程序的可读性,明确表达各运算符间的优先关系,建议使用括号§4.1 逻辑运算符逻辑运算符注:与位运算的区别注:与位运算的区别 l逻辑操作符的结果为一逻辑操作符的结果为一位位1,,0或或xl逻辑操作符只对逻辑值逻辑操作符只对逻辑值运算l如操作数为全如操作数为全0,则其逻,则其逻辑值为辑值为falsel如操作数有一位为如操作数有一位为1,则,则其逻辑值为其逻辑值为truel若操作数只包含若操作数只包含0、、x、、z,则逻辑值为,则逻辑值为xl逻辑反操作符将操作数逻辑反操作符将操作数的逻辑值取反例如,的逻辑值取反例如,若操作数为全若操作数为全0,则其,则其逻辑值为逻辑值为0,逻辑反操,逻辑反操作值为作值为1lparameter five = 5;l reg ans;l reg [3: 0] rega, regb, regc;l initiall beginl rega = 4‘b0011; //逻辑值为逻辑值为“1”l regb = 4‘b10xz; //逻辑值为逻辑值为“1”l regc = 4‘b0z0x; //逻辑值为逻辑值为“x”l endl initial l forkl #1 ans = rega && 0; // ans = 0l #2 ans = rega || 0; // ans = 1l #3 ans = rega && five; // ans = 1l #4 ans = regb && rega; // ans = 1l #5 ans = regc || 0; // ans = xl joinlendmodule 逻辑反与位反的对比逻辑反与位反的对比! logical not 逻辑反逻辑反~ bit-wise not 位反位反 逻辑反的结果为一位逻辑反的结果为一位1,,0或或x。

位反的结果与操作数的位数相同位反的结果与操作数的位数相同module negation(); reg [3: 0] rega, regb; reg [3: 0] bit; reg log; initial begin rega = 4'b1011; regb = 4'b0000; end initial fork #10 bit = ~rega; // num = 0100 #20 bit = ~regb; // num = 1111 #30 log = !rega; // num = 0 #40 log = !regb; // num = 1 #50 $finish; joinendmodule 4.2 关系运算符关系运算符共有以下4种: (1) ab a大于b (3) a<=b a小于或等于b (4) a>=b a大于或等于b说明:关系为假关系为假(flase),则返回值是,则返回值是0;关系为真;关系为真(true),则返回值是,则返回值是1;如;如果某个操作数的值不定,则关系是模糊的,返回值是不定值果某个操作数的值不定,则关系是模糊的,返回值是不定值x。

§4.2 关系运算符关系运算符 所有的关系运算符有着相同的优先级别关系运算符的优先级别低于算术运算符的优先级别见下例: aB 逻辑1 D>=C 逻辑1 DB)?1:0; 4.3 等式运算符在Verilog HDL语言中存在4种等式运算符; (1) == (等于); (2) != (不等于); (3) === (等于); (4) !== (不等于)§4.3 等式运算符等式运算符注:!注:! 双等号双等号 三等号之间不能有空格三等号之间不能有空格 “==”和“!=”又称为逻辑等式运算符,其结果由两个操作数的值决定。

由于操作数中某些位可能是不定值x和高阻值z,结果可能为不定值x “===”和“!==”运算符在对操作数进行比较时对不定值x和高阻值z也进行比较,两个操作数必须完全一致,其结果才是1,否则为0和“!==”运算符常用于case表达式的判别,所以又称为“case等式运算符”关键点:结果不会出现x,只能是1或0§4.3 等式运算符等式运算符===01xz==01xz01000010xx10100101xxx0010xxxxxz0001zxxxx表表4.2 等式运算符的真值表等式运算符的真值表 §4.3 等式运算符等式运算符if(A==1’bx) $display(“A is X”); (当A等于x时,这个语句不执行)if(A===1’bx) $display(“A is X”); (当A等于X时,这个语句执行)下面举一个例子说明下面举一个例子说明“====”和和“======”的区别 a=4’b1010 b=4’b1101 c=4’b1xxz m=4’b1xxz n=4’b1xxx a!=b 逻辑1 c==a 逻辑x c==m 逻辑x c===m 逻辑1 c===n 逻辑0 4.4 移位运算符 在Verilog HDL中有两种移位运算符:“<<”(左移位运算符)和“>>”(右移位运算符)。

其使用方法如下: a>>n 或 a<>1=4’b0100; 4’b1001>>4=4’b0000;module shift;; reg [3::0] start,,result;; initial begin start ==1;; //start值0001 result==(start<<2);; endendmodule进行移位运算时应注意移位前后变量的位数 §4.4 移位运算符移位运算符?? 仿真波形 4.5 位拼接运算符在Verilog HDL语言中有一个特殊的运算符:{ }即:即: 位拼接运算符位拼接运算符 用这个运算符可以把两个或多个信号的某些位拼接起来进行运算操用这个运算符可以把两个或多个信号的某些位拼接起来进行运算操作。

作其使用方法如下: {信号信号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.5 位拼接运算符位拼接运算符 位拼接还可以用重复法来简化表达式见下例: { 4 { w } } 等同于等同于 {w,,w,,w,,w}位拼接还可以用嵌套的方式来表达见下例: {b,,{3{a,,b}}} 等同于等同于 {b,,a,,b,,a,,b,,a,,b} 注意:注意:在位拼接表达式中不允许存在没有指明位数没有指明位数的信号因为在计算拼接信号位宽的大小时必须知道其中每个信号的位宽a[3] a[2] a[1] a[0]wire [3:0] a;b[3] b[2] b[1] b[0]wire [3:0] b;a[3] a[2] a[1] a[0] b[3] b[2] b[1] b[0]{a,b}a和b可表达的十进制数范围均为0~15,而{a,b}可表示0~255范围的十进制数§4.5 位拼接运算符位拼接运算符 例在级联和复制时,必须指在级联和复制时,必须指定位数,否则将产生错误。

定位数,否则将产生错误下面是类似错误的例子:下面是类似错误的例子: a[7:0] = {4{ ´b10}}; b[7:0] = {2{ 5}}; c[3:0] = {3´b011, ´b0};级联时不限定操作数的数级联时不限定操作数的数目在操作符符号目在操作符符号{ }中,中,用逗号将操作数分开用逗号将操作数分开 {A, B, C, D}module concatenation; reg [7: 0] rega, regb, regc, regd; reg [7: 0] new; initial begin rega = 8'b0000_0011; regb = 8'b0000_0100; regc = 8'b0001_1000; regd = 8'b1110_0000; end initial fork #10 new = {regc[ 4: 3], regd[ 7: 5], regb[ 2], rega[ 1: 0]}; // new = 8'b11111111 #20 new= {4{ regb[2]}}; // new = 11111111 joinendmodule 4.6 缩减运算符 缩减运算符(reduction operator)是单目运算符,也有与、或、异或、同或等运算。

缩减运算是对单个操作数进行与、或、异或、同或等的递缩减运算是对单个操作数进行与、或、异或、同或等的递推运算,推运算,最后的运算结果是最后的运算结果是1位的二进制数位的二进制数缩减运算的具体运算过程是: 第一步先将操作数的第第一步先将操作数的第1位与第位与第2位进行与、或等运算;位进行与、或等运算; 第二步将运算结果与第第二步将运算结果与第3位进行与、或等运算,依次类推,直至最位进行与、或等运算,依次类推,直至最后后1位例如:例如:reg [3:0] B;; reg C;; C==&B;; 相当于:相当于: C==( ( B[0] & B[1]) & B[2]) & B[3];; §4.6 缩减接运算符缩减接运算符 例module reduction(); reg val; reg [3: 0] rega, regb; initial begin rega = 4'b0100; regb = 4'b1111; end initial fork #10 val = & rega ; // val = 0 #20 val = | rega ; // val = 1 #30 val = & regb ; // val = 1 #40 val = | regb ; // val = 1 #50 val = ^ rega ; // val = 1 #60 val = ^ regb ; // val = 0 #70 val = ^rega && ®b; // val = 1 $finish; joinendmodule• 缩减操作符的操作数只有一个。

缩减操作符的操作数只有一个•对操作数的所有位进行位操作对操作数的所有位进行位操作•结果只有一位,可以是结果只有一位,可以是0, 1, X 条件操作符的语法条件操作符的语法l = ? :l l例如:例如:assign out = (en == 0) ? in :1’ bz;lassign out = sel == 2'b00 ? a :sel == 2'b01 ? b :sel == 2'b10 ? c : d;如果条件值为如果条件值为x或或z,则结果可能为,则结果可能为x或或z 4.7 运算符优先级 优先级别优先级别! ~* / %+ -<< >>< <= > >=== != === !==&^ ^~|&&||?:高优先级高优先级低优先级低优先级§4.7 运算符优先级运算符优先级 4.8 关键词 在Verilog HDL中,所有的关键词是事先定义好的确认符,用来组织语言结构关键词是用小写字母定义的 always,and,assign,begin,case,casex,casez,cmos,deassign,default,defparam,disable,edge,else,end,endcase,endmodule。

标识符标识符 字母、数字、字母、数字、$、下划线、下划线组成组成 ,区分大小写,,区分大小写, 但但第一个字符第一个字符必须是必须是字母或下划线字母或下划线 正确:正确: count, _a1, a$ 错误:错误: 3count,, cout* $a 4.9 赋值语句和块语句4.9.1 赋值语句在Verilog HDL语言中,信号有两种赋值方式:l 非阻塞非阻塞(non_blocking)赋值方式赋值方式 “b<==a”:: l 阻塞阻塞(blocking)赋值方式赋值方式 “b==a”::注:注:1、过程赋值、过程赋值 2、只能给寄存器变量赋值、只能给寄存器变量赋值§4.9 赋值语句和块语句赋值语句和块语句 (1)阻塞阻塞(blocking)赋值方式赋值方式 “b==a”:: ●赋值语句执行完后,块才结束; ●b的值在赋值语句执行完后立刻就改变; ●在时序逻辑中使用时(在沿触发的always块中使用时),综合后可能会产生意想不到的结果 这种赋值方式是立刻执行的,也就是说执行下一条语句时,这种赋值方式是立刻执行的,也就是说执行下一条语句时,b已等于已等于a。

§4.9 赋值语句和块语句赋值语句和块语句注:注:注:注:“ “=”=”既能用于既能用于既能用于既能用于“ “assign”assign”中,也能用于中,也能用于中,也能用于中,也能用于initialinitial、、、、alwaysalways中 reg b;reg c;always @(posedge clk) begin b==a;; c==b;; end【例4.2】图图 4.2 阻塞赋值方式的阻塞赋值方式的“always”电路图电路图aclkqaclkbc错误设计!错误设计!§4.9 赋值语句和块语句赋值语句和块语句 仿真 RTL-viewer (2)非阻塞非阻塞(non_blocking)赋值方式赋值方式 “b<==a”:: ●在语句块中,上面语句所赋的变量值不能立即就为下面的语句所用; ●块结束后才完成赋值操作,块结束前被赋值的变量保持上一次所赋的值; ●在编写可综合的时序逻辑模块时,这是最常用的赋值方法意即,在always块中经常使用 §4.9 赋值语句和块语句赋值语句和块语句这种方式的赋值不是立刻执行的,也就是说这种方式的赋值不是立刻执行的,也就是说“always”块内的下一条语句执行后,块内的下一条语句执行后,b并不等于并不等于a,而是保持原来,而是保持原来的值,的值,“always”块结束后,才进行赋值。

块结束后,才进行赋值 reg b;reg c;always @(posedge clk) begin b<=a;; c<==b;; end【例4.1】aclkqaclkqaclkbc图图 4.1 非阻塞赋值方式的非阻塞赋值方式的“always”电路图电路图…1010110101x10101xx§4.9 赋值语句和块语句赋值语句和块语句 仿真注:注:注:注:“ “《《《《=”=”不能用于不能用于不能用于不能用于“ “assign”assign”中,只能用于中,只能用于中,只能用于中,只能用于initialinitial、、、、alwaysalways中,只能对中,只能对中,只能对中,只能对regreg型变量进行赋值型变量进行赋值型变量进行赋值型变量进行赋值 RTL-viewer 阻塞与非阻塞赋值语句行为差别lmodule non_block1;l reg a, b, c, d, e, f;l initial beginl a = #10 1; // time 10l b = #2 0; // time 12l c = #4 1; // time 16l endl initial begin l d <= #10 1; // time 10l e <= #2 0; // time 2l f <= #4 1; // time 4l endl initiall beginl$monitor($ time,," a= %b b= %b c= %b d= %b e= %b f= %b", a, b, c, d, e, f);lendlendmodule输出结果:输出结果: 0 a= x b= x c= x d= x e= x f = x 2 a= x b= x c= x d= x e= 0 f = x 4 a= x b= x c= x d= x e= 0 f = 110 a= 1 b= x c= x d= 1 e= 0 f = 112 a= 1 b= 0 c= x d= 1 e= 0 f = 116 a= 1 b= 0 c= 1 d= 1 e= 0 f = 1 4.9.2 块语句块语句通常用来将两条或多条语句组合在一起,使其在格式上看更像一条语句。

块语句有两种:块语句块语句begin_end 用来标识顺序执行的语句,用它来标识的块称为顺序块顺序块;fork_ join 用来标识并行执行的语句,用它来标识的块称为并行块并行块§4.9 赋值语句和块语句赋值语句和块语句 1. 顺序块顺序块的特点: ●块内的语句是按顺序执行的,即只有上面一条语句执行完后下面的语句才能执行 ●每条语句的延迟时间是相对于前一条语句的仿真时间而言的 ●直到最后一条语句执行完,程序流程控制才跳出该语句块顺序块的格式如下: begin 语句句1 语句句2;; …… 语句句n;; end begin::块名名 块内声明内声明语句句 语句句1:: 语句句2;; …… 语句句n;; end或或说明: ●块名即该块的名字,一个标识名,其作用后面再详细介绍 ●块内声明语句可以是参数声明语句、reg型变量声明语句、integer型变量声明语句和real型变量声明语句。

§4.9 赋值语句和块语句赋值语句和块语句 begin areg==breg;; creg==areg;; //creg的的值为breg的的值 end【例4.3】begin areg==breg;; #10 creg==areg;; //在两条在两条赋值语句句间延延迟10个个时间单位位 end【例4.4】§4.9 赋值语句和块语句赋值语句和块语句第一条赋值语句先执行,areg的值更新为breg的值,然后程序流程控制转到第二条赋值语句,creg的值更新为areg的值因为这两条赋值语句之间没有任何延迟时间,creg的值实为breg的值当然可以在顺序块里延迟控制时间来分开两个赋值语句的执行时间 parameter d==50;; //声明声明d是一个参数是一个参数 reg [ 7::0] r;; //声明声明r是一个是一个8位的寄存器位的寄存器变量量 begin //由一系列延由一系列延迟产生的波形生的波形 #d r==’h35;; #d r==’hE2;; #d r==’h00;; #d r==’hF7;; #d -->end_wave;; //触触发事件事件end__wave end 【例4.5】05010015020035E200F7X250§4.9 赋值语句和块语句赋值语句和块语句 §4.9 赋值语句和块语句赋值语句和块语句l reg x, y;l reg[1:0] z, w;l initiall beginl x=1’b0;l y=1’b1;l z={x,y};l w={y,x};l end reg x, y; reg[1:0] z, w; initial begin x=1’b0; #5 y=1’b1; #10 z={x,y}; #20 w={y,x}; end 产生一个时序波形 2.并行块并行块的特点:●块内语句是同时执行的,即程序流程控制一进入到该并行块,块内语句则开始同时并行地执行。

●块内每条语句的延迟时间是相对于程序流程控制进入到块内的仿真时间●延迟时间是用来给赋值语句提供执行时序的●当按时间时序排序在最后的语句执行完后或一个disable语句执行时,程序流程控制跳出该程序块§4.9 赋值语句和块语句赋值语句和块语句并行并行块的格式如下:的格式如下: fork 语句句1;; 语句句2;; …… 语句句n,, joinfork::块名名块内声明内声明语句句语句句1;;语句句2;;……语句句n;;join或或注意注意:fork-join块是不可综合语句块是不可综合语句 fork #50 r==’h35;; #100 r==’hE2;; #150 r==’h00;; #200 r==’hF7;; #250 —> end_wave;;//触触发事件事件end_wavejoin【例4.6】05010015020035E200F7X250§4.9 赋值语句和块语句赋值语句和块语句fork和和join语句常用于语句常用于test bench描述。

这是因为可以一起描述这是因为可以一起给出矢量及其绝对时间,而不必描述所有先前事件的时间给出矢量及其绝对时间,而不必描述所有先前事件的时间 例 (完成的仿真时刻不同) reg x, y; reg[1:0] z, w; initial fork x=1’b0; y=1’b1; z={x,y}; w={y,x}; join reg x, y; reg[1:0] z, w; initial fork x=1’b0; #5 y=1’b1; #10 z={x,y}; #20 w={y,x}; join §4.9 赋值语句和块语句赋值语句和块语句 在Verilog HDL语言中,可以给每个块取个名字,只需将名字加在关键词begin或fork后面即可这样做的原因有以下几点: 1)可以在块内定义局部变量,即只在块内使用的变量;可以在块内定义局部变量,即只在块内使用的变量; 2) 是设计层次的一部分,命名块中声明的变量可以通过层次名引用进行访问是设计层次的一部分,命名块中声明的变量可以通过层次名引用进行访问 3)可以使用关键词可以使用关键词disable禁止一个命名块禁止一个命名块3.块 名(命名块)§4.9 赋值语句和块语句赋值语句和块语句 begin: block1 integer i; // 变量i是block1的静态本地变量 …….. //可通过层次名 top.block1.i被其他模块访问 end ……. l命名块的禁用l关键字:disablel l Verilog通过disable提供了一种中止命名块执行的方法。

disable可以用来从循环中退出、处理错误条件以及根据控制信号来控制某些代码段是否被执行l 块语句禁用后,紧接在块语句后的语句被执行 disable是典型的不可综合语句是典型的不可综合语句 命名块的禁用命名块的禁用……..disablelreg [15:0] flag;linteger i;linitiallbeginl flag=16’b0010_0000_0000_0000;l i=0;l begin: block1l while(i<16)l beginl if(flag[i])l beginl $display(“Encountered a True bit at element number %d”,i);l disable block1; //找到值为找到值为1的位,禁用的位,禁用block1l end l i=i+1;l endl endlend 4.起始时间和结束时间 在并行块和顺序块中都有一个起始时间和结束时间的概念。

对于顺序块,起始时间就是第一条语句开始被执行的时间,结束时间就对于顺序块,起始时间就是第一条语句开始被执行的时间,结束时间就是最后一条语句执行完的时间;是最后一条语句执行完的时间; 对于并行块,起始时间对于块内所有的语句是相同的,即程序流程控制进对于并行块,起始时间对于块内所有的语句是相同的,即程序流程控制进入该块的时间,其结束时间是按时间排序在最后的语句执行结束的时间入该块的时间,其结束时间是按时间排序在最后的语句执行结束的时间 §4.9 赋值语句和块语句赋值语句和块语句 在在fork_join块内,各条语句不必按顺序给出块内,各条语句不必按顺序给出,因此在并行块里,各条语句在前还是在后是无关紧要的fork #250 -->end_wave;; #200 r==’hF7;; #150 r==’h00;; #100 r==’hE2;; #50 r==’h35;; join【例4.7】 在这个例子中,各条语句并不是按被执行的先后顺序给出的,但同样可以生成前面例子中的波形。

§4.9 赋值语句和块语句赋值语句和块语句 l当一个块嵌入另一个块时,块的起始时间和结束时间是很重要的跟跟在块后面的语句在该块的结束时间到了才能开始执行,在块后面的语句在该块的结束时间到了才能开始执行,也就是说,只有该块完全执行完后,后面的语句才可以执行例: begin #2 x=1’b0; fork #5 y=1’b1; #10 z={x,y}; join #20 w={y,x}; end 嵌套块 小结 (1)无论是逻辑运算、逻辑比较还是逻辑等式等逻辑操作一般发生在条件判断语句中,其输出只有1或0,也可以理解为成立(真)或不成立(假) && II ! == <= >= < > (2)位拼接运算符{ },可以借助于拼接符用一个信号名来表示由多位信号组成的复杂信号,其中每个功能信号可以有自己独立的名字和位宽例如控制信号,可以用如下的位拼接来表示:assign control={read,write,sel[2:0],halt, load_instr,…};这样可以大大提高程序的可读性和可维护性。

(3)缩减运算符(reduction operator) -----合理地使用缩减运算符可以使程序简洁、明了 &a Ia ^a(4)阻塞和非阻塞赋值--在硬件实现时这两者有很大的不同 注:注:I I 、、““<=<= ” ” 不能用于不能用于assign assign assignassign out=out=a+ba+b; ; 用在用在initial always initial always 块块 II II 、、 “ “=“ =“ 即可用于即可用于assignassign,又可用于,又可用于initial always initial always IIIIII、、 “ “=“=“ —— 组合逻辑, ““<=<= ” —” —— — 时序逻辑、时序逻辑、 IIIIIIII、在同一个过程块,最好不要同时用、在同一个过程块,最好不要同时用““=” =” ““《《=”=” (5)begin end块、fork join块,起始时间、结束时间。

思考题1、逻辑运算符与按位逻辑运算符有什么不同,它们各在什么场合使用?2、指出两种逻辑等式运算符的不同点,解释书上的真值表3、拼接符的作用是什么?为什么说合理地使用拼接符可以提高程序的可读性和可维护性?拼接符表示的操作其物理意义是什么?4、如果都不带时间延迟,阻塞和非阻塞赋值有什么不同?举例说明它们的不同点5、举例说明顺序块和并行块的不同?6、如果在顺序块中,前面有一条语句是无限循环,下面的语句能否进行?7、如果在并行块中,发生上述情况,会如何呢?第第4章章 运算符、赋值语句和结构说明语句运算符、赋值语句和结构说明语句 第五章第五章 条件语句、循环语句、块语句条件语句、循环语句、块语句5.1 条件语句(if_else语句)5.2 case语句5.3 条件语句的语法5.4 多路分支语句5.5 循环语句5.6 顺序块和并行块5.7 生成块5.8 举例第第5章章 条件语句、循环语句、块语句与生成语句条件语句、循环语句、块语句与生成语句 5.1 条件语句(if_else语句) if语句是用来判定所给定的条件是否满足,根据判定的结果(真或假)决定执行给出的两种操作之一。

Verilog HDL提供了3种形式得if语句1)if(表达式)语句(表达式)语句例如: if(a>b) out1=int1;註: 生成锁存器§5.1 条件语句(条件语句(if_else语句)语句) ((2))if(表达式)(表达式) 语句句1 else 语句句2例如:例如: if(a>b) out1=int1;else out1=int2; §5.1 条件语句(条件语句(if_else语句)语句)if(a&&b) out=1; else out=0; (3))if(表达式)(表达式) 语句句1;; else if(表达式(表达式2)) 语句句2;; else if(表达式(表达式3)) 语句句3;; …… else if(表达式(表达式m)) 语句句m;; else 语句句n;;例如:例如: if(a>b) out1=int1; else if(a==b) out1=int2; else out1=int3;§5.1 条件语句(条件语句(if_else语句)语句) 注意:条件语句必须在过程块语句中使用。

所谓过程块语句是指由initial和always语句引导的执行语句集合除了这两种块语句引导的begin end块中可以编写条件语句外,模块中的其他地方都不能编写例如:例如:always @(some_event) begin if(a>b) out1=int1; else if(a==b) out1=int2; else out1=int3; end§5.1 条件语句(条件语句(if_else语句)语句) 说明:(1)3种形式的if语句在if后面都有“表达式”,一般为逻辑表达式或关系表达式系统对表达式的值进行判断,若为若为0,,x,,z,按,按“假假”处理;若为处理;若为1,按,按“真真”处理处理,执行指定的语句 (2)第2)、第3)种形式的if语句,在每个else前面有一个分号,整个语句结束处有一个分号例如: if(a>b) out1=int1; else out1=int2;各有一个分号§5.1 条件语句(条件语句(if_else语句)语句) (3)在if和else后面可以包含一个内嵌的操作语句,也可以有多个操作语句,此时用begin和end这两个关键词将几个语句包含起来成为一个复合块语句。

如: if(a>b) begin out1<=int1;; out2<=int2;; end else begin out1<=int2;; out2<=int1;; end §5.1 条件语句(条件语句(if_else语句)语句) (4)允许一定形式的表达式简写方式如下面的例子: if(expression) 等同与等同与 if(expression====1) if(!expression) 等同与等同与 if(expression!==1)§5.1 条件语句(条件语句(if_else语句)语句) (5)if语句的嵌套在if语句中又包含一个或多个if语句称为if语句的嵌套一般形式如下: if(expression1) if(expression2) 语句句1;; (内嵌内嵌if) else 语句句2;; else if(expression3) 语句句3;(内嵌;(内嵌if)) else 语句句4;; 注意注意:if与else的配对关系,else总是与它上面最近的总是与它上面最近的if配对配对。

可以用begin_end块语句来确定配对关系例如: if( a ) begin if( b ) 语句语句1 (内嵌内嵌if) end else 语句语句2if( a ) if( b ) 语句语句1 (内嵌内嵌if)else 语句语句2 例if(index>0) for(scani=0;;scani0) begin $display(“......”);; memory[scani]=0;; endelse //*WRONG*//$display(“error--index is zero”);; if(index>0) begin for(scani==0;; scani0) begin $display(“…”);; memory[scani]==0;; end end else //*WRONG*//$display(“error--index is zero”);; 这部分程序用if_else语句来检测变量index,以决定3个寄存器modify_segn中哪一个的值应当与index相加作为memory的寻址地址,并且将相加值存入寄存器index以备下次检测使用。

reg [31:0] instruction,segment_area[255:0]; reg [7:0] index; reg [5:0] modify_seg1,modify_seg2, modify_seg3; parameter segment1=0, inc_seg1=1, segment2=20,inc_seg2=2, segment3=64,inc_seg3=4, data=128; //检测寄存器index的值 if (index endcase (2) casez (表达式表达式) endcase (3) casex (表达式表达式) endcase 5.2 case语句§5.2 case语句语句 说 明: (1)case括弧内的表达式称为控制表达式控制表达式,case分支项中的表达式称为分分支表达式支表达式。

(2)当控制表达式的值与分支表达式的值相等时,执行分支表达式后面的语句如果所有的分支表达式的值都没有与控制表达式的值相匹配,就执行default后面的语句 (3)一个case语句里只准有一个default项对于default项,若分支表达式若分支表达式将所有情况列出,可不写将所有情况列出,可不写default项;有未列出的可能值,应写项;有未列出的可能值,应写default项§5.2 case语句语句case(控制表达式控制表达式) 分支表达式分支表达式1:: 语句;语句; 分支表达式分支表达式2:: 语句;语句; 默认项默认项(default):: 语句;语句; endcase reg [15::0] rega;; reg [9::0] result;; case(rega) 16’d0:: result==10’b0111111111;; 16’d1:: result==10’b1011111111;; 16’d2:: result==10’b1101111111;; 16’d3:: result==10’b1110111111;; 16’d4:: result==10’b1111011111;; 16’d5;; result==10’b1111101111;; 16’d6;; result==10’b1111110111;; 16’d7:: result==10’b1111111011;; 16’d8:: result==10’b1111111101;; 16’d9:: result==10’b1111111110;; default:: result==10’bx;; endcase§5.2 case语句语句 (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控制表达式的位宽)§5.2 case语句语句 case语句与if_else_if语句的区别: (1)if_else_if(1)if_else_if结构中的条件表达式更为直观结构中的条件表达式更为直观 §5.2 case语句语句 (2)if(2)if语句具有优先级,可用于描述具有优先级的电路;语句具有优先级,可用于描述具有优先级的电路; casecase语句不具语句不具有优先级,只能用于描述无优先级的电路。

有优先级,只能用于描述无优先级的电路 case语句通常综合成一级多路复用器,而if--else则综合成优先编码的串接的多个多路复用器,通常使用case 语句要比if语句快case 语句仿真要比条件赋值语句快 (3)对于那些分支表达式中存在值为不定值x和高阻值z的 位时,case语句提供了处理这种情况的手段 case(select[1::2]) 2’b00:: result==0;; 2’b01:: result==flaga;; 2’b0x,, 2’b0z:: result==flaga?’bx::0;; 2’b10:: result==flagb;; 2’bx0,, 2’bz0:: result==flagb?’bx::0;; default::result==’bx;; endcase§5.2 case语句语句case0 01 1x xz z0 01 10 00 00 01 10 01 10 00 0x x0 00 01 10 0z z0 00 00 01 1 case(sig) 1’bz:: $display(“signal is floating”);; 1’bx:: $display(“signal is unknown”);; default::$display(“signal is %%b”,,sig);; endcase【例5.2】§5.2 case语句语句 Verilog HDL提供了case语句的其他两种形式,即casez和casex,这可用来处理比较过程中的不必考虑的情况。

所谓不必关心的情况,即在表达式进行比较时,不将该位的状态考虑在内casez0 01 1x xz z0 01 10 00 01 11 10 01 10 01 1x x0 00 01 11 1z z1 11 11 11 1casex0 01 1x xz z0 01 10 01 11 11 10 01 11 11 1x x1 11 11 11 1z z1 11 11 11 1case(a) 2’b1x: out=1; // a=2’b1x, casez(a) 2’b1z: out=1; // a=2’b10, 11, 1x, 1z 2’b1x: out=0; // a=2’b1x, 1zcasex(a) 2’b1x: out=1; // a=2’b10, 11, 1x, 1zcase 0 01 1x xz z0 01 10 00 00 01 10 01 10 00 0x x0 00 01 10 0z z0 00 00 01 1 reg[7::0] ir;; casez(ir) 8’b1???????::instruction1(ir);; 8’b01??????::instruction2(ir);; ………….. 8’b00010???::instruction3(ir);; 8’b000001??::instruction4(ir);; endcase【例5.3】§5.2 case语句语句 reg[7::0] r,,mask;; mask==8’bx0x0x0x0;; casex(r^mask) //r^mask=x-x-x-x- 8’b001100xx::stat1;; 8’b1100xx00::stat2;; 8’h00xx0011::stat3;; 8’bxx001100::stat4;; endcase【例5.4】§5.2 case语句语句 使用条件语句不当在设计中生成了不必要的锁存器使用条件语句不当在设计中生成了不必要的锁存器 Verilog HDL设计中容易犯的一个通病是由于对语言理解不全面,使用不准确,从而生成了并不想要的锁存器。

下面给出了一个在“always”块中不正确使用if语句,造成这种错误的例子always @(al or d)beginif(al) q=d;end有锁存器有锁存器综合后的电路结果§5.2 case语句语句要点:在在"always"块内,如果在给定的条件下变量没块内,如果在给定的条件下变量没有赋值,这个变量将保持原值,也就是说会生成一个锁有赋值,这个变量将保持原值,也就是说会生成一个锁存器 always @(al or d)beginIf(al) q=d;else q=0;end无锁存器无锁存器综合后的电路结果§5.2 case语句语句 Verilog HDL程序的另一种偶然生成锁存器是在使用case语句时缺少default项的情况下发生的always @(sel[1:0] or a or b)case (sel[1:0])2’b00: q<=a;2’b11: q<=b;endcasealways @(sel[1:0] or a or b)case (sel[1:0])2’b00: q<=a;2’b11: q<=b;default: q<=‘b0endcase有锁存器有锁存器无锁存器无锁存器§5.2 case语句语句 总结:为避免产生不必要的锁存器,应遵循下面两个原则: 1、如果用到、如果用到if语句,最好写上语句,最好写上else项;项;2、如果用、如果用case语句,最好写上语句,最好写上default项。

项 遵循上面两条原则,就可以避免发生这种设计错误,使设计者更加明确设计目标,同时也增强了Verilog程序的可读性§5.2 case语句语句 5.3 条件语句的语法条件语句的语法//第一第一类条件条件语句句if (!lock) buffer=data;if (enable) out=in;//第二第二类条件条件语句句if(number_queued

它与它与always语句不同之处在于它不能独立写在程序中,语句不同之处在于它不能独立写在程序中,而必须写在而必须写在initial块中§5.5 循环语句循环语句 产生周期波形 reg clock initial begin: m clock=1’b0; forever #10 clock=~clock; endinitial begin …… ……disable m 5.5.2 repeat语句repeat语句的格式如下: repeat(表达式表达式) 语句;句; 或 repeat(表达式表达式) begin 多条多条语句句 end在repeat语句中,其表达式通常为常量表达式§5.5 循环语句循环语句 下面的例子中使用repeat循环语句及加法和移位操作来实现一个乘法器移位相加乘法器原理1 0 0 1 ((9))0 1 1 0 ((6))×0 0 0 01 0 0 11 0 0 10 0 0 0++0 0 1 1 0 1 1 0 ((54))§5.5 循环语句循环语句 parameter size==8,,longsize==16;; reg [size::1] opa,,opb;; reg [longsize::1] result;; begin::mult reg [longsize::1] shift_opa,,shift_opb;; shift_opa=opa;; shift_opb=opb; result=0;; repeat(size) begin if(shift_opb[1]) result=result+shift_opa; shift_opa=shift_opa<<1;; shift_opb=shift_opb>>1;; end end§5.5 循环语句循环语句 5.2.3 while语句while语句的格式如下: while(表达式表达式) 语句句 或while(表达式表达式) begin 多条多条语句句 end§5.5 循环语句循环语句 下例用while循环语句对rega这个8位二进制数中值为1的位进行计数。

begin::count1s reg[7::0] tempreg;; count==0;; tempreg==rega;; while(tempreg) begin if(tempreg[0]) count==count+1;; tempreg==tempreg>>1;; end end§5.5 循环语句循环语句 5.5.4 for语句for语句的一般形式为: for(循环变量赋初值;循环结束条件;循环变量增值循环变量赋初值;循环结束条件;循环变量增值) 执行语句;执行语句; §5.5 循环语句循环语句begin 循环变量赋初值; while(循环结束条件) begin 执行语句 循环变量增值, end end begin::init_mem reg[7::0] tempi;; for(tempi==0;;tempi

§5.5 循环语句循环语句 在for循环中,循环变量增值表达式可以不必是一般的常规加法或减法表达式下面是对rega八位二进制数中值为1的位进行计数的另一种方法 begen::count1s reg[7::0] tempreg; count=0; for(tempreg=rega;tempreg;tempreg=tempreg>>1) if(tempreg[0]) count=count+1;end§5.5 循环语句循环语句 for循环按照时钟节拍运行lalways@(posedge clk)lbeginlfor(i=0;i<=1024;i=i+1)l mem[i]=i;l endlinitiallbeginlfor(i=0;i<=1024;i=i+1)l beginl mem[i]=i;l @(posedge clk)l endl end§哪一种哪一种? 第六章第六章 结构语句、系统任务、函数语句和显结构语句、系统任务、函数语句和显示系统任务示系统任务6.1 6.1 结构说明语句结构说明语句6.2 task6.2 task和和functionfunction说明语句说明语句6.3 6.3 关于使用任务和函数的小关于使用任务和函数的小结结6.4 6.4 常用的系统任务常用的系统任务6.5 6.5 其它系统函数和任务其它系统函数和任务第第6章章 结构语句、系统任务、函数语句和显示系统任务结构语句、系统任务、函数语句和显示系统任务 6.1 结构说明语句结构说明语句Verilog语言中的任何过程模块都从属于以下4种结构的说明语句: initial说明语句说明语句 always说明语句说明语句 task说明语句说明语句 function说明语句说明语句§6.1 结构说明语句结构说明语句 一个程序模块可以有多个initial和always过程块。

每个initial和always语句在仿真的一开始同时立即开始执行 在一个模块中,使用initial和always语句的次数是不受限制的 initial语句只执行一次,而语句只执行一次,而always语句则是不断地重复活语句则是不断地重复活动着,直到仿真过程结束动着,直到仿真过程结束 §6.1 结构说明语句结构说明语句 6.1.1 initial语句initial语句的格式如下: initial begin 语句句1;; 语句句2;; …… 语句句n;; end§6.1 结构说明语句结构说明语句 initial begin areg=0;; //初始化寄存器初始化寄存器areg for(index=0;;index

§6.1 结构说明语句结构说明语句 initial begin inputs==’b000000;; //初始初始时刻刻为0 #10 inputs==’b011001;; #10 inputs==’b011011;; #10 inputs==’b011000;; #10 inputs==’b001000;; end【例6.2】用initial语句来生成激励波形 从这个例子中,我们可以看到initial语句的另一用途,即用initial语句来生成激励波形作为电路的测试仿真信号 注意:一个模块中可以有多个initial块,它们都是并行运行的initial块常用于测试文件的编写,用来产生仿真测试信号和设置信号记录等仿真环境§6.1 结构说明语句结构说明语句 6.1.2 always语句声明格式如下: always <时序控制序控制> <语句句> always语句在仿真过程中是不断活动着的,但语句在仿真过程中是不断活动着的,但always语句后跟着的过语句后跟着的过程块是否执行,则要看它的触发条件是否满足,如满足则运行过程块一次;程块是否执行,则要看它的触发条件是否满足,如满足则运行过程块一次;如不断满足,则不断地循环执行。

如不断满足,则不断地循环执行 always语句由于其不断重复执行特性,只有和一定的时序控制结合在一起才有用如果一个always语句没有时序控制(条件或延时),则这个always语句将会生成一个仿真死锁例如:always areg=~areg; 但如果加上时序控制,则将变为一条非常有用的描述语句,如: always #half_period areg=~areg;上§6.1 结构说明语句结构说明语句 reg [7::0] counter;; reg tick;; always @(posedge areg) begin tick=~=~tick;; //产生何种生何种电路?路? counter==counter+1;;//产生何种生何种电路?路? end【例6.5】§6.1 结构说明语句结构说明语句 要点:always的时间控制可以是边沿触发边沿触发也可以是电平触发电平触发;可以是单个信号也可以是多个信号,当有多个信号时中间需要用关键字or连接。

always @(posedge clock or posedge reset) begin …… endalways @(a or b or c) begin …… end由两个边沿触发的always只要其中一个沿出现,就立即执行一次过程块由多个电平触发的always块,只要a、b、c中任何一个发生变化,从高到低或从低到高都会执行一次过程块§6.1 结构说明语句结构说明语句 要点:沿触发的always块用于描述时序逻辑,如有限状态机;电平触发的always块用来描述组合逻辑要点: 一个模块中可以有多个always块,它们都是并行运行的,多个always块没有前后之分§6.1 结构说明语句结构说明语句always@(op or a or b) begin case(op) 3’d0: y=a^b; 3’d1: y=a&b; ……. endcase always@(posedge clk) begin if(clr) cnt=0; else cnt=cnt+1; end 1、always块的or事件控制由关键词“or”连接的多个事件名或信号名组成的列表称为敏感列表敏感列表。

关键词关键词““oror””也可以用也可以用““,,””代替MAX+plus II不支持该语法,其它工具如Quartus II可以支持)always @(reset or clock or d)begin if(reset) q=1’b0; else if(clock) q=d;end【例6.6】§6.1 结构说明语句结构说明语句always @(reset , clock , d)begin if(reset) q=1’b0; else if(clock) q=d;end //用用reset异步下降沿复位,异步下降沿复位,clock正跳正跳变沿触沿触发的的D寄存器寄存器always @(posedge clk , negedge reset)if(!reset) q<=0;else q<=d;【例6.7】§6.1 结构说明语句结构说明语句当需要将所有输入信号列入敏感列表所有输入信号列入敏感列表时,可以使用两种方法简化书写: @* @* 和和 @(*)@(*) //一般写法一般写法always @(a or b or c or d or e or f or g or h or p or m) begin y1=a?b+c:d+e; y2=f?g+h:p+m; end//简化写法化写法always @(*)begin…end【例6.8】@*操作符的使用§6.1 结构说明语句结构说明语句包括所有输入变量包括所有输入变量 2.电平敏感时序控制 前面的事件控制使用符号@和敏感列表来表示,Verilog中也可以采用另外一种表示电平敏感时序控制的方法: 关键字wait表示等待电平敏感的条件为真。

always wait (count_enable) #20 count=count+1; always @( a or b) begin wait (!enable) out = a + b; end§6.1 结构说明语句结构说明语句注注::wait语句不能语句不能综合综合 将块的所有输入都列入敏感表是很好的描述习惯module sens (a, q, b, sl);linput a, b, sl;loutput q;lreg q; always @( sl )lbeginl if (! sl)l q = a;l elsel q = b;lendendmodulemodule sensc (q, a, b, sl);linput a, b, sl;loutput q;lreg q;lalways @( sl or a or b)lbeginl if (! sl)l q = a;l elsel q = b;lendendmodule敏感列表 几点说明:module cnt( q, data, load, clk,clr); output [7:0] q; input [7:0] data; input load, clk,clr; reg [7:0] q; always @(posedge clk) begin if( load ) q = data; else if(clr) q=0 ; else q=q+1; endendmodule1、时序逻辑尽量使用《=2、同步、异步?3、逻辑电平一致4、边沿型,电平型不要放在同一敏感列表5、电平型---组合 边沿型---时序 6.2 task和和function说明语句说明语句task —— 任务function —— 函数§6.2 task和和function说明语句说明语句任务和函数可以把一个很大的程序模块分解成许多较小的任任务和函数可以把一个很大的程序模块分解成许多较小的任务和函数,便于理解和调试。

任务和函数往往是在大的程序务和函数,便于理解和调试任务和函数往往是在大的程序模块中且在不同地点多次用到的相同的程序段使用模块中且在不同地点多次用到的相同的程序段使用tasktask和和functionfunction语句可以简化程序的结构,使程序明白易懂语句可以简化程序的结构,使程序明白易懂 6.2.2 task说明语句(1)任务的定义定义任务的语法如下: task <任任务名名>;; <端口及数据端口及数据类型声明型声明语句句> <语句句1> <语句句2> …… <语句句n> endtask§6.2 task和和function说明语句说明语句task my_task;; input a,,b;; output d,,e;; ……endtask任务和函数都必须在模块内进行定义,其作用范围仅局限于定义他们的模块任务和函数只能使用行为级语句,但不能包含always和initial块 (2)任务的调用及变量的传递 <任务名任务名> (端口端口1,端口,端口2,,…,端口,端口n);; §6.2 task和和function说明语句说明语句1、在always和initial块中调用任务。

2、参数列表必须与任务的端口声明顺序一致3、任务调用中接收返回数据的变量必须是寄存器类型task my_task;; input a,,b;; inout c;; output d,,e;; …… <语句句> //执行任行任务工作相工作相应的的语句句 ……endtask 任务调用: my_task(v,,w,,x,,y,,z);; §6.2 task和和function说明语句说明语句§ 说明:说明:* *包含时序控制(包含时序控制(# #延迟,延迟,@, wait@, wait))* *没有输出变量或输出变量数目大于一没有输出变量或输出变量数目大于一* *没有输入变量没有输入变量只能定义为任务 下面的任务中含有时序控制和一个输入,但没有输出、输入/输出和内部变量,也不显示任何结果lmodule top;l reg clk, a, b;l DUT u1 (out, a, b, clk);l always #5 clk = !clk;l task neg_clocks;l input [31:0] number_of_edges;l repeat( number_of_edges) @( negedge clk);l endtaskl initial beginl clk = 0; a = 1; b = 1;l neg_clocks(3); // 任务调用任务调用l a = 0; l neg_clocks (5);l b = 0;l endlendmodule 下面的任务中有输入,输出,时序控制,并且引用了一个module变量。

module mult (clk, a, b, out, en_mult); input clk, en_mult; input [3: 0] a, b; output [7: 0] out; reg [7: 0] out; always @( posedge clk) multme (a, b, out); // 任务调用任务调用 task multme; // 任务定义任务定义 input [3: 0] xme, tome; output [7: 0] result; wait (en_mult) result = xme * tome; endtaskendmodule 下面是一个具体的例子来说明怎样在模块设计中使用任务,使程序容易读懂 module traffic_lights;; reg clock,,red,,amber,,green;; parameter on==1,,off=0,,red_tics==350,, amber_tics=30,,green_tics=200;; //交通灯初始化交通灯初始化 initial red=off;; initial amber==off;; initial green=off;; //交通灯控制交通灯控制时序序 always begin red=on;; //开开红灯灯 light(red,,red_tics) //调用等待任用等待任务 green==on;; //开开绿灯灯 light(green,,green_ tics);; //等待等待 amber=on;; //开黄灯开黄灯 light(amber,,amber_tics);; //等待等待 end§6.2 task和和function说明语句说明语句 //定义交通灯开启时间的任务定义交通灯开启时间的任务 task light;; output color;; input [31::0] tics;; begin repeat(tics) @(posedge clock);; //等待等待tics个时钟的上升沿个时钟的上升沿 color==off;; //关灯关灯 end endtask//产生时钟脉冲的产生时钟脉冲的always块块 always begin #100 clock==0;; #100 clock==1;; end endmodule 这个例子描述了一个简单的交通灯的时序控制,并且该交通灯有它自己的时这个例子描述了一个简单的交通灯的时序控制,并且该交通灯有它自己的时钟产生器。

钟产生器§6.2 task和和function说明语句说明语句 说明:l任务的定义和调用都在一个模块内l任务内部不能包含initial,aways语句l可以有延时,定时控制l任务引用和模块调用一样,通过任务名端口调用l可以调用别的任务、函数和任务本身l可在任务内用disable将任务中断 6.2.3 function说明语句函数的目的是返回一个用于表达式的值1)定义函数的语法: function <返回返回值的的类型或范型或范围> (函数名函数名);; <端口端口说明明语句句> <变量量类型型说明明语句句> begin <语句句> …… end endfunction 注意:<返回值的类型或范围>这一项是可选项,如缺省则返回值为一位寄存器类型数据缺省则返回值为一位寄存器类型数据§6.2 task和和function说明语句说明语句function [7::0] getbyte;; input [15::0] address;; begin <说明明语句句> endendfunction function [7::0] getbyte;; input [15::0] address;; begin <说明明语句句> //从地址字中提取低字从地址字中提取低字节的程序的程序 getbyte==result_expression;; //把把结果果赋予函数的返回字予函数的返回字节 endendfunction§6.2 task和和function说明语句说明语句(2)从函数返回的值: 函数的定义隐含声明了与函数同名的内部寄存器。

如在函数的声明语句中<返回值的类型或范围>为缺省,则这个寄存器是一位的,否则是与函数定义中<返回值的类型或范围>一致的寄存器 函数返回值可以声明为其它register类型:integer, real, 或time在任何表达式中都可调用函数 (3)函数的调用: 函数的调用是通过将函数作为表达式中的操作数作为表达式中的操作数来实现的其调用格式如下: 变量=变量=<函数名函数名> (<表达式表达式>, <表达式表达式>, ……);; 下面的例子中通过对两次调用函数getbyte的结果进行位拼接运算来生成一个字: word==control?{getbyte(msbyte),,getbyte(lsbyte)}::0;;§6.2 task和和function说明语句说明语句function [7::0] getbyte;; input [15::0] address;; begin <说明明语句句> //从地址字中提取低字从地址字中提取低字节的程序的程序 getbyte==result_expression;; //把把结果果赋予函数的返回字予函数的返回字节 endendfunction module checksub (neg, a, b); output neg; reg neg; input a, b; function integer sub; input [7: 0] in_a, in_b; sub = in_a - in_b; // 结果可能为负结果可能为负 endfunction always @ (a or b) if (sub ( a, b) < 0) neg = 1; else neg = 0;endmodule数据类型 module orand (a, b, c, d, e, out); input [7: 0] a, b, c, d, e; output [7: 0] out; reg [7: 0] out; always @( a or b or c or d or e) out = f_or_and (a, b, c, d, e); // 函数调用函数调用 function [7:0] f_or_and; input [7:0] a, b, c, d, e; if (e = = 1) f_or_and = (a | b) & (c | d); else f_or_and = 0; endfunctionendmodule 函数的使用规则:函数的使用规则: 与任务相比较,函数的使用有较多的约束。

●函数的定义不能包含有任何的时间控制语句,即任何用#、@或wait 来标识的语句; ●定义函数时至少要有一个输入参数; ●在函数的定义中必须有一条赋值语句给函数的一个内部变量赋结果值,该内部变量和函数同名 ● ●不含有不含有 “ “<= ”<= ”语句 ● ●没有输出或没有输出或inoutinout变量变量 ●函数不能启动任务;§6.2 task和和function说明语句说明语句 module tryfact;//函数的定函数的定义function [31:0] factorial;input [3:0] operand;reg [3:0] index;begin factorial=1; for(index=2;index<=operand;index=index+1) factorial=index*factorial; end endfunction【例6.10】定义一个可进行阶乘运算的名为factorial的函数,该函数返回一个32位的寄存器型的值,可以后向调用自身并打印结果。

§6.2 task和和function说明语句说明语句 //函数的函数的测试reg [31:0] result;reg [3:0] n;initialbegin result=1; for(n=2;n<=9;n=n+1) begin $display(“Partial result n=%d result=%d”,n,result); result=n*factorial(n)/((n*2)+1); end $display(“Finalresult=%d”,result);endendmodule //模模块结束束§6.2 task和和function说明语句说明语句 module parity;reg [31:0] addr;reg parity;initialbegin addr=32’h3456_789a; #10 addr=32’hc4c6_78ff; #10 addr=32’hff56_ff9a; #10 addr=32’h3faa_aaaaend【例6.11】偶校验位的计算偶校验——数据中“1”的个数为偶数的时候,这个校验位就是“0”,否则这个校验位就是“1”。

即加上校验位,1的个数始终为偶数 §6.2 task和和function说明语句说明语句 //每当地址每当地址值发生生变化,化,计算新的偶校算新的偶校验位位always @(addr)begin parity=calc_parity(addr); $display(“Parity calculated=%b”,cal_parity(addr));end//定定义偶校偶校验计算函数算函数function calc_parity;input [31:0] address;begin calc_parity= ^address;//返回所有地址位的异或返回所有地址位的异或值endendfunctionendmodule§6.2 task和和function说明语句说明语句 function calc_parity(input [31:0] address);begin calc_parity= ^address;//返回所有地址位的异或返回所有地址位的异或值endendfunction可以使用C风格进行函数定义 【例6.12】§6.2 task和和function说明语句说明语句 module shifter;`define LEFT_SHIFT 1’b0`define RIGHT_SHIFT 1’b1reg [31:0] addr,left_addr,right_addr;reg control;always @(addr)begin left_addr=shift(addr,`LEFT_SHIFT); right_addr=shift(addr,`RIGHT_SHIFT);endfunction [31:0] shift;input [31:0] address;input control;begin shift=(control==`LEFT_SHIFT)?(address<<1):(address>>1);endendfunctionendmodule【例6.13】左/右移位寄存器§6.2 task和和function说明语句说明语句 task和function的不同点 1)函数只能与主模块共用同一个仿真时间单位,而任务可以定义 自己的仿真时间单位。

l2)函数不能启动任务,而任务能启动其他任务和函数l3)函数至少要有一个输入变量,而任务可以没有或有多个任何类型的变量l4)函数返回一个值,而任务则不返回值l5)函数中不能有disable,任务中可以 6)函数调用语句不能单独作为一条语句出现,只能作为赋值语句的右端操作数任务任务---------一个任务就像一个过程,它可以从不同位置执行共同的代码段其中可以包含延迟、时序、事件等语法结构,可以具有多个输出变量函数函数---------用于代替纯组合逻辑的Verilog代码,只能有一个输出一般用于各类转换和常用的计算它不能包含任何时延或时序控制 任务及函数共同点l任务和函数必须在任务和函数必须在modulemodule内调用内调用l在任务和函数中不能声明在任务和函数中不能声明wirewirel所有输入所有输入/ /输出都是输出都是局部局部寄存器寄存器l任务任务/ /函数执行完成后才返回结果函数执行完成后才返回结果l 例如,若任务例如,若任务/ /函数中有函数中有foreverforever语句,语句,则永远不会返回结果则永远不会返回结果 小结(1)一个程序模块可以有多个initial和always过程块。

2)每个initial和always在仿真的一开始便同时立即开始 运行3)initial语句在模块中只执行一次4)always语句则是不断地重复执行,直到仿真过程结束5)always语句后跟着的过程块是否运行,则要看它的触发条件是 否满足,如满足则运行过程块一次,再次满足则再运行一次,循环往复直至仿真 过程结束6)always的时间控制可以是沿触发也可以是电平触发,可以是单个信号也可以是多个信号,中间需要用关键宇or连接7)沿触发的always块常常描述时序行为,如有限状态机8)电平触发的always块常常用来描述组合逻辑的行为 在Verilog HDL语言中,每个系统函数和任务前面都用一个标识符$来确认这些系统函数和任务提供了非常强大的功能下面对一些常用的系统函数和任务逐一加以介绍 6.4.1 $display和$write任务 格式: $display(“格式控制符”,输出变量列表,输出变量列表);; $write (“格式控制符”,输出变量列表,输出变量列表) ;这两个任务的作用基本相同 $display自动地在输出后进行换行,自动地在输出后进行换行,$write则不进行自动换行。

则不进行自动换行如果想在一行里输出多个信息,可以使用$write在$display和$write中,其输出格式控制是用双引号括起来的字符串它包括两种信息6.4 6.4 常用的系统任务常用的系统任务§6.4 常用的系统任务常用的系统任务 (1)格式说明——由“%”和格式字符组成 将输出的数据转换成指定的格式输出输出格式输出格式说明说明%h 或或 %H以十六进制数的形式输出以十六进制数的形式输出%d 或或 %D以十进制数的形式输出以十进制数的形式输出%o 或或 %O以八进制数的形式输出以八进制数的形式输出%b 或或 %B以二进制数的形式输出以二进制数的形式输出%c 或或 %C以以ASCII码字符的形式输出码字符的形式输出%v 或或 %V输出网络型数据信号强度输出网络型数据信号强度%m 或或 %M输出等级层次的名字输出等级层次的名字%s 或或 %S以字符串的形式输出以字符串的形式输出%t 或或 %T以当前的时间格式输出以当前的时间格式输出%e 或或 %E以指数的形式输出实型数以指数的形式输出实型数%f 或或 %F以十进制数的形式输出实型数以十进制数的形式输出实型数%g 或或 %G以较短的结果按指数或十进制输出实型数以较短的结果按指数或十进制输出实型数§6.4 常用的系统任务常用的系统任务 (2)普通字符,即需要原样输出的字符。

其中一些特殊的字符可以通过表6.2给出的转换序列来输出表中的字符形式用于格式字符串参数中,用来显示特殊的字符换码序列换码序列功能功能\n换行换行\t横向跳格横向跳格\\反斜杠字符反斜杠字符\\”双引号字符双引号字符”\o1~3位八进制数代表的字符位八进制数代表的字符%%百分号百分号%§6.4 常用的系统任务常用的系统任务 module disp;; initial begin $display(“\\\t%%%%\n\”\123”);; end endmodule;;输出结果为: \% “S 从上面的这个例子中可以看到一些特殊字符的输出形式(八进制数123就是字符S)例6.17】§6.4 常用的系统任务常用的系统任务 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【例6.18】§6.4 常用的系统任务常用的系统任务 输出数据的显示宽度:在$display中,输出列表中数据的显示宽度是自动按照输出格式进行调整的。

这样,在显示输出数据时,在经过格式转换以后,总是用表达式的最大可能值所占的位数来显示表达式的当前值 十进制数格式输出-----输出结果前面的0值用空格来代替 其他进制------输出结果前面的0仍然显示出来 可以通过在%和表示进制的字符中间插入一个0,便自动调整显示输出数据宽度的方式见下例: $display(“d=%=%0h a=%=%0h”,,data,,addr);; 这样在显示输出数据时,在经过格式转换以后,总是用最少的位数来在经过格式转换以后,总是用最少的位数来显示表达式的当前值显示表达式的当前值下面举例说明§6.4 常用的系统任务常用的系统任务 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 输出出结果果为:: Printing with maximum size==- -10==00a:: Printing with minimum size ==10==a;;【例6.8】§6.4 常用的系统任务常用的系统任务 如果输出列表中表达式的值包含有不确定的值或高阻值,其结果输出遵循以下规则。

●如果表达式值的所有位均为不定值所有位均为不定值,则输出结果为小写的小写的x x;部分位为不定制,则输出大写的大写的X X; ●如果表达式值的所有位均为高阻值所有位均为高阻值,则输出结果为小写的小写的z z;部分位为高阻值,则输出大写的大写的Z Z 在输出格式为十六进制和八进制的情况下,每个x或z表示每4位或每3位的二进制数: $display(‘‘%d, %d”,4’bxxxx, 4’b10xx) 输出结果 x X§6.4 常用的系统任务常用的系统任务 对于二进制输出格式,表达式值的每一位的输出结果为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 §6.4 常用的系统任务常用的系统任务 module M;module M; ………. ………. initial $display ("Displaying in %m"); initial $display ("Displaying in %m"); endmoduleendmodule module top; module top; M m1( ); // M m1( ); //显示层次信息显示层次信息 M m2( );M m2( ); M m3( ); ……. M m3( ); ……. endmoduleendmodule §6.4 常用的系统任务常用的系统任务6.4.3 显示层次 %m 可以用于显示任务如:可以用于显示任务如:$ $display,$write,$monitor,$strobedisplay,$write,$monitor,$strobe任务中的任务中的%m%m显示任何级别的层次 显示结果显示结果 Displaying in top.m1Displaying in top.m1 Displaying in top.m2 Displaying in top.m2 Displaying in top.m3 Displaying in top.m3 6.4.4 选通显示 $strobe 与$display$display区别在于: 如果许多其他语句与$display任务在同一个时间单位执行,那么这些语句与$display任务的执行顺序是不确定的。

而$strobe总是在同时刻的其他赋值语句执行完成后才执行 always @(posedge clock) begin a=b; c=d; end always @(posedge clock) $strobe(“Displaying a=%b,c=%b”,a,c); //在a、c被赋值后才执行【例6.22】§6.4 常用的系统任务常用的系统任务 integer cool; initial begin cool=1; $display(“cool value is%d”,cool) $strobe(“cool value is%d”,cool); cool=2; $strobe(“cool value is%d”,cool); end 输出 cool value is 1 cool value is 2 cool value is 2 思考题1、怎样理解initial语句只执行一次的概念?2、在initial语句引导的过程块中是否可以有循环语句?如果可以,是否与思考题1相矛盾?3、怎样理解由always语句引导的过程块是不断活动的?4、不断活动与不断执行有什么不同?5、怎样理解沿触发和电平触发的不同?6、是不是可以说沿触发是有间隔的,在一定的时间区间里只需要注意有限的点,而电平触发却需要注意无穷多个点?7、沿触发的always块和电平触发的always块各表示什么类型的逻辑电路的行为?为什么?8、简单叙述任务与函数的不同点。

9、简单叙述$display、$write和$strobe的不同点10、简单叙述Verilog1364-2001版语法规定的电平敏感列表的简化写法11、如何在Verilog测试模块中,利用文件的读写产生预定格式的信号,并记录有测试价值的信号?第第6章章 结构语句、系统任务、函数语句和显示系统任务结构语句、系统任务、函数语句和显示系统任务 第七章第七章 调试用系统任务和常用编译预处调试用系统任务和常用编译预处理语句理语句7.1 7.1 系统任务系统任务$monitor$monitor7.2 7.2 时间度量系统函数时间度量系统函数$time$time7.3 7.3 系统任务系统任务$finish$finish7.4 7.4 系统任务系统任务$stop$stop7.5 7.5 系统任务系统任务$ $readmembreadmemb和和$ $readmemhreadmemh7.6 7.6 系统任务系统任务$random$random7.7 7.7 编译预处理编译预处理第第7章章 调试用系统任务和常用编译预处理语句调试用系统任务和常用编译预处理语句 $monitor(“格式控制符格式控制符”,输出变量列表,输出变量列表);; $monitor作用:监控和输出参数列表中的表达式或变量值。

监控和输出参数列表中的表达式或变量值每当参数列表中变量或表达式的值发生变化时,将自动输出显示 $monitor(“%d ,rxd=%b txd=%b”, $time ,rxd,txd );在$monitor中,参数可以是$time系统函数 $monitor($time,,,,“rxd=%=%b txd=%=%b”,,rxd,,txd);;注:,,表示空参数,显示为空格 7.1 7.1 系统任务系统任务$monitor$monitor§7.1 系统任务系统任务$monitor module testfixture; reg a, b, sel; wire out; MUX2_ 1 mux(out, a, b, sel); initial begin a = 0; b = 1; sel= 0; #5 b = 0; #5 b = 1; sel= 1; #5 a = 1; #5 $finish; end initial$monitor($time, ," out=% b a=%b b=%b sel=%b", out, a, b,sel);endmodule文本输出$monitor举例结果0 out= 0 a= 0 b= 1 sel= 05 out= 0 a= 0 b= 0 sel= 010 out= 1 a= 0 b= 1 sel= 115 out= 1 a= 1 b= 1 sel= 1如果同一时刻,两个或多个参数的值发生变化,则在该时刻只输出显示一次。

但在$monitor中,参数可以是$time系统函数这样,参数列表中变量或表达式的值同时发生变化的时刻可以通过标明同一时刻的多行输出来显示 $ $monitoronmonitoron和$ $monitoroffmonitoroff这两个任务的作用是通过打开和关闭监控标志来控制、监控任务$monitor的启动和停止其中: $monitoroff 任务用于关闭监控标志,停止监控任务$monltor; $monltoron则用于打开监控标志,启动监控任务$monitor $monitor$monitor与与$display$display的不同之处还在于的不同之处还在于$monitor$monitor往往在往往在initialinitial块中调用,只要不调用块中调用,只要不调用$ $monitoroffmonitoroff,,$monitor$monitor便不间断便不间断地对其所设定的信号进行监视地对其所设定的信号进行监视§7.1 系统任务系统任务$monitor 在Verilog HDL中有两种类型的时间系统函数:$time和$realtime。

用这两个时间系统函数可以得到当前的仿真时刻 1.系统函数$time $time可以返回一个以64位的整数来表示当前的仿真时刻值该时刻是以模块的仿真时间尺度为基准的下面举例说明§7.2 时间度量系统函数时间度量系统函数$time【例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 2.$ $realtimerealtime系统函数 $realtime和$time的作用是一样的,只是$realtime返回的时间数字是一个实型数,该数字也是以时间尺度为基准的下面举例说明:§7.2 时间度量系统函数时间度量系统函数$time `timescale 10ns//1ns module test;; reg set;; parameter p==1.6;; initial begin $monitor($realtime,,,,“set==”,,set);; #p set=0:: #p set==1;; end endmodule【例7.2】输出结果为: 0 set=x 1.6 set=0 3.2 set=1 格式: $finish;; $finish(n);; 系统任务$finish的作用是退出仿真器,返回主操作系统,也就是结束仿真过程。

任务$finish可以带参数,根据参数的值输出不同的特征信息如果不带参数,默认$finish的参数值为1下面给出了对于不同的参数值,系统输出的特征信息: 0——不输出任何信息; 1——输出当前仿真时刻和位置; 2——输出当前仿真时刻,位置和在仿真过程中所用memory及CPU时间的统计7.3 7.3 系统任务系统任务$finish$finish§7.3 系统任务系统任务$finish例 initial begin clock=0; reset=1; ……. …… #900 $finish end 格式: $stop;; $stop(n);; $stop任务的作用是把EDA工具(例如仿真器)置成暂停模式,在仿真环境下给出一个交互式的命令提示符,将控制权交给用户这个任务可以带有参数表达式根据参数值(0,1或2)的不同,输出不同的信息参数值越大,输出的信息越多7.4 7.4 系统任务系统任务$stop$stop§7.3 系统任务系统任务$finish 在Verilog HDL程序中有两个系统任务$ $readmembreadmemb和$ $readmemhreadmemh用来从文件中读取数据到存储器,其使用格式共有以下6种;1)$readmemb(1)$readmemb(““< <数据文件名数据文件名> >””,,< <存储器名存储器名>)>);;2)$readmemb(2)$readmemb(““< <数据文件名数据文件名> >””,,< <存储器名存储器名> >,,< <起始地址起始地址>)>);;3)$readmemb(3)$readmemb(““< <数据文件名数据文件名> >””,,< <存储器名存储器名> >,,< <起始地址起始地址> >,,< <结束地址结束地址>)>);;4)$readmemh(4)$readmemh(““< <数据文件名数据文件名> >””,,< <存储器名存储器名>)>);;5)$readmemh(5)$readmemh(““< <数据文件名数据文件名> >””,,< <存储器名存储器名> >,,< <起始地址起始地址>)>);;6)$readmemh(6)$readmemh(““< <数据文件名数据文件名> >””,,< <存储器名存储器名> >,,< <起始地址起始地址> >,,< <结束地址结束地址>)>)。

7.5 7.5 系统任务系统任务$ $readmembreadmemb和和$ $readmemhreadmemh§7.5 系统任务系统任务$readmemb和和$readmemh 地址一词指对存储器(memory)建模的数组的寻址指针当数据文件被读取时,每一个被读取的数字都被存放到地址连续的存储器单元中去存储器单元的存放地址范围由系统任务声明语句中的起始地址和结束地址来说明,每个数据的存放地址在数据文件中进行说明 §7.5 系统任务系统任务$readmemb和和$readmemh reg[7:0] mem[1:256]; initial $readmemh(“mem.dat”,mem); initial $readmemh("mem.dat”,mem,16); initial $readmemh(“mem.dat”,mem,128,1);l例如:文件路径 “c:\memdata.dat”,则有:l reg [7:0] mema [0:255];l ……l $readmemb(“c:\memdata.dat”,,mema,,0,,255);; 当地址出现在数据文件中,其格式为字符“@”后跟上十六进制数。

如: @hh…h 对于这个十六进制的地址数中,允许大写和小写的数字在字符“@”和数字之间不允许存在空白位置可以在数据文件里出现多个地址当系统任务遇到一个地址说明时,系统任务将该地址后的数据存放到存储器中相应的系统任务将该地址后的数据存放到存储器中相应的地址单元中去地址单元中去§7.5 系统任务系统任务$readmemb和和$readmemhreg[7:0] mem[0:7];reg[7:0] mem[0:7]; integer i; integer i; initial initial begin begin $ $readmemb(“init.dat”,memreadmemb(“init.dat”,mem); ); for(ifor(i=0;i<8;i=i+1)=0;i<8;i=i+1)$ $display(“mem[%ddisplay(“mem[%d]=%]=%b”,i,mem[ib”,i,mem[i]) ]) init.datinit.dat @002 @002 11111111 01010000 11111111 01010000 00000000 11110000 00000000 11110000 @006 @006 11101011 00001111 11101011 00001111 0000_00000110_0001 0011_0010// 地址地址3~255没有定义没有定义@100 // hex1111_1100//地址地址257~1022没有定义没有定义@3FF1110_0010module readmem;reg [0:7] mema [0:1023]initial$readmemb(“mem_file.txt”, mema);endmodule文本文件:文本文件:mem_file.txt000000000011000011001100102111111002561110001010230 7 (1)(1)如果系统任务声明语句中和数据文件里都没有进行地址说明。

如果系统任务声明语句中和数据文件里都没有进行地址说明 (2)(2)如果系统任务中说明了存放的起始地址,没有说明存放的结如果系统任务中说明了存放的起始地址,没有说明存放的结束地址 ((3)3)如果在系统任务声明语句中,起始地址和结束地址都进行了如果在系统任务声明语句中,起始地址和结束地址都进行了说明 (4)(4)如果地址信息在系统任务和数据文件里都进行了说明,那么如果地址信息在系统任务和数据文件里都进行了说明,那么数据文件里的地址必须在系统任务中地址参数声明的范围之内数据文件里的地址必须在系统任务中地址参数声明的范围之内否则将提示错误信息,并且装载数据到存储器中的操作被中断否则将提示错误信息,并且装载数据到存储器中的操作被中断 (5)(5)如果数据文件里的数据个数和系统任务中起始地址及结束地如果数据文件里的数据个数和系统任务中起始地址及结束地址暗示的数据个数不同的话,也要提示错误信息址暗示的数据个数不同的话,也要提示错误信息说明说明 该函数返回一个该函数返回一个3232位的随机数,它是一个带符号的整型数位的随机数,它是一个带符号的整型数 $random一般的用法是:$random%%b,其中,其中b>0。

它给出了一个范围在(-b+1):(b-1)中的随机数下面给出一个产生随机数的例子: reg [23::0]rand;; rand==$random%%60;; 上面的例子给出了一个范围在-59到59之间的随机数,下面的例子通过位拼接操作产生一个值在0~59之间的数 reg[23::0]rand;; rand=={$random}%%60;; §7.6 系统任务系统任务$random7.6 7.6 系统任务系统任务$random$random §7.6 系统任务系统任务$random `timescale 1ns//1ns module random_pulse(dout);; output dout;; reg dout;; integer delay1,,delay2,,k;; initial begin #10 dout==0;; for(k==0;;k<100;;k==k+1) begin delay1== {$random}%%10;; ////delay1在在0到到10 ns间变化化 delay2=={$random}%%20;; ////delay2在在0到到20 ns间变化化 #delay1 dout==1;; #delay2 dout==0;; end end endmodule【例7.3】 7.1.1 宏定义'define 用一个指定的标识符(即名字)来代表一个字符串,它的一般形式为: `define标识符标识符(宏名宏名) 字符串字符串(宏内容宏内容) ------提供了一种简单的文本替换的功能提供了一种简单的文本替换的功能如: `define signal string [例7.4] `define WORDSIZE 8 module reg[1::`WORDSIZE] data;; //相当于定相当于定义reg [1::8] data;;§7.7 编译预处理编译预处理注:“ ` ” 不是“ ‘ ”l使用编译指导使用编译指导`define,, 可以可以提高描述的可读性提高描述的可读性l定义全局设计参数,定义全局设计参数,如延时和矢量的位如延时和矢量的位数。

数 关于宏定义的几点说明:l1、宏名可以用大写字母表示,也可以用小写字母表示建议使用大写字母,以与变量名相区别l2、`define命令可以出现在模块定义里面,也可以出现在模块定义外面宏名的有效范围为定义命令之后到原文件结束通常,`define命令写在模块定义的外面,作为程序的一部分,在此程序内有效l3、在引用已定义的宏名时,必须在宏名的前面加上符号“ ` ”,表示该名字是一个经过宏定义的名字l4、宏定义是用宏名代替一个字符串,也就是作简单的置换,不作语法检查预处理时照样代入,不管含义是否正确只有在编译已被宏展开后的源程序时才报错 l5、宏定义不是Verilog HDL语句,不必在行末加分号如果加了分号会连分号一起进行置换如: [例2]:module test; reg a, b, c, d, e, out; `define expression a+b+c+d; assign out = `expression + e; ... endmodule 经过宏展开以后,该语句为: assign out = a+b+c+d;+e;error 6、在进行宏定义时,可引用已定义的宏名,可以层层置换。

module test; reg a, b, c; wire out; `define aa a + b `define cc c + `aa assign out = `cc; endmodule这样经过宏展开以后,语句为assign out = c + a + b;7、宏名和宏内容必须在同一行中进行声明如果在宏内容中包含有注释行,注释行不会作为被置换的内容module`define typ_nand nand #5 //delay `typ_nand g121(q21,n10,n11); ……… endmodule经过宏展开以后,该语句为:nand #5 g121(q21,n10,n11); `define和parameter区别`define在编译前预处理,parameter在编译过程中完成替换1、作用域不同 parameter作用于声明的模块, `define从编译器读到这条指令开始到到编译结束都有效,或遇到`undef命令失效可以应用于整个工程2、传递功能不同 parameter可以用作模块例化的参数传递, `define没此功能。

7.2.2 “文件包含”处理'include 所谓“文件包含”处理是一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包含到本文件之中Verilog HDL语言提供了‘include命令来实现“文件包含”的操作其一般形式为: `include “文件名文件名”例如: `include “adder.v” module testbench; ….§7.7 编译预处理编译预处理 例:l(1)文件a.vlmodule a (a,b,out);l input a, b;l output out;l wire out;l assign out = a^b;lendmodule(2)(2)文件文件b.vb.v`include "`include "a.va.v" " module module bbb(c,d,e,outbbb(c,d,e,out); ); input input c,d,ec,d,e; ; output out; output out; wire wire out_aout_a; ; wire out; wire out; a a a(.a(c),.b(d),.out(out_aa(.a(c),.b(d),.out(out_a));)); assign out= assign out=e&out_ae&out_a; ; endmoduleendmodule 关于“文件包含”处理的几点说明:l一个`include命令只能指定一个被包含的文件,如果要包含n个文件,要用n个`include命令。

注意下面的写法是非法的`include "aaa.v“ "bbb.v“l`include命令可以出现在Verilog HDL源程序的任何地方,被包含文件名可以是相对路径名,也可以是绝对路径名例如: 'include "parts/count.v“ `include "../../library/mux. v”l可以将多个`include命令写在一行,在`include命令行,只可以出现空格和注释行例如下面的写法是合法的 ‘include “fileB“ ’include ”fileC“ //…… 如果文件1包含文件2,而文件2要用到文件3的内容,则可以在文件1用两个`include命令分别包含文件2和文件3,而且文件3应出现在文件2之前例如在下面的例子中,即在file1.v中定义:`include"file3.v"`include"file2.v“module test(a,b,out); input[1:`size2] a, b; output[1:`size2] out; wire[1:`size2] out; assign out= a+b;endmodulefile2.v的内容为:`define size2 `size1+1.file3.v的内容为:`define size1 4.l这样,file1.v和file2.v都可以用到file3.v的内容。

在file2.v中不必再用 `include "file3.v"了 文件包含是可以嵌套的例如上面的问题也可以这样处理 7.7.3 时间尺度时间尺度timescaletimescale `timescale命令用来说明跟在该命令后的模块的时间单位和时间精度 `timescale<`timescale<时间单位时间单位> >//< <时间精度时间精度> > 时间单位时间单位:用来定义模块中仿真时间和延迟时间的基准单位的;:用来定义模块中仿真时间和延迟时间的基准单位的; 时间精度时间精度:声明该模块的仿真时间的精确程度的,该参量被用来对延迟时:声明该模块的仿真时间的精确程度的,该参量被用来对延迟时间值进行取整操作间值进行取整操作( (仿真前仿真前) ),因此该参量又可以被称为取整精度因此该参量又可以被称为取整精度§ --------延时值超出精度要先舍入后使用延时值超出精度要先舍入后使用§ `timescale必须在模块之前出现必须在模块之前出现 如果在同一个程序设计里,存在多个’timescale命令,则用最小的时间精度值来决定仿真的时间单位。

另外时间精度至少要和时间单位一样精确,时间精度值不能大于时间单位值 §7.7 编译预处理编译预处理 例l `timescale 1 ns / 10 pslmodule MUX2_1 (out, a, b, sel);l output out;l input a, b, sel;lnot #1 not1( sel_, sel);land #2 and1( a1, a, sel);land #2 and2( b1, b, sel);lor #1 or1( out, a1, b1);lendmodule 时间单位定义s秒(1s)ms千分之一秒(10-3s)μs百万分之一秒(10-6s)ns十亿分之一秒(10-9s)ps万亿分之一秒(10-12s)fs千万亿分之一秒(10-15s)§7.7 编译预处理编译预处理在`timescale命令中,用于说明时间单位和时间精度参量值的数字必须是整数,其有效数字为有效数字为1,,10,,100,单位为s,,ms,,us,,ns,,ps,,fs这几种单位的意义说明如表所列 下面举例说明`timescale命令的用法 [例7.10] `timescale 1ns//1ps;; 在这个命令之后,模块中所有的时间值都表示是1 ns的整数倍。

这是因为在‘timescale命令中,定义了时间单位为1 ns模块中的延迟时间可表达为带3位小数的实型数,因为’timescale命令定义时间精度为1 ps§7.7 编译预处理编译预处理[例7.10] `timescale 10us/100ns:延迟时间的最小分辨率为十分之一us(100 ns),即延迟时间可表达为带一位小数的实型数 [例7.11] 仿真代码仿真结果§7.7 编译预处理编译预处理 [例7.12] `timeseal 10ns/1ns module test; reg set; parameter d=1.55; initial begin #d set=0; #d set=1; end endmodule 按照以下的步骤来计算 (1)根据时间精度,参数d值被从1.55取整为1.6 (2)因为时间单位是10 ns,时间精度是1 ns,所以延迟时间#d为时间单位的整数倍,即为16 ns (3)EDA工具预定在仿真时刻为16 ns的时候给寄存器set赋值为0(即语句#d set=0;执行时刻),在仿真时刻为32 ns的时候给寄存器set赋值为1(即语句#d set=1;执行时刻)。

l精度的时间单位应尽量与设计的实际精度精度的时间单位应尽量与设计的实际精度相同l精度是仿真器的仿真时间步精度是仿真器的仿真时间步l若时间单位与时间精度差别很大将严重影响仿若时间单位与时间精度差别很大将严重影响仿真速度l如如`timescale 1s / 1ps,则仿真器在,则仿真器在1秒内要扫秒内要扫描其事件序列描其事件序列1012次;而次;而`timescale 1s/1ms则只需扫描则只需扫描103次 7.7.4 条件编译命令`ifdef、、`else、、`endif 一般情况下,Verilog HDL源程序中所有的行都将参加编译但是有时希望对其中的一部分内容只有在满足条件时才进行编泽,也就是对一部分内容指定编译的条件,这就是“条件编译”有时,希望当满足条件时对一组语句进行编译,而当条件不满足是则编译另一部分 条件编译命令有以下几种形式 `ifdef 宏名宏名(标识符符):: 程序段程序段1 `else 程序段程序段2 `endif 它的作用是当宏名已经被定义过,则对程序段1进行编译,程序段2将被忽略;否则编译程序段2,程序段1被忽略。

`ifdef 宏名宏名(标识符符):: 程序段程序段1 `endif 这里的“宏名”是一个Verilog HDL的标识符,“程序段”可以是Verilog语句组,也可以是命令行这些命令可以出现在源程序的任何地方§7.7 编译预处理编译预处理 module module compile(y,a,bcompile(y,a,b); ); output y; output y; input input a,ba,b; ; ` `ifdefifdef add // add //宏名宏名 assign y=assign y=a+ba+b; ; `else`else assign y=a-b; assign y=a-b; ` `endifendif endmoduleendmodule 7.8 小结(1)在多模块调试的情况下,$monitor需配合$monitoron与$monitoroff使用。

2)$monitor与$display的不同之处在于$monitor是连续监视数据的变化,因而往往只要在测试模块的initial块中调用一次就可以监视被测试模块的所有感兴趣的信号,不需要也不能在always过程块中调用$monitor (3)$time常用在$monitor中,用来做时间标记4)$stop和$finish常用在测试模块的initial模块中,配合时间延迟用来控制仿真的持续时间5)$random在编写测试程序是非常有用的,可以用来产生边沿不稳定的波形,和随机出现的脉冲正确地使用它能有效地发现实际设计中存在的问题 (6)$readmem在编写测试程序也是非常有用的,可以用来生成给定的复杂数据流复杂数据可以用C语言产生,存在文件中用$readmem取出存入存储器,再按节拍输出,这在验证算法逻辑电路时特别有用 (7)在用`timescale时需要注意的是,当多个带不同timescale定义的模块包含在一起时只有最后一个才起作用所以属于一个项目,但`timescale定义不同的多个模块最好分开编译,不要包含在一起编译,以免把时间单位搞混 (8)宏定义字符串引用时,不要忘记,要用“ ` ”引导。

这与C语言不同,C语言直接引用就行,但Verilog必须用“ ` ”引导 (9)include等编译预处理也必须用“ ` ”引导,而不是与C语言一样用“#”引导或不需要引导符 思考题1、为什么在多模块调试的情况下$monitor需要配合$monitoron和$monitoroff来工作?2、请用$random配合求模运算编写: (1)用于测试的跳变沿抖动为周期1/10的时钟波形 (2)随机出现的脉宽随机的窄脉冲3、Verilog的编译预处理与C语言的编译预处理有什么不同?4、请仔细阐述`timescale编译预处理的作用?5、不同`timescale定义的多模块仿真测试时需要注意什么?6、为什么说系统任务$readmem可以用来产生用于算法验证的及其复杂的测试用数据流?7、为什么说熟练的使用条件编译命令可以使源代码有更大的灵活性,可以适用于不同的实现对象,如不同工艺的ASIC或速度规模不同的FPGA或CPLD,从而为软核的商品化创造条件?第第7章章 调试用系统任务和常用编译预处理语句调试用系统任务和常用编译预处理语句 结束!结束! 。

下载提示
相似文档
正为您匹配相似的精品文档
相关文档