VHDL语法学习笔记:一文掌握VHDL语法

您所在的位置:网站首页 VHDL中的赋值语句用等号表示 VHDL语法学习笔记:一文掌握VHDL语法

VHDL语法学习笔记:一文掌握VHDL语法

2024-01-02 07:44| 来源: 网络整理| 查看: 265

今天给大侠带来FPGA 之 VHDL 语法学习笔记,话不多说,上货。

 

 

VHDL语法学习笔记

 

 

一、VHDL简介

1.1 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 的工业标准硬件描述语言,在电子工程领域已成为事实上的通用硬件描述语言。

 

 

1.2 VHDL 的特点

VHDL 主要用于描述数字系统的结构、行为、功能和接口。除了含有许多具有硬件特征的语句外,VHDL 在语言形式、描述风格和句法上与一般的计算机高级语言十分相似。VHDL 的程序结构特点是将一项工程设计,或称设计实体(可以是一个元件、一个电路模块或一个系统)分成外部和内部两部分。

外部也可称为可视部分,它描述了此模块的端口,而内部可称为不可视部分,它涉及到实体的功能实现和算法完成。在对一个设计实体定义了外部端口后,一旦其内部开发完成,其他的设计就可以直接调用这个实体。这种将设计实体分成内外部分的概念是VHDL 系统设计的基本点。

应用 VHDL 进行工程设计有以下的优点:

1.行为描述

与其他的硬件描述语言相比,VHDL 具有更强的行为描述能力,强大的行为描述能力是避开具体的器件结构,从逻辑行为上描述和设计大规模电子系统的重要保证。

2.仿真模拟

VHDL 丰富的仿真语句和库函数,使得在任何系统的设计早期就能查验设计系统的功能可行性,随时可对设计进行仿真模拟。

3.大规模设计

一些大型的 FPGA 设计项目必须有多人甚至多个开发组共同并行工作才能实现。VHDL 语句的行为描述能力和程序结构决定了它具有支持大规模设计的分解和已有设计的再利用功能。

4.门级网表

对于用 VHDL 完成的一个确定的设计,可以利用 EDA 工具进行逻辑综合和优化,并自动把VHDL 描述设计转变成门级网表。

5.独立性

VHDL 对设计的描述具有相对独立性,设计者可以不懂硬件的结构,也不必对最终设计实现的目标器件有很深入地了解。

 

 

 

 

二、VHDL 程序基本结构

一般的 VHDL 程序可以由实体(Entity)、结构体(Architecture)、配置(Configuration)、程序包和程序包体(Package)以及库(Library)5 个部分组成,它们是 VHDL 程序的设计单元。

其中实体、配置和程序包属于初级设计单元,主要的功能是进行端口、行为、函数等的定义。结构体和程序包体是次级设计单元,包含了所有行为以及函数的实现代码。其中,程序包和程序包体又属于公用设计单元,即它们是被其他程序模块调用的。库则是一批程序包的集合。

图 1 所示为 VHDL 程序设计单元之间的关系。

 

图 1 VHDL 程序设计单元关系图

 

无论是复杂的还是简单的数字模块,用 VHDL 来描述都至少需要包括两个部分,即实体申明(Entity Declaration)和结构体(Architecture)。其中实体申明用于说明模块的端口,而结构体用于描述模块的功能。本节下面将详细介绍 VHDL 程序的各个设计单元。

 

 

2.1 实体的申明方法

实体是设计的基本模块和设计的初级单元,在分层次设计中,顶层有顶级实体,含在顶级实体中的较低层次的描述为低级实体,通过配置可把顶层实体和底层实体连接起来。可以将实体理解为电路图设计中的芯片符号(Symbol),符号规定了电路的符号名、接口和数据类型。由连线(或信号)将符号互连建立设计所需的电路图,互连线生成的网表,在设计实现之前一直是设计验证的仿真模型,并在设计验证后,由网表向布线工具提供所需的连接信息和层信息。

图 2 所示是传统设计中 R-S 触发器的符号图,用 VHDL 对其进行描述的代码如下:

ENTITY rsff IS PORT ( Set, Reset : IN BIT; Q, QB : BUFFER BIT ); END rsff;

 

图 2 R-S 触发器的 VHDL 实体描述和符号

 

实体语句用关键词 ENTITY 开头,实体名 rsff 是描述的符号名,在结束实体语句的 END rsff之间,实体语句可以用关键词 BEGIN 把实体语句分成两部分:即 BEGIN 之前是实体说明,BEGIN之后是实体语句。

在 ENTITY 语句的实体说明部分,常用 PORT 付语描述实体对外界连接的端口(数目、方向和数据类型)。实体 rsff 有 4 个端口,Set/Reset 是输入 IN 模式,Q/QB 是输出BUFFER(缓冲)模式,都为 BIT 类型。实体说明中还可说明数据类型、子程序和常量等数据信息,实体语句常用于描述设计经常用到的判断和检查信息。

实体描述的格式如下:

ENTITY 实体名 IS [GENERIC(参数表);] [PORT(端口表);] [BEGIN 实体语句部分;] END [ENTITY] [实体名];

 

其中,GENERIC 是用于说明设计实体和其外部环境通信的对象,规定端口的大小、实体中子元件的数目、实体的延时特性等。只能用整数类型表示,如整型、时间型等,其他类型的数据不能逻辑综合。格式如下:

GENERIC ([CONSTANT]属性名称:[IN]子类型标识[:=静态表达式],……);

 

PORT 关键字用于定义模块的端口,它的格式如下:

PORT( [SIGNAL] 端口名称:[方向]类型标识[BUS] [:=静态表达式], [SIGNAL] 端口名称:[方向] 类型标识[BUS] [:=静态表达式], … [SIGNAL] 端口名称:[方向] 类型标识[BUS] [:=静态表达式]);

 

• SIGNAL:SIGNAL 是关键字,但是由于 PORT 之后必须是信号类,所以一般可以将 SIGNAL关键字省略。

• 端口名称:是该端口的标识,通常由英文字母和数字组成,但是必须是英文字母打头。

• 方向:定义了端口是输入还是输出,如 IN、OUT。表明端口方向的关键字如表1所示。

• 类型标识:说明流过该端口的数据类型,常用的数据类型有 BIT(位)、BIT_VECTOR(位向量)、BOOLEAN(布尔型)和 INTEGER(整数型)4 种。

• BUS 关键字:在该端口和多个输出端相连的情况下使用。

 

表 1 端口方向关键字说明表

 

 

2.2 结构体的描述方法

结构体描述实体的行为功能,一个实体可以有多个结构体。结构体是一个基本设计单元,它具体地指明了所设计模块的行为、元件及内部的连接关系,也就是说它定义了设计单元具体的功能。结构体对其基本设计单元的输入/输出关系可以用 3 种方式进行描述,即行为描述(基本设计单元的数学模型描述)、寄存器传输描述(数据流描述)和结构描述(逻辑元件连接描述)。

不同的描述方式只体现在描述语句上,而结构体的结构是完全一样的。由于结构体是对实体功能的具体描述,因此它一定要跟在实体的后面。通常,先编译实体之后才能对结构体进行编译。如果实体需要重新编译,那么相应结构体也应重新进行编译。

结构体的格式如下:

ARCHITECTURE 结构体名 OF 实体名 IS [定义语句] BEGIN [并行处理语句] END 结构体名;

 

定义语句用于对结构体内部所使用的信号、常数、数据类型和函数等进行定义。信号定义和端口说明的语句一样,应有信号名和数据类型的说明,但因它是内部连接用的信号,故没有也不需有方向的说明。并行处理语句具体地描述了结构体的行为及其连接关系,它们都是可以并行执行的。

以上面介绍的 R-S 触发器为例。假设已经有一个实现了与非功能的模块 nand2,用它实现R-S 触发器的原理图如图 3 所示。

 

图 3 R-S 触发器的实现原理图

 

对应以上原理图的结构体描述如下:

library IEEE;use IEEE.std_logic_1164.all;​ENTITY rsff isPORT ( set, reset: in bit; q, qb: buffer );END ENTITY;​ARCHITECTURE arch_rsff OF rsff IS COMPONENT nand2 PORT ( a, b : IN BIT; c: OUT BIT);      END COMPONENT;     BEGIN U1: nand2 PORT MAP (set, qb, q); U2: nand2 PORT MAP (reset, q, qb);END arch_rsff;

 

上面的代码中,以关键字 ARCHITECTURE 作为结构体的开头,结构体名为 arch_rsff,表示描述 rsff 实体的结构体 arch_rsff。ARCHITECTURE 和 BEGIN 之间是结构体说明区, BEGIN和 END 之间是结构体语句区。结构体说明区描述组件(COMPONENT)和局部信号,结构体语句中用的具体元件(上例是 nand2)均应在结构体说明中说明接口,以便将描述的信息通知给编辑器。

如果设计者希望将模块分为若干个相对比较独立的子模块进行描述,可以将一个结构体用几个子结构来构成。VHDL 结构体描述常常用到 3 种语句结构:PROCESS 语句结构、BLOCK 语句结构和子程序结构。

 

1).PROCESS 语句结构

进程语句是一种并发处理语句,在一个结构体中多个 PROCESS 语句可以同时并行运行(相当于多个 CPU 同时运作)。PROCESS 语句是 VHDL 语言中描述硬件系统并发行为的最基本语句。

 

PROCESS 语句归纳起来有如下几个特点:

• 它可以与其他进程并发运行,并可存取结构体或实体号中所定义的信号;• 进程结构中的所有语句都是按顺序执行的;

• 为启动进程,在进行结构中必须包含一个显式的敏感信号量表或包含一个 WAIT 语句;

• 进程之间的通信是通过信号量传递来实现的。

 

PROCESS 语句的格式如下:

[进程名]:PROCESS(信号 1,信号 2,…)BEGIN…END PROCESS;

 

一般情况下进程名可以被省略。进程申明关键字 PROCESS 后面括号内的信号是此进程的敏感信号,这些信号的变化会激活过程的执行。例如下面的代码就表示过程 main_proc 在信号clk 和 reset 变化时执行:

library IEEE;use IEEE.std_logic_1164.all;​ENTITY counter is PORT ( clk, reset: in bit; c: out bit );END ENTITY;​ARCHITECTURE arch of counter isBEGIN main_proc: PROCESS(clk, reset) BEGIN if (reset = '1') then … end if; END PROCESS;END

 

在进程中也可以定义一些变量,这些变量是局部量,只能在进程内部使用,它们的赋值是立即生效的。局部变量定义的格式如下:

VARIABLE 变量名:数据类型 [约束条件] [:=表达式];

 

下面的代码演示了定义一个局部变量并且使用它的方法:

library IEEE;use IEEE.std_logic_1164.all;​ENTITY counter is PORT ( a: in bit; c: out bit );END ENTITY;​ARCHITECTURE arch of counter isBEGIN main_proc: PROCESS(a) VARIABLE item:array0(7 downto 0); --定义一个变量 item BEGIN item(7):=a; c2) THEN…这个判断运算,当 a=0 时,后面的判断不再继续,避免出现除数为 0 的运算。

VHDL 的逻辑运算符如表 6 所示。

表 6 VHDL 逻辑运算符

 

2).关系运算符

关系运算符两边必须为相同的类型,其结果为 boolean 类型。

等号(=)和不等号(/=)两边可以为任意类型的运算对象。其他关系运算符的运算对象必须为标量类型或离散类型的一维数组。对于复杂的运算对象,如数组,两个值相等意味着两个值的所有对应元素相等。VHDL 的关系运算符如表 7 所示。

表 7 VHDL 关系运算符

 

3).算术运算符

算术运算符包括一些基本的算术运算,使用算术运算符需要注意的是乘方(**)运算的右边必须为整数。VHDL 的算术运算符如表 8 所示。

表 8 VHDL 算术运算符

 

4).移位运算符

移位运算符为二元运算符,左边必须为一维数组,且元素类型为 bit 或 boolean 类型。右边运算数为整数,可以为负数,相当于反方向移位。一位移位与循环移位的语义示意如图 5 所示。

图 5 一位移位与循环移位示意图

 

VHDL 的移位运算符如表 9 所示。

表 9 VHDL 移位运算符

 

除了上面介绍的,VHDL 中运算符还包括正号“+”、负号“-” 以及“&”。其中,连接符号(&)用于一维数组,这个数组的元素个数可以为 1,运算结果为右边数组连接在左边数组之后形成新数组,例如:

sel = 20 ns) REPORT "setup violation" SEVERITY WARNING; END IF; END IF; END PROCESS;

 

3).IF 语句

IF 语句是根据所指定的条件来确定执行哪些语句,其格式如下:

IF condition THEN sequence_of_statementsELSIF condition THEN sequence_of_statementsELSE sequence_of_statementEND IF;

 

IF 语句用关键字 IF 开头和用关键字 END IF 结尾,END IF 分开拼写。有两个可选付句(ELSIF付句和 ELSE 付句),ELSIF 付句可重复并允许有多个 ELSIF 付句,可选 ELSE 付句但只允许有一个 ELSE 付句。付句中的条件是一布尔表达式,如条件为真值,则下一语句被执行;如果条件不为真,那么接着执行跟在 ELSE 付句后的顺序语句。

下面举一个 IF 语句的使用例子,如下:

IF (day = sunday) THEN weekend := TRUE;ELSIF (day = saturday) THEN weekend := TRUE;ELSE weekday := TRUE;END IF;

 

以上代码的意义如下:有两个变量 weekend 和 weekday,每当 day 等于 saturday 或 sunday时变量 weekend 变为真,执行跟着的下一句并控制转到跟在 END IF 之后的语句,否则转到 ELSIF语句部分并检查 day 是否为 Saturday;当变量 day 等于 saturday,执行跟着的下一句并再次控制转到跟在 END IF 之后的语句;若 day 并不等于 sunday 或 saturday,执行 ELSE 语句部分。

 

4).CASE 语句

当单个表达式的值在多个起作用的项中选择时用 CASE 语句。CASE 语句的格式如下:

CASE expression IS WHEN choice1 => sequence_of_statements WHEN choice2 | choice3 => sequence_of_statements … WHEN OTHERS => sequence_of_statementsEND CASE;

 

下面是一个使用 CASE 语句执行处理器指令的例子:

CASE instruction IS WHEN load_accum => accum data_out process_IO(addr); WHEN OTHERS => process_error(instruction);END CASE

 

5).循环语句

当需要重复操作时用循环语句,或者实现的模块需要很强的迭代能力时用循环语句:

[循环标示 :] [循环条件] LOOP 顺序处理语句END LOOP[LOOP_label];

 

其中循环条件可以用 WHILE 语句或者 FOR 语句来描述。WHLIE 语句有一个循环控制的条件 condition,只要条件表达式为真,WHILE 循环语句就一直执行下去,除非要退出循环。例如:

WHILE (day = weekday) LOOP day := get_next_day(day);END LOOP

 

FOR 循环是根据预先的设定进行迭代,所指定的范围并不一定必须为整数值,也可以表示成一个子类型的指示或者一个范围语句,例如:

PROCESS (clk) TYPE day_of_week IS (sun,mon,tue,wed,thur,fri,sat);BEGIN FOR i IN day_of_week LOOP IF i = sat THEN son


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3