全国大学生电子设计竞赛训练教程55 常见错误及其原因分析.docx
- 文档编号:11609581
- 上传时间:2023-03-28
- 格式:DOCX
- 页数:16
- 大小:318.72KB
全国大学生电子设计竞赛训练教程55 常见错误及其原因分析.docx
《全国大学生电子设计竞赛训练教程55 常见错误及其原因分析.docx》由会员分享,可在线阅读,更多相关《全国大学生电子设计竞赛训练教程55 常见错误及其原因分析.docx(16页珍藏版)》请在冰豆网上搜索。
全国大学生电子设计竞赛训练教程55常见错误及其原因分析
5.5常见错误及其原因分析
初学VHDL,往往会碰到不少问题和错误。
例如:
综合时出现警告和错误、编译无法通过等问题,使得设计无法实现;或者程序,综合等均通过,但不能得到正确的仿真结果,即所设计的硬件与原意要求不符等等。
通过资料的收集和归纳,总结出以下一些注意事项,常见问题及错误,并提出改正方案,以供参考。
5.5.1避免语法错误
VHDL规定了一些固定的描述格式,用于描述各种不同的功能,在Xilinx或Max+plusⅡ环境下,关键字会以蓝色显示,端口宽度会以紫色显示,以示区别,黑色字则是可由用户自定义的名称、数值等。
下面几个简单的例子作说明:
1.端口的定义
端口的定义为:
port(端口名,端口名:
端口类型(空格)端口宽度);
entitysztopis
Port(clk:
instd_logic;
ring,sz:
outstd_logic;――定义多个相同类型的端口,用逗号格开
hour:
instd_logic_vector(3downto0);――4位数据
sec:
outstd_logic_vector(6downto0)――7位数据
);
endsztop;
2.信号和变量的定义
信号定义:
SIGNAL信号名:
数据类型;
signala:
std_logic;
signalb:
std_logic_vector(2downto0);
变量定义:
VARIABLE变量名:
数据类型;
variablec0,c1:
integer;
variabled:
integerrange0to256;
variablecnt:
std_logic_vector(3downto0);
3.CASE语句
casesegis
when"0000"=>q<="0000001";
when"0001"=>q<="1001111";
when"1001"=>q<="0000100";
whenothers=>q<="1111111";
endcase;
初学者要紧记这些语法结构,特别注意标点符号的用法,从而避免编程时可能出现的大量小错误。
5.5.2信号与变量
信号与变量都可以用于描述器件内部结构,两者的区别如表5.5.1所示。
表5.5.1信号与变量的区别
信号
变量
基本用法
电路中的信号连线
进程中局部数据存储单元
适用范围
在整个结构体内的任何地方都能使用
只能在所定义的进程中使用
定义位置
进程外部
进程内部
赋值符号
<=
:
=
多次赋值
在进程的最后才对信号赋值
立即赋值
初学编程时经常出现的错误是信号或变量的定义位置混淆,如果在进程外部定义变量,或在进程内部定义信号,综合时就会出现Unexpectedsymbolread的错误。
对信号赋值的符号是“<=”,对变量的赋值符号是“:
=”,如例5.5.1所示。
编程时应正确使用。
【例5.5.1】
entitymulticlockis
Port(clk:
instd_logic;
ps:
outstd_logic);
endmulticlock;
architectureBehavioralofmulticlockis
signalps0:
std_logic;--定义信号
begin
process(clk)
variableclk1:
integerrange0to32;--定义变量
begin
ifclk'eventandclk='1'then
clk1:
=clk1+1;--变量赋值
ifclk1=16then
ps0<='1';--信号赋值
elsifclk1=32then
ps0<='0';
clk1:
=0;
endif;
endif;
ps<=ps0;
endprocess;
下面举例说明信号与变量用法的区别:
【例5.5.2】
entitydffis
Port(clk,d:
instd_logic;
q:
outstd_logic);
enddff;
architectureBehavioralofdffis
signala,b:
std_logic;
begin
process(clk)
begin
ifclk'eventandclk='1'then
a<=d;b<=a;q<=b;
endif;
endprocess;
endBehavioral
【例5.5.3】
entitydff1is
Port(clk,d:
instd_logic;
q:
outstd_logic);
enddff1;
architectureBehavioralofdff1is
begin
process(clk)
variablea,b:
std_logic;
begin
ifclk'eventandclk='1'then
a:
=d;b:
=a;q<=b;
endif;
endprocess;
endBehavioral
例5.5.2中的三个赋值语句是并行执行的,在同一时刻中,d的值并不能立即传送到q,实际电路中,a的赋值是上一时钟周期的d,b的值是上一时钟周期的a,q的值是上一时钟周期的b,如图5.5.1所示的仿真图,q比d延时了两个时钟周期。
图5.5.1例5.5.2程序仿真图
例5.5.3由于使用了变量,它的值是立即变化的,三条赋值语句顺序执行,完成了数据的传递,得到的仿真结果如图5.5.2所示。
图5.5.2例5.3程序仿真图
5.5.3IF—ELSE语句
if—else构成的条件语句必须有严格的描述,首先要做到逻辑清晰,层次合理分明,特别注意条件的完整性,也就是说,要为所有可能发生的条件给出对应的处理方式。
例5.5.4给出两种描述一个比较器的程序:
【例5.5.4】
程序1:
entitycomp_1is
程序2:
entitycomp_2is
Port(a,b:
instd_logic;
q:
outstd_logic);
endcomp_1;
architectureBehavioralofcomp_1is
begin
process(a,b)
begin
ifa>bthenq<='1';
elsifa --遗漏条件“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
Foun
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 全国大学生电子设计竞赛训练教程55 常见错误及其原因分析 全国大学生 电子设计 竞赛 训练 教程 55 常见 错误 及其 原因 分析