You are on page 1of 218

VERILOG

Hardware Descript Language

Shanghai University Microelectronic R&D Center


2

Table of Contents
1. EDA与硬件描述语言
2. Verilog HDL设计入门
3. Verilog HDL基础知识
4. Verilog行为描述
5. Verilog系统函数与编译向导
6. 实例分析
第一章

EDA与硬件描述语言

Shanghai University Microelectronic R&D Center


4

EDA设计主要流程
„ 第一步:行为级描述
在完成系统性能分析与功能划分的基础上,对于各个电路
功能模块,用HDL语言(Verilog HDL/VHDL)完成行为级
(Behavior Level)描述。
„ 第二步:行为级优化与RTL级描述的转化
z行为级算法优化与功能仿真
‹优化的目标是选择最优的算法实现方法
‹仿真的目的是为了验证给定的行为描述是否能够实现所需的功能
z完成向RTL级描述的转化
‹现有的EDA工具只能接受RTL级(RTL:Register Transport
Level寄存器传输级)描述的HDL文件进行自动逻辑综合
5

EDA设计主要流程(续)

! 以上步骤与具体的实现工艺无关
6

EDA设计主要流程(续)
„ 第三步:选定工艺库,确定约束条件,完成逻辑综
合与逻辑优化
z 逻辑综合与逻辑优化(Logic Synthesis & Logic
Optimization)的目标是将RTL级HDL代码映射到具体的
工艺上加以实现
z 设计过程与实现工艺相关联
„ 第四步:门级仿真
z EDA设计过程的每一个阶段都需要进行模拟仿真
z 门级仿真包含了门单元的延时信息,需要相应工艺的仿真
库的支持
7

EDA设计主要流程(续)
„ 第五步:测试生成
z 功能测试(Function Test)--为了检测线路的逻辑、
时序等是否正确
z 制造测试(Manufacture Test)--实现高的故障覆盖
率,通常称之为测试向量,可自动生成(ATPG:
Automatic Test Pattern Generation)

! 以上设计步骤通常称之为前端设计
8

EDA设计主要流程(续)
„ 第六步:布局布线(P&R:Place & Routing)
z 借助于版图综合的自动布局布线工具,在对应工艺的版图
库支持下完成的,通常称之为后端设计
„ 第七步:参数提取
„ 第八步:后仿真
z 主要进行时序模拟,考察在增加连线延时后,时序是否仍
然满足设计要求
„ 第九步:制版、流片
9

Introduction to HDL
„ HDL
z Hardware Description Language
z 为了描述硬件电路而专门设计的一种语言
„ Why use a HDL?
z It is becoming very difficult to design directly on
hardware
z It is easier and cheaper to explore different design
option
z Reduce time and cost
10

Different Levels of Abstraction


„ 系统级(System Level)
z 针对整个电子系统的性能的描述,是系统的最高层次的
抽象描述
z 目前仍以C语言为主导
„ 行为级(Behavioral Level)
z 对每一个功能模块完成行为描述,也有称为算法级
(Arithmetic Level)或功能级(Functional Level)
„ RTL级(Register Transport Level)
z 算法或功能以数字电路来实现
z 数字电路可看作是寄存器与组合逻辑电路的合成
11

Different Levels of Abstraction


„ 逻辑门级(Gate Level)
z A model that describes the logic gates and the
interconnections between them
„ 开关级(Switch Level)
z A model that describes the transistors and the
interconnections between them
12

Verilog概述
„ 什么是Verilog HDL?

Verilog HDL(Hardware Description Language)是一


种硬件描述语言,用于从算法级、门级到开关级的多种抽
象设计层次的数字系统建模。
13

Verilog的历史
„ 最初是于1983年由Gateway Design Automation
公司(后被Cadence收购)为其模拟器产品开发的硬
件建模语言
„ 1990年,Cadence公司成立OVI (Open Verilog
International) 组织来负责推广Verilog
„ 1995年,IEEE制定了Verilog HDL标准,即IEEE
Std 1364 - 1995
14

Verilog与VHDL
„ 目前,设计者使用Verilog和VHDL的情况
z 美国:Verilog: 60%, VHDL: 40%
z 台湾:Verilog: 50%, VHDL: 50%
„ 两者的区别:
z VHDL侧重于系统级描述,从而更多的为系统级设计人员
所采用
z Verilog侧重于电路级描述,从而更多的为电路级设计人
员所采用
15

Verilog HDL与 C语言


„ 虽然Verilog的某些语法与C语言接近,但存在本质
上的区别
z Verilog是一种硬件语言,最终是为了产生实际的硬件电
路或对硬件电路进行仿真
z C语言是一种软件语言,是控制硬件来实现某些功能
z 利用Verilog编程时,要时刻记得Verilog是硬件语言,要
时刻将Verilog与硬件电路对应起来
„ SystemC and SystemVerilog:面向SOC
16

Verilog HDL Behavior Language


„ Structural and procedural like the C
programming language.
„ Used to describe algorithmic level and RTL
level Verilog models.
„ Key features
z procedural constructs for conditional, if-else, case,
and looping operations.
z arithmetic, logical, bit-wise, and reduction
operations for expressions.
z timing control.
17

Verilog HDL Structural Language


„ Used to describe gate-level and switch-level
circuits.
„ Key features
z a complete set of combinational primitives.
z support primitive gate delay specification.
z support primitive gate output strength specification.
18

Verilog Simulator
„ Verilog-XL
„ VCS
„ NC-Verilog
„ Active HDL
„ ModelSim
……
19

举例
用HDL语言描述一个上升沿D触发器,其中clk为触发
器的时钟,data,q分别为触发器的输入、输出。
module dff_pos(data, clk, q); //define a module dff_pos
//for D flip-flop
input data, clk;
output q;
reg q;
always @(posedge clk)
q = data;
endmodule
第二章

Verilog HDL设计入门

Shanghai University Microelectronic R&D Center


21

本章提要
„ 本章简要地介绍有关Verilog HDL设计的一些入门
基础知识

„ 对Verilog HDL的设计方法、编程实现过程有个基
本的认识
1、设计方法

„ Bottom-up的设计方法

„ Top-down的设计方法

Shanghai University Microelectronic R&D Center


23

Bottom-up的设计流程
24

Bottom-up的设计方法
„ 流程
1. 选择具体的元器件
2. 通过逻辑电路设计,完成系统中各独立功能模块的设计
3. 把各功能模块连接起来,组成整个硬件系统
„ 优点
z 符合硬件设计传统的设计习惯
„ 缺点
z 缺乏对整个电子系统总体性能的把握
z 设计周期长
25

Top-down的设计流程
26

Top-down的设计方法
„ 优点
z 缩短了设计周期
„ 缺点
z 需要依赖EDA设计工具的支持
z 需要有精确的工艺库的支持
2、Verilog HDL的基本结构
与硬件描述的设计过程

Shanghai University Microelectronic R&D Center


28

模块(module)
„ 模块是Verilog的基本描述单位
„ 模块的定义从关键词module开始,到关键词
endmodule结束
„ 每条Verilog HDL语句以分号“;”作为结束
29

举例
用Verilog HDL语言描述一个上升沿D触发器,其中
clk为触发器的时钟,data,q分别为触发器的输入、
输出。
module dff_pos(data, clk, q);
input data, clk;
output q;
data q
reg q;
always @(posedge clk)
q = data;
clk
endmodule
30

模块的基本结构
1. 模块定义行
z 以module开头
z 接着给出所定义模块的模块名
z 括号内给出端口名列表(端口名等价于硬件中的外接引
脚,模块通过这些端口与外界发生联系)
z 以分号结束
2. 端口类型说明
z 端口类型只有input、output、inout三种
31

模块的基本结构(续)
3. 数据类型说明
z 支持的数据类型有连线类和寄存器类两个大类
z 一位宽的wire类可被缺省外,其它凡将在后面的描述中
出现的变量都应给出相应的数据类型说明
4. 描述体部
z 具体展开对模块的描述
5. 结束行
z 用关键词endmodule标志模块定义的结束
z 它的后面没有分号
32

行为描述与结构描述
„ 行为描述(Behavior)描述行为或功能特性

„ 结构描述(Structure)描述通过什么样的结构方
式将不同的实体连接起来用以实现所要求的行为或
功能
33

举例
写出二选一MUX功能模块的Verilog HDL的行为描述
和结构描述
„行为描述模块
module mux_beh( out, a, b, sel );
output out;
input a, b, sel;
assign out = ( sel == 0 ) ? a : b;
endmodule
34

举例(续)
„ 结构描述模块
module mux_str( out, a, b, sel );
output out;
input a, b, sel;
not gate1( net1, sel );
and gate2( net2, a, net1 );
and gate3( net3, b, sel );
or gate4( out, net2, net3 );
endmodule
35

测试与仿真
„ 测试平台(Test Bench)
z 在输入端口加入测试信号,从输出端口检测其输出结果
是否正确
„ 通常将需要测试的对象称之为DUT(Device
Under Test)
„ 测试模块
z 要调用DUT
z 包含用于测试的激励信号源
z 能够实施对输出信号的检测,并报告检测的结果
36

二选一MUX的测试模块
module test_for_mux;
reg a, b, s;
// 调用DUT
mux_str mux1( out, a, b, s );
// 产生测试激励信号 0 a=0 b=1 s=0 out=0
initial 10 a=1 b=1 s=0 out=1
begin 20 a=1 b=0 s=0 out=1
a = 0; b = 1; s = 0; 30 a=1 b=0 s=1 out=0
#10 a = 1; 40 a=1 b=1 s=1 out=1
#10 b = 0; 50 a=0 b=1 s=1 out=1
#10 s = 1;
#10 b = 1;
#10 a = 0;
#10 $finish;
end
// 检测输出信号
initial
$monitor( $time, “ a=%b b=%b s=%b out=%b”, a, b, s, out );
endmodule
37

过程语句
„ initial
z 只顺序地执行一次
z 没有触发条件
„ always
z 当顺序执行到最后一条语句后,会自动返回到第一条语
句重新开始执行,是一条没有穷尽的循环语句
z 往往带有触发条件
38

A Full Adder Example

a b ci sum cout
0 0 0 0 0
0 0 1 1 0
0 1 0 1 0
0 1 1 0 1
1 0 0 1 0
1 0 1 0 1
1 1 0 0 1
1 1 1 1 1
39

Overview of Verilog Module


„ A Verilog module includes the following parts:
module module_name(port_name);

port declaration

data type declaration

task & function declaration

module functionality or structure

timing specification
endmodule
40

全加器的门级描述
41

全加器的行为级描述
module fadder( sum, cout, a,
b, ci );
// port declaration
output sum, cout; Whenever a or b or ci changes
input a, b, ci; its logic state, evaluate sum
reg sum, cout; and cout by using the equation
// behavior description sum = a ⊕ b ⊕ ci
always @( a or b or ci ) cout = ab + b ⋅ ci + ci ⋅ a
begin
sum = a ^ b ^ ci;
cout = ( a & b ) | ( b &
ci ) | ( ci & a );
end
endmodule
42

测试模块
module testfixture;

// Data type declaration

// Instantiate modules

// Applying stimulus

// Display results

endmodule
第三章

Verilog HDL基础知识

Shanghai University Microelectronic R&D Center


44

本章提要
„ 本章集中介绍Verilog HDL的基础部分,包括基本
词法定义,数据类型,运算符等
1、基本词法定义

Shanghai University Microelectronic R&D Center


46

空白符
„ 空白符是以下几种字符与控制符的总称
z 空格
z TAB键
z 换行符
z 换页符
„ 空白符起分隔符的作用
z 允许在一行内写多条Verilog HDL语句
47

注释行
„ 单行注释
z 以“//”开始到行末结束,不允许续行
„ 多行注释
z 以“/*”开始,到“*/”结束,可以跨越多行,但不允许嵌套
„ 注释行中的内容只是为了便于阅读理解
„ 在必要的地方增加适当的注释说明,在HDL编程中
尤为重要
„ 有些操作控制命令以注释行的方式出现在HDL描述
中,它不影响HDL的仿真,但其它工具可以识别这
些控制命令
48

Verilog HDL的四种逻辑状态
„ Verilog HDL需要用数字或字符去表达在数字电路
中存储与传送的逻辑状态

0 逻辑零、逻辑非、低电平

1 逻辑1、逻辑真、高电平

x或X 不确定的逻辑状态

z或Z 高阻态
49

整数及其表示
„ 整数可以表示成十进制、十六进制、八进制、二进
制等
„ 表示方法有两种
z 直接由0~9的数字串组成的十进制数
z +/- <位宽>’<基数符号><按基数表示的数值>
‹位宽是指所要表示的整数用二进制展开时所需的二进制位的个数
(bit数),其值用十进制数表示。
‹位宽在表示中可以被缺省
50

基数符号

数制 基数符号 合法的表示值

二进制 b or B 0, 1, x, X, z, Z, ?, _

八进制 o or O 0~7, x, X, z, Z, ?, _

十进制 d or D 0~9, _

十六进制 h or H 0~9, a~f, A~F, x, X, z, Z, ?, _


51

基数符号说明
1. 问号“?”是高阻态z的另一种表示
2. 下划线“_”的引入只是为了增加可读性
3. 在数值表示中,左边为最高有效位(MSB),右边为最低
有效位(LSB)
4. 在二进制表示中,x,z只代表相应位的逻辑状态;在八进
制表示中,一位的x,z代表的是三个二进制位都处于x或z
态;在十六进制中则对应代表四个二进制位都处于x或z态
5. 对于带符号的整数,正、负号的表示应在最左边
52

整数表示实例
数值表示 位宽 数制 等效二进制值及其解释
10 缺省 十进制 0…0_1010(32位或以上)
4ac 缺省 十进制 非法
’h4ac 缺省 十六进制 0…0_0100_1010_1100(32位或以上)
9’o671 9位 八进制 110_111_001
9’o-671 9位 八进制 非法
6’hf3 6位 十六进制 11_0011,高位部分被舍去
6’hf 6位 十六进制 00_1111,高位部分由0补足
3’b10x 3位 二进制 10x
12’h2x6 12 位 十六进制 0010_xxxx_0110
6’hx 6位 十六进制 xx_xxxx,高位部分由x补足
53

实数及其表示
„ 实数可以用十进制数表示,也可用指数表示
„ 在Verilog HDL中,实数可以参与的运算是受限制
的。
„ 当实数被转换为整数时,是按四舍五入的方式进行

54

字符串
„ 定义
z 为两个双引号 “ ” 之间的字符
z 字符串不允许跨行
„ 可通过前导的控制键(反斜杠及百分号)引入一些特殊字符

特殊字符表示 意义
\n 换行
\t Tab键
\\ 反斜杠\
\” 引号”
\ddd 由三位八进制数表示的ASCII值
%% %
55

取名规则
1. 必须是由字母(a~z,A~Z)或下划线开头,长
度小于1024字符的一串字符序列
2. 后续部分可以是字母(a~z,A~Z)、数字
(0~9)、下划线、$
3. 还可以是以反斜杠“\”开头,并以空白符结尾的任
何字符序列。但反斜杠本身及空白符都不属标识
符组成部分
56

系统命令
„ 以$开头的标识符用以代表系统命令(系统任务与
系统函数)
„ $display
„ $monitor
„ $finish
57

关键词
„ Verilog HDL语言内部已经使用的词称为关键词或
保留词,应避免使用
„ 所有的关键词都是小写
„ always, and, assign, attribute, begin, buf, case,
default, else……
2、数据类型

Shanghai University Microelectronic R&D Center


59

数据类型
„ 连线类型和寄存器类型
z 驱动方式(或赋值方式)不同
z 保持方式不同
z 对应硬件实现不同
60

连线类型
„ 对应硬件电路中的物理信号连接
„ 驱动有两种方式
z 在结构描述中把它连接到一个门或模块的输出端
z 用连续赋值语句assign对其进行赋值
„ 没有电荷保持作用,当没有被驱动时,将处于高阻
态Z
61

寄存器类型
„ 对应的是具有状态保持作用的硬件电路元件,如触
发器、锁存器等
„ 驱动可以通过过程赋值语句实现
„ 过程赋值在接受下一次的过程赋值之前,将保持原
值不变
„ 当寄存器类型没有被赋值前,将处于不定态X
62

连线类型及其功能
连线类型 连线功能
wire, tri 标准连线(缺省)
wor, trior 多重驱动时,具有线或特性的连线
wand, triand 多重驱动时,具有线与特性的连线
trireg 具有电荷保持特性的连线
tri1 上拉电阻(pullup)
tri0 下拉电阻(pulldown)
supply1 电源线,逻辑1
supply0 电源线,逻辑0
63

补充说明
„ 连线主要出现在模块的结构描述中,对应硬件电路
中的物理信号连接。
„ 在对连线进行描述时,必须用连线类型定义语句进
行类型说明,当说明被缺省时,表示的是位宽为
1bit的wire型连线。wire是标准的,不附带其它逻
辑功能的连线。
„ tri与wire的功能是完全一致的。
„ wire与wor以及wand三者之间的差别体现在有多重
驱动时连线所具有的不同逻辑特性
64

寄存器类型及其说明

寄存器类型 功能说明

reg 用于行为描述中对寄存器类的说明,由过程赋值语句赋值

integer 32位带符号整型变量

real 64位浮点、双精度、带符号实型变量

time 64位无符号时间变量
65

解释
„ 所有寄存器类的量,都有“寄存”性,即在接受下一
次赋值前,将保持原值不变。
„ 所有寄存器类都必须给出类型说明(无缺省状态)。
„ 寄存器类的量,必须通过过程赋值语句进行赋值。
„ integer、real、time都是纯数学的抽象描述,不对
应于任何具体的硬件电路实现。
66

标量与矢量
„ 线宽只有一条的连线,以及位数只有一位的寄存器
称之为标量
„ 线宽大于一条的连线,或位数大于一位的寄存器称
之为矢量。
„ 矢量的说明
z 矢量的范围由括在方括号中的一对数字表示,中间用一
个冒号相隔。形式为:[ msb : lsb ]
3、参数定义、宏替换及模拟时间
单位的定标

Shanghai University Microelectronic R&D Center


68

参数定义语句parameter
„ 用于对延时、线宽、寄存器位数等物理量的定义
„ 用一个文字参数来代替一个数字量
„ 优点
z 增加描述的可读性
z 为以后的修改带来方便
69

例子
module module_name(……);
// 此处可插入必要的端口说明
parameter msb=7, lsb=0, delay=1;
reg [msb:lsb] reg_a;
and #delay (x, y, z);
......
endmodule
70

参数定义语句的形式描述
parameter <参数定义表项>;
z 参数定义表项给出具体的各个参数与数字量之间所谓对
应关系,相互间用逗号“,”相隔。
71

宏替换`define
„ 宏替换的形式描述:
`define <宏名> <进行宏替换的文本内容>
„ 宏替换是在编译时告知编译器,用宏替换定义中的
文本内容来直接替代模块描述文件中出现的宏名。
„ 一条宏替换定义语句只能定义一个宏替换,且定义
结束时无分号。
„ 宏替换定义本身以及用到宏替换的地方必须有撇号
“`”作开头。
72

例子
`define msb 8 //用宏名msb来替代常数8
`define lsb 0 //用宏名lsb来替代常数0
`define delay_and and #1 /*用宏名delay_and来替代单元
名and及其延时参数*/
reg [`msb : `lsb] a;
`define_and (x, y, z);
73

模拟时间定标
„ 对模拟器的时间单位及时间计算的精度进行定标
„ 定义
z `timescale <计时单位>/<计时精度>
z 计时单位与计时精度都由整数及相应的时间单位二部分
组成
z 时间单位:
‹s ms(毫秒10-3s) us(微秒10-6s)
‹ns(纳秒10-9s) ps (微微秒10-12s)
‹fs (毫微微秒10-15s)
74

说明
„ 计时单位必须大于等于精度单位
„ 对timescale的定义必须在模块描述的外部进行
„ 模拟器允许对不同模块定义不同的时标,但以最小
的精度进行模拟计算
4、运算符

Shanghai University Microelectronic R&D Center


76

运算符的分类
运算符分类 所含运算符
算术运算符 +, -, *, /, %

位运算符 ~, &, |, ^, ^~ or ~^

缩位运算符 &, ~&, |, ~|, ^, ^~ or ~^

逻辑运算符 !, &&, ||

关系运算符 <, >, <=, >=

相等与全等运算符 ==, !=, ===, !==

逻辑移位运算符 <<, >>

连接运算符 { }

条件运算符 ? :
77

运算符的分类
„ 单目运算符
z 只有一个操作数,且运算符位于操作数的左边
„ 双目运算符
z 有两个操作数,各位于运算符的两边
„ 三目运算符
z 属于这一类的只有条件运算符(? : )一个
78

运算符的优先级顺序
运算符优先级顺序
! ~ + - (unary) 最高优先级
* / %
+ - (binary)
<< >>
< <= > >=
== != === !==
& ~&
^ ~^
| ~|
&&
|| 最低优先级
? :
79

算术运算符
1. 加法运算符: +,实现加法运算
2. 减法运算符: -,实现减法运算
3. 乘法运算符: * ,实现乘法运算
4. 除法运算符: / ,实现除法运算
5. 取模运算符: %,实现取模运算

„ 在算术运算操作中,操作数是作为一个整体参与运算的,
因而,如果某个操作数的某一位为不定态(x值),则整
个表达式的运算结果也为不定态
80

位运算符
„ 按位取反运算符: ~
„ 按位与运算符: &
„ 按位或运算符: |
„ 按位异或运算符: ^
„ 按位同或运算符: ^~或~^
81

缩位运算符
„ 缩位运算符是单目运算符,按位进行逻辑运算
„ 缩位运算符包括
z 与(&)
z 或(|)
z 异或(^)
z 及其相应的非操作(~&, ~|, ~^或^~)
82

逻辑运算符
„ 逻辑与运算符: &&(双目运算符)
„ 逻辑或运算符: ||(双目运算符)
„ 逻辑非运算符: ! (单目运算符)
83

关系运算符
1. 小于: <
2. 大于: >
3. 小于等于: <=
4. 大于等于: >=
84

相等与全等运算符
„ 共有四种:
1. 相等运算符: ==
2. 不等运算符: !=
3. 全等运算符: ===
4. 不全等运算符: !==
„ 都是双目运算符,得到的结果是1位的逻辑值
85

相等算符
„ 逐位比较二个操作数相应位的值是否相等,只有当每一位都
相等时,相等关系才满足。
„ 如果任何一个操作数中的某一位存在不定态或高阻态,则将
得到一个不定态的结果。

== 0 1 X Z

0 1 0 X X

1 0 1 X X

X X X X X

Z X X X X
86

全等算符
„ 将不定态或高阻态看作是逻辑状态的一种而参与比较。

=== 0 1 X Z

0 1 0 0 0

1 0 1 0 0

X 0 0 1 0

Z 0 0 0 1
87

逻辑移位运算符
1. 逻辑左移:<<
2. 逻辑右移:>>
88

连接运算符
„ 将两组或两组以上的信号用大括号括起来,拼接成
一组新的信号。
„ 对于一些重复信号的连接,可以用它的简化表示方
法{ n { a } },表示将信号a重复连接n次。
89

条件运算符
„ <条件运算符> ? <条件为真时的表达式> : <条件为假时的表达式>
90

允许实型量参与的运算符

算符类型 运算符

算术算符 + - * /

关系算符 > >= < <=

逻辑算符 ! && ||

相等算符 == !=

条件算符 ? :
91

不允许实型量参与的运算符

算符类型 运算符
连接算符 { }

取模算符 %

位运算符 ~ & |

全等算符 === !==

缩位算符 ^ ~^ & ~& | ~|

移位算符 << >>


第四章

Verilog行为描述

Shanghai University Microelectronic R&D Center


93

本章提要
„ 提出了对模块进行行为描述的构成框架

„ 系统性地介绍各类行为描述语句的形式定义与实用
方法
1、Verilog行为描述的构成框架

Shanghai University Microelectronic R&D Center


95

模块的基本结构

模块定义行

模 端口类型说明
块 过程语句(initial / always)
数据类型说明 过程块1

述 描述体 过程块2 过程赋值语句
块语句
结束行 ...... 高级程序语句
96

过程块
„ Verilog HDL对模块的行为描述以过程块为基本组
成单位,一个模块的行为描述由一个或多个并行运
行的过程块组成。
97

过程块的形式定义
过程语句 @ (事件控制敏感表)
块语句开始标识符: 块名
块内局部变量说明
一条或多条过程赋值或高级程序语句
块语句结束标识符
„ 斜体表示的是可缺省的部分
„ 过程语句是指initial或always
„ 事件控制敏感表只在always过程语句中出现,用于激活过程语句的执行
„ 块语句标识符分begin-end(串行块)与fork-join(并行块)两类
„ 块名和块内局部变量说明均为可选项。
98

过程语句initial与always
1. 都是从模拟的0时刻开始执行,但initial过程语句后面的块
语句沿时间轴只执行一次,而always则循环地重复执行其
后的块语句。
2. initial过程语句不带触发条件,因而必定从模拟的0时刻开
始执行它后面的块语句;always过程语句则通常带有触发
(激活)条件,只有当触发条件被满足时,其后的块语句
才真正开始执行。如果触发条件被缺省,则认为触发条件
始终被满足。
3. 一个模块的行为描述中可以有多个initial与always语句,
代表多个过程块的存在,它们之间相互独立,并行运行。
99

initial过程语句
„ 在实际的描述过程中,最经常地应用于测试模块中
对激励向量的描述。
„ 在对硬件功能模块的行为描述中,仅在必要时给寄
存器变量赋以初值。
„ 是一条主要面向模拟的过程语句,通常不为逻辑综
合工具接受。
100

always过程语句
„ 在测试模块中一般用于对时钟的描述,但更多地用
于对硬件功能模块的行为描述。
„ 功能模块的行为描述是由过程块构成的,每个过程
块都要由过程语句所引导,因而每个功能模块的行
为描述中,至少存在一个always过程语句。
101

例1
„ 产生两个时钟的行为描述模块。
module clk_gen_demo(clock1, clock2);
output clock1, clock2; //port-type declaration
reg clock1, clock2; //data-type declaration
/*starting the behavioral description*/
initial //procedure block1
begin
clock1=0;
clock2=1;
end
always //procedure block2
#50 clock1=~clock1;
always //procedure block3
#100 clock2=~clock2;
endmodule
2、块语句

Shanghai University Microelectronic R&D Center


103

块语句
„ 由块标识符begin-end或fork-join界定的一组行为
描述语言。
„ 过程块所要完成的具体操作内容,都是通过块语句
中所包含的描述语句的执行而得以实现的。
104

串行块begin-end
„ 位于串行块中的各条语句按串行方式顺序执行
„ 特点:
1. 串行块中的每条语句依据块中的排列次序,先后逐条顺序执
行。块中每条语句给出的延时都是相对于前一条语句执行结
束的相对时间。
2. 串行块的起始执行时间就是串行块中第一条语句开始执行的
时间。串行块的结束时间就是块中最后一条语句执行结束的
时间。
3. 串行块的行为描述可以形象地理解为硬件电路中,数据在时
钟及控制信号作用下,沿数据通道的各级寄存器之间的传送
过程。
105

包含延时的串行块描述例子2
begin
#10 reg_a=reg_b;
#10 reg_c=reg_a;
end

„ 当流程控制进入串行块语句后,经过10单位时间,将
reg_b的值赋给reg_a
„ 再经过10单位时间,又将reg_a的值赋给reg_c
„ 最后遇到块结束标识符end后,流程控制便转出块外
106

不包含延时的串行块描述例子3
begin
reg_a=reg_b;
reg_c=reg_a;
end

„ 执行过程的先后顺序及最终的执行结果都没有改变
107

并行块fork-join
„ 位于并行块中的各条语句按并行方式同时执行
„ 特点:
1. 并行块中的每条语句都是同时开始并行执行的,各条语句的执
行过程与语句在块中的先后排列顺序无关。块中每条语句给出
的延时都是相对于并行块开始执行时的绝对时间。
2. 并行块的起始执行时间就是流程控制转入并行块的时间,并行
块中的每条语句都是相对于这一时间同时开始执行的。并行块
的结束时间就是并行块中按执行时间排序最后执行的一条语句
结束的时间。
3. 并行块的行为描述可以形象地理解为硬件电路上电后,各电路
模块同时开始工作的过程。
108

包含延时的并行块描述例子4
fork
#10 reg_a=reg_b;
#10 reg_c=reg_a;
join
109

例5
„ 用串行块行为描述产生一段周期为100时间单位、占空比为1:1的信号波
形。
module wave_gen_seri(wav);
output wav;
reg wav;
event end_wave;
parameter delay=50;
initial
begin
wav=0;
#delay wav=1;
#delay wav=0;
#delay wav=1;
#delay wav=0;
#delay ->end_wave;
end
endmodule
110

例6
„ 用并行块行为描述产生一段周期为100时间单位、占空比为1:1的信号波
形。
module wave_gen_para(wav);
output wav;
reg wav;
event end_wave;
initial
fork
wav=0;
#50 wav=1;
#100 wav=0;
#150 wav=1;
#200 wav=0;
#250 ->end_wave;
join
endmodule
111

例7
„ 用于验证并行块行为描述中语句的排序不影响语句的执行过程的例子。
module wave_gen_para_verify(wav);
output wav;
reg wav;
event end_wave;
initial
fork
#250 ->end_wave;
#200 wav=0;
#150 wav=1;
#100 wav=0;
#50 wav=1;
wav=0;
join
endmodule
112

有名块Named-block
„ 块是可以取名的,方法是在块语句开始标识符后
面加上一个冒号,之后给出一个名字。
„ 作用
1. 便于实现对块语句执行过程的有效控制
2. 允许在块语句内部引入局部变量
3、赋值语句

Shanghai University Microelectronic R&D Center


114

什么是过程赋值语句
„ 位于过程块中的赋值语句称之为过程赋值语句。
„ 过程赋值语句只能对寄存器类的量进行赋值。
115

例8
„ 对各种形式的寄存器变量进行过程赋值的例子

reg_a=8’b1011_1100; //对一个8位寄存器的赋值
reg_a[3]=1’b0; //对寄存器的某一位赋值
reg_a[7:4]=4’b1010; //对寄存器的其中几位赋值
mem_a[address]=8’h5d; //对由address地址指定的存储器单元赋值
{carry, sum}=reg_a+reg_b; //通过连接算符构成一个整体进行赋值
116

过程赋值语句的两种延时模式
„ 依据定时控制在过程赋值语句中的不同位置,分为
外部模式和内部模式两类。
117

外部模式
<定时控制> <寄存器变量>=<表达式>;
„ 经“定时控制”所确定的延时后,再计算右端表达式的值,
并把结果赋给左端的寄存器变量。
„ 定时控制
1. 延时控制:就是直接给出所需延时的时间,如
#delay a=b;
2. 事件控制:以符号“@”开头,后面紧跟的是事件控制敏感表
① @ ( 信号名 )
② @ ( posedge 信号名 )
③ @ ( negedge 信号名 )
④ @ ( 敏感事件1 or 敏感事件2 or 敏感事件3 …… )
118

事件控制1

„ @ ( 信号名 )
z 信号名所指定的信号通常是一位的,但也可以是多位
的,并且对数据类型没有限制。
z 只有等到检测到信号名所确定的信号发生变化(一般是
指上升沿或下降沿)时,后面的赋值语句才被执行。
„ @ ( posedge 信号名 )
z 只关心信号发生上升沿跳变情况的出现(Positive
Edge)
119

事件控制2

„ @ ( negedge 信号名 )
z 只关心信号发生下降沿跳变情况的出现(Negative
Edge)

„ @ ( 敏感事件1 or 敏感事件2 or 敏感事件3 …… )


z 敏感事件是指上面三类事件控制中的任一种事件
120

内部模式
<寄存器变量>=<定时控制> <表达式>;
„ “定时控制”的表现形式与外部模式中的完成一致。
„ 差别
z 在外部模式中,定时控制位于过程赋值语句之前,直接
体现为对过程赋值语句执行时间的延期上,只有当延时
时间时间被满足,或其它类型的激发条件被满足后,过
程赋值语句才能被计算和赋值。
z 在内部模式中,先完成对表达式的求值过程,再等待延
时的到期,等到条件满足时,再把前面求得的结果赋给
左边的寄存器变量。
121

阻塞型过程赋值
„ 阻塞型过程赋值算符:=
„ 在串行块的执行过程中,前一条语句没有完成赋值
过程之前,后面的语句不可能被执行。也可以解释
为,由于前一条赋值语句的执行,使得后面的赋值
语句都被阻塞住了。这样的赋值过程称之为阻塞型
赋值过程,相应的赋值语句被称为阻塞型赋值语句
(Blocking Assignment Statement)
122

非阻塞型过程赋值
„ 非阻塞型过程赋值算符:<=
„ 在一个串行块中,一条非阻塞型赋值语句的执行,
并不影响块中其它语句的执行。
„ 当一个串行块中的语句全部由非阻塞型赋值语句构
成时,对这个串行块的执行构成的解释与对并行块
的解释完全是一样的。
123

例9
module demo_blocking_or_non;
reg a, b, c, d, f;
//方法一:blocking assignment in a serial block
initial
begin
a=#10 1;
b=#5 0;
c=#1 1;
end
//方法二:non-blocking assignment in a serial block
initial
begin
a<=#10 1;
b<=#5 0;
c<=#1 1;
end
endmodule
124

例10
„ 用非阻塞型赋值语句产生一段周期为100时间单位、占空比为1:1的信号
波形。
module wave_gen_para(wav);
output wav;
reg wav;
event end_wave;
initial
begin
wav<=0;
#50 wav<=1;
#100 wav<=0;
#150 wav<=1;
#200 wav<=0;
#250 ->end_wave;
end
endmodule
125

说明
„ 串行块中非阻塞型赋值语句的执行过程与并行块中
阻塞型赋值语句的执行过程是完全一致的。
„ 作为一种可综合化设计,通常一个块语句中不允许
同时出现阻塞型过程赋值语句与非阻塞型过程赋值
语句。
126

例11
用串行块及阻塞型赋值语句描述的一个例子。
module demo_seri_bloc(reg_a, reg_b, data, clk);
input data, clk;
output reg_a, reg_b;
reg reg_a, reg_b;
always @(posedge clk)
begin
reg_a=data;
reg_b=reg_a;
end
ednmodule
127

例12
用并行块及阻塞型赋值语句描述的一个例子。
module demo_seri_para(reg_a, reg_b, data, clk);
input data, clk;
output reg_a, reg_b;
reg reg_a, reg_b;
always @(posedge clk)
fork
reg_a=data;
reg_b=reg_a;
join
ednmodule
128

例13
用串行块及非阻塞型赋值语句描述的一个例子。
module demo_seri_nonblk(reg_a, reg_b, data, clk);
input data, clk;
output reg_a, reg_b;
reg reg_a, reg_b;
always @(posedge clk)
begin
reg_a<=data;
reg_b<=reg_a;
end
ednmodule
129

综合结果
130

连续赋值语句与过程赋值语句的差别
1. 赋值对象不同
z 连续赋值语句用于对连线类变量
z 过程赋值语句完成对寄存器类变量的赋值
2. 赋值过程实现方式不同
z 连线变量一旦被连续赋值语句赋值后,赋值语句右端表
达式中的信号有任何变化,都将随时反映到左端的连线
变量中
z 过程赋值语句只要在语句被执行到时,赋值过程才进行
一次,且赋值过程的具体执行时刻还受到定时控制及延
时模式等多方面的影响
131

连续赋值语句与过程赋值语句的差别
3. 语句出现的位置不同
z 连续赋值语句不能出现在任何一个过程块中
z 过程赋值语句则只能出现在过程块中

4. 语句结构不同
z 连续赋值语句以关键词assign为先导,语句中的赋值算符只要阻
塞型一种形式
z 过程赋值语句不需要相应的先导关键词,语句中的赋值算符分阻塞
型和非阻塞型两类

5. 冲突处理方式不同
z 一条连线可被多条连续赋值语句同时驱动,最后的结果依据连线类
型的不同有相应的冲突处理方式
z 寄存器变量在同一时刻只允许一条过程赋值语句对其进行赋值
132

例14
„ 用连续赋值语句实现一个与门的描述
module demo_and_assign(c, a, b);
input a, b;
output c;
assign c=a&b;
endmodule

„ 用过程赋值语句实现一个与门的描述
module demo_and_procedure(c, a, b);
input a, b;
output c;
reg c;
always @(a or b) c=a&b;
endmodule
4、高级程序语句

Shanghai University Microelectronic R&D Center


134

高级程序语句
„ 所谓高级程序语句,就是直接借用高级语言中的程序设计语
句对模块进行描述。
„ 高级程序语句只能出现在对模块进行行为描述的过程块中。
„ 分成三类
z if-else条件语句
z case语句
z 循环语句
‹forever循环语句
‹repeat循环语句
‹while循环语句
‹for循环语句
135

if-else条件语句
„ if (条件表达式) 块语句
z 当条件表达式成立时,执行后面的块语句,当条件表达
式不成立时后面的块语句不被执行
z 一条没有else选项的if语句映射到硬件上,形成的是一个
锁存器
136

if-else条件语句
„ if (条件表达式) 块语句1
else 块语句2
z 当条件表达式成立时,执行后面的块语句1,当条件表达
式不成立时,执行else后面的块语句2。
z 一条带有else选项的if语句映射到硬件上,通常形成的是
一个多路选择器(MUX)
137

if-else条件语句
„ if (条件表达式1) 块语句1
else if (条件表达式1) 块语句2
......
else if (条件表达式n) 块语句n
else 块语句n+1
z 表示多路选择控制
z 条件判断有先后次序,隐含者一种优先级关系
138

例15
描述一个具有同步清零功能(低电平有效)的上升沿D触发器。
module dff_sync(q, d, clear, clk);
output q;
input d, clear, clk;
reg q;
always @(posedge clk)
if(!clear)
q=0; //synchronous clear
else
q=d; //normal D flip-flop
ednmodule
139

例16
描述一个具有异步清零功能(低电平有效)的上升沿D触发器。
module dff_asyn(q, d, clear, clk);
output q;
input d, clear, clk;
reg q;
always @(clear or posedge clk)
if(!clear)
q=0; //asynchronous clear
else
q=d; //normal D flip-flop
ednmodule
140

case语句
„ 当多路选择的控制条件集中在某个变量的变化上
时,用case语句加以表达显得更为方便与直观
„ case语句最适宜于对CPU的译码等部件的描述以及
对有限状态机的描述
„ case语句分为case、casez、casex共三种表示方

141

case语句的表示形式
case (敏感表达式)
值1: 块语句1
值2: 块语句2
……
值n: 块语句n
default: 块语句n+1
endcase
142

例17
用case语句实现指令译码
143

例18
module demo_xz(sig);
input sig;
always @(sig)
case(sig)
1’b1: $display(“signal value is 1”);
1’b0: $display(“signal value is 0”);
1’bx: $display(“signal is in unknown state”);
1’bz: $display(“signal is in high impedance state”);
endcase
endmodule
144

casez与casex语句
„ 在case语句中,敏感表达式与值项之间的比较是一
种全等比较
„ 在casez语句中,如果比较的双方有一边的某一位
的值是z,那么这一位的比较就不予考虑
„ 在casex语句中,如果比较的双方有一边的某一位
的值是z或x,那么这一位的比较就不予考虑
145

forever循环语句
„ forever循环语句的形式定义:
forever 块语句

„ forever循环语句是一个永无止境的循环语句,即执
行完块语句后,接下来再重新执行,永不停止

initial
begin
clock=0;
forever #50 clock=~clock;
end
146

repeat循环语句
„ repeat循环语句的形式定义:
repeat (循环次数计算表达式) 块语句

„ 先计算出循环次数表达式的值,并将它作为循环过
程重复执行次数的基值被保存起来,接着执行后面
的块语句,块语句执行结束后,将重复执行次数减
去一次,再接着重新执行下一次的块语句操作,直
到循环执行次数被减为0时,结束整个循环过程。
147

while循环语句
„ while循环语句的形式定义:
while (循环执行条件表达式) 块语句

„ 先判断循环执行条件表达式是否为真,如果是,执
行后面的块语句,接着再判断循环执行条件表达式
是否仍为真,直到表达式的值为非真时,结束循环
过程。
148

例20
计算一个变量中含有值为1的位的个数(用移位寄存器实现)。
module demo_count(var,count)
parameter var_size=8, cnt_size=4;
input [var_size:0] var;
output [cnt_size] count;
reg [cnt_size:0] count;
reg [var_size:0] tmp_var;
always @(var)
begin
count=0;
tmp_var=var;
while(tmp_var)
begin
if(tmp_var[0]) count=count+1;
tmp_var=tmp_var>>1;
end
end
endmodule
149

例20
计算一个变量中含有值为1的位的个数(用下标变量实现)。
module demo_count(var,count)
parameter var_size=8, cnt_size=4;
input [var_size:0] var;
output [cnt_size] count;
integer i;
reg [cnt_size:0] count;
always @(var)
begin
count=0;
i=0;
while(i<var_size)
begin
count=count+tmp_var[i];
i=i+1;
end
end
endmodule
150

for循环语句
„ for循环语句的形式定义:
for ( 表达式1; 表达式2; 表达式3 ) 块语句

„ 表达式1只在第一次循环开始前计算一次,通常是
为了给循环控制变量赋初值。表达式2是一个循环
结束控制的条件表达式。表达式3往往是给循环变
量增值(或减值),然后再对循环结束控制的条件
表达式2重新计算和判断,若条件表达式的值仍为
真,则继续执行上述循环过程,直到表达式2不成
立时,循环过程被终止。
151

for循环语句
„ for循环语句可以看作是while循环语句的一种简约
表示形式。
begin
表达式1;
while(表达式2)
begin
循环体语句;
表达式3;
end
end
152

例21
153

disable循环中断控制语句
„ disable语句的形式定义:
disable 块名或任务名;

„ disable语句的引入,是为了中止正在进行中的循
环或任务。
154

例22
……
begin: top
for(i=0; i<n; i=i+1)
begin: inner
if(a==0)
disable inner; //skip to the next for loop
…… //other statements
if(a==b)
disable top; //exit the for loop
…… //other statements
end
end
……
155

wait语句
„ wait语句的形式定义:
wait ( 条件表达式 ) 块语句或空语句

„ 代表一种等待状态,当条件表达式非真时,过程处
于等待状态,直到等到条件表达式为真时,等待状
态才告结束。
5、Verilog任务与函数

Shanghai University Microelectronic R&D Center


157

任务(task)的形式定义
task 任务名;
端口与类型说明;
局部变量说明;
块语句
endtask
158

例23 用task实现译码器中乘法的描述
159

归纳
1. 任务的定义与引用都在一个module模块内部。
2. 任务的定义与module的定义有些类似,同样需要
进行端口说明与数据类型说明。另外,任务定义
的内部没有过程块,但在块语句中可以包含定时
控制部分。
3. 当任务被引用时,任务被激活。
4. 一个任务可以调用别的任务或函数。
160

函数(function)的形式定义
function <位宽说明> 函数名;
输入端口与类型说明;
局部变量说明;
块语句
endfunction
161

例24 用function实现译码器中乘法的描述
162

任务与函数的异同
1. 任务和函数的定义和引用都位于模块的内部,而不是一个
独立的模块。
2. 函数不能调用任务,而任务可以调用任何其它的任务或函
数。
3. 任务可以没有输入变量或有任意类型的I/O变量,而函数允
许有输入变量且至少有一个,输出则由函数名自身担当。
4. 函数通过函数名返回一个值,任务名本身没有值的意义,
只是实现某种操作,传值通过I/O端口实现。
5. 任务和函数的定义中,内部都没有过程块。
6. 函数还可以出现在连续赋值语句assign的右端表达式中。
6、Verilog模块调用

Shanghai University Microelectronic R&D Center


164

模块调用
„ 模块调用是Verilog HDL结构描述的基本构成方式
„ 一个硬件系统的描述中,必定有而且只能有一个
顶层模块
„ 有两类
1. 基本门调用( Primitive Instantiation )
2. 通常的module模块调用( Module Instantiation )
„ 模块调用的最基本形式:
模块名 调用名(端口名表项);
165

例25
module comp(out_port1, out_port2, in_port1, in_port2);
output out_port1, out_port2;
input in_port1, in_port2;
…… //other statements
endmodule
//调用方式一:位置对应调用方式
module demo_top1;
comp gate1(Q, R, J, K);
endmodule
//调用方式二:端口名对应调用方式
module demo_top2;
comp gate2(.in_port1(K),.out_port1(Q),.out_port2(R),.in_port2(J));
endmodule
//调用方式三:存在不连接端口的调用方式
module demo_top3;
comp gate3(Q, , J, K);
endmodule
166

说明
1. 位置对应调用法
按照定义时确定的端口顺序,结合设计中实际的连接关系,将模块
定义时的端口名对应地用与之相连的信号线名称所替代。

2. 端口名对应调用法
模块定义时的端口名和调用时的实际连接信号名之间一一对应关系
被显式地表示出来。调用时端口名的排列顺序可以随意改变。
.定义时的端口名( 调用时与之相连的信号名 )

3. 允许出现不连接的端口
允许调用时在不连接的端口名的相应位置不提供相连的信号名,但
为保证端口名之间的对应关系,逗号不能省略。
第五章

Verilog 系统函数与编译向导

Shanghai University Microelectronic R&D Center


168

本章提要
„ 本章有代表性地介绍由Verilog HDL模拟系统提供
的系统功能调用:系统任务与系统函数。
„ 介绍了由Verilog HDL编译系统提供的用于编译预
处理的编译向导语句。
1、Verilog系统任务与系统函数

Shanghai University Microelectronic R&D Center


170

系统任务和系统函数
„ 系统任务和系统函数是面向模拟的、嵌入到Verilog HDL
语句中的模拟系统功能调用。
„ 调用系统函数时会返回一个值,而调用系统任务则只完成
某项任务,没有值的返回。
„ 依据实现功能的不同,可分成以下几类:
1. 输出控制类系统任务:完成对输出量的格式控制,$display,
$write, $monitor
2. 模拟时标类系统函数:$time, $realtime
3. 进程控制类系统任务:用于对模拟进程的控制,$finish, $stop
4. 文件读写类系统任务:用于控制对数据文件的读写方式
5. 其它类
171

系统任务$display与$write
„ $display与$write属输出控制类系统任务
„ 调用形式
$display ( “格式控制字符串”, 输出变量名表项 ) ;
$write ( “格式控制字符串”, 输出变量名表项 ) ;
z 输出变量名表项就是指要输出的变量,各变量名之间以
逗号相隔
z 格式控制字符串的内容包括两部分
‹ 需要与输出变量一起在输出时一并显示的普通字符
‹ 对输出变量显示形式进行控制的格式说明符
„ $display在输出结束后会自动换行,而$write不会
172

输出格式说明符
格式说明符 输出格式
%h 或 %H 以十六进制的格式输出
%d 或 %D 以十进制的格式输出
%o 或 %O 以八进制的格式输出
%b 或 %B 以二进制的格式输出
%c 或 %C 以ASCII字符形式输出
%s 或 %S 以字符串方式输出
%v 或 %V 输出连线型数据的驱动强度
%t 或 %T 输出模拟系统所使用的时间单位
%m 或 %M 输出所在模块的分级名(Hierarchical Name)
%e 或 %E 将实型量以指数方式显示
%f 或 %F 将实型量以浮点方式显示
%g 或 %G 将实型量以上面两种中较短的方式显示
173

系统任务$monitor
„ 属于输出控制类系统任务
„ 调用形式
$monitor (“格式控制字符串”, 输出变量名表项 );
$monitoron;
$monitoroff;
„ $display是每调用一次就执行一次,而$monitor一旦被调
用后,就相当于启动了一个后台进程,将随时对输出变量名
表项中列出的各个变量进行检测,如发现其中的任何一个变
量在模拟过程中的某一时刻发生了任何形式的改变,则系统
将按照调用$monitor时所规定的格式,输出一次变量的结
果。
174

系统函数$time与$realtime
„ 属模拟时标类系统函数
„ 调用形式
$time
$realtime
„ 都返回从模拟程序开始执行到被调用时刻的时间,
$time返回的是64位的整数,$realtime返回的是一
个实型数。
175

系统任务$finish与$stop
„ 用于控制模拟进程的系统任务
„ 调用形式
$finish; $stop;
$finish(n); $stop(n);
„ $finish的作用就是终止仿真器的运行,结束仿真过程。
$stop的作用只相当于一个pause暂停语句。
„ n只能取以下三个值:
0:不输出任何信息。
1:输出结束仿真的时间及模拟文件的位置
2:在1的基础上增加对CPU时间、机器内存占有情况等统计结果的输出。

当$finish不带参数时,对应于缺省值1。
2、编译向导

Shanghai University Microelectronic R&D Center


177

文件包含`include
„ 把语句中指定的源文件全部包含到当前的文件中
„ 形式定义:
`include “文件名”

„ 几点说明:
1. 每条`include语句只能用于对一个文件的包含,多个文
件的包含只需用多条语句分别注明即可。
2. 文件包含允许嵌套。
3. 必要时,`include文件包含语句中的文件名表项中应指
明包含文件的目录路径。
178

取消编译向导`resetall
„ 编译系统碰到这条编译向导语句后,将取消前面所
有由编译向导引入的定义,并恢复其原始的缺省
态。
„ 这条语句通常被放在一个Verilog HDL源文件的最
开始,取消可能的由于与别的文件一起编译而带来
的一些不必要的编译控制。
第六章

实例分析

Shanghai University Microelectronic R&D Center


180

本章提要
„ 介绍初学者在开始用硬件描述语言进行电路描述时
容易出现的错误,分析错误的原因,指出修改的方

„ 介绍了一些常用功能模块的描述实例
1、Verilog设计常见错误分析

Shanghai University Microelectronic R&D Center


使用非Verilog表达方式

Shanghai University Microelectronic R&D Center


183

例1
integer i;
for ( i=0; i<8; i++ )
begin
……
将i++改写为i=i+1
end

„ 出现了非法的自增算符“i++”,这是熟悉C语言编
程者最易犯的典型错误
„ 类似的错误包括自减算符“--”
184

例2
initial
begin
a=0, b=0, c=0;
#10 a=1, b=1;
#10 a=0, c=1;
…… 将逗号改写为分号
end

„ Verilog HDL以分号作为语句的结束符
„ 设计时会不经意中用逗号代替,从而产生错误
与类型说明相关的错误

Shanghai University Microelectronic R&D Center


186

例3
module mux_beh( out, a, b, sel );
output out;
input a, b, sel;
assign out = ( sel == 0 ) ? a : b;
endmodule

module test_for_mux;
mux_str mux_beh(out, a, b, s);
initial
begin
$monitor($time,“ a=%b b=%b s=%b out=%b”, a, b, s, out);
a=0; b=1; s=0;
#10 a=1;
#10 s=1;
#10 b=0;
#10 $finish;
end
endmodule
187

例3错误分析
„ 在对MUX的行为描述中,因为涉及到的都是一位的
连线型量,因而类型说明可以被缺省。
„ 在测试模块中,激励信号在initial过程块中被过程
语句所赋值,因而都必须是寄存器型的量,不能被
缺省。
„ 修改方法:
z 在测试模块中增加对激励信号a,b,s的寄存器类型说明
语句
z reg a, b, s;
188

遗漏寄存器类量的类型说明
„ 在Verilog HDL模块描述内部,如果一个量被过程
赋值语句所赋值,那么在模块的数据类型说明部
分,必须能够找到它的寄存器类的类型说明语句
„ 如果一个量被assign连续赋值语句所赋值,则这个
量必须是连线型的
189

例4
module adder( sum, a, b );
output [8:0] sum;
input [7:0] a, b;
assign sum=a+b;
endmodule

module test_adder;
reg [7:0] a, b;
adder add( a, b, sum );
initial
begin
$monitor($time, “a=%b b=%b sum=%b”, a, b, sum);
a=0; b=0;
#100 a=1; b=1;
……
#100 $finish;
end
endmodule
190

例4错误分析
„ 在对测试模块进行编译时,a、b信号通过显式说明
可以知道它们的类型与线宽,但sum找不到相应的
类型说明与位宽说明,因而被看作是缺省的一位宽
的连线,这与实际的9位线宽的连线发生矛盾。
„ 修改方法:
z 在测试模块中增加对sum的线宽说明
z wire [8:0] sum;
191

遗漏有位宽的wire连线的类型说明
„ 在Verilog HDL的结构描述中,对wire型的连线可
以缺省其连线类型说明,但线宽说明不能被缺省。
„ 如果连线的位宽不是一位,而又不能以其它方式说
明线宽特征,则必须用显式说明语句指明连线的宽
度。
与always过程语句相关的错误

Shanghai University Microelectronic R&D Center


193

例5
module mux(out, a, b, select);
output out;
input a, b, select;
case(select)
1’b0: out=a;
1’b1: out=b;
endcase
endmodule

„ 例5是用case语句来描述一个二选一的MUX,根据select
的值,选择相应的一个输出信号加以输出。
„ case语句在Verilog中属于高级程序语句,只能出现在由过
程语句先导的过程块中,不能单独构成一个行为描述模块
194

例6
module mux(out, a, b, select);
output out;
input a, b, select;
always
case(select)
1’b0: out=a;
1’b1: out=b;
endcase
endmodule

„ always过程语句在本质上一个循环语句
„ 由于case语句内部没有延时说明,因而会出现类似于死机
的现象
195

例7
module mux(out, a, b, select);
output out;
input a, b, select;
always @(select)
case(select)
1’b0: out=a;
1’b1: out=b;
endcase
endmodule

„ 例7的描述与所要实现的二选一功能仍有出入
„ 事件控制敏感表不全
„ 输出out必须增加寄存器类的数值类型说明
196

例8(正确)
module mux(out, a, b, select);
output out;
input a, b, select;
reg out;
always @(a or b or select)
case(select)
1’b0: out=a;
1’b1: out=b;
endcase
endmodule
由零延时引起的模拟错误

Shanghai University Microelectronic R&D Center


198

例9
module comparator(out, in1, in2);
output [1:0] out;
input [7:0] in1, in2;
reg [1:0] out;
always
begin
if(in1==in2)
out=2’b00;
else if(in1>in2)
out=2’b01;
else
out=2’b10;
end
initial
#10 $finish;
endmodule
199

例9错误分析
„ 该模块用于模拟时,出现类似死机的现象
„ always过程语句中没有事件控制敏感表,因而循环
条件始终成立
„ 条件语句内部的赋值语句中都不存在延时说明,因
而整个循环体的执行始终停留在0时刻进行
2、Verilog设计实例

Shanghai University Microelectronic R&D Center


常用组合电路的设计

Shanghai University Microelectronic R&D Center


202

例10
基本组合电路的设计:
203

例10
module orand(OUT,A,B,C,D,E);
input A,B,C,D,E;
output OUT;

//描述方法一:基本元件调用方式
or (or1, A, B);
or (or2, C, D);
and (OUT, or1, or2, E);

endmodule
204

例10
module orand(OUT,A,B,C,D,E);
input A,B,C,D,E;
output OUT;

//描述方法二:assign连续赋值语句方式
assign OUT=E&(A|B)&(C|D);

endmodule
205

例10
module orand(OUT,A,B,C,D,E);
input A,B,C,D,E;
output OUT;

//描述方法三:过程赋值语句方式
reg OUT;
always @(A or B or C or D or E)
begin
if(E)
OUT=(A|B)&(C|D);
else
OUT=0;
end

endmodule
206

例10
module orand(OUT,A,B,C,D,E);
input A,B,C,D,E;
output OUT;

//描述方法四:过程连续赋值语句方式
reg OUT;
always @(E)
begin
if(E)
assign OUT=(A|B)&(C|D);
else
assign OUT=0;
end

endmodule
207

例11
数据锁存器的设计

8
in

8
out

en
208

例11
module dlatch(out, in, enable);
input [7:0] in;
output [7:0] out;
8
input enable; in

8
out
//描述方法一:过程赋值语句描述方式
en
reg [7:0] out;
always @(in or enable)
begin
if(enable)
out=in;
end

endmodule
209

例11
module dlatch(out, in, enable);
input [7:0] in;
output [7:0] out;
8
input enable; in

8
out
//描述方法二:过程连线赋值语句描述方式
en
reg [7:0] out;
always @(enable)
begin
if(enable)
assign out=in;
else
deassign out;
end
endmodule
210

例12
多路器MUX的描述

4
a

b
4
out

sel
211

例12
module mux(out, a, b, c, d, sel);
output [3:0] out;
input [3:0] a, b, c, d;
4
input [1:0] sel; a
reg [3:0] out;
always @(a or b or c or d or sel) b
4
begin out

case(sel) c
2’b00: out=a;
2’b01: out=b; d
2’b10: out=c; 2
2’b11: out=d;
sel
default: out=4’bx;
endcase
end
endmodule
212

例13
四位加法器的描述
module adder4(a,b,sum,cin,cout);
input [3:0] a, b;
output [3:0] sum;
input cin;
output cout;
assign {cout,sum}=a+b+cin;
endmodule
常用时序电路的设计

Shanghai University Microelectronic R&D Center


214

例14
普通触发器的设计
module dff(q,data,clk);
output q;
input data, clk;
reg q;
always @(posedge clk)
begin
q=data;
end
endmodule
215

例15
同步清零、置位触发器的设计
module dff_rs_syn(q,data,set,clr,clk);
output q;
input data, set, clr, clk;
reg q;
always @(posedge clk)
begin
if(!clr)
q=0;
else if(!set)
q=1;
else
q=data;
end
endmodule
216

例16
异步清零、置位触发器的设计
module dff_rs_asyn(q,data,set,clr,clk);
output q;
input data, set, clr, clk;
reg q;
always @(clr or set or posedge clk)
begin
if(!clr)
q=0;
else if(!set)
q=1;
else
q=data;
end
endmodule
217

例17
移位寄存器的设计
module shift(data_out, data_in, clr, clk);
output [7:0] data_out;
input data_in, clr, clk;
reg [7:0] data_out;
always @(posedge clk)
begin
if(!clr)
data_out=8’b0;
else
begin
data_out=data_out<<1;
data_out[0]=data_in
end
end
endmodule
218

有限状态机的设计

You might also like