您现在的位置:首页 > >

第5讲第5章硬件描述语言VHDL

发布时间:

原理图设计方法:设计人员普遍熟悉并使用直观的原理图描述方法进行系统设计,随着数字 系统设计规模日益增大、复杂程度日益提高,如果仍然采用图形方式描述电路,设计工作的 周期长、成本高,无法满足快速高效的设计要求。 硬件描述语言设计方法:为了满足设计人员对抽象层次更高的电路描述需求,硬件描述语言 (HDL:Hardware Description Language)应运而生。

HDL优势:具有对系统的高层次描述功能,为数字系统设计提供了强大的灵活性和通用性,
有效地缩短了设计周期,降低了设计成本。 HDL标准化:20年代80年代后期,硬件描述语言向着标准化、集成化的方向发展,其中 VHDL和Verilog HDL先后成为IEEE标准。 超高速集成电路硬件描述语言VHDL:Very High Speed Integrated Circuit Hardware Description Language简称VHDL,是最早被接纳为IEEE标准的硬件描述语言。VHDL由美国 国防部组织开发,1987年被IEEE确认为IEEE1076标准,1993年升级为IEEE1164标准。 本章介绍VHDL:介绍VHDL程序结构、语法规则、常用语句。相信通过硬件描述语言的学 习,你会发现硬件电路的设计,原来也可以如同软件设计一样,方便修改和完善。通过本章 的学习,将为顺利完成FPGA设计应用打下良好的设计基础。

第5章 硬件描述语言VHDL
5.1 VHDL 程序结构 5.2 VHDL 语法规则 5.3 VHDL并行语句 5.4 VHDL 顺序语句

★ 硬件描述语言 ◆ ABEL ◆ AHDL ◆ Verilog HDL IEEE标准 ◆ VHDL 美国国防部在80年代初提出了VHSIC(Very High Speed Integrated Circuit)计划,其目标之一是为下一代集成电路的 生产,实现阶段性的工艺极限以及完成10万门级以上的设计, 建立一项新的描述方法。1981年提出了一种新的HDL,称之为 VHSIC Hardware Description Language,简称为VHDL。

★ VHDL语言的主要优点 ◆ 是一种多层次的硬件描述语言,覆盖面广,描述能 力强。即设计的原始描述可以是非常简练的描述, 经过层层细化求精,最终成为可直接付诸生产的电 路级或版图参数描述,整个过程都可以在VHDL的 环境下进行。 ◆ VHDL 有良好的可读性,即可以被计算机接受,也 容易被理解用VHDL 书写的原文件,即是程序,又 是文挡,即是技术人员之间交换信息的文件,又可 作为合同签约者之间的文件。

★ VHDL语言的主要优点 ◆ VHDL本身的生命期长。因为VHDL的硬件描述与工艺 技术无关,不会因工艺变化而使描述过时。与工艺技术 有关的参数可通过VHDL提供的属性加以描述,工艺改 变时,只需修改相应程序中的属性参数即可。 支持大规模设计的分解和已有设计的再利用。一个大规 模设计不可能一个人独立完成,它将由多人,多项目组 来共同完成。VHDL为设计的分解和设计的再利用提供 了有力的支持。 VHDL已成为IEEE承认的一个工业标准,事实上已成 为通用硬件描述语言。





5.1 VHDL程序结构
VHDL可以描述什么:一个系统、一个单元模块或一个门电路都可以。 VHDL程序结构:无论VHDL描述的电路复杂还是简单,一段VHDL程序包含五个部 分:实体entity、结构体architecture、库library、配臵configuration和包package。 实体entity:描述电路和系统的输入、输出端口等外部信息。 结构体architecture:描述电路和系统的功能信息,对系统的结构或行为的具体描述。 库library:库中存放的是已经编译过的实体、结构体、配臵和包,库可以由设计者自 己生成,也可以由ASIC制造商或其他公司提供。放在VHDL程序段的最前面。 配臵configuration:完成对库的使用,从库中选择需要的单元完成自己的设计方案。 包package:存放共享数据、常数和子程序等。 VHDL程序结构必须有的两个部分:在五个组成部分中,实体和结构体是必不可少的, 其余的部分可以根据需要选用。

VHDL的基本组成
参数部分——library库

VHDL 语言

接口部分—设计实体

描述部分—结构体

5.1.1 library库
1.库的用途:库是一个集合,专门用来存放已经编译过的实体、结构体,库可以由设 计者自己生成,也可以由其他公司提供。 2.库的种类:VHDL中有五类库:IEEE库、STD库、ASIC库、WORK库和用户自定

义库。
IEEE库:存放IEEE标准1076中的标准包集合,如std_logic_1164,std_logic_arith和 std_logic_unsigned等。 STD库:存放VHDL的标准数据类型,如Boolean等数据类型的定义等,包括输入/输

出两个标准程序包,由于STD库是VHDL的标准配臵,可以不用进行库的说明,STD
库对VHDL程序均是可见的。 WORK库:用于存放用户设计和定义的设计单元和程序包,保存当前进行的设计. 只要在VHDL的应用环境中,都可以随时调用STD库和WORK库,所以不需专门的调 用语句。 ASIC库:存放与逻辑门对应的实体,目的是为了进行门级仿真。在 FPGA/CPLD的设计中一般都不需要VITAL库的程序包。 用户自定义库:存放用户自己定义的实体集合,使用前必须首先进行库的说明。

3.库的说明 库说明语句如下:
USE 库名.程序包名.项目名 USE 库名.程序包名.ALL 调用程序包 语句

LIBRARY ieee; USE ieee.std_logic_1164.all;
标 准 程 序 包

定 义 程 序 包

在VHDL语言中,库的说明通常放在实体描述的最前面。 注意:多数情况下,只有对库进行说明,设计者才能使用 库集合中已经定义的数据。

4.库的使用

五类库中除了WORK和STD库,其它三类库在使用之前需要进行库的说明,还
要说明使用库中的哪个包集合。 库使用举例:为了使用IEEE库中的std_logic_1164、std_logic_arith和

std_logic_unsigned程序包,应使用下列语句:
library IEEE; use IEEE.std_logic_1164.all; --使用IEEE库 --使用IEEE库std_logic_1164程序包所有设计单元

use IEEE.std_logic_arith.all;

--使用IEEE库std_logic_arith程序包所有设计单元

use IEEE.std_logic_unsigned.all; --使用IEEE库std_logic_unsigned程序包所有设计单元

注意:如果使用std_logic和std_logic_vector,必须在实体描述前写出下面的库说 明和使用包集合的说明语句:

5.1.2 entity实体
entity实体:用来描述设计的对外端口信息,如输入和输出端口 的描述,也可以描述参数化的数值。提供设计模块的公共信息,

是VHDL设计电路的最基本部分。
1. entity实体描述格式 entity 实体名 is [generic(类属表);] [port(端口表);] [declarations说明语句;] [begin 实体语句部分];

end [实体名];

[ ]表示其中的部分是可选项。

1. entity实体描述格式
实体语句的一般格式 ENTITY 实体名 IS [PORT(端口名)] END ENTITY 实体名

VHDL实体的描述方法:

调用程序包 b1 语句

a1

kxor

c1

ENTITY kxor IS PORT(a1,b1:IN std_logic;
实体 c1:OUT std_logic); 及实 体声 明语 句 标 准 程 序 包 定 义 程 序 包

END kxor;

设计实体说明 ENTITY kxor IS PORT(a1,b1:IN std_logic; c1:OUT std_logic); END kxor;
ENTITY、IS、PORT、IN、OUT和END为关键字; ENTITY...END之间表示实体内容; kxor表示实体的名称,即电路的符号名; PORT——端口(引脚)信息关键字,描述了信号的流向; std_logic表示信号取值的类型为标准逻辑。

2.端口表 端口表:用来说明设计实体对象的对外信息。 端口表书写格式: port (端口名{,端口名}:[方向] 子类型 [bus] [:=初始值] {;端口名{,端口名}:[方向] 子类型 [bus] [:=初始值]});

端口名是端口的标识符,端口方向表明数据通过该端口的流动方向,端口子类型说明端口
的数据类型。 端口很重要:端口是实体和外界通信的动态信息通道,每个端口都有端口名、端口方向以 及端口子类型。 例如:2选1数据选择器端口的VHDL描述如下: entity mux21 is port (d0,d1,sel: in bit; y: out bit); end mux21; --实体名:mux21 --输入信号:d0, d1, sel,均为bit数据类型 --输出信号:y,为bit数据类型 --实体描述结束

3.类属表
类属表:描述的是实体与外界通信的静态信息通道。类属表主

要用来规定端口的大小,实体中元件的数目,实体的定时特性
等。通常放在端口语句之前。

类属表的书写格式:
generic ([常量]名字表:[in]类属标识[:=初始值];…);

例如:generic(wide:integer:=32);
--说明wide为常数,其数值为整数32

3.端口方向 端口方向的四种模式:输入in、输出out、双向inout和缓冲buffer。缺省值是 输入。 输入in:输入仅允许数据由外部流向实体输入端口。主要用于时钟输入、复 位、使能,单向数据输入等输入信号的描述。 输出out:输出仅允许数据从实体内部流向实体输出端口,输出模式不能用 于反馈,因为输出端口在实体内部不可读。通常用于电路的各种输出,如计 数器、移位寄存器等输出信号描述。 双向inout:双向模式允许数据流入或流出实体,双向模式允许用于内部反馈。 双向模式可以替代其它任一模式,适合描述双向数据总线等。

缓冲buffer:缓冲模式通常用于内部有反馈需求的信号描述。 buffer与out类
似,只是buffer允许用于内部反馈,而out不能用于内部反馈。

Out与Buffer的区别
Entity test1 is port(a: in std_logic; b,c: out std_logic ); end test1; architecture a of test1 is begin b <= not(a); c <= b;--Error end a; Entity test2 is port(a: in std_logic; b : buffer std_logic; c: out std_logic ); end test2; architecture a of test2 is begin b <= not(a); c <= b; end a;

4.常用端口类型 常用端口类型:布尔boolean、位bit、位矢量bit_vector、整数integer、标准逻辑 std_logic和标准逻辑矢量std_logic_vector等。 布尔boolean:布尔类型的取值为“true”或“false”。 位bit:位类型的取值只有“0”或“1”。 位矢量bit_vector:位矢量是位类型的集合,基本元素是bit类型。 整数integer:整数常用来说明常数,不用来说明输入输出信号。 标准逻辑std_logic:标准逻辑由IEEE_std_logic_1164程序包支持,其取值有9种:0 (信号0)、1(信号1)、H(弱信号1)、L(弱信号0)、Z(高阻)、X(不定)、 W(弱信号不定)、U(初始值)和—(不可能情况)等。

标准逻辑矢量std_logic_vector:标准逻辑矢量是标准逻辑的集合,基本元素是
std_logic类型。 使用时注意:如果使用std_logic或std_logic_vector ,需要在实体前使用下述语句进行 说明: library IEEE; use IEEE_std_logic_1164.all;

设计实体举例
再例:
d0 d1 d2 d3

sel

out1

s

ENTITY sel IS PORT(d0,d1,d2,d3:IN BIT; s :IN INTEGER RANGE 0 TO 3; out1 :OUT BIT); END sel;

5.1.3 architecture结构体
结构体:是电路和系统的逻辑功 能描述部分。所有的结构体均附 属于该实体,是实体的说明。描 述实体硬件的互连关系、数据的 传输和变换以及动态行为。即描 述设计实体的内部结构和对外部 设计实体端口间的逻辑关系。 一个实体可以对应多个结构体, 每个结构体可以代表该硬件的 某一方面特性,例如行为特性, 结构特性。
调用程序包 语句

实体 及实 体声 明语 句

标 准 程 序 包

定 义 程 序 包

结 构 体 1

结 构 体 2

结 构 体 n

1.结构体描述格式
architecture 结构体名 of 实体名 is
[说明语句]; begin

[并行语句];
end [结构体名]; 结构体由两部分组成:begin前的说明语句部分和begin后的并行语句部分。 结构体名:是该结构体的唯一名称,of后面跟随的实体名表明该结构体对应 的是哪个实体,is表明结构体的命名结束。 说明语句:用于对结构体内部所用到的信号、常数和函数等的定义,其定义 只对结构体内部可见,即结构体内部可以使用。 并行语句:描述电路和系统并行发生的行为。有关结构体的说明语句和并行 语句在后面有详细的介绍。

结构体举例
当异或门的符号和外部端口a1、b1和c1确定之后,就要确定 实体的内部电路,使之与实体相对应。

ARCHITECTURE kxor_arc OF kxor IS BEGIN c1 <= (NOT a1 AND b1) OR (a1 AND NOT b1); END kxor_arc;
a1
b1

c1

a1
b1

kxor

c1

该例的完整程序
LIBRARY ieee;

USE ieee.std_logic_1164.all;
ENTITY kxor IS PORT(a1,b1:IN std_logic; c1:OUT std_logic); END kxor; ARCHITECTURE kxor_arc OF kxor IS BEGIN c1 <= (NOT a1 AND b1) OR (a1 AND NOT b1); END kxor_arc;

a1
b1

a1 a1 b1 a1 b1 a1 b1 a1 b1 a1 b1 a1 a1 b1 a1 b1 a1 b1 a1 b1 a1 b1 a1 b1 a1 b1 a1 b1 a1 b1 a1 b1 a1 b1 a1 b1 a1 b1 a1 b1 a1 b1 a1 b1 a1 b1
b1 b1

kxor

c1 c1 c1 c1 c1 c1 c1 c1 c1 c1 c1 c1 c1 c1 c1 c1 c1 c1 c1 c1 c1 c1 c1 c1

c1

结构体举例2(自学)
举例:二选一数据选择器的结构体描述。 architecture con of mux21 is signal tmp:bit; begin tmp<= (d0 and sel) or (d1 and (not sel)); --并行语句:关于数据选择 器的功能描述 --实体mux21的结构体con的描述 --说明语句:内部信号tmp的定义

y<=tmp;
end con;

--并行语句:内部信号的输出

在前面实体部分曾经定义了二选一数据选择器的端口,在结构体部分给出了

该数据选择器信号之间逻辑关系的描述。

举例:将实体和结构体举例的两部分程序联在一起,则实现二选一数据选择器完整的设计描述。
完整程序如下: entity mux21 is port (d0,d1,sel: in bit; y: out bit); end mux21; architecture con of mux21 is --实体mux21的结构体con的描述 --实体名:mux21 --输入信号:d0,d1,sel --输出信号:y

signal tmp:bit;
begin tmp<= (d0 and sel) or (d1 and (not sel)); y<=tmp; end con;

--说明语句:关于内部信号tmp的定义

--并行语句:关于数据选择器的功能描述 --并行语句:内部信号的输出

5.1.4 子程序
子程序:是在主程序调用它以后能将处理结果返回主程序的程序模块。子程序可以 反复调用,使用方便。调用子程序时首先需要对其初始化,再次调用时要再次初始 化,子程序内部的值不能保持。 子程序有两种:过程(procedure)和函数(function)。procedure和function有所不 同,前者的参数可以是输入in、输出out或双向inout属性的参数,其返回值可以是多

个,其返回值在声明语句中说明。后者的所有参数都是in属性,返回值只有一个,
在声明语句之外说明。 子程序内部语句:是顺序语句,有关顺序语句的介绍请参考5.4节。

1.过程 过程语句的书写格式: procedure过程名(参数1,参数2,…)is [定义语句]; begin [顺序语句]; end过程名;

举例:实现输入数据din的循环左移,根据输入s值确定循环左移的位数。
procedure shift ( din,s:in std_logic_vector; --输入信号s、din

signal dout:out std_logic_vector) is
variable sc:integer; begin sc:=conv_integer (s);

--输出信号dout
--整数变量sc --左移位数s的数据格式转换

for i in din’range loop
if (sc+i<=din’left) then dout (sc+i)<=din (i); else --实现循环左移

dout (sc+i-din’left)<=din (i);
end if; end shift;

使用过程之前,需要将初始值传递给过程的输入参数,启动过程的执行。执行结 束后,应当将输出值拷贝到过程调用者定义的变量或信号中。

2.函数

函数的书写格式:
function 函数名(参数1,参数2,…) return 数据类型名 is [定义语句]; begin [顺序语句]; return [返回变量名];

end [函数名];

由于函数中所有的参数都是输入信号,因此端口方向in可以省略。函数的输入值由调 用者拷贝到输入参数中,如果没有特别指定,在function语句中按常数处理。

举例:返回两数中的较小数值的函数描述。
function min (x, y: integer) return integer is begin if x<y then return x; else return y; end if; end min; 使用函数的方法:首先需要将函数集合到包(package)中,再利用use语句使包对设计成为可见、 可使用的,然后,在设计结构体中就可以直接使用函数了。 rerurn语句:既可以用于函数function内部,也可以用于过程procedure内部,用来结束当前函数 或过程体的执行。 关于函数的使用:读者可参考书中第7章7.4节 RC6算法设计实现,使用了大量的function,极大 地方便了复杂程序的设计描述。 --两数中较小的数返回 --函数min,有两个参数x和y --返回整数类型的数据

5.2 VHDL语法规则
VHDL语言与其它高级语言一样,编写程序时也要遵循一定的语法规则。 介绍的VHDL语言规则有:数据对象、数据类型、属性、基本运算符

5.2.1 数据对象
数据对象有四种类型:常数constant、信号signal、变量variable和文件 files类型。 数据对象的使用:常数constant、信号signal、变量variable属于可综合 的数据对象,文件files类型仅在行为仿真时使用。

1.对象说明
常数说明格式: constant 常数名表:数据类型 [:=表达式];

信号说明格式:
signal 信号名表:数据类型 [:=表达式]; 变量说明格式:

variable 变量名表:数据类型 [:=表达式];
注意:常数名表、信号名表和变量名表,用“,”隔开多个标识符。
举例: constant a1, a2: bit; signal out1, out2: std_logic_vector (3 downto 0); variable a, b, c: std_logic; --常数a1和a2均为bit类型 --信号out1, out2均为 std_logic_vector类型 --变量a, b, c均为std_logic类型

2.信号与变量 使用时应当特别注意:信号与变量都与一定的物理对象相对应,但是它们有许多不同之 处。 物理意义不同:信号对应电路设计中一条硬件连接线;变量与硬件没有直接对应关系, 变量通常用来暂存某些值。信号是全局量,可以用于进程之间的联系,变量是局部量, 只能在进程语句、函数语句和过程中使用。 赋值符号不同:信号赋值用“<=”符号;变量赋值用“:=”符号。 定义位臵不同:信号应当在结构体(architecture)、包(package)、实体(entity)的

说明语句定义。变量则在进程(process)、函数(function)和过程(procedure)的说
明部分定义。 附加延时不同:信号赋值语句执行时有可能附加延时。变量赋值语句执行时,没有延时 立刻执行。

下面有两个进程描述语句举例,进一步说明了信号与变量的不同之处。
例如:
process (a, b, c, d) begin d <= a; x <= b+d; d <= c; y <= b+d; end process; 程序执行的结果是:x = b+c; y = b+c。 -- a, b, c, d均定义为信号

程序分析:信号d先代入a,接着再代入c,但是并未进行处理,当进程中的所有语句执行完毕,
信号d最后代入的值c作为最终的数值,所以d中的数值是c。 程序执行的结果是:x = b+d =b+c; y = b+d =b+c。

例如:
process (a, b, c) variable d: std_logic; begin d := a; x <= b+d; d := c; -- a, b, c是信号 --d是变量

y <= b+d;
end process; 程序执行的结果是:x = b+a; y = b+c。 程序分析:由于d是变量,没有延时立即执行,因此执行语句d := a 后,a的值赋给d,所以在 执行语句x <= b+d后,x = b+a;接着又执行语句d := c,c的值又赋给d,所以执行语句y <= b+d之后,y = b+c。 程序执行的结果是:x = b+d= b+a; y = b+d =b+c。

5.2.2 数据类型
VHDL的数据类型: VHDL中的每个数据对象都具有特定的数据类型,数据
对象进行的操作类型必须与其数据类型相匹配,不匹配时必须使用转换函数。

VHDL提供的数据类型:多种标准数据类型以及用户自定义的数据类型。
介绍的内容:标准数据类型、用户自定义数据类型、数据类型之间的转换。

1.标准数据类型
标准数据类型有10种:这些数据类型及其含义如表所示。 使用时应当注意:不是所有的综合工具都支持上述10种标准数据类型。QuartusII综 合工具不支持实数、时间、错误等级和字符串等数据类型。

标准数据类型 整数(integer) 实数(real) 位(bit) 位矢量(bit_vector) 布尔量(boolean) 浮点数,-1.0E+38~+1.0E+38 逻辑“0”或“1” 位矢量,元素为bit 逻辑“true”或逻辑“false”

含 义 整数32位,-2147483647~+2147483647(-(231-1) ~+(231-1))

字符(character)
时间(time) 错误等级(severity level) 自然数(natural) 正整数(positive) 字符串(string)

ASCII字符
时间单位fs,ps,ns,μs,ms,sec,min,hr NOTE(注意), MARNING(警告), ERROR(出错), FAILURE(失败) 整数的子集。自然数是大于等于0的整数 正整数是大于0的正整数 字符矢量

2.用户定义的数据类型

在VHDL语言的使用过程中,可以由用户自己定义数据类型。
用户定义的数据类型书写格式: type数据类型名 {,数据类型名} is 数据类型定义; 可以由用户定义的数据类型有:枚举类型、整数类型、实数和浮点数类型、数组类型、 存取类型、文件类型、记录类型和物理类型等。 这里介绍:QuartusII综合工具支持的常用用户定义数据类型。

(1)整数类型
VHDL已经预定义的整数:从-(231-1)到+(231-1),即从-2147483647到+ 2147483647。整数和适用于整数的运算符VHDL已经预先定义,编写VHDL程序时 可以直接使用。 用户定义的整数类型:自定义的整数类型可以认为是VHDL预定义整数的一个子类。 书写格式: type 数据类型名 is 数据类型定义 约束范围; 例如: type a is integer range -63 to 63;

(2)枚举类型

枚举类型:是一种非常重要的数据类型,用于建立抽象的模型。设计者用枚举类型
严格地表达一个特定操作所需的值,枚举类型的所有值都由设计者自己定义。 枚举类型使用:枚举类型常用来定义状态机中的状态。

枚举类型格式:
type数据类型名is (元素,元素,…) 例如:
type states is(idle,decision,read,write);--数据states枚举类型定义,有4种取值。
枚举类型可以用于信号和变量的定义,例如: signal present_state,next_steate:states; --状态信号present_state,next_steate定义

variable present_state,next_steate:states; --状态变量present_state,next_steate定义

(3)数组类型 数组类型:相同类型的数据集合形成的数据类型就是数组类型。 数组类型格式: type 数组类型名 is array (范围) of 原数据类型名; 例如:

type big_word is array(0 to 63)of std_logic; --一维数组的定义
除定义一维数组外,还可以定义两维数组。 例如: type matrix_type is array(0 to 15)of std_logic_vector(0 to 31); 推荐使用:数组元素的排列即可以用升序(to),也可以用降序(downto)。推荐

使用后者。

(4)记录类型 记录类型:数组类型是同一类型数据集合形成的,而记录类型是将不同类型数据和数 据名组织在一起形成的新类型。 记录类型格式: type 数据类型名 is record

元素名:数据类型名;
元素名:数据类型名; …

end record;
例如: type opcode is(add,sub,mul,div); type instruction is record operator:opcode; op1:integer; op2:integer; end record; --枚举类型定义 --记录类型定义 --枚举类型元素 --整数类型元素 --整数类型元素 --结束记录类型定义

3.数据类型的转换 在VHDL语言中,数据类型的定义是非常严格的,不同数据类型的数据不能进行运算 和直接代入。为了进行运算和代入操作,必要时需要进行数据类型之间的转换。 数据类型的转换函数如表所示,转换函数通常由VHDL包集合提供,因此在使用转换 函数之前,使用library和use语句,使包集合可以使用。
包集合 函数名 to_stdlogicvector (a) std_logic_1164 to_bitvector (a) to_stdlogic (a) to_bit (a) conv_std_logic_vector (a,位长) conv_integer (a) conv_integer 功 能

由bit_vector转换为std_logic_vector 由std_logic_vector转换为bit_vector 由bit转换为std_logic 由std_logic转换为bit
由integer,unsigned,signed转换为std_logic_vector

std_logic_arith
std_logic_unsigned

由unsigned,signed转换为integer 由std_logic_vector转换为integer

例如:由std_logic_vector转换为integer的VHDL程序。 library IEEE; use IEEE.Std_logic_1164.all; --使用std_logic_1164包集合

use IEEE.Std_logic_unsigned.all;
Entity add3 is

--使用std_logic_unsigned包集合

port (data : in std_logic_vector (2 downto 0); … ); end add3; architecture ver1 of add3 is

signal in_data: integer range 0 to 5;
… begin in_data <= con_integer (data); … end ver1; --数据类型的转换

5.2.3 属性
属性问题:属性提供的是关于信号、类型等的指定特性。
这里介绍常用的属性:值类属性、函数类属性、范围属性

1.值类属性
值类属性:用于返回数据类型或数组类型的特定值,还可返回数组的长度或者类型的 最底边界。

值类属性表示:常用单引号’指定属性,单引号后面跟属性名,单引号前面是所附属
性的对象。 常用的值类属性:’left、’right、’high、’low、’length等。

例如:属性’left生成一个类型最左边的值;属性’right是生成一个类型最右边的值;
例如:属性’high生成一个类型的最大值;属性’low生成类型的最小值; 例如:属性’length生成限制性数组中的元素数。

需要注意的是:EDA综合软件不同对预定义属性的支持程度也各不相同,使用时应参
考特定的综合工具说明。

举例:

type count is integer range 0 to 127; type states is (idle,decision,read,write); type word is array (15 downto 0)of std_logic;

对上述数据类型求其属性及其返回值如表所示。
返回值 Count ’left=0 States ’left=idle Word ’left =15 Count ’right=127 States ’right =write ’right生成的是类型最右边的值 属性描述 ’left生成的是类型最左边的值

Word ’right =0
Count ’high=127 States ’high =write Word ’high =15 Count ’low=0 States ’low =idle Word ’low =0 Count ’length=128 States ’length =4 ’length生成的是限制性数组中元件数 ’low生成的是类型最小值 ’high生成的是类型最大值

Word ’length =16

2.函数类属性 最常用的函数类属性:’event。 ’event函数类属性:表明若属性对象有事件发生,则’event属性生成布尔值“true”。 ’event使用:常用来检查时钟边沿是否有效。

例如:
if clk’event and clk=’1’ then --判断是否发生clk信号变化且变化为1,即clk的上升沿 if clk’event and clk=’0’ then --判断是否发生clk信号变化且变化为0,即clk的下降沿

3.范围属性 最常用的范围属性:’ range ’ range范围属性:生成一个限制性数组对象的范围。 例如: signal word:bit_vector(10 downto 0); word’range =10 downto 0;

5.2.4 基本运算符
VHDL定义的运算符主要有: 算术运算符、关系运算符、逻辑运算符、赋值运算符、关联运算符和其它运算符。 运算符的优先级别: 优先级最高的是乘方(**)、取绝对值(abs)和非(not);其次是乘、除、取模、求 余;然后依次是正负号、连接符、移位运算符、关系运算符、逻辑运算符。

需要注意的是:
操作数的数据类型应当与操作符所要求的数据类型一致。EDA综合软件对运算符支 持程度各不相同,使用时应参考综合工具的说明。

类别

运算符

功能

数据类型

+
_ * / 算术运算符


减 乘 除

MOD
REM ** ABS + _

取模
取余 乘方 取绝对值 正 负

整数、实数、物理量

类别

运算符 AND OR NAND NOR XNOR NOT 与 或 与非 或非 同或 非 异或

功能

数据类型

逻辑运算符

XOR SLL

逻辑左移

逻辑型数据, 如:bit、std_logic

SRL
SLA SRA ROL ROR

逻辑右移
算术左移 算术右移 逻辑循环左移 逻辑循环右移

类别 =

运算符 相等

功能

数据类型

/=
关系运算符 < > <= >= 赋值运算符 <= := => 关联运算符 并臵运算符 &

不等
小于 大于 小于等于 大于等于 信号赋值 变量赋值 例化元件时用于 形参到实参的映 射 连接 bit、std_logic 整数、实数; std_logic等枚举类型

5.3 VHDL并行语句
并行语句:VHDL描述的实际系统中许多操作都是并行发生的,VHDL中的并行语句 就是用来描述这种并行发生的行为。

已经见过的并行语句:结构体就是由一至多个并行语句构成的,这些语句相互之间是
并行运行的,并行语句的书写顺序不代表其执行的顺序。 介绍常用的并行语句:信号赋值语句、 process进程语句、 black块语句、 component 元件例化语句、generate生成语句。

5.3.1 信号赋值语句
信号赋值语句主要有:一般信号赋值、条件信号赋值和选择信号赋值三种形式。
一般信号赋值语句格式:目的信号<=敏感信号表达式; 应当注意:信号赋值语句在结构体中,即在进程外部使用时,是并行信号赋值语 句,但是,如果在进程内部使用则是顺序信号赋值语句。
例如: architecture beha of a is begin out<=a (i); --结构体中,在进程外部,为并行信号赋值

end beha;
上述程序的描述与下面程序的描述相互等价。 architecture beha of a is begin

process (a, i )
begin out<=a (i); end process; end beha; --在进程内部,为顺序信号赋值

条件信号赋值语句格式: [标号] 目的信号名<= 表达式1 when 条件1 else 表达式2 when 条件2 else


表达式n; 当when后面的条件成立时,则对应表达式的值代入目的信号。

例5.1:使用when_else语句设计二选一数据选择器。
library IEEE; use IEEE.Std_logic_1164.all;

entity mux21_2 is
port (i0,i1,sel : in std_logic; y : out std_logic); end mux21_2;

architecture ver1 of mux21_2 is
begin y <= i0 when sel= '0' else

i1 when sel= '1';
end ver1;

选择信号赋值语句格式:

[标号] with 表达式 select
目的信号名<= 表达式1 when 条件1, 表达式2 when 条件2, 表达式n when条件n; 当when后面的条件成立时,则对应表达式的值代入目的信号。

例5.2:使用with_select语句设计二选一数据选择器。 library IEEE; use IEEE.Std_logic_1164.all; entity mux21_3 is port (i0,i1,sel : in std_logic; y : out std_logic); end mux21_3; architecture ver1 of mux21_3 is begin with sel select y <= i0 when '0' , i1 when '1', 'X' when others; --当条件不能全部列出时,必须使用该语句。 end ver1;

例5.1和例5.2采用不同的语句描述,描述的是相同功能的电路,其仿真结果也是一样的

5.3.2 process进程语句
process语句格式: [进程标号:] process [(敏感信号表)] [进程说明部分]; begin [顺序语句]; end process[进程标号];

敏感信号表:表中只要有一个信号发生变化,进程就会启动。
进程说明部分:可以说明数据类型、子程序、枚举、变量等。 进程语句使用:放在结构体begin后的并行语句,但是进程begin后的所有语句都是按 顺序依次执行的。 结构体中可以有多个进程:一个结构体中的多个process语句可以同时并发执行,进程 之间的数据通信是通过信号传递实现的。

例5.3:8D触发器设计 library IEEE; use IEEE.std_logic_1164.all; entity d8_logic is

port (clk: in std_logic;
d : in std_logic_vector (7 downto 0); q : out std_logic_vector (7 downto 0)); end d8_logic;

architecture behave of d8_logic is
begin process (clk) begin

--实体d8_logic的结构体描述
--进程的敏感信号是时钟信号clk

if (clk'event and clk= '1' ) then
q<=d; end if; end process;

--如果发生时钟的上升沿,执行q<=d操作

--进程结束

end behave;

--结构体结束

5.3.3
块语句格式: [块标号:] block [块头] [说明语句]; begin [并行语句]; end block [块标号];

black块语句

块头:主要用于信号的映射及参数的定义,通常通过generic、generic_map、port和 port_map语句实现。

说明语句:与结构体的说明语句相同。
块语句功能:块可以看作是结构体的子模块,或者看作系统的局部电路。

例5.4:使用block语句设计的半加器和半减器。 library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity block_example is port (a, b : in std_Logic; carry, sum, borrow, difference: out std_Logic); end block_example; architecture a of block_example is begin half_adder: block --半加器 begin sum <= a xor b; carry <= a and b; end block half_adder; half_Subtractor: block -- 半减器 begin difference <= a xor b; borrow <= not a and b; end block half_subtractor; end a; 注意:block_example实体的2输入4输出,对于该实体结构体中所有block块,这些信号都可用。

5.3.4

component元件例化语句

元件语句:分为元件说明语句和元件例化语句,元件说明和元件例化语句的使用

是构成层次化设计的重要途径。
元件说明语句:将预先设计好的实体定义为一个底层元件。 元件例化语句:将元件说明语句定义的元件与另一设计实体中的端口相连接,为 该设计实体引入一个底层设计元件,从而形成层次化设计。

元件语句格式分为两部分:元件说明语句格式和元件例化语句格式。 元件说明语句格式: component 元件名 [generic(类属表);] [port(信号表);] end component; 元件例化语句格式: [元件标号:] 元件名port map (信号映射); 信号映射:分为位臵映射和名称映射。 位臵映射:就是把实际信号与底层元件的信号书写位臵一一对应,只写实际信号名 称,不用写底层元件的信号名称。

名称映射格式:形式参数=>实际参数。其中符号“=>”为关联运算符,形式参数指
的是底层元件的信号名称,实际参数指的是调用底层元件的信号名称。

例5.5:完成四位加法器的设计。采用方法如下:首先设计一位全加器fulladder ,再利用
component元件语句,调用全加器fulladder ,构造四位加法器。 全加器fulladder设计如下: library ieee;

use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all; entity fulladder is port (a, b, c: in std_logic;

carry, sum: out std_logic);
end fulladder; architecture a of fulladder is begin

sum<=a xor b xor c;
carry<=(a and b) or (a and c) or (b and c); end a; 程序说明:fulladder实体是一位全加器,输入信号a, b和c,进位输出carry以及和输出sum,

信号顺序为a, b, c, carry, sum。

由全加器构成四位加法器的框图如图所示,四位加法器b4_adder程序如下: library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; entity b4_adder is port (a, b: in std_logic_vector (3 downto 0); s : out std_logic_vector (3 downto 0)); end b4_adder; architecture a of b4_adder is signal c: std_logic_vector (4 downto 0); component fullAdder --元件说明语句,形成底层元件 port ( a, b, c : in std_logic; carry, sum: out std_logic); end component; begin u0: fulladder port map (a (0), b (0), c (0), c (1), s (0));--元件例化语句,调用底层元件 u1: fulladder port map (a (1), b (1), c (1), c (2), s (1));--采用位臵映射,建立调用关联关系 u2: fulladder port map (a (2), b (2), c (2), c (3), s (2)); u3: fulladder port map (a (3), b (3), c (3), c (4), s (3)); c(0) <= '0'; end a; 注意:两段程序fulladder 和b4_adder应当放在同一个目录下,进行调用和管理。

5.3.5
以简化这类电路的VHDL描述。 生成语句有两种格式:

generate生成语句

生成语句应用范围:有些实际电路往往会由许多重复的基本结构组成,生成语句可

标号:for 变量 in不连续区域 generate [并行语句]; end generate [标号]; 或者: 标号: if 条件 generate [并行语句]; end generate [标号];

例5.6:利用已有的D触发器构成4位移位寄存器,其组成框图如图所示。利用生成语

句,循环调用D触发器构成4位移位寄存器。

例5.6:利用生成语句,循环调用已有的D触发器构成4位移位寄存器。 entity shift is port (sin, clk: in bit; sout: out bit); end shift; architecture netlist1 of shift is component dff port (d, clk: in bit; q: out bit); end component; signal z: bit_vector (0 to 4); begin z (0)<= sin; gf: for i in 0 to 3 generate u1: dff port map (z (i), clk, z (i+1)); end generate; sout <= z (4); end netlist1; 注意:移位寄存器的输入信号和输出信号的连接无法用for_generate语句实现,只有用信号 赋值语句完成,在程序中用红色标出。 --生成语句,重复调用4次 --元件例化,重复调用D触发器 --中间信号的定义 --元件说明,准备调用D触发器

5.4 VHDL顺序语句
顺序语句:按照语句出现的先后顺序执行,顺序语句只能出现在进程或子程序中。

常用顺序语句:信号赋值语句、变量赋值语句、if语句、case语句、loop语句、next语
句、exit语句、return语句、null语句、wait语句等。

信号赋值语句:既可用作并行语句,也可作顺序语句使用。信号赋值语句出现在 进程、过程和函数之外时,为并行语句,否则为顺序语句。信号赋值语句的格式 及其使用已经在并行语句中介绍,这里不再重复介绍。

5.4.1 变量赋值语句
变量赋值语句:变量的说明和赋值只能在进程、函数和过程中。 变量赋值语句格式: 目的变量:= 表达式; 变量赋值语句含义:将表达式的值代入目的变量中,两者的类型应保持一致。 使用变量赋值语句注意:变量类似于一般高级语言的局部变量,只在局部范围内使 用。VHDL中的变量只在进程或子程序内部使用,变量值无法传递到进程和子程序 的外部。

5.4.2 if语句
if语句:根据所指定的条件来确定执行哪些语句,因此if语句可以实现多选择控制。 if语句格式: if 条件 then

顺序语句;
{elsif 条件 then 顺序语句;}

[else
顺序语句]; end if; if语句中条件:为布尔表达式,如果满足条件,则执行关键词then后面的顺序语句; 如果所有条件都不满足,则执行else后面的顺序语句,end if结束操作。

例5.7:用if语句设计四选一数据选择器。 library ieee; use ieee.std_logic_1164.all; entity mux41 is port (d0, d1, d2, d3: in std_logic; s: in std_logic_vector (1 downto 0); x: out std_logic); end mux41; architecture archmux of mux41 is begin process (s, d0, d1, d2, d3) begin if s = "00" then x <= d0; elsif s = "01" then x <= d1; elsif s = "10" then x <= d2; else x <= d3; end if; end process; end archmux;

5.4.3 case语句
case语句:可以根据条件表达式的取值执行不同的语句。 case与if语句功能相似,但 在case语句中,when语句可以颠倒条件的判别次序不会发生逻辑功能的变化,而if语 句使用时,颠倒条件的判别次序可能使逻辑功能变化。case语句的可读性比if语句强。 case语句格式: case 表达式 is

{when 条件表达式 => 顺序语句;}
[when others=> 顺序语句;] end case;

需要注意的是:使用case语句时需要将表达式的所有取值都列出,否则,必须使用
when others来替代未列出的取值。

例5.8:使用case语句描述低有效输出的3-8译码器。 library ieee; use ieee.std_logic_1164.all; entity decode38 is port(input: in std_logic_vector (2 downto 0); outy: out std_logic_vector (7 downto 0)); end decode38; architecture behave of decode38 is begin process (input) begin case input is when "000" => outy <="11111110"; when "001" => outy <="11111101"; when "010" => outy <="11111011"; when "011" => outy <="11110111"; when "100" => outy <="11101111"; when "101" => outy <="11011111"; when "110" => outy <="10111111"; when "111" => outy <="01111111"; when others => outy <="XXXXXXXX"; end case; end process; end behave;

5.4.4 loop语句
loop语句:能使程序进行有规则的循环,循环的次数受迭代算法的控制,常用来描 述迭代电路的行为。loop语句包含重复执行的一组顺序语句。 loop语句的书写格式有两种:这里介绍其中的一种。 for-loop语句格式: [标号:] for 循环变量 in 离散范围 loop 顺序语句; end loop [标号];

循环变量:其值在每次循环中都发生变化。
离散范围:表示循环变量在循环过程中依次取值的范围。 使用建议:EDA综合工具对for-loop语句支持较好,建议使用。

例5.9:使用for循环变量语句描述8位奇偶校验电路。 library ieee; use ieee.std_logic_1164.all; entity check is port(ain:in std_logic_vector (7 downto 0);aout:out std_logic); end; architecture a of check is begin processs (ain) variable tmp: std_logic; begin tmp:='0'; for n in 0 to 7 loop --n是循环变量,是整数变量,取值范围0~7 tmp:=tmp xor ain(n); end loop; aout<=tmp; end process; end a;

5.4.5 null语句
null语句:表示无任何动作。 null语句执行:只是为了使程序执行走到下一个语句。 null语句格式: null; 举例:在case语句的使用中曾经设计了3-8译码器电路,这里应用null语句实现3-8译 码器的设计。

例5.10:使用了null语句描述的3-8译码器电路。 library ieee; use ieee.std_logic_1164.all; entity decode38_2 is port (input: in std_logic_vector (2 downto 0); outy: out std_logic_vector (7 downto 0)); end decode38_2; architecture behave of decode38_2 is begin process (input) begin case input is when "000"=>outy<="11111110"; when "001"=>outy<="11111101"; when "010"=>outy<="11111011"; when "011"=>outy<="11110111"; when "100"=>outy<="11101111"; when "101"=>outy<="11011111"; when "110"=>outy<="10111111"; when "111"=>outy<="01111111"; when others=>null; end case; end process; end behave;

--null语句的使用



热文推荐
猜你喜欢
友情链接: 简历 面试求职范文 职业规划 自我管理 社交礼仪 76242百科