下载第 12章 建 模 实 例本章给出了一些用 Verilog HDL编写的硬件建模实例。
12.1 简单元件建模连线是一种最基本的硬件单元。连线在 Verilog HDL中可被建模为线网数据类型。考虑 4
位与门,其行为描述如下:
` t i m e s c a l e 1 n s / 1 n s
m o d u l e And4 (A,B,C) ;
i n p u t [3:0] B,C;
o u t p u t [3:0] A;
assign #5 A = B & C;
e n d m o d u l e
& (与 )逻辑的时延定义为 5 ns。这个模型代表的硬件如图 1 2 - 1所示。
图 12-1 一个 4位与门本实例和下面的实例表明布尔等式如何在连续赋值语句中被建模为表达式。连线单元能被建模为线网数据类型。例如,在下面的描述中,F表示将 ~ (非 )操作符的输出连接到 ^ (异或 )
操作符输入的线网。该模块表示的电路如图 1 2 - 2所示。
m o d u l e B o o l e a n _ E x (D,G,E,) ;
i n p u t G,E;
o u t p u t D;
w i r e F;
assign F =? E;
a s s i g n D = F ^ G;
e n d m o d u l e
考虑下列行为和如图 1 2 - 3所示相应硬件的表示。
m o d u l e A s y n c h r o n o u s;
w i r e A,B,C,D;
a s s i g n C = A| D
a s s i g n A = ~ (B & C) ;
e n d m o d u l e
门时延为 5 ns
图 12-2 组合电路图 12-3 异步反馈环路该电路带有一个异步反馈环路。如果模型用特定的值集 (B=1,D= 0 )仿真,仿真时间将由于仿真器总在两个赋值语句间迭代而永远停滞不前。迭代时间是两个零时延。因此,在使用带有零时延的连续赋值语句对线网赋值,以及在表达式中使用相同的线网值时,必须格外小心。
在特定的情况下,有时需要使用这样的异步反馈。下面将演示一个这样的异步反馈;语句代表一个周期为 20 ns的周期性波形。其硬件表示如图 1 2 - 4所示。注意这样的 always 语句需要一个 initial 语句将寄存器初始化为 0或 1,否则寄存器的值将固定在值 x上。
r e g A c e;
i n i t i a l
Ace = 0;
a l w a y s
#10 Ace = ~ Ace;
向量线网或向量寄存器型元件能被访问,既可以访问称为位选择的单个元素,也可以访问称为部分选择的片段。例如,
r e g A;
r e g [0:4] C;
r e g [ 5,0 ] B,D;
always
b e g i n
.,,
D [4:0] = B [5:1] | C; //D [ 4,0 ]和 B[ 5,1 ]都是部分选择。
D [5] = A & B [5]; //D [ 5 ]和 B[ 5 ]都是位选择。
e n d
第一个过程性赋值语句暗示着:
D [4] = B [5] | C [0];
D [3] = B [4] | C [ 1 ] ;
.,,
位选择、部分选择和向量可以并置,形成更大的向量。如,
wire [7:0] C,CC;
wire C X;
.,,
a s s i g n C = {CX,CC [ 6,0 ] } ;
也可以引用索引值在运行时才可计算的向量元素。如,
Adf = Plb[ K ] ;
意味着解码器的输出为 A d f,并且 K指定选择地址。 P l b是向量;本语句对解码器的行为建模。
可以使用预定义的移位操作符执行移位操作。移位操作可以用合并操作符建模。例如,
wire [0:7] A,Z;
.,,
a s s i g n Z = {A [1:7],A [0]}; //循环左移。
a s s i g n Z = {A [7],A [0:6]}; //循环右移。
a s s i g n Z = {A [1:7],1'b0}; //左移操作。
向量的子域称为部分选择,也能够在表达式中使用。例如,3 2位指令寄存器 I n s t r _ R e g中前 1 6位表示地址,接下来 8位表示操作码,余下的 8位表示索引。给出如下说明:
第 12章 建 模 实 例 137下载图 12-4 时钟发生器
r e g [31:0] Memory [0,1023 ];
w i r e [31:0] I n s t r _ R e g ;
w i r e [15:0] A d d r e s s ;
w i r e [7:0] Op_Code,Index;
w i r e [ 0,9 ] P r o g _ C t r ;
w i r e R e a d _ C t l;
从 I n s t r _ R e g读取子域信息的一种方法是使用三个连续赋值语句。指令寄存器的部份选择被赋值给指定的线网。
a s s i g n INstr_Reg = Memory[P r o g _ C t r] ;
a s s i g n Address = Instr_Reg[ 3 1,1 6 ] ;
a s s i g n Op_Code = Instr_Reg[ 1 5,8 ] ;
a s s i g n Index = Instr_Reg[ 7,0 ] ;
.,,
a l w a y s
@ (p o s e d g e R e a d _ C t l)
Task_Call ( Address,Op_Code,Index) ;
可用连续赋值语句为三态门的行为建模,如:
w i r e Triout = Enable? TriIN,1 ' b z ;
当 E n a b l e为 1时,Tr i O u t获得 Tr i I n的值。当 E n a b l e为 0时,Tr i O u t为高阻值。
12.2 建模的不同方式本节给出了 Verilog HDL语言提供的三种不同建模方式的实例:数据流方式、行为方式和结构方式。参看图 1 2 - 5所示的电路,该电路将输入 A的值存入寄存器,然后与输入 C相乘。
第一种建模方式是数据流方式,它使用连续赋值语句对电路建模。
m o d u l e Save_Mult_Df (A,C,C l k B,Z) ;
i n p u t [0:7] A;
i n p u t [0:3] C;
i n p u t C l k B;
o u t p u t [ 0,1 1 ] Z;
w i r e S 1;
a s s i g n Z = S1 * C;
assign S1 = ClkB? A,S1;
e n d m o d u l e
这种表示方法不直接蕴含任何结构,却隐式地描述了结构。但是,它的功能性非常清晰。
寄存器已使用时钟控制方式建模。
第二种描述电路的方法是使用带有顺序程序块的 always 语句,将电路建模为顺序程序描述。
m o d u l e S a v e _ M u l t _ S e q (A,C,C l k B,Z);
i n p u t [0:7] A ;
i n p u t [0:3] C ;
i n p u t C l k B;
138 Verilog HDL 硬件描述语言 下载图 12-5 带缓冲的乘法器寄存器
o u t p u t [ 0,1 1 ] Z;
r e g [0:11] Z;
a l w a y s
@(A o r C o r C l k B)
b e g i n,SEQ
/ /由于标记了程序块,可以说明一个局部寄存器变量 S 1。
r e g [0:7] S 1;
i f (C l k B)
S1 = A;
Z = S1 * C;
e n d
e n d m o d u l e
这种模型也描述了电路的行为,但是没有蕴含任何结构,无论是隐式还是显示的。在这种方式中,寄存器用 i f语句建模。
第三种描述 S a v e _ M u l t电路的方法是假定已存在 8位寄存器和 8位乘法器,将电路建模为线网表。
m o d u l e S a v e _ M u l t _ N e t l i s t (A,C,C l k B,Z)
i n p u t [0:7] A ;
i n p u t [0:3] C ;
i n p u t C l k B ;
o u t p u t [0:11] Z;
w i r e [0:7] S 1,S 3;
W i r e [0:15] S 2;
R e g 8 R 1 (,D i n(A),.C l k(C l k B),.D o u t(S 1) ) ;
M u l t 8 M 1 (,A(S 1),.B( { 4′ 1 b 0 0 0 0,C} ),.Z(Z) ) ;
e n d m o d u l e
这种描述方式显式地描述了电路结构,但其行为是未知的。这是因为 R e g 8和 M u l t 8的模块名是任意的,并且它们可以有与其相关的各种行为。
12.3 时延建模考虑 3输入或非门。它的行为可以使用连续赋值语句建模,如
a s s i g n #12 Gate_Out =? (A | B | C) ;
这条语句对带有 1 2个时间单位时延的或非门建模。这一时延表示从信号 A,B或 C上事件发生到结果值出现在信号 G a t e _ O u t上的时间。一个事件可以是任何值的变化,如 x -> z,x - > 0,
或者 1- > 0。
如果要显式地对上升和下降时间建模,则在连续赋值语句中使用两个时延,例如:
a s s i g n #(12,14) Zoom =? (A | B | C) ;
/ * 1 2是上升时延,1 4是下降时延,min(12,14) = 12是转换到 x的时延 * /
在能够对高阻值 Z赋值的逻辑中,也能够定义第三种时延,即关断时延。例如:
a s s i g n #(12,14,10) Z o o m = A > B? C,1bz;
/ /上升时延为 1 2,1 4是下降时延,m i n ( 1 2,1 4,10) = 12是转换到 x的时延,关断时延为 1 0。
每个时延值都能够用 m i n,t y p,m a x表示,例如,
第 12章 建 模 实 例 139下载
a s s i g n #(9:10:11,11:12:13,13:14:15) Z o o m = A > B? C,1bz;
时延值通常可以是表达式。
基本门和 U D P中的时延可以通过在实例中指定时延值建模。下面是 5输入基本与门。
a n d #(2,3) A 1(O t,I n 1,I n 2,I n 3,I n 4,I n 5) ;
已指定输出的上升时延为 2个时间单位,下降时延为 3个时间单位。
模型中位于端口边界的时延可使用指定程序块来定义。如下面的半加器模块的例子。
m o d u l e H a l f _ A d d e r(A,B,S,C) ;
i n p u t A,B;
o u t p u t S,C;
s p e c i f y
(A => S) = (1.2,0.8);
(B => S) = (1.0,0.6);
(A => C) = (1.2,1.0);
(B => C) = (1.2,0.6);
e n d s p e c i f y
a s s i g n S = A ^ B;
a s s i g n C = A | B;
e n d m o d u l e
除在连续赋值语句中对时延建模外,时延还可以用指定程序块建模。是否存在一种从模块外部指定时延的方法?一种选择是使用 S D F (标准时延格式)和 Ve r i l o g仿真器可能提供的反标机制。如果需要在 Verilog HDL模型中显式地指定这一信息,一种方法是在 H a l f - A d d e r模块上创建两个虚模块,每个模块带有不同的时延集。
m o d u l e H a l f _ A d d e r(A,B,S,C);
i n p u t A,B ;
o u t p u t S,C ;
a s s i g n S = A ^ B;
a s s i g n C = A | B;
e n d m o d u l e
module H a _ O p t(A,B,S,C);
i n p u t A,B ;
o u t p u t S,C ;
s p e c i f y
(A => S) = (1.2,0.8);
(B => S) = (1.0,0.6);
(A => C) = (1.2,1.0);
(B => C) = (1.2,0.6);
e n d s p e c i f y
Half_Adder H1 (A,B,S,C) ;
e n d m o d u l e
m o d u l e H a l f _ P e s s(A,B,S,C) ;
140 Verilog HDL 硬件描述语言 下载见参考文献
i n p u t A,B;
o u t p u t S,C ;
s p e c i f y
(A => S) = (0.6,0.4);
(B => S) = (0.5,0.3);
(A => C) = (0.6,0.5);
(B => C) = (0.6,0.3);
e n d s p e c i f y
Half_Adder H2(A,B,S,C) ;
e n d m o d u l e
有了这两个模块,H a l f _ A d d e r模块独立于任何时延,并且依赖于你所选用的时延方式,
即模拟相应的高层模块 H a _ O p t或 H a _ P e s s。
传输时延在连续赋值语句和门级原语模型中指定的时延为惯性时延。传输时延能够用带有语句内时延的非阻塞性赋值语句建模。实例如下,
m o d u l e T r a n s p o r t (W a v e A,D e l a y e d W a v e) ;
p a r a m e t e r T R A N S P O R T _ D E L A Y = 500;
i n p u t W a v e A;
o u t p u t D e l a y e d W a v e;
r e g D e l a y e d W a v e ;
a l w a y s
@ (W a v e A) DelayedWave <= #TRANSPORT_DELAY WaveA;
e n d m o d u l e
a l w a y s语句中包含带有语句内时延的非阻塞性赋值。 Wa v e A上的任何变化以后都会使
D e l a y e d Wa v e在延迟 T R A N S P O RT _ D E L AY时获得调度。结果在 Wa v e A上出现的波形在被延迟
T R A N S P O RT _ D E L AY后出现在 D e l a y e d Wa v e上;这种时延波形的实例如图 1 2 - 6所示。
图 12-6 传输时延实例
12.4 条件操作建模在特定条件下发生的操作可以使用带有条件操作符的连续赋值语句,或在 a l w a y s语句中用 i f语句或 c a s e语句建模。请看一个算术逻辑电路。它的行为可用如下所示的连续赋值语句建模。
m o d u l e S i m p l e _ A L U(A,B,C,PM,ALU) ;
i n p u t [0:3] A,B,C;
i n p u t P M;
第 12章 建 模 实 例 141下载
o u t p u t [0:3] A L U;
a s s i g n A L U = P M? A + B,A - B;
e n d m o d u l e
多路选择开关也能够使用 always 语句建模。首先确定选线的值,然后,c a s e语句根据这个值选择相应的输入赋值到输出。
` t i m e s c a l e 1 n s / 1 n s
module M u l t i p l e x e r(Sel,A,B,C,D,Mux_Out) ;
i n p u t [0:1] S e l;
i n p u t A,B,C,D;
o u t p u t M u x _ O u t ;
r e g M u x _ O u t;
reg T e m p;
p a r a m e t e r MUX_DELAY = 15;
a l w a y s
@ (Sel o r A o r B o r C o r D)
b e g i n,P 1
c a s e (S e l)
0,T e m p = A;
1,T e m p = B;
2,T e m p = C;
3,T e m p = D;
e n d c a s e
M u x _ O u t = # MUX_DELAY Temp;
e n d
e n d m o d u l e
多路选择开关也可以用如下形式的连续赋值语句建模:
a s s i g n #MUX_DELAY Mux_Out = (Sel == 0)? A,(Sel == 1)? B,
(S e l == 2)? C,(S e l == 3)? D,1'b x;
12.5 同步时序逻辑建模到目前为止,本章中的绝大多数实例都是组合逻辑。对于同步时序逻辑建模,语言中已提供寄存器数据类型对寄存器和存储器建模。但是并不意味着每种寄存器数据类型都可对同步时序逻辑建模。通过控制赋值方式对同步时序逻辑建模是一种常见的方法。
参见如下实例,它表明了如何通过控制寄存器对同步边沿触发的 D型触发器建模。
` t i m e s c a l e 1 n s / 1 n s
m o d u l e D _ F l i p _ F l o p (D,Clock,Q) ;
i n p u t D,Clock;
o u t p u t Q;
r e g Q;
a l w a y s
@ (p o s e d g e C l o c k)
Q = #5 D;
e n d m o d u l e
a l w a y s语句表明当 C l o c k上出现上升沿时,Q会在 5 ns后被赋值为 D;否则 Q不发生变化
(寄存器在被赋新值前保持原值) 。 a l w a y s语句中的行为表达了 D型触发器的语义。提供这一模
142 Verilog HDL 硬件描述语言 下载型后,8位寄存器可按如下方式进行建模。
m o d u l e Register8 (D,Q,Clock) ;
p a r a m e t e r START = 0,S T O P = 7;
i n p u t [START,STOP] D;
i n p u t C l o c k;
o u t p u t [START,STOP ] Q;
w i r e [START,STOP] C a k;
D_Flip_Flop DFF0
[START,STOP] (,D (D),,Clock (C a k),.Q (Q) ) ;
b u f B 1 (C a k [0],Cak [1],C a k [2],C a k [3],C a k [4],
C a k [5],Cak [6],Cak [7],C l o c k) ;
e n d m o d u l e
考虑如图 1 2 - 7所示的门级交叉耦合锁存器电路及其数据流模型。
图 12-7 门级锁存器
m o d u l e G a t e d _ F F (A,G,Q,Qbar) ;
i n p u t A,G;
o u t p u t Q,Qbar;
w i r e S1,S2;
a s s i g n S 1 = ~ (A & G) ;
a s s i g n S 2 = ~ (S1 & G) ;
a s s i g n Q = ~ (Qbar & S1) ;
a s s i g n Qbar = ~ (Q & S2) ;
endmodule
在此例中,连续赋值语句的语义蕴含了锁存器结构。
存储器可用寄存器数组建模。实例如下,其中 A S I Z E是地址端口的位数,D S I Z E是 R A M数据端口的位数。
m o d u l e RAM_Generic (Address,Data_In,Data_out,RW) ;
p a r a m e t e r A S I Z E = 6,D S I Z E = 4;
i n p u t [A S I Z E-1,0] A d d r e s s;
i n p u t [D S I Z E-1,0] D a t a _ I n;
i n p u t R W;
o u t p u t [D S I Z E-1,0] D a t a _ O u t;
r e g [D S I Z E- 1:0] D a t a _ O u t;
r e g [0,D S I Z E- 1] M e m _ F F [ 0,6 3 ] ;
a l w a y s
@ (R W)
if (R W) // 从 R A M中读取数据。
Data_Out = Mem_FF [A d d r e s s] ;
第 12章 建 模 实 例 143下载
e l s e / /向 R A M写入数据。
M e m _ F F [A d d r e s s] = D a t a _ I n;
endmodule
同步时序逻辑也可以用电平敏感或边沿触发控制方式建模。电平敏感类型锁存器建模实例如下。
m o d u l e Level_Sens_FF (Strobe,D,Q,Qbar) ;
i n p u t Strobe,D;
o u t p u t Q,Qbar;
r e g Q,Qbar;
a l w a y s
b e g i n
wait (Strobe = = 1);
Q = D;
Q b a r = ~ D;
e n d
endmodule
当 s t ro b e为 1时,D上的任何事件都被传输到 Q;当 S t ro b e变成 0时,Q和 Q b a r中的值保持不变,并且输入 D上的任何变化都不再影响 Q和 Q b a r上的值。
理解过程性赋值语句的语义对决定同步时序逻辑的行为功能非常重要。考虑模块 B o d y 1和
B o d y 2之间的不同之处。
m o d u l e B o d y 1;
r e g A;
i n i t i a l A = 0;
a l w a y s A = ~ A;
e n d m o d u l e
m o d u l e B o d y 2;
w i r e C l o c k;
r e g A;
i n i t i a l A = 0;
always
@ (Clock )
i f (~ Clock)
A = ~ A;
e n d m o d u l e
模块 B o d y 1蕴含的电路结构如图 1 2 - 8所示,而模块 B o d y 2蕴含的电路结构如图 1 2 - 9所示。
如果 B o d y 1按如上所述进行模拟,模拟将由于零时延异步反馈而陷入死循环(模拟时间停止不前) 。在模块 Body 2中,A的值只有在 C l o c k信号下降沿时锁存,在其他情形下( C l o c k不处在上升沿时),A上的任何变化(触发器的输入)都不会影响触发器的输出。
144 Verilog HDL 硬件描述语言 下载图 12-8 不蕴含触发器图 12-9 蕴含触发器触发器
12.6 通用移位寄存器通用串行输入、串行输出移位寄存器能够使用 a l w a y s语句块内的 f o r循环语句建模。寄存器的数量被定义为参数,这样通用移位寄存器的数量在其他设计中被引用时,可以修改。
m o d u l e S h i f t _ R e g (D,Clock,Z) ;
i n p u t D,Clock;
o u t p u t Z;
p a r a m e t e r NUM_REG = 6,
r e g [1,N U M _ R E G ] Q;
i n t e g e r P;
a l w a y s
@ (n e g e d g e C l o c k) b e g i n
/ /寄存器右移一位:
for (P = 1; P< N U M _ R E G; P = P + 1)
Q[P+1] = Q[P] ;
/ /加载串行数据:
Q[1] = D;
e n d
/ /从最右端寄存器获取输出:
a s s i g n Z = Q [NUM_REG];
e n d m o d u l e
可以通过用不同的参数值引用模块 S h i f t _ R e g获取不同长度的移位寄存器。
m o d u l e D u m m y;
w i r e Data,Clk,Za,Zb,Zc;
/ / 6位移位寄存器:
Shift_Reg SRA (Data,Clk,Za) ;
/ / 4位移位寄存器:
Shift_Reg # 4 SRB (Data,Clk,Zb) ;
/ / 1 0位移位寄存器:
Shift_Reg #10 SRC (Data,Clk,Zc) ;
e n d m o d u l e
12.7 状态机建模状态机通常可使用带有 a l w a y s语句的 c a s e语句建模。状态信息存储在寄存器中。 c a s e语句的多个分支包含每个状态的行为。下面是表示状态机简单乘法算法的实例。当 R e s e t信号为高时,累加器 A c c和计数器 C o u n t被初始化。当 R e s e t变为低时,乘法开始运算。如果乘数 M p l r在
C o u n t位的值为 1,被乘数加到累加器上。然后,被乘数左移 1位且计数器加 1。如果 C o u n t是 1 6,
乘法运算完成,并且 D o n e信号被置为高。如若不然,检查乘数 M p l r的 C o u n t位,并重复 a l w a y s
语句。状态图如图 1 2 - 1 0所示,其后是相应的状态机模型。
第 12章 建 模 实 例 145下载图 12-10 乘法器的状态图
m o d u l e Multiply (Mplr,Mcnd,Clock,Reset,Done,Acc) ;
/ / M p l r是乘数,M c n d是被乘数。
i n p u t [15:0] Mplr,Mcnd;
i n p u t Clock,Reset;
o u t p u t D o n e;
r e g D o n e;
o u t p u t [31:0] A c c;
reg [31:0] A c c;
p a r a m e t e r I N I T = 0,A D D = 1,SHIFT = 2;
r e g [0:1] M p y _ S t a t e;
r e g [31:0] M c n d _ T e m p;
i n i t i a l Mpy_State = I N I T; //初始状态为 I N I T。
a l w a y s
@ (n e g e d g e C l o c k) b e g i n,P R O C E S S
i n t e g e r C o u n t ;
c a s e (M p y _ S t a t e)
I N I T:
i f (R e s e t)
M p y _ S t a t e = I N I T;
/ *由于 M p y _ S t a t e将保持原值,上面的语句并不需要 * /。
e l s e
b e g i n
A c c = 0;
C o u n t = 0;
M p y _ S t a t e = A D D;
Done = 0;
M c n d _ T e m p [15:0] = M c n d;
M c n d _ T e m p [31:16] = 16'd 0 ;
e n d
A D D:
b e g i n
i f (Mplr [C o u n t] )
A c c = Acc + Mcnd_Temp;
M p y _ S t a t e = S H I F T ;
e n d
S H I F T:
146 Verilog HDL 硬件描述语言 下载复位 ACC.
如果 Mplr[Count]=1 将
Mcnd 加到 Acc
递增 Count左移 Mcnd
初始化 Count
b e g i n
/ /M c n d _ T e m p左移:
Mcnd_Temp = {Mcnd_Temp [30:0],1'b 0 } ;
Count = Count+ 1;
i f (Count == 16)
b e g i n
M p y _ S t a t e = I N I T;
Done = 1;
e n d
e l s e
M p y _ S t a t e = A D D;
end
e n d c a s e / /对 M p y _ S t a t e的 c a s e语句结束。
e n d / /顺序程序块 P R O C E S S。
endmodule
寄存器 M p y _ S t a t e保存状态机模型的状态。最初,状态机模型处于 I N I T状态,并且只要
R e s e t为真,模型就停留在这一状态。当 R e s e t为假时,累加器 A c c被清空。计数器 C o u n t被复位,
被乘数 M c n d被加载到临时变量 M c n d _ Te m p中,然后模型状态前进到状态 A D D。当模型处于
A D D状态时,只有当乘数在 C o u n t位置的位为 1时,M c n d _ Te m p中的被乘数才被加到 A c c上,然后模型状态前进到 S H I F T状态。在这一状态,乘法器再一次左移,计数器加 1;并且如果计数器值为 1 6,D o n e置为真,模型返回到 I N I T状态。此时,a c c包含乘法运算的结果。如果计数器值小于 1 6,模型本身反复通过 A D D和 S H I F T状态直到计数器值变为 1 6。
状态转换发生在时钟的各个下跳沿;这通过使用@ (n e g e d g e C l o c k)时序控制来指定。
12.8 交互状态机交互状态机能够使用通过公共寄存器通信的独立的 a l w a y s语句进行描述。考虑图 1 2 - 11所示的两个交互进程的状态图,T X是一个发送器,M P是一个微处理器。如果进程 T X不忙,进程 M P将要发送的数据放置在数据总线上,然后向进程 T X发送信号 L o a d _ T X,通知其装载数据并开始发送数据。进程 T X在数据传送期间设置 T X _ B u s y表明其处于忙状态,不能从进程 M P接收任何进一步的数据。
下面显示了这两个交互进程的框架模型,图中仅显示了控制信号和状态转换,没有描述操作数据的代码。
图 12-11 两个交互进程的状态图第 12章 建 模 实 例 147
进程进程
(注意:园括号中的表达式表示控制 )
下载
m o d u l e Interacting_FSM (C l o c k) ;
i n p u t C l o c k;
p a r a m e t e r M1 = 0,M2 = 1,M3 = 2;
p a r a m e t e r T1 = 0,T2 = 1; T3 = 2,T4 = 3;
r e g [0:1] M P _ S t a t e;
r e g [0:1] T X _ S t a t e;
r e g Load_TX,TX_Busy;
a l w a y s
@ (n e g e d g e C l o c k) b e g i n,MP
c a s e (M P _ S t a t e)
M 1,//向数据总线装载数据。
b e g i n
Load_TX = 1;
M P _ S t a t e = M2;
e n d
M 2,//等待确认信号。
if (T X _ B u s y)
b e g i n
MP_State = M3;
Load_MX = 0;
e n d
M 3,//等待进程 T X结束。
if (~ T X _ B u s y)
MP_State = M1;
e n d c a s e
end / /顺序块 M P结束。
a l w a y s
@ (n e g e d g e C l o c k) b e g i n,TX
c a s e (T X _ S t a t e)
T 1,//等待装载的数据。
i f (L o a d _ T X)
b e g i n
TX_State = T2;
T X _ B u s y = 1;//从数据总线中读取数据。
e n d
T 2,//发送开始标志。
TX_State = T3;
T3,/ /传送数据。
TX_State = T4;
T 4,//发送跟踪标志以结束传送。
b e g i n
TX_Busy = 0;
T X _ S t a t e = T1;
148 Verilog HDL 硬件描述语言 下载
e n d
e n d c a s e
e n d / /顺序块 T X结束。
endmodule
此交互有限状态机的时序行为关系如图 1 2 - 1 2所示。
图 12-12 两个交互进程的时序行为考虑两个交互进程的另外一个实例,时钟分频器 D I V和接收器 R X。在这种情况下,进程
D I V产生一个新时钟,并且进程状态变换(转换)序列与新时钟同步。状态图如图 1 2 - 1 3所示。
图 12-13 DIV产生 RX的时钟
m o d u l e A n o t h e r _ E x a m p l e _ F S M 2 (C l o c k) ;
i n p u t C l o c k ;
p a r a m e t e r D 1 = 1,D 2 = 2,D 3 = 3;
p a r a m e t e r R 1 = 1,R 2 = 2;
r e g [0:1] Div_State,RX_State;
r e g N e w _ C l o c k ;
a l w a y s
@ (p o s e d g e C l o c k) begin,DIV
c a s e (D i v _ S t a t e)
D 1:
b e g i n
D i v _ S t a t e = D2;
New_Clock = 0;
e n d
D 2:
Div_State = D3;
第 12章 建 模 实 例 149下载进程 进程
D 3,
b e g i n
New_Clock = 1;
D i v _ S t a t e = D1;
e n d
e n d c a s e
end / /顺序块 D I V结束。
a l w a y s
@ (n e g e d g e N e w _ C l o c k) b e g i n,R X
c a s e (R X _ S t a t e)
R1,RX_State= R 2;
R2,RX_State = R 1;
e n d c a s e
end / /顺序块结束。
endmodule
顺序块 D I V在其状态序列转换过程中产生新时钟。这一进程的状态转换发生在时钟的上升沿。顺序块在 N e w _ C l o c k的每个下降沿执行。图 1 2 - 1 4显示了这些交互状态机的波形序列。
图 12-14 进程 RX和 DIV之间的交互
12.9 Moore有限状态机建模
M o o r e有限状态机( F S M)的输出只依赖于状态而不依赖其输入。这种类型有限状态机的行为能够通过使用带有在状态值上转换的 c a s e语句的 a l w a y s语句建模。图 1 2 - 1 5显示了 M o o r e有限状态机的状态转换图实例,接着是 M o o r e有限状态机对应的行为模型。
图 12-15 Moore机的状态图
m o d u l e Moore_FSM (A,Clock,Z) ;
i n p u t A,Clock;
150 Verilog HDL 硬件描述语言 下载
o u t p u t Z;
r e g Z;
p a r a m e t e r ST0 = 0,ST1 = 1,S T 2 = 2,ST3 = 3;
reg [ 0,1 ] M o o r e _ S t a t e;
a l w a y s
@ (n e g e d g e C l o c k)
c a s e (M o o r e _ S t a t e)
S T 0:
b e g i n
Z = 1;
i f ( A )
Moore_State = ST2;
e n d
S T 1:
b e g i n
Z = 0;
i f ( A )
Moore_State = ST3;
e n d
S T 2:
b e g i n
Z = 0;
i f ( ~ A )
M o o r e _ S t a t e = S T 1 ;
e l s e
Moore_State = S T 3 ;
e n d
S T 3:
b e g i n
Z = 1;
i f (A)
Moore_State = ST0;
e n d
e n d c a s e
e n d m o d u l e
12.10 Mealy型有限状态机建模在 M e a l y型有限状态机中,输出不仅依赖机器的状态而且依赖于它的输入。这种类型的有限状态机能够使用与 Moore FSM相似的形式建模。即使用 a l w a y s语句。为了说明语言的多样性,使用不同的方式描述 M e a l y机。这一次,我们用两条 a l w a y s语句,一条对有限状态机的同步时序行为建模,一条对有限状态机的组合部分建模。图 1 2 - 1 6给出了状态转换表的一个实例,
接着是相应的行为模型。
第 12章 建 模 实 例 151下载图 12-16 Mealy机状态转换表
m o d u l e M e a l y _ F S M (A,Clock,Z) ;
i n p u t A,Clock;
o u t p u t Z;
r e g Z;
p a r a m e t e r S T 0 = 0,ST1 = 1,ST2 = 2,ST3 = 3;
r e g [1:2] P_State,N_State;
a l w a y s
@ (n e g e d g e C l o c k) //同步时序逻辑部分。
P _ S t a t e = N _ S t a t e;
a l w a y s
@ (P_State or A) b e g i n,C O M B _ P A R T
c a s e (P _ S t a t e)
S T 0:
i f (A)
b e g i n
Z = 1;
N_State = S T 3;
e n d
else
Z = 0;
S T 1:
i f (A)
begin
Z = 0;
N_State = S T 0;
e n d
else
Z = 1;
S T 2:
i f (~ A)
Z = 0;
e l s e
b e g i n
Z = 1;
N_State = S T 1;
152 Verilog HDL 硬件描述语言 下载输入A
表中的项为次态和输出Z
当前状态
e n d
S T 3:
b e g i n
Z = 0;
i f (~ A)
N_State = S T 2;
e l s e
N_State = ST1;
e n d
e n d c a s e
e n d / /顺序块 C O M B _ P A R T结束。
e n d m o d u l e
在这种类型的有限状态机中,因为状态机的输出可以直接依赖独立于时钟的输入,将输入信号放入组合的部分时序程序块的事件列表中是非常重要的。因为 M o o r e有限状态机的输出只依赖于状态,并且状态转换在时钟上同步发生,在 M o o r e有限状态机中不会发生这种情况。
12.11 简化的 21点程序本节介绍简化的 2 1点程序的状态机描述。玩 2 1点程序需要一幅扑克牌。从 2到 1 0的牌取值与面值相同,牌 A的值可以为 1或者为 11。游戏的目标是接收一定数量随机产生的牌,总分
(所有牌值的总和)尽可能接近 2 1而又不超过 2 1。
当插入新牌时,C a rd _ R d y为真,并且 C a rd _ Va l u e为牌的值。 R e q u e s t _ C a rd表明程序何时就绪准备接收新牌。如果接收牌的序列总和超过 2 1,L o s t置为真,以表明牌序列已经输了;
否则 Wo n置为真以表明游戏已获胜。状态排序由时钟控制。图 1 2 - 1 7显示了 2 1点程序模块的输入和输出。
图 12-17 21点程序模块的外部视图程序的行为在如下的模块说明中描述。程序在总得分不大于 1 7前一直接收新牌。得分不超过 2 1时,第一个 A按 11取值;得分超过 2 1时,牌 A按减 1 0处理,即取值为 1。三个寄存器用于存储程序的值,To t a l保存总和,C u rre n t _ C a rd _ Va l u e保存读取的牌值(取值从 1到 1 0),
A e c _ A s _ 11用于记忆牌 A是否取值为 11而不是 1。 2 1点程序的状态存储在寄存器 B J _ S t a t e中。
m o d u l e Blackjack (Card_Rdy,Card_Value,
Request_Card,Won,Lost,Clock) ;
i n p u t Card_Rdy,Clock;
i n p u t [0:3] C a r d _ V a l u e;
o u t p u t Request_Card,Lost,Won;
reg Request_Card,Lost,Won;
Pa r a m e t e r INITIAL_ST = 0,GETCARD_ST = 1,
REMCARD_ST = 2,A D D _ S T = 3,CHECK_ST = 4,
第 12章 建 模 实 例 153下载
W I N _ S T = 5,BACKUP_ST = 6,LOSE_ST = 7;
r e g [0:2] B J _ S t a t e;
r e g [0:3] C u r r e n t _ C a r d _ V a l u e;
r e g [0:4] T o t a l;
r e g A c e _ A s _ 1 1;
a l w a y s
@ (n e g e d g e C l o c k)
c a s e (B J _ S t a t e)
INITIAL_ST,
b e g i n
T o t a l = 0;
A c e _ A s _ 1 1 = 0;
Won = 0;
L o s t = 0;
BJ_State = GETCARD_ST
e n d
G E T C A T D _ S T:
b e g i n
Request_Card = 1;
i f (C a r d _ R d y)
b e g i n
Current_Card_Value = Card_Value;
BJ_State = REMCATD_ST;
e n d / /否则停留在状态 G E T C A R D _ S T上不变。
e n d
R E M C A R D _ S T,//等待牌被移走。
i f (C a r d _ R d y)
Re q u e s t _ C a r d= 0 ;
e l s e
BJ_State = ADD_ST;
A D D _ S T:
b e g i n
i f (~Ace_As_11 && Current_Card_Value)
b e g i n
Current_Card_Value = 11;
Ace_As_11 = 1;
e n d
Total = Total + Current_Card_Value;
B J _ S t a t e = C H E C K _ S T;
e n d
C H E C K _ S T:
i f (Total < 17)
B J _ S t a t e = G E T C A R D _ S T;
e l s e
154 Verilog HDL 硬件描述语言 下载
begin
i f (Total < 2 2 )
B J _ S t a t e = W I N _ S T;
e l s e
BJ_State = B A C K U P _ S T;
e n d
B A C K U P _ S T:
i f (A c e _ A s _ 1 1)
b e g i n
Total = Total - 1 0 ;
A c e _ A s _ 1 1 = 0;
BJ_State = C H E C K _ S T;
e n d
e l s e
BJ_State = LOSE_ST;
L O S E _ S T:
b e g i n
L o s t = 1;
Request_Card = 1;
if (C a r d _ R d y)
BJ_State = I N I T I A L _ S T;
/ /否则停留在这个状态上不变。
e n d
W I N _ S T:
b e g i n
W o n = 1;
Request_Card = 1;
i f (C a r d _ R d y)
BJ_State = I N I T I A L _ S T;
/ /否则停留在这个状态上不变。
e n d
e n d c a s e
e n d m o d u l e / / 2 1点程序结束。
习题
1,为芒果汁饮料机编写一个 Verilog HDL模型。机器分发价值 1 5美分一听的芒果汁。只接收 5
分镍币和一角硬币。任何变化必须被返回。使用测试验证程序测试该模型。
2,编写一个模型,描述带有同步预置和清空的触发器模型行为。
3,编写带有串行数据输入、并行数据输入、时钟和并行数据输出的 4位移位寄存器模型。使用测试验证程序测试该模型。
4,使用行为构造方式描述 D型触发器。然后使用这一模块,编写一个 8位寄存器模型。
5,编写测试 1 2,11节描述的 2 1点游戏模型的测试验证程序。
6,使用移位操作符,描述解码器模块,然后使用测试验证程序测试该模块。解码器的输入数量指定为:
第 12章 建 模 实 例 155下载
` d e f i n e NUM_INPUTS 4
[提示:使用移动操作符计算解码器输出的数量。 ]
7,编写并行到串行的 8位转换器模型。输入为 8位向量,在时钟上升沿从左位开始一次发送出一位。只有在前面的输入向量的所有位都发送出去以后,才读入下一个输入。
8,编写与练习 7行为相反的串行到并行的 8位转换器。为体现传输时延,在时钟上升沿经过一小段时延后对输入流采样。使用高层模块将本练中编写的模型与练习 7编写的模型连接,并使用测试验证程序测试其输出。
9,编写具有保持控制的 N位计数器模型。如果保持为 1,计数器保持它的值,如果保持变为 0,
计数器被重置为 0,并再次启动计数器。编写测试验证程序测试该模型。
10,编写通用队列模型,队列中的字长为 N,字数为 M。 I n p u t D a t a 是被写入队列的字;当
A d d w o rd为 1时,向队列中添加字。从队列中读出的字存储在 Output Data中;当 Read Wo rd
为 1时,从队列中读取字。设置相应的标志 E m p t y 和 F u l l。所有的事务发生在时钟 C l o c k A的下降沿。编写测试验证程序测试该模型。
11,编写可参数化的时钟分频器模型。输出时钟的周期是输入时钟周期的 2 *N倍,输出时钟与输入时钟的上升沿同步。编写测试验证程序测试该模型的正确性。
156 Verilog HDL 硬件描述语言 下载