原创 VHDL学习

2008-9-26 11:57 4976 6 6 分类: FPGA/CPLD

关键词:
设计库和标准程序包 
library library_name;
use library_name.package_name.all; 
? 由于STD_LOGIC数据类型不属于VHDL标准库,所以使用时要予以以下声明:
          library IEEE; 
         use IEEE.Std_Logic_1164.all; 
 
 ENTITY   称为实体,描述了电路器件外部情况及各信号端口的基本性质。
entity entity_name is
generic (generic_list);
port (p_name:port_m   data_type;

p_name:port_mi   data_type);
end entity entity_name;
? 电路的端口及其端口信号描述语句PORT()
          p_name端口信号名
          port_m 端口模式:IN       单向只读模式,规定数据只能通过此端口被读入实体中。
                                            OUT     单向输出模式,规定数据只能通过此端口从实体向外流出,或者可以将实体中的数据向此端口赋值 。
                                            INOUT   输入输出双向口
                                            BUFFER  与INOUT类似,区别在于输入信号来自于实体内部产生的回读输出的信号,即允许反馈。
         data_type 数据类型:整数数据类型 INTEGER
                                                布尔数据类型 BOOLEAN
                                                标准逻辑位数据类型 STD_LOGIC
                      type std_ulogic is (   'U',      -- Uninitialized
                                             'X',      -- Forcing   Unknown
                                             '0',      -- Forcing   0
                                             '1',      -- Forcing   1
                                             'Z',      -- High Impedance
                                             'W',      -- Weak     Unknown
                                             'L',      -- Weak     0
                                             'H',      -- Weak     1
                                             '-',     -- Don't Care    );
                                  位数据类型   BIT
                                 BIT数据类型的信号规定的取值范围是逻辑位‘1’,‘0’。
 
 ARCHITECTURE 称为结构体,结构体负责描述电路内部逻辑功能或电路结构,并行语句。
architecture architecture_name of entity_name is
architecture_declarations(说明语句)
                   begin
                            concurrent_statements(功能描述语句)
                   end [ architecture ] [ architecture_name ];
 
                   说明语句:包括在结构体中需要说明和定义的数据对象、数据类型、元件调用声明等。并非必须的。
                   功能描述语句:必须的,给出相应的电路功能描述语句,可以是并行语句、顺序语句或他们的混合。
 
PROCESS_END PROCESS 进程语句和顺序语句,VHDL中,所有合法的顺序描述语句必须放在进程语句中,比如IF_THEN_ELSE_END IF等。
[process_label:] process [ ( sensitivity_list ) ] [ is ]
[process_declarations]?
         begin 
                   sequential_statements?
end process [ process_label ] ;
           sensitivity_list:敏感信号表,通常要求把进程中所有的输入信号都放在敏感信号表中。 
         PROCESS的执行依赖于敏感信号的变化,当某一敏感信号发生跳变,就将启动此进程语句,而在执行一遍整个进程的顺序语句后,便返回进程的启示端,进入等待状态,直到下一次敏感信号中某一信号跳变才再次进入“启动—运行”状态,再执行一遍进程。一个结构体中,可以存在多个进程,它们是并行的,而任意一个进程属于顺序语句。
 
AND(与)、OR(或)、NOT(非)、NAND(与非)、NOR(或非)、XOR(异或)、XNOR(同或) 逻辑操作符,构成组合电路,他们的操作数有三种类型,分别为BIT  BOOLEAN  STD_LOGIC.
 
IF_THEN_ELSE_END IF 条件语句
if condition then
sequential_statements
end if; 
if condition then
    sequential_statements
else 
sequential_statements
end if; 
if condition then
    sequential_statements
    elsif condition then
         sequential_statements
    else 
         sequential_statements
end if; 
 赋值语句 
signal_name  <= [delay_mechanism ] waveform ;
 
WHEN_ELSE 条件信号赋值语句
signal_name  <= [delay_mechanism ] waveform1 when condition1 else
                           [delay_mechanism ] waveform2 when condition2 else
                           . . .
                           [delay_mechanism ] waveformn;
with selection select
signal_name  <= [delay_mechanism ] waveform1 when choice1,
               [delay_mechanism ] waveform2 when choice2,
                            . . .
               [delay_mechanism ] waveformn when others;
 
 SIGNAL 信号定义和数据对象(Data Objects),它规定了信号的行为方式和功能特点。
Simplified Syntax:
signal signal_name : type;
signal signal_name : type := initial_value;
注:signal可作为内部的节点,这就决定它不需要像端口那样定义模式,即数据流动不受方向限制,可用来建立寄存器等。
 
EVENT 信号跳变检测表示和信号属性函数
signal_name’event[and signal_>
 
不完整条件语句与时序电路 
比如在未满足if条件,又没有else明确指出其他条件时如何操作时,即在条件语句中没有对所有可能发生的条件给出对应的处理方式,这样就产生了不完整条件语句。此时,VHDL综合器将引进一个时序元件保持当前状态值。利用这种不完全条件语句的描述引进寄存器元件,从而构成时序电路的方式是VHDL描述时序电路最重要的途径。
CLK’LAST_VALUE=‘0’(‘1’)
rising_edge()测定上升沿的函(LIBRARY IEEE ;
USE IEEE.STD_LOGIC_1164.ALL ;)
 
l          WAIT 
Simplified Syntax:
wait; 
wait on signal_list;
wait until condition;
wait for time;


 


边沿检测:为了确保clk发生的了一次由0到1的上升跳变,采用如下语句:


clk'event  and  (clk=' 1 ' ) and ( clk'last_vaule=' 0 ' )


其他表达方式:clk='1' and clk'last_vaule='0'


                           rising_edge(clk)--必须打开std_logic_1164程序包


                          wait  until clk='1'


两种不同的触发方式的表达:1.边沿触发;2.电平触发。


边沿触发:.


...


process (clk)


begin


if clk='1'


then q<= d;                --利用进程启动特性对clk的边沿检测


end if;


end process;



电平触发:


...


process(clk,d)


begin


if clk='1'                     --电平触发型寄存器


then q<=d;


end if;


end process;



造成两个程序所生成的触发类型不同的原因是,第一个程序中完全靠检测clk的上升沿(因为当敏感信号变化的时候process才被启动,所以也就是当clk从0到1或者1到0的时候才启动process,当从1到0的时候不满足if clk='1'跳出process,所以只有在clk从0到1的时候,也就是上升沿的时候才能执行q<=d)将当前的d送入q中,直到下一次clk上升沿的到来,送入新的当前的d值,也就产生了边沿触发;而第二个程序中,有clk和d俩个敏感信号,也就是说当clk变化的时候,即clk上升沿的情况下将当前的d送入q;而当d变化的时候,启动process,此时clk=‘1’作为一个条件,满足这个条件则把d送入q,否则跳出process保持原值,综合起来看clk='1'是作为一个条件,当clk='1'时,也就是当clk为高电平的时候将d送入q,就产生了电平触发.


CASE语句,属于顺序语句,因此必须放在process中使用,用法如下:
case expression is


when choice => sequential_statements      --quential_statements 顺序语句构成,语句间用;隔开。when choice => sequential_statements. . .


(when others=>sequential_statements)   --如果有没有被列举的情况,用此语句统一处理。


end case;


注:


1.choice 必须在expression的取值范围内;


2.when条件句中,必须覆盖expression中的所有情况,如果choice中没有覆盖expression中的所有情况,则要用others关键词,涵盖剩下的所有情况再作处理;


3.expression的每个情况只能出现一次,必须且只能选中一个情况。


std_logic_vector         标准逻辑矢量数据类型, 为一维数组,所以要求注明其宽度,用法如下:
例如:pout : out  std_logic_vector(7downto 0) ;  --定义了一个宽度为8位的标准逻辑矢量,每一位分别为pout(7),pout(6),pout(5)... ...pout(1),pout(0).


或者signal: std_logic_vector(1 to 4 )        --4位


其中的每一位都为std_logic类型,用于表达多通道端口或节点,或者总线BUS。类似的数据类型还有bit_vector.


&  并置操作符,表示将操作数或数组合并起来形成新的数组,用法如下:
abc<=a&b 相当于 abc(1)<=a;abc(0)<=b.    a,b可代表操作数或者数组。


component         元件例化语句,用于对现有的实体定义为元件为准备调用作出声明,并配合port map()(端口映射语句)以达到连接底层元件形成更高层次电路结构,用法如下:
Simplified Syntax:


architecture architecture_name of entity_name is


component component_name [ is ]


    generic (generic_list);    port (port_list);end component component_name;


component component_name2 [ is ]


    generic (generic_list);    port (port_list);end component component_name2;


...


begin


port map()   端口映射语句,用于说明元件与当前设计实体中元件间及接口间的连接说明,用法如下:
port map( [被例化成元件的实体中的端口名=>]当前实体中指定的端口名,...  );  --"=>"为连接符号。


注:


当前的设计实体相当于一个高一层次的电路系统,而当前设计的实体中指定的接口相当于整个电路系统上的插座,而被例化的实体形成的元件相当于要插在这些插座上的芯片。



q : bufferr integer rang 15 dwonto 0   -- 定义q为buffer类型的端口,此端口的数据类型为integer,此整数的取值范围是从15到0。

注:


1.integer 的取值可用符号的32位2进制数表示。


2.需要注意的是,VHDL仿真器将integer类型作为有符号数处理,而VHDL综合器则将integer作为无符号数处理。而且VHDL综合器要求必须使用rang子句为所定义的数限定范围,然后根据所限定的范围来确定此信号或变量的2进制的位数,因为VHDL综合器无法综合未限定范围的恶整数类型的信号和变量。


3.整数在表达式中不加引号,而逻辑数必须加引号,一位的加单引号,一位以上的加双引号。


4.natural,positive 为integer的子类型。



 关于signal

signal可作为内部的节点,这就决定它不需要像端口那样定义模式,即数据i流动不受方向限制,可用来建立寄存器等。



关于算数运算

VHDL规定加减等算数操作符对应的操作数只能是integer,而当不同数据类型间运算操作的时候就要调用运算符重载函数 ieee库中的std_logic_unsigned程序包中,其中预定义的操作符有+、-、*、=、>=、<=、>、<、/=、and、mod,用法如下:


library ieee;


use ieee_logic_unsigned.all



veriable 变量,也是数据对象的一种,赋值符号为“:=”。 
others=>X)缺省赋值操作符,可以在较多的矢量赋值中作省略化的赋值。例如:

signal d1,d3 :std_logic_vector(4 dwonto 0)


veriable d2,d4:std_logic_vector(15 downto 0)


...


d1<=(others=>'0');


d2:=(1=>'1',4=>'1',others=>'0');


d3<=(1=>d1(3),3=>d2(3)???,others=>d1(2));


所谓同步异步都是对于时钟信号而言的,不依赖于时钟而有效的信号称为异步信号,否则称为同步信号。


 穿行并行,我的理解是如果将一个vector一次性一次送性的给另一个vector的话就是并行,如果是一个bit一个bit的送的话就是串行。



 数据对象

VHDL中的数据对象有三种,常量(constant)、变量(veriable)、信号(signal),用来描述目标量的属性的。



常量(constant),允许的三个设计单元有实体,结构体,程序包,块,进程,子程。常量的可视性,即常量的作用范围决定于它被定义的位置:包=>实体=>结构体=>进程等。signal 也有the same attribute. 
变量(veriable),是一个局部量,只作用于在定义了变量的process和subprogram的顺序语句里面,而且变量的数据传输没有延时行为。变量的主要作用是在进程中作为临时的数据存储单元(当前)。 
信号(signal),信号的define 和使用的范围为entity,architecture和package,而不能在process和subprogram的顺序语句中。而且,在没有作特殊设置时,信号也有一个最小传输延时,它的硬件特征更为明显,类似于连接线,可以作为设计实体并行语句模块间的信息交流通道,它即可以保存当前值也可以保存历史值,和触发器的记忆功能有很好的对应关系,只是不必care信号上的数据流动方向。关于信号的初始值的设定和veriable一样,因为电路上电后的随机性,因此综合器并不支持设置初始值。由于process的敏感列表里可以有信号,那么信号就能把process外部的信息引入或传出.在process中,当多个同名信号被赋值,只执行最后一个,因为当遇到end process的时候才对signal赋值。但是当并行语句中却不允许同一信号有多个驱动源的。 
硬件电路系统上来看,变量和信号相当于电路系统中的连线和连线上传输的信号,常量相当于电路中的恒定电平,如gnd和vcc。在不完整条件语句中,变量和信号有同样的功能都能。  
关于process(clk) begin

if clk'event and clk='1' then


a<=d;        --d,q为port,a,b为signal    


b<=a;


q<=b;


end if ;


end  process;中的一些问题!


首先,此进程描述的是当clk上升沿发生时,将信号由port d输入到a到b,再由port q输出。


下面要说的是这个进程执行时的几个问题。


首先,此进程执行的时候,a的赋值,b的赋值,q的赋值是并行执行的,也就是说a,b,q的赋值是同时的。但这是在进程中,也就是说应该先将a赋值,再将a的值赋给b,最后把b的值由q输出,这样一个顺序执行,为什么会是并行执行的呢?为什么赋值结束后q输出的值并不是d输入的值呢,而是上一时钟b的值?


这是因为,对于某一个时钟周期的信号,确实是按从a到b到q的顺序传输的。而对于同一个时钟,各个节点上的信号都不是当前其上一个节点上的信号,原因很简单,就是因为要有一个固定延时赋值才完成。也就是说q输出的值是b上一时钟的值,而b被更新的值是上一时钟a的值... ...而当前这个时刻,每一个一个节点的值都是被赋给的新值,也就是说,在这个固定延时时间里,各个节点被赋值是同时发生的。


这个进程中的信号的顺序赋值,很完美的体现了硬件行为,即整体描述了一个信号是如何在节点之间传递的,又描述出每个时钟的信号都是如何在节点之间动作的,这就是HDL的魅力吧!~呵呵


 



三态门

三态门的应用 三态门的有很多的实际应用,比如数据和地址BUS的构建,RAM或堆栈的数据端口设计等。


三态门的设计 当输入输出状态时,dataout<=datain;而当高阻状态的时候,则dataout<="ZZZZZZZZ"


注:


尽可能不用'Z'做比较值,表达式和操作数。否则综合会出错。


VHDL虽然不区分大小写,但是高阻态已经定义为大写'Z'。


大多数FPGA器件内部都无法构成三态门,所以只能用多路选择器的结构来实现,有的甚至在端口都无法实现。



双向端口设计

双向端口inout 模式的设计也必须考虑到三态的使用,其实是高阻的使用。这是因为,当双向端口在完成输入的时,必须使原来呈输出模式的端口呈高阻态,否则,待输入的外部数据势必会与端口处原有电平发生“线与”。


状态机


自定义数据类型语句:


TYPE 数据类型名 IS 数据形式 OF 构成数据形式的数据元素的类型;


TYPE 数据类型名 IS (数据元素描述) ;


其中数据形式包括:Array type ,Enumeration type ,Interger type,Record type,Time type,Real type


构成数据形式的元素类型包括:bit, Boolean ,character ,std_logic


状态符号化,表征每个状态的二进制数用文字符号来表示,最左边的为‘0’或“0000”向右依次加1


 


SUBTYPE 子类型名 IS 基本数据类型 RANGE 约束范围;


SUBTYPE 没有新定义数据类型只是对已有的数据类型加以约束,引进SUBTYPE的益处在于:


1.         提高可读性和易处理性;


2.         其实质的好处在于提高综合的优化效率,即综合器可以根据子类型所设的约束范围有效的推出参与综合的寄存器的数目等优化措施。


 


般有限状态机的设计:


一、说明部分:




说明部分在architecture与begin之间;


定义枚举型数据形式描以述状态;


把状态变量定义为信号便于信息传输,状态变量数据类型和描述状态的数据类型一致,因此只能在状态中取值。

二、主控时序(REG)进程,在时钟驱动下负责状态转换current_state<=next_state,它不负责状态的取值。主控时序进程中必须包含一个时钟敏感信号。next_state的内容由其他进程实际情况决定。


三、主控组合(COM)即状态译码进程,由当前状态(current_state)进入相应状态(所谓进入相应状态就是做此状态下规定的行为),并和外部输入state_input共同作用决定下一个状态next_state和对外发出控制信号comb_outputs,直至下一个时钟脉冲到来进入新一轮的状态周期转换。


四、辅助进程:



一些算法进程; 
配合状态机工作的其他时序进程; 
为稳定输出的数据锁存器等。

五、状态机的分类


Moore 型/Mealy 型


 


Moore 型,同步输出,输出为当前状态的函数,输入发生变化还须等待时的钟到来,时钟使状态变化时,输出才变化。


Mealy 型,异步输出,输出为当前状态和所有输入信号的函数,它的输出是在输入变化后立即发生的,不依赖时钟。


 

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
6
关闭 站长推荐上一条 /3 下一条