第 3章 VHDL编程基础第 3章 VHDL编程基础
3.1 概述
3.2 VHDL程序基本结构
3.3 VHDL语言要素
3.4 VHDL顺序语句
3.5 VHDL并行语句
3.6 子程序 (SUBPROGRAM)
3.7 库、程序包及其他
3.8 VHDL描述风格
3.9 基本逻辑电路设计
3.10 状态机的 VHDL设计第 3章 VHDL编程基础
3.1 概 述
3.1.1 常用硬件描述语言简介常用硬件描述语言有 VHDL,Verilog和 ABEL语言 。 VHDL
起源于美国国防部的 VHSIC,Verilog起源于集成电路的设计,
ABEL则来源于可编程逻辑器件的设计 。 下面从使用方面将三者进行对比 。
(1) 逻辑描述层次:一般的硬件描述语言可以在三个层次上进行电路描述,其层次由高到低依次可分为行为级,RTL级和门电路级。 VHDL语言是一种高级描述语言,适用于行为级和 RTL
级的描述,最适于描述电路的行为; Verilog语言和 ABEL语言是一种较低级的描述语言,适用于 RTL级和门电路级的描述,最适于描述门级电路。
第 3章 VHDL编程基础
(2) 设计要求,VHDL进行电子系统设计时可以不了解电路的结构细节,设计者所做的工作较少; Verilog和 ABEL语言进行电子系统设计时需了解电路的结构细节,设计者需做大量的工作 。
(3) 综合过程:任何一种语言源程序,最终都要转换成门电路级才能被布线器或适配器所接受。因此,VHDL语言源程序的综合通常要经过行为级 → RTL级 → 门电路级的转化,VHDL几乎不能直接控制门电路的生成。而 Verilog语言和 ABEL语言源程序的综合过程要稍简单,即经过 RTL级 → 门电路级的转化,易于控制电路资源。
第 3章 VHDL编程基础
(4) 对综合器的要求,VHDL描述语言层次较高,不易控制底层电路,因而对综合器的性能要求较高,Verilog和 ABEL对综合器的性能要求较低 。
(5) 支持的 EDA工具:支持 VHDL和 Verilog的 EDA工具很多,
但支持 ABEL的综合器仅仅 Dataio一家 。
(6) 国际化程度,VHDL和 Verilog已成为 IEEE标准,而
ABEL正朝国际化标准努力。
第 3章 VHDL编程基础
3.1.2 VHDL的优点
VHDL的英文全名是 Very-High-Speed Integrated Circuit
Hardware Description Language,诞生于 1982年。 1987年底,
VHDL被 IEEE ( The Institute of Electrical and Electronics Engineers)
和美国国防部确认为标准硬件描述语言。自 IEEE公布了 VHDL的标准版本 (IEEE-1076)之后,各 EDA公司相继推出了自己的 VHDL
设计环境,或宣布自己的设计工具可以和 VHDL接口。此后 VHDL
在电子设计领域得到了广泛的接受,并逐步取代了原有的非标准硬件描述语言。 1993年,IEEE对 VHDL进行了修订,从更高的抽象层次和系统描述能力上扩展 VHDL的内容,公布了新版本的
VHDL,即 IEEE标准的 1076-1993版本。现在,VHDL和 Verilog作为 IEEE的工业标准硬件描述语言,又得到众多 EDA公司的支持,
在电子工程领域,已成为事实上的通用硬件描述语言。有专家认为,在新的世纪中,VHDL与 Verilog语言将承担起几乎全部的数字系统设计任务。
第 3章 VHDL编程基础
VHDL主要用于描述数字系统的结构、行为、功能和接口。
除了含有许多具有硬件特征的语句外,VHDL的语言形式和描述风格与句法十分类似于一般的计算机高级语言。 VHDL的程序结构特点是将一项工程设计,或称设计实体 (可以是一个元件、一个电路模块或一个系统 )分成外部 (或称可视部分,即端口 )和内部 (或称不可视部分 ),即设计实体的内部功能和算法完成部分。
在对一个设计实体定义了外部界面后,一旦其内部开发完成后,
其他的设计就可以直接调用这个实体。这种将设计实体分成内外部分的概念是 VHDL系统设计的基本点。应用 VHDL进行工程设计的优点是多方面的,具体如下:
第 3章 VHDL编程基础
(1) 与其他的硬件描述语言相比,VHDL具有更强的行为描述能力 。 强大的行为描述能力是避开具体的器件结构,从逻辑行为上描述和设计大规模电子系统的重要保证 。 就目前流行的
EDA工具和 VHDL综合器而言,将基于抽象的行为描述风格的
VHDL程序综合成为具体的 FPGA和 CPLD等目标器件的网表文件已不成问题,只是在综合与优化效率上略有差异 。
(2) VHDL具有丰富的仿真语句和库函数,使得在任何大系统的设计早期,就能查验设计系统的功能可行性,随时可对系统进行仿真模拟,使设计者对整个工程的结构和功能可行性做出判断。
第 3章 VHDL编程基础
(3) VHDL语句的行为描述能力和程序结构,决定了它具有支持大规模设计的分解和已有设计的再利用功能。符合市场需求的大规模系统高效、高速的完成必须有多人甚至多个开发组共同并行工作才能实现,VHDL中设计实体的概念、程序包的概念、设计库的概念为设计的分解和并行工作提供了有利的支持。
第 3章 VHDL编程基础
(4) 用 VHDL完成一个确定的设计,可以利用 EDA工具进行逻辑综合和优化,并自动把 VHDL描述设计转变成门级网表 (根据不同的实现芯片 )。这种方式突破了门级设计的瓶颈,极大地减少了电路设计的时间和可能发生的错误,降低了开发成本。
利用 EDA工具的逻辑优化功能,可以自动地把一个综合后的设计变成一个更小、更高速的电路系统。反过来,设计者还可以容易地从综合和优化的电路获得设计信息,返回去更新修改
VHDL设计描述,使之更加完善。
第 3章 VHDL编程基础
(5) VHDL对设计的描述具有相对独立性 。 设计者可以不懂硬件的结构,也不必管最终设计的目标器件是什么,而进行独立的设计 。 正因为 VHDL的硬件描述与具体的工艺技术和硬件结构无关,所以 VHDL设计程序的硬件实现目标器件有广阔的选择范围,其中包括各种系列的 CPLD,FPGA及各种门阵列器件 。
(6) 由于 VHDL具有类属描述语句和子程序调用等功能,对于完成的设计,在不改变源程序的条件下,只需改变类属参量或函数,就能轻易地改变设计的规模和结构。
第 3章 VHDL编程基础
3.1.3 VHDL程序设计约定为了便于程序的阅读和调试,本书对 VHDL程序设计特作如下约定:
(1) 语句结构描述中方括号,[ ]”内的内容为可选内容 。
(2) 对于 VHDL的编译器和综合器来说,程序文字的大小写是不加区分的 。 本书一般使用大写 。
(3) 程序中的注释使用双横线,--”。在 VHDL程序的任何一行中,双横线,--”后的文字都不参加编译和综合。
第 3章 VHDL编程基础
(4) 为了便于程序的阅读与调试,书写和输入程序时,使用层次缩进格式,同一层次的对齐,低层次的较高层次的缩进两个字符 。
(5) 考虑到 MAX+plusII要求源程序文件的名字与实体名必须一致,因此为了使同一个 VHDL源程序文件能适应各个 EDA
开发软件上的使用要求,建议各个源程序文件的命名均与其实体名一致。
第 3章 VHDL编程基础
3.2 VHDL程序基本结构
3.2.1 VHDL程序设计举例
1,设计思路全加器可以由两个 1位的半加器构成,而 1位半加器可以由如图 3.1所示的门电路构成 。
1位半加器的端口信号 A 和 B分别是 2位相加的二进制输入信号,SO是相加和的输出信号,CO是进位输出信号,左边的门电路结构构成了右边的半加器 H_ADDER。在硬件上可以利用半加器构成如图 3.2所示的全加器,当然还可以将一组这样的全加器级联起来构成一个串行进位的加法器。图 3.2中,全加器
F_ADDER内部的功能结构是由 3个逻辑器件构成的,即由两个半加器 U1,U2和一个或门 U3连接而成。
第 3章 VHDL编程基础图 3.1 1位半加器逻辑原理图
A
B
CO
SO
H _ A D D E R
A
B
CO
SO
第 3章 VHDL编程基础图 3.2 1 位全加器逻辑原理图
A
B
CO
SO
H _ A D D E R
U1
A I N
B I N
C I N
S2
A
B
CO
SO
H _ A D D E R
U2
S1
S3
A
B
C
U3
O R 2
C O U T
S U M
F _ A D D E R
A I N
B I N
C I N
C O U T
S U M
第 3章 VHDL编程基础
2,VHDL源程序
1) 或门的逻辑描述
-- IEEE库的使用说明
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
--实体 OR2的说明
ENTITY OR2 IS
PORT(A,B,IN STD_LOGIC;
C,OUT STD_LOGIC);
END ENTITY OR2;
--实体 OR2的结构体 ART1的说明
ARCHITECTURE ART1 OF OR2 IS
BEGIN
C<=A OR B;
END ARCHITECTURE ART1;
第 3章 VHDL编程基础
2) 半加器的逻辑描述
-- IEEE库的使用说明
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
--实体 H_ADDER的说明
ENTITY H_ADDER IS
PROT(A,B,IN STD_LOGIC;
CO,SO,OUT STD_LOGIC);
第 3章 VHDL编程基础
END ENTITY H_ADDER;
-- 实体 H_ADDER的结构体 ART2的说明
ARCHITECTURE ART2 OF H_ADDER IS
BEGIN
SO<=(A OR B) AND (A NAND B);
CO<=NOT (A NAND B);
END ARCHITECTURE ART2;
第 3章 VHDL编程基础
3) 全加器的逻辑描述
-- IEEE库的使用说明
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
--实体 F_ADDER的说明
ENTITY F_ADDER IS
PORT(AIN,BIN,CIN,IN STD_LOGIC;
COUT,SUM,OUT STD_LOGIC);
END ENTITY F_ADDER;
--实体 F_ADDER的结构体 ART3的说明
ARCHITECTURE ART3 OF F_ADDER IS
--元件调用声明第 3章 VHDL编程基础
COMPONENT H_ADDER
PORT(A,B,IN STD_LOGIC;
CO,SO,OUT STD_LOGIC);
END COMPONENT;
COMPONENT OR2
PORT(A,B,IN STD_LOGIC;
C,OUT STD_LOGIC);
END COMPONENT;
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章 VHDL编程基础
3,说明及分析
(1) 整个设计包括三个设计实体,分别为 OR2,H_ADDER
和F _ADDER,其中实体 F_ADDER为顶层实体 。 三个设计实体均包括三个组成部分:库,程序包使用说明,实体说明和结构体说明 。 这三个设计实体既可以作为一个整体进行编译,综合与存档,也可以各自进行独立编译,独立综合与存档,或被其他的电路系统所调用 。
第 3章 VHDL编程基础
(2) 实体 OR2定义了或门 OR2的引脚信号 A,B(输入 )和 C(输出 ),其对应的结构体 ART1描述了输入与输出信号间的逻辑关系,即将输入信号 A,B相或后传给输出信号端 C,由此实体和结构体描述一个完整的或门元件 。
(3) 实体 H_ADDER及对应的结构体 ART2描述了一个如图
3.1所示的半加器。由其结构体的描述可以看到,它是由一个与非门、一个非门、一个或门和一个与门连接而成的,其逻辑关系来自于半加器真值表。在 VHDL中,逻辑算符 NAND,NOT、
OR和 AND分别代表“与非”、“非”、“或”和“与” 4种逻辑运算关系。
第 3章 VHDL编程基础
(4) 在全加器接口逻辑 VHDL描述中,根据图 3.2右侧的 1位二进制全加器 F_ADDER的原理图,实体 F_ADDER定义了引脚的端口信号属性和数据类型。其中,AIN和 BIN分别为两个输入的相加位,CIN为低位进位输入,COUT 为进位输出,SUM为 1
位和输出。其对应的结构体 ART3的功能是利用 COMPONENT
声明语句和 COMPONENT例化语句将上面由两个实体 OR2和
H_ADDER描述的独立器件,按照图 3.2全加器内部逻辑原理图中的接线方式连接起来。
第 3章 VHDL编程基础
(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。符号,=>”表示信号连接。
第 3章 VHDL编程基础
(6) 实体 F_ADDER引导的逻辑描述也是由三个主要部分构成的,即库、实体和结构体。从表面上看来,库的部分仅包含一个 IEEE标准库和打开的 IEEE.STD_LOGIC_1164.ALL程序包。但实际上,从结构体的描述中可以看出,其对外部的逻辑有调用的操作,这类似于对库或程序包中的内容作了调用。因此,库结构部分还应将上面的或门和半加器的 VHDL描述包括进去,作为工作库中的两个待调用的元件。由此可见,库结构也是 VHDL
程序的重要组成部分。
第 3章 VHDL编程基础
3.2.2 VHDL程序的基本结构从前面的设计实例可以看出,一个相对完整的 VHDL程序 (或称为设计实体 )具有如图 3.3所示的比较固定的结构。至少应包括三个基本组成部分:库、程序包使用说明,实体说明和实体对应的结构体说明。其中,库、程序包使用说明用于打开 (调用 )本设计实体将要用到的库、程序包;实体说明用于描述该设计实体与外界的接口信号说明,是可视部分;结构体说明用于描述该设计实体内部工作的逻辑关系,是不可视部分。在一个实体中,可以含有一个或一个以上的结构体,而在每一个结构体中又可以含有一个或多个进程以及其他的语句。根据需要,实体还可以有配置说明语句。配置说明语句主要用于以层次化的方式对特定的设计实体进行元件例化,或是为实体选定某个特定的结构体。
第 3章 VHDL编程基础如何才算一个完整的 VHDL程序 (设计实体 ),并没有完全一致的结论,因为不同的程序设计目的可以有不同的程序结构。
通常认为,一个完整的设计实体的最低要求应该能为 VHDL综合器所接受,并能作为一个独立设计单元,即以元件的形式存在的 VHDL程序。这里所谓的元件,既可以被高层次的系统所调用,成为该系统的一部分,也可以作为一个电路功能块而独立存在和独立运行。
第 3章 VHDL编程基础图 3.3 VHDL程序设计基本结构库、程序包使用说明配置 ( C ON F I GU R A T I ON )
结构体 ( AR C HI T E C T UR E )
实体 ( E NT I T Y)
P O R T 端口说明结构体说明
GE NE R I C 类属说明体实计设结构体功能描述第 3章 VHDL编程基础
3.2.3 实体 (ENTITY)
实体是一个设计实体的表层设计单元,其功能是对这个设计实体与外部电路进行接口描述 。 它规定了设计单元的输入输出接口信号或引脚,是设计实体经封装后对外的一个通信界面 。
1,实体语句结构实体说明单元的常用语句结构如下:
ENTITY 实体名 IS
[GENERIC(类属表 ); ]
[PORT(端口表 ); ]
END ENTITY 实体名;
第 3章 VHDL编程基础实体说明单元必须以语句,ENTITY 实体名 IS”开始,以语句,END ENTITY 实体名;”结束,其中的实体名是设计者自己给设计实体的命名,可作为其他设计实体对该设计实体进行调用时用。中间在方括号内的语句描述,在特定的情况下并非是必须的。例如构建一个 VHDL仿真测试基准等情况中可以省去方括号中的语句。
第 3章 VHDL编程基础
2,类属 (GENERIC)说明语句类属 (GENERIC)参量是一种端口界面常数,常以一种说明的形式放在实体或块结构体前的说明部分。类属为所说明的环境提供了一种静态信息通道,类属的值可以由设计实体外部提供。
因此,设计者可以从外面通过类属参量的重新设定而容易地改变一个设计实体或一个元件的内部电路结构和规模。
第 3章 VHDL编程基础类属说明的一般书写格式如下:
GENERIC([常数名;数据类型 [:设定值 ]
{;常数名:数据类型 [:设定值 ]});
类属参量以关键词 GENERIC引导一个类属参量表,在表中提供时间参数或总线宽度等静态信息。类属表说明用于确定设计实体和其外部环境通信的参数,传递静态的信息。类属说明在所定义的环境中的地位十分接近常数,但却能从环境 (如设计实体 )外部动态地接受赋值,其行为又有点类似于端口 PORT。因此,常如以上的实体定义语句那样,将类属说明放在其中,且放在端口说明语句的前面。
第 3章 VHDL编程基础在一个实体中定义的、可以通过 GENERIC参数类属的说明,
为它创建多个行为不同的逻辑结构。比较常见的情况是选用类属来动态规定一个实体端口的大小,或设计实体的物理特性,
或结构体中的总线宽度,或设计实体中、底层中同种元件的例化数量等。一般在结构体中,类属的应用与常数是一样的。例如,当用实体例化一个设计实体的器件时,可以用类属表中的参数项定制这个器件,如可以将一个实体的传输延时、上升和下降延时等参数加到类属参数表中,然后根据这些参数进行定制,这对于系统仿真控制是十分方便的。类属中的常数名是由设计者确定的类属常数名,数据类型通常取 INTEGER或 TIME等类型,设定值即为常数名所代表的数值。但需注意,综合器仅支持数据类型为整数的类属值。
第 3章 VHDL编程基础
【 例 3.2.1】
ENTITY MCK IS
GENERIC(WIDTH,INTEGER:=16);
PORT(ADD_BUS,OUT STD_LOGIC_VECTOR(WIDTH-1
DOWNTO 0)) ;
...
在这里,GENERIC语句对实体 MCK的作为地址总线的端口
ADD_BUS的数据类型和宽度作了定义,即定义 ADD_BUS为一个 16位的位矢量 。
第 3章 VHDL编程基础
【 例 3.2.2】 2输入与门的实体描述 。
ENTITY AND2 IS
GENERIC(RISEW,TIME:=1 ns;
FALLW,TIME:=1 ns);
PORT( A1,IN STD_LOGIC;
A0,IN STD_LOGIC;
Z0,OUT STD_LOGIC);
END ENTITY AND2;
这是一个准备作为 2输入与门的设计实体的实体描述,在类属说明中定义参数 RISEW为上沿宽度,FALLW为下沿宽度,它们分别为 1 ns,这两个参数用于仿真模块的设计。
第 3章 VHDL编程基础
3,PORT端口说明由 PORT引导的端口说明语句是对于一个设计实体界面的说明 。 实体端口说明的一般书写格式如下:
PORT(端口名:端口模式 数据类型;
{端口名:端口模式 数据类型 });
第 3章 VHDL编程基础其中,端口名是设计者为实体的每一个对外通道所取的名字;
端口模式是指这些通道上的数据流动方式,如输入或输出等;
数据类型是指端口上流动的数据的表达格式。由于 VHDL是一种强类型语言,它对语句中的所有操作数的数据类型都有严格的规定。一个实体通常有一个或多个端口,端口类似于原理图部件符号上的管脚。实体与外界交流的信息必须通过端口通道流入或流出。
第 3章 VHDL编程基础
IEEE 1076标准包中定义了 4种常用的端口模式,各端口模式的功能及符号分别见表 3.1和图 3.4。在实际的数字集成电路中,IN相当于只可输入的引脚,OUT相当于只可输出的引脚,
BUFFER相当于带输出缓冲器并可以回读的引脚 (与 TRI引脚不同 ),而 INOUT相当于双向引脚 (即 BIDIR引脚 )。由图 3.4的
INOUT电路可见,此模式的端口是普通输出端口 (OUT)加入三态输出缓冲器和输入缓冲器构成的。
在实用中,端口描述中的数据类型主要有两类:位 (BIT)和位矢量 (BIT_VECTOR)。若端口的数据类型定义为 BIT,则其信号值是一个 1位的二进制数,取值只能是 0或 1;若端口数据类型定义为 BIT_VECTOR,则其信号值是一组二进制。
第 3章 VHDL编程基础表 3.1 端口模式说明端口模式 端口模式说明 ( 以设计实体为主体 )
IN 输入,只读模式,将变量或信号信息通过该端口读入
OUT 输出,单向赋值模式,将信号通过该端口输出
BU F F E R 具有读功能的输出模式,可以读或写,只能有一个驱动源
IN O U T 双向,可以通过该端口读入或写出信息第 3章 VHDL编程基础图 3.4 端口模式符号图
IN O U T B U F F E R I N O U T
第 3章 VHDL编程基础
3.2.4 结构体 (ARCHITECTURE)
结构体是用于描述设计实体的内部结构以及实体端口间的逻辑关系。结构体内部构造的描述层次和描述内容一般可以用图 3.5来说明。一般地,一个完整的结构体由两个基本层次组成:
● 对数据类型、常数、信号、子程序和元件等元素的说明部分。
● 描述实体逻辑行为的,以各种不同的描述风格表达的功能描述语句。
第 3章 VHDL编程基础图 3.5 结构体构造图进程语句块语句体结构明说体构结述能描功体构结元件例化语句子程序调用语句信号赋值语句常数说明数据类型说明信号说明例化元件说明子程序说明第 3章 VHDL编程基础结构体将具体实现一个实体。每个实体可以有多个结构体,
每个结构体对应着实体不同结构和算法实现方案,其间的各个结构体的地位是同等的,它们完整地实现了实体的行为,但同一结构体不能为不同的实体所拥有。结构体不能单独存在,它必须有一个界面说明,即一个实体。对于具有多个结构体的实体,必须用 CONFIGURATION配置语句指明用于综合的结构体和用于仿真的结构体,即在综合后的可映射于硬件电路的设计实体中,一个实体只对应一个结构体。在电路中,如果实体代表一个器件符号,则结构体描述了这个符号的内部行为。当把这个符号例化成一个实际的器件安装到电路上时,则需配置语句为这个例化的器件指定一个结构体 (即指定一种实现方案 ),或由编译器自动选一个结构体。
第 3章 VHDL编程基础
1,结构体的一般语句格式结构体的语句格式如下:
ARCHITECTURE 结构体名 OF 实体名 IS
[说明语句 ]
BEGIN
[功能描述语句 ]
END ARCHITECTURE 结构体名;
其中,实体名必须是所在设计实体的名字,而结构体名可以由设计者自己选择,但当一个实体具有多个结构体时,结构体的取名不可重复。
第 3章 VHDL编程基础
2.结构体说明语句结构体中的说明语句是对结构体的功能描述语句中将要用到的信号 (SIGNAL)、数据类型 (TYPE)、常数 (CONSTANT)、
元件 (COMPONENT)、函数 (FUNCTION)和过程 (PROCEDURE)
等加以说明的语句。但在一个结构体中说明和定义的数据类型、
常数、元件、函数和过程只能用于这个结构体中,若希望其能用于其他的实体或结构体中,则需要将其作为程序包来处理。
第 3章 VHDL编程基础
3.功能描述语句结构如图 3.5所示的功能描述语句结构可以含有五种不同类型的,
以并行方式工作的语句结构。而在每一语句结构的内部可能含有并行运行的逻辑描述语句或顺序运行的逻辑描述语句。各语句结构的基本组成和功能分别是:
(1) 块语句是由一系列并行执行语句构成的组合体,它的功能是将结构体中的并行语句组成一个或多个模块。
第 3章 VHDL编程基础
(2) 进程语句定义顺序语句模块,用以将从外部获得的信号值,或内部的运算数据向其他的信号进行赋值。
(3) 信号赋值语句将设计实体内的处理结果向定义的信号或界面端口进行赋值。
(4) 子程序调用语句用于调用一个已设计好的子程序。
(5) 元件例化语句对其他的设计实体作元件调用说明,并将此元件的端口与其他的元件、信号或高层次实体的界面端口进行连接。
第 3章 VHDL编程基础
3.3 VHDL语言要素
3.3.1 VHDL文字规则
VHDL文字 (Literal)主要包括数值和标识符。数值型文字主要有数字型、字符串型、位串型。
1.数字型文字数字型文字的值有多种表达方式,现列举如下:
(1) 整数文字:整数文字都是十进制的数,如:
5,678,0,156E2(=15600),45_234_287(=45234287)
数字间的下划线仅仅是为了提高文字的可读性,相当于一个空的间隔符,而没有其他的意义,因而不影响文字本身的数值。
第 3章 VHDL编程基础
(2) 实数文字:实数文字也都是十进制的数,但必须带有小数点,如:
188.993,88_670_551.453_909(=88670551.453909),1.0,
44.99E-2(=0.4499),1.335,0.0
(3) 以数制基数表示的文字:用这种方式表示的数由五个部分组成。第一部分,用十进制数标明数制进位的基数;第二部分,数制隔离符号,#”;第三部分,表达的文字;第四部分,
指数隔离符号,#”;第五部分,用十进制表示的指数部分,这一部分的数如果是 0可以省去不写。现举例如下:
第 3章 VHDL编程基础
10#170# --(十进制数表示,等于 170)
2#1111_1110# --(二进制数表示,等于 254)
16#E#E1 --(十六进制数表示,等于 2#11100000#,等于 224)
16#F.01#E+2 --(十六进制数表示,等于 3841.00)
(4) 物理量文字 (VHDL综合器不接受此类文字 )。如:
60s(60秒 ),100m(100米 ),kΩ(千欧姆 ),177A(177安培 )
第 3章 VHDL编程基础
2,字符串型文字字符是用单引号引起来的 ASCII字符,可以是数值,也可以是符号或字母,如:‘ R?,‘ A?,‘ *’,‘ Z?。而字符串则是一维的字符数组,须放在双引号中。 VHDL中有两种类型的字符串:文字字符串和数位字符串。
(1) 文字字符串:文字字符串是用双引号引起来的一串文字,
如:
,ERROR”,,BOTH S AND Q EQUAL TO L”,,X”,
,BB$CC”
第 3章 VHDL编程基础
(2) 数位字符串:数位字符串也称位矢量,是预定义的数据类型 BIT的一位数组,它们所代表的是二进制、八进制或十六进制的数组,其位矢量的长度即为等值的二进制数的位数。数位字符串的表示首先要有计算基数,然后将该基数表示的值放在双引号中,基数符以,B”、,O”和,X”表示,并放在字符串的前面。它们的含义分别是:
● B:二进制基数符号,表示二进制数位 0或 1,在字符串中每一个位表示一个 BIT。
● O:八进制基数符号,在字符串中的第一个数代表一个八进制数,即代表一个 3位 (BIT)的二进制数。
第 3章 VHDL编程基础
● X:十六进制基数符号 (0~ F),代表一个十六进制数,
即代表一个 4位的二进制数。
例如:
B“1_1101_1110” --二进制数数组,位矢数组长度是 9
X“AD0” --十六进制数数组,位矢数组长度是 12
第 3章 VHDL编程基础
3.标识符标识符用来定义常数、变量、信号、端口、子程序或参数的名字。 VHDL的基本标识符就是以英文字母开头,不连续使用下划线,_”,不以下划线,_”结尾的,由 26个大小写英文字母、
数字 0~ 9以及下划线,_”组成的字符串。 VHDL?93标准还支持扩展标识符,但是目前仍有许多 VHDL工具不支持扩展标识符。
标识符中的英语字母不分大小写。 VHDL的保留字不能用于作为标识符使用。如,DECODER_1,FFT,Sig_N,NOT_ACK,
State0,Idle是合法的标识符;而 _DECODER_1,2FFT,SIG_#N,
NOT_ACK,RYY_RST,data_BUS,RETURN则是非法的标识符。
第 3章 VHDL编程基础
4.下标名及下标段名下标名用于指示数组型变量或信号的某一元素,而下标段名则用于指示数组型变量或信号的某一段元素,其语句格式如下:
数组类型信号名或变量名 (表达式 1 [TO/DOWNTO 表达式
2]);
表达式的数值必须在数组元素下标号范围以内,并且必须是可计算的。 TO表示数组下标序列由低到高,如,2 TO 8”;
DOWNTO表示数组下标序列由高到低,如,8 DOWNTO 2”。
第 3章 VHDL编程基础如果表达式是一个可计算的值,则此操作数可很容易地进行综合。如果是不可计算的,则只能在特定的情况下综合,
且耗费资源较大。
如下是下标名及下标段名使用示例:
SIGNAL A,B,C,BIT_VECTOR(0 TO 7);
SIGNAL M,INTEGER RANGE 0 TO 3;
SIGNAL Y,Z,BIT;
Y<=A(M); --M是不可计算型下标表示
Z<=B(3); --3是可计算型下标表示
C (0 TO 3)<=A (4 TO 7); --以段的方式进行赋值
C (4 TO 7)<=A (0 TO 3); --以段的方式进行赋值第 3章 VHDL编程基础
3.3.2 VHDL数据对象在 VHDL中,数据对象 (Data Objects)类似于一种容器,它接受不同数据类型的赋值。数据对象有三种,即常量
(CONSTANT)、变量 (VARIABLE)和信号 (SIGNAL)。前两种可以从传统的计算机高级语言中找到对应的数据类型,其语言行为与高级语言中的变量和常量十分相似。但信号是具有更多的硬件特征的特殊数据对象,是 VHDL中最有特色的语言要素之一。
第 3章 VHDL编程基础
1.常量 (CONSTANT)
常量的定义和设置主要是为了使设计实体中的常数更容易阅读和修改。例如,将位矢的宽度定义为一个常量,只要修改这个常量就能很容易地改变宽度,从而改变硬件结构。在程序中,常量是一个恒定不变的值,一旦作了数据类型的赋值定义后,在程序中不能再改变,因而具有全局意义。常量的定义形式如下:
CONSTANT 常量名:数据类型 ﹕ =表达式;
例如:
CONSTANT FBUS﹕ BIT_VECTOR﹕ =“010115”;
CONSTANT VCC﹕ REAL﹕ =5.0;
CONSTANT DELY﹕ TIME﹕ =25ns;
第 3章 VHDL编程基础
VHDL要求所定义的常量数据类型必须与表达式的数据类型一致。常量的数据类型可以是标量类型或复合类型,但不能是文件类型 (File)或存取类型 (Access)。
常量定义语句所允许的设计单元有实体、结构体、程序包、
块、进程和子程序。在程序包中定义的常量可以暂不设具体数值,它可以在程序包体中设定。
第 3章 VHDL编程基础常量的可视性,即常量的使用范围取决于它被定义的位置。
在程序包中定义的常量具有最大全局化特征,可以用在调用此程序包的所有设计实体中;定义在设计实体中的常量,其有效范围为这个实体定义的所有的结构体;定义在设计实体的某一结构体中的常量,则只能用于此结构体;定义在结构体的某一单元的常量,如一个进程中,则这个常量只能用在这一进程中。
第 3章 VHDL编程基础
2.变量 (VARIABLE)
在 VHDL语法规则中,变量是一个局部量,只能在进程和子程序中使用。变量不能将信息带出对它作出定义的当前设计单元。变量的赋值是一种理想化的数据传输,是立即发生,不存在任何延时的行为。 VHDL语言规则不支持变量附加延时语句。
变量常用在实现某种算法的赋值语句中。
第 3章 VHDL编程基础定义变量的语法格式如下:
VARIABLE 变量名:数据类型,=初始值;
例如:
VARIABLE A,INTEGER; --定义 A为整数型变量
VARIABLE B,C,INTEGER,=2; --定义 B和 C为整型变量,初始值为 2
第 3章 VHDL编程基础变量作为局部量,其适用范围仅限于定义了变量的进程或子程序中。仿真过程中惟一的例外是共享变量。变量的值将随变量赋值语句的运算而改变。变量定义语句中的初始值可以是一个与变量具有相同数据类型的常数值,也可以是一个全局静态表达式,这个表达式的数据类型必须与所赋值变量一致。此初始值不是必需的,综合过程中综合器将略去所有的初始值。
变量数值的改变是通过变量赋值来实现的,其赋值语句的语法格式如下:
目标变量名,=表达式;
第 3章 VHDL编程基础
3,信号 (SIGNAL)
信号是描述硬件系统的基本数据对象,它类似于连接线。
信号可以作为设计实体中并行语句模块间的信息交流通道。在
VHDL中,信号及其相关的信号赋值语句、决断函数、延时语句等很好地描述了硬件系统的许多基本特征。如硬件系统运行的并行性;信号传输过程中的惯性延时特性;多驱动源的总线行为等。
信号作为一种数值容器,不但可以容纳当前值,也可以保持历史值。这一属性与触发器的记忆功能有很好的对应关系。
信号的定义格式如下:
SIGNAL 信号名,数据类型 ﹕ =初始值;
第 3章 VHDL编程基础信号初始值的设置不是必需的,而且初始值仅在 VHDL的行为仿真中有效。与变量相比,信号的硬件特征更为明显,它具有全局性特性。例如,在程序包中定义的信号,对于所有调用此程序包的设计实体都是可见的;在实体中定义的信号,在其对应的结构体中都是可见的。
事实上,除了没有方向说明以外,信号与实体的端口 (PORT)
概念是一致的。相对于端口来说,其区别只是输出端口不能读入数据,输入端口不能被赋值。信号可以看成是实体内部的端口。
反之,实体的端口只是一种隐形的信号,端口的定义实际上是作了隐式的信号定义,并附加了数据流动的方向。信号本身的定义是一种显式的定义,因此,在实体中定义的端口,在其结构体中都可以看成一个信号,并加以使用而不必另作定义。以下是信号的定义示例:
第 3章 VHDL编程基础
SIGNAL S1,STD_LOGIG﹕ =0; --定义了一个标准位的单值信号 S1,初始值为低电平
SIGNAL S2,S3,BIT; --定义了两个位 BIT的信号 S2和 S3
SIGNAL S4,STD_LOGIC_VECTOR(15 DOWNTO 0); --定义了一个标准位矢的位矢量
--(数组、总线 )信号,共有 16个信号元素以下示例定义的信号数据类型是设计者自行定义的,这是
VHDL所允许的:
TYPE FOUR IS(?X?,‘ 0?,‘ I?,‘ Z?);
SIGNAL S1﹕ FOUR;
SIGNAL S2﹕ FOUR﹕ =?X?;
SIGNAL S3﹕ FOUR﹕ =?L?;
第 3章 VHDL编程基础其中,信号 S1的初始值取为默认值,VHDL规定初始值取值以取 LEFT'MOST项 (即数组中的最左项 )为默认值。在此例中是‘ X?(任意状态 )。
信号的使用和定义范围是实体、结构体和程序包。在进程和子程序中不允许定义信号。信号可以有多个驱动源,或者说赋值信号源,但必须将此信号的数据类型定义为决断性数据类型。
在进程中,只能将信号列入敏感表,而不能将变量列入敏感表。可见进程只对信号敏感,而对变量不敏感。
第 3章 VHDL编程基础
4.三者的使用比较
(1) 从硬件电路系统来看,常量相当于电路中的恒定电平,
如 GND或 VCC接口,而变量和信号则相当于组合电路系统中门与门间的连接及其连线上的信号值。
(2) 从行为仿真和 VHDL语句功能上看,二者的区别主要表现在接受和保持信号的方式、信息保持与传递的区域大小上。
例如信号可以设置延时量,而变量则不能;变量只能作为局部的信息载体,而信号则可作为模块间的信息载体。变量的设置有时只是一种过渡,最后的信息传输和界面间的通信都靠信号来完成。
第 3章 VHDL编程基础
(3) 从综合后所对应的硬件电路结构来看,信号一般将对应更多的硬件结构,但在许多情况下,信号和变量并没有什么区别。例如在满足一定条件的进程中,综合后它们都能引入寄存器。这时它们都具有能够接受赋值这一重要的共性,而 VHDL综合器并不理会它们在接受赋值时存在的延时特性。
(4) 虽然 VHDL仿真器允许变量和信号设置初始值,但在实际应用中,VHDL综合器并不会把这些信息综合进去。这是因为实际的 FPGA/CPLD芯片在上电后,并不能确保其初始状态的取向。因此,对于时序仿真来说,设置的初始值在综合时是没有实际意义的。
第 3章 VHDL编程基础
3.3.3 VHDL数据类型
VHDL是一种强类型语言,要求设计实体中的每一个常数、
信号、变量、函数以及设定的各种参量都必须具有确定的数据类型,并且相同数据类型的量才能互相传递和作用。 VHDL作为强类型语言的好处是使 VHDL编译或综合工具很容易地找出设计中的各种常见错误。 VHDL中的数据类型可以分成四大类。
标量型 (SCALAR TYPE):属单元素的最基本的数据类型,
通常用于描述一个单值数据对象,它包括实数类型、整数类型、
枚举类型和时间类型。
第 3章 VHDL编程基础复合类型 (COMPOSITE TYPE):可以由细小的数据类型复合而成,如可由标量复合而成。复合类型主要有数组型 (ARRAY)和记录型 (RECORD)。
存取类型 (ACCESS TYPE):为给定的数据类型的数据对象提供存取方式。
文件类型 (FILES TYPE):用于提供多值存取类型。
这四大数据类型又可分成在现成程序包中可以随时获得的预定义数据类型和用户自定义数据类型两个类别。预定义的 VHDL
数据类型是 VHDL最常用、最基本的数据类型。这些数据类型都已在 VHDL的标准程序包 STANDARD和 STD_LOGIC_1164及其他的标准程序包中作了定义,并可在设计中随时调用。
第 3章 VHDL编程基础用户自定义的数据类型以及子类型,其基本元素一般仍属
VHDL的预定义数据类型。尽管 VHDL仿真器支持所有的数据类型,但 VHDL综合器并不支持所有的预定义数据类型和用户自定义数据类型。如 REAL,TIME,FILE,ACCES等数据类型。在综合中,它们将被忽略或宣布为不支持。
第 3章 VHDL编程基础
1,VHDL的预定义数据类型
1) 布尔 (BOOLEAN)数据类型程序包 STANDARD中定义布尔数据类型的源代码如下:
TYPE BOOLEAN IS(FALES,TRUE);
布尔数据类型实际上是一个二值枚举型数据类型,它的取值有 FALSE和 TRUE两种。综合器将用一个二进制位表示
BOOLEAN型变量或信号。
例如,当 A大于 B时,在 IF语句中的关系运算表达式 (A>B)
的结果是布尔量 TRUE,反之为 FALSE。综合器将其变为 1或 0信号值,对应于硬件系统中的一根线。
第 3章 VHDL编程基础
2) 位 (BIT)数据类型位数据类型也属于枚举型,取值只能是 1或 0。位数据类型的数据对象,如变量、信号等,可以参与逻辑运算,运算结果仍是位的数据类型。 VHDL综合器用一个二进制位表示 BIT。
在程序包 STANDARD中定义的源代码是:
TYPE BIT IS (?0?,‘ 1?);
第 3章 VHDL编程基础
3) 位矢量 (BIT_VECTOR)数据类型位矢量只是基于 BIT数据类型的数组,在程序包
STANDARD中定义的源代码是:
TYPE BIT _VETOR IS ARRAY(NATURAL RANGE<>)OF
BIT;
使用位矢量必须注明位宽,即数组中的元素个数和排列,
例如:
SIGNAL A﹕ BIT_VECTOR(7 TO 0);
信号 A被定义为一个具有 8位位宽的矢量,它的最左位是
A(7),最右位是 A(0)。
第 3章 VHDL编程基础
4) 字符 (CHARACTER)数据类型字符类型通常用单引号引起来,如‘ A?。字符类型区分大小写,如‘ B?不同于‘ b?。字符类型已在 STANDARD程序包中作了定义。
第 3章 VHDL编程基础
5) 整数 (INTEGER)数据类型整数类型的数代表正整数、负整数和零。在 VHDL中,整数的取值范围是 -21 473 647~ +21 473 647,即可用 32位有符号的二进制数表示。在实际应用中,VHDL仿真器通常将
INTEGER类型作为有符号数处理,而 VHDL综合器则将
INTEGER作为无符号数处理。在使用整数时,VHDL综合器要求用 RANGE子句为所定义的数限定范围,然后根据所限定的范围来决定表示此信号或变量的二进制数的位数,因为 VHDL综合器无法综合未限定的整数类型的信号或变量。
第 3章 VHDL编程基础如语句,SIGNAL TYPE1 ﹕ INTEGER RANGE 0 TO 15;”
规定整数 TYPE1的取值范围是 0~ 15共 16个值,可用 4位二进制数来表示,因此,TYPE1将被综合成由四条信号线构成的信号。
整数常量的书写方式示例如下:
2 --十进制整数
10E4 --十进制整数
16#D2# --十六进制整数
2#11011010# --二进制整数第 3章 VHDL编程基础
6) 自然数 (NATURAL)和正整数 (POSITIVE)数据类型自然数是整数的一个子类型,非负的整数,即零和正整数;
正整数也是整数的一个子类型,它包括整数中非零和非负的数值。它们在 STANDARD程序包中定义的源代码如下:
SUBTYPE NATURAL IS INTEGER RANGE 0 TO
INTEGER 'HIGH;
SUBTYPE POSITIVE IS INTEGER RANGE 1 TO
INTEGER 'HIGH;
第 3章 VHDL编程基础
7) 实数 (REAL)数据类型
VHDL的实数类型类似于数学上的实数,或称浮点数。实数的取值范围为 -1.0E38~ +1.0E38。通常情况下,实数类型仅能在
VHDL仿真器中使用,VHDL综合器不支持实数,因为实数类型的实现相当复杂,目前在电路规模上难以承受。
实数常量的书写方式举例如下:
65971.333333 --十进制浮点数
8#43.6#E+4 --八进制浮点数
43.6E-4 --十进制浮点数第 3章 VHDL编程基础
8) 字符串 (STRING)数据类型字符串数据类型是字符数据类型的一个非约束型数组,或称为字符串数组。字符串必须用双引号标明。如:
VARIABLE STRING_VAR﹕ STRING(1 TO 7);

STRING_VAR﹕,A B C D”;
第 3章 VHDL编程基础
9) 时间 (TIME)数据类型
VHDL中惟一的预定义物理类型是时间。完整的时间类型包括整数和物理量单位两部分,整数和单位之间至少留一个空格,
如 55 ms,20 ns。
第 3章 VHDL编程基础
STANDARD 程序包中也定义了时间。定义如下:
TYPE TIME IS RANGE -2147483647 TO 2147483647
units
fs; --飞秒,VHDL中的最小时间单位
ps = 1000 fs; --皮秒
ns = 1000 ps; --纳秒
us = 1000 ns; --微秒
ms = 1000 us; --毫秒
sec = 1000 ms; --秒
min = 60 sec; --分
hr = 60 min; --时
end untis;
第 3章 VHDL编程基础
10) 错误等级 (SEVERITY_LEVEL)
在 VHDL仿真器中,错误等级用来指示设计系统的工作状态,
共有四种可能的状态值,NOTE(注意 ),WARNING(警告 )、
ERROR(出错 ),FAILURE(失败 )。在仿真过程中,可输出这四种值来提示被仿真系统当前的工作情况。其定义如下:
TYPE SEVERITY_LEVEL IS (NOTE,WARNING,ERROR,
FAILURE);
第 3章 VHDL编程基础
2,IEEE预定义标准逻辑位与矢量在 IEEE库的程序包 STD_LOGIC_1164中,定义了两个非常重要的数据类型,即标准逻辑位 STD_LOGIC 和标准逻辑矢量
STD_LOGIC_VECTOR。
1) 标准逻辑位 STD_LOGIC_1164中的数据类型以下是定义在 IEEE库程序包 STD_LOGIC_1164中的数据类型。数据类型 STD_LOGIC的定义如下所示:
TYPE STD_LOGIC IS ('U','X',‘ 0?,'1','Z','W','L',
'H','-');
第 3章 VHDL编程基础各值的含义是:
'U'--未初始化的,'X'--强未知的,‘ 0?--强 0,'1'--强 1,'Z'--
高阻态,'W'--弱未知的,'L'--弱 0,'H'--弱 1,'-'--忽略。
在程序中使用此数据类型前,需加入下面的语句:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
第 3章 VHDL编程基础由定义可见,STD_LOGIC是标准的 BIT数据类型的扩展,
共定义了 9种值,这意味着,对于定义为数据类型是标准逻辑位
STD_LOGIC的数据对象,其可能的取值已非传统的 BIT那样只有 0和 1两种取值,而是如上定义的那样有 9种可能的取值。目前在设计中一般只使用 IEEE的 STD_LOGIC标准逻辑的位数据类型,
BIT型则很少使用。
由于标准逻辑位数据类型的多值性,在编程时应当特别注意。因为在条件语句中,如果未考虑到 STD_LOGIC的所有可能的取值情况,综合器可能会插入不希望的锁存器。
第 3章 VHDL编程基础程序包 STD_LOGIC_1164中还定义了 STD_LOGIC型逻辑运算符 AND,NAND,OR,NOR,XOR和 NOT的重载函数,以及两个转换函数,用于 BIT与 STD_LOGIC的相互转换。
在仿真和综合中,STD_LOGIC值是非常重要的,它可以使设计者精确模拟一些未知和高阻态的线路情况。对于综合器,
高阻态和,-”忽略态可用于三态的描述。但就综合而言,
STD_LOGIC型数据能够在数字器件中实现的只有其中的 4种值,
即,-”、,0”、,1”和,Z”。当然,这并不表明其余的 5种值不存在。这 9种值对于 VHDL的行为仿真都有重要意义。
第 3章 VHDL编程基础
2) 标准逻辑矢量 (STD_LOGIC_VECTOR)数据类型
STD_LOGIC_VECTOR类型定义如下:
TYPE STD_LOGIC_VECTOR IS ARRAY (NATURAL
RANGE<>) OF STD_LOGIC;
显然,STD_LOGIC_VECTOR是定义在 STD_LOGIC_1164程序包中的标准一维数组,数组中的每一个元素的数据类型都是以上定义的标准逻辑位 STD_LOGIC。
STD_LOGIC_VECTOR数据类型的数据对象赋值的原则是:
同位宽、同数据类型的矢量间才能进行赋值。下例描述的是
CPU中数据总线上位矢赋值的操作示意情况,注意例中信号数据类型定义和赋值操作中信号的数组位宽。
第 3章 VHDL编程基础
【 例 3.3.1】

TYPE T_DATA IS ARRAY(7 DOWNTO 0) OF STD_LOGIC; -- 自定义数组类型
SIGNAL DATABUS,MEMORY,T_DATA; --定义信号 DATABUS,MEMORY
CPU﹕ PROCESS --CPU工作进程开始
VAR1ABLE REG1﹕ T_DATA --定义寄存器变量 REG1
BEGIN

DATABUS<=REG1; --向 8位数据总线赋值
END PROCESS CPU; --CPU工作进程结束
MEM﹕ PROCESS --RAM工作进程开始
BEGIN

DATABUS<=MEMORY;
END PROCESS MEM;

第 3章 VHDL编程基础
3,其他预定义标准数据类型
VHDL综合工具配带的扩展程序包中,定义了一些有用的类型。如 Synopsys公司在 IEEE库中加入的程序包
STD_LOGIC_ARITH中定义了如下的数据类型:无符号型
(UNSIGNED)、
有符号型 (SIGNED)、小整型 (SMALL _INT)。
在程序包 STD_LOGIC_ARITH中的类型定义如下:
TYPE UNSIGNED IS ARRAY (NATURAL RANGE <>) OF
STD_LOGIC;
TYPE SIGNED IS ARRAY (NATURAL RANGE<>) OF
STD_LOGIC;
SUBTYPE SMALL_INT IS INTEGER RANGE 0 TO 1;
第 3章 VHDL编程基础如果将信号或变量定义为这几个数据类型,就可以使用本程序包中定义的运算符。在使用之前,请注意必须加入下面的语句:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_ARITH.ALL;
UNSIGNED类型和 SIGNED类型是用来设计可综合的数学运算程序的重要类型,UNSIGNED用于无符号数的运算,
SIGNED用于有符号数的运算。在实际应用中,大多数运算都需要用到它们。
第 3章 VHDL编程基础在 IEEE程序包中,UNMERIC_STD和 NUMERIC_BIT程序包中也定义了 UNSIGNED型及 SIGNED型,NUMERIC_STD是针对于 STD_LOGIC型定义的,而 NUMERIC_BIT是针对于 BIT
型定义的。在程序包中还定义了相应的运算符重载函数。有些综合器没有附带 STD_LOGIC_ARITH程序包,此时只能使用
NUMBER_STD和 NUMERIC_BIT程序包。
在 STANDARD程序包中没有定义 STD_LOGIC_VECTOR的运算符,而整数类型一般只在仿真的时候用来描述算法,或作数组下标运算,因此 UNSIGNED和 SIGNED的使用率是很高的。
第 3章 VHDL编程基础
1) 无符号数据类型 (UNSIGNED TYPE)
UNSIGNED数据类型代表一个无符号的数值,在综合器中,
这个数值被解释为一个二进制数,这个二进制数的最左位是其最高位。例如,十进制的 8可以作如下表示:
UNSIGNED(“1000")
如果要定义一个变量或信号的数据类型为 UNSIGNED,则其位矢长度越长,所能代表的数值就越大。如一个 4位变量的最大值为 15,一个 8位变量的最大值则为 255,0是其最小值,不能用
UNSIGNED定义负数。以下是两则无符号数据定义的示例:
第 3章 VHDL编程基础
VARIABLE VAR﹕ UNSIGNED(0 TO 10);
SIGNAL SIG﹕ UNSIGNED(5 TO 0);
其中,变量 VAR有 11位数值,最高位是 VAR(0),而非
VAR(10);信号 SIG有 6位数值,最高位是 SIG(5)。
第 3章 VHDL编程基础
2) 有符号数据类型 (SIGNED TYPE)
SIGNED数据类型表示一个有符号的数值,综合器将其解释为补码,此数的最高位是符号位,例如,SIGNED(“0101”) 代表 +5,5; SIGNED(“1011”) 代表 -5。
若将上例的 VAR定义为 SIGNED数据类型,则数值意义就不同了,如:
VARIABLE VAR﹕ SIGNED(0 TO 10);
其中,变量 VAR有 11位,最左位 VAR(0)是符号位。
第 3章 VHDL编程基础
4,用户自定义数据类型方式
VHDL允许用户自行定义新的数据类型,它们可以有多种,
如枚举类型 (ENUMERA-
TION TYPE)、整数类型 (INTEGER TYPE)、数组类型
(ARRAY TYPE)、记录类型 (RECORD TYPE)、时间类型 (TIME
TYPE)、实数类型 (REAL TYPE)等。用户自定义数据类型是用类型定义语句 TYPE和子类型定义语句 SUBTYPE实现的,以下将介绍这两种语句的使用方法。
第 3章 VHDL编程基础
1) TYPE语句用法
TYPE语句语法结构如下:
TYPE 数据类型名 IS 数据类型定义 [OF 基本数据类型 ];
其中,数据类型名由设计者自定;数据类型定义部分用来描述所定义的数据类型的表达方式和表达内容;关键词 OF后的基本数据类型是指数据类型定义中所定义的元素的基本数据类型,一般都是取已有的预定义数据类型,如 BIT,STD_LOGIC
或 INTEGER等。
第 3章 VHDL编程基础以下列出了两种不同的定义方式:
TYPE ST1 IS ARRAY(0 TO 15)OF STD_LOGIC;
TYPE WEEK IS (SUN,MON,TUE,WED,THU,FRI,SAT);
第一句定义的数据 ST1是一个具有 16个元素的数组型数据类型,数组中的每一个元素的数据类型都是 STD_LOGIC型;第二句所定义的数据类型是由一组文字表示的,而其中的每一文字都代表一个具体的数值,如可令 SUN=“1010”。
在 VHDL中,任一数据对象 (SIGNAL,VARIABLE、
CONSTANT)都必须归属某一数据类型,只有同数据类型的数据对象才能进行相互作用。利用 TYPE语句可以完成各种形式的自定义数据类型以供不同类型的数据对象间的相互作用和计算。
第 3章 VHDL编程基础
2) SUBTYPE语句用法子类型 SUBTYPE只是由 TYPE所定义的原数据类型的一个子集,它满足原数据类型的所有约束条件,原数据类型称为基本数据类型。子类型 SUBTYPE的语句格式如下:
SUBTYPE 子类型名 IS 基本数据 RANGEA 约束范围;
子类型的定义只在基本数据类型上作一些约束,并没有定义新的数据类型。子类型定义中的基本数据类型必须在前面已通过 TYPE定义的类型。如下例:
SUBTYPE DIGITS INTEGER RANGE 0 TO 9;
第 3章 VHDL编程基础例中,INTEGER是标准程序包中已定义过的数据类型,子类型 DIGITS只是把 INTEGER约束到只含 10个值的数据类型。
由于子类型与其基本数据类型属同一数据类型,因此属于子类型的和属于基本数据类型的数据对象间的赋值和被赋值可以直接进行,不必进行数据类型的转换。
利用子类型定义数据对象的好处是,除了使程序提高可读性和易处理外,其实质性的好处在于有利于提高综合的优化效率,这是因为综合器可以根据子类型所设的约束范围,有效地推知参与综合的寄存器的最合适的数目。
第 3章 VHDL编程基础
5,枚举类型
VHDL中的枚举数据类型是用文字符号来表示一组实际的二进制数的类型 (若直接用数值来定义,则必须使用单引号 )。例如状态机的每一状态在实际电路虽是以一组触发器的当前二进制数位的组合来表示的,但设计者在状态机的设计中,为了更便于阅读和编译,往往将表征每一状态的二进制数组用文字符号来代表。
第 3章 VHDL编程基础
【 例 3.3.2】
TYPE M_STATE IS( STATE1,STATE2,STATE3,STATE4,
STATE5);
SIGNAL CURRENT_STATE,NEXT_STATE,M_STATE;
在这里,信号 CURRENT_STATE和 NEXT_STATE的数据类型定义为 M_STATE,它们的取值范围是可枚举的,即从
STATE1~ STATE5共 5种,而这些状态代表 5组惟一的二进制数值。
第 3章 VHDL编程基础在综合过程中,枚举类型文字元素的编码通常是自动的,
编码顺序是默认的,一般将第一个枚举量 (最左边的量 )编码为 0,
以后的依次加 1。综合器在编码过程中自动将第一枚举元素转变成位矢量,位矢的长度将取所需表达的所有枚举元素的最小值。
如上例中用于表达 5个状态的位矢长度应该为 3,编码默认值为如下方式:
STATE1='000'; STATE2='001'; STATE3='010'; STATE4='011';
STATE5='100';
于是它们的数值顺序便成为
STATE1<STATE2<STATE3<STATE4<STATE5。一般而言,编码方法因综合器不同而不同。
为了某些特殊的需要,编码顺序也可以人为设置。
第 3章 VHDL编程基础
6.整数类型和实数类型整数和实数的数据类型在标准的程序包中已作了定义,但在实际应用中,特别在综合中,由于这两种非枚举型的数据类型的取值定义范围太大,综合器无法进行综合。因此,定义为整数或实数的数据对象的具体的数据类型必须由用户根据实际的需要重新定义,并限定其取值范围,以便能为综合器所接受,
从而提高芯片资源的利用率。
实际应用中,VHDL仿真器通常将整数或实数类型作为有符号数处理,VHDL综合器对整数或实数的编码方法是:
第 3章 VHDL编程基础
·对用户已定义的数据类型和子类型中的负数,编码为二进制补码;
·对用户已定义的数据类型和子类型中的正数,编码为二进制原码。
编码的位数,即综合后信号线的数目只取决于用户定义的数值的最大值。在综合中,以浮点数表示的实数将首先转换成相应数值大小的整数。因此在使用整数时,VHDL综合器要求使用数值限定关键词 RANGE,对整数的使用范围作明确的限制。
如下例所示:
第 3章 VHDL编程基础
【 例 3.3.3】
数据类型定义 综合结果
TYPE N1 IS RANGE 0 TO 100; --7位二进制原码
TYPE N2 IS RANGE 10 TO 100; --7位二进制原码
TYPE N3 IS RANGE -100 TO 100; --8位二进制补码
SUBTYPE N4 IS N3 RANGE 0 TO 6; --3位二进制原码第 3章 VHDL编程基础
7.数组类型数组类型属复合类型,是将一组具有相同数据类型的元素集合在一起,作为一个数据对象来处理的数据类型。数组可以是一维 (每个元素只有一个下标 )数组或多维数组 (每个元素有多个下标 )。 VHDL仿真器支持多维数组,但 VHDL综合器只支持一维数组。
数组的元素可以是任何一种数据类型,用以定义数组元素的下标范围子句决定了数组中元素的个数,以及元素的排序方向,即下标数是由低到高,或是由高到低。如子句,0 TO 7”是由低到高排序的 8个元素;,15 DOWNTO 0”是由高到低排序的
16个元素。
第 3章 VHDL编程基础
VHDL允许定义两种不同类型的数组,即限定性数组和非限定性数组。它们的区别是,限定性数组下标的取值范围在数组定义时就被确定了,而非限定性数组下标的取值范围需留待随后根据具体数据对象再确定。
第 3章 VHDL编程基础限定性数组定义语句格式如下:
TYPE 数组名 IS ARRAY (数组范围 ) OF数据类型;
其中,数组名是新定义的限定性数组类型的名称,可以是任何标识符,其类型与数组元素相同;数组范围明确指出数组元素的定义数量和排序方式,以整数来表示其数组的下标;数据类型即指数组各元素的数据类型。
第 3章 VHDL编程基础
【 例 3.3.4】
TYPE STB IS ARRAY(7 DOWNTO 0) OF STD_LOGIC;
这个数组类型的名称是 STB,它有 8个元素,它的下标排序是 7,6,5,4,3,2,1,0,各元素的排序是 STB(7),
STB(6),…,STB(1),STB(0)。
第 3章 VHDL编程基础
【 例 3.3.5】
TYPE X IS (LOW,HIGH);
TYPE DATA_BUS IS ARRAY (0 TO 7,X) OF BIT;
首先定义 X为两元素的枚举数据类型,然后将 DATA_BUS
定义为一个数组类型,其中每一元素的数据类型是 BIT。
第 3章 VHDL编程基础非限制性数组的定义语句格式如下:
TYPE 数组名 IS ARRAY (数组下标名 RANGE<>) OF 数据类型;
其中,数组名是定义的非限制性数组类型的取名;数组下标名是以整数类型设定的一个数组下标名称;符号,< >”是下标范围待定符号,用到该数组类型时,再填入具体的数值范围;
数据类型是数组中每一元素的数据类型。
以下三例表达了非限制性数组类型的不同用法。
第 3章 VHDL编程基础
【 例 3.3.6】
TYPE BIT_VECTOR IS ARRAY(NATURAL RANE<>) OF BIT;
VARABLE VA,BIT_VECTOR(1 TO 6);
--将数组取值范围定在 1~ 6
第 3章 VHDL编程基础
【 例 3.3.7】
TYPE REAL_MATRIX IS ARRAY (POSITIVE RANGE<>) OF
REAL;
VARIABLE REAL_MATRIX_OBJECT,REAL_MATRIX(1 TO
8); - -限定范围第 3章 VHDL编程基础
【 例 3.3.8】
TYPE LOGIC_VECTOR IS ARRAY(NATURAL RANGE<>,
POSITIVE RANGE<>) OF LOG_4;
VARIABLEL4_OBJECT,LOG_4_VECTOR(0 TO 7,1 TO 2);
--限定范围第 3章 VHDL编程基础
8.记录类型由已定义的、数据类型不同的对象元素构成的数组称为记录类型的对象。定义记录类型的语句格式如下:
TYPE 记录类型名 IS RECORD
元素名,元素数据类型;
元素名,元素数据类型;

END RECORD [记录类型名 ];
第 3章 VHDL编程基础
【 例 3.3.9】
TYPE RECDATA IS RECORD --将 RECDATA定义为四元素记录类型
ELEMENT1 ﹕ TIME; --将元素 ELEMENT1定义为时间类型
ELEMENT2 ﹕ TIME; --将元素 ELEMENT2定义为时间类型
ELEMENT3 ﹕ STD_LOGIC; --将元素 ELEMENT3定义为标准位类型
END RECORD;
第 3章 VHDL编程基础对于记录类型的数据对象赋值的方式,可以是整体赋值也可以是对其中的单个元素进行赋值。在使用整体赋值方式时,
可以有位置关联方式或名字关联方式两种表达方式。如果使用位置关联,则默认为元素赋值的顺序与记录类型声明时的顺序相同。如果使用了 OTHERS选项,则至少应有一个元素被赋值,
如果有两个或更多的元素由 OTHERS选项来赋值,则这些元素必须具有相同的类型。此外,如果有两个或两个以上的元素具有相同的子类型,就可以以记录类型的方式放在一起定义。
第 3章 VHDL编程基础
【 例 3.3.10】 利用记录类型定义的一个微处理器命令信息表。
TYPE REGNAME IS (AX,BX,CX,DX);
TYPE OPERATION IS RECORD
OPSTR﹕ STRING(1 TO 10);
OPCODE﹕ BIT_VECTOR(3 DOWNTO 0);
OP1,OP2,RES,REGNAME;
END RECORD;
VARIABLE INSTR1,INSTR2,OPERATION;

第 3章 VHDL编程基础
INSTR1﹕ =("ADD AX,BX","0001",AX,BX,AX);
INSTR2﹕ =("ADD AX,BX",,0010",OTHERS=>BX);
VARIABLE INSTR3﹕ OPERATION;

INSTR3.MNEMONIC﹕ ="MUL AX,BX";
INSTR3.OP1﹕ =AX;
第 3章 VHDL编程基础本例中,定义的记录 OPERATION共有五个元素,一个是加法指令码的字符串 OPSTR,一个是 4位操作码 OPCODE,另三个是枚举型数据 OP1,OP2,RES(其中 OP1和 OP2是操作数,RES
是目标码 )。例中定义的变量 INSTR1的数据类型是记录型
OPERATION,它的第一个元素是加法指令字符串 "ADD AX,
BX";第二个元素是此指令的 4位命令代码,0001”;第三、第四个元素为 AX和 BX; AX和 BX相加后的结果送入第五个元素
AX,因此这里的 AX是目标码。
第 3章 VHDL编程基础语句,INSTR3,OPSTR﹕ =?MUL AX,BX;’”赋给
INSTR3中的元素 OPSTR。一般地,对于记录类型的数据对象进行单元素赋值时,就在记录类型对象名后加点 (“.”),再加赋值元素的元素名。
记录类型中的每一个元素仅为标量型数据类型构成称为线性记录类型;否则为非线性记录类型。只有线性记录类型的数据对象都是可综合的。
第 3章 VHDL编程基础
9.数据类型转换由于 VHDL是一种强类型语言,这就意味着即使对于非常接近的数据类型的数据对象,在相互操作时,也需要进行数据类型转换。
1) 类型转换函数方式类型转换函数的作用就是将一种属于某种数据类型的数据对象转换成属于另一种数据类型的数据对象。
第 3章 VHDL编程基础
【 例 3.3.11】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY CNT4 IS
PORT(CLK﹕ IN STD_LOGIC;
P﹕ INOUT STD_LOGIC_VECTOR(3 DOWNTO 0);
END CNT4;
LIBRARY DATAIO;
USE DATAIO.STD_LOGIC_OPS.ALL
ARCHITECTURE BEHV OF CNT4 IS
BEGIN
第 3章 VHDL编程基础
PROCESS(CLK)
BEGIN
IF CLK=?1?AND CLK'EVENT THEN
P<=TO_VECTOR(2,TO_INTEGER(P)+1);
END IF
END PROCESS;
END BEHV;
第 3章 VHDL编程基础此例中利用了 DATAIO库中的程序包 STD_LOGIC_OPS中的两个数据类型转换函数,TO_VECTOR和 TO_INTEGER(前者将
INTEGER 转换成 STD_LOGIC_VECTOR,后者将
STD_LOGIC_VECTOR转换成 INTEGER)。通过这两个转换函数,
就可以使用,+”运算符进行直接加 1操作了,同时又能保证最后的加法结果是 STD_LOGIC_VECTOR数据类型。
利用类型转换函数来进行类型的转换需定义一个函数,使其参数类型为被转换的类型,返回值为转换后的类型。这样就可以自由地进行类型转换。在实际应用中,类型转换函数是很常用的。
VHDL的标准程序包中提供了一些常用的转换函数。
第 3章 VHDL编程基础
【 例 3.3.12】
FUCTION TO_BIT (S﹕ STD_ULOGIC; XMAP﹕ BIT:=?0?)RETURN BIT;
FUNCTION TO_BITVECTOR(S﹕ STD_LOGIC_VECTOR;
XMAP﹕ BIT:=?0?)RETURN BIT_VECTOR;
FUNCTION TO_BITVECTOR(S﹕ STD_ULOGIC_VECTOR;
XMAP﹕ BIT:=?0?)RETURN BIT_VECTOR;
第 3章 VHDL编程基础下面是转换函数 TO_BITVECTOR的函数体:
FUNCTION TO_BITVECTOR(S﹕ STD_LOGIC_VECTOR;
XMAP﹕ BIT:=?0?)
RETURN BIT_VECTOR IS
ALIAS SV﹕ STD_LOGIC_VECTOR(S'LENGTH-1 DOWNTO 0) IS S;
VARIABLE RESULT﹕ BIT_VECTOR(S'LENGTH-1 DOWNTO 0);
BEGIN
FOR I IN RESULT?RANGE LOOP
第 3章 VHDL编程基础
CASE SV(I) IS
WHEN '0'|'L'=>RESULT(I):='0';
WHEN '1'|'H' =>RESULT(I):='1';
WHEN OTHERS=>RESULT(I),=XMAP;
END CASE;
END LOOP;
RETURN RESULT;
END;
第 3章 VHDL编程基础不难看出,转换函数 TO_BITVECTOR 的功能就是将
STD_LOGIC_VECTOR的数据类型转换成 BIT_VECTOR的数据类型。
注意,在 STANDARD程序包和 STD_LOGIC_1164程序包都没有定义 VECTOR与 INTEGER类型之间的转换函数,而 EDA工具厂商的程序包里含有这些转换类型。
第 3章 VHDL编程基础
2) 直接类型转换方式直接类型转换的一般语句格式是:
数据类型标识符 (表达式 )
一般情况下,直接类型转换仅限于非常关联 (数据类型相互间的关联性非常大 )的数据类型之间,必须遵循以下规则:
(1) 所有的抽象数字类型是非常关联的类型 (如整型、浮点型 ),如果浮点数转换为整数,则转换结果是最接近的一个整型数。
第 3章 VHDL编程基础
(2) 如果两个数组有相同的维数、两个数组的元素是同一类型,并且在各处的下标范围内索引是同一类型或非常接近的类型,那么这两个数组是非常关联类型。
(3) 枚举型不能被转换。
如果类型标识符所指的是非限定数组,则结果会将被转换的数组的下标范围去掉,即成为非限定数组。如果类型标识符所指的是限定性数组,则转换后的数组的下标范围与类型标识符所指的下标范围相同。转换结束后,数组中元素的值等价于原数组中的元素值,见例 3.3.13。
第 3章 VHDL编程基础
【 例 3.3.13】
VARIABLE DATAC,PARAMC,INTEGER;

DATAC:=INTEGER(74.94*REAL(PARAMC));
在类型与其子类型之间无需类型转换。即使两个数组的下标索引方向不同,这两个数组仍有可能是非常关联类型的。
第 3章 VHDL编程基础
3.3.4 VHDL操作符
VHDL的各种表达式由操作数和操作符组成,其中操作数是各种运算的对象,而操作符则规定运算的方式。
1.操作符种类及对应的操作数类型在 VHDL中,有四类操作符,即逻辑操作符 (Logical
Operator)、关系操作符 (Relational Operator)和算术操作符
(Arithmetic Operator),此外还有重载操作符 (Overloading
Operator)。前三类操作符是完成逻辑和算术运算的最基本的操作符的单元,重载操作符是对基本操作符作了重新定义的函数型操作符。各种操作符所要求的操作数的类型详见表 3.2,操作符之间的优先级别见表 3.3。
第 3章 VHDL编程基础 表 3.2 VHDL操作符列表类 型 操作符 功 能 操作数数据类型
+ 加 整数
– 减 整数
& 并置 一维数组
* 乘 整数和实数 ( 包括浮点数 )
/ 除 整数和实数 ( 包括浮点数 )
M O D 取模 整数
RE M 取余 整数
S L L 逻辑左移 BIT 或布尔型一维数组
S RL 逻辑右移 BIT 或布尔型一维数组
S L A 算术左移 BIT 或布尔型一维数组
S RA 算术右移 BIT 或布尔型一维数组
RO L 逻辑循环左移 BIT 或布尔型一维数组
RO R 逻辑循环右移 BIT 或布尔 型一维数组
** 乘方 整数
A BS 取绝对值 整数
+ 正 整数算术操作符
– 负 整数第 3章 VHDL编程基础
= 等于 任何数据类型
/= 不等于 任何数据类型
< 小于 枚举与整数类型,及对应的一维数组
> 大于 枚举与整数类型,及对应的一维数组
<= 小于等于 枚举与整数类型,及对应的一维数组关系操作符
>= 大于等于 枚举与整数类型,及对应的一维数组
AND 与 BIT,BO O L E A N,S T D _ L O G IC
O R 或 BIT,BO O L E A N,S T D _ L O G IC
NAND 与非 BIT,BO O L E A N,S T D _ L O G IC
NOR 或非 BIT,BO O L E A N,S T D _ L O G IC
X O R 异或 BIT,BO O L E A N,S T D _ L O G IC
X N O R 异或非 BIT,BO O L E A N,S T D _ L O G IC
逻辑操作符
NOT 非 BIT,BO O L E A N,S T D _ L O G IC
表 3.2 VHDL操作符列表第 3章 VHDL编程基础表 3.3 VHDL操作符优先级运 算 符 优 先 级
NOT,A B S,**
*,/,M O D,R E M
+ ( 正号 ),- ( 负号 )
+,-,&
S L L,S L A,S R L,S R A,R O L,R O R
=,/ =,<,< =,>,> =
AND,O R,N A N D,N O R,X O R,X N OR
最高优先级最低优先级第 3章 VHDL编程基础
2,各种操作符的使用说明
(1) 严格遵循在基本操作符间操作数是同数据类型的规则;
严格遵循操作数的数据类型必须与操作符所要求的数据类型完全一致的规则 。
(2) 注意操作符之间的优先级别。当一个表达式中有两个以上的算符时,可使用括号将这些运算分组。
(3) VHDL共有 7种基本逻辑操作符,对于数组型 (如
STD_LOGIC_VECTOR)数据对象的相互作用是按位进行的。一般情况下,经综合器综合后,逻辑操作符将直接生成门电路。
信号或变量在这些操作符的直接作用下,可构成组合电路。
第 3章 VHDL编程基础
(4) 关系操作符的作用是将相同数据类型的数据对象进行数值比较 (=,/=)或关系排序判断 (<,<=,>,>=),并将结果以布尔类型 (BOOTLEAN)的数据表示出来,即 TRUE或 FALSE两种。
对于数组或记录类型的操作数,VHDL编译器将逐位比较对应位置各位数值的大小而进行比较或关系排序。
就综合而言,简单的比较运算 (= 和 /=)在实现硬件结构时,
比排序操作符构成的电路芯片资源利用率要高。
(5) 在表 3.2中所列的 17种算术操作符可以分为求和操作符、
求积操作符、符号操作符、混合操作符、移位操作符等五类操作符。
第 3章 VHDL编程基础
● 求和操作符包括加减操作符和并置操作符。加减操作符的运算规则与常规的加减法是一致的,VHDL规定它们的操作数的数据类型是整数。对于大于位宽为 4的加法器和减法器,
VHDL综合器将调用库元件进行综合。
在综合后,由加减运算符 (+,-)产生的组合逻辑门所耗费的硬件资源的规模都比较大,但当加减运算符的其中一个操作数或两个操作数都为整型常数,则只需很少的电路资源。
并置运算符 (&)的操作数的数据类型是一维数组,可以利用并置符将普通操作数或数组组合起来形成各种新的数组。例如
,VH”&“DL”的结果为,VHDL”;,0”&“1”的结果为,01”,
连接操作常用于字符串。但在实际运算过程中,要注意并置操作前后的数组长度应一致。
第 3章 VHDL编程基础
● 求积操作符包括 * (乘 ),/(除 ),MOD(取模 )和 REM(取余 )
四种操作符。 VHDL规定,乘与除的数据类型是整数和实数 (包括浮点数 )。在一定条件下,还可对物理类型的数据对象进行运算操作。
但需注意的是,虽然在一定条件下,乘法和除法运算是可综合的,但从优化综合、节省芯片资源的角度出发,最好不要轻易使用乘除操作符。对于乘除运算可以用其他变通的方法来实现。
操作符 MOD和 REM的本质与除法操作符是一样的,因此,
可综合的取模和取余的操作数必须是以 2为底数的幂。 MOD和
REM的操作数数据类型只能是整数,运算操作结果也是整数。
第 3章 VHDL编程基础
● 符号操作符,+”和,-”的操作数只有一个,操作数的数据类型是整数,操作符,+”对操作数不作任何改变,操作符,-”
作用于操作数后的返回值是对原操作数取负,在实际使用中,
取负操作数需加括号。如,Z:=X*(-Y);。
● 混合操作符包括乘方,**”操作符和取绝对值,ABS”操作符两种。 VHDL规定,它们的操作数数据类型一般为整数类型。乘方 (**)运算的左边可以是整数或浮点数,但右边必须为整数,而且只有在左边为浮点时,其右边才可以为负数。一般地,VHDL综合器要求乘方操作符作用的操作数的底数必须是 2。
第 3章 VHDL编程基础
● 六种移位操作符号 SLL,SRL,SLA,SRA,ROL和 ROR
都是 VHDL'93标准新增的运算符,在 1987标准中没有。
VHDL'93标准规定移位操作符作用的操作数的数据类型应是一维数组,并要求数组中的元素必须是 BIT或 BOOLEAN的数据类型,移位的位数则是整数。在 EDA工具所附的程序包中重载了移位操作符以支持 STD_LOGIC_VECTOR及 INTEGER等类型。
移位操作符左边可以是支持的类型,右边则必定是 INTEGER型。
如果操作符右边是 INTEGER型常数,移位操作符实现起来比较节省硬件资源。
第 3章 VHDL编程基础其中 SLL是将位矢向左移,右边跟进的位补零; SRL的功能恰好与 SLL相反; ROL和 ROR的移位方式稍有不同,它们移出的位将用于依次填补移空的位,执行的是自循环式移位方式; SLA
和 SRA是算术移位操作符,其移空位用最初的首位来填补。
第 3章 VHDL编程基础移位操作符的语句格式是:
标识符号 移位操作符号 移位位数;
操作符可以用以产生电路。就提高综合效率而言,使用常量值或简单的一位数据类型能够生成较紧凑的电路,而表达式复杂的数据类型 (如数组 )将相应地生成更多的电路。如果组合表达式的一个操作数为常数,就能减少生成的电路;如果两个操作数都是常数,在编译期间,相应的逻辑被压缩掉,或者被忽略掉,而生成了零个门。在任何可能的情况下,使用常数意味着设计描述将不会包含不必要的函数,并将被快速的综合,
产生一个更有效的电路实现方案。
第 3章 VHDL编程基础
3.重载操作符为了方便各种不同数据类型间的运算,VHDL允许用户对原有的基本操作符重新定义,赋予新的含义和功能,从而建立一种新的操作符,这就是重载操作符,定义这种操作符的函数称为重载函数。事实上,在程序包 STD_LOGIC_UNSIGNED中已定义了多种可供不同数据类型间操作的算符重载函数。
Synopsys的程序包 STD_LOGIC_ARITH、
STD_LOGIC_UNSIGNED和 STD_LOGIC_
SIGNED中已经为许多类型的运算重载了算术运算符和关系运算符,因此只要引用这些程序包,SINGEND,UNSIGEND、
STD_LOGIC 和 INTEGER之间即可混合运算; INTEGER、
STD_LOGIC和 STD_LOGIC_VECTOR之间也可以混合运算。
第 3章 VHDL编程基础
3.4 VHDL顺序语句顺序语句 (Sequential Staements)和并行语句 (Concurrent
Statements)是 VHDL程序设计中两大基本描述语句系列。在逻辑系统的设计中,这些语句从多侧面完整地描述数字系统的硬件结构和基本逻辑功能,其中包括通信的方式、信号的赋值、多层次的元件例化以及系统行为等。
顺序语句是相对于并行语句而言的,其特点是每一条顺序语句的执行 (指仿真执行 )顺序是与它们的书写顺序基本一致的,
但其相应的硬件逻辑工作方式未必如此,希望读者在理解过程中要注意区分 VHDL语言的软件行为及描述综合后的硬件行为间的差异。
第 3章 VHDL编程基础顺序语句只能出现在进程 (Process)和子程序中。在 VHDL中,
一个进程是由一系列顺序语句构成的,而进程本身属并行语句,
这就是说,在同一设计实体中,所有的进程是并行执行的。然而任一给定的时刻内,在每一个进程内,只能执行一条顺序语句。一个进程与其设计实体的其他部分进行数据交换的方式只能通过信号或端口。如果要在进程中完成某些特定的算法和逻辑操作,也可以通过依次调用子程序来实现,但子程序本身并无顺序和并行语句之分。利用顺序语句可以描述逻辑系统中的组合逻辑、时序逻辑或它们的综合体。
VHDL有如下六类基本顺序语句:赋值语句;转向控制语句;
等待语句;子程序调用语句;返回语句;空操作语句。
第 3章 VHDL编程基础
3.4.1 赋值语句赋值语句的功能就是将一个值或一个表达式的运算结果传递给某一数据对象,如信号或变量,或由此组成的数组。
VHDL设计实体内的数据传递以及对端口界面外部数据的读写都必须通过赋值语句的运行来实现。
第 3章 VHDL编程基础
1.信号和变量赋值赋值语句有两种,即信号赋值语句和变量赋值语句。
变量赋值与信号赋值的区别在于,变量具有局部特征,它的有效只局限于所定义的一个进程中,或一个子程序中,它是一个局部的、暂时性数据对象 (在某些情况下 )。对于它的赋值是立即发生的 (假设进程已启动 ),即是一种时间延迟为零的赋值行为。
第 3章 VHDL编程基础信号则不同,信号具有全局性特征,它不但可以作为一个设计实体内部各单元之间数据传送的载体,而且可通过信号与其他的实体进行通信 (端口本质上也是一种信号 )。信号的赋值并不是立即发生的,它发生在一个进程结束时。赋值过程总是有某种延时的,它反映了硬件系统并不是立即发生的,它发生在一个进程结束时。赋值过程总是有某些延时的,它反映了硬件系统的重要特性,综合后可以找到与信号对应的硬件结构,
如一根传输导线、一个输入输出端口或一个 D触发器等。
第 3章 VHDL编程基础但是,读者必须注意,在某些条件下变量赋值行为与信号赋值行为所产生的硬件结果是相同的,如都可以向系统引入寄存器。
变量赋值语句和信号赋值语句的语法格式如下:
变量赋值目标,= 赋值源;
信号赋值目标,<= 赋值源;
在信号赋值中,需要注意的是,当在同一进程中,同一信号赋值目标有多个赋值源时,信号赋值目标获得的是最后一个赋值源的赋值,其前面相同的赋值目标不作任何变化。
第 3章 VHDL编程基础读者可以从例 3.4.1中看出信号与变量赋值的特点及它们的区别。当在同一赋值目标处于不同进程中时,其赋值结果就比较复杂了,这可以看成是多个信号驱动源连接在一起,可以发生线与、线或或者三态等不同结果。
第 3章 VHDL编程基础
【 例 3.4.1】
SIGNAL S1,S2,STD_LOGIC;
SIGNAL SVEC,STD_LOGIC_VECTOR(0 TO 7);
...
PROCESS(S1,S2)
VARIABLE V1,V2,STD_LOGIC;
BEGIN
V1,=?1?; --立即将 V1置位为 1
V2,=?1?; --立即将 V2置位为 1
S1 <=?1?; --S1被赋值为 1
S2 <=?1?; --由于在本进程中,这里的 S2不是最后一个赋值语句故第 3章 VHDL编程基础
SVEC(0) <= V1; --将 V1在上面的赋值 1,赋给 SVEC(0)
SVEC(1) <= V2; --将 V2在上面的赋值 1,赋给 SVEC(1)
SVEC(2) <= S1; --将 S1在上面的赋值 1,赋给 SVEC(2)
SVEC(3) <= S2; --将最下面的赋予 S2的值‘ 0?,赋给 SVEC(3)
V1,=?0?; --将 V1置入新值 0
V2,=?0?; --将 V2置入新值 0
S2,=?0?; --由于这是 S2最后一次赋值,赋值有效,
--此‘ 0?将上面准备赋入的‘ 1?覆盖掉第 3章 VHDL编程基础
SVEC(4) <= V1; --将 V1在上面的赋值 0,赋给 SVEC(4)
SVEC(5) <= V2; --将 V2在上面的赋值 0,赋给 SVEC(5)
SVEC(6) <= S1; --将 S1在上面的赋值 1,赋给 SVEC(6)
SVEC(7) <= S2; --将 S2在上面的赋值 0,赋给 SVEC(7)
END PROCESS;
第 3章 VHDL编程基础
2.赋值目标赋值语句中的赋值目标有四种类型。
1) 标识符赋值目标及数组单元素赋值目标标识符赋值目标是以简单的标识符作为被赋值的信号或变量名。
数组单元素赋值目标的表达形式为:
数组类信号或变量名 (下标名 )
第 3章 VHDL编程基础下标名可以是一个具体的数字,也可以是一个文字表示的数字名,它的取值范围在该数组元素个数范围内。下标名若是未明确表示取值的文字 (不可计算值 ),则在综合时,将耗用较多的硬件资源,且一般情况下不能被综合。
标识符赋值目标及数组单元素赋值目标的使用实例,见例
3.4.1 。
第 3章 VHDL编程基础
2) 段下标元素赋值目标及集合块赋值目标段下标元素赋值目标可用以下方式表示:
数组类信号或变量名 (下标 1 TO/DOWNTO 下标 2)
括号中的两个下标必须用具体数值表示,并且其数值范围必须在所定义的数组下标范围内,两个下标的排序方向要符合方向关键词 TO或 DOWNTO,具体用法如例 3.4.2 所示。
第 3章 VHDL编程基础
【 例 3.4.2】
VARIABLE A,B,STD_LOGIC_VECTOR (1 TO 4);
A (1 TO 2),= "10" ; -- 等效于 A(1):=?1?,A(2):=?0?
A (4 DOWNTO 1),="1011";
集合块赋值目标,是以一个集合的方式来赋值的。对目标中的每个元素进行赋值的方式有两种,即位置关联赋值方式和名字关联赋值方式,具体用法如例 3.4.3所示。
第 3章 VHDL编程基础
【 例 3.4.3】
SIGNAL A,B,C,D,STD_LOGIC:
SIGNAL S,STD_LOGIC_VECTOR( 1 TO 4)
...
VARIABLE E,F,STD_LOGIC;
VARIABLE G,STD_LOGIC_VECTOR(1 TO 2 );
VARIABLE H,STD_LOGIC_VECTOR(1 TO 4 );
S <= (?0?,‘ 1?,‘ 0?,‘ 0?) ;
(A,B,C,D) <= S ; --位置关联方式赋值
..,--其他语句第 3章 VHDL编程基础
(3=> E,4=>F,2 =>G(1),1=>G(2) ),= H; --名字关联方式赋值示例中的信号赋值语句属位置关联赋值方式,其赋值结果等效于:
A <=?0?; B <=?1?; C <=?0? ; D <=?0?;
示例中的变量赋值语句属名字关联赋值方式,赋值结果等效于:
G(2),= H(1) ; G(1),= H(2) ; E,= H(3) ; F,= H(4) ;
第 3章 VHDL编程基础
3.4.2 转向控制语句转向控制语句通过条件控制开关决定是否执行一条或几条语句,或重复执行一条或几条语句,或跳过一条或几条语句。
转向控制语句共有五种,IF 语句,CASE 语句,LOOP 语句、
NEXT 语句和 EXIT 语句。
第 3章 VHDL编程基础
1,IF语句
IF语句是一种条件语句,它根据语句中所设置的一种或多种条件,有选择地执行指定的顺序语句,其语句结构如下:
IF 条件句 THEN
顺序语句
{ELSIF 条件句 THEN
顺序语句 };
[ELSE
顺序语句 ];
END IF
第 3章 VHDL编程基础
IF语句中至少应有一个条件句,条件句必须由布尔表达式构成。 IF语句根据条件句产生的判断结果 TRUE或 FALSE,有条件地选择执行其后的顺序语句。如果某个条件句的布尔值为真
(TRUE),则执行该条件句后的关键词 THEN后面的顺序语句,
否则结束该条件的执行,或执行 ELSIF或 ELSE后面的顺序语句后结束该条件句的执行 …… 直到执行到最外层的 END IF语句,
才完成全部 IF语句的执行。
第 3章 VHDL编程基础
【 例 3.4.4】
K1,IF (A>B) THEN
OUTPUT<=?1?;
END IF K1;
其中,K1是条件句名称,可有可无。若条件句 (A>B)检测结果为 TRUE,则向信号 OUTPUT赋值 1,否则此信号维持原值。
第 3章 VHDL编程基础
【 例 3.4.5】 IF语句完成的一个具有 2输入与门功能的函数定义。
FUNCTION AND_FUNC(X,Y,IN BIT) RETURN BIT
IS
BEGIN
IF X=?1? AND Y=?1? THEN RETURN?1?;
ELSE RETURN?0?;
END IF;
END AND_FUNC;
第 3章 VHDL编程基础
【 例 3.4.6】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY CONTROL_STMTS IS
PORT (A,B,C,IN BOOLEAN;
OUTPUT,OUT BOOLEAN);
END CONTROL_STMTS;
ARCHITECTURE EXAMPLE OF CONTROL_STMTS IS
BEGIN
第 3章 VHDL编程基础
PROCESS(A,B,C)
VARIABLE N,BOOLEAN;
BEGIN
IF A THEN N,=B;
ELSE N,=C;
END IF;
OUTPUT <=N;
END PROCESS,
END EXAMPLE;
第 3章 VHDL编程基础例 3.4.6对应的硬件电路如图 3.6所示。
图 3.6 例 3.4.6 的硬件实现电路
C
A
B
O U TP U T
第 3章 VHDL编程基础图 3.7 双 2选 1多路选择器电路
P1
P2
B
C
B
A
S
B
A
S
A
Z
M U X 2 1M U X 2 1
第 3章 VHDL编程基础
【 例 3.4.7】
SIGNAL A,B,C,P1,P2,Z,BIT;
...
IF (P1=?1?) THEN
Z<=A; --满足此语句的执行条件是 (P1=?1?)
ELSIF (P2=?0?) THEN
Z<=B; --满足此语句的执行条件是 (P1=?0?)AND (P2=?0?)
ELSE
Z<=C; --满足此语句的执行条件是 (P1=?0?)AND (P2=?1?)
END IF;
第 3章 VHDL编程基础从本例可以看出,IF_THEN_ELSIF语句中顺序语句的执行条件具有向上相与的功能,有的逻辑设计恰好需要这种功能。例 3.4.8正是利用了这一功能以十分简洁的描述完成了一个 8线 _3线优先编码器的设计。
第 3章 VHDL编程基础
【 例 3.4.8】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY CODER IS
PORT ( IN,STD_LOGIC_VECTOR(0 TO 7);
OUTPUT,OUT STD_LOGIC_VECTOR(0 TO 2));
END CODER;
ARCHITECTURE ART OF CODER IS
SIGNAL SINT,STD_LOGIC_VECTOR(4 DOWNTO 0);
BEGIN
PROCESS(IN)
第 3章 VHDL编程基础
BEGIN
IF(IN(7)=?0?) THEN
OUTPUT<="000"; --(IN(7)=?0?)
ELSIF(IN(6)=?0?) THEN
OUTPUT <="100"; --(IN(7)=?1?) AND (IN(6)=?0?)
ELSIF(IN(5)=?0?) THEN
OUTPUT <="010"; --(IN(7)=?1?)AND(IN(6)=?1?)AND(IN(5)=?0?)
ELSIF(IN(4)=?0?) THEN
OUTPUT <="110";
ELSIF(IN(3)=?0?) THEN
OUTPUT <="001";
第 3章 VHDL编程基础
ELSIF(IN(2)=?0?) THEN
OUTPUT <="101";
ELSIF(IN(1)=?0?) THEN
OUTPUT <="011";
ELSE
OUTPUT<="111";
END IF;
END PROCESS;
END ART;
第 3章 VHDL编程基础
2,CASE 语句
CASE语句根据满足的条件直接选择多项顺序语句中的一项执行。
CASE语句的结构如下:
CASE 表达式 IS
WHEN 选择值 =>顺序语句;
WHEN 选择值 =>顺序语句;
[ WHEN OTHERS =>顺序语句; ]

END CASE;
第 3章 VHDL编程基础当执行到 CASE语句时,首先计算表达式的值,然后根据条件句中与之相同的选择值,执行对应的顺序语句,最后结束
CASE语句。表达式可以是一个整数类型或枚举类型的值,也可以是由这些数据类型的值构成的数组 (请注意,条件句中的
,=>”不是操作符,它只相当于,THEN”的作用 )。
选择值可以有四种不同的表达方式:① 单个普通数值,如
4;② 数值选择范围,如 (2 TO 4),表示取值 2,3或 4;③ 并列数值,如 3 | 5,表示取值为 3或者 5;④ 混合方式,以上三种方式的混合。
第 3章 VHDL编程基础使用 CASE语句需注意以下几点:
(1) 条件句中的选择值必须在表达式的取值范围内。
(2) 除非所有条件句中的选择值能完整覆盖 CASE语句中表达式的取值,否则最末一个条件句中的选择必须用,OTHERS”
表示。它代表已给的所有条件句中未能列出的其他可能的取值,
这样可以避免综合器插入不必要的寄存器。这一点对于定义为
STD_LOGIC和 STD_LOGIC_VECTOR数据类型的值尤为重要,
因为这些数据对象的取值除了 1和 0以外,还可能有其他的取值,
如高阻态 Z、不定态 X 等。
第 3章 VHDL编程基础
(3) CASE语句中每一条件句的选择只能出现一次,不能有相同选择值的条件语句出现。
(4) CASE语句执行中必须选中,且只能选中所列条件语句中的一条。这表明 CASE语句中至少要包含一个条件语句。
第 3章 VHDL编程基础
【 例 3.4.9】 用 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 ENTITY MUX41;
ARCHITECTURE ART OF MUX41 IS
SIGNAL S,STD_LOGIC_VECTOR(1 DOWNTO 0);
第 3章 VHDL编程基础
BEGIN
S<=S1 & S2;
PROCESS(S1,S2,A,B,C,D)
BEGIN
CASE S IS
WHEN "00"=>Z<=A;
WHEN "01"=>Z<=B;
WHEN "10"=>Z<=C;
WHEN "11"=>Z<=D;
WHEN OTHERS =>Z<='X';
END CASE;
END PROCESS;
END ART;
第 3章 VHDL编程基础注意本例的第五个条件名是必需的,因为对于定义
STD_LOGIC_VECTOR数据类型的 S,在 VHDL综合过程中,它可能的选择值除了 00,01,10和 11外,还可以有其他定义于
STD_LOGIC的选择值。本例的逻辑图如图 3.8所示。
例 3.4.10描述的 4选 1选择器是用 IF语句和 CASE语句共同完成的。这不是一个多路选择器,它是根据 4位输入码来确定 4位输出中哪一位输出为 1。此外,请注意它的选择表达式的数据类型是整数。
第 3章 VHDL编程基础图 3.8 4选 1多路选择器
S1
S2
C
B
A
D
C
A
B
D
S2 S1
Z
第 3章 VHDL编程基础
【 例 3.4.10】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY MUX41 IS
PORT(S4,S3,S2,S1,IN STD_LOGIC;
Z4,Z3,Z2,Z1,OUT STD_LOGIC);
END MUX41;
ARCHITECTURE ART OF MUX41 IS
SIGNAL TEMP,INTEGER RANGE 0 TO 15
BEGIN
PROCESS(S4,S3,S2,S1)
第 3章 VHDL编程基础
BEGIN
TEMP<=?0?; --输入初始值
IF (S1=?1?) THEN SEL<=SEL+1;
ELSIF(S2=?1?) THEN SEL<=SEL+2;
ELSIF(S3=?1?) THEN SEL<=SEL+4;
ELSIF(S4=?1?) THEN SEL<=SEL+8;
ELSE NULL; --注意,这里使用了空操作语句
END IF;
Z1<=?0?; Z2<=?0?; Z3<=?0?; Z4<=?0?; --输入初始值第 3章 VHDL编程基础
CASE TEMP IS
WHEN 0 =>Z1<=?1?; --当 SEL=0时选中
WHEN 1|3 =>Z2<=?1?; --当 SEL为 1或 3时选中
WHEN 4 TO 7|2 =>Z3<=?1?; --当 SEL为 2,4,5,6或 7时选中
WHEN OTHERS =>Z4<=?1?; --当 SEL为 8~ 15中任一值时选中
END CASE;
END PROCESS;
END ART;
第 3章 VHDL编程基础例 3.4.10中的 IF_THEN_ELSIF 语句所起的作用是数据类型转换器的作用,即把输入的 S4,S3,S2,S1的 4位二进制输入值转化为能与 TEMP对应的整数值,以便可以在条件句中进行比较。
与 IF语句相比,CASE语句组的程序可读性比较好,这是因为它把条件中所有可能出现的情况全部列出来了,可执行条件一目了然。而且 CASE语句的执行过程不像 IF语句那样有一个逐项条件顺序比较的过程。 CASE语句中条件句的次序是不重要的,
它的执行过程更接近于并行方式。一般地,综合后,对相同的逻辑功能,CASE语句比 IF语句的描述耗用更多的硬件资源,而且有的逻辑,CASE语句无法描述,只能用 IF语句来描述。这是因为 IF_THEN_ELSIF语句具有条件相与的功能和自动将逻辑值
,-”包括进去的功能 (逻辑值,-”有利于逻辑化简 ),而 CASE语句只有条件相或的功能。
第 3章 VHDL编程基础
3,LOOP语句
LOOP语句就是循环语句,它可以使所包含的一组顺序语句被循环执行,其执行次数可由设定的循环参数决定,循环的方式由 NEXT和 EXIT语句来控制。其语句格式如下:
[LOOP 标号,] [重复模式 ] LOOP
顺序语句
END LOOP [LOOP 标号 ];
重复模式有两种,WHILE 和 FOR,格式分别为:
[LOOP 标号,] FOR 循环变量 IN 循环次数范围 LOOP --重复次数已知
[LOOP 标号,]WHILE 循环控制条件 LOOP --重复次数未知第 3章 VHDL编程基础
【 例 3.4.11】 简单 LOOP语句的使用。

L2,LOOP
A:=A+1;
EXIT L2 WHEN A>10; --当 A大于 10时跳出循环
END LOOP L2;

第 3章 VHDL编程基础
【 例 3.4.12】 FOR_LOOP语句的使用 (8位奇偶校验逻辑电路的 VHDL程序 )。
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 ART OF P_CHECK IS
SIGNAL TMP,STD_LOGIC;
第 3章 VHDL编程基础
BEGIN
PROCESS(A)
BEGIN
TMP <=?0?;
FOR N IN 0 TO 7 LOOP
TMP <=TMP XOR A(N);
END LOOP;
Y<= TMP;
END PROCESS;
END ART;
第 3章 VHDL编程基础
【 例 3.4.13】 利用 LOOP语句中的循环变量简化同类顺序语句的表达式的使用。
SIGNAL A,B,C,STD_LOGIC_VECTOR(1 TO 3);

FOR N IN 1 TO 3 LOOP
A(N)<=B(N) AND C(N);
END LOOP;
第 3章 VHDL编程基础此段程序等效于顺序执行以下三个信号赋值操作:
A(1)<=B(1) AND C(1);
A(2)<=B(2) AND C(2);
A(3)<=B(3) AND C(3);
注意,LOOP循环的范围最好以常数表示,否则,在
LOOP体内的逻辑可以重复任何可能的范围,这样将导致耗费过大的硬件资源,综合器不支持没有约束条件的循环。
第 3章 VHDL编程基础
【 例 3.4.14】 WHILE_LOOP语句的使用。
SHIFT1,PROCESS(INPUTX)
VARIABLE N,POSITIVE:=1;
BEGIN
L1,WHILE N<=8 LOOP --这里的,<=”是小于等于的意思
OUTPUTX(N)<=INPUTX(N+8);
N:=N+1;
END LOOP L1;
END PROCESS SHIFT1;
第 3章 VHDL编程基础在 WHILE_LOOP语句的顺序语句中增加了一条循环次数的计算语句,用于循环语句的控制。在循环执行中,当 N的值等于 9时将跳出循环。
在例 3.4.15和例 3.4.16程序设计中,分别使用了上述两种不同的循环方式,图 3.9和图 3.10是分别对应于例 3.4.15和例 3.4.16
的逻辑电路,试比较这两个例子在软件描述和硬件结构上的区别。
第 3章 VHDL编程基础
【 例 3.4.15】
ENTITY LOOPEXP IS
PORT (A,IN BIT_VECTOR (0 TO 3);
OUT1,OUT BIT_VECTOR(0 TO 3);
END LOOPEXP;
ARCHITECTURE ART OF LOOPEXP IS
BEGIN
PROCESS (A)
VARIABLE B,BIT;
BEGIN
第 3章 VHDL编程基础
B:=1
FOR I IN 0 TO 3 LOOP
B:=A(3-I) AND B;
OUT1(I)<=B;
END LOOP;
END PROCESS;
END ART;
第 3章 VHDL编程基础图 3.9 例 3.4.15对应的硬件电路
A [ 3 ]
A [ 2 ]
A [ 1 ]
A [ 0 ]
O U T 1 [ 3 ]
O U T 1 [ 2 ]
O U T 1 [ 1 ]
O U T 1 [ 0 ]
第 3章 VHDL编程基础图 3.10 例 3.4.16对应的硬件电路
A [ 2 ]
A [ 1 ]
A [ 0 ]
O U T1 [ 2 ]
O U T1 [ 1 ]
O U T1 [ 0 ]
第 3章 VHDL编程基础
【 例 3.4.16】
ENTITY WHILEEXP IS
PORT (A,IN BIT_VECTOR(0 TO 3);
OUT1,OUT BIT_VECTOR (0 TO 3);
END WHILEEXP;
ARCHITECTURE ART OF WHILEEXP IS
BEGIN
PROCESS(A)
VARIABLE B,BIT;
VARIABLE I,INTEGER;
第 3章 VHDL编程基础
BEGIN
I:=0;
WHILE I< 4 LOOP
B:=A(3-I) AND B;
OUT1(I)<=B;
END LOOP;
END PROCESS;
END ART;
VHDL综合器支持 WHILE语句的条件是,LOOP的结束条件值必须是在综合时就可以决定。综合器不支持无法确定循环次数的 LOOP语句。
第 3章 VHDL编程基础
4,NEXT 语句
NEXT语句主要用在 LOOP语句执行中有条件的或无条件的转向控制。它的语句格式有以下三种:
NEXT [LOOP 标号 ] [WHEN 条件表达式 ];
当 LOOP 标号缺省时,则执行 NEXT 语句时,即刻无条件终止当前的循环,跳回到本次循环 LOOP语句开始处,开始下一次循环,否则跳转到指定标号的 LOOP语句开始处,重新开始执行循环操作。若 WHEN子句出现并且条件表达式的值为 TRUE,则执行 NEXT语句,进入跳转操作,否则继续向下执行。
第 3章 VHDL编程基础
【 例 3.4.17】

L1,FOR CNT_VALUE IN 1 TO 8 LOOP
S1,A(CNT_VALUE):=?0?;
NEXT WHEN (B=C);
S2,A(CNT_VALUE+8):=?0?;
END LOOP L1;
第 3章 VHDL编程基础本例中,当程序执行到 NEXT语句时,如果条件判断式
(B=C)的结果为 TRUE,将执行 NEXT语句,并返回到 L1,使
CNT_VALUE加 1后执行 S1开始赋值语句,否则将执行 S2开始的赋值语句。
在多重循环中,NEXT语句必须如例 3.4.18所示那样,加上跳转标号。
第 3章 VHDL编程基础
【 例 3.4.18】

L_X,FOR CNT_VALUE IN 1 TO 8 LOOP
S1,A(CNT_VALUE):=?0?;
K:=0;
L_Y,LOOP
S2,B(k):=?0?;
NEXT L_X WHEN (E>F):
S3,B(k+8):=?0?;
K:=K+1;
NEXT LOOP L_Y;
NEXT LOOP L_X;

第 3章 VHDL编程基础当 E>F为 TRUE时执行语句 NEXT L_X,跳转到 L_X,使
CNT_VALUE加 1,从 S1处开始执行语句;若为 FALSE,则执行 S3后使 K加 1。
第 3章 VHDL编程基础
5,EXIT语句
EXIT语句也是 LOOP语句的内部循环控制语句,其语句格式如下:
EXIT [LOOP 标号 ] [WHEN 条件表达式 ];
这里,每一种语句格式与前述的 NEXT 语句的格式和操作功能非常相似,惟一的区别是 NEXT语句是跳向 LOOP 语句的起始点,而 EXIT语句则是跳向 LOOP语句的终点。
下例是一个两元素位矢量值比较程序。在程序中,当发现比较值 A和 B不同时,由 EXIT语句跳出循环比较程序,并报告比较结果。
第 3章 VHDL编程基础
【 例 3.4.19】
SIGNAL A,B,STD_LOGIC_VECTOR(1 DOWNTO 0);
SIGNAL A_LESS_THEN_B,BOOLEAN;

A_LESS_THEN_B<=FLASE; --设初始值
FOR I IN 1 DOWNTO 0 LOOP
IF (A(I)=?1? AND B(I)=?0?) THEN
A_LESS_THEN_B<=FALSE;
EXIT;
第 3章 VHDL编程基础
ELSIF (A(I)=?0? AND B(I)=?1?) THEN
A_LESS_THEN_B<=TRUE; --A<B
EXIT;
ELSE;
NULL;
END IF;
END LOOP; --当 I=1时返回 LOOP语句继续比较第 3章 VHDL编程基础
NULL为空操作语句,是为了满足 ELSE的转换。此程序先比较 A和 B的高位,高位是 1者为大,输出判断结果 TRUE或
FALSE后中断比较程序;当高位相等时,继续比较低位,这里假设 A不等于 B。
第 3章 VHDL编程基础
3.4.3 WAIT 语句在进程中 (包括过程中 ),当执行到 WAIT等待语句时,运行程序将被挂起 (Suspension),直到满足此语句设置的结束挂起条件后,将重新开始执行进程或过程中的程序。但 VHDL规定,
已列出敏感量的进程中不能使用任何形式的 WAIT语句。 WAIT
语句的语句格式如下:
WAIT [ON 信号表 ] [UNTIL 条件表达式 ] [FOR 时间表达式 ];
单独的 WAIT,未设置停止挂起条件的表达式,表示永远挂起。
第 3章 VHDL编程基础
WAIT ON 信号表,称为敏感信号等待语句,在信号表中列出的信号是等待语句的敏感信号。当处于等待状态时,敏感信号的任何变化 (如从 0~ 1或从 1~ 0的变化 )将结束挂起,再次启动进程。如:
WAIT ON S1,S2;
表示当 S1或 S2中任一信号发生改变时,就恢复执行 WAIT语句之后的语句。
WAIT UNTIL 条件表达式,称为条件等待语句,该语句将把进程挂起,直到条件表达式中所含信号发生了改变,并且条件表达式为真时,进程才能脱离挂起状态,恢复执行 WAIT语句之后的语句。
例 3.4.20中的两种表达方式是等效的。
第 3章 VHDL编程基础
【 例 3.4.20】
(a) WAIT_UNTIL 结构 (b) WAIT_ON结构
..,LOOP
WAIT UNTIL ENABLE =?1?; WAIT ON ENABLE
..,EXIT WHEN ENABLE =?1?;
END LOOP;
由以上脱离挂起状态、重新启动进程的两个条件可知,例
3.4.20结束挂起所需满足的条件,实际上是一个信号的上跳沿。
因为当满足所有条件后 ENABLE为 1,可推知 ENABLE一定是由
0变化来的。因此,上例中进程的启动条件是 ENABLE出现一个上跳信号沿。
第 3章 VHDL编程基础一般地,只有 WAIT_UNTIL格式的等待语句可以被综合器接受 (其余语句格式只能在 VHDL仿真器中使用 )。 WAIT_UNTIL
语句有以下三种表达方式:
WAIT UNTIL 信号 =VALUE; --①
WAIT UNTIL 信号 'EVENT AND 信号 =VALUE; --②
WAIT UNTIL NOT 信号 'STABLE AND 信号 =VALUE --③
第 3章 VHDL编程基础如果设 CLOCK为时钟信号输入端,以下四条 WAIT语句所设的进程启动条件都是时钟上跳沿,所以它们对应的硬件结构是一样的。
WAIT UNTIL CLOCK =?1?;
WAIT UNTIL RISING_EDGE(CLOCK);
WAIT UNTIL NOT CLOCK'STABLE AND CLOCK='1';
WAIT UNTIL CLOCK=?1? AND CLOCK'EVENT;
例 3.4.21中的进程将完成一个硬件求平均的功能,每一个时钟脉冲由 A输入一个数值,4个时钟脉冲后将获得此 4个数值的平均值。
第 3章 VHDL编程基础
【 例 3.4.21】
PROCESS
BEGIN
WAIT UNTIL CLK=?1?;
AVE<=A;
WAIT UNTIL CLK=?1?;
AVE<=AVE+A;
WAIT UNTIL CLK=?1?;
AVE<=AVE+A;
WAIT UNTIL CLK=?1?;
AVE<=(AVE+A)/4;
END PROCESS;
第 3章 VHDL编程基础
【 例 3.4.22】
PROCESS
BEGIN
RST_LOOP,LOOP
WAIT UNTIL CLOCK=?1? AND CLOCK'EVENT ; --等待时钟信号
NEXT RST_LOOP WHEN (RST=?1?); --检测复位信号 RST
X<=A; --无复位信号,执行赋值操作
WAIT UNTIL CLOCK=?1?AND CLOCK'EVENT; --等待时钟信号
NEXT RST_LOOP WHEN (RST=?1?); --检测复位信号 RST
Y<=B; --无复位信号,执行赋值操作
END LOOP RST_LOOP;
END PROCESS
第 3章 VHDL编程基础例 3.4.22中每一时钟上升沿的到来都将结束进程的挂起,继而检测电路的复位信号 RST是否为高电平。如果是高电平,则返回循环的起始点;如果是低电平,则进行正常的顺序语句执行操作,如示例中的赋值操作。
一般地,在一个进程中使用了 WAIT语句后,经综合就会产生时序逻辑电路。时序逻辑电路的运行依赖于时钟的上升沿或下降沿,同时还具有数据存储的功能。
例 3.4.23就是一个比较好的说明,此例描述了一个可预置校验对比值的四位奇偶校验电路,它的功能除对输入的 4位码
DATA(0 TO 3)进行奇偶校验外,还将把校验结果与预置的校验值 NEW_CORRECT_PARITY进行比较,并将比较值 PARITY_OK
输出。
第 3章 VHDL编程基础
【 例 3.4.23】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY PARI IS
PORT(CLOCK,IN STD_LOGIC;
SET_PARITY,IN STD_LOGIC;
NEW_CORRECT_PARITY,IN STD_LOGIC;
DATA,IN STD_LOGIC_VECTOR(0 TO 3);
PARITY_OK,OUT BOOLEAN);
END PARI;
第 3章 VHDL编程基础
ARCHITECTURE ART OF PARI IS
SIGNAL CORRECT_PARITY,STD_LOGIC;
BEGIN
PROCESS(CLOCK)
VARIABLE TEMP,STD_LOGIC;
BEGIN
WAIT UNTIL CLOCK'EVENT AND CLOCK=?1?;
IF SET_PARITY=?1?THEN
FIRST,CORRECT_PARITY<=NEW_CORRECT_PARITY;
第 3章 VHDL编程基础
END IF;
TEMP:=?0?;
FOR I IN DATA'RANGE LOOP
TEMP:=TEMP XOR DATA(I);
END LOOP;
SECOND,PARITY_OK_<=(TEMP=CORRECT_PARITY);
END PROCESS;
END ART;
第 3章 VHDL编程基础图 3.11 例 3.4.23综合后的 RTL硬件电路图
F D 11
Q0D0
Q0D0
O
S
B
A
M U X 2 1
F D 11
C L O C K
D A T A [ 2 ]
D A T A [ 1 ]
D A T A [ 3 ]
D A T A [ 0 ]
X Y J G
K Z D
Y Z Z
第 3章 VHDL编程基础例 3.4.23中,NEW_CORRECT_PARITY是预置校验值输入端,SET_PARITY是预置校验值的输入与比较控制端。从例
3.4.23可以看出,由于 WAIT语句的加入,综合后引入了两个 D
触发器,用于存储数据。第一个触发器存储 CORRECT_PARITY,
它来自标号为 FIRST的语句;第二个触发器用于两个时钟信号间 PARITY_OK的存储,它来自标号为 SECORD的语句。综合器没有为变量 TEMP的赋值行为增加触发器,因为 TEMP是一个临时变量。
WAIT FOR时间表达式为超时语句,在此语句中定义了一个时间段,从执行到当前的 WAIT语句开始,在此时间段内,进程处于挂起状态,当超过这一时间段后,进程自动恢复执行。
由于此语句不可综合,在此不做讨论。
第 3章 VHDL编程基础
3.4.4 子程序调用语句在进程中允许对子程序进行调用。子程序包括过程和函数,
可以在 VHDL的结构体或程序包中的任何位置对子程序进行调用。
从硬件角度讲,一个子程序的调用类似于一个元件模块的例化,也就是说,VHDL综合器为子程序的每一次调用都生成一个电路逻辑块。所不同的是,元件的例化将产生一个新的设计层次,而子程序调用只对应于当前层次的一部分。
第 3章 VHDL编程基础子程序的结构详见 3.6节,它包括子程序首和子程序体。子程序分成子程序首和子程序体的好处是,在一个大系统的开发过程中,子程序的界面,即子程序首是在公共程序包中定义的。
这样一来,一部分开发者可以开发子程序体,另一部分开发者可以使用对应的公共子程序,即可以对程序包中的子程序作修改,而不会影响对程序包说明部分的使用。这是因为,对于子程序体的修改,并不会改变子程序首的界面参数和出入口方式的定义,从而对子程序体的改变不会改变调用子程序的源程序的结构。
第 3章 VHDL编程基础
1.过程调用过程调用就是执行一个给定名字和参数的过程。调用过程的语句格式如下:
过程名 [([形参名 =>]实参表达式
{,[形参名 =>]实参表达式} )];
其中,括号中的实参表达式称为实参,它可以是一个具体的数值,也可以是一个标识符,是当前调用程序中过程形参的接受体。在此调用格式中,形参名即为当前欲调用的过程中已说明的参数名,即与实参表达式相联系的形参名。被调用中的形参名与调用语句中的实参表达式的对应关系有位置关联法和名字关联法两种,位置关联可以省去形参名。
第 3章 VHDL编程基础一个过程的调用有三个步骤:首先将 IN 和 INOUT模式的实参值赋给欲调用的过程中与它们对应的形参;然后执行这个过程;最后将过程中 IN和 INOUT模式的形参值赋还给对应的实参。
实际上,一个过程对应的硬件结构中,其标识形参的输入输出是与其内部逻辑相连的。在例 3.4.24中定义了一个名为
SWAP的局部过程 (没有放在程序包中的过程 ),这个过程的功能是对一个数组中的两个元素进行比较,如果发现这两个元素的排列不符合要求,就进行交换,使得左边的元素值总是大于右边的元素值。连续调用三次 SWAP后,就能将一个三元素的数组元素从左至右按序排列好,最大值排在左边。
第 3章 VHDL编程基础
【 例 3.4.24】
PACKAGE DATA_TYPES IS --定义程序包
TYPE DATA_ELEMENT IS INTEGER RANGE 0 TO 3; --定义数据类型
TYPE DATA_ARRAY IS ARRAY(1 TO 3) OF DATA_ELEMENT;
END DATA_TYPES;
USE WORK.DATA_TYPES.ALL; --打开以上建立在当前工作库的
--程序包 DATA_TYPES
ENTITY SORT IS
PORT(IN_ARRAY,IN DATA_ARRAY;
OUT_ARRAY,OUT DATA_ARRAY);
END SORT
第 3章 VHDL编程基础
ARCHITECTURE ART OF SORT IS
BEGIN
PROCESS(IN_ARRAY) --进程开始,设 DATA_TYPES为敏感信号
PROCEDURE SWAP(DATA,INOUT DATA_ARRAY;
LOW,HIGH,IN INTEGER ) IS
--SWAP的形参名为 DATA,LOW,HIGH
VARIABLE TEMP,DATA_ELEMENT;
BEGIN --开始描述本过程的逻辑功能
IF(DATA(LOW)>DATA(HIGH))THEN --检测数据
TEMP:=DATA(LOW);
第 3章 VHDL编程基础
DATA(LOW):=DATA(HIGH);
DATA(HIGH):=TEMP;
END IF;
END SWAP; --过程 SWAP定义结束
VARIABLE MY_ARRAY,DATA_ARRAY;
--在本进程中定义变量 MY_ARRAY
BEGIN --进程开始
MY_ARRAY;=IN_ARRAY; --将输入值读入变量
SWAP(MY_ARRAY,1,2);
--MY_ARRAY,1,2是对应于 DATA,HIGH的实参
SWAP(MY_ARRAY,2,3); --位置关联法调用,第 2、第 3元素交换
SWAP(MY_ARRAY,1,2); --位置关联法调用,第 1、第 2元素再次交换
OUT_ARRAY<=MY_ARRAY;
END PROCESS;
END ART;
第 3章 VHDL编程基础
2.函数调用函数调用与过程调用是十分相似的,不同之处是,调用函数将返还一个指定数据类型的值,函数的参量只能是输入值。
第 3章 VHDL编程基础
3.4.5 返回语句 (RETURN)
返回语句只能用于子程序体中,并用来结束当前子程序体的执行。其语句格式如下:
RETURN [表达式 ];
当表达式缺省时,只能用于过程,它只是结束过程,并不返回任何值;当有表达式时,只能用于函数,并且必须返回一个值。用于函数的语句中的表达式提供函数返回值。每一函数必须至少包含一个返回语句,并可以拥有多个返回语句,但是在函数调用时,只有其中一个返回语句可以将值带出。
例 3.4.25是一过程定义程序,它将完成一个 RS触发器的功能。注意其中的时间延迟语句和 REPORT语句是不可综合的。
第 3章 VHDL编程基础
【 例 3.4.25】
PROCEDURE RS(SIGNAL S,R,IN STD_LOGIC;
SIGNAL Q,NQ,INOUT STD_LOGIC) IS
BEGIN
IF(S=?1?AND R=?1?)THEN
REPORT“FORBIDDEN STATE,S AND R ARE EQUAL TO?1?”;
RETURN
ELSE
Q<=S AND NQ AFTER 5 ns;
NQ<=S AND Q AFTER 5 ns;
END IF;
END PROCEDURE RS;
第 3章 VHDL编程基础当信号 S 和 R 同时为 1 时,在 IF语句中的 RETURN语句将中断过程。
例 3.4.26中定义的函数 OPT的返回值由输入参量 OPRAN
决定。当 OPRAN为高电平时,返回相“与”值,A AND B”;
当为低电平时,返回相“或”值,A OR B”。
第 3章 VHDL编程基础
【 例 3.4.26】
FUNCTION OPT(A,B,OPT,STD_LOGIC) RETURN STD_LOGIC IS
BEGIN
IF(OPR=?1?)THEN
RETURN(A AND B);
ELSE
RETURN(A OR B);
END IF;
END FUNCTION OPT;
第 3章 VHDL编程基础图 3.12 函数 OPT的电路结构图
R EN _ V A L U
A
B
O P R
第 3章 VHDL编程基础
3.4.6 空操作语句 (NULL)
空操作语句的语句格式如下:
NULL;
空操作语句不完成任何操作,它惟一的功能就是使逻辑运行流程跨入下一步语句的执行。 NULL常用于 CASE语句中,为满足所有可能的条件,利用 NULL来表示所余的不用条件下的操作行为。
在例 3.4.27的 CASE语句中,NULL用于排除一些不用的条件。
第 3章 VHDL编程基础
【 例 3.4.27】
CASE OPCODE IS
WHEN,001”=> TMP,= REGA AND REGB;
WHEN,101”=> TMP,= REGA OR REGB;
WHEN,110”=> TMP,= NOT REGA;
WHEN OTHERS => NULL;
END CASE;
第 3章 VHDL编程基础此例类似于一个 CPU内部的指令译码器功能。,001”,
"101"和,110”分别代表指令操作码,对于它们所对应在寄存器中的操作数的操作算法,CPU只能对这三种指令码作反应,当出现其他码时,不作任何操作。
需要指出的是,与其他的 EDA工具不同,MAX+plusII对
NULL语句的执行会出现擅自加入锁存器的情况,因此,应避免使用 NULL语句,改用确定操作,如可改为:
WHEN OTHERS => TMP,=REGA;
第 3章 VHDL编程基础
3.4.7 其他语句和说明
1.属性 (ATTRIBUTE)描述与定义语句
VHDL中预定义属性描述语句有许多实际的应用,可用于对信号或其他项目的多种属性检测或统计。 VHDL中可以具有属性的项目如下:
类型、子类型;过程、函数;信号、变量、常量;实体、
结构体、配置、程序包;元件;语句标号。
第 3章 VHDL编程基础属性是以上各类项目的特性,某一项目的特定属性或特征通常可以用一个值或一个表达式来表示,通过 VHDL的预定义属性描述语句就可以加以访问。
属性的值与对象 (信号、变量和常量 )的值完全不同,在任一给定的时刻,一个对象只能具有一个值,但却可以具有多个属性。 VHDL还允许设计者自己定义属性 (即用户定义的属性 )。
第 3章 VHDL编程基础表 3.4是常用的预定义属性。其中综合器支持的属性有:
LEFT,RIGHT,HIGH,LOW,RANGE,RVERS_RANGE、
LENGTH,EVENT和 STABLE等。
预定义属性描述语句实际上是一个内部预定义函数,其语句格式是:
属性测试项目名’属性标识符属性测试项目即属性对象,可由相应的标识符表示,属性标识符就是列于表 3.4中的有关属性名。以下仅就可综合的属性项目使用方法作一说明。
第 3章 VHDL编程基础
1) 信号类属性信号类属性中,最常用的当属 EVENT。例如,语句
,CLOCK'EVENT”就是对以 CLOCK为标识符的信号,在当前的一个极小的时间段内发生事件的情况进行检测。所谓发生事件,
就是电平发生变化,从一种电平方式转变到另一种电平方式。
如果在此时间段内,CLOCK由 0变成 1或由 1变成 0都认为发生了事件,于是这句测试事件发生与否的表达式将向测试语句,如 IF
语句,返回一个 BOOLEAN值 TRUE,否则为 FALSE。
第 3章 VHDL编程基础
【 例 3.4.28】
CLOCK'EVENT AND CLOCK=?1?
本例表示对 CLOCK信号上升沿的测试。即一旦测试到
CLOCK有一个上升沿时,此表达式将返回一个布尔值 TRUE。
当然,这种测试是在过去的一个极小的时间段 Δ内进行的,之后又测得 CLOCK为 1,从而满足此语句所列条件
,CLOCK=?1?”,因而也返回 TRUE,两个,TRUE”相与后仍为
TRUE。由此便可以从当前的,CLOCK=?1?”推断,在此前的 Δ
时间段内,CLOCK必为 0。因此,例 3.4.28的表达式可以用来对信号 CLOCK的上升沿进行检测。例 3.4.29是此表达式的实际应用。
第 3章 VHDL编程基础
【 例 3.4.29】
PROCESS(CLOCK)
IF(CLOCK'EVENT AND CLOCK=?1?) THEN
Q<=DATA;
END IF;
END PROCESS;
第 3章 VHDL编程基础本例中的进程即为对上升沿触发器的 VHDL描述。进程中
IF语句内条件表达式即可为此触发器时钟输入信号的上升沿进行测试,上升沿一旦到来,表达式在返回 TRUE后,立即执行赋值语句 Q<=DATA,并保持此值于 Q端,直至下一次时钟上升沿的到来。同理,以下表达式表示对信号 CLOCK下降沿的测试:
(CLOCK'EVENT AND CLOCK=?0?)
属性 STABLE的测试功能恰与 EVENT相反,它是信号在 Δ时间段内无事件发生,则返还 TRUE值。以下两语句的功能是一样的。
第 3章 VHDL编程基础
【 例 3.4.30】
NOT(CLOCK'STABLE AND CLOCK=?1?)
(CLOCK'EVENT AND CLOCK=?1?)
请注意,语句,NOT(CLOCK'STABLE AND CLOCK=?1?)”
表达方式是不可综合的。因为,对于 VHDL综合器来说,括号中的语句已等效于一条时钟信号边沿测试专用语句,它已不是操作数,所以不能用操作数方式来对待。
第 3章 VHDL编程基础表 3.4 预定义的属性函数功能表属 性 名 功 能 与 含 义 适 用 范 围
L E F T [(N )]
返回类型或者子类型的左边界,用于数组时,N 表示二维数组行序号类型、子类型
RIG H T [(N )]
返回类型或者子类型的右边界,用于数组时,N 表示二维数组行序号类型、子类型
H IG H [(N )]
返回类型或者子类型的上限值,用于数组时,N 表示二维数组行序号类型、子类型
L O W [(N )]
返回类型或者子类型的下限值,用于数组时,N 表示二维数组行序号类型、子类型
L E N G T H [(N )]
返回数组范围的总长度 ( 范围个数 ),用于 数组时,N 表示二维数组行序号数组
S T RU CT U RE [(N )]
如果块或结构体只含有元件具体装配语句或被 动进程时,
属性? S T U RCT U RE 返回 T RU E
块、构造第 3章 VHDL编程基础续表
B E H A V IO R
如果由块标志指定块或者由构造名指定结构体,又不含有元件具体装配语句,则? B E H A V IO R 返回 T R U E
块、构造
P O S (V A L U E ) 参数 V A L U E 的位置序号 枚举类型
V A L (V A L U E ) 参数 V A L U E 的位置值 枚举类型
S U C C (V A L U E ) 比 V A L U E 的位置序号大的一个相邻位置值 枚举类型
P R E D (V A L U E ) 比 V A L U E 的位置序号小的一个相邻位置值 枚举类型
LEF T O F (V A L U E ) 在 V A L U E 左边位置的相邻值 枚举类型
R IG H T O F (V A L U E ) 在 VA L U E 右边位置的相邻值 枚举类型
E V E N T
如果当前的 Δ 期间内发生了事件,则返回 T R U E,否则返回 F A L S E
信号
A C T IV E
如果当前的 Δ 期间内信号有效,则返回 T R U E,否则返回
F A L S E
信号
L A S T _ E V E N T 从信号最近一次的发生事件至今所经历的时间 信号
L A S T _ V A L U E 最近一次事件发生之前信号的值 信号第 3章 VHDL编程基础续表属 性 名 功 能 与 含 义 适 用 范 围
L A S T _ A C T IV E 返回自信号前面一次事件处理至今所经历时间 信号
D E L A Y E D [(T IM E )]
建立和参考信号同类型的信号,该信号紧跟着 参考信号之后,并有一个可选的时间表达式指定延迟时间信号
S T A B L E [(T IM E )]
每当在可选的时间表达式指定的时间内信号无 事件时,该属性建立一个值为 T R U E 的布尔型信号信号
Q U IE T [(T IM E )]
每当参考信号在可选的时间内无事项处理时,该属性建立一个值为 T R U E 的布尔型信号信号
T R A N S A C T IO N
在此信号上有事件发生,或每个事项处理中,它的值翻转时,该属性建立一个 B IT 型的信号 ( 每次信号有效时,重复返回 0 和 1 的值 )
信号
R A N G E [(N )] 返回按指定排序范围,参数 N 指定二维数组的第 N 行 数组
R E V E R S E _
R A N G E [(N )]
返回按指定逆序范围,参数 N 指定二维数组的第 N 行 数组第 3章 VHDL编程基础说明:● 'LEFT,'RIGHT,'LENGTH和 'LOW用来得到类型或者数组的边界。
● 'POS,'VAL,'SUCC,'LEFTOF和 'RIGHTOF用来管理枚举类型。
● 'ACTIVE,'EVENT,'LAST_ACTIVE,'LAST_EVENT
和 'LAST_VALUE当事件发生时,用来返回有关信息。
● 'DELAYED,'STABLE,'QUIET和 'TRANSACTION建立一个新信号,该新信号为有关的另一个信号返回信号。
● 'RANGE和 'REVERSE_RANGE在该类型恰当的范围内用来控制语句。
第 3章 VHDL编程基础另外还应注意,对于普通的 BIT数据类型的 CLOCK,它只是有 1和 0两种取值,因而例 3.4.30的表述作为对信号上升沿到来与否的测试是正确的。但如果 CLOCK的数据类型已定义为
STD_LOGIC,则其可能的值有 9种。这样一来,就不能从例
3.4.30中的,(CLOCK=?1?)=TRUE”来推断 Δ时刻前 CLOCK一定是 0。因此,对于这种数据类型的时钟信号边沿检测,可用以下表达式来完成:
第 3章 VHDL编程基础
RISING_EDGE(CLOCK)
这条语句只能用于标准位数据类型的信号,其用法如下:
IF RISING_EDGE(CLOCK)THEN
或 WAIT UNTIL RISING_EDGE(CLOCK)
在实际使用中,'EVENT比 'STABLE更常用。对于目前常用的 VHDL综合器来说,EVENT只能用于 IF和 WAIT语句中。
第 3章 VHDL编程基础
2) 数据区间类属性数据区间类属性有 'RANGE[(N)]和 'REVERSE_RANGE[(N)],
这类属性函数主要是对属性项目取值区间进行测试,返还的内容不是一个具体值,而是一个区间,它们的含义如表 3.4所示。
对于同一属性项目,'RANGE和 'REVERSE_RANGE返回的区间次序相反,前者与原项目次序相同,后者相反,见例 3.4.31。
第 3章 VHDL编程基础
【 例 3.4.31】

SIGNAL RANGE1,IN STD_LOGIC_VECTOR(0 TO 7);

FOR I IN RANGE1'RANGE LOOP

本例中的 FOR_LOOP语句与语句,FOR I IN 0 TO 7
LOOP”的功能是一样的,这说明 RANGE1'RANGE返回的区间即为位矢 RANGE1定义的元素范围。如果用 'REVERSE RANGE,
则返回的区间正好相反,是 (7 DOWNTO 0)。
第 3章 VHDL编程基础
3) 数值类属性在 VHDL中的数值类属性测试函数主要有 'LEFT,'RIGHT,
'HIGH,'LOW,它们的功能如表 3.4所示。这些属性函数主要用于对属性目标的一些数值特性进行测试。例如:
第 3章 VHDL编程基础
【 例 3.4.32】

PROCESS(CLOCK,A,B);
TYPE OBJ IS ARRAY(0 TO 15) OF BIT;
SIGNAL S1,S2,S3,S4,INTEGER;
BEGIN
S1<=OBJ'RIGNT;
S2<=OBJ'LEFT;
S3<=OBJ'HIGH;
S4<=OBJ'LOW;

信号 S1,S2,S3、和 S4获得的赋值分别为 0,15,0和 15。
第 3章 VHDL编程基础
4) 数组属性 'LENGTH
此函数的用法同前,只是对数组的宽度或元素的个数进行测定。例如:
【 例 3.4.33】

TYPE ARRY1 ARRAY (0 TO 7) OF BIT;
VARIABLE WTH1,INTEGER;

WTH1,=ARRY1'LENGTH; --WTH1=8

第 3章 VHDL编程基础
5) 用户定义属性属性与属性值的定义格式如下:
ATTRIBUTE 属性名:数据类型;
ATTRIBUTE 属性名 OF 对象名:对象类型 IS 值;
VHDL综合器和仿真器通常使用自定义的属性实现一些特殊的功能。由综合器和仿真器支持的一些特殊的属性一般都包括在 EDA工具厂商的程序包里,例如 Synplify综合器支持的特殊属性都在 SYNPLIFY.ATTRIBUTES程序包中,使用之前加入以下语句即可:
第 3章 VHDL编程基础
LIBRARY SYNPLIFY;
USE SYNPLICITY.ATTRIBUTES.ALL;
又如在 DATA I/O公司的 VHDL综合器中,可以使用属性
PINNUM为端口锁定芯片引脚。
第 3章 VHDL编程基础
【 例 3.4.34】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY CNTBUF IS
PORT( DIR,IN STD_LOGIC;
CLK,CLR,OE,IN STD_LOGIC;
A,B,INOUT STD_LOGIC_VECTOR(0 TO 1);
Q,INOUT STD_ LOGIC_VECTOR(3 DOWNTO 0));
第 3章 VHDL编程基础
ATTRIBUTE PINNUM,STRING;
ATTRIBUTE PINNUM OF CLK,SIGNAL IS "1";
ATTRIBUTE PINNUM OF CLR,SIGNAL IS "2";
ATTRIBUTE PINNUM OF DIR,SIGNAL IS "3";
ATTRIBUTE PINNUM OF OE,SIGNAL IS "11";
ATTRIBUTE PINNUM OF A,SIGNAL IS "13,12";
ATTRIBUTE PINNUM OF B,SIGNAL IS "19,18";
ATTRIBUTE PINNUM OF Q,SIGNAL IS "17,16,15,14";
END CNTBUF;
第 3章 VHDL编程基础
Synopsys FPGA Express 中也在 SYNOPSYS.ATTRIBUTES
程序包中定义了一些属性,用以辅助综合器完成一些特殊功能。
定义一些 VHDL综合器和仿真器所不支持的属性通常是没有意义的。
第 3章 VHDL编程基础
2,文本文件操作 (TEXTIO)
这里所谓的文件操作只能用于 VHDL仿真器中,因为在 IC中,
并不存在磁盘和文件,所以 VHDL综合器忽略程序中所有与文件操作有关的部分。
在完成较大的 VHDL程序的仿真时,由于输入信号很多,输入数据复杂,这时可以采用文件操作的方式设置输入信号。将仿真时输入信号所需要的数据用文本编辑器写到一个磁盘文件中,然后在 VHDL程序的仿真驱动信号生成模块中调用
STD.TEXTIO程序包中的子程序,读取文件中的数据,经过处理后或直接驱动输入信号端。
第 3章 VHDL编程基础仿真的结果或中间数据也可以用 STD.TEXTIO程序包中提供的子程序保存在文本文件中,这对复杂的 VHDL设计的仿真尤为重要。
VHDL仿真器 ModelSim支持许多操作子程序,附带的
STD.TEXTIO程序包源程序是很好的参考文件。
第 3章 VHDL编程基础文本文件操作用到的一些预定义的数据类型及常量定义如下:
TYPE LINE IS ACCESS STRING;
TYPE TEXT IS FILE OF STRING;
TYPE SIDE IS (RIGHT,LEFT);
SUBTYPE WIDTH IS NATURAL;
FILE INPUT,TEXT OPEN READ_MODE IS "STD_INPUT";
FILE OUTPUT,TEXT OPEN WRITE_MODE IS "STD_OUTPUT";
STD.TEXTIO程序包中主要有四个过程用于文件操作,即
READ,READLINE,WRITE和 WRITELINE。因为这些子程序都被多次重载以适应各种情况,实用中请参考 VHDL仿真器给出的 STD.TEXTIO源程序获取详细的信息。
第 3章 VHDL编程基础
【 例 3.4.35】

COMPONENT COUNTER8
PORT(CLK,IN STD_LOGIC;
RESET,IN STD_LOGIC;
CE,LOAD,DIR,IN STD_LOGIC;
DN,IN INTEGER RANGE 0 TO 255;
COUNT,OUT INTEGER RANGE 0 TO 255 );
END COMPONENT;

FILE RESULTS,TEXT OPEN WRITE_MODE IS "RESULTS.TXT";

第 3章 VHDL编程基础
PROCEDURE WRITE_RESULTS (CLK,STD_LOGIC;
RESET,STD_LOGIC;
CE,STD_LOGIC;
LOAD,STD_LOGIC;
DIR,STD_LOGIC;
DIN,STD_LOGIC;
COUNT,STD_LOGIC; ) IS
VARIABLE V_OUT,LINE;
BEGIN
--写入时间
WRITE(V_OUT,NOW,RIGHT,16,PS);
第 3章 VHDL编程基础
--写入输入值
WRITE(V_OUT,CLK,RIGHT,2);
WRITE(V_OUT,RESTET,RIGHT,2);
WRITE(V_OUT,CE,RIGHT,2);
WRITE(V_OUT,LOAD,RIGHT,2);
WRITE(V_OUT,DIR,RIGHT,2);
WRITE(V_OUT,DIN,RIGHT,257);
--写入输出值
WRITE(V_OUT,COUNT,RIGHT,257);
WRITELINE(RESULTS,V_OUT);
END WRITE_RESULTS;

第 3章 VHDL编程基础
3,ASSERT语句
ASSERT(断言 )语句只能在 VHDL仿真器中使用,综合器通常忽略此语句。 ASSERT语句判断指定的条件是否为 TRUE,
如果为 FALSE则报告错误。语句格式是:
ASSERT 条件表达式
REPORT 字符串
SEVERITY 错误等级 [SEVERITY_LEVEL];
第 3章 VHDL编程基础
【 例 3.4.36】
ASSERT NOT (S=?1? AND R=?1?)
REPORT "BOTH VALUES OF SIGNALS S AND R ARE
EQUAL TO?1?"
SEVERITY ERROR;
如果出现 SEVERITY子句,则该子句一定要指定一个类型为
SEVERITY_LEVEL的值。
第 3章 VHDL编程基础
SEVERITY_LEVEL共有如下四种可能的值:
● NOTE:可以用在仿真时传递信息。
● WARNING:用在非平常的情形,此时仿真过程仍可继续,
但结果可能是不可预知的。
● ERROR:用在仿真过程继续执行下去已经不可能的情况。
● FAILURE:用在发生了致命错误,仿真过程必须立即停止的情况。
ASSERT语句可以作为顺序语句使用,也可以作为并行语句使用。作为并行语句时,ASSERT语句可看成为一个被动进程。
第 3章 VHDL编程基础
4,REPORT语句
REPORT语句类似于 ASSERT语句,区别是它没有条件。
其语句格式如下:
REPORT 字符串;
REPORT字符串 SEVERITY SEVERITY_LEVEL;
第 3章 VHDL编程基础
【 例 3.4.37】
WHILE COUNTER <=100 LOOP
IF COUNTER>50
THEN REPORT "THE COUNTER IS OVER 50";
END IF;

END LOOP;
在 VHDL'93标准中,REPORT语句相当于前面省略了
ASSERT FALSE的 ASSERT语句,而在 1987标准中不能单独使用
REPORT语句。
第 3章 VHDL编程基础
5.决断函数决断 (Resolution)函数定义了当一个信号有多个驱动源时,以什么样的方式将这些驱动源的值决断为一个单一的值。决断函数用于声明一个决断信号。
【 例 3.4.38】
PACKAGE RES_PACK IS
FUNCTION RES_FUNC(DATA,IN BIT_VECTOR) RETURN BIT:
SUBTYPE RESOLVED_BIT IS RES_FUNC BIT);
END;
PACKAGE BODY RES_PACK IS
FUNCTION RES_FUNC(DATA,IN BIT_VECTOR) RETURN BIT IS
第 3章 VHDL编程基础
BEGIN
FOR I IN DATA 'RANGE LOOP
IF DATA(I)=?0?THEN
RETURN?0?;
END IF;
END LOOP;
RETURN?1?;
END;
END;
第 3章 VHDL编程基础
USE WORK.RES_PACK.ALL;
ENTITY WAND_VHDL IS
PORT(X,Y,IN BIT; Z,OUT RESOLVED_BIT);
END WAND_VHDL;
ARCHITECTURE WAND_VHDL OF WAND_VHDL IS
BEGIN
Z<=X;
Z<=Y;
END WAND_VHDL;
通常决断函数只在 VHDL仿真时使用,但许多综合器支持预定义的几种决断信号。
第 3章 VHDL编程基础
3.5 VHDL并行语句相对于传统的软件描述语言,并行语句结构是最具 VHDL特色的。在 VHDL中,并行语句具有多种语句格式,各种并行语句在结构体中的执行是同步进行的,或者说是并行运行的,其执行方式与书写的顺序无关。在执行中,并行语句之间可以有信息往来,也可以是互为独立、互不相关、异步运行的 (如多时钟情况 )。每一并行语句内部的语句运行方式可以有两种不同的方式,即并行执行方式 (如块语句 )和顺序执行方式 (如进程语句 )。
因此,VHDL并行语句勾画出了一幅充分表达硬件电路的真实的运行图景。
第 3章 VHDL编程基础图 3.13所示的是在一个结构体中各种并行语句运行的示意图。这些语句不必同时存在,在每一语句模块都可以独立异步运行,模块之间并行运行,并通过信号来交换信息。
请注意,VHDL中的并行运行有多层含义,即模块间的运行方式可以有同时运行、异步运行、非同步运行等方式,从电路的工作方式上可以包括组合逻辑运行方式、同步逻辑运行方式和异步逻辑运行方式等。
第 3章 VHDL编程基础如图 3.13所示的结构体中的并行语句主要有 7种:
● 并行信号赋值语句 (CONCURRENT SIGNAL ASSIGNMENTS)。
● 进程语句 (PROCESS STATEMENTS)。
● 块语句 (BLOCK STATEMENTS)。
● 条件信号赋值语句 (SELECTED SIGNAL ASSIGNMENTS)。
● 元件例化语句 (COMPONENT INSTANTIATIONS)。
● 生成语句 (GENERATE STATEMENTS)。
● 并行过程调用语句 (CONCURRENT PROCEDURE CALLS)。
第 3章 VHDL编程基础并行语句在结构体中的使用格式如下:
ARCHITECTURE 结构体名 OF 实体名 IS
说明语句
BEGIN
并行语句
END ARCHITECTURE 结构体名;
第 3章 VHDL编程基础并行语句与顺序语句并不是相互对立的语句,它们往往互相包含、互为依存,它们是一个矛盾的统一体。严格地说,
VHDL中不存在纯粹的并行行为和顺序行为的语句。例如,相对于其他的并行语句,进程属于并行语句,而进程内部运行的都是顺序语句,而一个单句并行赋值语句,从表面上看是一条完整的并行语句,但实质上却是一条进程语句的缩影,它完全可以用一个相同功能的进程来替代。所不同的是,进程中必须列出所有的敏感信号,而单纯的并行赋值语句的敏感信号是隐性列出的。
第 3章 VHDL编程基础图 3.13结构体中的并行语句模块生成语句条件信号赋值语句元件例化语句并行信号赋值语句块语句进程语句并行过程调用语句信号信号 信号 信号 信号 信号
A R C H I T E C T U R E
E N D A R C H I T E C T U R E
第 3章 VHDL编程基础
3.5.1 进程语句进程 (PROCESS)语句是最具 VHDL语言特色的语句。因为它提供了一种用算法 (顺序语句 )描述硬件行为的方法。进程实际上是用顺序语句描述的一种进行过程,也就是说进程用于描述顺序事件。 PROCESS语句结构包含了一个代表着设计实体中部分逻辑行为的、独立的顺序语句描述的进程。一个结构体中可以有多个并行运行的进程结构,而每一个进程的内部结构却是由一系列顺序语句来构成。
第 3章 VHDL编程基础需要注意的是,PROCESS结构中的顺序语句,及其所谓的顺序执行过程只是相对于计算机中的软件行为仿真的模拟过程而言的,这个过程与硬件结构中实现的对应的逻辑行为是不相同的。 PROCESS结构中既可以有时序逻辑的描述,也可以有组合逻辑的描述,它们都可以用顺序语句来表达。然而,硬件中的组合逻辑具有最典型的并行逻辑功能,而硬件中的时序逻辑也并非都是以顺序方式工作的。
第 3章 VHDL编程基础
1,PROCESS语句格式
PROCESS语句的表达格式如下:
[进程标号,]PROCESS[(敏感信号参数表 )][IS]
[进程说明部分 ]
BEGIN
顺序描述语句
END PROCESS[进程标号 ];
进程说明部分用于定义该进程所需的局部数据环境。
第 3章 VHDL编程基础顺序描述语句部分是一段顺序执行的语句,描述该进程的行为。 PROCESS中规定了每个进程语句在它的某个敏感信号
(由敏感信号参量表列出 )的值改变时都必须立即完成某一功能行为。这个行为由进程顺序语句定义,行为的结果可以赋给信号,并通过信号被其他的 PROCESS或 BLOCK读取或赋值。当进程中定义的任一敏感信号发生更新时,由顺序语句定义的行为就要重复执行一次,当进程中最后一个语句执行完成后,执行过程将返回到第一个语句,以等待下一次敏感信号变化,如此循环往复以至无限。但当遇到 WAIT语句时,执行过程将被有条件地终止,即所谓的挂起 (Suspention)。
第 3章 VHDL编程基础一个结构体中可含有多个 PROCESS结构,每一
PROCESS结构对于其敏感信号参数表中定义的任一敏感参量的变化,每个进程可以在任何时刻被激活或者称为启动。而所有被激活的进程都是并行运行的,这就是为什么 PROCESS
结构本身是并行语句的道理。
第 3章 VHDL编程基础
2,PROCESS 组成
PROCESS语句结构是由三个部分组成的,即进程说明部分、
顺序描述语句部分和敏感信号参数表。
(1) 进程说明部分主要定义一些局部量,可包括数据类型、
常数、属性、子程序等。但需注意,在进程说明部分中不允许定义信号和共享变量。
(2) 顺序描述语句部分可分为赋值语句、进程启动语句、子程序调用语句、顺序描述语句和进程跳出语句等。
第 3章 VHDL编程基础信号赋值语句:即在进程中将计算或处理的结果向信号
(SIGNAL)赋值。
● 变量赋值语句:即在进程中以变量 (VARIABLE)的形式存储计算的中间值。
● 进程启动语句:当 PROCESS的敏感信号参数表中没有列出任何敏感量时,进程的启动只能通过进程启动语句 WAIT语句。
这时可以利用 WAIT语句监视信号的变化情况,以便决定是否启动进程。 WAIT语句可以看成是一种隐式的敏感信号表。
第 3章 VHDL编程基础
● 子程序调用语句:对已定义的过程和函数进行调用,并参与计算。
● 顺序描述语句:包括 IF语句,CASE语句,LOOP语句和
NULL语句等。
● 进程跳出语句:包括 NEXT语句和 EXIT语句。
第 3章 VHDL编程基础
(3) 敏感信号参数表需列出用于启动本进程可读入的信号名
(当有 WAIT语句时例外 )。
第 3章 VHDL编程基础
【 例 3.5.1】
ARCHITECTURE ART OF STAT IS
BEGIN
P1,PROCESS -- 该进程未列出敏感信号,进程需靠 WAIT语句来启动
BEGIN
WAIT UNTIL CLOCK ; -- 等待 CLOCK激活进程
IF (DRIVER=?1?) THEN -- 当 DRIVER为高电平时进入 CASE语句第 3章 VHDL编程基础
CASE OUTPUT IS
WHEN S1=> OUTPUT<=S2;
WHEN S2=> OUTPUT<=S3;
WHEN S3=> OUTPUT<=S4;
WHEN S4=> OUTPUT<=S1;
END CASE;
END PROCESS P1;
END ARCHITECTURE ART;
第 3章 VHDL编程基础
【 例 3.5.2】
SIGNAL CNT4,INTEGER RANGE 0 TO 15; --注意 CNT4的数据类型
...
PROCESS(CLK,CLEAR,STOP) --该进程定义了 3个敏感信号 CLK、
CLEAR,STOP
BEGIN --当其中任何一个改变时,都将启动进程的运行
IF CLEAR=?0? THEN
CNT4<=0;
ELSIF CLK'EVENT AND CLK=?1?THEN --如果遇到时钟上升沿,则 ……
IF STOP=?0?THEN --如果 STOP为低电平,则进行加法计数,否则停止计数
CNT4<=CNT4+1;
END IF;
END IF;
END PROCESS;
第 3章 VHDL编程基础
3.进程设计要点进程的设计需要注意以下几方面的问题:
(1) 虽然同一结构体中的进程之间是并行运行的,但同一进程中的逻辑描述语句则是顺序运行的,因而在进程中只能设置顺序语句。
第 3章 VHDL编程基础
(2) 进程的激活必须由敏感信号表中定义的任一敏感信号的变化来启动,否则必须有一个显式的 WAIT语句来激活。这就是说,进程既可以由敏感信号的变化来启动,也可以由满足条件的 WAIT语句来激活;反之,在遇到不满足条件的 WAIT语句后,
进程将被挂起。因此,进程中必须定义显式或隐式的敏感信号。
如果一个进程对一个信号集合总是敏感的,那么,我们可以使用敏感表来指定进程的敏感信号。但是,在一个使用了敏感表的进程 (或者由该进程所调用的子程序 )中不能含有任何等待语句。
第 3章 VHDL编程基础
(3) 结构体中多个进程之所以能并行同步运行,一个很重要的原因是进程之间的通信是通过传递信号和共享变量值来实现的。所以相对于结构体来说,信号具有全局特性,它是进程间进行并行联系的重要途径。因此,在任一进程的进程说明部分不允许定义信号 (共享变量是 VHDL'93增加的内容 )。
第 3章 VHDL编程基础
(4) 进程是重要的建模工具。进程结构不但为综合器所支持,
而且进程的建模方式将直接影响仿真和综合结果。需要注意的是综合后对应于进程的硬件结构,对进程中的所有可读入信号都是敏感的,而在 VHDL行为仿真中并非如此,除非将所有的读入信号列为敏感信号。
进程语句是 VHDL程序中使用最频繁和最能体现 VHDL语言特点的一种语句,其原因大概是由于它的并行和顺序行为的双重性,以及其行为描述风格的特殊性。为了使 VHDL的软件仿真与综合后的硬件仿真对应起来,应当将进程中的所有输入信号都列入敏感表中。不难发现,在对应的硬件系统中,一个进程和一个并行赋值语句确实有十分相似的对应关系,并行赋值语句就相当于一个将所有输入信号隐性的列入结构体监测范围的
(即敏感表的 )进程语句。
第 3章 VHDL编程基础综合后的进程语句所对应的硬件逻辑模块,其工作方式可以是组合逻辑方式的,也可以是时序逻辑方式的。例如在一个进程中,一般的 IF语句,综合出的多为组合逻辑电路 (一定条件下 );若出现 WAIT语句,在一定条件下,综合器将引入时序元件,如触发器。
第 3章 VHDL编程基础
【 例 3.5.3】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY CNT10 IS
PORT(CLR,IN STD_LOGIC;
IN1,IN STD_LOGIC_VECTOR(3 DOWNTO 0);
OUT1,OUT STD_LOGIC_VECTOR(3 DOWNTO 0));
END CNT10;
ARCHITECTURE ART OF CNT10 IS
第 3章 VHDL编程基础
BEGIN
PROCESS (IN1,CLR)
BEGIN
IF (CLR=?1? OR IN1= "1001") THEN
OUT1<="0000"; --有清零信号,或计数已达 9,OUT1输出 0,
ELSE --否则作加 1操作
OUT1<=IN1+1; --注意,使用了重载算符 "+",重载算符 "+"是在库
ENG IF --STD_LOGIC_UNSIGNED中预先声明的
END PROCESS;
END ART;
第 3章 VHDL编程基础本例的程序中有一个产生组合电路的进程,它描述一个十进制加法器,对于每 4位输入 IN1(3 DOWNTO 0),此进程对其作加 1操作,并将结果由 OUT1(3 DOWNTO 0)输出。由于是组合电路,故无记忆功能。
第 3章 VHDL编程基础本程序经综合后产生的逻辑电路图如图 3.14所示。图中,
ADDER41是一个 1位加 4位的加法器,即 A(3 DOWNTO
0)+B0=S(3 DOWNTO 0),这里取 B0=1; MUX42是一个多路选择器,选择方式如图 3.14所示。由图 3.14可以看出,这个加法器只能对输入值作加 1操作,却不能将加 1后的值保存起来。如果要使加法器有累加作用,必须引入时序元件来储存相加后的值。
例 3.5.4对例 3.5.3作了改进,在进程中增加一条 WAIT语句,使此语句后的信号赋值有了寄存的功能,从而使综合后的电路变成时序电路 (如图 3.15所示 )。
第 3章 VHDL编程基础图 3.14 组合电路型十进制加法器 CNT10综合后的 RTL硬件结构图
M U X 4 2
C LR
O U T 1 [ 0 ]
A D D ER 4 1
I N 1 [ 3 ]
I N 1 [ 2 ]
I N 1 [ 1 ]
I N 1 [ 0 ]
0 O U T 1 [ 3 ]
O U T 1 [ 2 ]
O U T 1 [ 1 ]
S0
Z3
Z2
Z1
Z0
B3
B2
B1
B0
A3
A2
A1
A0
A3
A2
A1
A0
V C C 1
S3
S2
S1
S0
B0
O R 2
A N D 4
N O T
S 0 = 1,= > Z [ 3,,0 ] = B [ 3,,0 ]
S 0 = 0,= > Z [ 3,,0 ] = A [ 3,,0 ]
第 3章 VHDL编程基础图 3.15 组合电路型十进制加法器 CNT10综合后的 RTL硬件结构图 (增加了 D触发器 )
B0
C L R
Q0D0
0
Q0D0
F D 1 1
Q0D0
F D 1 1
Q0D0
F D 1 1
F D 1 1
M U X 4 2
A3
A2
A1
A0
V C C
1
A D D E R 4 1
O R 2
A N D 4
N O T
S 0 = 1,= > Z [ 3,,0 ] = B [ 3,,0 ]
S 0 = 0,= > Z [ 3,,0 ] = A [ 3,,0 ]
C L K
S3
S2
S1
S0
S0
B3
B2
B1
B0
A3
A2
A1
A0
Z3
Z2
Z1
Z0
O U T 1 [ 0 ]
O U T 1 [ 1 ]
O U T 1 [ 2 ]
O U T 1 [ 3 ]
第 3章 VHDL编程基础
【 例 3.5.4】
LIBRARY IEEE
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY CNT10 IS
PORT(CLR,IN STD_LOGIC;
CLK,IN STD_LOGIC;
CNT,BUFFER STD_LOGIC_VECTOR(3 DOWNTO 0));
END CNT10;
ARCHITECTURE ART OF CNT10 IS
第 3章 VHDL编程基础
BEGIN
PROCESS
BEGIN
WAIT UNTIL CLK'EVENT AND CLK =?1?; --等待时钟 CLK的上沿
IF (CLR=?1?OR CNT=9) THEN
CNT<="0000";
ELSE
CNT<=CNT+1;
END IF;
END PROCESS;
END ART;
第 3章 VHDL编程基础例 3.5.4描述的是一个典型的十进制时序逻辑加法计数器,
综合后的 RTL电路结构如图 3.15所示。图 3.15与图 3.14电路的惟一区别是增加了 4个 D触发器,用于加 1值后的储存;对于原来的
4位外输入值,则由 4个 D触发器的储存值反馈回来替代,整个加法操作只需加入时钟脉冲即可。
第 3章 VHDL编程基础例 3.5.5描述的是一个含有异步清零 (复位 )功能的 4状态同步有限状态机,在结构体中用了两个同步运行的进程。在第一个进程中,首先监测复位信号 RST,一旦测到复位信号,立即使当前状态返回到初始态S 0。如无复位信号,即刻监测时钟信号,
一旦测到时钟信号 CLK的上升沿,立即将当前状态的值赋给信号 CURRENT_STATE,并由它传递给第二个进程。在同一时间内,第二个进程根据信号 CURRENT_STATE的值确定下一状态的值,见图 3.16。
第 3章 VHDL编程基础图 3.16 4状态同步有限状态机电路图
B1
B
AA1
I N C
N O T
N O R 2
C L K
R S T
D Q
C
D Q
C
D _ F F
M U X 2 1
S
O U T 1
N A N D 2
N A N D 3
第 3章 VHDL编程基础
【 例 3.5.5】
PACKAGE MTYPE IS
TYPE STATE_T IS (S0,S1,S2,S3); --利用程序包定义数据类型
END MTYPE;
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE WORK.MTYPE.ALL; --打开程序包
ENTITY S4_MACHINE IS
PORT(CLK,INC,A1,B1,INSTD_LOGIC;
RST,IN BOOLEAN;
OUT1,OUT STD_LOGIC);
第 3章 VHDL编程基础
END ENTITY S4_MACHINE;
ARCHITECTURE ART OF S4_MACHINE IS
SIGNAL CURRENT_STATE,NEXT_STATE,STATE_T;
BEGIN
SYNC,PROCESS(CLK,RST) --第一个进程
BEGIN
IF (RST) THEN
CURRENT_STATE<=S0; --监测复位信号
ELSIF(CLK'EVENT AND CLK=?1?) THEN --监测时钟上沿
CURRENT_STATE<=NEXT_STATE;
END IF;
END PROCESS SYNC;
第 3章 VHDL编程基础
FSM,PROCESS(CURRENT_STATE,A1,B1) --第二个进程
BEGIN
OUT1<=A1;
NEXT_STATE<=S0;
IF (INC=?1?) THEN
CASE CURRENT_STATE IS
WHEN S0=> NEXT_STATE<=S1;
WHEN S1=> NEXT_STATE<=S2; OUT<=B1;
WHEN S2=> NEXT_STATE<=S3;
WHEN S2=> NULL
END CASE;
END IF;
END PROCESS FSM;
END ART;
第 3章 VHDL编程基础
【 例 3.5.6】

A_OUT <=A WHEN (ENA) ELSE 'Z';
B_OUT <=B WHEN (ENA) ELSE 'Z';
C_OUT <=C WHEN (ENA) ELSE 'Z';
PROCESS (A_OUT)
BEGIN
BUS_OUT <=A_OUT;
END PROCESS;
PROCESS (B_OUT)
第 3章 VHDL编程基础
BEGIN
BUS_OUT <=B_OUT;
END PROCESS;
PROCESS (C_OUT)
BEGIN
BUS_OUT <=C_OUT;
END PROCESS;

第 3章 VHDL编程基础本例中的程序用 3个进程语句描述了 3个并列的三态缓冲器电路,这个电路由 3个完全相同的三态缓冲器构成,且输出是连接在一起的。这是一种总线结构,它的功能是可以在同一条线上的不同时刻内传输不同的信息。对应的硬件结构如图 3.17
所示,这是一个多驱动信号的实例,有许多实际的应用。
第 3章 VHDL编程基础图 3.17 三态缓冲器总线结构
B U S _ O U T
C _ O U T
E N C
O
T
1
1
B _ O U T
E N B
O
T
1
1
B C
A _ O U T
E N A
O
T
1
1
A
第 3章 VHDL编程基础
3.5.2 块语句块 (BLOCK)语句是一种将结构体中的并行描述语句进行组合的方法,它的主要目的是改善并行语句及其结构的可读性,
或是利用 BLOCK的保护表达式关闭某些信号。
1,BLOCK语句的格式
BLOCK语句的表达格式如下:
块标号,BLOCK [(块保护表达式 )]
接口说明类属说明
BEGIN
并行语句
END BLOCK [块标号 ];
第 3章 VHDL编程基础接口说明部分有点类似于实体的定义部分,它可包含由关键词 PORT,GENERIC,PORT MAP和 GENERIC MAP引导的接口说明等语句,对 BLOCK的接口设置以及与外界信号的连接状况加以说明。
块的类属说明部分和接口说明部分的适用范围仅限于当前
BLOCK。所以,所有这些在 BLOCK内部的说明对于这个块的外部来说是完全不透明的,即不能适用于外部环境,但对于嵌套于内层的块却是透明的。块的说明部分可以定义的项目主要有:
USE语句、子程序、数据类型、子类型、常数、信号、元件。
块中的并行语句部分可包含结构体中的任何并行语句结构。
BLOCK语句本身属并行语句,BLOCK语句中所包含的语句也是并行语句。
第 3章 VHDL编程基础
2,BLOCK的应用
BLOCK的应用可使结构体层次鲜明,结构明确。利用
BLOCK语句可以将结构体中的并行语句划分成多个并列方式的
BLOCK,每一个 BLOCK都像一个独立的设计实体,具有自己的类属参数说明和界面端口,以及与外部环境的衔接描述。以下是两个使用 BLOCK语句的实例,例 3.5.7描述了一个具有块嵌套方式的 BLOCK语句结构。
在较大的 VHDL程序的编程中,恰当的块语句的应用对于技术交流、程序移值、排错和仿真都是十分有益的。
第 3章 VHDL编程基础
【 例 3.5.7】

ENTITY GAT IS
GENERIC(L_TIME,TIME; S_TIME,TIME); --类属说明
PORT (B1,B2,B3,INOUT BIT); --结构体全局端口定义
END ENTITY GAT;
ARCHITECTURE ART OF GAT IS
SIGNAL A1,BIT; --结构体全局信号 A1定义
BEGIN
BLK1,BLOCK --块定义,块标号名是 BLK1
GENERIC (GB1,GB2,TIME); --定义块中的局部类属参量第 3章 VHDL编程基础
GENERIC MAP (GB1=>L-TIME,GB2=>S-TIME); --局部端口参量设定
PORT (PB,IN BIT; PB2,INOUT BIT); --块结构中局部端口定义
POTR MAP(PB1=>B1,PB2=>A1); --块结构端口连接说明
CONSTANT DELAY,TIME:=1 MS; --局部常数定义
SIGNAL S1,BIT; --局部信号定义
BEGIN
S1<=PB1 AFTER DELAY;
PB2<=S1 AFTER GB1,B1 AFTER GB2;
END BLOCK BLK1;
END ARCHITECTURE ART;
第 3章 VHDL编程基础
【 例 3.5.8】

B1,BLOCK
SIGNAL S1,BIT;
BEGIN
S1<=A AND B;
B2,BLOCK
SIGNAL S2,BIT;
BEGIN
S2<=C AND D;
第 3章 VHDL编程基础
B3,BLOCK
BEGIN
Z<=S2;
END BLOCK B3;
END BLOCK B2;
Y<=S1;
END BLOCK B1;

本例在不同层次的块中定义了同名的信号,显示了信号的有效范围。
第 3章 VHDL编程基础
3,BLOCK语句在综合中的地位与大部分的 VHDL语句不同,BLOCK语句的应用,包括其中的类属说明和端口定义,都不会影响对原结构体的逻辑功能的仿真结果。例如,下两例的仿真结果是完全相同的。
【 例 3.5.9】
A1,OUTL<=?1? AFTER 2 NS;
BLK1,BLOCK
BEGIN
A2,OUT 2<=?1? AFTER 3 NS;
A3,OUT 3<=?0? AFTER 2 NS;
END BLOCK BLK1;
第 3章 VHDL编程基础
【 例 3.5.10】
A1,OUT <=?1? AFTER 3 NS;
A2,OUT<=?1? AFTER 3 NS;
A3,OUT<=?0? AFTER 2 NS;
由于 VHDL综合器不支持保护式 BLOCK语句 (GUARDED
BLOCK),在此不讨论该语句的应用。基于实用的观点,结构体中功能语句的划分最好使用元件例化 (COMPONENT
INSTANTIATION)的方式来完成。
第 3章 VHDL编程基础块语句的并行工作方式更为明显,块语句本身是并行语句结构,而且它的内部也都是由并行语句构成的 (包括进程 )。
需特别注意的是,块中定义的所有的数据类型、数据对象
(信号、变量、常量 )和子程序等都是局部的;对于多层嵌套的块结构,这些局部定义量只适用于当前块,以及嵌套于本层块的所有层次的内部块,而对此块的外部来说是不可见的。
例 3.5.11是一个含有三重嵌套块的程序,从此例能很清晰地了解上述关于块中数据对象的可视性规则。
第 3章 VHDL编程基础
【 例 3.5.11】

B1,BLOCK --定义块 B1
SIGNAL S,BIT; --在 B1块中定义 S
BEGIN
S<=A AND B; --向 B1中的 S赋值
B2,BLOCK --定义块 B2,套于 B1块中
SIGNAL S,BIT; --定义 B2块中的信号 S
BEGIN
S<=A AND B; --向 B2中的 S赋值第 3章 VHDL编程基础
B3,BLOCK
BEGIN
Z<= S; --此 S来自 B2块
END BLOCK B3;
END BLOCK B2;
Y<= S; --此 S来自 B1块
END BLOCK B1;
此例是对嵌套块的语法现象作一些说明,它实际描述的是如图 3.18所示的两个相互独立的 2输入与门。
第 3章 VHDL编程基础图 3.18 两个 2输入与门
B
C
D
A
Z
Y
第 3章 VHDL编程基础
3.5.3 并行信号赋值语句并行信号赋值语句有三种形式:简单信号赋值语句、条件信号赋值语句和选择信号赋值语句。
这三种信号赋值语句的共同点是:赋值目标必须都是信号,
所有赋值语句与其他并行语句一样,在结构体内的执行是同时发生的,与它们的书写顺序和是否在块语句中没有关系。每一信号赋值语句都相当于一条缩写的进程语句,而这条语句的所有输入 (或读入 )信号都被隐性地列入此过程的敏感信号表中。
因此,任何信号的变化都将启动相关并行语句的赋值操作,而这种启动完全是独立于其他语句的,它们都可以直接出现在结构体中。
第 3章 VHDL编程基础
1,简单信号赋值语句并行简单信号赋值语句是 VHDL并行语句结构的最基本的单元,它的语句格式如下:
信号赋值目标 <=表达式式中信号赋值目标的数据类型必须与赋值符号右边表达式的数据类型一致。
第 3章 VHDL编程基础
【 例 3.5.12】
ARCHITECTURE ART OF XHFZ IS
SIGNAL S1,STD_LOGIC;
BEGIN
OUTPUT 1<= A AND B ;
OUTPUT 2<= C+D;
B1,BLOCK
SIGNAL E,F,G,H,STD_LOGIC;
BEGIN
G<=E OR F;
H<=E XOR F;
END BLOCK B1
S1<=G;
END ARCHITECTURE ART
第 3章 VHDL编程基础
2.条件信号赋值语句条件信号赋值语句的表达方式如下:
赋值目标 <= 表达式 WHEN 赋值条件 ELSE
表达式 WHEN 赋值条件 ELSE

表达式;
第 3章 VHDL编程基础在结构体中的条件信号赋值语句的功能与在进程中的 IF语句相同。在执行条件信号赋值语句时,每一赋值条件是按书写的先后关系逐项测定的,一旦发现赋值条件 =TRUE,立即将表达式的值赋给赋值目标。
对于在例 3.4.7中用顺序语句描述的电路 (见图 3.7)也可以用例 3.5.13的条件赋值语句来描述。
第 3章 VHDL编程基础
【 例 3.5.13】

Z <= A WHEN P1=?1? ELSE
B WHEN P2=?0? ELSE
C;

请注意,由于条件测试的顺序性,第一句具有最高赋值优先级,第二句其次,第三句最后。这就是说,如果当 P1和 P2同时为 1 时,Z获得的赋值是 A。
第 3章 VHDL编程基础
3.选择信号赋值语句选择信号赋值语句格式如下:
WITH 选择表达式 SELECT
赋值目标信号 <=表达式 WHEN选择值表达式 WHEN选择值

表达式 WHEN选择值;
第 3章 VHDL编程基础选择信号赋值语句本身不能在进程中应用,但其功能却与进程中的 CASE语句的功能相似。 CASE语句的执行依赖于进程中敏感信号的改变而启动进程,而且要求 CASE语句中各子句的条件不能有重叠,必须包容所有的条件。
选择信号语句中也有敏感量,即关键词 WITH旁的选择表达式。每当选择表达式的值发生变化时,就将启动此语句对于各子句的选择值进行测试对比,当发现有满足条件的子句的选择值时,就将此子句表达式中的值赋给赋值目标信号。与 CASE语句相类似,选择赋值语句对于子句条件选择值的测试具有同期性,不像以上的条件信号赋值语句那样是按照子句的书写顺序从上至下逐条测试的。因此,选择赋值语句不允许有条件重叠的现象,也不允许存在条件涵盖不全情况。
第 3章 VHDL编程基础图 3.19
D E C O D E R
D _ O U T
A
B
C
D1
D2
B
C
A
D A T A 1
D A T A O U T
D A T A 2
第 3章 VHDL编程基础
【 例 3.5.14】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY DECODER IS
PORT(A,B,C,IN STD_LOGIC;
DATA1,DATA2,IN STD_LOGIC;
DATAOUT,OUT STD_LOGIC);
END DECODER;
ARCHITECTURE ART OF DECODER IS
BEGIN
SIGNAL INSTRUCTION,STD_LOGIC_VECTOR(2 DOWNTO 0);
第 3章 VHDL编程基础
INSTRUCTION <=C & B & A;
WITH INSTRUCTION SELECT
DATAOUT <=DATA1 AND DATA2 WHEN "000",
DATA1 OR DATA2 WHEN "001",
DATA1 NAND DATA2 WHEN "010",
DATA1 NOR DATA2 WHEN "011",
DATA1 XOR DATA2 WHEN "100",
DATA1 NXOR DATA2 WHEN "101",
'Z' WHEN OTHERS; --当不满足条件时,输出呈高阻态
END ARCHITECTURE ART;
第 3章 VHDL编程基础
3.5.4 并行过程调用语句并行过程调用语句可以作为一个并行语句直接出现在结构体或块语句中。并行过程调用语句的功能等效于包含了同一个过程调用语句的进程。并行过程调用语句的语句调用格式与前面讲的顺序过程调用语句是相同的,即过程名 (关联参量名 )。
例 3.5.15是个说明性的例子,在这个例子中,首先定义了一个完成半加器功能的过程。此后在一条并行语句中调用了这个过程,而在接下去的一条进程中也调用了同一过程。事实上,
这两条语句是并行语句,且完成的功能是一样的。
第 3章 VHDL编程基础
【 例 3.5.15】

PROCEDURE ADDER(SIGNAL A,B,IN STD_LOGIC; --过程名为 ADDER
SIGNAL SUM,OUT STD_LOGIC);

ADDER(A1,B1,SUM1); --并行过程调用
… --在此,A1,B1,SUM1即为分别对应于 A,B,SUM的关联参量名
PROCESS(C1,C2); --进程语句执行
BEGIN
ADDER(C1,C2,S1); --顺序过程调用,在此 C1,C2,S1即为分别对
END PROCESS; --应于 A,B,SUM的关联参量名第 3章 VHDL编程基础并行过程的调用,常用于获得被调用过程的多个并行工作的复制电路。例如,要同时检测出一系列有不同位宽的位矢信号,每一位矢信号中的位只能有一个位是 1,而其余的位都是 0,
否则报告出错。完成这一功能的一种办法是先设计一个具有这种位矢信号检测功能的过程,然后对不同位宽的信号并行调用这一过程。
例 3.5.16中首先设计了一个过程 CHECK,用于确定一给定位宽的位矢是否只有一个位是 1,如果不是,则将 CHECK中的输出参量,ERROR”设置为 TRUE(布尔量 )。
第 3章 VHDL编程基础
【 例 3.5.16】
PROCEDURE CHECK(SIGNAL A,IN STD_LOGIC_VECTOR; --在调用时
SIGNANL ERROR,OUT BOOLEAN) IS --再定位置
VARIABLE FOUND_ONE,BOOLEAN,=FALSE; --设初始值
BEGIN
FOR I IN A'RANGE LOOP --对位矢量 A的所有的位元素进行循环检测
IF A(I)=?1?THEN --发现 A中有‘ 1?
IF FOUND_ONE THEN --FOUND_ONE为 TRUE,则表明发现了一个以上的‘ 1?
ERROR<=TRUE; --发现了一个以上的‘ 1?,令 FOUND_ONE为 TRUE
RETURN; --结束过程第 3章 VHDL编程基础
END IF;
FOUND_ONE,=TRUE; --在 A中已发现了一个‘ 1?
END IF;
END LOOP; --再测 A中的其他位
ERROR<=NOT FOUND_ONE; --如果没有任何‘ 1?被发现,ERROR将被置 TRUE
END PROCEDURE CHECK;
第 3章 VHDL编程基础
【 例 3.5.17】

CHBLK,BLOOK
SIGNAL S1,STD_LOGIC_VECTOR(0 TO 0); --过程调用前设定矢尺寸
SIGNAL S2,STD_LOGIC_VECTOR(0 TO 1);
SIGNAL S3,STD_LOGIC_VECTOR(0 TO 2);
SIGNAL S4,STD_LOGIC_VECTOR(0 TO 3);
SIGNAL E1,E2,E3,E4,BOOLEAN;
BEGIN
CHECK(S1,E1); --并行过程调用,关联参数名为 S1,E1
CHECK(S2,E2); --并行过程调用,关联参数名为 S2,E2
CHECK(S3,E3); --并行过程调用,关联参数名为 S3,E3
CHECK(S4,E4); --并行过程调用,关联参数名为 S4,E4
END BLOCK;

第 3章 VHDL编程基础图 3.20 块 CHBLK的逻辑电路结构图
S 1 [ 0 ] E1
E3
E2
S 2 [ 1 ]
S 2 [ 0 ]
S 3 [ 0 ]
S 3 [ 2 ]
S 3 [ 1 ]
S 4 [ 0 ]
S 4 [ 1 ]
S 4 [ 2 ]
S 4 [ 3 ]
E4
第 3章 VHDL编程基础
3.5.5 元件例化语句元件例化就是将预先设计好的设计实体定义为一个元件,然后利用特定的语句将此元件与当前的设计实体中的指定端口相连接,从而为当前设计实体引入一个新的低一级的设计层次。
在这里,当前设计实体相当于一个较大的电路系统,所定义的例化元件相当于一个要插在这个电路系统板上的芯片,而当前设计实体中指定的端口则相当于这块电路板上准备接受此芯片的一个插座。元件例化是使 VHDL设计实体构成自上而下层次化设计的一种重要途径。
第 3章 VHDL编程基础在一个结构体中调用子程序,包括并行过程的调用非常类似于元件例化,因为通过调用,为当前系统增加了一个类似于元件的功能模块。但这种调用是在同一层次内进行的,并没有因此而增加新的电路层次,这类似于在原电路系统增加了一个电容或一个电阻。
第 3章 VHDL编程基础元件例化是可以多层次的,在一个设计实体中被调用安插的元件本身也可以是一个低层次的当前设计实体,因而可以调用其他的元件,以便构成更低层次的电路模块。因此,元件例化就意味着在当前结构体内定义了一个新的设计层次,这个设计层次的总称叫元件,但它可以以不同的形式出现。如上所说,
这个元件可以是已设计好的一个 VHDL设计实体,可以是来自
FPGA元件库中的元件,也可是以别的硬件描述语言 (如 Verilog)
设计实体。该元件还可以是软的 IP核,或者是 FPGA中的嵌入式硬 IP核。
第 3章 VHDL编程基础元件例化语句由两部分组成,前一部分是将一个现成的设计实体定义为一个元件的语句,第二部分则是此元件与当前设计实体中的连接说明,它们的语句格式如下:
-- 元件定义语句
COMPONENT 例化元件名 IS
GENERIC (类属表 )
PORT(例化元件端口名表 )
END COMPONENT 例化元件名;
--元件例化语句元件例化名:例化元件名 PORT MAP(
[例化元件端口名 =>] 连接实体端口名,…) ;
第 3章 VHDL编程基础以上两部分语句在元件例化中都是必须存在的。第一部分语句是元件定义语句,相当于对一个现成的设计实体进行封装,
使其只留出外面的接口界面。就像一个集成芯片只留几个引脚在外一样,它的类属表可列出端口的数据类型和参数,例化元件端口名表可列出对外通信的各端口名。元件例化的第二部分语句即为元件例化语句,其中的元件例化名是必须存在的,它类似于标在当前系统 (电路板 )中的一个插座名,而例化元件名则是准备在此插座上插入的、已定义好的元件名。 PORT MAP是端口映射的意思,其中的例化元件端口名是在元件定义语句中的端口名表中己定义好的例化元件端口的名字,连接实体端口名则是当前系统与准备接入的例化元件对应端口相连的通信端口,相当于插座上各插针的引脚名。
第 3章 VHDL编程基础元件例化语句中所定义的例化元件的端口名与当前系统的连接实体端口名的接口表达有两种方式。一种是名字关联方式,
在这种关联方式下,例化元件的端口名和关联 (连接 )符号,=>”
两者都是必须存在的。这时,例化元件端口名与连接实体端口名的对应式,在 PORT MAP句中的位置可以是任意的。
另一种是位置关联方式。若使用这种方式,端口名和关联连接符号都可省去,在 PORT MAP子句中,只要列出当前系统中的连接实体端口名就行了,但要求连接实体端口名的排列方式与所需例化的元件端口定义中的端口名一一对应。
以下是一个元件例化的示例,例 3.5.18中首先完成了一个 2
输入与非门的设计,然后利用元件例化产生了如图 3.21所示的由 3个相同的与非门连接而成的电路。
第 3章 VHDL编程基础图 3.21 ORD41逻辑原理图
A1
U1
U2
Z1
U3
B1
C1
D1
A
B
A
B
A
B
C
C
C
S1
S2
N D 2
N D 2
N D 2
第 3章 VHDL编程基础
【 例 3.5.18】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY ND2 IS
PORT(A,B,IN STD_LOGIC;
C,OUT STD_LOGIC);
END ND2;
ARCHITECTURE ARTND2 OF ND2 IS
BEGIN
Y<=A NAND B;
END ARCHITECTURE ARTND2;
第 3章 VHDL编程基础
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY ORD41 IS
PORT(A1,B1,C1,D1,IN STD_LOGIC;
Z1,OUT STD_LOGIC);
END ORD41;
ARCHITECTURE ARTORD41 OF ORD41 IS
COMPONENT ND2
PORT(A,B,IN STD_LOGIC;
C,OUT STD_LOGIC);
第 3章 VHDL编程基础
END COMPONENT;
SIGNAL X,Y,STD_LOGIC;
BEGIN
U1,ND2 PORT MAP (A1,B1,X); --位置关联方式
U2,ND2 PORT MAP (A=>C1,C=>Y,B=>D1); --名字关联方式
U3,ND2 PORT MAP (X,Y,C=>Z1); --混合关联方式
END ARCHITECTURE ARTORD41;
第 3章 VHDL编程基础
3.5.6 生成语句生成语句可以简化为有规则设计结构的逻辑描述。生成语句有一种复制作用,在设计中,只要根据某些条件,设定好某一元件或设计单位,就可以利用生成语句复制一组完全相同的并行元件或设计单元电路结构。生成语句的语句格式有如下两种形式:
[标号,]FOR 循环变量 IN 取值范围 GENERATE
说明
BEGIN
并行语句
END GENERATE[标号 ];
第 3章 VHDL编程基础
[标号,]IF 条件 GENERATE
说明
BEGIN
并行语句
END GENERATE[标号 ];
第 3章 VHDL编程基础这两种语句格式都是由如下四部分组成:
(1) 生成方式:有 FOR语句结构或 IF语句结构,用于规定并行语句的复制方式。
(2) 说明部分:这部分包括对元件数据类型、子程序和数据对象作一些局部说明。
(3) 并行语句:生成语句结构中的并行语句是用来,COPY”
的基本单元,主要包括元件、进程语句、块语句、并行过程调用语句、并行信号赋值语句甚至生成语句。这表示生成语句允许存在嵌套结构,因而可用于生成元件的多维阵列结构。
(4) 标号:生成语句中的标号并不是必须的,但如果在嵌套生成语句结构中就是很重要的。
第 3章 VHDL编程基础对于 FOR语句结构,主要是用来描述设计中的一些有规律的单元结构,其生成参数及其取值范围的含义和运行方式与
LOOP语句十分相似。但需注意,从软件运行的角度上看,FOR
语句格式中生成参数 (循环变量 )的递增方式具有顺序的性质,但是最后生成的设计结构却是完全并行的,这就是为什么必须用并行语句来作为生成设计单元的缘故。
第 3章 VHDL编程基础生成参数 (循环变量 )是自动产生的,它是一个局部变量,
根据取值范围自动递增或递减。取值范围的语句格式与 LOOP语句是相同的,有两种形式:
表达式 TO 表达式; --递增方式,如 1 TO 5
表达式 DOWNTO 表达式; --递减方式,如 5 DOWNTO 1
其中的表达式必须是整数。
例 3.5.19是利用了 VHDL数组属性语句 ATTRIBUTE'RANGE
作为生成语句的取值范围,进行重复元件例化过程,从而产生了一组并列的电路结构 (如图 3.22所示 )。
第 3章 VHDL编程基础图 3.22 生成语句产生的 8个相同的电路模块
A [ 0 ]
C O M P
I N P U T O U T P U T B [ 0 ]
A [ 1 ]
C O M P
I N P U T O U T P U T B [ 1 ]
A [ 7 ]
C O M P
I N P U T O U T P U T B [ 7 ]

第 3章 VHDL编程基础
【 例 3.5.19】

COMPONENT COMP
PORT (X,IN STD_LOGIC; Y,OUT STD_LOGIC);
END COMPONENT;
SIGNAL A,B,STD_LOGIC_VECTOR (0 TO 7);

GEN,FOR I IN A'RANGE GENERATE
U1,COMP PORT MAP (X=> A(I),Y=>B(I));
END GENERATE GEN;

第 3章 VHDL编程基础以下将利用元件例化和 FOR_GENERATE语句完成一个 8位三态锁存器的设计。示例仿照 74373(或 74LS373/74HC373)的工作逻辑进行设计。 74373的器件引脚功能如图 3.23所示,它的引脚功能分别是,D1~ D8为数据输入端; Q1~ Q8为数据输出端;
OEN为输出使能端,若 OEN=1,则 Q8~ Q1的输出为高阻态,
若 OEN=0,则 Q8~ Q1的输出为保存在锁存器中的信号值; G为数据锁存控制端,若 G=1,D8~ D1输入端的信号进入 74373中的 8位锁存器中,若 G =0,74373中的 8位锁存器将保持原先锁入的信号值不变。
74373的内部工作原理如图 3.24所示。可采用传统的自底向上的方法来设计 74373。首先设计底层的 1位锁存器 LATCH,例
3.5.20是 74373逻辑功能的完整描述。
第 3章 VHDL编程基础图 3.23 74373引脚图
7 4 3 7 3
D8D7D6D5D4D3D2D1 O EN G
Q8Q7Q6Q5Q4Q3Q2Q1
第 3章 VHDL编程基础图 3.24 SN74373的内部逻辑结构
O E N
L A T C H
L A T C H
L A T C H
L A T C H
L A T C H
L A T C H
L A T C H
L A T C H
Q
Q
Q
Q
Q
Q
Q
Q
E N A
D
E N A
D
D
E N A
D
E N A
D
E N A
D
E N A
D
E N A
D
E N A
G
D8
D7
D6
D5
D4
D3
D2
D1
O T 1 1
O T 1 1
O T 1 1
O T 1 1
O T 1 1
O T 1 1
O T 1 1
Q8
Q7
Q6
Q5
Q4
Q3
Q2
Q1
O T 1 1
第 3章 VHDL编程基础
【 例 3.5.20】
--1位锁存器 LATCH的逻辑描述
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY LATCH IS
PORT(D,IN STD_LOGIC;
ENA,IN STD_LOGIC;
Q,OUT STD_LOGIC);
END ENTITY LATCH;
ARCHITECTURE ONE OF LATCH IS
SIGNAL SIG_SAVE,STD_LOGIC;
第 3章 VHDL编程基础
BEGIN
PROCESS(D,ENA)
BEGIN
IF ENA=?1? THEN
SIG_SAVE<=D;
END IF;
Q<= SIG_SAVE;
END PROCESS;
END ARCHITECTURE ONE;
--SN74373的逻辑描述
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
第 3章 VHDL编程基础
ENTITY SN74373 IS --SN74373器件接口说明
PORT (D,IN STD_LOGIC_VECTOR(8 DOWNTO 1); --定义 8位输入信号
OEN,IN STD_LOGIC;
G,IN STD_LOGIC;
Q,OUT STD_LOGIC_VECTOR(8 DOWNTO 1); --定义 8位输出信号
END ENTITY SN74373;
ARCHITECTURE ONE OF SN74373 IS
COMPONENT LATCH --声明调用前面描述的 1位锁存器
PORT(D,ENA,IN STD_LOGIC;
Q,OUT STD_LOGIC );
END COMPONENT;
SIGNAL SIG_MID,STD_LOGIC_VECTOR (8 DOWNTO 1);
第 3章 VHDL编程基础
BEGIN
GELATCH,FOR INUM IN 1 TO 8 GENERATE
--用 FOR_GENERATE 语句循环例化 8个 1锁存器
LATCHX,LATCH PORT MAP(D(INUM),G,SIG_MID(INUM));
--位置关联
END GENERATE;
Q<=SIG_MID WHEN OEN=0 ELSE --条件信号赋值语句
"ZZZZZZZZ"; --当 OEN=1 时,Q(8)~Q(1)输出状态呈高阻态
END ARCHITECTURE ONE;
ARCHITECTURE TWO OF SN74373 IS
SIGNAL SIGVEC_SAVE,STD_LOGIC_VECTOR(8 DOWNTO 1);
第 3章 VHDL编程基础
BEGIN
PROCESS(D,OEN,G)
BEGIN
IF OEN=?0? THEN --IF语句
Q<=SIGVEC_SAVE; ELSE
Q<="ZZZZZZZZ";
END IF;
IF G=?1?THEN
SIGVEC_SAVE<=D;
END IF;
END PROCESS;
END ARCHITECTURE TWO;
第 3章 VHDL编程基础由本例可以看出:
(1) 程序中安排了两个结构体,以不同的电路来实现相同的逻辑,即一个实体可以对应多个结构体,每个结构体对应一种实现方案。在例化这个器件的时候,需要利用配置语句指定一个结构体,即指定一种实现方案,否则 VHDL综合器会自动选择最新编译的结构体,即结构体 TWO。
第 3章 VHDL编程基础
(2) COMPONENT语句对将要例化的器件进行了接口声明,
它对应一个已设计好的实体 (ENTITY LATCH)。 VHDL综合器根据 COMPONENT指定的器件名和接口信息来装配器件。本例中 COMPONENT语句说明的器件 LATCH必须与前面设计的实体 LATCH的接口方式完全对应。这是因为,对于结构体
ONE,在未用 COMPONENT 声明之前,VHDL编译器和
VHDL综合器根本不知道有一个已设计好的 LATCH器件存在。
第 3章 VHDL编程基础
(3) 在 FOR_GENERATE语句使用中,GELATCH为标号,
INUM为变量,从 1~ 8共循环了 8次。
(4),LATCHX,LATCH PORT MAP(D(INUM),G,
SIG_MID(INUM));"是一条含有循环变量 INUM的例化语句,且信号的连接方式采用的是位置关联方式,安装后的元件标号是
LATCHX。 LATCH引脚 D连在信号线 D(INUM)上,引脚 ENA连在信号线 G上,引脚 Q连在信号线 SIG_MID(INUM)上。 INUM
的值从 1~ 8,LATCH从 1~ 8共例化了 8次,即共安装了 8个
LATCH。信号线 D(1)~ D(8),SIG_MID(1)~ SIG_MID(8)都分别连在这 8个 LATCH上。
第 3章 VHDL编程基础读者可以将例 3.5.20中的结构体 ONE所描述功能与图 3.24中的原理图描述方式进行对比。
通常情况下,一些电路从总体上看是由许多相同结构的电路模块组成的,但在这些电路的两端却是不规则的,无法直接使用 FOR_GENERATE语句描述。例如,由多个 D触发器构成的移位寄存器,它的串入和串出的两个末端结构是不一样的。
第 3章 VHDL编程基础对于这种内部由多个规则模块构成而两端结构不规则的电路,可以用 FOR_GENERATE语句和 IF_GENERATE语句共同描述。设计中,可以根据电路两端的不规则部分形成的条件用
IF_GENERATE语句来描述,而用 FOR_GENERATE语句描述电路内部的规则部分。使用这种描述方法的好处是,使设计文件具有更好的通用性、可移植性和易改性。实用中,只要改变几个参数,就能得到任意规模的电路结构。
第 3章 VHDL编程基础
3.6 子程序 (SUBPROGRAM)
子程序是一个 VHDL程序模块,它是利用顺序语句来定义和完成算法的,应用它能更有效地完成重复性的设计工作。子程序不能从所在的结构体的其他块或进程结构中直接读取信号值或者向信号赋值,而只能通过子程序调用及与子程序的界面端口进行通信。
第 3章 VHDL编程基础子程序有两种类型,即过程 (PROCEDURE)和函数
(FUNCTION)。过程的调用可通过其界面获得多个返回值,而函数只能返回一个值。在函数入口中,所有参数都是输入参数,
而过程有输入参数、输出参数和双向参数。过程一般被看作一种语句结构,而函数通常是表达式的一部分。过程可以单独存在,而函数通常作为语句的一部分调用。
VHDL子程序有一个非常有用的特性,就是具有可重载性的特点,即允许有许多重名的子程序,但这些子程序的参数类型及返回值数据类型是不同的。
第 3章 VHDL编程基础在实用中必须注意,综合后的子程序将映射于目标芯片中的一个相应的电路模块,且每一次调用都将在硬件结构中产生具有相同结构的不同的模块,这一点与在普通的软件中调用子程序有很大的不同。因此,在面向 VHDL的实用中,要密切关注和严格控制子程序的调用次数,每调用一次子程序都意味着增加了一个硬件电路模块。
第 3章 VHDL编程基础
3.6.1 函数 (FUNCTION)
在 VHDL中有多种函数形式,如在库中现成的具有专用功能的预定义函数和用于不同目的的用户自定义函数。函数的语言表达格式如下:
FUNCTION 函数名 (参数表 ) RETURN 数据类型; --函数首
FUNCTION 函数名 (参数表 ) RETURN 数据类型 IS --函数体开始
[说明部分 ];
BEGIN
顺序语句;
END FUNCTION 函数名; --函数体结束一般地,函数定义由两部分组成,即函数首和函数体。
第 3章 VHDL编程基础
1.函数首函数首是由函数名、参数表和返回值的数据类型三部分组成的。函数首的名称即为函数的名称,需放在关键词
FUNCTION之后,它可以是普通的标识符,也可以是运算符 (这时必须加上双引号 )。函数的参数表是用来定义输入值的,它可以是信号或常数,参数名需放在关键词 CONSTANT或 SIGNAL
之后,若没有特别说明,则参数被默认为常数。如果要将一个已编制好的函数并入程序包,函数首必须放在程序包的说明部分,而函数体需放在程序包的包体内。如果只是在一个结构体中定义并调用函数,则仅需函数体即可。由此可见,函数首的作用只是作为程序包的有关此函数的一个接口界面。
第 3章 VHDL编程基础
【 例 3.6.1】
FUNCTION FOUC1(A,B,C,REAL) RETURN REAL;
FUNCTION "*" (A,B,INTEGER) RETURN INTEGER; -
-注意函数名 *要用引号括住
FUNCTION AS2(SIGNAL IN1,IN2,REAL) RETURN
REAL; --注意信号参量的写法以上是三个不同的函数首,它们都放在某一程序包的说明部分。
第 3章 VHDL编程基础
2,函数体函数体包括对数据类型、常数、变量等的局部说明,以及用以完成规定算法或转换的顺序语句,并以关键词 END
FUNCTION 以及函数名结尾。一旦函数被调用,就将执行这部分语句。
第 3章 VHDL编程基础
【 例 3.6.2】
ENTITY FUNC IS
PORT ( A,IN BIT_VECTOR(0 TO 2);
M,OUT BUT_VECTOR (0 TO 2));
END ENTITY FUNC;
ARCHITECTURE ART OF FUNC IS
FUNCTION SAM(X,Y,Z,BIT)RETURN BIT IS
--定义函数 SAM,该函数无函数首
BEGIN
RETURN (X AND Y) OR Y;
END FUNCTION SAM;
第 3章 VHDL编程基础
BEGIN
PROCESS(A)
BEGIN
M(0)<=SAM (A(0),A(1),A(2));
--当 A的 3个位输入元素 A(0),A(1)和 A(2)中的
M(1)<=SAM (A(2),A(0),A(1));
--任何一位有变化时,将启动对函数 SAM的调用,
M(2)<=SAM (A(1),A(2),A(0));
--并将函数的返回值赋给 M输出
END PROCESS;
END ARCHITECTURE ART;
第 3章 VHDL编程基础
3.6.2 重载函数 (OVERLOADED FUNCTION)
VHDL允许以相同的函数名定义函数,即重载函数。但这时要求函数中定义的操作数具有不同的数据类型,以便调用时用以分辨不同功能的同名函数。在具有不同数据类型操作数构成的同名函数中,以运算符重载式函数最为常用。这种函数为不同数据类型间的运算带来极大的方便,例 3.6.3中以加号,+”
为函数名的函数即为运算符重载函数。 VHDL中预定义的操作符如,+”、,AND”、,MOD”、,>”等运算符均可以被重载,
以赋予新的数据类型操作功能,也就是说,通过重新定义运算符的方式,允许被重载的运算符能够对新的数据类型进行操作,
或者允许不同的数据类型之间用此运算符进行运算。
第 3章 VHDL编程基础例 3.6.3给出了一个 Synopsys公司的程序包
STD_LOGIC_UNSIGNED中的部分函数结构。示例没有把全部内容列出。在程序包 STD_LOGIC_UNSIGNED的说明部分只列出了四个函数的函数首。在程序包体部分只列出了对应的部分内容,程序包体部分的 UNSIGNED()函数是从
IEEE.STD_LOGIC_ARITH库中调用的,在程序包体中的最大整型数检出函数 MAXIUM只有函数体,没有函数首,这是因为它只在程序包体内调用。
第 3章 VHDL编程基础
【 例 3.6.3】
LIBRARY IEEE; --程序包首
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE STD_LOGIC_ARITH.ALL;
PACKAGE STD_LOGIC_UNSIGNED IS
FUNCTION,+”(L,STD_LOGIC_VECTOR; R,INTEGER)
RETURN STD_LOGIC_VECTOR;
FUNCTION,+”(L,INTEGER; R,STD_LOGIC_VECTOR)
RETURN STD_LOGIC_VECTOR;
FUNCTION,+”(L,STD_LOGIC_VECTOR; R,STD_LOGIC)
RETURN STD_LOGIC_VECTOR;
第 3章 VHDL编程基础
FUNCTION SHR(ARG,STD_LOGIC_VECTOR;
COUNT,STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;

END STD_LOGIC_UNSIGNED;
LIBRARY IEEE; --程序包体
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
PACKAGE BODY STD_LOGIC_UNSIGNED IS
FUNCTION MAXIMUM(L,R,INTEGER) RETURN INTEGER IS
BEGIN
IF L>R THEN
RETURN L;
第 3章 VHDL编程基础
ELSE
RETURN R;
END IF;
END;
FUNCTION,+”(L,STD_LOGIC_VECTOR; R,INTEGER)
RETURN STD_LOGIC_VECTOR IS
VARIABLE RESULT,STD_LOGIC_VECTOR(L'RANGE);
BEGIN
RESULT,= UNSIGNED(L)+R;
RETURN STD_LOGIC_VECTOR(RESULT);
END;

END STD_LOGIC_UNSIGNED;
第 3章 VHDL编程基础通过此例,不但可以从中看到在程序包中完整的函数置位形式,而且还将注意到,在函数首的三个函数名都是同名的,
即都是以加法运算符,+”作为函数名。以这种方式定义函数即所谓运算符重载。对运算符重载 (即对运算符重新定义 )的函数称重载函数。
实用中,如果已用,USE”语句打开了程序包
STD_LOGIC_UNSIGNED,这时,如果设计实体中有一个
STD_LOGIC_VECTOR位矢和一个整数相加,程序就会自动调用第一个函数,并返回位矢类型的值。若是一个位矢与
STD_LOGIC数据类型的数相加,则调用第三个函数,并以位矢类型的值返回。
第 3章 VHDL编程基础
【 例 3.6.4】 重载函数使用实例 (4位二进制加法计数器 )。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL; -- 注意此程序包的功能!
ENTITY CNT4 IS
PORT( CLK,IN STD_LOGIC;
Q,BUFFER STD_LOGIC_VECTOR(3 DOWNTO 0));
END CNT4;
ARCHITECTURE ONE OF CNT4 IS
BEGIN
PROCESS(CLK
第 3章 VHDL编程基础
BEGIN
IF CLK'EVENT AND CLK=?1?THEN
IF Q=15 THEN -- Q两边的数据类型不一致,程序自动调用了重载函数
Q<=“0000”;
ELSE
Q<=Q+1; --这里,程序自动调用了加号,+”的重载函数
END IF;
END IF;
END PROCESS;
END ARCHITECTURE ONE;
第 3章 VHDL编程基础
3.6.3 过程 (PROCEDURE)
过程的语句格式是:
PROCEDURE 过程名 (参数表 ); --过程首
PROCEDURE 过程名 (参数表 ) IS --过程体开始
[说明部分 ];
BEGIN
顺序语句;
END PROCEDURE 过程名; --过程体结束过程由过程首和过程体两部分组成,过程首不是必须的,
过程体可以独立存在和使用。
第 3章 VHDL编程基础
1.过程首过程首由过程名和参数表组成。参数表用于对常数、变量和信号三类数据对象目标作出说明,并用关键词 IN,OUT和
INOUT定义这些参数的工作模式,即信息的流向。以下是三个过程首的定义示例。
第 3章 VHDL编程基础
【 例 3.6.5】
PROCEDURE PRO1(VARIABLE A,B,INOUT REAL);
PROCEDURE PRO2 (CONSTANT A1,IN INTEGER;
VARIABLE B1,OUT INTEGER);
PROCEDURE PRO3 (SIGNAL SIG,INOUT BIT);
注意:一般地,可在参量表中定义三种流向模式,即 IN、
OUT和 INOUT。如果只定义了 IN模式而未定义目标参量类型,
则默认为常量;若只定义了 INOUT或 OUT,则默认目标参量类型是变量。
第 3章 VHDL编程基础
2.过程体过程体是由顺序语句组成的,过程的调用即启动了对过程体的顺序语句的执行。过程体中的说明部分只是局部的,其中的各种定义只能适用于过程体内部。过程体的顺序语句部分可以包含任何顺序执行的语句,包括 WAIT语句。但如果一个过程是在进程中调用的,且这个进程已列出了敏感参量表,则不能在此过程中使用 WAIT语句。
第 3章 VHDL编程基础根据调用环境的不同,过程调用有两种方式,即顺序语句方式和并行语句方式。在一般的顺序语句自然执行过程中,一个过程被执行,则属于顺序语句方式;当某个过程处于并行语句环境中时,其过程体中定义的任一 IN或 INOUT的目标参量发生改变时,将启动过程的调用,这时的调用是属于并行语句方式的。过程与函数一样可以重复调用或嵌套式调用。综合器一般不支持含有 WAIT语句的过程。以下是两个过程体的使用示例。
第 3章 VHDL编程基础
【 例 3.6.6】
PROCEDURE PRG1(VARIABLE VALUE,INOUT
BIT_VECTOR(0 TO 7)) IS
BEGIN
CASE VALUE IS
WHEN“0000” => VALUE:,0101”;
WHEN“0101” => VALUE:,0000”;
WHEN OTHERS => VALUE:,1111”;
END CASE;
END PROCEDURE PRG1;
这个过程对具有双向模式变量的值 VALUE作了一个数据转换运算。
第 3章 VHDL编程基础
【 例 3.6.7】
PROCEDURE COMP(A,R,IN REAL;
M,IN INTEGER;
V1,V2,OUT REAL) IS
VARIABLE CNT,INTEGER;
BEGIN
V1,=1.6*A; --赋初始值
V2,=1.0; --赋初始值
Q1,FOR CNT IN 1 TO M LOOP
V2,= V2*V1;
第 3章 VHDL编程基础
EXIT Q1 WHEN V2>V1; --当 V2>V1,跳出循环 LOOP
END LOOP Q1;
ASSERT (V2<V1);
REPORT "OUT OF RANGE" --输出错误报告
SEVERITY ERROR;
END PROCEDURE COMP;
第 3章 VHDL编程基础在以上过程 COMP的参量表中,定义 A和 R为输入模式,数据类型为实数; M为输入模式,数据类型为整数。这三个参量都没有以显式定义它们的目标参量类型,显然它们的默认类型都是常数。由于 V2,V1定义为输入模式的实数,因此默认类型是变量。在过程 COMP的 LOOP语句中,对 V2进行循环计算直到 V2大于 R,EXIT语句中断运算,并由 REPORT语句给出错误报告。
第 3章 VHDL编程基础
3.6.4 重载过程 (OVERLOADED PROCEDURE)
两个或两个以上有相同的过程名和互不相同的参数数量及数据类型的过程称为重载过程。对于重载过程,也是靠参量类型来辨别究竟调用哪一个过程。
第 3章 VHDL编程基础
【 例 3.6.8】
PROCEDURE CAL(V1,V2,IN REAL;
SIGNAL OUT1,INOUTINTEGER);
PROCEDURE CAL(V1,V2,IN IN TEGER;
SIGNAL OUT1,INOUT REAL);

CAL(20.15,1.42,SIGN1);
--调用第一个重载过程 CAL,SIGN1为 INOUT式的整数信号
CAL(23,320,SIGN2);
--调用第二个重载过程 CAL,SIGN1为 INOUT式的实数信号

第 3章 VHDL编程基础如前所述,在过程结构中的语句是顺序执行的,调用者在调用过程前应先将初始值传递给过程的输入参数。一旦调用,即启动过程语句,按顺序自上而下执行过程中的语句,
执行结束后,将输出值返回到调用者的,OUT”和,INOUT”
所定义的变量或信号中。
第 3章 VHDL编程基础
3.7 库、程序包及其他
3.7.1 库 (LIBRARY)
在利用 VHDL进行工程设计中,为了提高设计效率以及使设计遵循某些统一的语言标准或数据格式,有必要将一些有用的信息汇集在一个或几个库中以供调用。这些信息可以是预先定义好的数据类型、子程序等设计单元的集合体 (程序包 ),或预先设计好的各种设计实体 (元件库程序包 )。因此,可以把库看成是一种用来存储预先完成的程序包和数据集合体的仓库。
第 3章 VHDL编程基础库 (LIBRARY)的语句格式如下:
LIBRARY 库名;
这一语句即相当于为其后的设计实体打开了以此库名命名的库,以便设计实体可以利用其中的程序包。如语句
,LIBRARY IEEE;”表示打开 IEEE库。
第 3章 VHDL编程基础
1.库的种类
VHDL程序设计中常用的库有 4种。
1) IEEE库
IEEE库是 VHDL设计中最为常见的库,它包含有 IEEE标准的程序包和其他一些支持工业标准的程序包。 IEEE库中的标准程序包主要包括 STD_LOGIC_1164,NUMERIC_BIT和
NUMERIC_STD等程序包。其中的 STD_LOGIC_1164是最重要的最常用的程序包,大部分基于数字系统设计的程序包都是以此程序包中设定的标准为基础的。
第 3章 VHDL编程基础此外,还有一些程序包虽非 IEEE标准,但由于其已成事实上的工业标准,也都并入了 IEEE库。这些程序包中,最常用的是 Synopsys 公司的 STD_LOGIC_ARITH、
STD_LOGIC_SIGNED和 STD_LOGIC_UNSIGNED程序包。目前流行于我国的大多数 EDA工具都支持 Synopsys公司程序包。
一般基于大规模可编程逻辑器件的数字系统设计,IEEE库中的
4个程序包 STD_LOGIC_1164,STD_LOGIC_ARITH、
STD_LOGIC_SIGNED和 STD_LOGIC_UNSIGNED已经足够使用。另外需要注意的是,在 IEEE库中符合 IEEE标准的程序包并非符合 VHDL语言标准,如 STD_LOGIC_1164程序包。因此在使用 VHDL设计实体的前面必须以显式表达出来。
第 3章 VHDL编程基础
2) STD库
VHDL语言标准定义了两个标准程序包,即 STANDARD和
TEXTIO程序包,它们都被收入在 STD库中。只要在 VHDL应用环境中,可随时调用这两个程序包中的所有内容,即在编译和综合过程中,VHDL的每一项设计都自动地将其包含进去了。
由于 STD库符合 VHDL语言标准,在应用中不必如 IEEE库那样以显式表达出来。
第 3章 VHDL编程基础
3) WORK库
WORK库是用户的 VHDL设计的现行工作库,用于存放用户设计和定义的一些设计单元和程序包。因此自动满足 VHDL
语言标准,在实际调用中,不必以显式预先说明。
第 3章 VHDL编程基础
4) VITAL库使用 VITAL库,可以提高 VHDL门级时序模拟的精度,因而只在 VHDL仿真器中使用。库中包含时序程序包
VITAL_TIMING和 VITAL_ PRIMITIVES。 VITAL程序包已经成为 IEEE标准,在当前的 VHDL仿真器的库中,VITAL库中的程序包都已经并到 IEEE库中。实际上,由于各 FPGA/CPLD生产厂商的适配工具 (如 ispEXPERT Compiler)都能为各自的芯片生成带时序信息的 VHDL门级网表,用 VHDL仿真器仿真该网表可以得到非常精确的时序仿真结果。因此,基于实用的观点,在
FPGA/CPLD设计开发过程中,一般并不需要 VITAL库中的程序包。
第 3章 VHDL编程基础除了以上提到的库外,EDA工具开发商为了便于
FPGA/CPLD开发设计上的方便,都有自己的扩展库和相应的程序包,如 DATAIO公司的 GENERICS库,DATAIO库等,以及上面提到的 Synopsys 公司的一些库。
在 VHDL设计中,有的 EDA工具将一些程序包和设计单元放在一个目录下,而将此目录名,如,WORK”,作为库名,如
Synplicity公司的 Synplify。有的 EDA工具是通过配置语句结构来指定库和库中的程序包,这时的配置即成为一个设计实体中最顶层的设计单元。
此外,用户还可以自己定义一些库,将自己的设计内容或通过交流获得的程序包设计实体并入这些库中。
第 3章 VHDL编程基础
2.库的用法在 VHDL语言中,库的说明语句总是放在实体单元前面,而且库语言一般必须与 USE语言同用。库语言关键词 LIBRARY,
指明所使用的库名。 USE语句指明库中的程序包。一旦说明了库和程序包,整个设计实体都可进入访问或调用,但其作用范围仅限于所说明的设计实体。 VHDL要求一项含有多个设计实体的更大的系统,每一个设计实体都必须有自己完整的库说明语句和 USE语句。
第 3章 VHDL编程基础
USE语句的使用将使所说明的程序包对本设计实体部分全部开放,即是可视的。 USE语句的使用有两种常用格式:
USE 库名,程序包名,项目名;
USE 库名,程序包名,ALL;
第一语句格式的作用是,向本设计实体开放指定库中的特定程序包内所选定的项目。第二语句格式的作用是,向本设计实体开放指定库中的特定程序包内所有的内容。
第 3章 VHDL编程基础例如:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
以上的三条语句表示打开 IEEE库,再打开此库中的
STD_LOGIC_1164程序包和,STD_LOGIC_UNSIGNED.ALL程序包的所有内容。
第 3章 VHDL编程基础
【 例 3.7.1】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.STD_ULOGIC;
USE IEEE.STD_LOGIC_1164.RISING_EDGE;
此例中向当前设计实体开放了 STD_LOGIC_1164程序包中的 RISING_EDGE函数。但由于此函数需要用到数据类型
STD_ULOGIC,所以在上一条 USE语句中开放了同一程序包中的这一数据类型。
第 3章 VHDL编程基础
3.7.2 程序包 (PACKAGE)
为了使已定义的常数、数据类型、元件调用说明以及子程序能被更多的 VHDL设计实体方便地访问和共享,可以将它们收集在一个 VHDL程序包中。多个程序包可以并入一个 VHDL
库中,使之适用于更一般的访问和调用范围。这一点对于大系统开发,多个或多组开发人员并行工作显得尤为重要。
程序包的内容主要由如下四种基本结构组成,因此一个程序包中至少应包含以下结构中的一种。
第 3章 VHDL编程基础
● 常数说明:主要用于预定义系统的宽度,如数据总线通道的宽度。
● 数据类型说明:主要用于说明在整个设计中通用的数据类型,例如通用的地址总线数据类型定义等。
● 元件定义:主要规定在 VHDL设计中参与元件例化的文件 (已完成的设计实体 )对外的接口界面。
● 子程序说明:用于说明在设计中任一处可调用的子程序。
第 3章 VHDL编程基础定义程序包的一般语句结构如下:
--程序包首
PACKAGE 程序包名 IS --程序包首开始程序包首说明部分
END 程序包名; --程序包首结束
--程序包体
PACKAGE BODY 程序包名 IS --程序包体开始程序包体说明部分以及包体内容第 3章 VHDL编程基础
1.程序包首程序包首的说明部分可收集多个不同的 VHDL设计所需的公共信息,其中包括数据类型说明、信号说明、子程序说明及元件说明等。
程序包结构中,程序包体并非是必须的,程序包首可以独立定义和使用。
第 3章 VHDL编程基础
【 例 3.7.2】
PACKAGE PAC1 IS --程序包首开始
TYPE BYTE IS RANGE 0 TO 255; -- 定义数据类型 BYTE
SUBTYPE NIBBLE IS BYTE RANGE 0 TO 15; --定义子类型 NIBBLE
CONSTANT BYTE_FF,BYTE,=255; --定义常数 BYTE_FF
SIGNAL ADDEND,NIBBLE; --定义信号 ADDEND
COMPONENT BYTE_ADDER --定义元件
PORT(A,B,IN BYTE;
第 3章 VHDL编程基础
END COMPONENT ;
FUNCTION MY_FUNCTION(A,IN BYTE ) RETURN BYTE;
--定义函数
END PAC1; -- 程序包首结束如果要使用这个程序包中的所有定义,可用 USE语句访问此程序包:
LIBRARY WORK; --此句可省去
USE WORK.PAC1.ALL;
ENTITY…
ARCHITECTURE…

第 3章 VHDL编程基础
【 例 3.7.3】 在现行 WORK库中定义程序包并立即使用的示例。
PACKAGE SEVEN IS --定义程序包
SUBTYPE SEGMENTS IS BIT_VECTOR(0 TO 6);
TYPE BCD IS RANGE 0 TO 9;
END SEVEN;
USE WORK.SEVEN.ALL; --打开程序包,以便后面使用
ENTITY DECODER IS
PORT(INPUT,BCD; DRIVE,OUT SEGMENTS);
END DECODER;
ARCHITECTURE ART OF DECODER IS
BEGIN
WITH INPUT SELECT
DRIVE<=B“1111110” WHEN 0,
B“0110000” WHEN 1,
第 3章 VHDL编程基础
B“1101101” WHEN 2,
B“1111001” WHEN 3,
B“0110011” WHEN 4,
B“1011011” WHEN 5,
B“1011111” WHEN 6,
B“1110000” WHEN 7,
B“1111111” WHEN 8,
B“1111011” WHEN 9,
B“0000000” WHEN OTHERS;
END ARCHITECTURE ART;
第 3章 VHDL编程基础此例是一个 4位 BCD数向 7段译码显示码转换的 VHDL描述。
在程序包 SEVEN中定义了两个新的数据类型 SEGMENTS和
BCD。在 DECODER的实体描述中使用了这两个数据类型。
第 3章 VHDL编程基础
2,程序包体程序包体用于定义在程序包首中已定义的子程序的子程序体。程序包体说明部分的组成可以是 USE语句 (允许对其他程序包的调用 )、子程序定义、子程序体、数据类型说明、子类型说明和常数说明等。对于没有子程序说明的程序包体可以省去。
程序包常用来封装属于多个设计单元分享的信息,程序包定义的信号、变量不能在设计实体之间共享。
常用的预定义的程序包有 4种。
第 3章 VHDL编程基础
1) STD_LOGIC_1164程序包它是 IEEE库中最常用的程序包,是 IEEE的标准程序包。其中包含了一些数据类型、子类型和函数的定义,这些定义将
VHDL扩展为一个能描述多值逻辑 (即除具有,0”和,1”以外还有其他的逻辑量,如高阻态,Z”、不定态,X”等 )的硬件描述语言,很好地满足了实际数字系统的设计需求。该程序包中用得最多和最广的是定义了满足工业标准的两个数据类型
STD_LOGIC和 STD_LOGIC_VECTOR,它们非常适合于
FPGA/CPLD器件中多值逻辑设计结构。
第 3章 VHDL编程基础
2) STD_LOGIC_ARITH程序包它预先编译在 IEEE库中,是 Synopsys公司的程序包。此程序包在 STD_LOGIC_1164程序包的基础上扩展了三个数据类型
UNSIGNED,SIGNED和 SMALL_INT,并为其定义了相关的算术运算符和转换函数。
第 3章 VHDL编程基础
3) STD_LOGIC_UNSIGNED和 STD_LOGIC_SIGNED程序包这两个程序包都是 Synopsys公司的程序包,都预先编译在
IEEE库中。这些程序包重载了可用于 INTEGER型及 STD_LOGIC
和 STD_ LOGIC_VECTOR型混合运算的运算符,并定义了一个由
STD_LOGIC_VECTOR型到 INTEGER型的转换函数。这两个程序包的区别是,STD_LOGIC_SIGNED中定义的运算符考虑到了符号,
是有符号数的运算,而 STD_LOGIC_UNSIGNED则正好相反。
程序包 STD_LOGIC_ARITH,STD_LOGIC_UNSIGNED和
STD_LOGIC_SIGNED虽然未成为 IEEE标准,但已经成为事实上的工业标准,绝大多数的 VHDL综合器和 VHDL仿真器都支持它们。
第 3章 VHDL编程基础
4) STANDARD和 TEXTIO程序包这两个程序包是 STD库中的预编译程序包。 STANDARD程序包中定义了许多基本的数据类型、子类型和函数。它是 VHDL
标准程序包,实际应用中已隐性地打开了,故不必再用 USE语句另作声明。 TEXTIO程序包定义了支持文本文件操作的许多类型和子程序。在使用本程序包之前,需加语句 USE
STD.TEXTIO.ALL 。
TEXTIO程序包主要供仿真器使用。可以用文本编辑器建立一个数据文件,文件中包含仿真时需要的数据,然后仿真时用
TEXTIO程序包中的子程序存取这些数据。综合器中,此程序包被忽略。
第 3章 VHDL编程基础
3.7.3 配置 (CONFIGURATION)
配置可以把特定的结构体指定给一个确定的实体。通常在大而复杂的 VHDL工程设计中,配置语句可以为实体指定或配置一个结构体。如可利用配置使仿真器为同一实体配置不同的结构体以使设计者比较不同结构体的仿真差别,或者为例化的各元件实体配置指定的结构体,从而形成一个所希望的例化元件层次构成的设计实体。
第 3章 VHDL编程基础配置也是 VHDL设计实体中的一个基本单元,在综合或仿真中,可以利用配置语句为确定整个设计提供许多有用信息。
例如对以元件例化的层次方式构成的 VHDL设计实体,就可把配置语句的设置看成是一个元件表,以配置语句指定在顶层设计中的每一元件与一特定结构体相衔接,或赋予特定属性。配置语句还能用于对元件的端口连接进行重新安排等。
第 3章 VHDL编程基础
VHDL综合器允许将配置规定为一个设计实体中的最高层设计单元,但只支持对最顶层的实体进行配置。
配置语句的一般格式如下:
CONFIGURATION 配置名 OF 实体名 IS
配置说明
END配置名;
第 3章 VHDL编程基础配置主要为顶层设计实体指定结构体,或为参与例化的元件实体指定所希望的结构体,以层次方式来对元件例化作结构配置。如前所述,每个实体可以拥有多个不同的结构体,而每个结构体的地位是相同的,在这种情况下,可以利用配置说明为这个实体指定一个结构体。例 3.7.4是一个配置的简单方式应用,即在一个描述与非门 NAND的设计实体中会有两个以不同的逻辑描述方式构成的结构体,用配置语句来为特定的结构体需求作配置指定。
第 3章 VHDL编程基础
【 例 3.7.4】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY NAND IS
PORT(A,IN STD_LOGIC;
B,IN STD_LOGIC;
C,OUT STD_LOGIC);
END ENTITY NAND;
ARCHITECTURE ART1 OF NAND IS
BEGIN
C<=NOT (A AND B );
END ARCHITECTURE ART1;
ARCHITECTURE ART2 OF NAND IS
第 3章 VHDL编程基础
BEGIN
C<=?1? WHEN (A=?0?) AND(B=?0?) ELSE
1? WHEN (A=?0?) AND(B=?1?) ELSE
1? WHEN (A=?1?) AND(B=?0?) ELSE
0? WHEN (A=?1?) AND(B=?1?) ELSE
0?;
END ARCHITECTURE ART2;
CONFIGURATION SECOND OF NAND IS
FOR ART2
END FOR;
END SECOND;
CONFIGURATION FIRST OF NAND IS
FOR ART1
END FOR;
END FIRST;
第 3章 VHDL编程基础在本例中若指定配置名为 SECOND,则为实体 NAND配置的结构体为 ART2;若指定配置名为 FIRST,则为实体 NAND配置的结构体为 ART1。这两种结构的描述方式是不同的,但是有相同的逻辑功能。
如果将例 3.7.4中的配置语言全部除去,则可以用此具有两个结构体的实体 NAND构成另一个更高层次设计实体中的元件,
并由此设计实体中的配置语句来指定元件实体 NAND使用哪一个结构体。例 3.7.5就是利用例 3.7.4的文件 NAND实现 RS触发器设计的。最后,利用配置语句指定元件实体 NAND中的第二个结构 ART2来构成 NAND的结构体。
第 3章 VHDL编程基础
【 例 3.7.5】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY RS1 IS
PORT ( R,IN STD_LOGIC;
S,IN STD_LOGIC;
Q,OUT STD_LOGIC;
QF,OUT STD_LOGIC);
END RS1;
ARCHITECTURE RSF OF RS1 IS
COMPONENT NAND
--这里假设与非门的设计实体已进入工作库 WORK
第 3章 VHDL编程基础
PORT (A,IN STD_ LOGIC;
B,IN STD_LOGIC;
C,OUT STD_LOGIC);
END COMPONENT;
BEGIN
U1,NAND PORT MAP (A=>S,B=>QF,C=>Q);
U2,NAND PORT MAP (A=>Q,B=>R,C=>QF);
END RSF;
CONFIGURATION SEL OF RS1 IS
FOR RSF
FOR U1,U2,NAND
USE ENTITY WORK.NAND(ART2);
END FOR;
END FOR;
END SEL;
第 3章 VHDL编程基础
3.8 VHDL描述风格
VHDL的结构体用于具体描述整个设计实体的逻辑功能。对于所希望的电路功能行为,可以在结构体中用不同的语句类型和描述方式来表达;对于相同的逻辑行为,可以有不同的语句表达方式。在 VHDL中,这些描述方式 (建模方法 )称为描述风格,
通常可归纳为三种:行为描述、数据流 (寄存器传输 )描述和结构描述。
在实际应用中,为了能兼顾整个设计的功能、资源、性能几方面的因素,通常混合使用这三种描述方式。
第 3章 VHDL编程基础
3.8.1 行为描述如果 VHDL的结构体只描述了所希望电路的功能或者说电路行为,而没有直接指明或涉及实现这些行为的硬件结构,则称为行为描述。行为描述只表示输入与输出间转换的行为,它不包含任何结构信息。行为描述主要使用函数、过程和进程语句,
以算法形式描述数据的变换和传送。这里所谓的硬件结构,是指具体硬件电路的连接结构、逻辑门的组成结构、元件或其他各种功能单元的层次结构等。
第 3章 VHDL编程基础
【 例 3.8.1】 带异步复位功能的 8位二进制加法计数器的行为描述。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY CONTER_UP IS
PORT(RESET,CLOCK,IN STD_LOGIC;
COUNTER,OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END CONTER_UP;
ARCHITECTURE ART OF CONTER_UP IS
SIGNAL CNT_FF,UNSIGED(7 DOWNTO 0);
第 3章 VHDL编程基础
BEGIN
PROCESS(CLOCK,RESET,CNT_FF)
BEGIN
IF RESET=?1?THEN
CNT_FF<=X“00";
ELSIF(CLOCK=?1?AND CLOCK'EVENT)THEN
CNT_FF<=CNT_FF+1;
END IF;
END PROCESS;
COUNTER<=STD_LOGIC_VECTOR(CNT_FF);
END ARCHITECTURE ART;
第 3章 VHDL编程基础
(1) 本例的程序中,不存在任何与硬件选择相关的语句,也不存在任何有关硬件内部连线方面的语句。整个程序中,从表面上看不出是否引入寄存器方面的信息,或是使用组合逻辑还是时序逻辑方面的信息,只是对所设计的电路系统的行为功能作了描述,不涉及任何具体器件方面的内容,这就是所谓的行为描述方式,或行为描述风格。程序中,最典型的行为描述语句就是其中的:
ELSIF(CLOCK=?1?AND CLOCK?EVENT)THEN
它对加法器计数时钟信号的触发要求作了明确而详细的描述,
对时钟信号特定的行为方式所能产生的信息后果作了准确的定位。这充分展现了 VHDL语言最为闪光之处。 VHDL的强大系统描述能力,正是基于这种强大的行为描述方式。
第 3章 VHDL编程基础
(2) VHDL的行为描述功能具有很大的优越性。在应用
VHDL系统设计时,行为描述方式是最重要的逻辑描述方式,
行为描述方式是 VHDL编程的核心,可以说,没有行为描述就没有 VHDL。
将 VHDL的行为描述语句转换成可综合的门级描述是 VHDL
综合器的任务,这是一项十分复杂的工作。不同的 VHDL综合器,其综合和优化效率是不尽一致的。优秀的 VHDL综合器对
VHDL设计的数字系统产品的工作性能和性价比都会有良好的影响。所以,对于产品开发或科研,对 VHDL综合器应作适当的选择。 Cadence,Synplicity,Synopsys和 Viewlogic 等著名
EDA公司的 VHDL综合器都具有上佳的表现。
第 3章 VHDL编程基础
3.8.2 数据流描述数据流描述,也称 RTL描述,它是以类似于寄存器传输级的方式描述数据的传输和变换,以规定设计中的各种寄存器形式为特征,然后在寄存器之间插入组合逻辑。这类寄存器或者显式地通过元件具体装配,或者通过推论作隐含的描述。数据流描述主要使用并行的信号赋值语句,既显式表示了该设计单元的行为,
又隐含了该设计单元的结构。
数据流的描述风格是建立在用并行信号赋值语句描述基础上的。当语句中任一输入信号的值发生改变时,赋值语句就被激活,
随着这种语句对电路行为的描述,大量的有关这种结构的信息也从这种逻辑描述中“流出”。认为数据是从一个设计中流出,从输入到输出的观点称为数据流风格。数据流描述方式能比较直观地表述底层逻辑行为。
第 3章 VHDL编程基础
【 例 3.8.2】 一位全加器的数据流描述。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY ADDER1B IS
PORT(A,B,CIN,IN BIT
SUM,COUT,OUT BIT);
END ADDER1B;
ARCHITECTURE ART OF ADDER1B IS
SUM<= A XOR B XOR CIN;
COUNT<=(A AND B)OR (A AND CIN) OR (B AND CIN);
END ARCHITECTURE ART;
第 3章 VHDL编程基础
3.8.3 结构描述所谓结构描述是描述该设计单元的硬件结构,即该硬件是如何构成的。其主要使用元件例化语句及配置语句来描述元件的类型及元件的互连关系。利用结构描述可以用不同类型的结构,来完成多层次的工程,即从简单的门到非常复杂的元件 (包括各种已完成的设计实体子模块 )来描述整个系统。元件间的连接是通过定义的端口界面来实现的,其风格最接近实际的硬件结构,即设计中的元件是互连的。
第 3章 VHDL编程基础结构描述就是表示元件之间的互连,这种描述允许互连元件的层次式安置,像网表本身的构建一样。结构描述建模步骤如下:
(1) 元件说明:描述局部接口。
(2) 元件例化:相对于其他元件放置元件。
(3) 元件配置:指定元件所用的设计实体。即对一个给定实体,如果有多个可用的结构体,则由配置决定模拟中所用的一个结构。
第 3章 VHDL编程基础元件的定义或使用声明以及元件例化是用 VHDL实现层次化、模块化设计的手段,与传统原理图设计输入方式相仿。
在综合时,VHDL综合器会根据相应的元件声明搜索与元件同名的实体,将此实体合并到生成的门级网表中。
第 3章 VHDL编程基础
【 例 3.8.3】
ARCHITECTURE STRUCTURE OF COUNTER3 IS
COMPONENT DFF
PORT(CLK,DATA,IN BIT; Q,OUT BIT);
END COMPONENT;
COMPONENT AND2
PORT(I1,I2,IN BIT; O,OUT BIT);
END COMPONENT;
COMPONENT OR2
PORT(I1,I2,IN BIT; O,OUT BIT);
END COMPONENT;
COMPONENT NAND2
第 3章 VHDL编程基础
PORT(I1,I2,IN BIT; O,OUT BIT);
END COMPONENT;
COMPONENT XNOR2
PORT(I1,I2,IN BIT; O,OUT BIT);
END COMPONENT;
COMPONENT INV
PORT(I,IN BIT; O,OUT BIT);
END COMPONENT;
SIGNAL N1,N2,N3,N4,N5,N6,N7,N8,N9,BIT;
BEGIN
第 3章 VHDL编程基础
U1,DFF PORT MAP(CLK,N1,N2);
U2,DFF PORT MAP(CLK,N5,N3);
U3,DFF PORT MAP(CLK,N9,N4);
U4,INV PORT MAP(N2,N1);
U5,OR2 PORT MAP(N3,N1,N6);
U6,NAND2 PORT MAP(N1,N3,N7);
U7,NAND2 PORT MAP(N6,N7,N5);
U8,XNOR2 PORT MAP(N8,N4,N9);
U9,NAND2 PORT MAP(N2,N3,N8);
COUNT(0)<=N2; COUNT(1)<=N3; COUNT(2)<=N4;
END STRUCTURE;
第 3章 VHDL编程基础利用结构描述方式,可以采用结构化、模块化设计思想,
将一个大的设计划分为许多小的模块,逐一设计调试完成,然后利用结构描述方法将它们组装起来,形成更为复杂的设计。
显然,在三种描述风格中,行为描述的抽象程度最高,最能体现 VHDL描述高层次结构和系统的能力。
第 3章 VHDL编程基础
3.9 基本逻辑电路设计
3.9.1 组合逻辑电路设计
1.基本门电路基本门电路用 VHDL语言来描述十分方便。为方便起见,在下面的两输入模块中,使用 VHDL中定义的逻辑运算符,同时实现一个与门、或门、与非门、或非门、异或门及反相器的逻辑。
第 3章 VHDL编程基础
【 例 3.9.1】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY GATE IS
PORT (A,B,IN STD_LOGIC;
YAND,YOR,YNAND,YNOR,YNOT,YXOR,OUT STD_LOGIC);
END GATE;
ARCHITECTURE ART OF GATE IS
BEGIN
第 3章 VHDL编程基础
YAND<=A AND B; --与门输出
YOR<=A OR B; --或门输出
YNAND<=A NAND B; --与非门输出
YNOR<=A NOR B; --或非门输出
YNOT<=A NOT B; --反相器输出
YXOR<=A XOR B; --异或门输出
END ART;
第 3章 VHDL编程基础
2,3-8译码器下面我们分别以 4种方法描述一个 3-8译码器。
【 例 3.9.2】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED_ALL;
ENTITY DECODER IS
PORT(INP,IN STD_LOGIC_VECTOR(2 DOWNTO 0);
OUTP,OUT BIT_VECTOR (7 DOWNTO 0));
END DECODER;
第 3章 VHDL编程基础方法 1,使用 SLL逻辑运算符
ARCHITECTURE ART1 OF DECODER IS
BEGIN
OUTP<= "00000001" SLL (CONV_INTEGER(INP));
END ART1;
第 3章 VHDL编程基础方法 2,使用 PROCESS语句
ARCHITECTURE ART2 OF DECODER IS
BEGIN
PROCESS(INP)
BEGIN
OUTP<=(OTHERS=>?1?)
OUTP(COVN_INTEGER(INP))<=?1?
END PROCESS;
END ART2;
第 3章 VHDL编程基础方法 3,使用 WHEN ELSE 语句
ARCHITECTURE ART3 OF DECODER IS
BEGIN
OUTP(0)<=?1? WHEN INP="000" ELSE "0";
OUTP(1)<=?1? WHEN INP="001" ELSE "0";
OUTP(2)<=?1? WHEN INP="010" ELSE "0";
OUTP(3)<=?1? WHEN INP="011" ELSE "0";
OUTP(4)<=?1? WHEN INP="100" ELSE "0";
OUTP(5)<=?1? WHEN INP="101" ELSE "0";
OUTP(6)<=?1? WHEN INP="110" ELSE "0";
OUTP(7)<=?1? WHEN INP="111" ELSE "0";
END ART3;
第 3章 VHDL编程基础方法 4:使用 CASE_WHEN 语句
ARCHITECTURE ART4 OF DECODER IS
BEGIN
CASE INP IS
WHEN "000"=>OUTP<= "00000001";
WHEN "001"=>OUTP<= "00000010";
WHEN "010"=>OUTP<= "00000100";
WHEN "011"=>OUTP<= "00001000";
WHEN "100"=>OUTP<= "00010000";
WHEN "101"=>OUTP<= "00100000";
WHEN "110"=>OUTP<= "01000000";
WHEN "111"=>OUTP<= "10000000";
WHEN OTHERS=>OUTP<= "XXXXXXXX";
END CASE;
END ART4;
第 3章 VHDL编程基础
3,8-3线优先编码器下面我们用三种方法设计 8-3线优先编码器。
8-3线优先编码器,输入信号为 A,B,C,D,E,F,G和
H,输出信号为 OUT0,OUT1和 OUT2。输入信号中 A的优先级别最低,依次类推,H的优先级别最高。
第 3章 VHDL编程基础
【 例 3.9.3】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY ENCODER IS
PORT (A,B,C,D,E,F,G,H,IN STD_LOGIC:
OUT0,OUT1,OUT2,OUT STD_LOGIC);
END ENCODER;
第 3章 VHDL编程基础方法 1,使用条件赋值语句
ARCHITECTURE ART1 OF ENCODER IS
SIGNAL OUTS,STD_LOGIC_VECTOR(2 DOWNTO 0);
BEGIN
OUTS (2 DOWNTO 0)<= "111" WHEN H=?1? ELSE
"110" WHEN G=?1? ELSE
"101" WHEN F=?1? ELSE
"100" WHEN E=?1? ELSE
"011" WHEN D=?1? ELSE
"010" WHEN C=?1? ELSE
"001" WHEN B=?1? ELSE
"000" WHEN A=?1? ELSE
"XXX";
第 3章 VHDL编程基础
OUT0<=OUTS(0);
OUT1<=OUTS(1);
OUT2<=OUTS(2);
END ART1;
第 3章 VHDL编程基础方法 2:使用 LOOP语句
ARCHITECTURE ART2 OF ENCODER IS
BEGIN
PROCESS(A,B,C,D,E,F,G,H)
VARIABLE INPUTS,STD_LOGIC_VECTOR(7 DOWNTO 0);
VARIABLE I,INTEGER;
BEGIN
INPUT,=(H,G,F,E,D,C,B,A);
I,=7;
WHILE I>=0 AND INPUTS(I)/=?1? LOOP
I,=I-1;
END LOOP;
(OUT2,OUT1,OUT0)<=CONV_STD_LOGIC_VECTOR(I,3);
END PROCESS;
END ART2;
第 3章 VHDL编程基础方法 3,使用 IF语句
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY ENCODER IS
PORT(IN1,IN STD_LOGIC_VECTOR(7 DOWNTO 0);
OUT1,OUT STD_LOGIC_VECTOR(2 DOWNTO 0));
END ENCODER;
ARCHITECTURE ART3 OF ENCODER IS
BEGIN
PROCESS(INT1)
BEGIN
第 3章 VHDL编程基础
IF IN1(7)=?1? THEN OUT1<="111";
ELSIF IN1(6)=?1? THEN OUT1<="110";
ELSIF IN1(5)=?1? THEN OUT1<="101";
ELSIF IN1(4)=?1? THEN OUT1<="100";
ELSIF IN1(3)=?1? THEN OUT1<="011";
ELSIF IN1(2)=?1? THEN OUT1<="010";
ELSIF IN1(1)=?1? THEN OUT1<="001";
ELSIF IN1(0)=?1? THEN OUT1<="000";
ELSE OUT1<="XXX";
END IF ;
END PROCESS;
END ART3;
第 3章 VHDL编程基础
4,8位比较器比较器可以比较两个二进制是否相等,下面是一个 8位比较器的 VHDL描述。有两个 8位二进制数,分别是 A和 B,
输出为 EQ,当 A=B时,EQ=1,否则 EQ=0。
第 3章 VHDL编程基础
【 例 3.9.4】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_VECTOR(7 DOWNTO 0);
ENTITY COMPARE IS
PORT (A,B,IN STD_LOGIC_VECTOR(7 DOWNTO 0);
EQ,OUT STD_LOGIC);
END COMPARE;
ARCHITECTURE ART OF COMPARE IS
BEGIN
EQ <=?1? WHEN A=B ELSE?0?;
END ART;
第 3章 VHDL编程基础
5.四选一选择器选择器常用于信号的切换,四选一选择器可以用于四路信号的切换。四选一选择器有 4个信号输入端 INP(0)~ INP(3),两个信号选择端 A和 B 和一个信号输出端 Y。当 A,B输入不同的选择信号时,就可以使 INP(0)~ INP(3)中某个相应的输入信号与输出端 Y接通。
第 3章 VHDL编程基础
【 例 3.9.5】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY MUX41 IS
PORT (INP,IN STD_LOGIC_VECTOR(3 DOWNTO 0);
A,B,IN STD_LOGIC;
Y,OUT STD_LOGIC);
END MUX41;
ARCHITECTURE ART OF MUX41 IS
SIGNAL SEL,STD_LOGIC_VECTOR(1 DOWNTO 0);
第 3章 VHDL编程基础
BEGIN
SEL<=B&A;
PROCESS(INP,SEC)
BEGIN
IF(SEL="00")THEN Y<=INP(0);
ELSIF (SEL="01")THEN Y<=INP(1);
ELSIF (SEL="11")THEN Y<=INP(2);
ELSE Y<=INP(3);
END IF;
END PROCESS;
END ART;
第 3章 VHDL编程基础
6.算术运算下面的程序对输入操作数 A,B作加、减、乘、除运算。
【 例 3.9.6】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY ARITHMETIC IS
PORT (A,B,IN STD_LOGIC_VECTOR(3 DOWNTO 0);
Q1,OUT STD_LOGIC_VECTOR(4 DOWNTO 0);
Q2,Q3,OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
Q4,OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
第 3章 VHDL编程基础
END ARITHMETIC;
ARCHITECTURE ART OF ARITHMETIC IS
BEGIN
PROCESS(A,B)
BEGIN
Q1<=(?0?&A)+('0'&B); --ADDITION
Q2<=A-B; --SUBTRACTION
Q3<=A/B; --DIVISION
Q4<=A*B; --MULTIPLICATION
END PROCESS;
END ART;
第 3章 VHDL编程基础
7.三态门及总线缓冲器三态门和总线缓冲器是驱动电路经常用到的器件。
1) 三态门电路
【 例 3.9.7】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY TRISTATE IS
PORT (EN,DIN,IN STD_LOGIC;
DOUT,OUT STD_LOGIC);
END TRISTATE;
ARCHITECTURE ART OF TRISTATE IS
BEGIN
第 3章 VHDL编程基础
PROCESS(EN,DIN)
BEGIN
IF EN=?1? THEN
DOUT<=DIN;
ELSE
DOUT<='Z';
END IF ;
END PROCESS;
END ART;
第 3章 VHDL编程基础
2) 单向总线驱动器在微型计算机的总线驱动中经常要用单向总线缓冲器,它通常由多个三态门组成,用来驱动地址总线和控制总线。一个 8
位的单向总线缓冲器如图 3.25所示。
图 3.25 单向总线缓冲器
D O U T [ 7,,0 ]
EN
D I N [ 7,,0 ]
EN
T R I _ B U F 8
D O U T [ 7,,0 ]
D I N [ 7,,0 ]
第 3章 VHDL编程基础
【 例 3.9.8】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY TR1_BUF8 IS
PORT (DIN,IN STD_LOGIC_VECTOR(7 DOWNTO 0);
EN,IN STD_LOGIC;
DOUNT,OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
ARCHITECTURE ART OF TR1_BUF8 IS
BEGIN
PROCESS(EN,DIN)
IF(EN=?1?)THEN
DOUT<=DIN;
ELSE
DOUT<="ZZZZZZZZ";
END IF;
END PROCESS;
END ART;
第 3章 VHDL编程基础
3) 双向总线缓冲器双向总线缓冲器用于数据总线的驱动和缓冲,典型的双向总线缓冲器如图 3.26所示。图中的双向总线缓冲器有两个数据输入输出端 A和 B,一个方向控制端 DIR和一个选通端 EN。
EN=0时双向缓冲器选通,若 DIR=0,则 A=B,反之则 B=A。
图 3.26 双向总线缓冲器
B [ 7,,0 ]
EN
D I R
A [ 7,,0 ]
B [ 7,,0 ]
A [ 7,,0 ]
D I R
EN
B I D I R
第 3章 VHDL编程基础
【 例 3.9.9】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY BIDIR IS
PORT(A,B,INOUT STD_LOGIC_VECTOR(7 DOWNTO 0);
EN,DIR,IN STD_STD_LOGIC);
END BIDIR;
ARCHITECTURE ART OF BIDIR IS
SIGNAL AOUT,BOUT,STD_LOGIC_VECTOR(7 DOWNTO 0);
BEGIN
PROCESS(A,EN,DIR)
BEGIN
第 3章 VHDL编程基础
IF((EN=?0?)AND (DIR=?1?))THEN BOUT<=A;
ELSE BOUT<"ZZZZZZZZ";
END IF ;
B<=BOUT;
END PROCESS;
PROCESS(B,EN,DIR)
BEGIN
IF((EN=?0?)AND (DIR=?1?))THEN AOUT<=B;
ELSE AOUT<"ZZZZZZZZ";
END IF ;
A<=AOUT;
END PROCESS;
END ART;
第 3章 VHDL编程基础
3.9.2 时序逻辑电路设计在本节的时序电路设计主要有触发器、寄存器、计数器、
序列信号发生器和序列信号检测器等的设计实例。
1.触发器
1) D触发器第 3章 VHDL编程基础
【 例 3.9.10】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY DCFQ IS
PORT(D,CLK,IN STD_LOGIC;
Q,OUT STD_LOGIC);
END DCFQ;
ARCHITECTURE ART OF DCFQ IS
BEGIN
PROCESS(CLK)
BEGIN
IF (CLK'EVENT AND CLK=?1?)THEN -- 时钟上升沿触发
Q<=D;
END IF;
END PROCESS;
END ART;
第 3章 VHDL编程基础
2) T触发器
【 例 3.9.11】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY TCFQ IS
PORT(T,CLK,IN STD_LOGIC;
Q,BUFFER STD_LOGIC);
END TCFQ;
ARCHITECTURE ART OF TCFQ IS
BEGIN
PROCESS(CLK)
BEGIN
IF (CLK'EVENT AND CLK=?1?)THEN
Q<=NOT(Q);
ELSE Q<=Q;
END IF;
END PROCESS;
END ART;
第 3章 VHDL编程基础
3) RS触发器
【 例 3.9.12】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY RSCFQ IS
PORT(R,S,CLK,IN STD_LOGIC;
Q,QB,BUFFER STD_LOGIC);
END RSCFQ;
ARCHITECTURE ART OF RSCFQ IS
SIGNAL Q_S,QB_S,STD_LOGIC;
BEGIN
PROCESS(CLK,R,S)
BEGIN
IF (CLK'EVENT AND CLK=?1?)THEN
第 3章 VHDL编程基础
IF(S=?1? AND R=?0?) THEN
Q_S<=?0?;
QB_S<=?1?;
ELSIF (S<=?0? AND R<=?1?) THEN
Q_S<=?1?;
QB_S<=?0?;
ELSIF (S<=?0? AND R<=?0?) THEN
Q_S<=Q_S;
QB_S<=QB_S;
END IF;
END IF ;
Q<=Q_S;
QB<=QB_S;
END PROCESS;
END ART;
第 3章 VHDL编程基础
4) JK触发器
【 例 3.9.13】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY JKCFQ IS
PORT(J,K,CLK,IN STD_LOGIC;
Q,QB,BUFFER STD_LOGIC);
END JKCFQ;
ARCHITECTURE ART OF JKCFQ IS
SIGNAL Q_S,QB_S,STD_LOGIC;
BEGIN
PROCESS(CLK,J,K)
BEGIN
IF (CLK'EVENT AND CLK=?1?)THEN
IF(J=?0? AND K=?1?) THEN
第 3章 VHDL编程基础
Q_S<=?0?;
QB_S<=?1?;
ELSIF (J=?1? AND K=?0?) THEN
Q_S<=?1?;
QB_S<=?0?;
ELSIF (J=?1? AND K=?1?) THEN
Q_S<=NOT Q_S;
QB_S<=NOT QB_S;
END IF;
END IF ;
Q<=Q_S;
QB<=QB_S;
END PROCESS;
END ART;
第 3章 VHDL编程基础
2,触发器的同步和非同步复位触发器的初始状态应由复位信号来设置。按复位信号对触发器复位的操作不同,可以分为同步复位和非同步复位两种。
所谓同步复位,就是当复位信号有效且在给定的时钟边沿到来时,触发器才被复位;非同步复位,也称异步复位,则是当复位信号有效时,触发器就被复位,不用等待时钟边沿信号。下面以 D触发器为例分别予以举例第 3章 VHDL编程基础
1) 非同步复位 /置位的 D触发器
【 例 3.9.14】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY ASYNDCFQ IS
PORT(CLK,D,PRESET,IN STD_LOGIC;
Q,OUT STD_LOGIC);
END ASYNDCFQ;
ARCHITECTURE ART OF ASYNDCFQ IS
BEGIN
PROCESS(CLK,PRESET,D)
第 3章 VHDL编程基础
BEGIN
IF(PRESET='1')THEN --置位信号为 1,则触发器被置位
Q<='1';
ELSIF(D='1')THEN --置位信号为 1,则触发器被置位
Q<=?0?;
ELSIF(CLK'EVENT AND CLK=?1?)THEN
Q<=D;
END IF;
END PROCESS;
END ART;
第 3章 VHDL编程基础
2) 同步复位的 D触发器
【 例 3.9.15】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY SYNDCFQ IS
PORT(D,CLK,RESET,IN STD_LOGIC;
Q,OUT STD_LOGIC);
END SYNDCFQ;
ARCHITECTURE ART OF SYNDCFQ IS
BEGIN
第 3章 VHDL编程基础
PROCESS(CLK)
BEGIN
IF(CLK'EVENT AND CLK=?1?)THEN
IF(PRESET=?0?)THEN
Q<=?0?; --时钟边沿到来且有复位信号,触发器被复位
ELSE Q<=D; --且有复位信号,触发器被复位
END IF;
END IF;
END PROCESS;
END ART;
第 3章 VHDL编程基础
3,寄存器和移位寄存器
1) 寄存 (锁存 )器寄存器用于寄存一组二值代码,广泛用于各类数字系统。
因为一个触发器能储存 1位二值代码,所以用 N个触发器组成的寄存器能储存一组 N位的二值代码。下面给出一个 8位寄存器的
VHDL描述。
第 3章 VHDL编程基础
【 例 3.9.16】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY REG IS
PORT(D,IN STD_LOGIC_VECTOR(0 TO 7);
CLK,IN STD_LOGIC;
Q,OUT STD_LOGIC_VECTOR(0 TO 7));
END REG;
ARCHITECTURE ART OF REG IS
BEGIN
PROCESS(CLK) BEGIN
IF(CLK'EVENT AND CLK=?1?)THEN
Q<=D;
END IF;
END PROCESS;
END ART;
第 3章 VHDL编程基础
2) 移位寄存器移位寄存器除了具有存储代码的功能以外,还具有移位功能。所谓移位功能,是指寄存器里存储的代码能在移位脉冲的作用下依次左移或右移。因此,移位寄存器不但可以用来寄存代码,还可用来实现数据的串并转换、数值的运算以及数据处理等。
下面给出一个 8位的移位寄存器,其具有左移一位或右移一位、并行输入和同步复位的功能。
第 3章 VHDL编程基础
【 例 3.9.17】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY SHIFTER IS
PORT(DATA,IN STD_LOGIC_VECTOR(7 DOWNTO 0);
SHIFT_LEFT,IN STD_LOGIC;
SHIFT_RIGHT,IN STD_LOGIC;
RESET,IN STD_LOGIC;
MODE,IN STD_LOGIC_VECTOR(1 DOWNTO 0);
QOUT,BUFFER STD_LOGIC_VECTOR(7 DOWNTO 0));
END SHIFTER;
ARCHITECTURE ART OF SHIFTER IS
第 3章 VHDL编程基础
BEGIN
PROCESS
BEGIN
WAIT UNTIL(RISING_EDGE(CLK));
IF(RESET=?1?)THEN
QOUT<="00000000";
ELSE --同步复位功能的实现
CASE MODE IS
第 3章 VHDL编程基础
WHEN "01"=>QOUT<=SHIFT_RIGHT&QOUT(7 DOWNTO 1);
--右移一位
WHEN "10"=>QOUT<=QOUT(6 DOWNTO 0)&SHIFT_LEFT;
--左移一位
WHEN "11"=>QOUT<=DATA;
WHEN OTHERS=>NULL;
END CASE;
END IF;
END PROCESS;
END ART;
第 3章 VHDL编程基础
4,计数器计数器是在数字系统中使用最多的时序电路,它不仅能用于对时钟脉冲计数,还可以用于分频、定时、产生节拍脉冲和脉冲序列以及进行数字运算等。
1) 同步计数器下面是一个模为 60,具有异步复位、同步置数功能的
8421BCD码计数器。
第 3章 VHDL编程基础
【 例 3.9.18】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY CNTM60 IS
PORT(CI,IN STD_LOGIC;
NRESET,IN STD_LOGIC;
LOAD,IN STD_LOGIC;
D,IN STD_LOGIC_VECTOR(7 DOWNTO 0);
CLK,IN STD_LOGIC;
CO,OUT STD_LOGIC;
QH,BUFFER STD_LOGIC_VECTOR(3 DOWNTO 0);
QL,BUFFER STD_LOGIC_VECTOR(3 DOWNTO 0));
第 3章 VHDL编程基础
END CNTM60;
ARCHITECTURE ART OF CNTM60 IS
BEGIN
CO<=?1?WHEN(QH="0101"AND QL="1001"AND CI=?1?)ELSE'0';
--进位输出的产生
PROCESS(CLK,NRESET)
BEGIN
IF(NRESET=?0?)THEN --异步复位
QH<="0000";
QL<="0000";
ELSIF(CLK'EVENT AND CLK=?1?)THEN --同步置数
IF(LOAD=?1?)THEN
第 3章 VHDL编程基础
QH<=D(7 DOWNTO 4)
Q L<=D(3 DOWNTO 0);
ELSIF(CI=?1?)THEN --模 60的实现
IF(QL=9)THEN
QL<="0000";
IF(QH=5)THEN
QH<="0000";
ELSE --计数功能的实现
QH<=QH+1;
END IF
ELSE
QL<=QL+1;
END IF;
END IF; --END IF LOAD
END PROCESS;
END ART;
第 3章 VHDL编程基础
2) 异步计数器用 VHDL语言描述异步计数器,与上述同步计数器不同之处主要表现在对各级时钟的描述上。下面是一个由 8个触发器构成的异步计数器,采用元件例化的方式生成。
第 3章 VHDL编程基础
【 例 3.9.19】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY DIFFR IS
PORT(CLK,CLR,D,IN STD_LOGIC;
Q,QB; OUT STD_LOGIC);
END DIFFR;
ARCHITECTURE ART1 OF DIFFR IS
SIGNAL Q_IN,STD_LOGIC;
BEGIN
Q<=Q_IN;
QB<=NOT Q_IN;
PROCESS(CLK,CLR)
第 3章 VHDL编程基础
BEGIN
IF(CLR=?1?)THEN
Q_IN<=?0?;
ELSIF (CLK'EVENT AND CLK=?1') THEN
Q_IN<=D;
END IF;
END PROCESS;
END ART1;
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY RPLCOUNT IS
PORT(CLK,CLR,IN STD_LOGIC;
COUNT,OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END RPLCOUNT;
第 3章 VHDL编程基础
ARCHITECTURE ART2 OF RPLCOUNT IS
SIGNAL COUNT_IN,STD_LOGIC_VECTOR(8 DOWNTO 0);
COMPONENT DIFFR
PORT(CLK,CLR,D,IN STD_LOGIC;
Q,QB,OUT STD_LOGIC);
END COMPONENT;
BEGIN
COUNT_IN(0)<=CLK;
GEN1,FOR I IN 0 TO 7 GENERATE
U,DIFFR PORT MAP(CLK=>COUNT_IN(I),
CLR=>CLR,D=>COUNT_IN(I+1),
Q=>COUNT_IN(I),QB=>COUNT_IN(I+1));
END GENERATE;
END ART2;
第 3章 VHDL编程基础
5,序列信号发生器在数字信号的传输和数字系统的测试中,有时需要用到一组特定的串行数字信号,产生序列信号的电路称为序列信号发生器。
1),01111110”序列发生器该电路可由计数器与数据选择器构成,其 VHDL描述如下:
第 3章 VHDL编程基础
【 例 3.9.20】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY SENQGEN IS
PORT(CLK,CLR,CLOCK,IN STD_LOGIC;
ZO,OUT STD_LOGIC);
END SENQGEN;
ARCHITECTURE ART OF SENQGEN IS
SIGNAL COUNT,STD_LOGIC_VECTOR(2 DOWNTO 0);
SIGNAL Z,STD_LOGIC,=?0?;
BEGIN
第 3章 VHDL编程基础
PROCESS(CLK,CLR)
BEGIN
IF(CLR=?1?)THEN COUNT<="000";
ELSE
IF(CLK=?1?AND CLK'EVENT)THEN
IF(COUNT="111")THEN COUNT<="000";
ELSE COUNT<=COUNT +?1?;
END IF;
END IF;
END IF;
END PROCESS;
PROCESS(COUNT)
BEGIN
第 3章 VHDL编程基础
CASE COUNT IS
WHEN "000"=>Z<=?0?;
WHEN "001"=>Z<=?1?;
WHEN "010"=>Z<=?1?;
WHEN "011"=>Z<=?1?;
WHEN "100"=>Z<=?1?;
WHEN "101"=>Z<=?1?;
WHEN "110"=>Z<=?1?;
WHEN OTHERS=>Z<=?0?;
END CASE;
END PROCESS;
第 3章 VHDL编程基础
PROCESS(CLOCK,Z)
BEGIN --消除毛刺的锁存器
IF(CLOCK'EVENT AND CLOCK=?1?)THEN
ZO<=Z;
END IF;
END PROCESS;
END ART;
第 3章 VHDL编程基础
2) M序列发生器
M序列发生器主要由移位寄存器和反馈环节组成。下面是一个 20位的 M序列发生器的 VHDL描述。
【 例 3.9.21】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY XLGEN20 IS
PORT(CLK,LOAD,EN,IN STD_LOGIC;
DATA,IN STD_LOGIC_VECTOR(20 DOWNTO 0);
LOUT,BUFFER STD_LOGIC);
第 3章 VHDL编程基础
END XLGEN20;
ARCHITECTURE ART OF XLGEN20 IS
CONSTANT LEN,INTEGER,=20
SIGNAL LFSR_VAL,STD_LOGIC_VECTOR(LEN DOWNTO 0);
SIGNAL DOUT,STD_LOGIC_VECTOR(LEN DOWNTO 0);
BEGIN
PROCESS(LOAD,EN,DOUT)
BEGIN
IF (LOAD=?1?)THEN
LFSR_VAL<=DATA;
ELSIF (EN=?1?)THEN
LFSR_VAL(0)<=DOUT(3) XOR DOUT(LEN);
LFSR_VAL(LEN DOWNTO 1)<=DOUT(LEN-1 DOWNTO 0);
第 3章 VHDL编程基础
END IF;
END PROCESS;
PROCESS(CLK)
BEGIN
IF(CLK'EVENT AND CLK=?1?)THEN
DOUT<=LFSR_VAL;
LOUT<=LFSR_VAL(LEN);
END IF;
END PROCESS;
END ART;
第 3章 VHDL编程基础
6.序列信号检测器下面是一个,01111110”序列信号检测器的 VHDL描述。
【 例 3.9.22】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY DETECT IS
PORT( DATAIN,IN STD_LOGIC;
CLK,IN STD_LOGIC;
Q,OUT STD_LOGIC);
END DETECT;
ARCHITECTURE ART OF DETECT IS
第 3章 VHDL编程基础
TYPE STATETYPE IS(S0,S1,S2,S3,S4,S5,S6,S7,S8);
BEGIN
PROCESS(CLK)
VARIABLE PRESENT_STATE,STATETYPE;
BEGIN
Q<=?0?;
CASE PRESENT_STATE IS
WHEN S0=>
IF DATAIN=?0? THEN PRESENT_STATE,=S1;
ELSE PRESENT_STATE,=S0; END IF;
WHEN S1=>
IF DATAIN=?1? THEN PRESENT_STATE,=S2;
ELSE PRESENT_STATE,=S1; END IF;
第 3章 VHDL编程基础
WHEN S2=>
IF DATAIN=?1?THEN PRESENT_STATE,=S3;
ELSE PRESENT_STATE,=S1; END IF;
WHEN S3=>
IF DATAIN=?1?THEN PRESENT_STATE,=S4;
ELSE PRESENT_STATE,=S1; END IF;
WHEN S4=>
IF DATAIN=?1?THEN PRESENT_STATE,=S5;
ELSE PRESENT_STATE,=S1; END IF;
WHEN S5=>
IF DATAIN=?1?THEN PRESENT_STATE,=S6;
ELSE PRESENT_STATE,=S1; END IF;
第 3章 VHDL编程基础
WHEN S6=>
IF DATAIN=?1?THEN PRESENT_STATE,=S7;
ELSE PRESENT_STATE,=S1; END IF;
WHEN S7=>
IF DATAIN=?0?THEN PRESENT_STATE,=S8;
Q<=?1?; ELSE PRESENT_STATE,=S0; END IF;
WHEN S8=>
IF DATAIN=?0?THEN PRESENT_STATE,=S1;
ELSE PRESENT_STATE,=S2; END IF;
END CASE;
WAIT UNTIL CLK=?1?;
END PROCESS;
END ART;
第 3章 VHDL编程基础
3.9.3 存储器设计半导体存储器的种类很多,从功能上可以分为只读存储器
(Read_Only Memory,简称 ROM)和随机存储器 (Random Access
Memory,简称 RAM)两大类。
1,ROM
只读存储器在正常工作时从中读取数据,不能快速地修改或重新写入数,适用于存储固定数据的场合。下面是一个容量为 256× 4的 ROM存储的例子,该 ROM有 8位地址线 ADR(0)~
ADR(7),4位数据输出线 DOUT(0)~ DOUT(3)及使能 EN,如图
3.27所示。
第 3章 VHDL编程基础图 3.27 ROM
D O U T [ 3,,0 ]D O U T [ 3,,0 ]
EN
A D R [ 7,,0 ]A D R [ 7,,0 ]
EN
R O M
第 3章 VHDL编程基础例 3.9.23】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
USE STD.TEXTIO.ALL;
ENTITY ROM IS
PORT(EN,IN STD_LOGIC;
ADR,IN STD_LOGIC_VECTOR(7 DOWNTO 0);
DOUT,OUT STD_LOGIC_VECTOR(3 DOWNTO 0));
END ROM;
ARCHITECTURE ART OF ROM IS
第 3章 VHDL编程基础
SUB TYPE WORD IS STD_LOGIC_VECTOR(3 DOWNTO 0);
TYPE MEMORY IS ARRAY(0 TO 255) OF WORD;
SIGNAL ADR_IN,INTEGER RANGE 0 TO 255;
VARIABLE ROM,MEMORY;
VARABLE START_UP,BOOLEAN,=TRUE;
VARABLE L,LINE;
VARABLE J,INTEGER;
FILE ROMIN,TEXT IS IN "ROMIN";
BEGIN
PROCESS(EN,ADR)
IF START_UP THEN --初始化开始
FOR J IN ROM'RANGE LOOP
READLINE(ROMIN,1);
第 3章 VHDL编程基础
READ(1,ROM(J));
END LOOP;
START_UP,=FALSE; --初始化结束
END IF;
ADR_IN<=CONV_INTEGER(ADR);
IF(EN=?1?)THEN
DOUT<=ROM(ADR_IN);
ELSE
DOUT<="ZZZZ";
END IF;
END PROCESS;
END ART;
第 3章 VHDL编程基础
2,SRAM
RAM和 ROM的主要区别在于 RAM描述上有读和写两种操作,而且在读写上对时间有较严格的要求。下面我们给出一个
8× 8位的双口 SRAM的 VHDL描述实例,如图 3.28所示。
图 3.28 双口 SRAM
D A T A O U T [ 7,,0 ]
D A T A I N [ 7,,0 ]
WE
RE
C L O C K
W A D D [ 2,,0 ]
R A D D [ 2,,0 ]
D A T A O U T [ 7,,0 ]
D A T A I N [ 7,,0 ]
WE
RE
C L O C K
W A D D [ 2,,0 ]
R A D D [ 2,,0 ]
D P R A M
第 3章 VHDL编程基础
【 例 3.9.24】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY DPRAM IS
GENERIC(WIDTH,INTEGER,=8;
DEPTH,INTEGER,=8;
ADDER,INTEGER,=3);
PORT(DATAIN,IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
DATAOUT,OUT,STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
第 3章 VHDL编程基础
CLOCK,IN STD_LOGIC;
WE,RE,IN STD_LOGIC;
WADD,IN STD_LOGIC_VECTOR(ADDER-1 DOWNTO 0);
RADD,IN STD_LOGIC_VECTOR(ADDER-1 DOWNTO 0));
END DPRAM;
ARCHITECTURE ART OF DPRAM IS
TYPE MEM IS ARRAY(0 TO DEPTH-1) OF
STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
SIGNAL RAMTMP,MEM;
BEGIN
--写进程
PROCESS(CLOCK)
BEGIN
第 3章 VHDL编程基础
IF (CLOCK'EVENT AND CLOCK=?1?) THEN
IF(WE=?1?)THEN
RAMTMP(CONV_INTEGER(WADD))<=DATA;
END IF;
END IF;
END PROCESS;
--读进程
PROCESS(CLOCK)
BEGIN
IF(CLOCK'EVENT AND CLOCK=?1?)THEN
IF (RE=?1?) THEN
Q<=RAMTMP(CONV_INTEGER(RADD));
END IF;
END IF;
END PROCESS;
END ART;
第 3章 VHDL编程基础
3,FIFO
FIFO是先进先出堆栈,作为数据缓冲器,通常其数据存放结构完全与 RAM一致,只是存取方式有所不同。图 3.29电路为一个 8× 8 FIFO,其 VHDL描述如例 3.9.25。
图 3.29
D A T A [ 7,,0 ]
A C L K
C LO C K
WE
RE
WE
RE
C LO C K
A C L K
FF
EF
同步 F I F O
Q [ 7,,0 ]
D A T A [ 7,,0 ]
EF
FF
Q [ 7,,0 ]
第 3章 VHDL编程基础
【 例 3.9.25】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
ENTITY REG_FIFO IS
GENERIC(WIDTH,INTEGER,=8;
DEPTH,INTEGER,=8;
ADDR,INTEGER,=3);
PORT(DATA,IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
Q,OUT STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
ACLR,IN STD_LOGIC;
CLOCK,IN STD_LOGIC;
WE,IN STD_LOGIC;
RE,IN STD_LOGIC;
第 3章 VHDL编程基础
FF,OUT STD_LOGIC;
FF,OUT STD_LOGIC);
END REG_FIFO;
TYPE MEM IS ARRAY(0 TO DEPTH-1) OF
STD_LOGIC_VECTOR(WIDTH-1 DOWN TO 0);
SIGNAL RAMTMP,MEM;
SIGNAL WADD,STD_LOGIC_VECTOR(ADDR-1 DOWNTO 0);
SIGNAL RADD,STD_LOGIC_VECTOR(ADDR-1 DOWNTO 0);
SIGNAL WORDS,STD_LOGIC_VECTOR(ADDR-1 DOWNTO 0);
ARCHITECTURE ART OF REG_FIFO IS
BEGIN
--写指针修改进程
WRITE_POINTER,PROCESS(ACLR,CLOCK)
第 3章 VHDL编程基础
BEGIN
IF (ACLR=?0?) THEN
WADD<=(OTHERS=>?0?);
ELSIF (CLOCK'EVENT AND CLOCK=?1?) THEN
IF (WE=?1?) THEN
IF (WADD=WORDS) THEN
WADD<=(OTHERS=>?0?);
ELSE
WADD<=WADD+?1?;
END IF;
END IF;
END IF;
END PROCESS;
--写操作进程
WRITE_RAM,PROCESS(CLOCK)
第 3章 VHDL编程基础
BEGIN
IF (CLOCK'EVENT AND CLOCK=?1?) THEN
IF (WE=?1?) THEN
RAMTMP(CONV_INTEGER(WADD))<=DATA;
END IF;
END IF;
END PROCESS;
--读指针修改
READ_POINIER,PROCESS(ACLR,CLOCK)
BEGIN
IF (ACLR=?0?) THEN
RADD<=(OTHERS=>?0?);
ELSIF (CLOCK'EVENT AND CLOCK=?1?) THEN
第 3章 VHDL编程基础
IF (RE=?1?) THEN
IF (RADD=WORDS) THEN
RADD<=(OTHERS=>?0?);
ELSE
RADD<=RADD+?1?;
END IF;
END IF;
END IF;
END PROCESS;
--读操作进程
READ_RAM,PROCESS(CLOCK)
BEGIN
IF (CLOCK'EVENT AND CLOCK=?1?) THEN
IF (RE=?1?) THEN
Q<=RAMTMP(CONV_INTERGER(RADD));
第 3章 VHDL编程基础
END IF;
END IF;
END PROCESS;
--产生满标志进程
FFLAG,PROCESS(ACLR,CLOCK)
BEGIN
IF (ACLR=?0?) THEN
FF<=?0?;
ELSIF (CLOCK'EVENT AND CLOCK=?1?) THEN
IF (WE=?1?AND RE=?0?) THEN
IF ((WADD=RADD-1) OR
((WADD=DEPTH-1)AND(RADD=0))) THEN
FF<=?1?;
END IF;
第 3章 VHDL编程基础
ELSE
FF<=?0?;
END IF;
END IF;
END PROCESS;
--产生空标志进程
EFLAG,PROCESS(ACLR,CLOCK)
BEGIN
IF (ACLR=?0? THEN
EF<='0'
ELSIF (CLOCK'EVENT AND CLOCK=?1?) THEN
IF (RE=?1?AND WE=?0?) THEN
IF ((WADD=RADD+1) OR
第 3章 VHDL编程基础
((RADD=DEPTH-1)AND(WADD=0))) THEN
EF<=?0?;
END IF;
ELSE
EF<=?1?;
END IF;
END IF;
END PROCESS;
END ART;
第 3章 VHDL编程基础
3.10 状态机的 VHDL设计
3.10.1 状态机的基本结构和功能状态机是一类很重要的时序电路,是许多数字电路的核心部件。状态机的一般形式如图 3.30所示。除了输入信号、输出信号外,状态机还包括一组寄存器记忆状态机的内部状态。状态机寄存器的下一个状态及输出,不仅同输入信号有关,而且还与寄存器的当前状态有关,状态机可认为是组合逻辑和寄存器逻辑的特殊组合。它包括两个主要部分:组合逻辑部分和寄存器部分。寄存器部分用于存储状态机的内部状态;组合逻辑部分又分为状态译码器和输出译码器,状态译码器确定状态机的下一个状态,即确定状态机的激励方程,输出译码器确定状态机的输出,即确定状态机的输出方程。
第 3章 VHDL编程基础图 3.30 状态机的结构示意图状态译码器状态寄存器输出译码器状态输出反馈输入组合逻辑第 3章 VHDL编程基础状态机的基本操作有两种:
(1) 状态机内部状态转换。状态机经历一系列状态,下一状态由状态译码器根据当前状态和输入条件决定。
(2) 产生输出信号序列。输出信号由输出译码器根据当前状态和输入条件决定。
用输入信号决定下一状态也称为“转移”。除了转移之外,
复杂的状态机还具有重复和历程功能。从一个状态转移到另一个状态称为控制定序,而决定下一状态所需的逻辑称为转移函数。
第 3章 VHDL编程基础在产生输出的过程中,由是否使用输入信号可以确定状态机的类型。两种典型的状态机是摩尔 (MOORE)状态机和米立
(MEALY)状态机。在摩尔状态机中,其输出只是当前状态值的函数,并且仅在时钟边沿到来时才发生变化。米立状态机的输出则是当前状态值、当前输出值和当前输入值的函数。对于这两类状态机,控制定序都取决于当前状态和输入信号。大多数实用的状态机都是同步的时序电路,由时钟信号触发状态的转换。时钟信号同所有的的边沿触发的状态寄存器和输出寄存器相连,这使得状态的改变发生在时钟的上升沿。
此外,还利用组合逻辑的传播延迟实现状态机存储功能的异步状态机,这样的状态机难于设计并且容易发生故障,所以下面仅讨论同步时序状态机。
第 3章 VHDL编程基础
3.10.2 一般状态机的 VHDL设计为了能获得可综合的,高效的 VHDL状态机描述,建议使用枚举类数据类型来定义状态机的状态,并使用多进程方式来描述状态机的内部逻辑。例如可使用两个进程来描述,一个进程描述时序逻辑,包括状态寄存器的工作和寄存器状态的输出;
另一个进程描述组合逻辑,包括进程间状态值的传递逻辑以及状态转换值的输出。必要时还可引入第三个进程完成其他的逻辑功能。
第 3章 VHDL编程基础
【 例 3.10.1】 一般状态机的 VHDL设计模型。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY S_MACHINE IS
PORT(CLK,RESET,IN STD_LOGIC;
STATE_INPUTS,IN STD_LOGIC_VECTOR(0 TO 1)
COMB_OUTPUTS,OUT STD_LOGIC_VECTOR(0 TO 1));
END S_MACHINE;
ARCHITECTURE ART OF S_MACHINE IS
TYPE STATES IS (ST0,ST1,ST2,ST3);
--定义 STATES为枚举型数据类型第 3章 VHDL编程基础
SIGNAL CURRENT_STATE,NEXT_STATE,STATES;
BEGIN
REG,PROCESS (RESET,CLK) --时序逻辑进程
BEGIN
IF RESET=?1?THEN
CURRENT_STATE<=ST0; --异步复位
ELSIF (CLK=?1? AND CLK?EVENT) THEN
CURRENT_STATE<=NEXT_STATE;
--当测到时钟上升沿时转换至下一状态
END IF;
END PROCESS;
--由 CURRENT_STATE将当前状态值带出此进程,进入进程 COM
第 3章 VHDL编程基础
COM,PROCESS(CURRENT_STATE,STATE_INPUTS) --组合逻辑进程
BEGIN
CASE CURRENT_STATE IS --确定当前状态的状态值
WHEN ST0=>COMB_OUTPUTS<=“00”; --初始态译码输出,00”
IF STARE_INPUTS=“00”THEN --根据外部的状态控制输入,00”
NEXT_STATE<=ST0; --在下一时钟后,进程 REG的状态将维持为 ST0
ELSE
NEXT_STATE<=ST1;--否则,在下一时钟后,进程 REG的状态将为 ST1
END IF;
第 3章 VHDL编程基础
WHEN ST1=>COMB_OUTPUTS<=“01”; --对应 ST1的译码输出,01”
IF START_INPUTS =“00”THEN --根据外部的状态控制输入,00”
NEXT_STATE<=ST1; --在下一时钟后,进程 REG的状态将维持为 ST1
ELSE
NEXT_STATE<=ST2; --否则,在下一时钟后,进程 REG的状态将为 ST2
END IF;
WHEN ST2=>COMB_OUTPUTS<=“10”; --以下依次类推
IF STATE_INPUTS=“11”THEN
NEXT_STATE<=ST2;
ELSE
第 3章 VHDL编程基础
NEXT_STATE<=ST3;
END IF;
WHEN ST3=>COMB_OUTPUTS<=“11”;
IF STATE_INPUTS=“11”THEN
NEXT_STATE<=ST3;
ELSE
NEXT_STATE<=ST0;
--否则,在下一时钟后,进程 REG的状态将为 ST0
END IF;
END CASE;
END PROCESS;
--由信号 NEXT_STATE将下一状态值带出此进程,进入进程 REG
END ART;
第 3章 VHDL编程基础进程间一般是并行运行的,但由于敏感信号的设置不同以及电路的延迟,在时序上进程间的动作是有先后的。本例中,
进程,REG”在时钟上升沿到来时,将首先运行,完成状态转换的赋值操作。如果外部控制信号 STATE_INPUTS不变,只有当来自进程 REG的信号 CURRENT_STATE改变时,进程 COM才开始动作。在此进程中,将根据 CURRENT_STATE的值和外部的控制码 STATE_INPUTS来决定下一时钟边沿到来后,进程 REG
的状态转换方向。这个状态机的两位组合输出
COMB_OUTPUTS是对当前状态的译码,读者可以通过这个输出值了解状态机内部的运行情况;同时可以利用外部控制信号
STATE_INPUTS任意改变状态机的状态变化模式。
第 3章 VHDL编程基础在设计中,如果希望输出的信号具有寄存器锁存功能,则需要为此输出写第 3个进程,并把 CLK和 RESET信号放到敏感信号表中。
本例中,用于进程间信息传递的信号 CURRENT_STATE和
NEXT_STATE,在状态机设计中称为反馈信号。状态机运行中,
信号传递的反馈机制的作用是实现当前状态的存储和下一个状态的译码设定等功能。在 VHDL中可以有两种方式来创建反馈机制。即使用信号的方式和使用变量的方式,通常倾向于使用信号的方式。一般地,先在进程中使用变量传递数据,然后使用信号将数据带出进程。
第 3章 VHDL编程基础
3.10.3 摩尔状态机的 VHDL设计
【 例 3.10.2】 摩尔状态机的 VHDL设计模型之一。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY SYSTEM1 IS
PORT(CLOCK,IN STD_LOGIC; A,IN STD_LOGIC;
D,OUT STD_LOGIC);
END SYSTEM1;
ARCHITECTURE MOORE1 OF SYSTEM1 IS
SIGNAL B,C,STD_LOGIC;
BEGIN
第 3章 VHDL编程基础
FUNC1,PROCESS(A,C)
--第 1组合逻辑进程,为时序逻辑进程提供的反馈信息
BEGIN
B<=FUNC1(A,C); --C是反馈信号
END PROCESS;
FUNC2,PROCESS(C)
--第 2组合逻辑进程,为状态机输出提供数据
BEGIN
D<= FUNC2(C);
--输出信号 D所对应的 FUNC2,是仅为当前状态的函数第 3章 VHDL编程基础
END PROCESS;
REG,PROCESS(CLOCK) --时序逻辑进程,负责状态的转换
BEGIN
IF (CLOCK=?1?AND CLOCK?EVENT) THEN
C<=B; --B 是反馈信号
END IF;
END PROCESS;
END MOORE1;
第 3章 VHDL编程基础图 3.31 例 3.10.2的摩尔状态机示意图进程 F U N C 1
A
B
C LO C K
进程 R EG
C D
进程 F U N C 2
第 3章 VHDL编程基础
【 例 3.10.3】 摩尔状态机的 VHDL设计模型之二。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY SYSTEM2 IS
PORT (CLOCK,IN STD_LOGIC;
A,IN STD_LOGIC;
D,OUT STD_LOGIC);
END SYSTEM2;
ARCHITECTURE MOORE2 OF SYSTEM2 IS
BEGIN
REG,PROCESS(CLOCK)
BEGIN
IF (CLOCK=?1? AND CLOCK?EVENT) THEN
D<=FUNC(A,D);
END IF;
END PROCESS;
END MOORE2;
第 3章 VHDL编程基础图 3.32 例 3.10.3的直接反馈式摩尔状态机示意图组合逻辑功能块 F U N C
A
C LO C K
D
时序逻辑输出进程 R EG
第 3章 VHDL编程基础
【 例 3.10.4】 基于状态机的 ADC0809与 SRAM6264的通信控制器的设计。图 3.33是该控制器 ADTOSRAM与 ADC0809及
SRAM6264接口示意图。
图 3.33 ADTOSRAM与 ADC0809及 SRAM6264接口示意图
S T A R T
A D C 0 8 0 9
D I N [ 7,,0 ]
D I N [ 7,,0 ]
EO C
EO C
A D T O S R A M
通信控制器
S R A M
6 2 6 4
A D C 0 8 0 9
A D D R E S S [ 1 2,,0 ]
R A M _ D I N [ 7,,0 ]
WR
WR
RD
RD
A D D A
A D D R E S S [ 1 2,,0 ]
R A M _ D I N [ 7,,0 ]
S R A M
6 2 6 4
CSCS
C LK
R S T
S T A R T
OE
A D D A
A LE OE
A LE
第 3章 VHDL编程基础
--VHDL源程序 ADTOSRAM.VHD
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY ADTOSRAM IS PORT( --ADC0809接口信号
DIN,IN STD_LOGIC_VECTOR(7 DOWNTO 0);
--0809转换数据输入口
CLK,EOC,IN STD_LOGIC;
--CLK:状态机工作时钟; EOC:转换结束状态信号
RST,IN STD_LOGIC; --系统复位信号
ALE,OUT STD_LOGIC; --0809采样通道选择地址锁存信号
START,OUT STD_LOGIC; --0809采样启动信号,上升沿有效第 3章 VHDL编程基础
OE,OUT STD_LOGIC;
--转换数据输出使能,接 0809的 ENABLE(PIN 9)
ADDA,OUT STD_LOCIC; --0809采样通道地址最低位
--SRAM 6264接口信号
CS,OUT STD_LOGIC; --6264片选控制信号,低电平有效
RD,WR,OUT STD_LOGIC; --6264读 /写控制信号,低电平有效
RAM_DIN,OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
--6264数据写入端口
ADDRESS,OUT STD_LOGIC_VECTOR(12 DOWNTO 0));
--地址输出端口
END ADTOSRAM;
ARCHITECTURE ART OF ADTOSRAM IS
第 3章 VHDL编程基础
TYPE AD_STATES IS(ST0,ST1,ST2,ST3,
ST4,ST5,ST6,ST7) --A/D转换状态定义
TYPE WRIT_STATES IS (START_WRITE,WRITE1,WRITE2,WRITE3,
WRITE_END); SRAM数据写入控制状态定义
SIGNAL RAM_CURRENT_STATE,RAM_NEXT_STATE:WRIT_STATES;
SIGNAL ADC_CURRENT_STATE,ADC_NEXT_STATE:AD_STATES;
SIGNAL ADC_END,STD_LOGIC;
--0809数据转换结束并锁存标志位,高电平有效
SIGNAL LOCK,STD_LOGIC; --转换后数据输出锁存信号
SIGNAL ENABLE,STD_LOGIC; --A/D转换允许信号,高电平有效
SIGNAL ADDRES_PLUS,STD_LOGIC; --SRAM地址加 1时钟信号第 3章 VHDL编程基础
SIGNAL ADC_DATA,STD_LOGIC_VECTOR(7 DOWNTO 0);
--转换数据读入锁存器
SIGNAL ADDRES_CNT,STD_LOGIC_VECTOR(12 DOWNTO 0); -
-SRAM地址锁存器
BEGIN
ADDA<=?1?; --ADDA=1,ADDB=0,ADDC=0选 A/D采样通道为 IN-1
RD<=?1?; --SRAM写禁止
--ADC0809采样控制状态机
ADC,PROCESS(ADC_CURRENT_STATE,EOC,ENABLE)
--A/D转换状态机组合电路进程第 3章 VHDL编程基础
BEGIN
IF (RST=?1?) THEN ADC_NEXT_STATE<=ST0; --状态机复位
ELSE
CASE ADC_CURRENT_STATE IS
WHEN ST0=>ALE<=?0?; START<=?0?; OE<=?0?;
LOCK<=?0?; ADC_END<=?0?; --A/D转换初始化
IF (ENABLE=?1?') THEN ADC_NEXT_STATE<=ST1;
--允许转换,转下一状态
ELSE ADC_NEXT_STATE<=ST0; --禁止转换,仍停留在本状态
END IF;
WHEN ST1=>ALE<=?1?; START<=?0?; OE<=?0?;
LOCK<=?0?; ADC_END<=?0?;
第 3章 VHDL编程基础
ADC_NEXT_STATE<=ST2; --通道选择地址锁存,并转下一状态
WHEN ST2=>ALE<=?1?; START<=?1?; OE<=?0?;
LOCK<=?0?; ADC_END<=?0?;
ADC_NEXT_STATE<=ST3; --启动 A/D转换信号 START
WHEN ST3=>ALE<=?1?; START<=?1?; OE<=?0?;
LOCK<=?0?; ADC_END<=?0?; --延迟一个脉冲周期
IF (EOC=?0?) THEN ADC_NEXT_STATE<=ST4;
ELSE ADC_NEXT_STATE<=ST3; --转换未结束,继续等待第 3章 VHDL编程基础
END IF;
WHEN ST4=>ALE<=?0?; START<=?0?; OE<=?0?;
LOCK<=?0?; ADC_END<=?0?;
IF(EOC='0')THEN ADC_NEXT_STATE<=ST5; --转换结束,转下一状态
ELSE ADC_NEXT_STATE<=ST4; --转换未结束,继续等待
END IF;
WHEN ST5=>ALE<=?0?; START<=?0?; OE<=?1?;
LOCK<=?1?; ADC_END<=?1?;
ADC_NEXT_STATE<=ST6; --开启数据输出使能信号 OE
WHEN ST6=>ALE<=?0?; START<=?0?; OE<=?1?;
LOCK<=?1?; ADC_END<=?1?;
ADC_NEXT_STATE<=ST7; --开启数据锁存信号第 3章 VHDL编程基础
WHEN ST7=>ALE<=?0?; START<=?0?; OE<=?1?;
LOCK<=?1?; ADC_END<=?1?;
ADC_NEXT_STATE<=ST0;
--为 6264数据定入发出 A/D转换周期结束信号
WHEN OTHERS=>ADC_NEXT_STATE<=ST0;
--所有闲置状态导入初始态
END CASE;
END IF;
END PROCESS ADC;
AD_STATE,PROCESS(CLK) --A/D转换状态机时序电路进程
BEGIN
IF(CLK'EVENT AND CLK=?1?)THEN
第 3章 VHDL编程基础
ADC_CURRENT_STATE<=ADC_NEXT_STATE;
--在时钟上升沿,转至下一状态
END IF;
END PROCESS AD_STATE;
--由信号 CURRENT_STATE将当前状态值带出此进程
DATA_LOCK,PROCESS(LOCK)
BEGIN
--此进程中,在 LOCK的上升沿,将转换好的数据锁入锁存器 ADC_DATA中
IF (LOCK=?1? AND LOCK'EVENT) THEN
ADC_DATA<=DIN;
END IF;
END PROCESS DATA_LOCK;
第 3章 VHDL编程基础
--SRAM数据写入控制状态机
WRIT_STATE,PROCESS(CLK,RST)
--SRAM写入控制状态机时序电路进程
BEGIN
IF RST=?1?THEN RAM_CURRENT_STATE<=START_WRITE;
--系统复位
ELSIF(CLK'EVENT AND CLK=?1?) THEN
RAM_CURRENT_STATE<=RAM_NEXT_STATE;
--在时钟上升沿,转下一状态
END IF;
END PROCESS WRIT_STATE;
第 3章 VHDL编程基础
RAM_WRITE,PROCESS(RAM_CURRENT_STATE,ADC_END) --
SRAM控制时序电路进程
BEGIN
CASE RAM_CURRENT_STATE IS
WHEN START_WRITE=>CS<=?1?; WR<=?1?; ADDRES_PLUS<=?0?;
IF (ADDRES_CNT="1111111111111") --数据写入初始化
THEN ENABLE<=?0?; --SRAM地址计数器已满,禁止 A/D转换
RAMM_NEXT_STATE<=START_WRITE;
ELSE ENABLE<=?1? --SRAM地址计数器未满,允许 A/D转换
RAM_NEXT_STATE<=START_WRITE;
END IF;
第 3章 VHDL编程基础
WHEN WRITE1=>CS<=?1?; WR<=?1?;
ENABLE<=?1?; ADDRES_PLUS<=?0?; --判断 A/D转换周期是否结束
IF (ADC_END=?1?)THEN RAM_NEXT_STATE<=WRITE2; --已结束
ELSE RAM_NEXT_STATE<=WRITE1; --A/D转换周期未结束,等待
END IF;
WHEN WRITE2=>CS<=?1?; WR<=?1?; --打开 SRAM片选信号
ENABLE<=?0?; --禁止 A/D转换
ADDRES_PLUS<=?0?;ADDRESS<=ADDRES_CNT; --输出 13位地址
RAM_DIN<=ADC_DATA; --8位已转换好的数据输向 SRAM数据口
RAM_NEXT_STATE<=WRITE3; --进入下一状态第 3章 VHDL编程基础
WHEN WRITE3=>CS<=?0?; WR<=?0?; --打开写允许信号
ENABLE<=?0?; --仍然禁止 A/D转换
ADDRES_PLUS<=?1?; --产生地址加 1时钟上升沿,使地址计数器加 1
RAM_NEXT_STATE<=WRITE_END; --进入结束状态
WHEN WRITE_END=>CS<=?1?; WR<=?1?;
ENABLE<=?1?; --打开 A/D转换允许开关
ADDRES_PLUS<=?0?; --地址加 1时钟脉冲结束
RAM_NEXT_STATE<=START_WRITE; --返回初始状态
WHEN OTHERS=> RAM_NEXT_STATE<=START_WRITE;
END CASE;
END PROCESS RAM_WRITE;
第 3章 VHDL编程基础
COUNTER,PROCESS(ADDRES_PLUS) --地址计数器加 1进程
BEGIN
IF(RST=?1?)THEN ADDRES_CNT<="0000000000000"; --计数器复位
ELSIF(ADDRES_PLUS'EVENT AND ADDRES_PLUS=?1?)THEN
ADDRES_CNT<=ADDRES_CNT+1;
END IF;
END PROCESS COUNTER;
END ART;
第 3章 VHDL编程基础本例是根据图 3.32的摩尔状态机原理设计的具有同步双状态机的 VHDL电路设计。两个状态机的功能和工作方式是:
(1) ADC0809采样控制状态机。它由三个进程组成:
,ADC”、,AD_STATE”和,DATA_LOCK”。,ADC”是此状态机的组合逻辑进程,确定状态的转换方式和反馈控制信号的输出。工作过程中首先监测系统复位信号,RST”,当其为高电平时,使此进程复位至初始态,ST0”。在初始态中对转换允许信号,ENABLE”进行监测,当为低电平时,表明此时另一状态机正在对 6264进行写操作,为了不发生误操作,暂停 A/D转换。
第 3章 VHDL编程基础而在状态 ST2时启动 A/D转换信号,START”,在状态 ST4搜索到状态转换信号,EOC”由 0变 1时,即在状态 ST5开启输出使能信号,OE”,在下一状态使,LOCK”产生一个上跳沿,从而在此时启动进程,DATA_LOCK”,将由 0809转换好的位数据锁进锁存器,ADC _DATA"中。在接下去的一个状态 ST7中,将 A/D转换周期结束的标志位,ADC_END”置为高电平,以便通知另一状态机,本周期的转换数据已经进入数据锁存器中,可以对
6264进行写操作。进程,AD_STATE”是此状态机的动力部分,
即时序逻辑部分,负责状态的转换运行。
第 3章 VHDL编程基础
(2) SRAM6264数据写入控制状态机。它由三个进程组成:
,WRIT_STATE”、,RAM_WRITE”和,COUNTER,。进程
,WRIT_STATE”是此状态机时序逻辑部分,功能与进程
,AD_STATE”类似,只是多了一个异步复位功能。进程
,WRIT_STATE” 的功能与进程,ADC”类似,在状态
,START_WRITE”中,监测地址计数器是否已计满。若计满
(ADDRES_CNT="1111111111111")则发出 A/D转换禁止命令
(ENABLE=0),并等待外部信号为系统发出复位信号,RST”,
以便使寄存器 ADDRES_CNT清零;否则发出 A/D转换允许命令
(ENABLE=1),并转下一状态 WRITE1,在此状态中监测 A/D转换周期是否结束,若结束 (ADC_END=1),则进入 SRAM的各个写操作状态。在状态 WRITE2中,ADDRES_CNT中的 13位地址和 ADC_DATA中 8位数据预先输向 6264的对应端口;
第 3章 VHDL编程基础
ADC_DATA中的数据是在状态 WRITE3,WR=0时被写入
6264的。在此状态中,同时进行了另外两项操作,即发出 A/D
转换禁止命令和产生一个地址数加一脉冲上升沿,以便启动进程,COUNTER”,使地址计数器加一,为下一数据的写入作准备 (注意,此地址计数器的异步复位端是与全局复位信号线
,RST”相接的 )。在最后一个状态 WRITE_END中打开了 A/D转换允许开关。
第 3章 VHDL编程基础此程序中的两个状态机是同步工作的,同步时钟是 CLK。
但由于 A/D采样的速度,即采样周期的长短在一定范围内是不可预测的,所以必须设置几个标准位来协调两个状态机的工作,
这就是前面提到的 A/D转换允许命令标志位 ENABLE和 A/D转换周期结束标志位 ADC_END。此外还设定了两个异步时钟信号
LOCK和 ADDRES_PLUS,分别在进程,ADC”和
,WRIT_STATE”中的特定状态中启动进程,DATA_LOCK”或
,COUNTER”。
第 3章 VHDL编程基础图 3.34 例 3.10.4源程序进程关系示意图进程 F U N C 1
A
进程 R E G 进程 F U N C 2
C L O C K
C
B
D
第 3章 VHDL编程基础
3.10.4 米立状态机的 VHDL设计
【 例 3.10.5】 米立状态机的 VHDL设计模型之一。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY SYSTEM1 IS
PORT(CLOCK,IN STD_LOGIC;
A,IN STD_LOGIC;
D,OUT STD_LOGIC);
END SYSTEM1;
ARCHITECTURE MEALY1 OF SYSTEM1 IS
SIGNAL C,STD_LOGIC;
BEGIN
COM,PROCESS(A,C) --此进程用于状态机的输出第 3章 VHDL编程基础
BEGIN
D<=FUNC2(A,C)
END PROCESS;
REG,PROCESS(CLOCK) --此进程用于状态机的状态转换
BEGIN
IF (CLOCK=?1? AND CLOCK?EVENT) THEN
C<=FUNC1(A,C);
END IF;
END PROCESS;
END MEALY1;
第 3章 VHDL编程基础
【 例 3.10.6】 米立状态机的 VHDL设计模型之二。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY SYSTEM2 IS
PORT(CLOCK,IN STD_LOGIC;
A,IN STD_LOGIC;
D,OUT STD_LOGIC);
END SYSTEM2;
ARCHITECTURE MEALY2 OF SYSTEM2 IS
SIGNAL C,STD_LOGIC;
SIGNAL B,STD_LOGIC;
BEGIN
REG,PROCESS(CLOCK)
第 3章 VHDL编程基础
BEGIN
IF (CLOCK=?1? AND CLOCK?EVENT) THEN
C<=B;
END IF;
END PROCESS;
TRANSITIONS,PROCESS(A,C)
BEGIN
B<=FUNC1(A,C);
END PROCESS;
OUTPUTS,PROCESS(A,C);
BEGIN
D<=FUNC2(A,C);
END PROCESS;
END MEALY2;
第 3章 VHDL编程基础图 3.35 例 3.10.6的米立状态机示意图
T H R E E _ S
C N D
I N P U T
C L K
B
A
S
M U X 2 1
D _ F F
D Q
O T 1 1
O U T P U T
第 3章 VHDL编程基础使用 VHDL描述状态机时,必须注意避免由于寄存器的引入而创建了不必要的异步反馈路径。根据 VHDL综合器的规则,
对于所有可能的输入条件,当进程中的输出信号如果没有被完全地与之对应指定时,即没有为所有可能的输入条件提供明确的赋值时,此信号将自动被指定,即在未列出的条件下保持原值,这就意味着引入了寄存器。在状态机中,如果存在一个或更多的状态没有被明确地指定转换方式,或者对于状态机中的状态值没有规定所有的输出值,寄存器就将在设计者的不知不觉中被引入了。因此,在程序的综合过程中,应密切注视
VHDL综合器给出的每一个警告信息,并根据警告信息的指示,
对程序作必要的修改。