--遗漏条件“a=b”对应的操作
endif;
endprocess;
endBehavioral;
Port(a,b:
instd_logic;
q:
outstd_logic);
endcomp_2;
architectureBehavioralofcomp_2is
begin
process(a,b)
begin
ifa>bthenq<='1';
elseq<='0';
endif;
endprocess;
endBehavioral;
易见,程序1忽略了当“a=b”的情况,应为else语句囊括了与if语句所描述的情形相反的全部可能。
程序2则描述了所有的情况。
从两个程序的仿真结果图5.5.3和图5.5.4也可看出,图中,当a=b时,q有两种可能取值,而图中,q只有一种取值0。
这两个程序虽然很简单,错误也很明显,但类似的逻辑上的错误往往很容易犯,因此必须特别注意。
图5.5.3例5.5程序1仿真图
图5.5.4例5.5程序2仿真图
IF-ELSE语句的嵌套也是必须十分注意的,如果嵌套的层次没有分清,逻辑混乱,就得不到预期的功能,下面看例5.5.5例和5.5.6两个程序的对比:
例5.5.5取自于一个4位数码管动态显示的驱动器,该进程完成的是一个多位的计数器功能,从最低位起开始计数,满三进一(为方便观察仿真结果,实际应用多为十进制或六进制),计数的同时输出显示。
注意该IF-ElSE的嵌套最里一层位数最高,最低位在嵌套的最外层,循环次数最多。
【例5.5.5】
entitydt1is
Port(clk:
instd_logic;
reset:
instd_logic;
cnta0,cntb0,cntc0,cntd0:
outstd_logic_vector(3downto0));
enddt1;
architectureBehavioralofdt1is
begin
counter10:
process(reset,clk)
variablecnta,cntb,cntc,cntd:
std_logic_vector(3downto0);
begin
ifreset='0'then
cnta:
="0000";cntb:
="0000";cntc:
="0000";cntd:
="0000";
elsifrising_edge(clk)then
ifcnta="0011"thencnta:
="0000";cnta0<=cnta;--最低位
ifcntb="0011"thencntb:
="0000";cntb0<=cntb;
ifcntc="0011"thencntc:
="0000";cntc0<=cntc;
ifcntd="0011"thencntd:
="0000";cntd0<=cntd;--最高位
elsecntd:
=cntd+1;cntd0<=cntd;
endif;
elsecntc:
=cntc+1;cntc0<=cntc;
endif;
elsecntb:
=cntb+1;cntb0<=cntb;
endif;
elsecnta:
=cnta+1;cnta0<=cnta;
endif;
endif;
endprocess;
endBehavioral;
图5.5.5例5.5.5程序仿真图
但是,如果将程序中的IF-ELSE结构改成例5.5.6所示:
【例5.5.6】
entitydt2is
Port(clk:
instd_logic;
reset:
instd_logic;
cnta0,cntb0,cntc0,cntd0:
outstd_logic_vector(3downto0));
enddt2;
architectureBehavioralofdt2is
begin
counter10:
process(reset,clk)
variablecnta,cntb,cntc,cntd:
std_logic_vector(3downto0);
begin
ifreset='0'then
cnta:
="0000";cntb:
="0000";cntc:
="0000";cntd:
="0000";
elsifrising_edge(clk)then
ifcnta="0011"thencnta:
="0000";cnta0<=cnta;
elsecnta:
=cnta+1;cnta0<=cnta;endif;
ifcntb="0011"thencntb:
="0000";cntb0<=cntb;
elsecntb:
=cntb+1;cntb0<=cntb;endif;
ifcntc="0011"thencntc:
="0000";cntc0<=cntc;
elsecntc:
=cntc+1;cntc0<=cntc;endif;
ifcntd="0011"thencntd:
="0000";cntd0<=cntd;
elsecntd:
=cntd+1;cntd0<=cntd;endif;
endif;
endprocess;
endBehavioral;
图5.5.6例5.6.6程序仿真图
得到图5.5.6所示的仿真结果。
可见,结果不正确,因为IF语句在进程中结构是并行执行而不是顺序执行的。
5.5.4CASE语句
CASE语句与IF-ELSE语句的功能类似,在一些应用中,如编码器、译码器等,使用CASE语句更加方便。
CASE语句的使用要注意其在程序中的位置以及其起作用的时刻。
例如,为了得到一个分频系数可预置的分频器,例5.5.7和例5.5.8两个程序虽然都能通过综合,但得到的波形仿真却不同,如图5.5.7和图5.5.8。
前者的CASE语句受“clk”信号控制,实现了功能,而后者受“en”控制,得不到所需功能。
可见,CASE语句的位置不同,也会影响功能的实现。
【例5.5.7】
entitypulseis
Port(clk,en:
instd_logic;
k:
instd_logic_vector(3downto0);
clock:
outstd_logic);
endpulse;
architectureBehavioralofpulseis
begin
counter:
process(clk,en,k)
variablecnt0,cnt1,count:
integer:
=0;
variableclk0:
std_logic;
begin
ifen='0'then
count:
=0;
clk0:
='0';
casekis
when"0000"=>cnt0:
=1;cnt1:
=2;
when"0001"=>cnt0:
=2;cnt1:
=3;
when"0010"=>cnt0:
=3;cnt1:
=6;
when"0011"=>cnt0:
=3;cnt1:
=4;
whenothers=>cnt0:
=0;cnt1:
=0;
endcase;
elsifclk'eventandclk='1'then
count:
=count+1;
ifcount=cnt0then
clk0:
='1';
elsifcount=cnt1then
count:
=0;
clk0:
='0';
endif;
endif;
clock<=clk0;
endprocesscounter;
endBehavioral;
【例5.5.8】
entitypulsepis
Port(clk,en:
instd_logic;
k:
instd_logic_vector(3downto0);
clock:
outstd_logic);
endpulsep;
architectureBehavioralofpulsepis
begin
counter:
process(clk,en,k)
variablecnt0,cnt1,count:
integer:
=0;
variableclk0:
std_logic;
begin
ifen='0'then
count:
=0;
clk0:
='0';
elsifclk'eventandclk='1'then
count:
=count+1;
casekis
when"0000"=>cnt0:
=1;cnt1:
=2;
when"0001"=>cnt0:
=2;cnt1:
=3;
when"0010"=>cnt0:
=3;cnt1:
=6;
when"0011"=>cnt0:
=3;cnt1:
=4;
whenothers=>cnt0:
=0;cnt1:
=0;
endcase;
ifcount=cnt0then
clk0:
='1';
elsifcount=cnt1then
count:
=0;
clk0:
='0';
endif;
endif;
clock<=clk0;
endprocesscounter;
endBehavioral;
图5.5.7例5.5.7仿真图
图5.5.8例5.5.8仿真图
5.5.5多时钟源的解决方案
有时,在同一个实体中往往使用多个进程,而每个进程使用不同的时钟源驱动时,就会发生错误。
例如,由分频器产生多个不同频率的时钟脉冲去控制不同的部件时,如果每个进程都采用“ifclk’eventandclk=’1’then”这样的格式来描述时钟上升沿,综合将无法进行。
此时,可以用rising_edge来描述分频后得到的时钟的上升沿,就不会出错。
libraryIEEE;
useIEEE.STD_LOGIC_1164.ALL;
useIEEE.STD_LOGIC_ARITH.ALL;
useIEEE.STD_LOGIC_UNSIGNED.ALL;
entitymulticlockis
Port(clk:
instd_logic;
d0,d1:
instd_logic;
q0,q1:
outstd_logic);
endmulticlock;
architectureBehavioralofmulticlockis
signalclka,clke:
std_logic;
begin
main:
process(clk)
variablecount0,count1:
integer;
variableclk0,clk1:
std_logic;
begin
ifclk'eventandclk='1'then
count0:
=count0+1;count1:
=count1+1;
ifcount1=16then
clk1:
='1';
elsifcount1=32then
count1:
=0;
clk1:
='0';
endif;
ifcount0=8then
clk0:
='1';
elsifcount0=16then
count0:
=0;
clk0:
='0';
endif;
endif;
clka<=clk0;clke<=clk1;
endprocessmain;
second:
process(clka)
begin
ifclka'eventandclka='1'then
q0<=d0;
endif;
endprocesssecond;
third:
process(clke)
begin
ifclke'eventandclke='1'then
q1<=d1;
endif;
endprocess;
endBehavioral;
5.5.6仿真无波形
综合成功后进行波形仿真时常常会看不到波形,一般有两种可能:
第一种是仿真周期太长而无法看到,一般见于分频器或计数器中。
例如:
对一个32MHz的晶振进行分频,要求得到1Hz的信号。
这时要等32兆个CLK波形才能看到输出有跳变,在仿真图上当然是无法看到的,如果将分频系数减小,例如8分频,就可以看到仿真波形了。
一般分频系数大于几百时就会出现这种现象。
第二种是出现不定态(UNKNOWN),设计分频器时有这种情况,一般是由于没有对变量或信号进行初始化引起的,例如STD_LOGIC有七种逻辑状态,如果不指定其初始值是“0”还是“1”,系统就无法确定。
如例5.5.9及其仿真结果(图5.5.9)所示。
【例5.5.9】
entitypulseis
Port(clk:
instd_logic;
c:
outstd_logic);
endpulse;
architectureBehavioralofpulseis
begin
process(clk)
variabledd:
integer;
begin
ifclk'eventandclk='1'then
dd:
=dd+1;
ifdd=4thenc<='0';
elsifdd=8thenc<='1';dd:
=0;
endif;
endif;
endprocess;
图5.5.9例5.5.9仿真图(无输出波形)
为解决该问题,可以在定义变量或信号时指定其初始状态。
将例中的“variabledd:
integer;”改为“variabledd:
integer:
=0;”,就能得到如图5.5.10所示的波形了。
图5.5.10例5.9改正后的仿真图(正确的波形)
另一种办法是增加一个清零或置位信号,通过一个清零或置位信号对信号或变量进行初始化,如例5.5.10所示。
得到的结果如图5.5.10所示。
【例5.5.10】
entitypppis
Port(clk,en:
instd_logic;
c:
outstd_logic);
endppp;
architectureBehavioralofpppis
begin
process(clk,en)
variabledd:
integer;
begin
ifen='0'thendd:
=0;--增加了清零信号
elsifclk'eventandclk='1'thendd:
=dd+1;
ifdd=4thenc<='0';
elsifdd=8thenc<='1';dd:
=0;
endif;
endif;
endprocess;
图5.5.11例5.50程序仿真图
5.5.7执行时端口丢失
当综合与仿真完成后,就要进行引脚锁定(EditImplementationConstraite),执行引脚锁定时,有时会发现Port表找不到某些定义过的端口。
例如下面一段程序:
【例5.5.11】
entityloseportis
Port(clk,en:
instd_logic;
c:
outstd_logic);
endloseport;
architectureBehavioralofloseportis
begin
process(clk,en)
variabledd:
integerrange0to256;--变量范围
begin
ifen='0'then
dd:
=0;
elsifclk'eventandclk='1'then
dd:
=dd+1;
ifdd=612then--分频系数
c<='0';
elsifdd=1024then
c<='1';
dd:
=0;
endif;
endif;
endprocess;
endBehavioral;
综合后出现这样的警告:
WARNING:
Xst:
646-Signal
isassignedbutneverused.