基于FPGA的SOC在嵌入式系统应用越来越广了,比较流行的硬件描述语言有两种Verilog HDL/VHDL,均为IEEE标准。VHDL如果有C语言基础的话就会比较容易上手。而VHDL语言则需要Ada编程基础。另外VHDL语言具有大量成熟的模块,从某种角度说VHDL更具生命力。
VHDL 的历史
VHDL 的 英 文 全 名 是 Very-High-Speed Integrated Circuit Hardware DescriptionLanguage,诞生于 1982 年。
1987 年底,VHDL 被 IEEE 和美国国防部确认为标准硬件描述语言。自 IEEE 公布了 VHDL 的标准版本 IEEE-1076(简称 87 版)之后,各 EDA 公司相继推出了自己的 VHDL 设计环境,或宣布自己的设计工具可以提供 VHDL 接口。此后 VHDL 在电子设计领域逐步取代了原有的各种非标准硬件描述语言。
1993 年,IEEE 对 VHDL 进行了修订,从更高的抽象层次和系统描述能力上扩展 VHDL 的内容,并公布了新版本的 VHDL,即 IEEE 标准的 1076-1993版本(简称 93 版)。
现在,VHDL 和 Verilog HDL 作为 IEEE 的工业标准硬件描述语言,在电子工程领域已成为事实上的通用硬件描述语言。
VHDL 的特点
VHDL 主要用于描述数字系统的结构、行为、功能和接口。除了含有许多具有硬件特征的语句外,VHDL 在语言形式、描述风格和句法上与一般的计算机高级语言十分相似。VHDL 的程序结构特点是将一项工程设计,或称设计实体(可以是一个元件、一个电路模块或一个系统)分成外部和内部两部分。
外部也可称为可视部分,它描述了此模块的端口,而内部可称为不可视部分,它涉及到实体的功能实现和算法完成。在对一个设计实体定义了外部端口后,一旦其内部开发完成,其他的设计就可以直接调用这个实体。这种将设计实体分成内外部分的概念是VHDL 系统设计的基本点。
1.行为描述
与其他的硬件描述语言相比,VHDL 具有更强的行为描述能力,强大的行为描述能力是避开具体的器件结构,从逻辑行为上描述和设计大规模电子系统的重要保证。
2.仿真模拟
VHDL 丰富的仿真语句和库函数,使得在任何系统的设计早期就能查验设计系统的功能可行性,随时可对设计进行仿真模拟。
3.大规模设计
一些大型的 FPGA 设计项目必须有多人甚至多个开发组共同并行工作才能实现。VHDL 语句的行为描述能力和程序结构决定了它具有支持大规模设计的分解和已有设计的再利用功能。
4.门级网表
对于用 VHDL 完成的一个确定的设计,可以利用 EDA 工具进行逻辑综合和优化,并自动把VHDL 描述设计转变成门级网表。
5.独立性
VHDL 对设计的描述具有相对独立性,设计者可以不懂硬件的结构,也不必对最终设计实现的目标器件有很深入地了解。
让我们考虑一个简单的数字电路,如图所示。
此图显示有两个输入端口 a 和 b,以及一个输出端口 out1。该图表明输入和输出端口是一位宽。该电路的功能是对两个输入进行“与”运算并将结果放在输出端口上。
VHDL 使用类似的描述;但是,它有自己的语法。例如,它使用以下代码行来描述该电路的输入和输出端口:
1 entity circuit_1 is
2 Port ( a : in STD_LOGIC;
3 b : in STD_LOGIC;
4 out1 : out STD_LOGIC);
5 end circuit_1;
让我们逐行分解这意味着什么。
第 1 行:代码的第一行指定要描述的电路的任意名称。位于关键字“entity”和“is”之间的单词“circuit_1”决定了该模块的名称。
第 2 到 4 行:这些行指定电路的输入和输出端口。将这些线路与图 1 的电路进行比较,我们看到电路的端口及其特性列在关键字“端口”之后。例如,第 3 行说我们有一个名为“b”的端口。该端口是一个输入,如冒号后的关键字“in”所示。
关键字“std_logic”指定了什么?正如我们将在本文后面讨论的那样,std_logic 是 VHDL 中常用的数据类型。它可以用来描述一位数字信号。由于图 1 中的所有输入/输出端口都将传输 1 或 0,因此我们可以对这些端口使用 std_logic 数据类型。
第 5 行:此行确定“实体”语句的结束。
因此,代码的实体部分指定了 1) 要描述的电路的名称和 2) 电路的端口及其特性,即输入/输出和这些端口要传输的数据类型。代码的实体部分实际上描述了模块与其周围环境的接口。由讨论的“实体”语句指定的上述电路的特征在图 1 中以绿色显示。
除了电路与其环境的接口之外,我们还需要描述电路的功能。在图 1 中,电路的功能是对两个输入进行“与”运算并将结果放在输出端口上。为了描述电路的操作,VHDL 添加了“架构”部分并将其与实体语句定义的电路_1 相关联。
第 6 行:此行为将在下一行中描述的架构命名为“行为”。该名称位于关键字“architecture”和“of”之间。它还将这种架构与“电路_1”相关联。换言之,该架构将描述“电路_1”的操作。
第 8 行: 这指定了架构描述的开始。
第 9行 第 9 行使用 VHDL 的语法来描述电路的操作。两个输入 a 和 b 的 AND 在括号内,结果使用赋值运算符“<=”赋值给输出端口。
第 10 行 这指定了架构描述的结尾。如上所述,这些代码行描述了电路的内部操作,这里是一个简单的与门。
将我们到目前为止讨论的内容放在一起,我们几乎完成了用 VHDL 描述“Circuit_1”。我们得到以下代码:
1 entity circuit_1 is
2 Port ( a : in STD_LOGIC;
3 b : in STD_LOGIC;
4 out1 : out STD_LOGIC);
5 end circuit_1;
6 architecture Behavioral of circuit_1 is
8 begin
9 out1 <= ( a and b );
10 end Behavioral;
但是,我们仍然需要添加几行代码。这些行将添加一个包含一些重要定义的库,包括数据类型和运算符的定义。一个库可能由多个包组成。我们必须使给定库的所需包对设计可见。
由于上述示例使用数据类型“std_logic”,我们需要将“ieee”库中的“std_logic_1164”包添加到代码中。请注意,std_logic 数据类型的逻辑运算符也在“std_logic_1164”包中定义——否则我们必须使相应的包对代码可见。最终代码将是
1 library ieee;
2 use ieee.std_logic_1164.all
3 entity circuit_1 is
4 Port ( a : in STD_LOGIC;
5 b : in STD_LOGIC;
6 out1 : out STD_LOGIC);
7 end circuit_1;
8 architecture Behavioral of circuit_1 is
9 begin
10 out1 <= ( a and b );
11 end Behavioral;
在这里,我们创建两条新线以超越我们已经创建的内容。第一行添加库“ieee”,第二行指定需要此库中的包“std_logic_1164”。由于“std_logic”是一种常用的数据类型,我们几乎总是需要将“ieee”库和“std_logic_1164”包添加到VHDL代码中。
1.四类语言要素:
数据对象(Data Object)
变量(Variable)
物理含义:
暂存某些值的载体,常用于描述算法
局部量,定义于process、function、procedure
具体说明:
变量说明格式
variable 变量名:数据类型 约束条件:= 表达式;
如:variable a, b : bit;
variable count : integer range 0 to 255 := 10;
局部量,只能在进程和子程序中定义、使用,其作用范围仅局限于定义变量的进程和子程序中。
变量的初值可用于仿真,但综合时被忽略
常量(Constant)
物理含义:
电源、地、恒定逻辑值等
全局量,可定义于上面两种场合
常量说明:
对某一个常量名赋予一个固定的值
constant 常数名:数据类型:= 表达式;
constant data: bit_vector(3 downto 0):=“1010”
constant width: integer: = 8;
constant x: new_bit: = ‘x’;
常量数据类型必须与表达式的数据类型一致
常量是全局量,其作用范围取决于常量被定义的位置。
信号(Signal)
物理含义:
是硬件连接线,端口
全局量,定义于architecture、package、entitiy
具体说明:
电子硬件系统运行的基本特性
各部分电路工作的并行特性;
信号传输过程中的延时特性;
多驱动源的总线特性;
时序电路中触发器的记忆特性
信号是电子系统内部硬件连接和硬件特性的抽象表示:
signal 信号名:数据类型 约束条件:= 表达式;
如:signal s2 : std_logic_vector(15 downto 0);
综合时初值被忽略
信号是全局量,可在结构体、实体、块中 说明和使用信号
在进程和子程序中只能使用信号,不能说明信号
信号与端口的区别:信号本身无方向,可读可写;端口是一种有方向的隐形信号
数据类型(Data Type)
VHDL是一种强数据类型语言
设计实体中每一个常数、信号、变量、函数以及设定的各种参量都必须事先说明数据类型
同类型才能互相传递和作用
操作数(Operands)
操作对象常量或变量
逻辑操作符(Logical Operator)
6种:and、or、nand、nor、xor、not
操作数类型必须相同,可为如下类型:bit、bit_vector、std_logic、std_logic_vector、boolean,数组操作数的维数、大小必须相同
关系操作符(Relational Operator)
用于比较相同父类的两个操作数,返回boolean值
6 种:=、/=、<、<=、>、>=
算术操作符(Arithmetic Operator)
加操作符“+”、减操作符“-”
串联(并置)操作符“&”:通过连接操作数来建立新的数组。操作数可以是一个数组或数组中的一个元素.
重载操作符(Overloading Operator)
仅有一个操作数的操作符,包括:“+”、“-”
乘除操作符
用于整数类型:“*”、“/”、“mod”、“rem”
综合的限制:“/ ”、“mod”、“rem” 三种操作符的右操作数必须为 2 的正整数次幂,即 2n。实际电路用移位实现。
A rem B 余数运算符,利用操作数A决定结果的正负号;A mod B 取模运算符,利用操作数B决定结果的正负号。