vhdl语言学习总结 6页

  • 187.15 KB
  • 2022-08-11 发布

vhdl语言学习总结

  • 6页
  • 当前文档由用户上传发布,收益归属用户
  1. 1、本文档由用户上传,淘文库整理发布,可阅读全部内容。
  2. 2、本文档内容版权归属内容提供方,所产生的收益全部归内容提供方所有。如果您对本文有版权争议,请立即联系网站客服。
  3. 3、本文档由用户上传,本站不保证质量和数量令人满意,可能有诸多瑕疵,付费之前,请仔细阅读内容确认后进行付费下载。
  4. 网站客服QQ:403074932
VHDL语言学习总结jackhuan@163.net(初学VHDL,欢迎批评指正)1VHDL的程序结构一个VHDL程序包含实体entity、结构体architecture、配置configuration、包集package和库library五部分。实体,用于描述设计系统的外部接口信号;结构体,用于描述系统的行为,系统数据的流程或系统组织结构形式;实体+结构体=设计实体;实体是设计实体的表层设计单元,其功能是对这个设计实体与外部的电路接口进行描述,它规定了设计单元的输入、输出接口信号和引脚,是设计实体与外界的一个通信界面;结构体是用于描述设计实体的内部结构以及实体端口间的逻辑关系,结构体具体实现一个实体。一个电路系统的程序设计只有一个实体,可以有多个结构体。在实体中类属说明放在端口说明上端,而其他说明类型说明如数据的定义说明则放在端口定义的下面。配置一般用来为实体指定结构体,由于在设计中没有用到配置,故没有做深入研究。包集是库的一部分,用来存放库中具有类似功能或在某一个部件中使用的元件、函数或过程。库是一个设计中封装所有元器件的总和。2VHDL与C++的结构类比上述部分可以和C++的工程管理方式做一简单比较。C++中有类的声明部分(一般为.H文件)和实现部分(一般为.CPP文件)。在程序的编写过程中,我们首先在一个.H文件中将类的成员变量和成员函数做定义,然后在.CPP中使用具体的代码实现它。这样在应用这个类的其他程序代码中,一般在引用文件的开始加入如下语句:#include“***.h”//***代表我们要包含的文件名称就可以随意使用其内部的类和函数了。VHDL有类似之处。首先我们编写了*.VHD文件,内有实体entity和结构体architecture,开始还要引入库library和包package。在我们使用其他元件时,通常在architecture中做元件例化。例如要在myexp中例化元件myand,则:ArchitecturebehaveofmyexpisSignalmysig1:bit_vector(7downto0);…componentmyandport(din1:inbit;din2:inbit;dout:outbit);endcomponent;begin…p1:myandportmap(din1,din2,dout);1\n…endbehave;实际上元件例化就是对元件的包含,相当于在C++中#include的功能。有时不在myexp中做元件例化,但还是要引用这些软件,就用到库和包的概念了。在工程中建立一个vhd文件,如mylib.vhd,在里面定义包mypkg,包内包含元件例化语句。具体如下:packagemypkgiscomponentmycomp1port(…);endcomponent;componentmycomp2port(…);endcomponent;…endmypkg;需要指出的是,元件mycomp1和mycomp2的设计实体必须在当前工程下。然后在myexp.vhd中加入:librarymylib;usemylib.mypkg.all;就不必在architecture中做元件例化说明了,直接做端口映射就可以了。因此上面的两句语句就等同于C++中的头文件引用#include了。如果编程者熟悉C++,则使用上述的类比,就对一般的FPGA开发软件环境有清楚了了解了,实际上QuartusII和ISE与VisualStudio是何等的类似啊!3结构体的三种描述方法行为描述:对设计实体按算法的路径来描述,行为描述在EDA工程中称为高级描述;数据流描述:描述数据流程的运动路径,运动方向和运动结果等。数据流描述一般为并行语句,顺序语句不可以作数据流描述,但数据流描述不能实现同步的功能。结构化描述:对于一个负责的电子系统可以分解为诸多子系统,每个子系统再分解为模块。在多层次设计中,每个层次都可以作为一个元件,再构成一个模块,进而构成子系统,最后构成一个大的系统。每个元件可以分别作功能、时序仿真,然后再进行整体调试。4关于进程process在进程process中的敏感表中,其信号必须为输入,这些信号无论哪个发生变化都将启动进程process,进程一旦启动,其中的代码将从上至下顺序执行一遍。多个进程并行执行,只要敏感信号发生变化,进程就会并行触发。在一个进程中,一般使用一个if…endif;注意,这里的if是一个整体,内部当然还可以套用其他的if…endif;但是所有的if语句必须是一体的(或顺序的),不能是并行的。例如不能是如下格式:process(…)ifa=bthenc<=d;endif;ifa=4then2\nc<=d+1;endif;endprocess;这一般是不允许的,容易出现多驱动源的情况。注意,条件信号赋值语句不能进行嵌套,不能将目标值代入目标自身,所以不能使用条件赋值语句设计锁存器。5关于BLOCK用VHDL中的BLOCK模块对程序进行仿真时,用BLOCK模块所描述的各个语句是并行执行的,与模块中的语句书写顺序无关。6关于过程Procedure在过程语句中,参数可以是输入,也可以是输出,一般in做常数处理,out和inout作为变量拷贝。当过程语句在主程中调用结束后,将变量out和inout拷贝到调用者的信号和变量中。在过程调用时,若调用者需要将out和inout作为信号使用时,需要用定义语句特别指明。这里过程类似于C++中函数使用指针传递的形参。7关于函数function一般地,function的各种功能函数都被集中在包集合package中。8关于信号的驱动源狭义定义:在时间域内,给某个信号赋值的序列,都称为该信号的驱动源。一个进程只能为某个信号建立一个驱动源,而不论赋值多少次。下面是错误的驱动源程序:libraryieee;useieee.std_logic_1164.all;entitymuxisport(i0,i1,i2,i3,a,b:inbit;q:outbit);endmux;architecturebehaveofmuxisbeginq<=i0whena=’0’andb=’0’else‘0’;q<=i1whena=’0’andb=’1’else‘0’;q<=i2whena=’1’andb=’0’else‘0’;q<=i3whena=’1’andb=’1’else‘0’;endbehave;该程序的错误之处在于:若a=’0’&b=’0’成立,则q<=i0;但同时a=’0’&b=’1’不成立,则q<=’0’;a=’1’&b=’0’不成立,则q<=’0’;a=’1’&b=’1’不成立,则q<=’0’;若i0=1,则由第一个条件的q<=1,而第二、三、四个条件则q<=0,出现结果的多样化,这就是驱动源不唯一,因此是错误的。3\n正确的设计如下:architecturebehaveofmuxisbeginq<=i0whena=’0’andb=’0’elsei1whena=’0’andb=’1’elsei2whena=’1’andb=’0’elsei3whena=’1’andb=’1’else‘0’;endbehave;总结出来的结论是,在所有的并行结构中,不能对信号在并行语句中进行二次赋值,因此应特别注意。有时钟信号给信号设定驱动源。在process语句中要设定的敏感表即是该变化的信号,这样可以进行赋值(有些难陈述,可我也不知道如何更好将我的想法表达出来)。注意上述驱动源的定义是在某时间域内不可多重赋值,典型的如状态机。9关于状态机单进程的状态机结构architecturebehaveofxxxistypestateis(s0,s1,s2,s3);signalst:state;beginstctrl:process(clk,clr)beginifclk’eventandclk=’1’thenifclr=’1’thenst<=s0;elsecasestiswhens0=>st<=s1;whens1=>st<=s2;whens2=>st<=s3;whens3=>st<=s0;whenothers=>st<=s0;endcase;endif;endif;endprocess;pout<=“00”whenst=s0else“01”whenst=s1else“10”whenst=s2else“11”whenst=s3else“XX”;endbehave;典型的三进程状态机设计如下:4\narchitecturebehaveofxxxistypestateis(s0,s1,s2,s3);signalval:integerrange0to3;signalcurrst,nextst:state;beginstxchg:process(clk,clr)beginifclk’eventandclk=’1’thenifclr=‘1’thencurrst<=s0;elsecurrst<=nextst;endif;endif;endprocessstxchg;stdisc:process(currst)begincasecurrstiswhens0=>nextst<=s1;whens1=>nextst<=s2;whens2=>nextst<=s3;whens3=>nextst<=s1;whenothers=>nextst<=s0;endcase;endprocessstdisc;stvalu:process(currst)begincasecurrstiswhens0=>val<=0;whens1=>val<=1;whens2=>val<=3;whens3=>val<=4;endcase;endprocessstvalu;pout<=CONV_STD_LOGIC_VECTOR(val,2);endbehave;从上述可以看出,不在同一时间域内对同一信号赋值就可以避免多驱动源现象。10关于常量和信号常量定义所允许的设计单元有实体、结构体、程序包、块、进程和子程序。在程序包中定义的常量可以暂时不设置具体数值,它可以在程序包体中设定。常量的可视性,即常量的可用范围,取决于其所定义的位置。定义在程序包中的常量,适用于调用此程序包的所有设计实体;定义在实体中的常量,适用于该实体所对应的结构体;5\n定义在某结构体中的常量,仅适用于该结构体;定义在某进程单元中的常量,仅使用于本进程。信号的使用和定义范围是实体、结构体和程序包。在进程和子程序中不允许定义信号。6

相关文档