VHDL 编 程 基 础
目 录 3.1 概述 3.2 VHDL设计实体的基本结构 3.3 VHDL语言要素 3.4 VHDL顺序语句 3.5 VHDL并行语句 目 录 3.1 概述 3.2 VHDL设计实体的基本结构 3.3 VHDL语言要素 3.4 VHDL顺序语句 3.5 VHDL并行语句 3.6 VHDL的库和程序包 3.7 VHDL设计流程
3.1 概 述 3.1.1 VHDL语言简介 VHDL是超高速集成电路硬件描述语言(Very High Speed Integrated Circuit Hardware Description language)。是标准化程度最高的硬件描述语言。目前流行的EDA工具软件全部支持VHDL,VHDL是现代电子设计师必须掌握的硬件设计计算机语言。 (1) 逻辑描述层次:一般的硬件描述语言可以在三个层次上进行电路描述,层次由高到低依次可分为行为级、RTL级(寄存器转换级)和门电路级。VHDL语言是一种高级描述语言,适用于行为级和RTL级的描述,最适于描述电路的行为; (2) 设计要求:VHDL进行电子系统设计时可以不了解电路的结构细节,设计者所做的工作较少;Verilog和ABEL语言进行电子系统设计时需了解电路的结构细节,设计者需做大量的工作。
3.1.3 VHDL程序设计约定 为了便于程序的阅读和调试,对VHDL程序设计特作如下约定: (1) 语句结构描述中方括号“[ ]”内的内容为可选内容。 (2) 对于VHDL的编译器和综合器来说,程序文字的大小写是不加区分的。 (3) 程序中的注释使用双横线“--”。在VHDL程序的任何一行中,双横线“--”后的文字都不参加编译和综合。 (4) 为了便于程序的阅读与调试,书写和输入程序时,使用层次缩进格式,同一层次的对齐,低层次的较高层次的缩进两个字符。 (5) 考虑到MAX+plusII要求源程序文件的名字与实体名必须一致,因此为了使同一个VHDL源程序文件能适应各个EDA开发软件上的使用要求,建议各个源程序文件的命名均与其实体名一致。
3.2 VHDL设计实体的基本结构 通过VHDL描述一个二输入或门的实例,来说明VHDL的基本结构。 例1 一个二输入或门的VHDL程序如下: LIBRARY IEEE; -- IEEE库的使用说明 USE IEEE.STD_LOGIC_1164.ALL; --实体描述器件的输入、输出端口和数据类型用的程序包 ENTITY OR2 IS --实体OR2的说明 PORT(A,B: STD_LOGIC; ---端口声明,A、B是标准逻辑位类型的输入端口 C:OUT STD_LOGIC); --声明C是标准逻辑位类型的输出端口 END ENTITY OR2; ARCHITECTURE ONE OF OR2 IS --实体OR2的结构体ONE 的说明 BEGIN C<=A OR B; --二输入或门逻辑功能描述 END ARCHITECTURE ONE; 或门程序包含了VHDL的库、程序包、实体说明和结构体几个主要部分。语句C<=A OR B为或门电路的逻辑描述,其他都作为或门对外部端口的描述,设计实体定义了或门外部界面后,其他的设计就可以直接调用这个或门实体。
3.2.1 VHDL程序设计举例 1.设计思路 以全加器为例 例2 全加器可以由两个1位的半加器构成。1位半加器的端口信号A 和B分别是2位相加的二进制输入信号,SO是相加和的输出信号,CO是进位输出信号,左边的门电路结构构成了右边的半加器H_ADDER。
1 位全加器逻辑原理图 图中,全加器 F_ADDER内部的功能结构是由3个逻辑器件 构成的,即由两个半加器U1、U2和一个或门U3连接而成。
2. VHDL源程序 1) 或门的逻辑描述 LIBRARY IEEE; -- IEEE库的使用说明 USE IEEE.STD_LOGIC_1164.ALL; --实体描述器件的输入、输出端口和数据类型用的程序包 ENTITY or2 IS --实体or2的说明 PORT(a,b:IN STD_LOGIC; --端口声明,a、b是标准逻辑位类型的输入端口 c: OUT STD_LOGIC); --声明c是标准逻辑位类型的输出端口 END ENTITY or2; ARCHITECTURE art1 OF or2 IS --实体or2的结构体art1的说明 BEGIN c<=a OR b; END ARCHITECTURE art1;
2) 半加器的逻辑描述 LIBRARY IEEE; -- IEEE库的使用说明 USE IEEE.STD_LOGIC_1164.ALL; ENTITY h_adder IS --实体h_adder的说明 PORT(a,b:IN STD_LOGIC; co,so:OUT STD_LOGIC); END ENTITY h_adder; ARCHITECTURE art2 OF h_adder IS -- 实体h_adder的结构体art2的说明 BEGIN so<=(a OR b) AND (a NAND b); co<=NOT (a NAND b); END ARCHITECTURE art2;
3) 全加器的逻辑描述 LIBRARY IEEE; -- IEEE库的使用说明 USE IEEE.STD_LOGIC_1164.ALL; ENTITY f_adder IS --实体f_adder的说明 PORT(ain,bin,cin:IN STD_LOGIC; --端口声明,方向、数据类型名 cout,sum: OUT STD_LOGIC); END ENTITY f_adder; ARCHITECTURE art3 OF f_adder IS --实体F_ADDER的结构体ART3的说明 COMPONENT h_adder --元件调用声明,将h_adder作为元件连接到指定端口 PORT(a,b:IN STD_LOGIC; --端口声明 co,so:OUT STD_LOGIC); END COMPONENT h_adder;
COMPONENT or2 PORT(a,b:IN STD_LOGIC; c: OUT STD_LOGIC); END COMPONENT or2; SIGNAL d,e,f:STD_LOGIC; --定义中间信号转存点 BEGIN --元件连接说明 U1:h_adder PORT MAP(a=>ain,b=>bin,co=>d,so=>e); --名称映射法 U2:h_adder PORT MAP(a=>e,b=>cin,co=>f,so=>sum); --名字关联方式 U3:or2 PORT MAP(a=>d,b=>f,c=>cout); END ARCHITECTURE art3;
3. 说明及分析 (1) 整个设计包括三个设计实体,分别为or2、h_adder和f_adder,其中实体f_adder为顶层实体。三个设计实体均包括三个组成部分:库、程序包使用说明,实体说明和结构体说明。这三个设计实体既可以作为一个整体进行编译、综合与存档,也可以各自进行独立编译、独立综合与存档,或被其他的电路系统所调用。 (2) 实体 or2定义了或门or2的引脚信号a、b(输入)和c(输出),结构体art1描述了输入与输出信号间的逻辑关系,将输入信号a、b相或后传给输出信号端c,由此实体和结构体描述一个完整的或门元件。
(3) 实体h_adder及对应的结构体art2描述了一个半加器。是由一个与非门、一个非门、一个或门和一个与门连接而成的,其逻辑关系来自于半加器真值表。在VHDL中,逻辑算符NAND、NOT、OR和AND分别代表“与非”、“非”、“或”和“与”4种逻辑运算关系。 (4) 在全加器接口逻辑VHDL描述中,1位二进制全加器f_adder的原理图,实体f_adder定义了引脚的端口信号属性和数据类型。其中,ain和bin分别为两个输入的相加位,cin为低位进位输入,cout 为进位输出,sum为1位和输出。其对应的结构体art3的功能是利用COMPONENT声明语句和COMPONENT例化语句将上面由两个实体or2和h_adder描述的独立器件,按照图3.2全加器内部逻辑原理图中的接线方式连接起来。
(5) 在结构体art3中,COMPONENT→END COMPONENT 语句结构对所要调用的或门和半加器两元件作了声明(COMPONENT DECLARATION),并由SIGNAL语句定义了三个信号d、e和f,作为中间信号转存点,以利于几个器件间的信号连接。 “PORT MAP( )”语句称为元件例化语句(COMPONENT INSTANTIATION)。所谓例化,在电路板上,相当于往上装配元器件;在逻辑原理图上,相当于从元件库中取了一个元件符号放在电路原理图上,并对此符号的各引脚进行连线。例化也可理解为元件映射或元件连接,MAP是映射的意思。例如,语句“U2:h_adder PORT MAP(a=>e,b=>cin,co=>f,so=>sum)”表示将实体h_adder描述的元件U2的引脚信号a、b、co和so分别连向外部信号e、cin、f和sum。符号“=>”表示信号连接。
(6) 实体f_adder引导的逻辑描述也是由三个主要部分构成的,即库、实体和结构体。从表面上看来,库的部分仅包含一个IEEE标准库和打开的IEEE.STD_LOGIC_1164.ALL程序包。但实际上,从结构体的描述中可以看出,其对外部的逻辑有调用的操作,这类似于对库或程序包中的内容作了调用。因此,库结构部分还应将上面的或门和半加器的VHDL描述包括进去,作为工作库中的两个待调用的元件。由此可见,库结构也是VHDL程序的重要组成部分。
完整的VHDL程序(设计实体)具有固定的结构。应包括三个基本组成部分:库、程序包使用说明,实体说明和实体对应的结构体说明。 库、程序包使用说明用于打开本设计实体将要用到的库、程序包; 实体说明用于描述该设计实体与外界的接口信号说明,是可视部分; 结构体说明用于描述该设计实体内部工作的逻辑关系。 在一个实体中,可以含有一个或一个以上的结构体,而在每一个结构体中又可以含有一个或多个进程以及其他的语句。 实体还可以有配置说明语句。配置说明语句主要用于以层次化的方式对特定的设计实体进行元件例化,或是为实体选定某个特定的结构体。
3.2.2 VHDL程序的基本结构 VHDL程序设计基本结构
库、程序包 根据VHDL语法规则,在VHDL程序中使用的文字、数据对象、数据类型都需要预先定义。为了方便用VHDL编程,IEEE将预定义的数据类型、元件调用声明(Declaration)及一些常用子程序收集在一起,形成程序包,供VHDL设计实体共享和调用。 若干个程序包则形成库,常用的库是IEEE标准库。因此,在每个设计实体开始都有打开库或程序包的语句。例如 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; 表示设计实体中被描述器件的输入、输出端口和数据类型将要用到IEEE标准库中的STD_LOGIC_1164程序包。
3.2.3 实体(ENTITY) 实体(ENTITY)是设计实体中的重要组成部分,是一个完整的、独立的语言模块。它相当于电路中的一个器件或电路原理图上的一个元件符号。 实体由实体声明和结构体组成。实体声明部分指定了设计单元的输入输出端口或引脚,是设计实体经封装后对外的一个通信界面,是外界可以看到的部分。 结构体用来描述设计实体的逻辑结构和逻辑功能。由VHDL语句构成,是外界看不到的部分。一个实体可以拥有一个或多个结构体。
1.实体语句结构 实体声明部分的常用语句结构如下: ENTITY 实体名 IS [GENERIC(类属表);] [PORT(端口表);] END ENTITY 实体名; 实体声明单元必须以语句“ENTITY 实体名IS”开始,以语句“END ENTITY 实体名;”结束, 实体名是设计者自己给设计实体的命名,可作为其他 设计实体对该设计实体进行调用时用。中间在方括号内的语句描述,在特定的情况下并非是必须的。
类属(GENERIC)参数声明必须放在端口声明之前,用于指定如矢量位数、器件延迟时间等参数。类属声明的一般书写格式如下: {;常数名:数据类型[:设定值 ]}); 例: GENERIC(m:TIME=1.0ns); -- m是一个值为1.0ns的时间参数 Temp1<=d0 AND sel AFTER m; --表示d0 AND sel经1.0ns延迟后才送到Temp1
【例3.2.2】 2输入与门的实体描述。 ENTITY and2 IS GENERIC(RISEW:TIME:=1ns; FALLW:TIME:=1ns); PORT( a1:IN STD_LOGIC; a0:IN STD_LOGIC; z0:OUT STD_LOGIC); END ENTITY and2; 这是一个准备作为2输入与门的设计实体的实体描述,在类属说明中定义参数RISEW为上沿宽度,FALLW为下沿宽度,它们分别为1ns,这两个参数用于仿真模块的设计。
3.PORT端口说明 端口声明语句是描述器件的外部接口信号的声明,相当于器件的引脚声明。实体端口声明的一般书写格式如下: PORT(端口名:方向 数据类型; {端口名:方向 数据类型}); 例如 PORT(a, b:IN STD_LOGIC; --声明a, b是标准逻辑位类型的输入端口 s: IN STD_LOGIC; --声明s是标准逻辑位类型的输入端口 y: OUT STD_LOGIC); --声明y是标准逻辑位类型的输出端口
端口名是实体每一个对外通道的名字;端口方向模式是通道上数据流动的方式,如输入或输出等;数据类型是端口上流动数据的表达格式。 VHDL对语句中的所有操作数的数据类型都有严格的规定。一个实体通常有一个或多个端口,端口类似于原理图部件符号上的管脚。实体与外界交流的信息必须通过端口通道流入或流出。 IEEE 定义了4种常用的端口模式: IN--输入的引脚, OUT--输出的引脚, BUFFER--带输出缓冲器并可以回读的引脚(与TRI引脚不同), INOUT--双向引脚(即BIDIR引脚)。此模式的端口是普通输出端口(OUT)加入三态输出缓冲器和输入缓冲器构成的。 端口描述中的数据类型主要有两类: 位(BIT)和位矢量(BIT_VECTOR)。 若端口的数据类型定义为BIT,则其信号值是一个1位的二进制数,取值只能是0或1;若端口数据类型定义为BIT_VECTOR,则其信号值是一组二进制。
端口模式(方向)说明 端口模式符号图
3.2.4 结构体(ARCHITECTURE) 结构体是用于描述设计实体的内部结构以及实体端口间的逻辑关系,在电路上相当于器件的内部电路结构。一个完整的结构体由两个基本层次组成: ● 对数据类型、常数、信号、子程序和元件等元素的信号声明部分。 ● 描述实体逻辑行为的,以各种不同的描述风格表达的功能描述语句。
结 构 体 造 图
1. 结构体的一般语句格式 结构体的语句格式如下: ARCHITECTURE 结构体名 OF 实体名 IS [信号声明语句]; --为内部信号名称及类型声明 BEGIN [功能描述语句] END ARCHITECTURE 结构体名; 其中,实体名必须是所在设计实体的名字,而结构体名可以由设计者自己选择,但当一个实体具有多个结构体时,结构体的取名不可重复。 例如 设a、b是或非门的输入端口,z是输出端口,y是结构体内部信号,则用VHDL描述的两输入端或非门的结构体为: ARCHITECTURE nor1 OF templ IS SIGNAL y: STD_LOGIC; y<=a OR b; --结构体功能描述语句 z<=NOT y; END ARCHITECTURE nor1;
2.结构体说明语句 结构体中的说明语句是对结构体的功能描述语句中将要用到的信号(SIGNAL)、数据类型(TYPE)、常数(CONSTANT)、元件(COMPONENT)、函数(FUNCTION)和过程(PROCEDURE)等加以说明的语句。 但在一个结构体中说明和定义的数据类型、常数、元件、函数和过程只能用于这个结构体中,若希望其能用于其他的实体或结构体中,则需要将其作为程序包来处理。
功能描述语句结构含有五种不同类型,以并行方式工作。在每一语句结构的内部可能含有并行运行的逻辑描述语句或顺序运行的逻辑描述语句。 3.功能描述语句结构 功能描述语句结构含有五种不同类型,以并行方式工作。在每一语句结构的内部可能含有并行运行的逻辑描述语句或顺序运行的逻辑描述语句。 各语句结构的基本组成和功能分别是: (1) 块语句(BLOCK)是由一系列并行执行语句构成的组合体,它的功能是将结构体中的并行语句组成一个或多个模块。 (2) 进程语句(PROCESS)定义顺序语句模块,用以将从外部获得的信号值,或内部的运算数据向其他的信号进行赋值。 (3) 信号赋值语句(赋值目标<=表达式;)将设计实体内的处理结果向定义的信号或界面端口进行赋值。 (4) 子程序调用语句用于调用一个已设计好的子程序。子程序有过程(PROCEDURE)和函数(FUNCTION)两种类型。 (5) 元件例化(COMPONENT)语句对其他的设计实体作元件调用说明,并将此元件的端口与其他的元件、信号或高层次实体的界面端口进行连接。
例1: 半加器的描述 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; --IEEE库使用声明 ENTITY h_adder IS PORT(a,b:IN STD_LOGIC; --实体端口声明 so,co:OUT STD_LOGIC); END h_adder; ARCHITECTURE ONE OF h_adder IS BEGIN so<=a XOR b; --结构体功能描述语句 co<=a AND b; END ARCHITECTURE ONE;
例2:2选1数据选择器的描述 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY mux21 IS PORT( a,b: IN STD_LOGIC; s: IN STD_LOGIC; y: OUT STD_LOGIC); END mux21; ARCHITECTURE ONE OF mux21 IS BEGIN y<=a WHEN s='0' ELSE b; END ARCHITECTURE ONE;
例3:锁存器的描述 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY latch1 IS PORT( d: IN STD_LOGIC; ena: IN STD_LOGIC; q:OUT STD_LOGIC); END latch1; ARCHITECTURE ONE OF latch1 IS BEGIN PROCESS(d,ena) IF ena='1'THEN q<=d; END IF; END PROCESS; END ARCHITECTURE ONE;
例4 四位二进制加法计数器 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY cnt4evhdl IS PORT( clk,ena:IN STD_LOGIC; cout:OUT STD_LOGIC; q:BUFFER INTEGER RANGE 0 TO 15); END cnt4evhdl; ARCHITECTURE one OF cnt4evhdl IS BEGIN PROCESS(clk,ena) IF clk'EVENT AND CLK='1'THEN IF ena='1'THEN IF q=15 THEN q<=0; cout<='0'; ELSIF q=14 THEN q<=q+1; cout<='1'; ELSE q<=q+1; END IF; END PROCESS; END ARCHITECTURE one;
例5 七段显示译码器 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY Dec7svhdl IS PORT( a:IN BIT_VECTOR(3 DOWNTO 0); led7S:OUT BIT_VECTOR(7 DOWNTO 0)); END; ARCHITECTURE one OF Dec7svhdl IS BEGIN PROCESS(a) CASE a(3 DOWNTO 0) IS --case选择语句 WHEN "0000"=>LED7S<="00111111"; WHEN "0001"=>LED7S<="00000110"; WHEN "0010"=>LED7S<="01011011"; WHEN "0011"=>LED7S<="01001111"; WHEN "0100"=>LED7S<="01100110"; WHEN "0101"=>LED7S<="01101101"; WHEN "0110"=>LED7S<="01111101";
WHEN "0111"=>LED7S<="00000111"; WHEN "1000"=>LED7S<="01111111"; WHEN "1001"=>LED7S<="01101111"; WHEN "1010"=>LED7S<="01110111"; WHEN "1011"=>LED7S<="01111100"; WHEN "1100"=>LED7S<="00111001"; WHEN "1101"=>LED7S<="01011110"; WHEN "1110"=>LED7S<="01111001"; WHEN "1111"=>LED7S<="01110001"; WHEN OTHERS=>NULL; END CASE; END PROCESS; END ARCHITECTURE one;
例6 奇偶校验器的描述 LIBRARY IEEE; USE IEEE. STD_LOGIC_1164 例6 奇偶校验器的描述 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY p_check IS PORT( a:IN STD_LOGIC_VECTOR(7 DOWNTO 0); y:OUT STD_LOGIC); END p_check; ARCHITECTURE one OF p_check IS BEGIN PROCESS(a) VARIABLE temp:STD_LOGIC; BEGIN temp:='0'; FOR n IN 0 TO 7 LOOP temp:=temp XOR a(n); END LOOP; y<=temp; END PROCESS; END one;
例7 求最大值的函数 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; PACKAGE bpac1 IS FUNCTION max ( a,b:IN STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; --声明函数首 END; PACKAGE BODY bpac1 IS FUNCTION max ( a,b:IN STD_LOGIC_VECTOR) --声明函数体 RETURN STD_LOGIC_VECTOR IS BEGIN IF (a>b) THEN RETURN a; ELSE RETURN b; END IF; END max; END bpac1; 在设计实体中声明的数据类型、子程序或数据对象对于其他设计实体是不可再利用的。为了使已声明的数据类型、子程序、元件能被其他设计实体调用或共享,可以把它们汇集在程序包中。包中可以有多个元件和函数。 打开bpac1程序包的语句为:USE work.bpac1.ALL 放在实体声明前面 函数调用语句 函数名 (关联参数表) 例如,调用求最大值函数的语句为: peak<=max(data,peak);
元件例化语句 第一步 设计二输入与非门 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY nd2 IS PORT( a,b:IN STD_LOGIC; c:OUT STD_LOGIC); END nd2; ARCHITECTURE nd2behv OF nd2 IS BEGIN c<=a NAND b; END nd2behv; 第二步 将设计的元件声明装入my_pkg程序包中 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; PACKAGE my_pkg IS component nd2 --元件声明 PORT (a,b:IN STD_LOGIC; c:OUT STD_LOGIC); END component nd2 ; END my_pkg;
第三步 用元件例化产生图示的电路 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE work.my_pkg.ALL; --打开程序包 ENTITY ord41 IS PORT( a1,b1,c1,d1:IN STD_LOGIC; z1:OUT STD_LOGIC); END ord41; ARCHITECTURE ord41behv OF ord41 IS --元件例化 SIGNAL x,y:STD_LOGIC; BEGIN u1:nd2 PORT MAP(a1,b1,x); --位置关联方式 u2:nd2 PORT MAP(a=>c1,b=>d1,c=>y); --名字关联方式 u3:nd2 PORT MAP(x,y,c=>z1); --混合关联方式 END ord41behv;
整数文字由数字和下划线组成。下划线用来将数字分组,便于读出。 3.2 VHDL语言要素 3.2.1 VHDL文字规则 1.数字型文字 (1)整数文字 整数文字由数字和下划线组成。下划线用来将数字分组,便于读出。 例:5,678,156E2,45_234_287相当于(45,234,287) (2)实数文字 实数文字由数字、小数点和下划线组成。 例:188.993, 88_670_551.453_909相当于(88,670,551.453,909)
(3)以数字基数表示的文字 以数字基数表示的文字的格式为: 数制#数值# 例:10#170#; --十进制数值 16#FE#; --十六进制数值 2#11010001#; --二进制数值 8#376#; --八进制数字 (4)物理量文字 表示时间、长度等物理量。例如,60s,100m。 2.字符串文字 字符串文字包括字符和字符串。字符是以单引号括起来的数字、字母和符号。包括文字字符串和数值字符串。 (1)文字字符串 文字字符串是用双引号括起来的一维字符数组。 例:“ABC”,“A BOY”,“A”都是文字字符串。
(2)数值字符串 数值字符串也叫做矢量,格式为 数制基数符号“数值字符串” 例:B”111011110”; --二进制数数组,位矢量组长度是9 O”15”; --八进制数数组,等效B”001101”,位矢量组长度是6 X”AD0”; --十六进制数数组,等效B”101011010000”,位矢量组长度是12 B、O、X分别是二进制、八进制、十六进制基数符号。 3.标识符 标识符是用户给常量、变量、信号、端口、子程序或参数定义的名字。标识符的命名规则是:以字母开头,后跟若干字母、数字或单个下划线构成,但最后不能为下划线。 例: h_adder, mux21, example为合法标识符; 2adder, _mux21, ful__adder, adder_ 为错误的标识符。 4.下标名 下标名用于指示数组型变量或信号的某一元素。下标名的格式为: 标识符(表达式) 例:b(3), a(m)都是下标名。
5.段名 段名是多个下标名的组合。段名的格式为: 标识符(表达式 方向 表达式) 例: D(7 DOWNTTO 0); --可表示数据总线D7—D0 D(0 TO 7); --可表示数据总线D0—D7
3.2.2 VHDL数据对象 VHDL数据对象包括变量、常量和信号。 1.变量 变量(VARIABLE)是一个局部量。只能在进程(PROCESS)、函数(FUNCTION)和过程(PROCEDURE)中声明和使用。变量不能将信息带出对它定义的当前设计单元。变量赋值的数据传输是立即发生的,不存在延时。 变量要声明后才能使用,变量声明的语法格式为: VARIABLE 变量名:数据类型[:=初始值]; 例:VARIABLE a:INTEGER; --a为整型变量 VARIABLE b:INTEGER:=2; --b赋初值2 变量赋值语句的语法格式为: 目标变量名:=表达式 例: VARIABLE a,b:BIT_VECTOR(0 TO 7); VARIABLE x,y:INTEGER; x:=100; a:=“1010101” y:=15+x; a(3 TO 6):=(‘1’,’1’,’0’,’1’); a(0 TO 5):=b(2 TO 7); 是一种
2.信号 信号是描述硬件系统的基本数据对象。不仅可以容纳当前值,也可以保持历史值,类似于连线。 信号声明语句的语法格式为: SIGNAL 信号名:数据类型[:=初值]; SIGNAL temp:STD_LOGIC:=0; --temp为标准逻辑位信号 初值为0 SIGNAL flaga,flagb:BIT; --flaga,flagb为位信号 SIGNAL data:STD_LOGIC_VECTOR(15 DOWNTO 0); --data为标准逻辑位矢量,矢量长度为16 信号的赋值语句格式为: 目标信号名<=表达式 例:x<=9; z<=x AFTER 5ns; --目标信号需要一定延迟时间,设置延迟5ns 信号与变量是有区别的。变量在进程、函数和过程中声明,信号在结构体中声明。变量用“:=”号赋值,无延迟时间,而信号用“<=”赋值,赋值过程有延迟时间。信号赋初值的符号是“:=”。
3.常数 常数的声明格式为: CONSTANT 常数名:数据类型:=初值; 例: CONSTANT fbus:BIT_VECTOR:=“010111”; CONSTANT Vcc:REAL:=5.0; CONSTANT delay:TIME:25ns; 3.2.3 VHDL数据类型 1.BOOLEAN(布尔)数据类型 FALSE(假)和 TRUE(真),以枚举类型预定义,定义语句为: TYPE BOOLEAN IS (FALSE,TRUE); 2.BIT(位)数据类型 位数据类型包括‘0’和’1’,定义语句为: TYPE BIT IS (‘0’,’1’); 3.BIT_VECTOR 位矢量是用双引号括起来的数字序列,如“0011”,X”00FD”等。定义语句为: TYPE BIT_VECTOR IS ARRAY (Natural Range<>) OF BIT; 其中,<>表示数据范围未定界。在使用位矢量时,必须注明位宽, 例如:SIGNAL a:BIT_VECTOR (7 DOWNTO 0); 4.CHARACTER(字符)数据类型 字符是用单引号括起来的ASCII码字符,如‘A’,‘a’,定义语句为: Z TYPE CHARACTER IS (NUL,SOH,…);
5.INTEGER(整数)数据类型 整数包括正整数、负整数和零。整数是32位的带符号数。 6.NATURAL(自然数)和POSITIVE(正整数)数据类型 自然数是整数的一个子集,包括0和正整数。 7.REAL(实数)数据类型 实数由正、负、小数点和数字组成,例如,-1.0,+2.5,-1.0E38都是实数。 8.STRING(字符串)数据类型 字符串是用双引号括起来的字符序列,也称字符串矢量或字符串数组。例如,”A BOY.”,”1010011”等是字符串。 9.TIME(时间)数据类型 时间是物理量数据,由整数数据和单位两部分组成。定义语句为: TYPE TIME IS RANGE -2147483647 TO 2147483647
3.2.5 IEEE预定义的标准逻辑位和矢量 1.STD_LOGIC(标准逻辑位)数据类型 在VHDL中,标准逻辑位数据有九种逻辑值: ‘U’(未初始化的)、 ‘X’(强未知的)、 ‘0’(强0)、 ‘1’(强1)、 ‘Z’(高阻态)、 ‘W’(弱未知的)、 ‘L’(弱0)、 ‘H’(弱1)和’-’(忽略)。它们在STD_LOGIC_1164程序包中的定义语句: TYPE STD_LOGIC IS (‘U’,’X’,’0’,’1’,’Z’,’W’,’L’,’H’,’-’); 注意:STD_LOGIC数据类型中的数据是用大写字母定义的。 2. STD_LOGIC_VECTOR(标准逻辑矢量)数据类型 标准逻辑矢量数据在数字电路中常用于表示总线。它们在STD_LOGIC_1164程序包中的定义语句: TYPE STD_LOGIC_VECTOR IS ARRAY(Natural Range <>) OF STD_LOGIC;
3.2.6 VHDL操作符 VHDL的操作符包括逻辑操作符(Logic Operator)、关系操作符(Relational Operator) 、算术操作符(Arithmetic Operator)和符号操作符(Sign Operator)四类。 类型 操作符 功能 操作数数据类型 算 术 操 作 符 + 加 整数 - 减 & 并 一维数组 * 乘 整数和实数 / 除 MOD 取模 REM 求余 SLL 逻辑左移 BIT或布尔型一维数组 SRL 逻辑右移 SLA 算术左移 SRA 算术右移 ROL 逻辑循环左移 ROR 逻辑循环右移 ** 乘方 ABS 取绝对值
类型 操作符 功能 操作数数据类型 关 系 操 作 符 = 等于 任何数据类型 /= 不等于 < 小于 枚举与整数及对应的一维数组 > 大于 <= 小于等于 >= 大于等于 逻 辑 AND 与 BIT、BOOLEAN、STD_LOGIC OR 或 NAND 与非 NOR 或非 XOR 异或 NXOR 异或非 NOT 非 符号操作符 + 正 整数 - 负
注意: (1)要遵循在基本操作符间操作数是同数据类型的规则。 (2)要遵循操作数的数据类型必须与操作符要求的数据类型完全一致。 (3)包含多种操作符的表达式中,需要用括号将这些运算分组。例如(a OR b)XOR c (4)在VHDL中有并置运算操作符“&”,它用来完成一维数组的位扩展。例如,将一维数组s1,s2扩展为二维数组的语句是:s<=s1&s2。
VHDL的基本描述语句包括顺序语句(Sequential Statements)和并行语句(Concurrent Statements)。 顺序语句只能出现在进程(PROCESS)、过程(PROCEDURE)和函数(FUNCTION)中,按照程序书写的顺序自上而下、一条一条地执行。顺序语句可以描述数字逻辑系统中的组合逻辑电路和时序逻辑电路。 VHDL的顺序语句有赋值语句、流程控制语句、等待语句、子程序调用语句、返回语句和空操作语句等六类。
3.3.1 赋值语句 1.变量赋值语句 变量赋值语句的格式为: 目标变量名:=赋值源(表达式) 例如 x:=5.0。 2.信号赋值语句 信号赋值语句的格式为: 目标信号名<=赋值源 例如 y<=‘1’。 信号赋值语句可以出现在进程或结构体中,若出现在进程或子程序中则是顺序语句,若出现在结构体中则是并行语句。 对于数组元素赋值,可以采用下列格式: SIGNAL a,b:STD_LOGIC_VECTOR(1 TO 4); a<=“1101” --为信号a整体赋值 a(1 TO 2)<=“10”; --为信号a中的部分位赋值 a(1 TO 2)<=b(2 TO 3);
流程控制语句有IF语句、CASE语句、LOOP语句、NEXT语句和EXIT语句五种。 3.3.2 流程控制语句 流程控制语句有IF语句、CASE语句、LOOP语句、NEXT语句和EXIT语句五种。 1.IF语句 格式1为: IF 条件句 Then 顺序语句; END IF; 格式2为: ELSE 格式3 为: IF 条件句 Then 顺序语句; ELSEIF 条件句 Then … ELSE END IF; IF语句中至少应有1个条件语句,条件句必须由BOOLEAN表达式构成。 IF语句根据条件句产生的判断结果TRUE或FALSE,有条件的选择执行其后的顺序语句。
USE IEEE.STD_LOGIC_1164.ALL; ENTITY control1 IS 例:图示硬件电路的VHDL语言描述: LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY control1 IS PORT( a,b,c:IN BOOLEAN; y:OUT BOOLEAN); END control1; ARCHITECTURE example5 OF control1 IS BEGIN PROCESS(a,b,c) VARIABLE n:BOOLEAN; IF a THEN n:=b; ELSE n:=c; END IF; y<=n; END PROCESS; END example5; Y=a’c+ab
USE IEEE.STD_LOGIC_1164.ALL; ENTITY coder IS 例:8线-3线优先编码器的设计。 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY coder IS PORT( a:IN STD_LOGIC_VECTOR(7 DOWNTO 0); y:OUT STD_LOGIC_VECTOR(2 DOWNTO 0)); END coder; ARCHITECTURE example6 OF coder IS BEGIN PROCESS(a) IF (a(7)=‘0’) THEN y<=“111”; ELSEIF (a(7)=‘0’) THEN y<=“111”; ELSEIF (a(6)=‘0’) THEN y<=“110”; ELSEIF (a(5)=‘0’) THEN y<=“101”; ELSEIF (a(4)=‘0’) THEN y<=“100”; ELSEIF (a(3)=‘0’) THEN y<=“011”; ELSEIF (a(2)=‘0’) THEN y<=“010”; ELSEIF (a(1)=‘0’) THEN y<=“001”; ELSEIF (a(0)=‘0’) THEN y<=“000”; ELSE y<=“000”; END IF; END PROCESS; END example6; 输入 输出 a0 a1 a2 a3 a4 a5 a6 a7 y2 y1 y0 x x x x x x x 0 x x x x x x 0 1 x x x x x 0 1 1 x x x x 0 1 1 1 x x x 0 1 1 1 1 x x 0 1 1 1 1 1 x 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 0 0 0 1 1 0 1 0 0 0 1 0 0 0
USE IEEE.STD_LOGIC_1164.ALL; ENTITY mux41 IS PORT( s1,s2:IN STD_LOGIC; 2.CASE语句 用CASE语句描述4选1数据选择器 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY mux41 IS PORT( s1,s2:IN STD_LOGIC; a,b,c,d:IN STD_LOGIC; z:OUT STD_LOGIC); END mux41; ARCHITECTURE example7 OF mux41 IS SIGNAL s: STD_LOGIC_VECTOR(1 DOWNTO 0); BEGIN s<=s1&s2; --将s1和s2合并为s PROCESS(s1,s2,a,b,c,d) CASE s IS WHEN”00”=>z<=a; WHEN”01”=>z<=b; WHEN”10”=>z<=c; WHEN”11”=>z<=d; --条件句中的”=>”不是操作符,起到“THEN”的作用。 WHEN OTHERS=>z<=‘X’; --当s的值不是选择值时, z做未知处理 END CASE; END PROCESS; END example7; s1 s2 z 0 0 0 1 1 0 1 1 a b c d
3.LOOP语句 LOOP是循环语句,可以使一组顺序语句重复执行,执行的次数由设定的循环参数确定。 LOOP语句有3种格式,每种格式都可以用“标号”来给语句定位,但也可以不使用,用方括号将“标号”括起来,表示它为任选项。 (1)FOR_LOOP语句 例:8位奇偶校验器的描述 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY p_check IS PORT( a:IN STD_LOGIC_VECTOR(7 DOWNTO 0); y:OUT STD_LOGIC); END p_check ; ARCHITECTURE example8 OF p_check IS BEGIN PROCESS(a) VARIABLE temp:STD_LOGIC; temp:=‘0’; FOR n IN 0 TO 7 LOOP temp:=temp XOR a(n); END LOOP; y<=temp; END PROCESS; END example8;
(2)WHILE_LOOP语句 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY p_check_1 IS PORT( a:IN STD_LOGIC_VECTOR(7 DOWNTO 0); y:OUT STD_LOGIC); END p_check_1 ; ARCHITECTURE example8 OF p_check IS BEGIN PROCESS(a) VARIABLE temp:STD_LOGIC; VARIABLE n:INTEGER; temp:=‘0’; n:=0; WHILE n<8 LOOP temp:=temp XOR a(n); n:=n+1; END LOOP; y<=temp; END PROCESS; END example8;
1.时钟信号的VHDL描述 时钟信号的描述如图8.3所示,时钟上升沿和下降沿的到来表示发生了一个事件,用cp’EVENT表示,时钟的边沿变化可以用条件语句描述。例如: 时钟上升沿的到来可以写为“IF CLK'EVENT AND CLK='1'THEN”; 时钟下降沿的到来可以写为“IF CLK'EVENT AND CLK='0'THEN”。 也可以写做: 时钟上升沿“IF CLK=’1’AND CLK’LAST_VALUE=’0’ AND CLK’EVENT”; 时钟下降沿“IF CLK=’0’AND CLK’LAST_VALUE=’1’ AND CLK’EVENT”。 图8.3 时钟脉冲的VHDL描述
2.时序逻辑电路的VHDL描述 例8.14 带有异步复位、置位端的上升沿触发的D触发器。 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY DFF IS PORT( CLK,D,SET,RESET: IN BIT; Q: OUT BIT); END DFF; ARCHITECTURE ONE OF DFF IS BEGIN PROCESS(CLK,SET,RESET) IF SET='0' THEN Q<='1'; ELSIF RESET='0' THEN Q<='0'; ELSIF CLK'EVENT AND CLK='1'THEN Q<=D; END IF; END PROCESS; END ARCHITECTURE ONE;
例8.15 4位双向移位寄存器的VHDL程序,具有4种工作方式:数据保持、左移、右移和并行输入。 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY reg4 IS PORT( clk: IN BIT; din:IN BIT_VECTOR(3 DOWNTO 0); --并行输入数据 sin: IN BIT; --串行输入数据 mode:IN INTEGER RANGE 0 TO 3; --工作模式为0保持,1右移,2左移,3并入 Q: OUT BIT_VECTOR(3 DOWNTO 0)); --寄存器并行输出 END reg4;
ARCHITECTURE ONE OF reg4 IS SIGNAL FF:BIT_VECTOR(3 DOWNTO 0); BEGIN PROCESS(CLK) IF clk'EVENT AND clk='1'THEN CASE mode IS WHEN 0=>FF<=FF; --保持数据 WHEN 1=>FF(2 DOWNTO 0)<=FF(3 DOWNTO 1); --右移 FF(3)<=sin; WHEN 2=>FF(3 DOWNTO 1)<=FF(2 DOWNTO 0); --左移 FF(0)<=sin; WHEN OTHERS=>FF<=din; --并行输入 END CASE; END IF; END PROCESS; Q<=FF; --寄存器输出更新 END ARCHITECTURE ONE;