下载第 8章 行 为 建 模在前几章中,我们已经介绍了使用门和 U D P实例语句的门级建模方式,以及用连续赋值语句的数据流建模方式。本章描述 Verilog HDL中的第三种建模方式,即行为建模方式。为充分使用 Verilog HDL,一个模型可以包含所有上述三种建模方式。
8.1 过程结构下述两种语句是为一个设计的行为建模的主要机制。
1) initial 语句
2) always语句一个模块中可以包含任意多个 i n i t i a l或 a l w a y s语句。这些语句相互并行执行,即这些语句的执行顺序与其在模块中的顺序无关。一个 i n i t i a l语句或 a l w a y s语句的执行产生一个单独的控制流,所有的 i n i t i a l和 a l w a y s语句在 0时刻开始并行执行。
8.1.1 initial 语句
initial 语句只执行一次。 initial 语句在模拟开始时执行,即在 0时刻开始执行。 initial 语句的语法如下:
i n i t i a l
[t i m i n g _ c o n t r o l] p r o c e d u r a l _ s t a t e m e n t
p r o c e d u r a l _ s t a t e m e n t是下列语句之一:
p r o c e d u r a l _ a s s i g n m e n t(blocking or non-blocking) / /阻塞或非阻塞性过程赋值语句 / /
p r o c e d u r a l _ c o n t i n u o u s _ a s s i g n m e n t
c o n d i t i o n a l _ s t a t e m e n t
c a s e _ s t a t e m e n t
l o o p _ s t a t e m e n t
w a i t _ s t a t e m e n t
d i s a b l e _ s t a t e m e n t
e v e n t _ t r i g g e r
s e q u e n t i a l _ b l o c k
p a r a l l e l _ b l o c k
task_enable (user or system)
顺序过程 ( b e g i n,,,e n d )最常使用在进程语句中。这里的时序控制可以是时延控制,即等待一个确定的时间;或事件控制,即等待确定的事件发生或某一特定的条件为真。 i n i t i a l语句的各个进程语句仅执行一次。注意 i n i t i a l语句在模拟的 0时刻开始执行。 i n i t i a l语句根据进程语句中出现的时间控制在以后的某个时间完成执行。
下面是 i n i t i a l语句实例。
r e g Y u r t;
.,,
i n i t i a l
Y u r t = 2;
上述 i n i t i a l语句中包含无时延控制的过程赋值语句。 i n i t i a l语句在 0时刻执行,促使 Yu rt在 0
时刻被赋值为 2。下例是一个带有时延控制的 i n i t i a l语句。
r e g C u r t;
.,,
i n i t i a l
#2 C u r t = 1;
寄存器变量 C u rt在时刻 2被赋值为 1。 i n i t i a l语句在 0时刻开始执行,在时刻 2完成执行。
下例为带有顺序过程的 i n i t i a l语句。
p a r a m e t e r S I Z E = 1024;
r e g [7:0] R A M [ 0,S I Z E- 1 ] ;
r e g R i b R e g;
i n i t i a l
b e g i n,S E Q _ B L K _ A
i n t e g e r I n d e x;
R i b R e g = 0;
f o r (I n d e x = 0; I n d e x < S I Z E; I n d e x = I n d e x + 1)
R A M [I n d e x] = 0;
e n d
顺序过程由关键词 b e g i n,,,e n d定界,它包含顺序执行的进程语句,与 C语言等高级编程语言相似。 S E Q _ B L K _ A是顺序过程的标记;如果过程中没有局部说明部分,不要求这一标记。
例如,如果对 I n d e x的说明部分在 i n i t i a l语句之外,可不需要标记。整数型变量 I n d e x已在过程中声明。并且,顺序过程包含 1个带循环语句的过程性赋值。这一 i n i t i a l语句在执行时将所有的内存初始化为 0。
下例是另一个带有顺序过程的 i n i t i a l语句。在此例中,顺序过程包含时延控制的过程性赋值语句。
/ /波形生成:
p a r a m e t e r A P P L Y _ D E L A Y = 5;
r e g[ 0,7 ]p o r t _ A;
.,,
i n i t i a l
b e g i n
P o r t _ A = ' h 2 0 ;
#APPLY_DELAY Port_A= 'hF2;
#APPLY_DELAY Port_A= 'h41;
#APPLY_DELAY Port_A= 'h0A;
e n d
执行时,P o rt _ A的值如图 8 - 1所示。
图 8-1 使用 initial语句产生的波形如上面举例所示,I n i t i a l语句主要用于初始化和波形生成。
60 Verilog HDL 硬件描述语言 下载
8.1.2 always语句与 i n i t i a l语句相反,a l w a y s语句重复执行。与 i n i t i a l语句类似,a l w a y s语句语法如下:
a l w a y s
[t i m i n g _ c o n t r o l] p r o c e d u r a l _ s t a t e m e n t
过程语句和时延控制(时序控制)的描述方式与上节相同。
例如:
always
C l k = ~ C l k;
/ /将无限循环。
此 a l w a y s语句有一个过程性赋值。因为 a l w a y s语句重复执行,并且在此例中没有时延控制,
过程语句将在 0时刻无限循环。因此,a l w a y s语句的执行必须带有某种时序控制,如下例的
a l w a y s语句,形式上与上面的实例相同,但带有时延控制。
always
#5 C l k = ~ C l k;
/ /产生时钟周期为 1 0的波形。
此 a l w a y s语句执行时产生周期为 1 0个时间单位的波形。
下例是由事件控制的顺序过程的 a l w a y s语句。
r e g [0:5] I n s t r R e g;
r e g [3:0] A c c u m;
w i r e E x e c u t e C y c l e;
a l w a y s
@ (E c e c u t e C y c l e)
b e g i n
c a s e(I n s t r R e g[ 0,1 ] )
2'b00,S t o r e (Accum,InstrReg[ 2,5 ] ) ;
2'b11,L o a d (Accum,InstrReg[ 2,5 ] ) ;
2'b01,J u m p (I n s t r R e g[ 2,5 ] ) ;
2 ' b 1 0,;
e n d c a s e
e n d
/ /S t o r e,L o a d和 J u m p是 在别处定义的用户自定义的任务。
顺序过程 ( b e g i n,,,e n d )中的语句按顺序执行。这个 a l w a y s语句意味着只要有事件发生,即只要发生变化,E x e c u t e C y c l e就执行顺序过程中的语句;顺序过程的执行意味着按顺序执行过程中的各个语句。
下例为带异步预置的负边沿触发的 D触发器的行为模型。
m o d u l e D F F(Clk,D,Set,Q,Qbar) ;
i n p u t Clk,D,Set;
o u t p u t Q,Qbar;
r e g Q,Qbar;
a l w a y s
w a i t (S e t == 1)
b e g i n
#3 Q = 1;
#2 Q b a r = 0;
第 8章 行 为 建 模 61下载
w a i t (S e t == 0);
e n d
a l w a y s
@ (n e g e d g e C l k)
b e g i n
if (S e t != 1)
b e g i n
#5 Q = D;
#1 Q b a r = ~ Q;
e n d
e n d
e n d m o d u l e
此模型中有 2条 a l w a y s语句。第一条 a l w a y s语句中顺序过程的执行由电平敏感事件控制。
第二条 a l w a y s语句中顺序过程的执行由边沿触发的事件控制。
8.1.3 两类语句在模块中的使用一个模块可以包含多条 a l w a y s语句和多条 i n i t i a l语句。每条语句启动一个单独的控制流。
各语句在 0时刻开始并行执行。
下例中含有 1条 i n i t i a l语句和 2条 a l w a y s语句。
m o d u l e T e s t X o r B e h a v i o r;
r e g Sa,Sb,Zeus;
i n i t i a l
b e g i n
S a = 0;
S b = 0;
#5 S b = 1;
#5 S a = 1;
#5 S b = 0;
e n d
a l w a y s
@ (Sa or Sb) Zeus = Sa ^ Sb;
a l w a y s
@ (Z e u s)
$d i s p l a y ( "At time %t,S a = %d,S b = %d,Z e u s = %b",
$t i m e,S a,S b,Z e u s) ;
e n d m o d u l e
模块中的 3条语句并行执行,其在模块中的书写次序并不重要。 i n i t i a l语句执行时促使顺序过程中的第一条语句执行,即 S a赋值为 0;下一条语句在 0时延后立即执行。 i n i t i a l语句中的第 3行表示“等待 5个时间单位” 。这样 S b在 5个时间单位后被赋值为 1,S a在另外 5个时间单位后被赋值为 0。执行顺序过程最后一条语句后,i n i t i a l语句被永远挂起。
第一条 a l w a y s语句等待 S a或 S b上的事件发生。只要有事件发生,就执行 a l w a y s语句内的语句,然后 a l w a y s语句重新等待发生在 S a或 S b上的事件。注意根据 i n i t i a l语句对 S a和 S b的赋值,
a l w a y s语句将在第 0,5,1 0和 1 5个时间单位时执行。
62 Verilog HDL 硬件描述语言 下载同样,只要有事件发生在 Z e u s上,就执行第 2条 a l w a y s语句。在这种情况下,系统任务 $ d i s p l a y被执行,然后 a l w a y s
语句重新等待发生在 Z e u s上的事件。 S a,S b和 Z e u s上产生的波形如图 8 - 2所示。下面是模块模拟运行产生的输出。
在时刻 5,Sa = 0,Sb = 1,Zeus = 1
在时刻 10,Sa = 1,Sb = 1,Zeus = 0
在时刻 15,Sa = 1,Sb = 0,Zeus = 1
8.2 时序控制时序控制与过程语句关联。有 2种时序控制形式:
1) 时延控制
2) 事件控制
8.2.1 时延控制时延控制形式如下:
#delay procedural_statement
实例如下;
#2 Tx = R x- 5 ;
时延控制定义为执行过程中首次遇到该语句与该语句的执行的时间间隔。时延控制表示在语句执行前的“等待时延” 。上面的例子中,过程赋值语句在碰到该语句后的 2个时间单位执行,然后执行赋值。
另一实例如下:
i n i t i a l
b e g i n
#3 W a v e = 'b0111;
#6 W a v e = 'b1100;
#7 W a v e = 'b0000;
e n d
i n i t i a l语句在 0时刻执行。首先,等待 3个时间单位执行第一个赋值,然后等待 6个时间单位,执行第 2个语句;再等待 7个时间单位,执行第 3个语句;然后永远挂起。
时延控制也可以用另一种形式定义:
#d e l a y;
这一语句促使在下一条语句执行前等待给定的时延。下面是这种用法的实例。
parameter O N _ D E L A Y = 3,O F F _ D E L A Y = 5;
a l w a y s
b e g i n
# O N _ D E L A Y; //等待 O N _ D E L A Y规定的时延。
R e f C l k = 0;
# O F F _ D E L A Y; //等待 O F F _ D E L A Y规定的时延。
R e f C l k = 1;
e n d
时延控制中的时延可以是任意表达式,即不必限定为某一常量,见下面的例子。
# Strobe
Compare = TX^ a s k ;
第 8章 行 为 建 模 63下载图 8-2 Sa,Sb和 Zeus上产生的波形
#( P E R I O D / 2)
Clock =? C l o c k
如果时延表达式的值为 0,则称之为显式零时延。
#0; //显式零时延。
显式零时延促发一个等待,等待所有其它在当前模拟时间被执行的事件执行完毕后,才将其唤醒;模拟时间不前进。
如果时延表达式的值为 x或 z,其与零时延等效。如果时延表达式计算结果为负值,那么其二进制的补码值被作为时延,这一点在使用时务请注意。
8.2.2 事件控制在事件控制中,a l w a y s的过程语句基于事件执行。有两种类型的事件控制方式:
1) 边沿触发事件控制
2) 电平敏感事件控制
1,边沿触发事件控制边沿触发事件控制如下,
@ event procedural_statement
如下例所示,
@ (p o s e d g e C l o c k)
C u r r _ S t a t e = N e x t _ S t a t e;
带有事件控制的进程或过程语句的执行,须等到指定事件发生。上例中,如果 C l o c k信号从低电平变为高电平(正沿),就执行赋值语句;否则进程被挂起,直到 C l o c k信号产生下一个正跳边沿。
下面是进一步的实例。
@ (n e g e d g e R e s e t) C o u n t = 0;
@C l a
Z o o = F o o;
在第一条语句中,赋值语句只在 R e s e t上的负沿执行。第二条语句中,当 C l a上有事件发生时,F o o的值被赋给 Z o o,即等待 C l a上发生事件;当 C l a的值发生变化时,F o o的值被赋给 Z o o。
也可使用如下形式,
@ e v e n t ;
该语句促发一个等待,直到指定的事件发生。下面是确定时钟在周期的 i n i t i a l语句中使用的一个例子。
t i m e RiseEdge,OnDelay;
i n i t i a l
b e g i n
/ /等待,直到在时钟上发生正边沿:
@ (p o s e d g e C l o c k A) ;
R i s e E d g e = $t i m e;
/ /等待,直到在时钟上发生负边沿:
@ (n e g e d g e C l o c k A) ;
O n D e l a y = $t i m e - R i s e E d g e;
$d i s p l a y ("The on-period of clock is %t.",D e l a y) ;
e n d
事件之间也能够相或以表明“如果有任何事件发生” 。下例将对此进行说明。
@ (p o s e d g e C l e a r or negedgeR e s e t)
64 Verilog HDL 硬件描述语言 下载
Q = 0;
@ (Ctrl_A o r C t r l _ B)
D b u s = 'b z;
注意关键字 o r并不意味着在 1个表达式中的逻辑或。
在 Verilog HDL中 p o s e d g e和 n e g e d g e是表示正沿和负沿的关键字。信号的负沿是下述转换的一种:
1 -> x
1 -> z
1 -> 0
x -> 0
z -> 0
正沿是下述转换的一种:
0 -> x
0 -> z
0 -> 1
x -> 1
z -> 1
2,电平敏感事件控制在电平敏感事件控制中,进程语句或进程中的过程语句一直延迟到条件变为真后才执行。
电平敏感事件控制以如下形式给出:
w a i t (C o n d i t i o n)
p r o c e d u r a l _ s t a t e m e n t
过程语句只有在条件为真时才执行,否则过程语句一直等待到条件为真。如果执行到该语句时条件已经为真,那么过程语句立即执行。在上面的表示形式中,过程语句是可选的。
例如:
w a i t (S u m > 22)
S u m = 0;
w a i t (D a t a R e a d y)
D a t a = B u s;
w a i t (P r e s e t) ;
在第一条语句中,只有当 S u m的值大于 2 2时,才对 S u m清 0。在第二条语句中,只有当
D a t a R e a d y为真,即 D a t a R e a d y值为 1时,将 B u s赋给 D a t a。最后一条语句表示延迟至 P re s e t变为真(值为 1)时,其后续语句方可继续执行。
8.3 语句块语句块提供将两条或更多条语句组合成语法结构上相当于一条语句的机制。在 Ve r i l o g
H D L中有两类语句块,即:
1) 顺序语句块 (b e g i n,,,e n d):语句块中的语句按给定次序顺序执行。
2) 并行语句块 (f o r k,,,j o i n):语句块中的语句并行执行。
语句块的标识符是可选的,如果有标识符,寄存器变量可在语句块内部声明。带标识符的语句块可被引用;例如,语句块可使用禁止语句来禁止执行。此外,语句块标识符提供唯一标识寄存器的一种方式。但是,要注意所有的寄存器均是静态的,即它们的值在整个模拟第 8章 行 为 建 模 65下载运行中不变。
8.3.1 顺序语句块顺序语句块中的语句按顺序方式执行。每条语句中的时延值与其前面的语句执行的模拟时间相关。一旦顺序语句块执行结束,跟随顺序语句块过程的下一条语句继续执行。顺序语句块的语法如下:
b e g i n
[,b l o c 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 ( s )
e n d
例如:
/ /产生波形,
b e g i n
#2 S t r e a m = 1;
#5 S t r e a m = 0;
#3 S t r e a m = 1;
#4 S t r e a m = 0;
#2 S t r e a m = 1;
#5 S t r e a m = 0;
e n d
假定顺序语句块在第 1 0个时间单位开始执行。两个时间单位后第 1条语句执行,即第 1 2个时间单位。此执行完成后,下 1条语句在第 1 7个时间单位执行 (延迟 5个时间单位 )。然后下 1条语句在第 2 0个时间单位执行,以此类推。该顺序语句块执行过程中产生的波形如图 8 - 3所示。
图 8-3 顺序语句块中的累积时延下面是顺序过程的另一实例。
b e g i n
P a t = M a s k | M a t;
@ (n e g e d g e C l k) ;
F F = & P a t
e n d
在该例中,第 1条语句首先执行,然后执行第 2条语句。当然,第 2条语句中的赋值只有在
C l k上出现负沿时才执行。下面是顺序过程的另一实例。
b e g i n,S E Q _ B L K
r e g[0:3] S a t ;
S a t = Mask & Data;
F F = ^S a t;
e n d
在这一实例中,顺序语句块带有标记 S E Q _ B L K,并且有一个局部寄存器说明。在执行时,
首先执行第1条语句,然后执行第 2条语句。
66 Verilog HDL 硬件描述语言 下载
8.3.2 并行语句块并行语句块带有定界符 f o r k和 j o i n(顺序语句块带有定界符 b e g i n和 e n d),并行语句块中的各语句并行执行。并行语句块内的各条语句指定的时延值都与语句块开始执行的时间相关。
当并行语句块中最后的动作执行完成时 (最后的动作并不一定是最后的语句 ),顺序语句块的语句继续执行。换一种说法就是并行语句块内的所有语句必须在控制转出语句块前完成执行。
并行语句块语法如下:
f o r k
[,b l o c 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(s) ;
j o i n
例如:
// 生成波形:
f o r k
#2 S t r e a m = 1;
#7 S t r e a m = 0;
#10 S t r e a m = 1;
#14 S t r e a m = 0;
#16 S t r e a m = 1;
#21 S t r e a m = 0;
j o i n
如果并行语句块在第 1 0个时间单位开始执行,所有的语句并行执行并且所有的时延都是相对于时刻 1 0的。例如,第 3个赋值在第 2 0个时间单位执行,并在第 2 6个时间单位执行第 5个赋值,以此类推。其产生的波形如图 8 - 4所示。
图 8-4 并行语句块中的相对时延下例混合使用了顺序语句块和并 行 语句块,以强调两者的不同之处。
a l w a y s
b e g i n:S E Q _ A
#4 D r y = 5; // S1
f o r k,P A R _ A / / S 2
#6 C u n = 7; //P1
b e g i n,S E Q _ B / / P 2
E X E = B o x; //S6
#5 J a p = E x e; //S7
e n d
#2 D o p = 3; //P3
#4 G o s = 2; //P4
#8 P a s = 4; //P5
j o i n
第 8章 行 为 建 模 67下载
#8 B a x = 1; //S3
#2 Z o o m = 52; //S4
#6 $s t o p; //S5
e n d
a l w a y s语句中包含顺序语句块 S E Q_A,并且顺序语句块内的所有语句 ( S 1,S 2,S 3,S 4和
S 5 )顺序执行。因为 a l w a y s语句在 0时刻执行,D ry在第 4个时间单位被赋值为 5,并且并行语句块 PA R _ A在第 4个时间单位开始执行。并行语句块中的所有语句 ( P 1,P 2,P 3,P 4和 P 5 )在第 4
个时间单位并行执行。这样 C u n在第 1 0个时间单位被赋值,D o p在第 6个时间单位被赋值,G o s
在第 8个时间单位被赋值,P a s在第 1 2个时间单位被赋值。顺序语句块 S E Q _ B在第 4个时间单位开始执行,并导致该顺序块中的语句 S 6,S 7依次被执行; J a p在时间单位 9被赋于新值。因为并行语句块 PA R _ A中的所有语句在第 1 2个时间单位完成执行,语句 S 3在第 1 2个时间单位被执行,在第 2 0个时间单位 B a x被赋值,然后语句 S 4执行,在第 2 2个时间单位 Z o o m被赋值,然后执行下一语句。最终在第 2 8个时间单位执行系统任务 $ s t o p。 a l w a y s语句执行时发生的事件如图 8 - 5所示。
图 8-5 顺序语句块和并行语句块混合使用时的时延
8.4 过程性赋值过程性赋值是在 i n i t i a l语句或 a l w a y s语句内的赋值,它只能对寄存器数据类型的变量赋值。
表达式的右端可以是任何表达式。例如:
r e g[1:4] E n a b l e,A,B;
.,,
#5 E n a b l e = ~A ^ ~B;
E n a b l e为寄存器。根据时延控制,赋值语句被延迟 5个时间单位执行。右端表达式被计算,
并赋值给 E n a b l e。
过程性赋值与其周围的语句顺序执行。 a l w a y s语句实例如下:
a l w a y s
@ (A o r B o r C o r D)
b e g i n:A O I
r e g T e m p 1,T e m p 2;
Temp1 = A & B;
Temp2 = C & D;
Temp1 = Temp1 | T e m p 2 ;
68 Verilog HDL 硬件描述语言 下载
Z = ~T e m p 1;
e n d
/ *可用一个语句代替上面的 4条语句,例如,
Z = ~((A & B) | (C & D) ) ;
但是,上例的目的主要用于解释说明顺序过程语句的顺序特性 * /
a l w a y s语句内的顺序过程在信号 A,B,C或 D发生变化时开始执行。 Te m p 1的赋值首先执行。然后执行第二个赋值。在以前赋值中计算的 Te m p 1和 Te m p 2的值在第三条赋值语句中使用。
最后一个赋值使用在第三条语句中计算的 Te m p 1的值。
过程性赋值分两类:
1) 阻塞性过程赋值
2) 非阻塞性过程赋值在讨论这两类过程性赋值前,先简要地说明语句内部时延的概念。
8.4.1 语句内部时延在赋值语句中表达式右端出现的时延是语句内部时延。通过语句内部时延表达式,右端的值在赋给左端目标前被延迟。例如:
D o n e = #5 'b1;
重要的是右端表达式在语句内部时延之前计算,随后进入时延等待,再对左端目标赋值。
下例说明了语句间和语句内部时延的不同。
D o n e = #5 'b1; //语句内部时延控制与
b e g i n
T e m p = 'b1;
#5 D o n e = T e m p; //语句间时延控制
e n d
相同。而语句
Q = @(p o s e d g e C l k ) D; //语句内事件控制与
b e g i n
T e m p = D;
@ (p o s e d g e C l k) //语句间事件控制
Q = T e m p;
e n d
相同。
除以上两种时序控制 (时延控制和事件控制 )可用于定义语句内部时延外,还有另一种重复事件控制的语句内部时延表示形式。形式如下:
r e p e a t(e x p r e s s) @ (e v e n t _ e x p r e s s i o n)
这种控制形式用于根据一定数量的 1个或多个事件来定义时延。例如,
D o n e = r e p e a t(2) @ (n e g e d g e C l k A) A _ R E G + B _ R E G
这一语句执行时先计算右端的值,即 A _ R e g + B _ R e g的值,然后等待时钟 C l k A上的两个负沿,再将右端值赋给 D o n e。这一重复事件控制实例的等价形式如下:
第 8章 行 为 建 模 69下载
b e g i n
T e m p = A_REG + B _ R E G
@ (n e g e d g e C l k A) ;
@ (n e g e d g e C l k A) ;
D o n e = T e m p;
e n d
这种形式的时延控制方式在给某些边或一定数量的边的同步赋值过程(语句)中非常有用。
8.4.2 阻塞性过程赋值赋值操作符是,=”的过程赋值是阻塞性过程赋值。例如,
R e g A = 52;
是阻塞性过程赋值。阻塞性过程赋值在其后所有语句执行前执行,即在下一语句执行前该赋值语句完成执行。如下所示:
a l w a y s
@ (A o r B o r C i n)
b e g i n,C A R R Y _ O U T
r e g T 1,T 2,T 3 ;
T 1 = A & B;
T 2 = B & C i n;
T 3 = A & C i n;
C o u t = T 1 | T 2 | T 3;
e n d
T 1赋值首先发生,计算 T 1;接着执行第二条语句,T 2被赋值;然后执行第三条语句,T 3
被赋值;依此类推。
下例是使用语句内部时延控制的阻塞性过程赋值语句。
i n i t i a l
b e g i n
C l r = #5 0;
C l r = #4 1;
C l r = #10 0;
e n d
第一条语句在 0时刻执行,C l r在 5个时间单位后被赋值;接着执行第二条语句,使 C l r在 4
个时间单位后被赋值为 1 (从 0时刻开始为第 9个时间单位 );然后执行第三条语句促使 C l r在 1 0个时间单位后被赋值为 0 (从 0时刻开始为第 1 9个时间单位 )。图 8 - 6显示 C l r上产生的波形。
图 8-6 带有语句内部时延控制的阻塞性过程赋值另一实例如下:
b e g i n
A r t = 0;
70 Verilog HDL 硬件描述语言 下载
A r t = 1;
e n d
在这种情况下,A rt被赋值为 1。这是因为第一个 A rt被赋值为 0,然后执行下一条语句促使
A rt在 0时延后被赋值为 1。因此对 A rt的 0赋值被丢弃。
8.4.3 非阻塞性过程赋值在非阻塞性过程赋值中,使用赋值符号,< =” 。例如:
b e g i n
L o a d <= 32;
R e g A <= L o a d;
R e g B <= S t o r e;
e n d
在非阻塞性过程赋值中,对目标的赋值是非阻塞的 (因为时延 ),但可预定在将来某个时间步发生 (根据时延;如果是 0时延,那么在当前时间步结束 )。当非阻塞性过程赋值被执行时,
计算右端表达式,右端值被赋于左端目标,并继续执行下一条语句。预定的最早输出将在当前时间步结束时,这种情况发生在赋值语句中没有时延时。在当前时间步结束或任意输出被调度时,即对左端目标赋值。
在上面的例子中,我们假设顺序语句块在时刻 1 0执行。第一条语句促使 L o a d在第 1 0个时间单位结束时被赋值为 3 2;然后执行第 2条语句,L o a d的值不变 (注意时间还没有前进,并且第 1个赋值还没有被赋新值 ),R e g A的赋值被预定为在第 1 0个时间步结束时。在所有的事件在第 1 0个时间单位发生后,完成对左端目标的所有预定赋值。
下面的例子更进一步解释这种赋值特征。
i n i t i a l
b e g i n
C l r <= #5 1;
C l r <= #4 0;
C l r <= #10 0;
e n d
第一条语句的执行使 C l r 在第 5个时间单位被赋于值 1;第二条语句的执行使 C l r在第 4个时间单位被赋值为 0 (从 0时刻开始的第 4个时间单位 );最终,第 3条语句的执行使 C l r在第 1 0个时间单位被赋值为 0 (从 0时刻开始的第 1 0个时间单位 )。
注意 3条语句都是在 0时刻执行的。此外,在这种情况下,非阻塞性赋值执行次序变得彼此不相关。
C l r上产生的波形如图 8 - 7所示。
下面是带有 0时延的例子。
i n i t i a l
b e g i n
C b n <= 0;
C b n <= 1;
e n d
在 i n i t i a l语句执行后,因为同时对同一寄存器变量有多个赋值,C b n的值变得不确定,即
Cbn = x。 Verilog HDL标准中既没有规定在这种情况下,何种事件被调度,也没有规定事件第 8章 行 为 建 模 71下载图 8-7 带有语句内部时延的非阻塞性过程赋值被取消的次序。结果是根据特定的 Ve r i l o g模拟器的事件调度算法,C b n将被赋值为 0或 1 。
下面是同时使用阻塞性和非阻塞性过程赋值的实例,注意它们的区别。
reg [0:2] Q _ S t a t e;
i n i t i a l
b e g i n
Q _ S t a t e = 3’ b 0 1 1 ;
Q _ S t a t e <= 3’ b 1 0 0 ;
$d i s p l a y (,Current value of Q_State is %b”,Q _ S t a t e) ;
#5; //等待一定的时延。
$d i s p l a y (,The delayed value of Q_State is %b”,Q _ S t a t e) ;
e n d
执行 i n i t i a l语句产生如下结果:
Current value of Q_State is 011
The delayed value of Q_State is 100
第一个阻塞性赋值使 Q _ S t a t e被赋值为 3'b 0 11。执行第二条赋值语句 (为非阻塞性赋值语句 )
促使 Q _ S t a t e在当前时间步 (第 0步 )结束时被赋值为 3'b 1 0 0。因此当第一个 $d i s p l a y任务被执行时,Q _ S t a t e还保持来自第一个赋值的值,即 3'b 0 11。当 # 5时延被执行后,促使被调度的
Q _ S t a t e赋值发生,Q _ S t a t e的值被更新。延迟 5个时间单位后,执行下一个 $d i s p l a y任务,此时显示 Q _ S t a t e的更新值。
8.4.4 连续赋值与过程赋值的比较连续赋值与过程赋值有什么不同之处? 表 8 - 1列举了它们的差异。
表 8-1 过程赋值与连续赋值间的差异过 程 赋 值 连 续 赋 值在 a l w a y s语句或 i n i t i a l语句内出现 在一个模块内出现执行与周围其它语句有关 与其它语句并行执行;在右端操作数的值发生变化时执行驱动寄存器 驱动线网使用,=”或,=”赋值符号 使用,=”赋值符号无 a s s i g n关键词 (在过程性连续赋值中 有 a s s i g n关键词除外,参见第 8章第 8节 )
下例进一步解释了这些差别。
m o d u l e P r o c e d u r a l;
r e g A,B,Z;
a l w a y s
@ (B) b e g i n
Z = A;
A = B;
e n d
e n d m o d u l e
72 Verilog HDL 硬件描述语言 下载在上述情况下,使用不同模拟器对其进行模拟所产生的模拟结果可能会有所不同。 — 译者注
m o d u l e C o n t i n u o u s
w i r e A,B,Z;
a s s i g n Z = A;
a s s i g n A = B;
e n d m o d u l e
假定 B在 10 ns时有一个事件。在过程性赋值模块中,两条过程语句被依序执行,A在 10 ns
时得到 B的新值。 Z没有得到 B的值,因为赋值给 Z发生在赋值给 A之前。在连续性赋值语句模块中,第二个连续赋值被触发,因为这里有一个关于 B的事件。这引起了关于 A的事件,A引发第一个连续赋值被执行,这相应引起 Z得到了 A的值。 Z的新值为 A而不是 B。然而,如果事件发生在 A上,过程性模块中的 a l w a y s语句不执行,因为 A不在那个 a l w a y s语句的实时控制事件清单中。然而连续赋值语句中的第一个连续赋值执行,并且 Z得到 A的新值。
8.5 if 语句
i f语句的语法如下:
i f(c o n d i t i o n _ 1)
p r o c e d u r a l _ s t a t e m e n t _ 1
{else if(c o n d i t i o n _ 2)
p r o c e d u r a l _ s t a t e m e n t _ 2}
{e l s e
p r o c e d u r a l _ s t a t e m e n t _ 3}
如果对 c o n d i t i o n _ 1 求值的结果为一个非零值,那么 p ro c e d u r a l _ s t a t e m e n t _ 1被执行,如果
condition_1 的值为 0,x或 z,那么 p ro c e d u r a l _ s t a t e m e n t _ 1不执行。
如果存在一个 e l s e分支,那么这个分支被执行。以下是一个例子。
i f(S u m < 60)
b e g i n
G r a d e = C;
T o t a l _ C = Total _c + 1;
e n d
else if(S u m < 75)
b e g i n
G r a d e = B;
T o t a l _ B = T o t a l _ B + 1;
e n d
e l s e
b e g i n
G r a d e = A;
T o t a l _ A = T o t a l _ A + 1;
e n d
注意条件表达式必须总是被括起来,如果使用 i f - i f - e l s e格式,那么可能会有二义性,
如下例所示:
i f(C l k)
i f(R e s e t)
Q = 0;
e l s e
Q = D;
第 8章 行 为 建 模 73下载问题是最后一个 e l s e属于哪一个 i f? 它是属于第一个 i f的条件 (C l k)还是属于第二个 i f
的条件 (R e s e t)? 这在 Verilog HDL中已通过将 e l s e与最近的没有 e l s e的 i f相关联来解决。在这个例子中,e l s e与内层 i f语句相关联。
以下是另一些 i f语句的例子。
i f(S u m < 100)
S u m = S u m + 10;
i f(N i c k e l _ I n)
D e p o s i t = 5;
e l s e i f (D i m e _ I n)
D e p o s i t = 10;
else if(Q u a r t e r _ I n)
D e p o s i t = 25;
e l s e
D e p o s i t = E R R O R;
i f(C t r l)
b e g i n
i f( ~C t r l 2)
M u x = 4'd2;
e l s e
M u x = 4'd1;
e n d
e l s e
b e g i n
i f( ~C t r l 2)
M u x = 4'd8;
e l s e
M u x = 4'd4;
e n d
8.6 case语句
c a s e语句是一个多路条件分支形式,其语法如下:
c a s e(c a s e _ e x p r)
c a s e _ i t e m _ e x p r{,c a s e _ i t e m _ e x p r},p r o c e d u r a l _ s t a t e m e n t
.,,
.,,
[d e f a u l t:p r o c e d u r a l _ s t a t e m e n t]
e n d c a s e
c a s e语句首先对条件表达式 c a s e _ e x p r求值,然后依次对各分支项求值并进行比较,第一个与条件表达式值相匹配的分支中的语句被执行。可以在 1个分支中定义多个分支项;这些值不需要互斥。缺省分支覆盖所有没有被分支表达式覆盖的其他分支。
分支表达式和各分支项表达式不必都是常量表达式。在 c a s e语句中,x和 z值作为文字值进行比较。 c a s e语句如下所示:
parameter
M O N = 0,T U E = 1,W E D = 2,
T H U = 3,F R I = 4,
SAT = 5,S U N = 6;
r e g [0:2] D a y;
74 Verilog HDL 硬件描述语言 下载
i n t e g e r P o c k e t _ M o n e y;
c a s e (D a y)
T U E,P o c k e t _ M o n e y = 6; //分支 1。
M O N,
W E D,P o c k e t _ M o n e y = 2; //分支 2。
F R I,
S A T,
S U N,P o c k e t _ M o n e y = 7; //分支 3。
d e f a u l t,P o c k e t _ M o n e y = 0; //分支 4。
e n d c a s e
如果 D a y的值为 M O N或 W E D,就选择分支 2。分支 3覆盖了值 F R I,S AT和 S U N,而分支 4
覆盖了余下的所有值,即 T H U和位向量 111。 c a s e语句的另一实例如下:
m o d u l e A L U (A,B,OpCode,Z) ;
i n p u t [3:0] A,B;
i n p u t [1:2] O p C o d e;
o u t p u t [7:0] Z;
r e g [7:0] Z;
p a r a m e t e r
A D D _ I N S T R = 2'b10,
S U B _ I N S T R = 2'b11,
M U L T _ I N S T R = 2'b01,
D I V _ I N S T R = 2'b00;
always
@ (A o r B o r O p C o d e)
c a s e (O p C o d e)
A D D _ I N S T R,Z = A + B;
S U B _ I N S T R,Z = A -B;
M U L T _ I N S T R,Z = A * B;
D I V _ I N S T R,Z = A / B;
e n d c a s e
e n d m o d u l e
如果 c a s e表达式和分支项表达式的长度不同会发生什么呢? 在这种情况下,在进行任何比较前所有的 c a s e表达式都统一为这些表达式的最长长度。下例说明了这种情况。
c a s e (3'b101 << 2)
3'b100,$d i s p l a y ( "First branch taken!");
4'b0100,$d i s p l a y ( "Second branch taken!");
5'b10100,$d i s p l a y ( "Third branch taken!");
d e f a u l t,$d i s p l a y ( "Default branch taken!");
e n d c a s e
产生:
Third branch taken!
因为第 3个分支项表达式长度为 5位,所有的分支项表达式和条件表达式长度统一为 5。当计算 3 ' b 1 0 1 < < 2时,结果为 5 ' b 1 0 1 0 0,并选择第 3个分支。
case语句中的无关位上节描述的 c a s e语句中,值 x和 z只从字面上解释,即作为 x和 z值。这里有 c a s e语句的其第 8章 行 为 建 模 75下载它两种形式,c a s e x和 c a s e z,这些形式对 x和 z值使用不同的解释。除关键字 c a s e x和 c a s e z以外,
语法与 c a s e语句完全一致。
在 c a s e z语句中,出现在 c a s e表达式和任意分支项表达式中的值 z被认为是无关值,即那个位被忽略 (不比较 )。
在 c a s e x语句中,值 x和 z都被认为是无关位。 c a s e z语句实例如下:
c a s e( M a s k )
4'b1,D b u s[4] = 0;
4'b01,D b u s[3] = 0;
4'b001?,D b u s[2] = 0;
4'b0001,D b u s[1] = 0;
e n d c a s e
字符可用来代替字符 z,表示无关位。 c a s e z语句表示如果 M a s k的第 1位是 1 (忽略其它位 ),
那么将 D b u s[ 4 ]赋值为 0;如果 M a s k的第 1位是 0,并且第 2位是 1 (忽略其它位 ),那么 D b u s [ 3 ]被赋值为 0,并依此类推。
8.7 循环语句
Verilog HDL中有四类循环语句,它们是:
1) forever循环
2) repeat循环
3) while循环
4) for 循环
8.7.1 forever 循环语句这一形式的循环语句语法如下:
f o r e v e r
p r o c e d u r a l _ s t a t e m e n t
此循环语句连续执行过程语句。因此为跳出这样的循环,中止语句可以与过程语句共同使用。同时,在过程语句中必须使用某种形式的时序控制,否则,f o r e v e r循环将在 0时延后永远循环下去。
这种形式的循环实例如下:
i n i t i a l
b e g i n
C l o c k = 0;
# 5 f o r e v e r
#10 C l o c k = ~C l o c k;
e n d
这一实例产生时钟波形;时钟首先初始化为 0,并一直保持到第 5个时间单位。此后每隔
1 0个时间单位,C l o c k反相一次。
8.7.2 repeat 循环语句
repeat 循环语句形式如下:
r e p e a t(l o o p _ c o u n t)
p r o c e d u r a l _ s t a t e m e n t
76 Verilog HDL 硬件描述语言 下载这种循环语句执行指定循环次数的过程语句。如果循环计数表达式的值不确定,即为 x或
z时,那么循环次数按 0处理。下面是一些具体实例。
r e p e a t (C o u n t)
S u m = S u m + 10;
r e p e a t (S h i f t B y)
P _ R e g = P _ R e g << 1;
r e p e a t循环语句与重复事件控制不同。例如,
r e p e a t(C o u n t) //repeat循环语句
@ (p o s e d g e C l k) S u m = S u m + 1;
上例表示计数的次数,等待 C l k的正边沿,并在 C l k正沿发生时,对 S u m加 1。但是,
Sum = r e p e a t(C o u n t) @ (p o s e d g e C l k) S u m + 1;
// 重复事件控制该例表示首先计算 Sum + 1,随后等待 C l k上正沿计数,最后为左端赋值。
下面的表达式意味着什么?
r e p e a t(N U M _ O F _ T I M E S) @ (n e g e d g e C l o c k Z) ;
它表示在执行跟随在 r e p e a t语句之后的语句之前,等待 ClockZ 的 N U M _ O F _ T I M E S个负沿。
8.7.3 while 循环语句
while 循环语句语法如下:
w h i l e(c o n d i t i o n)
p r o c e d u r a l _ s t a t e m e n t
此循环语句循环执行过程赋值语句直到指定的条件为假。如果表达式在开始时为假,那么过程语句便永远不会执行。如果条件表达式为 x或 z,它也同样按 0(假)处理。例如:
w h i l e (B Y > 0 )
b e g i n
A c c = A c c << 1;
B y = B y - 1;
e n d
8.7.4 for 循环语句
for 循环语句的形式如下:
f o r(i n i t i a l _ a s s i g n m e n t ; c o n d i t i o n ; s t e p _ a s s i g n m e n t)
p r o c e d u r a l _ s t a t e m e n t
一 个 f o r 循 环 语 句 按 照 指 定 的 次 数 重 复 执 行 过 程 赋 值 语 句 若 干 次 。 初 始 赋 值
i n i t i a l _ a s s i g n m e n t给出循环变量的初始值。 c o n d i t i o n条件表达式指定循环在什么情况下必须结束。只要条件为真,循环中的语句就执行;而 s t e p _ a s s i g n m e n t给出要修改的赋值,通常为增加或减少循环变量计数。
i n t e g e r K;
for (K=0 ; K < M A X _ R A N G E ; K = K + 1)
b e g i n
i f(A b u s[K] == 0)
A b u s[K] = 1;
第 8章 行 为 建 模 77下载
else if(A b u s[k] == 1)
A b u s[K] = 0;
e l s e
$d i s p l a y( "A b u s[K] is an x or a z");
end
8.8 过程性连续赋值过程性连续赋值是过程性赋值的一类,即它不能够在 a l w a y s语句或 i n i t i a l语句中出现。这种赋值语句能够替换其它所有对线网或寄存器的赋值。它允许赋值中的表达式被连续驱动到寄存器或线网当中。注意,这不是一个连续赋值,连续赋值发生在 i n i t i a l或 a l w a y s语句之外。
过程性连续赋值语句有两种类型:
1) 赋值和重新赋值过程语句:它们对寄存器进行赋值。
2) 强制和释放过程性赋值语句:虽然它们也可以用于对寄存器赋值,但主要用于对线网赋值。
赋值和强制语句在如下意义上是“连续”的:即当赋值或强制发生效用时,右端表达式中操作数的任何变化都会引起赋值语句重新执行。
过程性连续赋值的目标不能是寄存器部分选择或位选择。
8.8.1 赋值—重新赋值一个赋值过程语句包含所有对寄存器的过程性赋值,重新赋值过程语句中止对寄存器的连续赋值。寄存器中的值被保留到其被重新赋值为止。
m o d u l e D E F(D,C l r,C l k,Q) ;
i n p u t D,C l r,C l k;
o u t p u t Q;
r e g Q;
a l w a y s
@ (C l r) b e g i n
i f( !C l r)
a s s i g n Q = 0; // D对 Q无效。
e l s e
d e a s s i g n Q;
e n d
a l w a y s
@ (n e g e d g e C l k) Q = D;
e n d m o d u l e
如果 C l r为 0,a s s i g n赋值语句使 Q清 0,而不管时钟边沿的变化情形,即 C l k和 D对 Q无效。
如果 C l r变为 1,重新赋值语句被执行;这就使得强制赋值方式被取消,以后 C l k能够对 Q产生影响。
如果赋值应用于一个已经被赋值的寄存器,a s s i g n赋值在进行新的过程性连续赋值前取消了原来的赋值。实例如下:
r e g[3:0] P e s t;
.,,
78 Verilog HDL 硬件描述语言 下载
P e s t = 0;
.,,
a s s i g n P e s t = H t y ^ M t u;
.,,
assign P e s t = 2; //将对 P e s t重新赋值,然后赋值。
.,,
d e a s s i g n P e s t; //Pest连续地保持值为 2。
.,,
a s s i g n P e s t[2] = 1; /*错误:对寄存器的位选择不能够作为过程性连续赋值的目标 * /
第二个赋值语句在进行下一个赋值前促使第一个赋值被重新赋值。在重新分配执行后,
P e s t的值在另一个对寄存器的赋值前保持为 2。
赋值语句在如下意义上是连续的:即在第 1个赋值执行后,第 2个赋值开始执行前,H t y或
M t u上的任何变化将促使第 1个赋值语句被重新计算。
8.8.2 force与 release
f o r c e和 r e l e a s e过程语句与 a s s i g n和 d e a s s i g n非常相似,不同的是 f o r c e和 r e l e a s e过程语句不仅能够应用于线网,也能够应用于寄存器的赋值。
当 f o r c e语句应用于寄存器时,寄存器的当前值被 f o r c e语句的值覆盖;当 r e l e a s e语句应用于寄存器时,寄存器中的当前值保持不变,除非过程性连续赋值已经生效(在 f o r c e语句被执行时),在这种情况下,连续赋值为寄存器建立新值。
当用 f o r c e过程语句对线网进行赋值时,该赋值方式为线网替换所有驱动源,直到在那个线网上执行 r e l e a s e语句为止。
w i r e P r t;
.,,
o r #1 (P r t,S t d,D z x) ;
i n i t i a l
b e g i n
f o r c e P r t = Dzx & S t d;
#5; // 等待 5个时间单位。
release P r t;
e n d
执行 f o r c e语句使 P rt的值覆盖来自于或门原语的值,直到 r e l e a s e语句被执行,然后或门原语的 P rt驱动源重新生效。尽管 f o r c e赋值有效(在前 5个时间单位),D z x和 S t d上的任何变化都促使赋值重新执行。
另一实例如下:
r e g[2:0] C o l t;
.,,
C o l t = 2;
f o r c e C o l t = 1;
.,,
r e l e a s e C o l t; // Colt保持值为 1。
.,,
a s s i g n C o l t = 5;
.,,
f o r c e C o l t = 3;
.,,
第 8章 行 为 建 模 79下载
r e l e a s e C o l t; // C o l t值变为 5。
.,,
f o r c e C o l t[1:0] = 3; /*错误:寄存器的部分选择不能设为过程性连续赋值的目标 * /
C o l t的第 1次释放促使 C o l t的值被保持为 1。这是因为在 f o r c e语句被应用时没有过程性连续赋值对寄存器赋值。在后面的 r e l e a s e语句中,C o l t因为过程性连续赋值在 C o l t上重新生效而重新获得值 5。
8.9 握手协议实例
a l w a y s语句可用于描述交互进程的行为,如有限状态机的交互。这些模块内的语句用对所有 a l w a y s语句可见的寄存器来相互通信。在 a l w a y s语句间使用在一个 a l w a y s语句内声明的寄存器变量传递信息并不可取(这可以使用层次路径名实现,见第 1 0章) 。
考虑下面两个交互进程的实例,R X,接收器; M P,微处理器。 R X进程读取串行的输入数据。
并发送 R e a d y信号表明数据可被读入 M P进程。 M P进程在将数据分配给输出后,回送一个接收信号 A c k到 R X进程以读取新的输入数据。两个进程的语句块流程如图 8 - 8所示。
图 8-8 两个交互进程这两个交互进程的行为可用下述行为模型加以描述:
' t i m e s c a l e 1 n s / 1 0 0 p s
m o d u l e I n t e r a c t i n g (S e r i a l _ I n,C l k,P a r a l l e l _ O u t)
i n p u t S e r i a l _ I n,C l k;
o u t p u t [0:7] P a r a l l e l _ O u t;
r e g [0:7] P a r a l l e l _ O u t;
r e g R e a d y,A c k;
w i r e [0:7] d a t a;
' i n c l u d e "Read_Word.v" //R e a d _ W o r d任务在此文件中定义。
a l w a y s
b e g i n,R X
R e a d _ W o r d(S e r i a l _ I n,C l k,D a t a) ;
/ /任务 R e a d _ W o r d在每个时钟周期读取串行数据,将其转换为并行数据并存于 D a t a中。 R e a d _ W o r d完成上述任务需要 1 0 n s。
R e a d y = 1;
w a i t(A c k) ;
R e a d y = 0;
# 4 0 ;
e n d
a l w a y s
b e g i n,M P
# 2 5 ;
80 Verilog HDL 硬件描述语言 下载
P a r a l l e l _ O u t = D a t a;
A c k = 1;
#25 A c k = 0;
w a i t (r e a d y) ;
e n d
e n d m o d u l e
这两个进程通过寄存器 R e a d y和 A c k的交互握手协议如图 8 - 9中的波形显示。
图 8-9 两进程间的握手协议习题
1,initial语句和 a l w a y s语句,哪一种可重复执行?
2,顺序语句块和并行语句块的区别是什么?举例说明。顺序语句块能否出现在并行语句块中?
3,语句块在什么时候需要标识符?
4,在 a l w a y s语句中是否有必要指定时延?
5,语句内部时延和语句间时延的区别是什么?举例说明。
6,阻塞性赋值和非阻塞性赋值有何区别?
7,casex语句与 c a s e语句有何区别?
8,能否在 a l w a y s语句中为线网类型(例如 w i r e型线网)赋值?
9,产生一个在 5 ns时刻开始、周期为 10 ns的时钟波形。
10,用一个 i n i t i a l语句和 1个 f o r e v e r循环语句替代下述 a l w a y s语句。
a l w a y s
@ (E x p e c t e d o r O b s e r v e d)
if (E x p e c t e d !== O b s e r v e d) b e g i n
$d i s p l a y ("MISMATCH,Expected = %b,Observed = %b"
Expected,Observed) ;
$s t o p;
e n d
11,按如下条件,两个 a l w a y s语句中 N e x t S t a t e A和 N e x t S t a t e B上的值是多少,C l o c k P在 5 ns时有 1
个正沿; C u rre n t S t a t e在时钟边沿前值为 5,并且在时钟沿 3 ns后改变为 7?
a l w a y s
@ (p o s e d g e C l o c k P)
#7 N e x t S t a t e A = C u r r e n t S t a t e;
第 8章 行 为 建 模 81
读取新的串行数据
MP的数据输出下载
a l w a y s
@ (p o s e d g e C l o c k P)
N e x t S t a t e = #7 C u r r e n t S t a t e;
12,使用行为建模方式写出如下有限状态机模型的行为描述。
I n p ( G a k ) P r e s e n t S t a t e N e x t S t a t e O u t p u t ( Z u k )
0 NO_ONE NO_ONE 0
1 NO_ONE ONE_ONE 0
0 ONE_ONE ONE_ONE 0
1 ONE_ONE TWO_ONE 0
0 TWO_ONE NO_ONE 0
1 TWO_ONE THREE_ONE 1
0 THREE_ONE NO_ONE 0
1 THREE_ONE THREE_ONE 1
13,使用 a l w a y s语句描述 J K触发器的行为功能。
14,描述如下电路行为:该电路在每一个时钟下跳沿(负沿)检查输入数据,当输入数据 U s g
为 1 0 11时,输出 A s m被置为 1。
15,描述多数逻辑电路行为。输入为 1 2位的向量。如果其中 1的数量超过 0的数量,输出设置为
1。当 D a t a _ R e a d y为 1时,才对输入数据进行检查。
82 Verilog HDL 硬件描述语言 下载
8.1 过程结构下述两种语句是为一个设计的行为建模的主要机制。
1) initial 语句
2) always语句一个模块中可以包含任意多个 i n i t i a l或 a l w a y s语句。这些语句相互并行执行,即这些语句的执行顺序与其在模块中的顺序无关。一个 i n i t i a l语句或 a l w a y s语句的执行产生一个单独的控制流,所有的 i n i t i a l和 a l w a y s语句在 0时刻开始并行执行。
8.1.1 initial 语句
initial 语句只执行一次。 initial 语句在模拟开始时执行,即在 0时刻开始执行。 initial 语句的语法如下:
i n i t i a l
[t i m i n g _ c o n t r o l] p r o c e d u r a l _ s t a t e m e n t
p r o c e d u r a l _ s t a t e m e n t是下列语句之一:
p r o c e d u r a l _ a s s i g n m e n t(blocking or non-blocking) / /阻塞或非阻塞性过程赋值语句 / /
p r o c e d u r a l _ c o n t i n u o u s _ a s s i g n m e n t
c o n d i t i o n a l _ s t a t e m e n t
c a s e _ s t a t e m e n t
l o o p _ s t a t e m e n t
w a i t _ s t a t e m e n t
d i s a b l e _ s t a t e m e n t
e v e n t _ t r i g g e r
s e q u e n t i a l _ b l o c k
p a r a l l e l _ b l o c k
task_enable (user or system)
顺序过程 ( b e g i n,,,e n d )最常使用在进程语句中。这里的时序控制可以是时延控制,即等待一个确定的时间;或事件控制,即等待确定的事件发生或某一特定的条件为真。 i n i t i a l语句的各个进程语句仅执行一次。注意 i n i t i a l语句在模拟的 0时刻开始执行。 i n i t i a l语句根据进程语句中出现的时间控制在以后的某个时间完成执行。
下面是 i n i t i a l语句实例。
r e g Y u r t;
.,,
i n i t i a l
Y u r t = 2;
上述 i n i t i a l语句中包含无时延控制的过程赋值语句。 i n i t i a l语句在 0时刻执行,促使 Yu rt在 0
时刻被赋值为 2。下例是一个带有时延控制的 i n i t i a l语句。
r e g C u r t;
.,,
i n i t i a l
#2 C u r t = 1;
寄存器变量 C u rt在时刻 2被赋值为 1。 i n i t i a l语句在 0时刻开始执行,在时刻 2完成执行。
下例为带有顺序过程的 i n i t i a l语句。
p a r a m e t e r S I Z E = 1024;
r e g [7:0] R A M [ 0,S I Z E- 1 ] ;
r e g R i b R e g;
i n i t i a l
b e g i n,S E Q _ B L K _ A
i n t e g e r I n d e x;
R i b R e g = 0;
f o r (I n d e x = 0; I n d e x < S I Z E; I n d e x = I n d e x + 1)
R A M [I n d e x] = 0;
e n d
顺序过程由关键词 b e g i n,,,e n d定界,它包含顺序执行的进程语句,与 C语言等高级编程语言相似。 S E Q _ B L K _ A是顺序过程的标记;如果过程中没有局部说明部分,不要求这一标记。
例如,如果对 I n d e x的说明部分在 i n i t i a l语句之外,可不需要标记。整数型变量 I n d e x已在过程中声明。并且,顺序过程包含 1个带循环语句的过程性赋值。这一 i n i t i a l语句在执行时将所有的内存初始化为 0。
下例是另一个带有顺序过程的 i n i t i a l语句。在此例中,顺序过程包含时延控制的过程性赋值语句。
/ /波形生成:
p a r a m e t e r A P P L Y _ D E L A Y = 5;
r e g[ 0,7 ]p o r t _ A;
.,,
i n i t i a l
b e g i n
P o r t _ A = ' h 2 0 ;
#APPLY_DELAY Port_A= 'hF2;
#APPLY_DELAY Port_A= 'h41;
#APPLY_DELAY Port_A= 'h0A;
e n d
执行时,P o rt _ A的值如图 8 - 1所示。
图 8-1 使用 initial语句产生的波形如上面举例所示,I n i t i a l语句主要用于初始化和波形生成。
60 Verilog HDL 硬件描述语言 下载
8.1.2 always语句与 i n i t i a l语句相反,a l w a y s语句重复执行。与 i n i t i a l语句类似,a l w a y s语句语法如下:
a l w a y s
[t i m i n g _ c o n t r o l] p r o c e d u r a l _ s t a t e m e n t
过程语句和时延控制(时序控制)的描述方式与上节相同。
例如:
always
C l k = ~ C l k;
/ /将无限循环。
此 a l w a y s语句有一个过程性赋值。因为 a l w a y s语句重复执行,并且在此例中没有时延控制,
过程语句将在 0时刻无限循环。因此,a l w a y s语句的执行必须带有某种时序控制,如下例的
a l w a y s语句,形式上与上面的实例相同,但带有时延控制。
always
#5 C l k = ~ C l k;
/ /产生时钟周期为 1 0的波形。
此 a l w a y s语句执行时产生周期为 1 0个时间单位的波形。
下例是由事件控制的顺序过程的 a l w a y s语句。
r e g [0:5] I n s t r R e g;
r e g [3:0] A c c u m;
w i r e E x e c u t e C y c l e;
a l w a y s
@ (E c e c u t e C y c l e)
b e g i n
c a s e(I n s t r R e g[ 0,1 ] )
2'b00,S t o r e (Accum,InstrReg[ 2,5 ] ) ;
2'b11,L o a d (Accum,InstrReg[ 2,5 ] ) ;
2'b01,J u m p (I n s t r R e g[ 2,5 ] ) ;
2 ' b 1 0,;
e n d c a s e
e n d
/ /S t o r e,L o a d和 J u m p是 在别处定义的用户自定义的任务。
顺序过程 ( b e g i n,,,e n d )中的语句按顺序执行。这个 a l w a y s语句意味着只要有事件发生,即只要发生变化,E x e c u t e C y c l e就执行顺序过程中的语句;顺序过程的执行意味着按顺序执行过程中的各个语句。
下例为带异步预置的负边沿触发的 D触发器的行为模型。
m o d u l e D F F(Clk,D,Set,Q,Qbar) ;
i n p u t Clk,D,Set;
o u t p u t Q,Qbar;
r e g Q,Qbar;
a l w a y s
w a i t (S e t == 1)
b e g i n
#3 Q = 1;
#2 Q b a r = 0;
第 8章 行 为 建 模 61下载
w a i t (S e t == 0);
e n d
a l w a y s
@ (n e g e d g e C l k)
b e g i n
if (S e t != 1)
b e g i n
#5 Q = D;
#1 Q b a r = ~ Q;
e n d
e n d
e n d m o d u l e
此模型中有 2条 a l w a y s语句。第一条 a l w a y s语句中顺序过程的执行由电平敏感事件控制。
第二条 a l w a y s语句中顺序过程的执行由边沿触发的事件控制。
8.1.3 两类语句在模块中的使用一个模块可以包含多条 a l w a y s语句和多条 i n i t i a l语句。每条语句启动一个单独的控制流。
各语句在 0时刻开始并行执行。
下例中含有 1条 i n i t i a l语句和 2条 a l w a y s语句。
m o d u l e T e s t X o r B e h a v i o r;
r e g Sa,Sb,Zeus;
i n i t i a l
b e g i n
S a = 0;
S b = 0;
#5 S b = 1;
#5 S a = 1;
#5 S b = 0;
e n d
a l w a y s
@ (Sa or Sb) Zeus = Sa ^ Sb;
a l w a y s
@ (Z e u s)
$d i s p l a y ( "At time %t,S a = %d,S b = %d,Z e u s = %b",
$t i m e,S a,S b,Z e u s) ;
e n d m o d u l e
模块中的 3条语句并行执行,其在模块中的书写次序并不重要。 i n i t i a l语句执行时促使顺序过程中的第一条语句执行,即 S a赋值为 0;下一条语句在 0时延后立即执行。 i n i t i a l语句中的第 3行表示“等待 5个时间单位” 。这样 S b在 5个时间单位后被赋值为 1,S a在另外 5个时间单位后被赋值为 0。执行顺序过程最后一条语句后,i n i t i a l语句被永远挂起。
第一条 a l w a y s语句等待 S a或 S b上的事件发生。只要有事件发生,就执行 a l w a y s语句内的语句,然后 a l w a y s语句重新等待发生在 S a或 S b上的事件。注意根据 i n i t i a l语句对 S a和 S b的赋值,
a l w a y s语句将在第 0,5,1 0和 1 5个时间单位时执行。
62 Verilog HDL 硬件描述语言 下载同样,只要有事件发生在 Z e u s上,就执行第 2条 a l w a y s语句。在这种情况下,系统任务 $ d i s p l a y被执行,然后 a l w a y s
语句重新等待发生在 Z e u s上的事件。 S a,S b和 Z e u s上产生的波形如图 8 - 2所示。下面是模块模拟运行产生的输出。
在时刻 5,Sa = 0,Sb = 1,Zeus = 1
在时刻 10,Sa = 1,Sb = 1,Zeus = 0
在时刻 15,Sa = 1,Sb = 0,Zeus = 1
8.2 时序控制时序控制与过程语句关联。有 2种时序控制形式:
1) 时延控制
2) 事件控制
8.2.1 时延控制时延控制形式如下:
#delay procedural_statement
实例如下;
#2 Tx = R x- 5 ;
时延控制定义为执行过程中首次遇到该语句与该语句的执行的时间间隔。时延控制表示在语句执行前的“等待时延” 。上面的例子中,过程赋值语句在碰到该语句后的 2个时间单位执行,然后执行赋值。
另一实例如下:
i n i t i a l
b e g i n
#3 W a v e = 'b0111;
#6 W a v e = 'b1100;
#7 W a v e = 'b0000;
e n d
i n i t i a l语句在 0时刻执行。首先,等待 3个时间单位执行第一个赋值,然后等待 6个时间单位,执行第 2个语句;再等待 7个时间单位,执行第 3个语句;然后永远挂起。
时延控制也可以用另一种形式定义:
#d e l a y;
这一语句促使在下一条语句执行前等待给定的时延。下面是这种用法的实例。
parameter O N _ D E L A Y = 3,O F F _ D E L A Y = 5;
a l w a y s
b e g i n
# O N _ D E L A Y; //等待 O N _ D E L A Y规定的时延。
R e f C l k = 0;
# O F F _ D E L A Y; //等待 O F F _ D E L A Y规定的时延。
R e f C l k = 1;
e n d
时延控制中的时延可以是任意表达式,即不必限定为某一常量,见下面的例子。
# Strobe
Compare = TX^ a s k ;
第 8章 行 为 建 模 63下载图 8-2 Sa,Sb和 Zeus上产生的波形
#( P E R I O D / 2)
Clock =? C l o c k
如果时延表达式的值为 0,则称之为显式零时延。
#0; //显式零时延。
显式零时延促发一个等待,等待所有其它在当前模拟时间被执行的事件执行完毕后,才将其唤醒;模拟时间不前进。
如果时延表达式的值为 x或 z,其与零时延等效。如果时延表达式计算结果为负值,那么其二进制的补码值被作为时延,这一点在使用时务请注意。
8.2.2 事件控制在事件控制中,a l w a y s的过程语句基于事件执行。有两种类型的事件控制方式:
1) 边沿触发事件控制
2) 电平敏感事件控制
1,边沿触发事件控制边沿触发事件控制如下,
@ event procedural_statement
如下例所示,
@ (p o s e d g e C l o c k)
C u r r _ S t a t e = N e x t _ S t a t e;
带有事件控制的进程或过程语句的执行,须等到指定事件发生。上例中,如果 C l o c k信号从低电平变为高电平(正沿),就执行赋值语句;否则进程被挂起,直到 C l o c k信号产生下一个正跳边沿。
下面是进一步的实例。
@ (n e g e d g e R e s e t) C o u n t = 0;
@C l a
Z o o = F o o;
在第一条语句中,赋值语句只在 R e s e t上的负沿执行。第二条语句中,当 C l a上有事件发生时,F o o的值被赋给 Z o o,即等待 C l a上发生事件;当 C l a的值发生变化时,F o o的值被赋给 Z o o。
也可使用如下形式,
@ e v e n t ;
该语句促发一个等待,直到指定的事件发生。下面是确定时钟在周期的 i n i t i a l语句中使用的一个例子。
t i m e RiseEdge,OnDelay;
i n i t i a l
b e g i n
/ /等待,直到在时钟上发生正边沿:
@ (p o s e d g e C l o c k A) ;
R i s e E d g e = $t i m e;
/ /等待,直到在时钟上发生负边沿:
@ (n e g e d g e C l o c k A) ;
O n D e l a y = $t i m e - R i s e E d g e;
$d i s p l a y ("The on-period of clock is %t.",D e l a y) ;
e n d
事件之间也能够相或以表明“如果有任何事件发生” 。下例将对此进行说明。
@ (p o s e d g e C l e a r or negedgeR e s e t)
64 Verilog HDL 硬件描述语言 下载
Q = 0;
@ (Ctrl_A o r C t r l _ B)
D b u s = 'b z;
注意关键字 o r并不意味着在 1个表达式中的逻辑或。
在 Verilog HDL中 p o s e d g e和 n e g e d g e是表示正沿和负沿的关键字。信号的负沿是下述转换的一种:
1 -> x
1 -> z
1 -> 0
x -> 0
z -> 0
正沿是下述转换的一种:
0 -> x
0 -> z
0 -> 1
x -> 1
z -> 1
2,电平敏感事件控制在电平敏感事件控制中,进程语句或进程中的过程语句一直延迟到条件变为真后才执行。
电平敏感事件控制以如下形式给出:
w a i t (C o n d i t i o n)
p r o c e d u r a l _ s t a t e m e n t
过程语句只有在条件为真时才执行,否则过程语句一直等待到条件为真。如果执行到该语句时条件已经为真,那么过程语句立即执行。在上面的表示形式中,过程语句是可选的。
例如:
w a i t (S u m > 22)
S u m = 0;
w a i t (D a t a R e a d y)
D a t a = B u s;
w a i t (P r e s e t) ;
在第一条语句中,只有当 S u m的值大于 2 2时,才对 S u m清 0。在第二条语句中,只有当
D a t a R e a d y为真,即 D a t a R e a d y值为 1时,将 B u s赋给 D a t a。最后一条语句表示延迟至 P re s e t变为真(值为 1)时,其后续语句方可继续执行。
8.3 语句块语句块提供将两条或更多条语句组合成语法结构上相当于一条语句的机制。在 Ve r i l o g
H D L中有两类语句块,即:
1) 顺序语句块 (b e g i n,,,e n d):语句块中的语句按给定次序顺序执行。
2) 并行语句块 (f o r k,,,j o i n):语句块中的语句并行执行。
语句块的标识符是可选的,如果有标识符,寄存器变量可在语句块内部声明。带标识符的语句块可被引用;例如,语句块可使用禁止语句来禁止执行。此外,语句块标识符提供唯一标识寄存器的一种方式。但是,要注意所有的寄存器均是静态的,即它们的值在整个模拟第 8章 行 为 建 模 65下载运行中不变。
8.3.1 顺序语句块顺序语句块中的语句按顺序方式执行。每条语句中的时延值与其前面的语句执行的模拟时间相关。一旦顺序语句块执行结束,跟随顺序语句块过程的下一条语句继续执行。顺序语句块的语法如下:
b e g i n
[,b l o c 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 ( s )
e n d
例如:
/ /产生波形,
b e g i n
#2 S t r e a m = 1;
#5 S t r e a m = 0;
#3 S t r e a m = 1;
#4 S t r e a m = 0;
#2 S t r e a m = 1;
#5 S t r e a m = 0;
e n d
假定顺序语句块在第 1 0个时间单位开始执行。两个时间单位后第 1条语句执行,即第 1 2个时间单位。此执行完成后,下 1条语句在第 1 7个时间单位执行 (延迟 5个时间单位 )。然后下 1条语句在第 2 0个时间单位执行,以此类推。该顺序语句块执行过程中产生的波形如图 8 - 3所示。
图 8-3 顺序语句块中的累积时延下面是顺序过程的另一实例。
b e g i n
P a t = M a s k | M a t;
@ (n e g e d g e C l k) ;
F F = & P a t
e n d
在该例中,第 1条语句首先执行,然后执行第 2条语句。当然,第 2条语句中的赋值只有在
C l k上出现负沿时才执行。下面是顺序过程的另一实例。
b e g i n,S E Q _ B L K
r e g[0:3] S a t ;
S a t = Mask & Data;
F F = ^S a t;
e n d
在这一实例中,顺序语句块带有标记 S E Q _ B L K,并且有一个局部寄存器说明。在执行时,
首先执行第1条语句,然后执行第 2条语句。
66 Verilog HDL 硬件描述语言 下载
8.3.2 并行语句块并行语句块带有定界符 f o r k和 j o i n(顺序语句块带有定界符 b e g i n和 e n d),并行语句块中的各语句并行执行。并行语句块内的各条语句指定的时延值都与语句块开始执行的时间相关。
当并行语句块中最后的动作执行完成时 (最后的动作并不一定是最后的语句 ),顺序语句块的语句继续执行。换一种说法就是并行语句块内的所有语句必须在控制转出语句块前完成执行。
并行语句块语法如下:
f o r k
[,b l o c 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(s) ;
j o i n
例如:
// 生成波形:
f o r k
#2 S t r e a m = 1;
#7 S t r e a m = 0;
#10 S t r e a m = 1;
#14 S t r e a m = 0;
#16 S t r e a m = 1;
#21 S t r e a m = 0;
j o i n
如果并行语句块在第 1 0个时间单位开始执行,所有的语句并行执行并且所有的时延都是相对于时刻 1 0的。例如,第 3个赋值在第 2 0个时间单位执行,并在第 2 6个时间单位执行第 5个赋值,以此类推。其产生的波形如图 8 - 4所示。
图 8-4 并行语句块中的相对时延下例混合使用了顺序语句块和并 行 语句块,以强调两者的不同之处。
a l w a y s
b e g i n:S E Q _ A
#4 D r y = 5; // S1
f o r k,P A R _ A / / S 2
#6 C u n = 7; //P1
b e g i n,S E Q _ B / / P 2
E X E = B o x; //S6
#5 J a p = E x e; //S7
e n d
#2 D o p = 3; //P3
#4 G o s = 2; //P4
#8 P a s = 4; //P5
j o i n
第 8章 行 为 建 模 67下载
#8 B a x = 1; //S3
#2 Z o o m = 52; //S4
#6 $s t o p; //S5
e n d
a l w a y s语句中包含顺序语句块 S E Q_A,并且顺序语句块内的所有语句 ( S 1,S 2,S 3,S 4和
S 5 )顺序执行。因为 a l w a y s语句在 0时刻执行,D ry在第 4个时间单位被赋值为 5,并且并行语句块 PA R _ A在第 4个时间单位开始执行。并行语句块中的所有语句 ( P 1,P 2,P 3,P 4和 P 5 )在第 4
个时间单位并行执行。这样 C u n在第 1 0个时间单位被赋值,D o p在第 6个时间单位被赋值,G o s
在第 8个时间单位被赋值,P a s在第 1 2个时间单位被赋值。顺序语句块 S E Q _ B在第 4个时间单位开始执行,并导致该顺序块中的语句 S 6,S 7依次被执行; J a p在时间单位 9被赋于新值。因为并行语句块 PA R _ A中的所有语句在第 1 2个时间单位完成执行,语句 S 3在第 1 2个时间单位被执行,在第 2 0个时间单位 B a x被赋值,然后语句 S 4执行,在第 2 2个时间单位 Z o o m被赋值,然后执行下一语句。最终在第 2 8个时间单位执行系统任务 $ s t o p。 a l w a y s语句执行时发生的事件如图 8 - 5所示。
图 8-5 顺序语句块和并行语句块混合使用时的时延
8.4 过程性赋值过程性赋值是在 i n i t i a l语句或 a l w a y s语句内的赋值,它只能对寄存器数据类型的变量赋值。
表达式的右端可以是任何表达式。例如:
r e g[1:4] E n a b l e,A,B;
.,,
#5 E n a b l e = ~A ^ ~B;
E n a b l e为寄存器。根据时延控制,赋值语句被延迟 5个时间单位执行。右端表达式被计算,
并赋值给 E n a b l e。
过程性赋值与其周围的语句顺序执行。 a l w a y s语句实例如下:
a l w a y s
@ (A o r B o r C o r D)
b e g i n:A O I
r e g T e m p 1,T e m p 2;
Temp1 = A & B;
Temp2 = C & D;
Temp1 = Temp1 | T e m p 2 ;
68 Verilog HDL 硬件描述语言 下载
Z = ~T e m p 1;
e n d
/ *可用一个语句代替上面的 4条语句,例如,
Z = ~((A & B) | (C & D) ) ;
但是,上例的目的主要用于解释说明顺序过程语句的顺序特性 * /
a l w a y s语句内的顺序过程在信号 A,B,C或 D发生变化时开始执行。 Te m p 1的赋值首先执行。然后执行第二个赋值。在以前赋值中计算的 Te m p 1和 Te m p 2的值在第三条赋值语句中使用。
最后一个赋值使用在第三条语句中计算的 Te m p 1的值。
过程性赋值分两类:
1) 阻塞性过程赋值
2) 非阻塞性过程赋值在讨论这两类过程性赋值前,先简要地说明语句内部时延的概念。
8.4.1 语句内部时延在赋值语句中表达式右端出现的时延是语句内部时延。通过语句内部时延表达式,右端的值在赋给左端目标前被延迟。例如:
D o n e = #5 'b1;
重要的是右端表达式在语句内部时延之前计算,随后进入时延等待,再对左端目标赋值。
下例说明了语句间和语句内部时延的不同。
D o n e = #5 'b1; //语句内部时延控制与
b e g i n
T e m p = 'b1;
#5 D o n e = T e m p; //语句间时延控制
e n d
相同。而语句
Q = @(p o s e d g e C l k ) D; //语句内事件控制与
b e g i n
T e m p = D;
@ (p o s e d g e C l k) //语句间事件控制
Q = T e m p;
e n d
相同。
除以上两种时序控制 (时延控制和事件控制 )可用于定义语句内部时延外,还有另一种重复事件控制的语句内部时延表示形式。形式如下:
r e p e a t(e x p r e s s) @ (e v e n t _ e x p r e s s i o n)
这种控制形式用于根据一定数量的 1个或多个事件来定义时延。例如,
D o n e = r e p e a t(2) @ (n e g e d g e C l k A) A _ R E G + B _ R E G
这一语句执行时先计算右端的值,即 A _ R e g + B _ R e g的值,然后等待时钟 C l k A上的两个负沿,再将右端值赋给 D o n e。这一重复事件控制实例的等价形式如下:
第 8章 行 为 建 模 69下载
b e g i n
T e m p = A_REG + B _ R E G
@ (n e g e d g e C l k A) ;
@ (n e g e d g e C l k A) ;
D o n e = T e m p;
e n d
这种形式的时延控制方式在给某些边或一定数量的边的同步赋值过程(语句)中非常有用。
8.4.2 阻塞性过程赋值赋值操作符是,=”的过程赋值是阻塞性过程赋值。例如,
R e g A = 52;
是阻塞性过程赋值。阻塞性过程赋值在其后所有语句执行前执行,即在下一语句执行前该赋值语句完成执行。如下所示:
a l w a y s
@ (A o r B o r C i n)
b e g i n,C A R R Y _ O U T
r e g T 1,T 2,T 3 ;
T 1 = A & B;
T 2 = B & C i n;
T 3 = A & C i n;
C o u t = T 1 | T 2 | T 3;
e n d
T 1赋值首先发生,计算 T 1;接着执行第二条语句,T 2被赋值;然后执行第三条语句,T 3
被赋值;依此类推。
下例是使用语句内部时延控制的阻塞性过程赋值语句。
i n i t i a l
b e g i n
C l r = #5 0;
C l r = #4 1;
C l r = #10 0;
e n d
第一条语句在 0时刻执行,C l r在 5个时间单位后被赋值;接着执行第二条语句,使 C l r在 4
个时间单位后被赋值为 1 (从 0时刻开始为第 9个时间单位 );然后执行第三条语句促使 C l r在 1 0个时间单位后被赋值为 0 (从 0时刻开始为第 1 9个时间单位 )。图 8 - 6显示 C l r上产生的波形。
图 8-6 带有语句内部时延控制的阻塞性过程赋值另一实例如下:
b e g i n
A r t = 0;
70 Verilog HDL 硬件描述语言 下载
A r t = 1;
e n d
在这种情况下,A rt被赋值为 1。这是因为第一个 A rt被赋值为 0,然后执行下一条语句促使
A rt在 0时延后被赋值为 1。因此对 A rt的 0赋值被丢弃。
8.4.3 非阻塞性过程赋值在非阻塞性过程赋值中,使用赋值符号,< =” 。例如:
b e g i n
L o a d <= 32;
R e g A <= L o a d;
R e g B <= S t o r e;
e n d
在非阻塞性过程赋值中,对目标的赋值是非阻塞的 (因为时延 ),但可预定在将来某个时间步发生 (根据时延;如果是 0时延,那么在当前时间步结束 )。当非阻塞性过程赋值被执行时,
计算右端表达式,右端值被赋于左端目标,并继续执行下一条语句。预定的最早输出将在当前时间步结束时,这种情况发生在赋值语句中没有时延时。在当前时间步结束或任意输出被调度时,即对左端目标赋值。
在上面的例子中,我们假设顺序语句块在时刻 1 0执行。第一条语句促使 L o a d在第 1 0个时间单位结束时被赋值为 3 2;然后执行第 2条语句,L o a d的值不变 (注意时间还没有前进,并且第 1个赋值还没有被赋新值 ),R e g A的赋值被预定为在第 1 0个时间步结束时。在所有的事件在第 1 0个时间单位发生后,完成对左端目标的所有预定赋值。
下面的例子更进一步解释这种赋值特征。
i n i t i a l
b e g i n
C l r <= #5 1;
C l r <= #4 0;
C l r <= #10 0;
e n d
第一条语句的执行使 C l r 在第 5个时间单位被赋于值 1;第二条语句的执行使 C l r在第 4个时间单位被赋值为 0 (从 0时刻开始的第 4个时间单位 );最终,第 3条语句的执行使 C l r在第 1 0个时间单位被赋值为 0 (从 0时刻开始的第 1 0个时间单位 )。
注意 3条语句都是在 0时刻执行的。此外,在这种情况下,非阻塞性赋值执行次序变得彼此不相关。
C l r上产生的波形如图 8 - 7所示。
下面是带有 0时延的例子。
i n i t i a l
b e g i n
C b n <= 0;
C b n <= 1;
e n d
在 i n i t i a l语句执行后,因为同时对同一寄存器变量有多个赋值,C b n的值变得不确定,即
Cbn = x。 Verilog HDL标准中既没有规定在这种情况下,何种事件被调度,也没有规定事件第 8章 行 为 建 模 71下载图 8-7 带有语句内部时延的非阻塞性过程赋值被取消的次序。结果是根据特定的 Ve r i l o g模拟器的事件调度算法,C b n将被赋值为 0或 1 。
下面是同时使用阻塞性和非阻塞性过程赋值的实例,注意它们的区别。
reg [0:2] Q _ S t a t e;
i n i t i a l
b e g i n
Q _ S t a t e = 3’ b 0 1 1 ;
Q _ S t a t e <= 3’ b 1 0 0 ;
$d i s p l a y (,Current value of Q_State is %b”,Q _ S t a t e) ;
#5; //等待一定的时延。
$d i s p l a y (,The delayed value of Q_State is %b”,Q _ S t a t e) ;
e n d
执行 i n i t i a l语句产生如下结果:
Current value of Q_State is 011
The delayed value of Q_State is 100
第一个阻塞性赋值使 Q _ S t a t e被赋值为 3'b 0 11。执行第二条赋值语句 (为非阻塞性赋值语句 )
促使 Q _ S t a t e在当前时间步 (第 0步 )结束时被赋值为 3'b 1 0 0。因此当第一个 $d i s p l a y任务被执行时,Q _ S t a t e还保持来自第一个赋值的值,即 3'b 0 11。当 # 5时延被执行后,促使被调度的
Q _ S t a t e赋值发生,Q _ S t a t e的值被更新。延迟 5个时间单位后,执行下一个 $d i s p l a y任务,此时显示 Q _ S t a t e的更新值。
8.4.4 连续赋值与过程赋值的比较连续赋值与过程赋值有什么不同之处? 表 8 - 1列举了它们的差异。
表 8-1 过程赋值与连续赋值间的差异过 程 赋 值 连 续 赋 值在 a l w a y s语句或 i n i t i a l语句内出现 在一个模块内出现执行与周围其它语句有关 与其它语句并行执行;在右端操作数的值发生变化时执行驱动寄存器 驱动线网使用,=”或,=”赋值符号 使用,=”赋值符号无 a s s i g n关键词 (在过程性连续赋值中 有 a s s i g n关键词除外,参见第 8章第 8节 )
下例进一步解释了这些差别。
m o d u l e P r o c e d u r a l;
r e g A,B,Z;
a l w a y s
@ (B) b e g i n
Z = A;
A = B;
e n d
e n d m o d u l e
72 Verilog HDL 硬件描述语言 下载在上述情况下,使用不同模拟器对其进行模拟所产生的模拟结果可能会有所不同。 — 译者注
m o d u l e C o n t i n u o u s
w i r e A,B,Z;
a s s i g n Z = A;
a s s i g n A = B;
e n d m o d u l e
假定 B在 10 ns时有一个事件。在过程性赋值模块中,两条过程语句被依序执行,A在 10 ns
时得到 B的新值。 Z没有得到 B的值,因为赋值给 Z发生在赋值给 A之前。在连续性赋值语句模块中,第二个连续赋值被触发,因为这里有一个关于 B的事件。这引起了关于 A的事件,A引发第一个连续赋值被执行,这相应引起 Z得到了 A的值。 Z的新值为 A而不是 B。然而,如果事件发生在 A上,过程性模块中的 a l w a y s语句不执行,因为 A不在那个 a l w a y s语句的实时控制事件清单中。然而连续赋值语句中的第一个连续赋值执行,并且 Z得到 A的新值。
8.5 if 语句
i f语句的语法如下:
i f(c o n d i t i o n _ 1)
p r o c e d u r a l _ s t a t e m e n t _ 1
{else if(c o n d i t i o n _ 2)
p r o c e d u r a l _ s t a t e m e n t _ 2}
{e l s e
p r o c e d u r a l _ s t a t e m e n t _ 3}
如果对 c o n d i t i o n _ 1 求值的结果为一个非零值,那么 p ro c e d u r a l _ s t a t e m e n t _ 1被执行,如果
condition_1 的值为 0,x或 z,那么 p ro c e d u r a l _ s t a t e m e n t _ 1不执行。
如果存在一个 e l s e分支,那么这个分支被执行。以下是一个例子。
i f(S u m < 60)
b e g i n
G r a d e = C;
T o t a l _ C = Total _c + 1;
e n d
else if(S u m < 75)
b e g i n
G r a d e = B;
T o t a l _ B = T o t a l _ B + 1;
e n d
e l s e
b e g i n
G r a d e = A;
T o t a l _ A = T o t a l _ A + 1;
e n d
注意条件表达式必须总是被括起来,如果使用 i f - i f - e l s e格式,那么可能会有二义性,
如下例所示:
i f(C l k)
i f(R e s e t)
Q = 0;
e l s e
Q = D;
第 8章 行 为 建 模 73下载问题是最后一个 e l s e属于哪一个 i f? 它是属于第一个 i f的条件 (C l k)还是属于第二个 i f
的条件 (R e s e t)? 这在 Verilog HDL中已通过将 e l s e与最近的没有 e l s e的 i f相关联来解决。在这个例子中,e l s e与内层 i f语句相关联。
以下是另一些 i f语句的例子。
i f(S u m < 100)
S u m = S u m + 10;
i f(N i c k e l _ I n)
D e p o s i t = 5;
e l s e i f (D i m e _ I n)
D e p o s i t = 10;
else if(Q u a r t e r _ I n)
D e p o s i t = 25;
e l s e
D e p o s i t = E R R O R;
i f(C t r l)
b e g i n
i f( ~C t r l 2)
M u x = 4'd2;
e l s e
M u x = 4'd1;
e n d
e l s e
b e g i n
i f( ~C t r l 2)
M u x = 4'd8;
e l s e
M u x = 4'd4;
e n d
8.6 case语句
c a s e语句是一个多路条件分支形式,其语法如下:
c a s e(c a s e _ e x p r)
c a s e _ i t e m _ e x p r{,c a s e _ i t e m _ e x p r},p r o c e d u r a l _ s t a t e m e n t
.,,
.,,
[d e f a u l t:p r o c e d u r a l _ s t a t e m e n t]
e n d c a s e
c a s e语句首先对条件表达式 c a s e _ e x p r求值,然后依次对各分支项求值并进行比较,第一个与条件表达式值相匹配的分支中的语句被执行。可以在 1个分支中定义多个分支项;这些值不需要互斥。缺省分支覆盖所有没有被分支表达式覆盖的其他分支。
分支表达式和各分支项表达式不必都是常量表达式。在 c a s e语句中,x和 z值作为文字值进行比较。 c a s e语句如下所示:
parameter
M O N = 0,T U E = 1,W E D = 2,
T H U = 3,F R I = 4,
SAT = 5,S U N = 6;
r e g [0:2] D a y;
74 Verilog HDL 硬件描述语言 下载
i n t e g e r P o c k e t _ M o n e y;
c a s e (D a y)
T U E,P o c k e t _ M o n e y = 6; //分支 1。
M O N,
W E D,P o c k e t _ M o n e y = 2; //分支 2。
F R I,
S A T,
S U N,P o c k e t _ M o n e y = 7; //分支 3。
d e f a u l t,P o c k e t _ M o n e y = 0; //分支 4。
e n d c a s e
如果 D a y的值为 M O N或 W E D,就选择分支 2。分支 3覆盖了值 F R I,S AT和 S U N,而分支 4
覆盖了余下的所有值,即 T H U和位向量 111。 c a s e语句的另一实例如下:
m o d u l e A L U (A,B,OpCode,Z) ;
i n p u t [3:0] A,B;
i n p u t [1:2] O p C o d e;
o u t p u t [7:0] Z;
r e g [7:0] Z;
p a r a m e t e r
A D D _ I N S T R = 2'b10,
S U B _ I N S T R = 2'b11,
M U L T _ I N S T R = 2'b01,
D I V _ I N S T R = 2'b00;
always
@ (A o r B o r O p C o d e)
c a s e (O p C o d e)
A D D _ I N S T R,Z = A + B;
S U B _ I N S T R,Z = A -B;
M U L T _ I N S T R,Z = A * B;
D I V _ I N S T R,Z = A / B;
e n d c a s e
e n d m o d u l e
如果 c a s e表达式和分支项表达式的长度不同会发生什么呢? 在这种情况下,在进行任何比较前所有的 c a s e表达式都统一为这些表达式的最长长度。下例说明了这种情况。
c a s e (3'b101 << 2)
3'b100,$d i s p l a y ( "First branch taken!");
4'b0100,$d i s p l a y ( "Second branch taken!");
5'b10100,$d i s p l a y ( "Third branch taken!");
d e f a u l t,$d i s p l a y ( "Default branch taken!");
e n d c a s e
产生:
Third branch taken!
因为第 3个分支项表达式长度为 5位,所有的分支项表达式和条件表达式长度统一为 5。当计算 3 ' b 1 0 1 < < 2时,结果为 5 ' b 1 0 1 0 0,并选择第 3个分支。
case语句中的无关位上节描述的 c a s e语句中,值 x和 z只从字面上解释,即作为 x和 z值。这里有 c a s e语句的其第 8章 行 为 建 模 75下载它两种形式,c a s e x和 c a s e z,这些形式对 x和 z值使用不同的解释。除关键字 c a s e x和 c a s e z以外,
语法与 c a s e语句完全一致。
在 c a s e z语句中,出现在 c a s e表达式和任意分支项表达式中的值 z被认为是无关值,即那个位被忽略 (不比较 )。
在 c a s e x语句中,值 x和 z都被认为是无关位。 c a s e z语句实例如下:
c a s e( M a s k )
4'b1,D b u s[4] = 0;
4'b01,D b u s[3] = 0;
4'b001?,D b u s[2] = 0;
4'b0001,D b u s[1] = 0;
e n d c a s e
字符可用来代替字符 z,表示无关位。 c a s e z语句表示如果 M a s k的第 1位是 1 (忽略其它位 ),
那么将 D b u s[ 4 ]赋值为 0;如果 M a s k的第 1位是 0,并且第 2位是 1 (忽略其它位 ),那么 D b u s [ 3 ]被赋值为 0,并依此类推。
8.7 循环语句
Verilog HDL中有四类循环语句,它们是:
1) forever循环
2) repeat循环
3) while循环
4) for 循环
8.7.1 forever 循环语句这一形式的循环语句语法如下:
f o r e v e r
p r o c e d u r a l _ s t a t e m e n t
此循环语句连续执行过程语句。因此为跳出这样的循环,中止语句可以与过程语句共同使用。同时,在过程语句中必须使用某种形式的时序控制,否则,f o r e v e r循环将在 0时延后永远循环下去。
这种形式的循环实例如下:
i n i t i a l
b e g i n
C l o c k = 0;
# 5 f o r e v e r
#10 C l o c k = ~C l o c k;
e n d
这一实例产生时钟波形;时钟首先初始化为 0,并一直保持到第 5个时间单位。此后每隔
1 0个时间单位,C l o c k反相一次。
8.7.2 repeat 循环语句
repeat 循环语句形式如下:
r e p e a t(l o o p _ c o u n t)
p r o c e d u r a l _ s t a t e m e n t
76 Verilog HDL 硬件描述语言 下载这种循环语句执行指定循环次数的过程语句。如果循环计数表达式的值不确定,即为 x或
z时,那么循环次数按 0处理。下面是一些具体实例。
r e p e a t (C o u n t)
S u m = S u m + 10;
r e p e a t (S h i f t B y)
P _ R e g = P _ R e g << 1;
r e p e a t循环语句与重复事件控制不同。例如,
r e p e a t(C o u n t) //repeat循环语句
@ (p o s e d g e C l k) S u m = S u m + 1;
上例表示计数的次数,等待 C l k的正边沿,并在 C l k正沿发生时,对 S u m加 1。但是,
Sum = r e p e a t(C o u n t) @ (p o s e d g e C l k) S u m + 1;
// 重复事件控制该例表示首先计算 Sum + 1,随后等待 C l k上正沿计数,最后为左端赋值。
下面的表达式意味着什么?
r e p e a t(N U M _ O F _ T I M E S) @ (n e g e d g e C l o c k Z) ;
它表示在执行跟随在 r e p e a t语句之后的语句之前,等待 ClockZ 的 N U M _ O F _ T I M E S个负沿。
8.7.3 while 循环语句
while 循环语句语法如下:
w h i l e(c o n d i t i o n)
p r o c e d u r a l _ s t a t e m e n t
此循环语句循环执行过程赋值语句直到指定的条件为假。如果表达式在开始时为假,那么过程语句便永远不会执行。如果条件表达式为 x或 z,它也同样按 0(假)处理。例如:
w h i l e (B Y > 0 )
b e g i n
A c c = A c c << 1;
B y = B y - 1;
e n d
8.7.4 for 循环语句
for 循环语句的形式如下:
f o r(i n i t i a l _ a s s i g n m e n t ; c o n d i t i o n ; s t e p _ a s s i g n m e n t)
p r o c e d u r a l _ s t a t e m e n t
一 个 f o r 循 环 语 句 按 照 指 定 的 次 数 重 复 执 行 过 程 赋 值 语 句 若 干 次 。 初 始 赋 值
i n i t i a l _ a s s i g n m e n t给出循环变量的初始值。 c o n d i t i o n条件表达式指定循环在什么情况下必须结束。只要条件为真,循环中的语句就执行;而 s t e p _ a s s i g n m e n t给出要修改的赋值,通常为增加或减少循环变量计数。
i n t e g e r K;
for (K=0 ; K < M A X _ R A N G E ; K = K + 1)
b e g i n
i f(A b u s[K] == 0)
A b u s[K] = 1;
第 8章 行 为 建 模 77下载
else if(A b u s[k] == 1)
A b u s[K] = 0;
e l s e
$d i s p l a y( "A b u s[K] is an x or a z");
end
8.8 过程性连续赋值过程性连续赋值是过程性赋值的一类,即它不能够在 a l w a y s语句或 i n i t i a l语句中出现。这种赋值语句能够替换其它所有对线网或寄存器的赋值。它允许赋值中的表达式被连续驱动到寄存器或线网当中。注意,这不是一个连续赋值,连续赋值发生在 i n i t i a l或 a l w a y s语句之外。
过程性连续赋值语句有两种类型:
1) 赋值和重新赋值过程语句:它们对寄存器进行赋值。
2) 强制和释放过程性赋值语句:虽然它们也可以用于对寄存器赋值,但主要用于对线网赋值。
赋值和强制语句在如下意义上是“连续”的:即当赋值或强制发生效用时,右端表达式中操作数的任何变化都会引起赋值语句重新执行。
过程性连续赋值的目标不能是寄存器部分选择或位选择。
8.8.1 赋值—重新赋值一个赋值过程语句包含所有对寄存器的过程性赋值,重新赋值过程语句中止对寄存器的连续赋值。寄存器中的值被保留到其被重新赋值为止。
m o d u l e D E F(D,C l r,C l k,Q) ;
i n p u t D,C l r,C l k;
o u t p u t Q;
r e g Q;
a l w a y s
@ (C l r) b e g i n
i f( !C l r)
a s s i g n Q = 0; // D对 Q无效。
e l s e
d e a s s i g n Q;
e n d
a l w a y s
@ (n e g e d g e C l k) Q = D;
e n d m o d u l e
如果 C l r为 0,a s s i g n赋值语句使 Q清 0,而不管时钟边沿的变化情形,即 C l k和 D对 Q无效。
如果 C l r变为 1,重新赋值语句被执行;这就使得强制赋值方式被取消,以后 C l k能够对 Q产生影响。
如果赋值应用于一个已经被赋值的寄存器,a s s i g n赋值在进行新的过程性连续赋值前取消了原来的赋值。实例如下:
r e g[3:0] P e s t;
.,,
78 Verilog HDL 硬件描述语言 下载
P e s t = 0;
.,,
a s s i g n P e s t = H t y ^ M t u;
.,,
assign P e s t = 2; //将对 P e s t重新赋值,然后赋值。
.,,
d e a s s i g n P e s t; //Pest连续地保持值为 2。
.,,
a s s i g n P e s t[2] = 1; /*错误:对寄存器的位选择不能够作为过程性连续赋值的目标 * /
第二个赋值语句在进行下一个赋值前促使第一个赋值被重新赋值。在重新分配执行后,
P e s t的值在另一个对寄存器的赋值前保持为 2。
赋值语句在如下意义上是连续的:即在第 1个赋值执行后,第 2个赋值开始执行前,H t y或
M t u上的任何变化将促使第 1个赋值语句被重新计算。
8.8.2 force与 release
f o r c e和 r e l e a s e过程语句与 a s s i g n和 d e a s s i g n非常相似,不同的是 f o r c e和 r e l e a s e过程语句不仅能够应用于线网,也能够应用于寄存器的赋值。
当 f o r c e语句应用于寄存器时,寄存器的当前值被 f o r c e语句的值覆盖;当 r e l e a s e语句应用于寄存器时,寄存器中的当前值保持不变,除非过程性连续赋值已经生效(在 f o r c e语句被执行时),在这种情况下,连续赋值为寄存器建立新值。
当用 f o r c e过程语句对线网进行赋值时,该赋值方式为线网替换所有驱动源,直到在那个线网上执行 r e l e a s e语句为止。
w i r e P r t;
.,,
o r #1 (P r t,S t d,D z x) ;
i n i t i a l
b e g i n
f o r c e P r t = Dzx & S t d;
#5; // 等待 5个时间单位。
release P r t;
e n d
执行 f o r c e语句使 P rt的值覆盖来自于或门原语的值,直到 r e l e a s e语句被执行,然后或门原语的 P rt驱动源重新生效。尽管 f o r c e赋值有效(在前 5个时间单位),D z x和 S t d上的任何变化都促使赋值重新执行。
另一实例如下:
r e g[2:0] C o l t;
.,,
C o l t = 2;
f o r c e C o l t = 1;
.,,
r e l e a s e C o l t; // Colt保持值为 1。
.,,
a s s i g n C o l t = 5;
.,,
f o r c e C o l t = 3;
.,,
第 8章 行 为 建 模 79下载
r e l e a s e C o l t; // C o l t值变为 5。
.,,
f o r c e C o l t[1:0] = 3; /*错误:寄存器的部分选择不能设为过程性连续赋值的目标 * /
C o l t的第 1次释放促使 C o l t的值被保持为 1。这是因为在 f o r c e语句被应用时没有过程性连续赋值对寄存器赋值。在后面的 r e l e a s e语句中,C o l t因为过程性连续赋值在 C o l t上重新生效而重新获得值 5。
8.9 握手协议实例
a l w a y s语句可用于描述交互进程的行为,如有限状态机的交互。这些模块内的语句用对所有 a l w a y s语句可见的寄存器来相互通信。在 a l w a y s语句间使用在一个 a l w a y s语句内声明的寄存器变量传递信息并不可取(这可以使用层次路径名实现,见第 1 0章) 。
考虑下面两个交互进程的实例,R X,接收器; M P,微处理器。 R X进程读取串行的输入数据。
并发送 R e a d y信号表明数据可被读入 M P进程。 M P进程在将数据分配给输出后,回送一个接收信号 A c k到 R X进程以读取新的输入数据。两个进程的语句块流程如图 8 - 8所示。
图 8-8 两个交互进程这两个交互进程的行为可用下述行为模型加以描述:
' t i m e s c a l e 1 n s / 1 0 0 p s
m o d u l e I n t e r a c t i n g (S e r i a l _ I n,C l k,P a r a l l e l _ O u t)
i n p u t S e r i a l _ I n,C l k;
o u t p u t [0:7] P a r a l l e l _ O u t;
r e g [0:7] P a r a l l e l _ O u t;
r e g R e a d y,A c k;
w i r e [0:7] d a t a;
' i n c l u d e "Read_Word.v" //R e a d _ W o r d任务在此文件中定义。
a l w a y s
b e g i n,R X
R e a d _ W o r d(S e r i a l _ I n,C l k,D a t a) ;
/ /任务 R e a d _ W o r d在每个时钟周期读取串行数据,将其转换为并行数据并存于 D a t a中。 R e a d _ W o r d完成上述任务需要 1 0 n s。
R e a d y = 1;
w a i t(A c k) ;
R e a d y = 0;
# 4 0 ;
e n d
a l w a y s
b e g i n,M P
# 2 5 ;
80 Verilog HDL 硬件描述语言 下载
P a r a l l e l _ O u t = D a t a;
A c k = 1;
#25 A c k = 0;
w a i t (r e a d y) ;
e n d
e n d m o d u l e
这两个进程通过寄存器 R e a d y和 A c k的交互握手协议如图 8 - 9中的波形显示。
图 8-9 两进程间的握手协议习题
1,initial语句和 a l w a y s语句,哪一种可重复执行?
2,顺序语句块和并行语句块的区别是什么?举例说明。顺序语句块能否出现在并行语句块中?
3,语句块在什么时候需要标识符?
4,在 a l w a y s语句中是否有必要指定时延?
5,语句内部时延和语句间时延的区别是什么?举例说明。
6,阻塞性赋值和非阻塞性赋值有何区别?
7,casex语句与 c a s e语句有何区别?
8,能否在 a l w a y s语句中为线网类型(例如 w i r e型线网)赋值?
9,产生一个在 5 ns时刻开始、周期为 10 ns的时钟波形。
10,用一个 i n i t i a l语句和 1个 f o r e v e r循环语句替代下述 a l w a y s语句。
a l w a y s
@ (E x p e c t e d o r O b s e r v e d)
if (E x p e c t e d !== O b s e r v e d) b e g i n
$d i s p l a y ("MISMATCH,Expected = %b,Observed = %b"
Expected,Observed) ;
$s t o p;
e n d
11,按如下条件,两个 a l w a y s语句中 N e x t S t a t e A和 N e x t S t a t e B上的值是多少,C l o c k P在 5 ns时有 1
个正沿; C u rre n t S t a t e在时钟边沿前值为 5,并且在时钟沿 3 ns后改变为 7?
a l w a y s
@ (p o s e d g e C l o c k P)
#7 N e x t S t a t e A = C u r r e n t S t a t e;
第 8章 行 为 建 模 81
读取新的串行数据
MP的数据输出下载
a l w a y s
@ (p o s e d g e C l o c k P)
N e x t S t a t e = #7 C u r r e n t S t a t e;
12,使用行为建模方式写出如下有限状态机模型的行为描述。
I n p ( G a k ) P r e s e n t S t a t e N e x t S t a t e O u t p u t ( Z u k )
0 NO_ONE NO_ONE 0
1 NO_ONE ONE_ONE 0
0 ONE_ONE ONE_ONE 0
1 ONE_ONE TWO_ONE 0
0 TWO_ONE NO_ONE 0
1 TWO_ONE THREE_ONE 1
0 THREE_ONE NO_ONE 0
1 THREE_ONE THREE_ONE 1
13,使用 a l w a y s语句描述 J K触发器的行为功能。
14,描述如下电路行为:该电路在每一个时钟下跳沿(负沿)检查输入数据,当输入数据 U s g
为 1 0 11时,输出 A s m被置为 1。
15,描述多数逻辑电路行为。输入为 1 2位的向量。如果其中 1的数量超过 0的数量,输出设置为
1。当 D a t a _ R e a d y为 1时,才对输入数据进行检查。
82 Verilog HDL 硬件描述语言 下载