资源描述
Verilog HDL简介
1基础概念
1.1标识符
定义
标识符( identifier)用于定义模块名、端口名、信号名等。 Verilog HDL 中的标识符( identifier)可以是任意一组字母、数字、$符号和_(下划线)符号的组合,但标识符的第一个字符必须是字母或者下划线。另外,标识符是区分大小写的。以下是标识符的几个例子:
Count
COUNT //与Count 不同。
R56_68
FIVE$
1.2关键词
Verilog HDL 定义了一系列保留字,叫做关键词,附录A 列出了语言中的所有保留字。注意只有小写的关键词才是保留字。例如,标识符always (这是个关键词)与标识符ALWAYS(非关键词)是不同的。
1.3操作符
与C语言的操作符基本相同,略有扩展。见附录2
1.4注释
//单行注释
/*多行注释 ----------
------------多行注释*/
1.5数字值集合
本小节介绍Verilog HDL的值的集合和常量( 整型、实型、字符型)和变量等。
1.5.1 值集合
Verilog HDL中规定了四种基本的值类型:
0:逻辑0或“假”;
1:逻辑1或“真”;
X:未知值;
Z:高阻。
注意这四种值的解释都内置于语言中。如一个为z 的值总是意味着高阻抗,一个为0 的值通常是指逻辑0 。
在门的输入或一个表达式中的为“z ”的值通常解释成“x ”。
此外,x 值和z 值都是不分大小写的,也就是说,值0x1z 与值0X1Z 相同。
Verilog HDL 中的常量是由以上这四类基本值组成的。
1.5.2 常量
Verilog HDL 中有三种常量:
整型、实型、字符串型。
下划线符号(_)可以随意用在整数或实数中,它们就数量本身没有意义。它们能用来提高易读性;唯一的限制是下划线符号不能用作为首字符。
下面主要介绍整型和字符串型。
1. 整型
整型数可以按如下两种方式书写:
1) 简单的十进制数格式
2) 基数格式
A. 简单的十进制格式
这种形式的整数定义为带有一个可选的“+”(一元)或“-”(一元)操作符的数字序列。
下面是这种简易十进制形式整数的例子。
32 十进制数32
-15 十进制数-15
B. 基数表示法
这种形式的整数格式为:
[size ] 'base value
size 定义以位计的常量的位长;base 为o 或O(表示八进制),b 或B(表示二进制),d 或D(表示十进制),h 或H (表示十六进制)之一;value 是基于base 的值的数字序列。值x 和z 以及十六进制中的a 到f 不区分大小写。
下面是一些具体实例:
5 'O37 5 位八进制数(二进制 11111 )
4 'D2 4 位十进制数(二进制0011)
4 'B1x_01 4 位二进制数
7 'Hx 7位x(扩展的x), 即xxxxxxx
4 'hZ 4 位z(扩展的z) , 即zzzz
4 'd-4 非法:数值不能为负
8 'h 2A 在位长和字符之间,以及基数和数值之间允许出现空格
3' b 001 非法: ` 和基数b 之间不允许出现空格
(2+3)'b10 非法:位长不能够为表达式
注意,x (或z )在十六进制值中代表4 位x(或z ),在八进制中代表3 位x(或z ),在二进制中代表1 位x (或z )。
基数格式计数形式的数通常为无符号数。这种形式的整型数的长度定义是可选的。如果没有
定义一个整数型的长度,数的长度为相应值中定义的位数。下面是两个例子:
'o 721 9 位八进制数
'h AF 8 位十六进制数
如果定义的长度比为常量指定的长度长,通常在左边填0 补位。但是如果数最左边一位为x 或z ,就相应地用x 或z 在左边补位。例如:
10'b10 左边添0 占位, 0000000010
10'bx0x1 左边添x 占位, x x x x x x x 0 x 1
如果长度定义得更小,那么最左边的位相应地被截断。例如:
3 ' b1001 _ 0011 与3'b011 相等
5'H0FFF 与5'H1F 相等
2. 字符串型
字符串是双引号内的字符序列。字符串不能分成多行书写。例如:
"INTERNAL ERROR"
" REACHED->HERE "
用8 位ASCII 值表示的字符可看作是无符号整数。因此字符串是8 位ASCII 值的序列。为存储字符串“INTERNAL ERROR ”,变量需要8 * 1 4 位。
r e g [1: 8*14] Message;
. . .
Message = "INTERNAL ERROR";
2、程序结构
2.1 设计方法
当前的ASIC设计有多种设计方法,但一般地采用自顶向下的设计方法。
随着技术的发展,一个芯片上往往集成了几十万到几百万个器件,传统的自底向上的设计方法已不太现实。因此,一个设计往往从系统级设计开始,把系统划分成几个大的基本的功能模块,每个功能模块再按一定的规则分成下一个层次的基本单元,如此一直划分下去。自顶向下的设计方法可用下面的树状结构表示:
图1 TOP-DOWN 设计思想
在数字电路设计中,数字电路可简单归纳为两种要素:线和器件。线是器件管脚之间的物理连线;器件也可简单归纳为组合逻辑器件(如与或非门等)和时序逻辑器件(如寄存器、锁存器、RAM等)。一个数字系统(硬件)就是多个器件通过一定的连线关系组合在一块的。因此,Verilog HDL的建模实际上就是如何使用HDL语言对数字电路的两种基本要素的特性及相互之间的关系进行描述的过程。
下面通过一些实例,以便对Verilog HDL 的设计建模有个大概的印象。
2.2 模块
2.2.1 简单事例
下面先介绍几个简单的Verilog HDL程序。
例[1] 加法器
module addr (a, b, cin, count, sum);
input [2:0] a;
input [2:0] b;
input cin;
output count;
output [2:0] sum;
assign {count,sum} = a +b + cin;
endmodule
该例描述一个3位加法器,从例子可看出整个模块是以module 开始,endmodule 结束。
例[2] 比较器
module compare (equal,a,b);
input [1:0] a,b; // declare the input signal ;
output equare ; // declare the output signal;
assign equare = (a == b) ? 1:0 ;
/ * if a = b , output 1, otherwise 0;*/
endmodule
该例描述一个比较器, 从上可看到,/* .... */ 和 // ... 表示注释部分。注释只是为了方便设计者读懂代码,对编译并不起作用。
例[3] 三态驱动器
module mytri (din, d_en, d_out);
input din;
input d_en;
output d_out;
// -- Enter your statements here -- //
assign d_out = d_en ? din :'bz;
endmodule
module trist (din, d_en, d_out);
input din;
input d_en;
output d_out;
// -- statements here -- //
mytri u_mytri(din,d_en,d_out);
endmodule
该例描述了一个三态驱动器。其中三态驱动门在模块 mytri 中描述,而在模块trist 中调用了模块mytri 。模块mytri 对trist 而言相当于一个已存在的器件,在trist 模块中对该器件进行实例化,实例化名 u_mytri 。
2.2.2 模块的结构
通过上面的实例可看出,一个设计是由一个个模块(module)构成的。一个模块的设计如下:
1、模块内容是嵌在module 和endmodule两个语句之间。每个模块实现特定的功能,模块可进行层次的嵌套,因此可以将大型的数字电路设计分割成大小不一的小模块来实现特定的功能,最后通过由顶层模块调用子模块来实现整体功能,这就是Top-Down的设计思想,如 2.2.1的例[3]。
2、模块包括接口描述部分和逻辑功能描述部分。这可以把模块与器件相类比。
模块的端口定义部分:
如上例: module addr (a, b, cin, count, sum); 其中module 是模块的保留字,addr 是模块的名字,相当于器件名。()内是该模块的端口声明,定义了该模块的管脚名,是该模块与其他模块通讯的外部接口,相当于器件的pin 。
模块的内容,包括I/O说明,内部信号、调用模块等的声明语句和功能定义语句。I/O说明语句如: input [2:0] a; input [2:0] b; input cin; output count; 其中的input 、output、inout 是保留字,定义了管脚信号的流向,[n:0]表示该信号的位宽(总线或单根信号线)。
逻辑功能描述部分如: assign d_out = d_en ? din :'bz;
mytri u_mytri(din,d_en,d_out);
功能描述用来产生各种逻辑(主要是组合逻辑和时序逻辑,可用多种方法进行描述,具体的用法下面章节有介绍),还可用来实例化一个器件,该器件可以是厂家的器件库也可以是我们自己用HDL设计的模块(相当于在原理图输入时调用一个库元件)。在逻辑功能描述中,主要用到assign 和always 两个语句。
3、对每个模块都要进行端口定义,并说明输入、输出口,然后对模块的功能进行逻辑描述,
当然,对测试模块,可以没有输入输出口。
4、Verilog HDL 的书写格式自由,一行可以写几个语句,也可以一个语句分几行写。具体由
代码书写规范约束。
5、除endmodule 语句外,每个语句后面需有分号表示该语句结束。
2.2.3 模块语法
1. 一个模块的基本语法如下:
一个模块的基本语法如下:
module module_name (port1, port2, ......) ;
// D e c l a r a t i o n s :
input, output, inout,
reg, wire, parameter,
function, task, . . .
//S t a t e m e n t s :
Initial statement
Always statement
Module instantiation
Gate instantiation
Continuous assignment
endmodule
模块的结构需按上面的顺序进行,声明区用来对信号方向、信号数据类型、函数、任务、参数等进行描述。语句区用来对功能进行描述如:器件调用(Module instantiation )等。
2. 书写语法建议
一个模块用一个文件;
模块名与文件名要同名;
一行一句语句。
信号方向按输入、输出、双向顺序描述。
设计模块时可尽量考虑采用参数化,提高设计的重用。
以上是初学者的建议,具体的或深入的方面可看相关的文档。下面的有关语法建议类似。
2.3 时延
信号在电路中传输会有传播延时等,如线延时、器件延时。时延就是对延时特性的HDL描述。举例如下:
assign # 2 B = A;
表示 B信号在2个时间单位后得到A信号的值。如下图:
图2时延
在Verilog HDL中,所有时延都必须根据时间单位进行定义,定义方式为在文件头添加如下语句:
`timescale 1ns /100ps
其中’timescale 是Verilog HDL 提供的编译预处理命令, 1ns 表示时间单位是1ns ,100ps表示时间精度是100ps。根据该命令,编译工具才可以认知 #2 为2ns。
在Verilog HDL 的IEEE标准中没有规定时间单位的缺省值,由各模拟工具确定。因此,在写代码时必须确定。
2.4 三种建模方式
在HDL的建模中,主要有结构化描述方式、数据流描述方式和行为描述方式,下面分别举例说明三者之间的区别。
2.4.1 结构化描述方式
结构化的建模方式就是通过对电路结构的描述来建模,即通过对器件的调用(HDL概念称为例化),并使用线网来连接各器件的描述方式。这里的器件包括Verilog HDL的内置门如与门and,异或门xor等,也可以是用户的一个设计。结构化的描述方式反映了一个设计的层次结构。
例[1]:一位全加器
图3 一位全加器的结构图
代码:
module FA_struct (A, B, Cin, Sum, Cout);
input A;
input B;
input Cin;
output Sum;
output Cout;
wire S1, T1, T2, T3;
// -- statements -- //
xor x1 (S1, A, B); //第1个参数是输出,后续参数是输入。以下同
xor x2 (Sum, S1, Cin);
and A1 (T3, A, B );
and A2 (T2, B, Cin);
and A3 (T1, A, Cin);
or O1 (Cout, T1, T2, T3 );
endmodule
该实例显示了一个全加器由两个异或门、三个与门、一个或门构成。S1、T1、T2、T3则是门与门之间的连线。代码显示了用纯结构的建模方式,其中xor 、and、or 是Verilog HDL 内置的门器件。以 xor x1 (S1, A, B) 该例化语句为例:
xor 表明调用一个内置的异或门,器件名称xor ,代码实例化名x1(类似原理图输入方式)。括号内的S1,A,B 表明该器件管脚的实际连接线(信号)的名称,其中 A、B是输入,S1是输出。其他同。
例[2]:两位的全加器
两位的全加器可通过调用两个一位的全加器来实现。该设计的设计层次示意图和结构图如
下:
图4 两位全加器的结构示意图
代码:
module Four_bit_FA (FA, FB, FCin, FSum, FCout ) ;
parameter SIZE = 2;
input [SIZE:1] FA;
input [SIZE:1] FB;
input FCin;
output [SIZE:1] FSum;
output FCout;
wire FTemp;
FA_struct FA1(
.A (FA[1]),
.B (FB[1]),
.Cin (FCin) ,
.Sum (FSum[1]),
.Cout (Ftemp)
);
FA_struct FA2(
.A (FA[2]),
.B (FB[2]),
.Cin (FTemp) ,
.Sum (FSum[2]),
.Cout (FCount )
);
endmodule
该实例用结构化建模方式进行一个两位的全加器的设计,顶层模块Four_bit_FA 调用了两个一位的全加器 FA_struct 。在这里,以前的设计模块FA_struct 对顶层而言是一个现成的器件,顶层模块只要进行例化就可以了。
注意这里的例化中,端口映射(管脚的连线)采用名字关联,如 .A (FA[2]) ,其中.A 表示调用器件的管脚A,括号中的信号表示接到该管脚A的电路中的具体信号。
wire 保留字表明信号Ftemp 是属线网类型(下面有具体描述)。
另外,在设计中,尽量考虑参数化的问题。
器件的端口映射必须采用名字关联。
2.4.2 数据流描述方式
数据流的建模方式就是通过对数据流在设计中的具体行为的描述的来建模。最基本的机制就是用连续赋值语句。在连续赋值语句中,某个值被赋给某个线网变量(信号),语法如下:
assign [delay] net_name = expression;
如:assign #2 A = B;
在数据流描述方式中,还必须借助于HDL提供的一些运算符,如按位逻辑运算符:逻辑与(&),逻辑或(|)等。
以上面的全加器为例,可用如下的建模方式:
图5 一位全加器的结构图
`timescale 1ns/100ps
module FA_flow(A,B,Cin,Sum,Cout)
input A,B,Cin;
output Sum, Cout;
wire S1,T1,T2,T3;
assign # 2 S1 = A ^ B;
assign # 2 Sum = S1 ^ Cin;
assign #2 T3 = A & B;
assign #2 T1 = A & Cin;
assign #2 T2 = B & Cin ;
assign #2 Cout = (T1 | T2) | T3;
endmodule
注意在各assign 语句之间,是并行执行的,即各语句的执行与语句之间的顺序无关。如上,当A有个变化时,S1、T3、T1 将同时变化,S1的变化又会造成Sum的变化。
参考:附录3 用数据流描述方式重写2-4译码器
2.4.3 行为描述方式
行为方式的建模是指采用对信号行为级的描述(不是结构级的描述)的方法来建模。在表示方面,类似数据流的建模方式,但一般是把用initial 块语句或always 块语句描述的归为行为建模方式。行为建模方式通常需要借助一些行为级的运算符如加法运算符(+),减法运算符(-)等。以下举个例子,对initial 和always 语句的具体应用可看相关章节的介绍,这里,先对行为建模方式有个概念。
例[1] 一位全加器的行为建模
module FA_behav1(A, B, Cin, Sum, Cout );
input A,B,Cin;
output Sum,Cout;
reg Sum, Cout;
reg T1,T2,T3;
always@ ( A or B or Cin )
begin
Sum = (A ^ B) ^ Cin ;
T1 = A & Cin;
T2 = B & Cin ;
T3 = A & B;
Cout = (T1| T2) | T3;
end
endmodule
需要先建立以下概念:
1、只有寄存器类型的信号才可以在always和initial 语句中进行赋值,类型定义通过reg语句实现。
2、always 语句是一直重复执行,由敏感表(always 语句括号内的变量)中的变量触发。
3、always 语句从0 时刻开始。
4、在begin 和end 之间的语句是顺序执行,属于串行语句。
例[2]:一位全加器的行为建模
module FA_behav2(A, B, Cin, Sum, Cout );
input A,B,Cin;
output Sum,Cout;
reg Sum, Cout;
always@ ( A or B or Cin )
begin
{Cout ,Sum} = A + B + Cin ;
end
endmodule
在例2中,采用更加高级(更趋于行为级)描述方式,即直接采用“+”来描述加法。{Cout,Sum}表示对位数的扩展,因为两个1bit 相加,和有两位,低位放在Sum 变量中,进位放在Cout 中。
2.4.4 混合设计描述
在实际的设计中,往往是多种设计模型的混合。一般地,对顶层设计,采用结构描述方式,对低层模块,可采用数据流、行为级或两者的结合。如上面的两bit 全加器,对顶层模块(Four_bit_FA)采用结构描述方式对低层进行例化,对低层模块(FA)可采用结构描述、数据流描述或行为级描述。
书写规范建议:
一个语句一行。
采用空四格的table 键进行缩进。
2.5 数据类型
Verilog HDL 主要包括两种数据类型
线网类型(net type) 和寄存器类型(reg type)。
2.5.1 线网类型
1. wire 和 tri 定义
线网类型主要有wire 和tri 两种。线网类型用于对结构化器件之间的物理连线的建模。如器件的管脚,内部器件如与门的输出等。以上面的加法器为例,输入信号A,B是由外部器件所驱动,异或门X1的输出S1是与异或门X2输入脚相连的物理连接线,它由异或门X1所驱动。
由于线网类型代表的是物理连接线,因此它不存贮逻辑值。必须由器件所驱动。通常由assign进行赋值。如 assign A = B ^ C;当一个wire 类型的信号没有被驱动时,缺省值为Z(高阻)。信号没有定义数据类型时,缺省为 wire 类型。
如上面一位全加器的端口信号 A,B,SUM等,没有定义类型,故缺省为wire 线网类型。
2. 两者区别
tri 主要用于定义三态的线网。
2.5.2 寄存器类型
1. 定义
reg 是最常用的寄存器类型,寄存器类型通常用于对存储单元的描述,如D型触发器、ROM等。存储器类型的信号当在某种触发机制下分配了一个值,在分配下一个值之时保留原值。但必须注意的是,reg 类型的变量,不一定是存储单元,如在always 语句中进行描述的必须用reg 类型的变量。
reg 类型定义语法如下:
reg [msb: lsb] reg1, reg2, . . . r e g N;
msb 和lsb 定义了范围,并且均为常数值表达式。范围定义是可选的;如果没有定义范围,缺省值为1 位寄存器。例如:
reg [3:0] Sat; // S a t 为4 位寄存器。
reg Cnt; //1 位寄存器。
reg [1:32] Kisp, Pisp, Lisp ;
寄存器类型的值可取负数,但若该变量用于表达式的运算中,则按无符号类型处理,如:
reg [3:0] A ;
.....
A = -1;
....
则A的二进制为 1111,在运算中,A总按无符号数15 来看待。
2. 寄存器类型的存储单元建模举例
用寄存器类型来构建两位的D触发器如下:
reg [1:0] Dout ;
.....
always@(posedge Clk)
Dout <= Din;
....
用寄存器数组类型来建立存储器的模型,如对2个8位的RAM建模如下:
reg [7:0] Mem[0:1] ;
对存储单元的赋值必须一个个第赋值,如上2个8位的RAM的赋值必须用两条赋值语句:
.....
Mem[0] = ‘h 55;
Mem[1] = ‘haa;
....
3. 书写规范建议
对数组类型,请按降序方式,如[7:0] ;
3 语句
3.1 赋值语句
参考:夏宇闻书p43-45
3.2块语句
参考:夏宇闻书p45-48
3.3 if语句
条件语句
if 语句的语法如下:
if(condition_1)
procedural_statement_1
{else if(condition_2)
procedural_statement_2}
{else
procedural_statement_3}
如果对condition_1 求值的结果为个非零值, 那么procedural_statement_1 被执, 如果
condition_1 的值为0 、x 或z ,那么procedural_statement_1 不执行。如果存在一个else 分支,那么这个分支被执行。以下是一个例子。
if(Sum < 60)
begin
Grade = C;
Total_C = Total _c + 1;
end
else if(Sum < 75)
begin
Grade = B;
Total_B = Total_B + 1;
end
else
begin
Grade = A;
Total_A = Total_A + 1;
end
注意条件表达式必须总是被括起来,如果使用if - if - else 格式,那么可能会有二义性,如下例所示:
if(C l k)
if(R e s e t)
Q = 0;
else
Q = D;
问题是最后一个else 属于哪一个if? 它是属于第一个if 的条件(Clk)还是属于第二个if的条件(Reset)? 这在Verilog HDL 中已通过将else 与最近的没有else 的if 相关联来解决。在这个例子中,else 与内层if 语句相关联。
以下是另一些if 语句的例子。
if(Sum < 100)
Sum = Sum + 10;
if(Nickel_In)
Deposit = 5;
else if (Dime_In)
Deposit = 10;
else if(Quarter_In)
Deposit = 25;
else
Deposit = ERROR;
书写建议:
1、条件表达式需用括号括起来。
2、若为if - if 语句,请使用块语句 begin --- end :
if(C l k)
begin
if(R e s e t)
Q = 0;
else
Q = D;
end
以上两点建议是为了使代码更加清晰,防止出错。
3、对if 语句,除非在时序逻辑中,if 语句需要有else 语句。若没有缺省语句,设计将产生一个锁存器,锁存器在ASIC设计中有诸多的弊端(可看同步设计技术所介绍)。如下一例:
if (T)
Q = D;
没有else 语句,当T为1(真)时,D 被赋值给Q,当T为0(假)时,因为没有else 语句,电路保持 Q 以前的值,这就形成一个锁存器。
3.4 case语句
case 语句是一个多路条件分支形式,其语法如下:
case(case_expr)
case_item_expr{ ,case_item_expr} :procedural_statement
. . .
. . .
[default:procedural_statement]
endcase
case 语句首先对条件表达式case_expr 求值,然后依次对各分支项求值并进行比较,第一个与条件表达式值相匹配的分支中的语句被执行。可以在1 个分支中定义多个分支项;这些值不需要互斥。缺省分支覆盖所有没有被分支表达式覆盖的其他分支。
例:
case (HEX)
4'b0001 : LED = 7'b1111001; // 1
4'b0010 : LED = 7'b0100100; // 2
4'b0011 : LED = 7'b0110000; // 3
4'b0100 : LED = 7'b0011001; // 4
4'b0101 : LED = 7'b0010010; // 5
4'b0110 : LED = 7'b0000010; // 6
4'b0111 : LED = 7'b1111000; // 7
4'b1000 : LED = 7'b0000000; // 8
4'b1001 : LED = 7'b0010000; // 9
4'b1010 : LED = 7'b0001000; // A
4'b1011 : LED = 7'b0000011; // B
4'b1100 : LED = 7'b1000110; // C
4'b1101 : LED = 7'b0100001; // D
4'b1110 : LED = 7'b0000110; // E
4'b1111 : LED = 7'b0001110; // F
default :LED = 7'b1000000; // 0
endcase
书写建议:
case 的缺省项必须写,防止产生锁存器。
4 结构建模
前面已简单介绍了结构化的描述方式,本章节再总结一下。
4.1 模块定义结构
我们已经了解到,一个设计实际上是由一个个module 组成的。一个模块module 的结构如下:
module module_name (port_list) ;
Declarations_and_Statements
endmodule
在结构建模中,描述语句主要是实例化语句,包括对Verilog HDL 内置门如与门(and)异或门(xor)等的例化,如3.3.1节中全加器的xor 门的调用;及对其他器件的调用,这里的器件包括FPGA厂家提供的一些宏单元以及设计者已经有的设计。
在实际应用中,实例化语句主用指后者,对内置门建议不采纳,而用数据流或行为级方式对基本门电路的描述。端口队列port_list 列出了该模块通过哪些端口与外部模块通信。
4.2 模块端口
模块的端口可以是输入端口、输出端口或双向端口。缺省的端口类型为线网类型(即wire 类型)。输出或输入输出端口能够被重新声明为reg 型。无论是在线网说明还是寄存器说明中,线网或寄存器必须与端口说明中指定的长度相同。下面是一些端口说明实例。
module Micro (PC, Instr, NextAddr );
/ / 端口说明
input [3:1] PC;
output [1:8] Instr;
inout [16:1] NextAddr;
/ /重新说明端口类型:
wire [16:1] NextAddr; // 该说明是可选的,因为缺省的就是wire类型,但如果指定了,就
必须与它的端口说明保持相同长度,这里定义线的位宽16,是总线。
reg [1:8] Instr; / /Instr 已被重新说明为reg 类型,因此它能在always 语句或在initial 语句中赋值。
. . .
Endmodule
4.3 实例化语句
1. 例化语法
一个模块能够在另外一个模块中被引用,这样就建立了描述的层次。模块实例化语句形式如下:
module_name instance_name(port_associations) ;
信号端口可以通过位置或名称关联;但是关联方式不能够混合使用。端口关联形式如下:
port_expr / /通过位置。
.PortName (port_expr) / /通过名称。
例[1]:
....
module and (C,A,B);
input A,B;
output C;
...
and A1 (T3, A, B ); //实例化时采用位置关联,T3对应输出端口C,A对应A,B对应B。
and A2( //实例化时采用名字关联,.C是and 器件的端口,其与信号T3相连
.C(T3),
.A(A),
.B(B)
);
....
port_expr 可以是以下的任何类型:
1) 标识符(reg 或net )如 .C(T3),T3为wire型标识符。
2) 位选择,如 .C(D[0]),C端口接到D信号的第0bit 位。
3) 部分选择,如 .Bus (Din[5:4])。
4) 上述类型的合并,如 .Addr({ A1,A2[1:0]}。
5) 表达式(只适用于输入端口),如 .A (wire Zire = 0 )。
建议:在例化的端口映射中请采用名字关联,这样,当被调用的模块管脚改变时不易出错。
2. 悬空端口的处理
在我们的实例化中,可能有些管脚没用到,可在映射中采用空白处理,如:
DFF d1 (
.Q(QS),
.Qbar ( ),
.Data (D ) ,
.Preset ( ), // 该管脚悬空
.Clock (CK)
); //名称对应方式。
对输入管脚悬空的,则该管脚输入为高阻 Z,输出管脚被悬空的,该输出管脚废弃不用。
3. 不同端口长度的处理
当端口和局部端口表达式的长度不同时,端口通过无符号数的右对齐或截断方式进行匹配。
例如:
module Child (Pba, Ppy) ;
input [5:0] Pba;
output [2:0] Ppy;
. . .
endmodule
module Top;
wire [1:2] Bdl;
wire [2:6] M p r;
Child C1 (Bdl, Mpr) ;
endmodule
在对Child 模块的实例中,Bdl[2]连接到Pba[ 0 ],Bdl[1] 连接到Pba[ 1 ],余下的输入端口Pba[5]、Pba[4]和Pba[3]悬空,因此为高阻态z 。与之相似,Mpr[6]连接到Ppy[0],Mpr[5]连接到Ppy[1],Mpr[4] 连接到Ppy[2 ]。参见下图:
图6 端口匹配
4.4 结构化建模具体实例
对一个数字系统的设计,我们采用的是自顶向下的设计方式。可把系统划分成几个功能模
块,每个功能模块再划分成下一层的子模块。每个模块的设计对应一个module ,一个module 设计成一个verilog HDL 程序文件。因此,对一个系统的顶层模块,我们采用结构化的设计,即顶层模块分别调用了各个功能模块。下面以一个实例(一个频率计数器系统)说明如何用HDL进行系统设计。
在该系统中,我们划分成如下三个部分:2输入与门模块,LED显示模块,4位计数器模块。系统的层次描述如下:
图7 系统层次描述
顶层模块CNT_BCD,文件名CNT_BCD.v,该模块调用了低层模块 AND2、CNT_4b和
HEX2LED 。系统的电路结构图如下:
图8 系统电路框图
顶层模块CNT_BCD对应的设计文件 CNT_BCD.v 内容为:
module CNT_BCD (BCD_A,BCD_B,BCD_C,BCD_D,CLK,GATE,RESET) ;
// ------------ Port declarations --------- //
input CLK;
input GATE;
input RESET;
output [3:0] BCD_A;
output [3:0] BCD_B;
output [3:0] BCD_C;
output [3:0] BCD_D;
wire CLK;
wire GATE;
wire RESET;
wire [3:0] BCD_A;
wire [3:0] BCD_B;
wire [3:0] BCD_C;
wire [3:0] BCD_D;
// ----------- Signal declarations -------- //
wire NET104;
wire NET116;
wire NET124;
wire NET132;
wire NET80;
wire NET92;
// -------- Component instantiations -------//
CNT_4b U0(
.CLK(CLK),
.ENABLE(GATE),
.FULL(NET80),
.Q(BCD_A),
.RE
展开阅读全文