下载第 10章 其 他 论 题本章讲述诸如函数、任务、层次结构、值变转储文件和编译程序指令等多种论题。
10.1 任务一个任务就像一个过程,它可以从描述的不同位置执行共同的代码段。共同的代码段用任务定义编写成任务,这样它就能够从设计描述的不同位置通过任务调用被调用。任务可以包含时序控制,即时延控制,并且任务也能调用其它任务和函数。
10.1.1 任务定义任务定义的形式如下:
t a s k t a s k _ i d;
[d e c l a r a t i o n s]
p r o c e d u r a l _ s t a t e m e n t
e n d t a s k
任务可以没有或有一个或多个参数。值通过参数传入和传出任务。除输入参数外(参数从任务中接收值),任务还能带有输出参数(从任务中返回值)和输入输出参数。任务的定义在模块说明部分中编写。例如:
m o d u l e H a s _ T a s k;
p a r a m e t e r MAXBITS = 8;
t a s k R e v e r s e _ B i t s;
i n p u t [MAXBITS - 1:0] D i n;
o u t p u t [MAXBITS - 1:0] D o u t;
i n t e g e r K;
b e g i n
f o r (K = 0; K < M A X B I T S; K = K + 1)
D o u t [M A X B I T S-K] = D i n[K] ;
e n d
e n d t a s k
.,,
e n d m o d u l e
任务的输入和输出在任务开始处声明。这些输入和输出的顺序决定了它们在任务调用中的顺序。下面是另一个例子,
t a s k R o t a t e _ L e f t;
i n o u t [1:16] I n _ A r r;
i n p u t [0:3] S t a r t _ B i t,S t o p _ B i t,R o t a t e _ B y;
r e g F i l l _ V a l u e;
i n t e g e r M a c 1,M a c 3;
b e g i n
f o r (M a c 3 = 1; Mac3 <= R o t a t e _ B y; M a c 3 = M a c 3 + 1)
b e g i n
F i l l _ V a l u e = I n _ A r r[S t o p _ B i t] ;
f o r (M a c 1 = S t o p _ B i t; M a c 1 >= S t a r t _ B i t + 1;
M a c 1 = M a c 1 - 1 )
I n _ A r r[M a c 1] = I n _ A r r [M a c 1 - 1];
I n _ A r r[S t a r t _ B i t] = F i l l _ V a l u e;
e n d
e n d
e n d t a s k
F i l l _ Va l u e是任务的局部寄存器,只能在任务中直接可见。任务的第 1个参数是输入输出数组 I n _ A rr,随后是 3个输入,S t a rt _ B i t,S t o p _ B i t和 R o t a t e _ B y。
除任务参数外,任务还能够引用说明任务的模块中定义的任何变量。在下一节将举例说明这种情况。
10.1.2 任务调用一个任务由任务调用语句调用。任务调用语句给出传入任务的参数值和接收结果的变量值。任务调用语句是过程性语句,可以在 always 语句或 initial 语句中使用。形式如下:
t a s k _ i d [ (e x p r 1,e x p r 2,.,,,e x p r N) ] ;
任务调用语句中参数列表必须与任务定义中的输入、输出和输入输出参数说明的顺序匹配。此外,参数要按值传递,不能按地址传递。在其它高级编程语言中,例如 P a s c a l,任务与过程的一个重要区别是任务能够被并发地调用多次,并且每次调用能带有自己的控制,最重要的一点是在任务中声明的变量是静态的,即它决不会消失或重新被初始化。因此一个任务调用能够修改被其他任务调用读取的局部变量的值。
下面是调用任务 R e v e r s e _ B i t s的实例,该任务定义已在前面章节中给出,
/ /寄存器说明部分:
r e g [M A X B I T S-1:0] R e g _ X,N e w _ R e g;
R e v e r s e _ B i t s(R e g _ X,N e w _ R e g); //任务调用。
R e g _ X的值作为输入值传递,即传递给 D i n。任务的输出 D o u t返回到 N e w _ R e g。注意因为任务能够包含定时控制,任务可在被调用后再经过一定时延才返回值。
因为任务调用语句是过程性语句,所以任务调用中的输出和输入输出参数必须是寄存器类型的。在上面的例子中,N e w _ R e g必须被声明为寄存器类型。
下面的例子不通过参数表向任务调用传入变量。尽管引用全局变量被认为是不良的编程风格,它有时却非常有用。
m o d u l e G l o b a l _ V a r;
reg [0:7] R a m Q [ 0,6 3 ] ;
i n t e g e r I n d e x;
r e g C h e c k B i t;
t a s k G e t P a r i t y;
i n p u t A d d r e s s;
o u t p u t P a r i t y B i t;
92 Verilog HDL 硬件描述语言 下载
P a r i t y B i t = ^R a m Q[A d d r e s s] ;
e n d t a s k
i n i t i a l
f o r (I n d e x = 0; I n d e x <= 63; I n d e x = I n d e x+ 1 )b e g i n
G e t P a r i t y(I n d e x,C h e c k B i t) ;
$d i s p l a y("Parity bit of memory word %d is %b.",
Index,CheckBit) ;
e n d
e n d m o d u l e
存储器 R a m Q的地址被作为参数传递,而存储器本身在任务内直接引用。
任务可以带有时序控制,或等待特定事件的发生。但是,输出参数的值直到任务退出时才传递给调用参数。例如:
m o d u l e T a s k W a i t;
r e g N o C l o c k;
t a s k G e n e r a t e W a v e f o r m;
o u t p u t C l o c k Q;
b e g i n
C l o c k Q = 1;
#2 C l o c k Q = 0;
#2 C l o c k Q = 1;
#2 C l o c k Q = 0;
e n d
e n d t a s k
i n i t i a l
G e n a r a t e W a v e f o r m (N o C l o c k) ;
e n d m o d u l e
任务 G e n e r a t e Wa v e f o r m对 C l o c k Q的赋值不出现在 N o C l o c k上,即没有波形出现在 N o C l o c k
上;只有对 C l o c k Q的最终赋值 0在任务返回后出现在 N o C l o c k上。为避免这一情形出现,最好将 C l o c k Q声明为全局寄存器类型,即在任务之外声明它。
10.2 函数函数,如同任务一样,也可以在模块不同位置执行共同代码。函数与任务的不同之处是函数只能返回一个值,它不能包含任何时延或时序控制(必须立即执行),并且它不能调用其它的任务。此外,函数必须带有至少一个输入,在函数中允许没有输出或输入输出说明。函数可以调用其它的函数。
10.2.1 函数说明部分函数说明部分可以在模块说明中的任何位置出现,函数的输入是由输入说明指定,形式如下:
f u n c t i o n [r a n g e] f u n c t i o n _ i d;
i n p u t _ d e c l a r a t i o n
o t h e r _ d e c l a r a t i o n s
p r o c e d u r a l _ s t a t e m e n t
e n d f u n c t i o n
第 10章 其 他 论 题 93下载如果函数说明部分中没有指定函数取值范围,则其缺省的函数值为 1位二进制数。函数实例如下:
m o d u l e F u n c t i o n _ E x a m p l e
p a r a m e t e r MAXBITS = 8;
f u n c t i o n [M A X B I T S-1:0] R e v e r s e _ B i t s;
i n p u t [M A X B I T S-1:0] D i n;
i n t e g e r K;
b e g i n
f o r (K=0; K < M A X B I T S; K = K + 1)
R e v e r s e _ B i t s [M A X B I T S-K] = D i n [K] ;
e n d
e n d f u n c t i o n
.,,
e n d m o d u l e
函数名为 R e v e r s e _ B i t s。函数返回一个长度为 M A X B I T S的向量。函数有一个输入 D i n.K,
是局部整型变量。
函数定义在函数内部隐式地声明一个寄存器变量,该寄存器变量与函数同名并且取值范围相同。函数通过在函数定义中显式地对该寄存器赋值来返回函数值。对这一寄存器的赋值必须出现在函数定义中。下面是另一个函数的实例。
f u n c t i o n P a r i t y;
i n p u t [0:31] S e t;
r e g [0:3] R e t;
integer J;
b e g i n
R e t = 0;
f o r (J = 0;J <= 31; J = J + 1)
if (S e t[J] = = 1 )
R e t = R e t + 1;
P a r i t y = R e t % 2;
e n d
e n d f u n c t i o n
在该函数中,P a r i t y是函数的名称。因为没有指定长度,函数返回 1位二进制数。 R e t和 J
是局部寄存器变量。注意最后一个过程性赋值语句赋值给寄存器,该寄存器从函数返回值
(与函数同名的寄存器在函数中被隐式地声明) 。
10.2.2 函数调用函数调用是表达式的一部分。形式如下:
f u n c _ i d(e x p r 1,e x p r 2,.,,,e x p r N)
以下是函数调用的例子:
r e g [M A X B I T S-1:0] N e w _ R e g,R e g _ X; //寄存器说明。
N e w _ R e g = R e v e r s e _ B i t s(R e g _ X); //函数调用在右侧表达式内。
与任务相似,函数定义中声明的所有局部寄存器都是静态的,即函数中的局部寄存器在
94 Verilog HDL 硬件描述语言 下载函数的多个调用之间保持它们的值。
10.3 系统任务和系统函数
Verilog HDL提供了内置的系统任务和系统函数,即在语言中预定义的任务和函数。它们分为以下几类:
1) 显示任务( display task)
2) 文件输入 /输出任务 ( File I/O task)
3) 时间标度任务 (timescale task)
4) 模拟控制任务 (simulation control task)
5) 时序验证任务 (timing check task)
6) PLA建模任务 ( PLA modeling task)
7) 随机建模任务 ( stochastic modeling task)
8) 实数变换函数 (conversion functions for real)
9) 概率分布函数 (probabilistic distribution function)
P L A建模任务和随机建模任务不在本书的讨论范围内。
10.3.1 显示任务显示系统任务用于信息显示和输出。这些系统任务进一步分为:
显示和写入任务
探测监控任务
连续监控任务
1,显示和写入任务语法如下:
t a s k _ n a m e (f o r m a t _ s p e c i f i c a t i o n 1,a r g u m e n t _ l i s t 1,
f o r m a t _ s p e c i f i c a t i o n 2,a r g u m e n t _ l i s t 2,
.,,,
f o r m a t _ s p e c i f i c a t i o n N,a r g u m e n t _ l i s t N) ;
t a s k _ n a m e是如下编译指令的一种:
$display $displayb $displayh $d i s p l a y o
$write $writeb $writeh $w r i t e o
显示任务将特定信息输出到标准输出设备,并且带有行结束字符;而写入任务输出特定信息时不带有行结束符。下列代码序列能够用于格式定义:
%h 或 %H,十六进制
%d 或 %D,十进制
%o 或 %O,八进制
%b 或 %B,二进制
%c 或 %C,ASCII字符
%v 或 %V,线网信号长度
%m 或 %M,层次名
%s 或 %S,字符串
%t 或 %T,当前时间格式如果没有特定的参数格式说明,缺省值如下:
第 10章 其 他 论 题 95下载
$ d i s p l a y与 $ w r i t e,十进制数
$ d i s p l a y b与 $ w r i t e b,二进制数
$ d i s p l a y o与 $ w r i t e o,八进制数
$ d i s p l a y h与 $ w r i t e h,十六进制数可以用如下代码序列输出特殊字符:
\n 换行
\t 制表符
\\ 字符 \
\" 字符”
\OOO 值为八进制值 O O O的字符
%% 字符 %
例如:
$d i s p l a y("Simulation time is %t",$t i m e) ;
$d i s p l a y( $t i m e,":R=%b,Q=%b,QB=%b",R,S,Q,QB);
/ /因为没有指定格式,时间按十进制显示。
$w r i t e("Simulation time is:);
$w r i t e( " % t \ n ",$t i m e) ;
上述语句输出 $ t i m e,R,S,Q和 Q B等值的执行结果如下:
Simulation time is 10
10:R=1,S=0,Q=0,QB=1
Simulation time is 10
2,探测任务探测任务有:
$s t r o b e $s t r o b e b $s t r o b e h $s t r o b e o
这些系统任务在指定时间显示模拟数据,但这种任务的执行是在该特定时间步结束时才显示模拟数据。,时间步结束”意味着对于指定时间步内的所有事件都已经处理了。
a l w a y s
@ (p o s e d g e R s t )
$s t r o b e("the flip-flop value is %b at time %t",Q,$t i m e) ;
当 R s t有一个上升沿时,$s t ro b e任务输出 Q的值和当前模拟时间。下面是 Q和 $t i m e的一些值的输出。这些值在每次 R s t的上升沿时被输出。
The flip-flop value is 1 at time 17
The flip-flop value is 0 at time 24
The flip-flop value is 1 at time 26
其格式定义与显示和写入任务相同。
探测任务与显示任务的不同之处在于:显示任务在遇到语句时执行,而探测任务的执行要推迟到时间步结束时进行。下面的例子有助于进一步区分这两种不同任务。
i n t e g e r C o o l;
i n i t i a l
b e g i n
Cool = 1;
$d i s p l a y("After first assignment,Cool has value %d",C o o l) ;
$s t r o b e("When strobe is executed,Cool has value %d",C o o l) ;
C o o l = 2;
$d i s p l a y("After second assignment,Cool has value %d",C o o l) ;
e n d
96 Verilog HDL 硬件描述语言 下载产生的输出为:
After first assignment,Cool has value 1
When strobe is executed,Cool has value 2
After second assignment,Cool has value 2
第一个 $d i s p l a y任务输出 C o o l的值 1( C o o l的第一个赋值) 。第二个 $d i s p l a y任务输出
C o o l的值 2( C o o l的第二个赋值) 。 $s t ro b e任务输出 C o o l的值 2,这个值保持到时间步结束。
3,监控任务监控任务有:
$m o n i t o r $m o n i t o r b $m o n i t o r h $m o n i t o r o
这些任务连续监控指定的参数。只要参数表中的参数值发生变化,整个参数表就在时间步结束时显示。例如:
i n i t i a l
$m o n i t o r ("At %t,D = %d,Clk = %d"),
$t i m e,D,C l k,"and Q is %b",Q);
当监控任务被执行时,对信号 D,C l k和 Q的值进行监控。若这些值发生任何变化,则显示整个参数表的值。下面是 D,C l k和 Q发生某些变化时的输出样本。
监控任务的格式定义与显示任务相同。在任意时刻对于特定的变量只有一个监控任务可以被激活。
可以用如下两个系统任务打开和关闭监控。
$m o n i t o r o f f; //禁止所有监控任务。
$m o n i t o r o n; //使能所有监控任务。
这些提供了控制输出值变化的机制。 $m o n i t o ro ff任务关闭了所有的监控任务,因此不再显示监控更多的信息。 $m o n i t o ro n任务用于使能所有的监控任务。
10.3.2 文件输入 /输出任务
1,文件的打开和关闭系统函数 $f o p e n用于打开一个文件。
i n t e g e r f i l e _ p o i n t e r = $ f o p e n(f i l e _ n a m e);
/ /系统函数 $f o p e n返回一个关于文件的整数(指针) 。
而下面的系统任务可用于关闭一个文件:
$f c l o s e(f i l e _ p o i n t e r);
这是一个关于它的用法的例子。
i n t e g e r T q _ F i l e;
i n i t i a l
第 10章 其 他 论 题 97下载
b e g i n
T q _ F i l e = $ f o p e n("? / j b / d i v,t q ") ;
.,,
$f c l o s e(T q _ F i l e) ;
e n d
2,输出到文件显示、写入、探测和监控系统任务都有一个用于向文件输出的相应副本,该副本可用于将信息写入文件。这些系统任务如下:
$f d i s p l a y $f d i s p l a y b $f d i s p l a y h $f d i s p l a y o
$f w r i t e $f w r i t e b $f w r i t e h $f w r i t e o
$f s t r o b e $f s t r o b e b $f s t r o b e h $f s t r o b e o
$f m o n i t o r $f m o n i t o r b $f m o n i t o r h $f m o n i t o r o
所有这些任务的第一个参数是文件指针,其余的所有参数是带有参数表的格式定义序列。
下面的实例将作进一步解释说明。
i n t e g e r V e c _ F i l e;
i n i t i a l
b e g i n
Vec_File = $fopen(" d i v,v e c ") ;
.,,
$f d i s p l a y(V e c _ F i l e,"The simulation time %t",$time);
/ /第一个参数 V e c _ F i l e是文件指针。
$f c l o s e(V e c _ f i l e) ;
e n d
等到 $f d i s p l a y任务执行时,文件,d i v,v e c”中出现下列语句:
The simulation time is 0
3,从文件中读取数据有两个系统任务能够用于从文件中读取数据,这些任务从文本文件中读取数据并将数据加载到存储器。它们是:
$readmemb $readmemh
文本文件包含空白空间、注释和二进制(对于 $re a d m e m b)或十六进制(对于
$re a d m e m h)数字。每个数字由空白空间隔离。当执行系统任务时,每个读取的数字被指派给存储器内的一个地址。开始地址对应于存储器最左边的索引。
r e g [0:3] Mem_A [0:63];
i n i t i a l
$r e a d m e m b( " o n e s _ a n d _ z e r o,v e c ",M e m _ A ) ;
/ /读入的每个数字都被指派给从 0开始到 6 3的存储器单元。
显式的地址可以在系统任务调用中可选地指定,例如:
$r e a d m e m b( " r x,v e x ",M e m _ A,1 5,3 0 ) ;
/ /从文件,r x,v e c”中读取的第一个数字被存储在地址 1 5中,下一个存储在地址
/ / 1 6,并以此类推直到地址 3 0。
也可以在文本文件中显式地给出地址。形式如下:
@ a d d r e s s _ i n _ h e x a d e c i m a l
在这种情况下,系统任务将数据读入指定地址。后续的数字从指定地址开始向后加载。
98 Verilog HDL 硬件描述语言 下载
10.3.3 时间标度任务系统任务
$p r i n t t i m e s c a l e
给出指定模块的时间单位和时间精度。若 $p r i n t t i m e s c a l e任务没有指定参数,则用于输出包含该任务调用的模块的时间单位和精度。如果指定到模块的层次路径名为参数,则系统任务输出指定模块的时间单位和精度。
$p r i n t t i m e s c a l e ;
$p r i n t t i m e s c a l e(h i e r _ p a t h _ t o _ m o d u l e) ;
下面是这些系统被调用时输出的样本。
Time scale of (C10) is 100ps/100ps
Time scale of (C10.INST) is lus/100ps
系统任务
$t i m e f o r m a t
指定 % t格式定义如何报告时间信息,该任务形式如下:
$t i m e f o r m a t(u n i t s _ n u m b e r,p r e c i s i o n,
s u f f i x,n u m e r i c _ f i e l d _ w i d t h) ;
其中 u n i t s _ n u m b e r为:
0,1 s
-1,100 ms
-2,10 ms
-3,1 ms
-4,100 us
-5,10 us
-6,1 us
-7,100 ns
-8,10 ns
-9,1 ns
-10,100 ps
-11,10 ps
-12,1 ps
-13,100 fs
-14,10 fs
-15,1 fs
系统任务调用
$t i m e f o r m a t(-4,3,"ps",5);
$d i s p l a y("Current simulation time is %t",$time);
将显示 $d i s p l a y任务中 % t说明符的值,如下:
Current simulation time is 0.051 ps
如果没有指定 $t i m e f o r m a t,% t按照源代码中所有时间标度的最小精度输出。
10.3.4 模拟控制任务系统任务
$f i n i s h;
使模拟器退出,并将控制返回到操作系统。
第 10章 其 他 论 题 99下载系统任务
$s t o p
使模拟被挂起。在这一阶段,交互命令可能被发送到模拟器。下面是该命令使用方法的例子。
i n i t i a l #500 $s t o p;
5 0 0个时间单位后,模拟停止。
10.3.5 定时校验任务系统任务:
$s e t u p(d a t a _ e v e n t,r e f e r e n c e _ e v e n t,l i m i t) ;
如果
(time_of_reference_event - time_of_data_event) < limit
则报告时序冲突( timing violation);
系统调用实例如下:
$s e t u p(D,p o s e d g e Ck,1,0);
系统任务:
$h o l d(r e f e r e n c e _ e v e n t,d a t a _ e v e n t,l i m i t) ;
如果
(time_of_data_event - time_of_reference_event) < limit,
则报数据保持时间时序冲突。
例如:
$h o l d(p o s e d g e C k,D,0,1) ;
系统任务 $s e t u p h o l d是 $s e t u p和 $h o l d任务的结合,
$s e t u p h o l d(r e f e r e n c e _ e v e n t,d a t a _ e v e n t,s e t u p _ l i m i t,h o l d _ l i m i t) ;
而系统任务:
$w i d t h(r e f e r e n c e _ e v e n t,l i m i t,t h r e s h o l d) ;
则检查信号的脉冲宽度限制,如果
threshold < (t i m e _ o f _ d a t a _ e v e n t - t i m e _ o f _ r e f e r e n c e _ e v e n t) < limit
则报告信号上出现脉冲宽度不够宽的时序错误。
数据事件来源于基准事件:它是带有相反边沿的基准事件,例如:
$w i d t h(n e g e d g e C k,0,0,0 ) ;
系统任务:
$p e r i o d(r e f e r e n c e _ e v e n t,l i m i t)
检查信号的周期,若
( time_of_data_event - time_of_reference_event) < limit
则报告时序错误。
基准事件必须是边沿触发事件。数据事件来源于基准事件:它是带有相同边沿的基准事件。
系统任务:
$s k e w(r e f e r e n c e _ e v e n t,d a t a _ e v e n t,l i m i t)
检查信号之间(尤其是成组的时钟控制信号之间)的偏斜( s k e w)是否满足要求,若
time_of_data_event - time_of_reference_event > limit
100 Verilog HDL 硬件描述语言 下载则报告信号之间出现时序偏斜太大的错误。如果 d a t a _ e v e n t的时间等于 r e f e r e n c e _ e v e n t的时间,
则不报出错。
系统任务,
$r e c o v e r y(r e f e r e n c e _ e v e n t,d a t a _ e v e n t,l i m i t) ;
主要检查时序状态元件(触发器、锁存器,R A M和 R O M等)的时钟信号与相应的置 /复位信号之间的时序约束关系,若
( time_of_data_event - time_of_reference_event) < limit
则报告时序冲突。该系统任务的基准事件必须是边沿触发事件。该系统任务在执行定时校检前记录新基准事件时间;因此,如果数据事件和基准事件在相同的模拟时间同时发生,就报告时序冲突错误。
系统任务:
$n o c h a n g e(r e f e r e n c e _ e v e n t,d a t a _ e v e n t,s t a r t _ e d g e _ o f f s e t,
e n d _ e d g e _ o f f s e t) ;
如果在指定的基准事件区间发生数据变化,就报告时序冲突错误。基准事件必须是边沿触发事件。例如:
$n o c h a n g e(n e g e d g e C l e a r,P e r s e t,0,0 ) ;
如果在 C l e a r为低时 P re s e t发生变化,将报告时序冲突错误。
上述每个系统任务均可以带有一个可选参数 n o t i f i e r。当发生时序冲突时,系统任务根据下列 c a s e语句改变自身的值来更新参数 n o t i f i e r。
c a s e (n o t i f i e r)
'bx,notifier= 'b0;
'b0,notifier= 'b1;
'b1,notifier = 'b0;
'bz,notifier= 'bz;
e n d
n o t i f i e r参数可提供关于时序冲突或传播 x到输出的时序冲突。使用参数 n o t i f i e r的例子如下:
r e g N o t i f y D i n ;
.,,
$s e t u p h o l d (n e g e d g e C l o c k,D i n,t S E T U P,t H O L D,N o t i f y D i n) ;
在这一实例中,N o t i f y D i n是参数 n o t i f i e r。如果时序冲突发生,寄存参数 N o t i f y D i n根据前面对参数 n o t i f i e r描述的 c a s e语句改变其值。
10.3.6 模拟时间函数下列系统函数返回模拟时间。
$time:返回 6 4位的整型模拟时间给调用它的模块。
$stime:返回 3 2位的时间。
$realtime:向调用它的模块返回实型模拟时间。
例如
` t i m e s c a l e 1 0 n s / 1 n s
m o d u l e T B ;
.,,
i n i t i a l
第 10章 其 他 论 题 101下载
$ m o n i t o r ("Put_A=%d Put_B=%d",Put_A,Put_B,
"Get_O=%d",Get_O,"at time %t",$time) ;
e n d m o d u l e
该例产生的输出如下:
Put_A=0 Put_B=0 Get_O=0 at time 0
Put_A=0 Put_B=1 Get_O=0 at time 5
Put_A=0 Put_B=0 Get_O=0 at time 16
$t i m e按模块 T B的时间单位比例返回值,并且被四舍五入。注意 $t i m e f o r m a t描述了时间值如何被输出。下面是另一例子及其输出。
i n i t i a l
$m o n i t o r ( "Put_A=%d Put_B=%d",Put_A,Put_B,
"Get_O=%d",Get_O,"at time %t",$realtime) ;
Put_A=0 Put_B=1 Get_O=0 at time 5.2
Put_A=0 Put_B=0 Get_O=0 at time 15.6
10.3.7 变换函数下列系统函数是数字类型变换的功能函数:
$rt o i(re a l _ v a l u e):通过截断小数值将实数变换为整数。
$i t o r(i n t e g e r _ v a l u e):将整数变换为实数。
$re a l t o b i t s(re a l _ v a l u e):将实数变换为 6 4位的实数向量表示法(实数的 IEEE 745表示法)
$b i t s t o re a l(b i t _ v a l u e):将位模式变换为实数(与 $re a l t o b i t s相反)
10.3.8 概率分布函数函数:
$r a n d o m [ (s e e d) ]
根据种子变量( s e e d)的取值按 3 2位的有符号整数形式返回一个随机数。种子变量(必须是寄存器、整数或时间寄存器类型)控制函数的返回值,即不同的种子将产生不同的随机数。如果没有指定种子,每次 $r a n d o m函数被调用时根据缺省种子产生随机数。
例如,
i n t e g e r Seed,Rnum;
w i r e C l k ;
i n i t i a l S e e d = 12;
a l w a y s
@ (Clk) Rnum= $random (S e e d) ;
在 C l k的每个边沿,$r a n d o m被调用并返回一个 3 2位有符号整型随机数。
如果数字在取值范围内,下述模运算符可产生- 1 0? + 1 0之间的数字。
Rnum = $r a n d o m(S e e d) % 11;
下面是没有显式指定种子的例子。
R n u m = $r a n d o m / 2; //种子变量是可选的。
注意数字产生的顺序是伪随机排序的,即对于一个初始种子值产生相同的数字序列。
表达式:
102 Verilog HDL 硬件描述语言 下载
{r a n d o m} % 11
产生0? 1 0之间的一个随机数。并置操作符( { })将 $r a n d o m函数返回的有符号整数变换为无符号数。
下列函数根据在函数名中指定的概率函数产生伪随机数。
$d i s t _ u n i f o r m ( s e e d,s t a r t,e n d)
$d i s t _ n o r m a l ( s e e d,m e a n,s t a n d a r d _ d e v i a t i o n,u p p e r)
$d i s t _ e x p o n e n t i a l ( s e e d,m e a n)
$d u s t _ p o i s s o n ( s e e d,m e a n)
$d i s t _ c h i _ s q u a r e ( s e e d,d e g r e e _ o f _ f r e e d o m)
$d i s t _ t ( s e e d,d e g r e e _ o f _ f r e e d o m)
$d i s t _ e r l a n d ( s e e d,k _ s t a g e,m e a n)
这些函数的所有参数都必须是整数。
10.4 禁止语句禁止语句是过程性语句(因此它只能出现在 a l w a y s或 i n i t i a l语句块内) 。禁止语句能够在任务或程序块没有执行完它的所有语句前终止其执行。它能够用于对硬件中断和全局复位的建模。其形式如下:
d i s a b l e t a s k _ i d ;
d i s a b l e b l o c k _ i d ;
在禁止语句执行后,继续执行任务调用或被禁止的程序块的下一条语句。
b e g i n,B L K _ A
/ /语句 1。
/ /语句 2。
d i s a b l e B L K _ A;
/ /语句 3。
/ /语句 4。
e n d
/ /语句 5。
语句 3和语句 4从未被执行。在禁止语句被执行后,执行语句 5。又如:
t a s k B i t _ T a s k;
begin
/ /语句 6。
d i s a b l e B i t _ T a s k;
/ /语句 7。
e n d
e n d t a s k
/ /语句 8。
Bit_Task; //任务调用
/ /语句 9。
第 10章 其 他 论 题 103下载当禁止语句被执行时,任务被放弃,即语句 7永远不会被执行。紧跟在任务调用后面继续执行的语句,在此例中是语句 9。
建议最好在任务定义中不要使用 d i s a b l e禁止语句,尤其是当任务具有一定的返回值时更是如此。这是因为当任务被禁止时,Ve r i l o g语言给出的输出和输入参数值是不确定的。如果必须在任务中这样做,一种比较稳妥的方法是:如果有,就在任务中禁止顺序程序块,例如,
t a s k E x a m p l e ;
o u t p u t [ 0,3 ] C o u n t;
b e g i n,L O C A L _ B L K
/ /语句 1 0。
Count = 10;
d i s a b l e L O C A L _ B L K;
/ /语句 1 1。
e n d
e n d t a s k
当禁止语句开始执行时,禁止语句促使顺序程序块 L O C A L _ B L K退出。由于这是任务中的唯一语句,因此任务退出,并且 C o u n t的值为 1 0。如果禁止语句被替换为:
d i s a b l e E x a m p l e;
那么在禁止语句开始执行后,C o u n t的值不确定。
10.5 命名事件考虑下述两个 a l w a y s语句。
r e g Ready,Done;
/ /获取 a l w a y s语句的交互:
i n i t i a l
b e g i n
D o n e = 0;
#0 D o n e = 1;
e n d
a l w a y s
@ (D o n e) b e g i n
.,,
/ /完成处理这个 a l w a y s语句。
/ /触发下一个 a l w a y s语句。
/ /在 R e a d y信号上创建一个事件。
R e a d y = 0;
#0 R e a d y = 1;
e n d
a l w a y s
@ (R e a d y) b e g i n
.,,
/ /完成处理这个 a l w a y s语句。
/ /创建事件触发前面的 a l w a y s语句。
D o n e = 0;
# 0 D o n e = 1;
e n d
104 Verilog HDL 硬件描述语言 下载每个 a l w a y s语句中的两个赋值必须要确认在 R e a d y和 D o n e上创建一个事件。这表明 R e a d y
和 D o n e的目的是作为两个 a l w a y s语句间的握手信号。
Verilog HDL提供一种替代机制实现这一功能 — 使用命名事件。命名事件是 Verilog HDL
语言的另外一种数据类型 ( Ve r i l o g语言中的其它两类数据类型是寄存器类型和线网数据类型) 。
命名事件必须在使用前声明。声明形式如下:
e v e n t Ready,Done;
事件声明说明 R e a d y和 D o n e为两个命名事件。声明命名事件后,可以使用事件触发语句创建事件。形式如下:
- > R e a d y ;
- > D o n e ;
命名事件上的事件能够同变量上的事件一样被监控,即使用 @机制,例如:
@ ( D o n e) <动作语句>
所以只要 D o n e 上的事件触发语句被执行,一个事件就在 D o n e上发生,这使 <动作语句 >执行。
可以用命名事件重写两类 always 语句的简例:
e v e n t Ready,Done
i n i t i a l
- >D o n e;
a l w a y s
@( D o n e) b e g i n
.,,
/ /触发下一个 a l w a y s语句。
/ /在 R e a d y上创建一个事件。
- >R e a d y ;
end
a l w a y s
@ (R e a d y)b e g i n
.,,
/ /创建事件来触发前面的 a l w a y s语句。
- > D o n e;
e n d
也可以使用事件描述状态机。下面是一个异步状态机实例:
e v e n t State1,State2,State3;
/ /状态复位
i n i t i a l
b e g i n
/ /复位状态逻辑。
- > S t a t e 1;
e n d
a l w a y s
@ (S t a t e 1) b e g i n
// State1 逻辑。
->State2; / /在 State2 上创建事件。
第 10章 其 他 论 题 105下载
e n d
a l w a y s
@ (S t a t e 2) b e g i n
/ / S t a t e 2 逻辑。
->State3; //在 State3 上创建事件。
e n d
a l w a y s
@ (S t a t e 3) b e g i n
/ / S t a t e 3 逻辑。它可以有如下语句:
i f (I n p u t A)
->State2; //在 State2 上创建事件。
e l s e
->State1; //在 State1 上创建事件。
e n d
i n i t i a l语句描述复位逻辑。在 initial 语句执行结束时,触发第 2条 always 语句,该语句中最后一条语句的执行促使在 S t a t e 2上发生一个事件;这促使第 3条 always 语句执行,然后第 4条
always 语句执行。在最后一条 always 语句中,根据 Input A的值决定事件发生在 S t a t e 2还是
S t a t e 1上。
10.6 结构描述方式和行为描述方式的混合使用在前面的章节中,我们描述了硬件建模的几种不同方式。 Verilog HDL允许所有这些不同风格的建模在单一模块中结合使用。模块语法如下:
m o d u l e m o d u l e _ n a m e(p o r t _ l i s t) ;
D e c l a r a t i o n s,
Input,ouput and inout declarations.
Net declarations.
Reg declarations.
Parameter declarations.
Initial statement.
Gate instantiation statement.
Module instantiation statement.
UDP instantiation statement.
Always statement.
Continuous assignment.
e n d m o d u l e
下面的实例采用不同的风格进行硬件建模:
m o d u l e MUX2x1 (C t r l,A,B,E n a,Z)
/ /输入说明:
i n o u t C t r l,A,B,E n a;
/ /输出说明:
o u t p u t Z;
/ /线网说明:
w i r e M o t,N o t _ C t r l ;
/ /带赋值的线网说明:
w i r e Z = Ena == 1? Mot,'bz;
106 Verilog HDL 硬件描述语言 下载
/ /门实例语句:
n o t (N o t _ C t r l,C t r l) ;
o r (M o t,T a,T b) ;
/ /连续赋值
a s s i g n T a = A & Ctrl;
a s s i g n T b = B & Not_Ctrl;
e n d m o d u l e
模块包含内置逻辑门(结构化组件)和连续赋值(数据流方式)的混合描述形式。
10.7 层次路径名
Verilog HDl中的标识符具有一个唯一的层次路径名。层次路径名通过由句点(.)隔开的名字组成。新层次由以下定义:
1) 模块实例化
2) 任务定义
3) 函数定义
4) 命名程序块任何标识符的全称路径名由顶层模块(不被任何其它模块实例化的模块)开始。这一路径名可在描述的任何层次使用。实例如下。图 1 0 - 1显示了层次。
图 10-1 模块层次
m o d u l e T o p;
w i r e S b u s;
f u n c t i o n F u n c,.,
.,,
e n d f u n c t i o n
t a s k P r o c
.,,
r e g A r t;
b e g i n,B L A
i n t e g e r D o t;
第 10章 其 他 论 题 107下载程序块 BLA
integer Dot
程序块 BLB
reg Art,Cit
.,,
e n d
b e g i n,B L B
reg Art,Cit;
.,,
e n d
e n d t a s k
Chil C1(...) ; //一个模块实例。
e n d m o d u l e / /模块 T o p。
m o d u l e C h i l ;
r e g A r t ;
.,,
e n d m o d u l e
本例中的层次名为:
T o p,C 1,A r t
T o p,P r o c,A r t
T o p,P r o c,B L B,A r t
T o p,P r o c,B L A,D o t
T o p,P r o c,B L B,C i t
T o p,S b u s
这些层次名允许自由访问层次结构中任一层次的任一数据项。数据不仅可读,而且可以通过路径名更新任何层次中的数据项的值。
较低层模块能够通过使用模块实例名限定变量引用高层 (称为向上引用 )或低层 (称为向下引用 )模块。形式如下:
m o d u l e _ i n s t a n c e _ n a m e,v a r i a b l e _ n a m e
对于向下路径引用,模块实例必须与较低层模块在同一层。例如:
m o d u l e T o p;
w i r e S b u s ;
Chil Cl (.,,); //一个模块实例。
$d i s p l a y (C l,A r t); //向下引用。
e n d m o d u l e
m o d u l e C h i l;
r e g A r t;
.,,
e n d m o d u l e
10.8 共享任务和函数一种在不同模块间共享任务和函数的方法是在文本文件中编写共享任务和函数的定义,
然后使用 ` i n c l u d e编译指令在需要的模块中包含这些定义。假设我们在文件,s h a r e,h”中有如下函数和任务定义:
f u n c t i o n S i g n e d P l u s;
108 Verilog HDL 硬件描述语言 下载
.,,
e n d f u n c t i o n
function S i g n e d M i n u s;
.,,
e n d f u n c t i o n
t a s k P r e s e t C l e a r ;
.,,
e n d t a s k
下面是在模块中使用文件的方式:
module SignedAlu (A,B,Operation,Z) ;
i n p u t [0:3] A,B;
i n p u t O p e r a t i o n ;
o u t p u t [0:3] Z;
r e g [0:3] Z;
/ /包含共享函数的定义。
` i n c l u d e,s h a r e,h”
a l w a y s
@ (A o r B o r O p e r a t i o n)
i f (O p e r a t i o n)
Z = S i g n e d P l u s (A,B) ;
e l s e
Z = S i g n e d M i n u s (A,B) ;
e n d m o d u l e
注意因为文件,S h a r e,h”中任务和函数定义没有被模块说明限定,` i n c l a d e编译指令必须在模块说明内出现。
有一种可选的方法是在模块内定义共享任务和函数,然后用层次名在不同的模块中引用需要的任务或函数。下面的实例与前面相同,但是这一次任务和函数定义在模块说明内出现。
module S h a r e ;
f u n c t i o n S i g n e d P l u s ;
.,,
e n d f u n c t i o n
f u n c t i o n S i g n e d M i n u s;
.,,
e n d f u n c t i o n
t a s k P r e s e t C l e a r ;
.,,
e n d t a s k
e n d m o d u l e
下面是在其它模块中引用共享函数的方法。
m o d u l e S i g n e d A l u 2 (A,B,Operation,Z) ;
i n p u t [0:3] A,B;
i n p u t O p e r a t i o n;
o u t p u t [0:3] Z;
第 10章 其 他 论 题 109下载
r e g [0:3] Z;
a l w a y s
@ (A o r B o r O p e r a t i o n)
i f (O p e r a t i o n)
Z = S h a r e,S i g n e d P l u s (A,B) ;
e l s e
Z = S h a r e,S i g n e d M i n u s (A,B) ;
e n d m o d u l e
10.9 值变转储文件值变转储( V C D)文件包含设计中指定变量取值变化的信息。它的主要目的是为其它后处理工具提供信息。
下面的系统任务用于创建和将信息导入 V C D文件。
1) $d u m p f i l e:本系统任务指定转储文件名。
例如:
$d u m p f i l e (,u a r t,d u m p” ) ;
2) $dumpvars:本系统任务指定哪些变量值变化时转储进转储文件。
$d u m p v a r s ;
/ /无参数,它指定在设计中转储所有变量。
$d u m p v a r s (level,module_name) ;
/ /在指定模块和所有指定层次下面的模块中的转储变量。
$d u m p v a r s (1,UART) ;
/ /只转储模块 U A R T中的变量。
$d u m p v a r s (2,UART) ;
/ /转储 U A R T及其下一层模块中的所有变量。
$d u m p v a r s (0,UART) ;
/ /第 0层导致 U A R T模块及其下面层次中所有模块中的各个变量被转储。
$d u m p v a r s (0,P_State,N_State) ;
/ /转储关于 P _ S t a t e和 N _ S t a t e的变量信息。层次数与此例无关,但是必须给出 / /层次数。
$d u m p v a r s (3,Div.Clk,UART) ;
/ /层次数只作用于模块本身及其下面两个层次中的所有变量。在此例中,只作用于模块 U A R T,即 U A R T中所有变量及 U A R T下面两个层次中各模块的所有变量,同时转储变量 D i v,C l k上值的变化。
3) $d u m p o ff:本系统任务促使转储任务被挂起。
$d u m p o f f ;
4) $d u m p o n:本系统任务促使所有转储任务被挂起。语法如下:
$d u m p o n;
5) $d u m p a l l:本系统任务执行时转储所有当前指定的变量值。语法如下:
$d u m p a l l
6) $d u m p l i m i t:本系统任务为 V C D文件指定最大长度 (字节 )。转储在到达此界限时停止。
110 Verilog HDL 硬件描述语言 下载例如,
$d u m p l i m i t (1024); //VCD文件的最大值为 1 0 2 4字节。
7) $ d u m p f l u s h:本系统任务刷新操作系统 V C D文件缓冲区中的数据,将数据存到 V C D
文件中。执行此系统任务后,转储任务处于唤醒状态。
$d u m p f l u s h ;
10.9.1 举例下面是在 5? 1 2之间计数的可逆计数器的例子:
m o d u l e C o u n t U p D o w n (Clk,Count,Up_Down) ;
i n p u t Clk,Up_Down;
o u t p u t [0:3] C o u n t ;
r e g [0:3] C o u n t ;
i n i t i a l C o u n t = ‘ d 5 ;
a l w a y s
@ (p o s e d g e C l k) b e g i n
i f (U p _ D o w n)
b e g i n
C o u n t = C o u n t + 1;
if (C o u n t > 12)
C o u n t = 12;
e n d
e l s e
b e g i n
C o u n t = C o u n t - 1 ;
i f (C o u n t < 5)
Count = 5;
e n d
e n d
e n d m o d u l e
m o d u l e T e s t;
r e g Clock,UpDn;
w i r e [0:3] C n t _ O u t;
p a r a m e t e r O N _ D E L A Y = 1,O F F _ D E L A Y = 2;
CountUpDown C1(Clock,Cnt_Out,UpDn) ;
a l w a y s
b e g i n
C l o c k = 1;
# O N _ D E L A Y;
C l o c k = 0;
# O F F _ D E L A Y ;
e n d
i n i t i a l
第 10章 其 他 论 题 111下载
b e g i n
U p D n = 0;
#50 UpDn = 1;
#100 $d u m p f l u s h;
$s t o p; //停止模拟。
e n d
i n i t i a l
b e g i n
$d u m p f i l e (,c o u n t,d u m p” ) ;
$d u m p l i m i t ( 4 0 9 6 ) ;
$d u m p v a r s (0,T e s t ;)
$d u m p v a r s (0,Cl.Count,Cl.Clk,C1.Up_Down) ;
e n d
e n d m o d u l e
10.9.2 VCD文件格式
V C D文件是 A S C I I文件。 V C D文件包含如下信息:
文件头信息:提供日期、模拟器版本和时间标度单位。
节点信息:定义转储作用域和变量类型。
取值变化:实际取值随时间变化。记录绝对模拟时间。
V C D文件实例如图 1 0 - 2所示。
图 10-2 VCD文件
112 Verilog HDL 硬件描述语言接右栏下载
10.10 指定程序块迄今为止,我们讨论的时延,如门时延和线网时延,都是分布式时延。模块中关于路径的时延,称为模块路径时延,可以使用指定程序块来指定。通常,指定程序块有如下用途:
1) 指定源和目的之间的通路。
2) 为这些通路分配时延。
3) 对模块进行时序校验。
指定程序块出现在模块说明内。形式如下:
s p e c i f y
spec_param_declarations / /参数说明
path_declarations / /通路说明
s y s t e m _ t i m i n g _ c h e c k s / /系统时序校验说明
e n d s p e c i f y
s p e c p a r a m (或指定参数 )说明指定程序块内使用的参数。实例如下:
s p e c p a r a m t S E T U P = 20,tHOLD = 25;
在指定程序块内能够描述下述三类模块通路:
简单通路
边沿敏感通路
与状态有关的通路可以使用如下两种形式说明简单通路。
source *> destination
/ /指定一个完全连接:源参数上的每一位都与目的参数的所有位相连接。
source => destination
/ /指定一个并行连接:源参数上的每一位分别与目的参数的位一一连接。
以下是一些实例。
i n p u t C l o c k;
i n p u t [7:4] D;
o u t p u t [4:1] Q;
(C l o c k => Q) = 5;
/ /从输入 C l o c k到 Q的每位延迟为 5。
(D *> Q) = (tRISE,tFALL) ;
/* 包括下述通路:
D[7] 到 Q [ 4 ]
D[7] 到 Q [ 3 ]
D[7] 到 Q [ 2 ]
D[7] 到 Q [ 1 ]
D[6] 到 Q [ 4 ]
.,,
D[4] 到 Q [ 1 ]
* /
在边沿敏感通路中,通路描述与源的边沿相关。例如,
(p o s e d g e C l o c k => (Qb +,Da)) = (2:3:2);
/ *通路时延从 C l o c k的正沿到 Q b。数据通路从 Q b到 D a,当 D a传播到 Q b时,D a不翻转。 * /
第 10章 其 他 论 题 113下载与状态有关的通路在某些条件为真时指定通路时延。例如,
i f (C l e a r)
(D => Q) = (2.1,4.2);
/ /只在 C l e a r为高电平时,为指定通路时延。
下面是可在指定程序块内使用的时序验证系统任务。
$s e t u p $h o l d
$s e t h o l d $p e r i o d
$s k e w $r e c o v e r y
$w i d t h $n o c h a n g e
下面是指定程序块的实例。
s p e c i f y
/ /指定参数:
s p e c p a r a m t C L K _ Q = (5:4:6);
s p e c p a r a m t S E T U P = 2.8,t H O L D = 4.4;
/ /指定通路的路径时延:
(Clock *> Q) = tCLK_Q;
(Data *> Q) = 12;
(Clear,Preset *> Q) = (4,5);
/ /时序验证:
$s e t u p h o l d (n e g e d g e Clock,Data,tSETUP,tHOLD) ;
e n d s p e c i f y
沿着模块通路,只有长度大于通路时延的脉冲才能传播到输出。但是,还可以通过用称为 PAT H P U L S E$的专门指定程序块参数进行控制。除用于指定被舍弃的脉冲宽度范围外,还可用于指定促使通路结束处出现 x的脉冲宽度范围。参数说明的简单形式如下:
P A T H P U L S E $= (reject_limit,[,error_limit]) ;
如果脉冲宽度小于 re j e c t _ l i m i t,那么脉冲就不会传播到输出。如果脉冲宽度小于
e rro r _ l i m i t(如果未指定就与 re j e c t _ l i m i t相同 )。但是大于 re j e c t _ l i m i t,在通路的目标处产生 x。
也可以按如下形式使用:
P A T H P U L S E$ i n p u t _ t e r m i n a l $ o u t p u t _ t e r m i n a l
PAT H P U L S E $参数为特殊通路指定脉冲界限。
下面是指定程序块的实例。
s p e c i f y
specparam PATHPULSE$= (1,2);
// Reject limit = 1,Error limit = 2.
specparam PATHPULSE$Data$Q = 6;
// Reject limit = Error limit = 6,在从 D a t a 到 Q 的路径上。
e n d s p e c i f y
10.11 强度在 Verilog HDL中除了指定四个基本值0、1,x和 z外,还可以对这些值指定如驱动强度和电荷强度等属性。
10.11.1 驱动强度驱动强度可以在如下情况中指定:
114 Verilog HDL 硬件描述语言 下载
1) 在线网说明中带赋值的线网。
2) 原语门实例中的输出端口。
3) 在连续赋值语句中。
驱动强度定义有两个值:一个是线网被赋值为 1时的强度值;另一个是线网被赋值为 0时的强度值。形式如下:
(strength_for_1,strength_for_0)
值的顺序并不重要。对于值 1的赋值,只允许如下的信号驱动强度:
supply1
stro n g 1
pull1
weak1
highz1(禁止对门级原语使用 )
对于值 0的赋值,允许如下的信号驱动强度:
supply0
stro n g 0
pull0
weak0
highz0 (禁止对门级原语使用 )
缺省的信号驱动强度定义为 (s t ro n g 0,s t ro n g 1)。例如:
/ /线网的强度:
w i r e (pull1,weak0) # (2,4) L r k = Pol && Ord;
/ /信号的驱动强度定义仅适用于标量类型的信号,如,w i r e,w a n d,w o r,t r i,t r i a n d,t r i o r、
t r i r e g,/ /t r i 0和 t r i 1。
/ /门级原语输出端口的驱动强度定义:
nand (pull1,strong0) # (3:4:4) A l (Mout,MinA,MinB,MinC) ;
/ /信号驱动强度仅适用于定义下列门级原语的外部端口,a n d,o r,x o r,n a n d,n o r,x n o r,/ /b u f
b u f i f 0,b u f i f 1,n o t,n o t i f 0,n o t i f 1,p u l l d o w n和 p u l l u p。
/ /连续赋值语句中的强度定义:
a s s i g n (weak1,pull0) #2.56 Wrt = Ctrl;
线网的驱动强度可以在显示任务中用 % v格式定义输出。例如:
$d i s p l a y ( " Prq is %v",Prq) ;
结果为:
Prq is Wel
10.11.2 电荷强度三态寄存器线网也能有选择地规定其存储的电荷强度。三态寄存器线网存储的电荷强度与三态线网相关的电容大小有关。电荷强度分为三类:
小型
中型(如果没有特别强调,则为缺省值)
大型第 10章 其 他 论 题 115下载此外,三态寄存器线网存储的电荷衰退时间也可被指定。实例如下:
trireg (s m a l l ) # (5,4,20) T r o;
三态寄存器线网 Tro有一个小型电容。上升时延是 5个时间单位,下降时延是 4个时间单位,
并且放电时间 (当线网处于高阻状态时的电容器放电 )是 2 0个时间单位。
10.12 竞争状态如果在连续赋值或 always 语句中未使用时延,即是零时延时,会产生竞争状态。这是因为 Verilog HDL没有定义同时发生的事件的模拟顺序。
下面用一个简例解释说明使用非阻塞性赋值的零时延情况。
b e g i n
S t a r t <= 0;
S t a r t <= 1;
end
在时间步结束时,值 0和值 1都被调度为 S t a rt赋值。根据事件的排序 (由模拟器内部决定 ),
S t a rt上的结果可以是 0,也可以是 1。
下面的另一例子显示由于事件排序产生的竞争状态。
i n i t i a l
b e g i n
P a l = 0;
C t r l = 1;
#5 Pal = 1;
C t r l = 0;
end
a l w a y s
@ (C o t o r C t r l) b e g i n
$d i s p l a y ("The value of Cot at time",$t i m e,"is",C o t) ;
e n d
a s s i g n Cot = Pal;
在时刻 0,当 P a l和 C t r l在 i n i t i a l语句内被赋值时,连续赋值语句和 a l w a y s语句都已为执行做好准备。那么哪一个先执行呢? Verilog HDL语言没有定义这种顺序。如果连续赋值语句首先执行,C o t赋值为 0,反过来触发 a l w a y s语句。但是因为它已为执行做好准备,所以没有发生任何改变。 a l w a y s语句开始执行,C o t的值显示为 0。
如果我们假设首先执行 a l w a y s语句,C o t的当前值被输出 (连续赋值语句还没有执行 ),然后连续赋值语句开始执行,更新 C o t的值。
因此,在处理零时延赋值时要格外注意。下面是竞争状态的另一实例。
a l w a y s @ (p o s e d g e G l o b a l C l k)
RegB = RegA;
a l w a y s @ (p o s e d g e G l o b a l C l k)
RegC = RegB;
语言没有指出在 G l o b a l C l k上有正沿时,哪一条 always 语句首先执行。如果执行第1条
always 语句,R e g B将立即获得 R e g A的值;随后第 2条 a l w a y s语句执行,R e g C将获得 R e g B最新
116 Verilog HDL 硬件描述语言 下载的取值 (第1条 a l w a y s语句中的赋值 )。
如果首先执行第 2条 always 语句,R e g C将获得 R e g B的旧值 (R e g B还没有被赋值 ),随后
R e g B将被赋于 R e g A的值。所以根据首先执行哪一条 a l w a y s语句,R e g C取不同的值。因为过程性赋值立即发生,即没有任何时延,所以会产生一些问题。避免这种问题的一种方法是插入语句内时延。但最好是使用非阻塞性赋值语句。如:
a l w a y s @ (p o s e d g e G l o b a l C l k)
RegB < = RegA;
a l w a y s @ (p o s e d g e G l o b a l C l k)
RegC <= RegB;
当 a l w a y s语句通过变量通信时,对变量赋值时使用非阻塞性赋值可以避免产生竞争状态。
习题
1,函数可以调用任务吗?
2,任务能够带有时延吗?
3,函数能够带有零个输入参数吗?
4,系统任务 $d i s p l a y和 $w r i t e有何区别?
5,系统任务 $s t ro b e和 $m o n i t o r有何区别?
6,编写一个函数,执行 B C D (二进制码的十进制数 )到 7段显示码的转换。
7,编写一个函数,将只包含十进制数字的四字符字符串转换为整数值。例如,如果 M y B u f f e r
包含字串符,4 2 9 8”,将其转换为值为 4 2 9 8的整型数 My Int。
8,在 Verilog HDL中除使用 $re a d m e m b和 $re a d m e m h系统任务外,还有其它读文件的方法吗?
9,系统任务 $s t o p和 $f i n i s h的区别是什么?
10,编写一个从存储器指定的开始和结束位置转储内容的任务。
11,什么是标识符参数 n o t i f i e r?举例说明它的用法。
12,如何向存储器的位置 0到位置 1 5装载数据?从文本文件,r a m,t x t”中读取十六进制值。
13,编写一个任务,模拟上跳沿触发计数器异步清零的行为。
14,什么语句可用于从任务返回?
15,什么系统任务会对 $t i m e值如何输出产生影响?
16,什么机制可用于规定被忽略的脉冲的界限?
17,编写一个执行 1 0位二进制向量做算术移位的函数。
18,说明禁止语句如何用于模仿 C编程语言中,c o n t i n u e”和,b r e a k”语句的行为。
19,给定一个绝对的 U N I X文件路径名,假定形式为 / D 1 / D 2 / D 3 / f i l e A,编写如下函数:
-G e t D i re c t o ry N a m e:返回文件路径 (即 / D 1 / D 2 / D 3 )
-G e t B a s e N a m e:返回文件名 (即 f i l e A)
假定路径名中的最大字符数为 5 1 2个字符。
第 10章 其 他 论 题 117下载