VHDL

更新时间:2024-06-30 22:21:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

第四章 VHDL简明教程

§4.1 VHDL基本结构与语法

·VHDL是VHSIC Hardware Description Language的缩写

□ VHSIC—Very High Speed Integrated Circuit(1982年)

·由美国国防部(DOD)制定,以作为各合同商之间提交复杂电路设计文档的一种标准方案 ·1987年被采纳为IEEE 1076标准 ·1993年被更新为IEEE 1164标准

HDL 的出现是为了适应电子系统设计的日益复杂性。若以计算机软件的设计与电路设计做个类比,机器码好比晶体管/MOS管;汇编语言好比网表;则HDL语言就如同高级语言,VHDL在语法和风格上类似与现代高级编程语言,如C语言。但要注意,VHDL毕竟描述的是硬件,它包含许多硬件特有的结构。 ·现在VHDL被广泛用于: 电路设计的文档记录 设计描述的逻辑综合 电路仿真

采用VHDL及自顶向下方法在大型数字系统设计中被广泛采用。在设计中你可采用较抽象的语言(行为/算法)来描述系统结构,然后细化成各模块,最后可借助编译器将VHDL描述综合为门级。

本教程仅对用于CPLD/FPGA设计描述的VHDL语言作一简单说明。其设计过程一般如下:

1. 代码编写;

2. 由综合器(如Synplify,Synopsys等)综合成门级网表; 3. 前仿真/功能仿真;

4. 布局/布线至某一类CPLD/FPGA中; 5. 后仿真/时序仿真。

4.1.1 VHDL的组成

一个VHDL设计由若干个VHDL文件构成,每个文件主要包含如下三个部分中的一个或全部:

1.程序包(Package); 2.实体(Entity);

3.结构体(Architecture).

120 — —

其各自作用如下图所示: VHDL设计 VHDL文件 程序包(Packages) 声明在设计或实体中将用到的常数,数据类型,元件及子程序等 实体(Entities) 声明到其他实体及其他设计的接口,即定义本设计的输入/出端口。 结构体(Architectures) 定义了实体的实现。即电路的具体描述

一个完整的VHDL设计必须包含一个实体和一个与之对应的结构体。一个实体可对应多个结构体,以说明采用不同方法来描述电路。

以下以具有异步清零、进位输入/输出的四位计数器为例,讲解VHDL的基本构件:以下为此计数器的VHDL代码:(黑体为关键字)

library ieee; --库,程序包调用 use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all;

ENTITY cntm16 IS --实体 PORT ( ci : IN std_logic; nreset : IN std_logic; clk : IN std_logic;

co : out std_logic; qcnt : buffer std_logic_vector(3 downto 0) --此处无;号 ); END cntm16;

ARCHITECTURE behave OF cntm16 IS --结构体 BEGIN

121 — —

co<='1' when (qcnt=\ and ci='1') else '0'; PROCESS (clk,nreset) --进程(敏感表) BEGIN IF(nreset='0') THEN qcnt<=\ ELSIF (clk'EVENT AND clk = '1') THEN if(ci='1') then qcnt<=qcnt+1; end if; END IF; --end if _reset END PROCESS; END behave;

*注:基本的标识符由字母、数字以及下划线组成,且具有如下特征:

第一个字符必须为字母; 最后一个字符不能是下划线; 不允许连续2个下划线。

最长32个字符,不区分大小写;不能和VHDL的保留字相同。

各完整语句均以“;”结尾,以“--” 开始的语句为注释语句,不参与编译。

下面将分别对程序包,实体,结构体做细致说明。

4.1.2 实体(Entity)

VHDL表达的所有设计均与实体有关,实体是设计中最基本的模块。设计的最顶层是顶层实体。如果设计分层次,那么在顶级实体中将包含较低级别的实体。 实体中定义了该设计所需的输入/输出信号,信号的输入/输出类型被称为端口模式,同时,实体中还定义他们的数据类型。 实体的格式如下:

entityis

port

end;

以上述的四位计数器为例,则该计数器的实体部分如下:

122 — —

ENTITY cntm16 IS

PORT ( ci nreset clk co qcnt

--实体

: IN

: IN : IN : out : buffer std_logic; std_logic; std_logic; std_logic;

std_logic_vector(3 downto 0) --此处无;号

); END cntm16; 端口模式 端口类型 信号名 由此看出,实体(ENTITY)类似于原理图中的符号(Symbol ),它并不描述模块的具体功能。 实体的通信点是端口(PORT),它与模块的输入/输出或器件的引脚相关联。 上述实体对应的原理图符号如下:

每个端口必须定义:

信号名:端口信号名在实体中必须是唯一的。信号名应是合法的标识符*。 属性:它包括

模式(MODE):决定信号的流向

类型(TYPE): 端口所采用的数据类型

端口模式(MODE)有以下几种类型: · IN 信号进入实体但并不输出; · OUT 信号离开实体但并不输入;并且不会在内部反馈使用; · INOUT 信号是双向的(既可以进入实体,也可以离开实体); · BUFFER 信号输出到实体外部,但同时也在实体内部反馈。 BUFFER(缓冲)是INOUT(双向)的子集,但不是由外部驱动

端口模式可用下图说明:(黑框代表一个设计或模块)

IN

OUT BUFFER INOUT

123 — —

端口类型(TYPE)定义端口的数据类型,包括以下几种: · integer 可用作循环的指针或常数,通常不用于I/O信号,

例如:

SIGNAL count :integer range 0 to 255 count <= count + 1 · bit 可取值‘0’或‘1’ · std_logic 工业标准的逻辑类型,取值‘0’,‘1’,‘X’,和‘Z’ --由IEEE std 1164标准定义 · std_logic_vector std_logic的组合,工业标准的逻辑类型

VHDL是与类型高度相关的语言,不允许将一种信号类型赋予另一种信号类型。在此教程中主要采用std_logic和std_logic_vector。若对不同类型的信号进行赋值需使用类型转换函数。

在VHDL中除上述常用于端口类型的数据类型外,还有其他多种数据类型用于定义内部信号,变量等:如

可枚举类型Enumeration(常用于定义状态机的状态)

存取型(Access Types),文件型(File Types)常用于建立模拟模型 物理类型(Physical Types)定义测量单位,用于模拟。 ??

其中可枚举类型Enumeration常用于定义状态机的状态,可枚举类型语法结构如下: type is (); 使用时和其他类型一样:

signal sig_name : type_name; 例:

定义: type traffic_light_state is (red, yellow, green); 使用: signal present_state, next_state :traffic_light_state; 此外,还可定义二维数组,详见第二部分的例子。

4.1.3 结构体(Architecture)

所有能被仿真的实体都由一个结构体描述, 结构体描述实体的行为功能。即设计的功能。一个实体可以有多个结构体,一种结构体可能为行为描述,而另一种结构体可能为设计的结构描述或数据通道的描述。结构体是VHDL设计中最主要部分,它一般由一些各子部分构成,如下图所示:

124 — —

结构体(Architecture) 声明区(Declarations) 信号声明;声明用于该结构体的类型,常数,元件,子程序。 并发语句 信号赋值(Signal Assignments) 计算结果,并赋值给信号 过程调用(Procedure Calls) 调用一个预先定义好的一个算法。 元件例化 (Component Instantiations) 调用另一个实体所描述的电路。即元件调用

结构体的一般格式如下:

过程(Processes) 定义一个新算法实现电路功能。在过程中赋值顺序语句。语句按放置的顺序执行。 architectureofis --结构体声明区域

--声明结构体所用的内部信号及数据类型

--如果使用元件例化,则在此声明所用的元件 begin --以下开始结构体,用于描述设计的功能 --concurrent signal assignments并行语句信号赋值 --processes 进程(顺序语句描述设计) --component instantiations 元件例化 end;

如上述四位计数器的结构体(Architecture)如下:

--这是一个模为16,同步计数,异步清零、进位输入/输出的计数器的结构体:

125 — —

ARCHITECTURE behave OF cntm16 IS BEGIN

co<='1' when (qcnt=\ and ci='1') else '0'; --并行赋值语句 PROCESS (clk,nreset) --进程(敏感表)

BEGIN IF(nreset='0') THEN --顺序语句

qcnt<=\

ELSIF (clk'EVENT AND clk = '1') THEN if(ci='1') then qcnt<=qcnt+1; end if; END IF; --end if _reset END PROCESS; END behave;

结构体(Architecture)描述的是实体中的具体逻辑,采用一些语句来描述设计的具体行为。因为语句中涉及到运算符,数据对象等,因此后面将分别说明。

★ 一个完整的、能够被综合实现的VHDL设计必须有一个实体和对应的结构体。一个实体和其对应结构体可构成一个完整的VHDL设计。一个实体可对应一个结构体或多个结构体。

4.1.4 程序包(Package)与USE语句

在VHDL语言中,数据类型、常量与子程序可以在实体说明部分和结构体部分加以说明;而且实体说明部分所定义的类型,常量及子程序在相应的结构体中是可见的(可以被使用)。但是,在一个实体的说明部分与结构体部分中定义的数据类型,常量及子程序对于其它实体的说明部分与结构体部分是不可见的。程序包就是为了使一组类型说明,常量说明和子程序说明对多个设计实体都成为可见的而提供的一种结构。

程序包定义了一组数据类型说明、常量说明、元件说明和子程序说明。以供其他多个设计实体引用。它如同C语言中的*.H文件,定义了一些类型说明, 函数一样。

程序包分包头和包体两部分。包头以保留字PACKAGE开头,包体则以PACKAGE BODY识别。

下面是一个程序包的例子:

--包头说明

PACKAGE Logic IS

TYPE Three_level_logic IS (‘0’,’L’,’Z’);

126 — —

CONSTANT Unknown_Value :Three_level_logic := ‘0’;

FUNCTION Invert ( input : Three_level_logic) RETURN Three_level_logic);

END Logic;

--包体说明

PACKAGE BODY Logic IS --如下是函数Invert的子程序体:

FUNCTION Invert ( input : Three_level_logic) RETURN Three_level_logic); BEGIN

CASE input IS

WHEN ‘0’=>RETURN ‘1’; WHEN ‘1’=>RETURN ‘0’; WHEN ‘Z’=>RETURN ‘Z’; END CASE; END invert; END Logic;

一个程序包所定义的项对另一个单元并不是自动可见的,如果在某个VHDL单元之前加上USE语句,则可以使得程序包说明中的定义项在该单元中可见。

--假定上述程序包Logic的说明部分已经存在 --下面的USE语句使得Three-level-logic 和 Invert; --对实体说明成为可见

USE Logic. Three_level_logic.Logic; USE Logic. Three_level_logic. Invert;

--或USE Logic.all。保留字all代表程序包中所有的都可见。即表示使用 --库/程序包中的所有定义

ENTITY Inverter IS

PORT (x; IN Three_level_logic; y: OUT Three_level_logic); END Inverter;

--结构体部分继承了实体说明部分的可见性, --所以不必再使用USE语句

ARCHITECTURE Three_level_logic OF Inverter IS BEGIN PROCESS

BEGIN

Y<=Invert (x) ;--一个函数调用

127 — —

WAIT ON x; END PROCESS;

END Inverter_body;

程序包的另一个例子可参考“上机练习”部分,它包含了两个元件的说明。

4.1.5 库(Library)

库是专门存放预先编译好的程序包(package)的地方,这样它们就可以在其它设计中被调用。它实际上对应一个目录,预编译程序包的文件就放在此目录中。用户自建的库即为设计文件所在的目录,库名与目录名的对应关系可在编译软件中指定。 例如在上述计数器设计中开始部分有:

LIBRARY ieee;

USE ieee.std_logic_1164.ALL;

USE ieee. std_logic_unsigned.ALL;

ieee是ieee标准库的标志名,下面两个USE语句使得以下设计可使用程序包

std_logic_1164、std_logic_unsigned中预定义的内容。

以下是IEEE两个标准库”std”与”ieee”中所包含的程序包的简单解释。

库 名 std ieee ieee ieee ieee ieee

在MAX+PLUSII软件系统中,在ALTERA库中提供如下两个程序包:

程序包名 standard std_logic_1164 numeric_std std_logic_arith std_logic_signed std_logic_unsigned 包中预定义内容 VHDL类型,如bit, bit_vector 定义std_logic, srd_logic_vector等 定义了一组基于 std_logic_1164中定义的类型的算术运算符,如“+”,“-”,SHL,SHR等。 定义有符号与无符号类型,及基于这些类型上的算术运算。 定义了基于std_logic与std_logic_vector类型上的有符号的算术运算。 定义了基于std_logic与std_logic_vector类型上的无符号的算术运算。 · maxplus2 定义了74系列各模块 · megacore 定义了如FFT、8255、8251、图象格式转换函数等大块。

128 — —

4.1.6 VHDL运算符

VHDL为构造计算数值的表达式提供了许多预定义算符。预定义算符可分为四种类型:算术运算符,关系运算符,逻辑运算符与连接运算符。分别叙述如下:

·算术运算符(Arithmetic operators) + 加 - 减 * 乘 / 除 ** 乘方 mod 求模 rem 求余 abs 求绝对值

·关系运算符 = 等于 /= 不等于 < 小于 <= 小于或等于 > 大于 >= 大于或等于

注:其中‘<=’操作符也用于表示信号的赋值操作

·逻辑运算符与连接运算符 and 逻辑与 or 逻辑或 nand 与非 nor 或非 xor 异或 xnor 同或 not 逻辑非

·连接运算符 & 连接,将两个对象或矢量连接成维数更大的矢量

129 — —

4.1.7 数据对象

在逻辑综合中,VHDL语言常用的数据对象为信号、常量、变量。 ·信号(Signal)

用于声明内部信号,而非外部信号(外部信号对应为in, out, inout, buffer),其在元件之间起互联作用,可以赋值给外部信号。 信号也可在状态机中表示状态变量。信号赋值符号为“<=”。 ·常量

常量在设计描述中保持某一规定类型的特定值不变。如利用它可设计不同模值的计数器,模值存于一常量中,不同的设计,改变模值仅需改变此常量值。 常量在定义时赋初值,赋值符号为“:=”。

·变量

变量只在给定的进程中用于声明局部值或用于子程序中。变量的赋值符号为“:=”。

下例为一位BCD码的加法器,从中可看出信号、常量、变量的定义及使用方法。

ENTITY bcdadder IS PORT (op1, op2 : IN integer range 0 to 9; result : OUT integer range 0 to 31 ); END bcdadder;

ARCHITECTURE behavior OF bcdadder IS

constant adjustnum : integer:=6; --定义一常量:整数型,值为6

signal binadd : integer range 0 to 18;

--定义一个信号,以保存两数二进制相加的和 BEGIN

binadd<=op1+op2; --信号赋值 process(binadd)

variable tmp:integer:=0; --定义一变量,并赋初值为0 begin

if binadd>9 then

tmp:=adjustnum; --变量赋值,立即起作用。 else

tmp:=0; end if;

result <= binadd+tmp; end process;

130 — —

END behavior;

注意,信号与变量赋值是不同的。在进程中,信号赋值在进程结束时起作用,而变量赋值是立即起作用的。如下面两个进程:

p1: process(A,B,C) p2: process(A,B,C) begin variable d:std_logic;

D<=A; --D为外部定义的信号 begin

D:=A; --立即赋值 X<=B+D;

D<=C; X<=B+D; Y<=B+D; D:=C; end process p1; Y<=B+D; 在进程结束更新时,D的值为C因此执行 end process p2; 结果X<=B+C; Y<=B+C; 此执行结果X<=B+A; Y<=B+C;

若使用synplify对p1进程进行逻辑综合可出现如下警告信息:

“Input a is unused”

4.1.8 VHDL常用语句

·VHDL常用语句分并行(Concurrent)语句和顺序(Sequential)语句: 并行语句(Concurrent):

并行语句总是处于进程(PROCESS)的外部。所有并行语句都 是并行执行的,即与它们出现的先后次序无关。 如when..else语句 顺序语句(Sequential):

顺序语句总是处于进程(PROCESS)的内部,并且从仿真的角度 来看是顺序执行的。如if-then-else语句。

下面先看一下进程:

131 — —

4.1.8.1进程Process

进程(PROCESS)用于描述顺序(sequential)事件并且包含在结构中。一个结构体可以包含多个进程语句。以下为进程语句的构成:

进程(Process) 声明区(Declarations) 内部变量声明;声明用于该进程的常数,元件,子程序。 顺序语句 信号赋值(<=) 过程调用 变量赋值(:=) loop语句(循环) next语句(跳过剩余循环) exit语句(退出循环) if语句 wait语句(等待时钟信号) case语句

null语句(空语句,值保持不变) 以下为进程语句的语法描述:

: process )

--此处声明局部变量,数据类型及其他局部声明(用于进程中) begin --进程开始

--进程中为顺序语句,如:

--signal and variable assignments 信号与变量的赋值

--if and case statements --if-then-else语句 case-when语句 --while and for loops

--function and procedure calls 函数,过程调用 end process; --进程结束

132 — —

其中,进程标号是可选项,可有可无。

敏感表(Sensitivity list)包括进程的一些信号,当敏感表中的某个信号变化时进程才被激活。如上述计数器为例:

PROCESS (clk,nreset) --进程(敏感表)

BEGIN IF(nreset='0') THEN --顺序语句 异步清零

qcnt<=\

ELSIF (clk'EVENT AND clk = '1') THEN if(ci='1') then qcnt<=qcnt+1; end if; END IF; --end if _reset END PROCESS; 在敏感表中,信号nreset,clk被列为敏感信号,当此两个信号变化时,此进程才被执行。注意信号ci并没有被列入敏感表,这是因为,ci起作用必须发生在时钟的上升沿,这时clk必定发生变化,引起进程的执行。同样,若为同步清零,敏感表中也可无nreset信号,此时进程如下:

PROCESS (clk) --进程(敏感表)

BEGIN

IF (clk'EVENT AND clk = '1') THEN --顺序语句 IF(nreset='0') THEN 同步清零

qcnt<=\

elsif(ci='1') then qcnt<=qcnt+1; end if; --end if _reset END IF; END PROCESS;

4.1.8.2 并行(Concurrent)语句和顺序(Sequential)语句

一个设计既可用并行语句描述也可用顺序语句描述。以下以四选一的数据选择器为例说明各常用语句。

□ 并行(Concurrent)语句

并行语句之间值的更新是同时进行的,与语句所在的顺序无关。并行语句包括: ·布尔方程

·条件赋值(如when—else—语句)

133 — —

·例化语句

一、布尔方程

四选一的数据选择器的库声明、程序包声明及实体定义如下: library ieee;

use ieee.std_logic_1164.all; entity mux4 is port ( s :in std_logic_vector(1 downto 0); a0,a1,a2,a3 :in std_logic; y :out std_logic); end mux4;

以布尔方程实现的结构体如下: architecture archmux of mux4 is begin

y<=((((a0 and not(s(0))) or (a1 and s(0)))) and not(s(1)))

or (((a2 and not(s(0))) or (a3 and s(0))) and s(1)); end archmux;

二、条件赋值

并行语句中条件赋值语句为:WITH-SELECT-WHEN语句及WHEN-ELSE语句。分别

如下:

--采用WITH-SELECT-WHEN实现的结构体

architecture archmux of mux4 is begin

with s select

y<= a0 when \ a1 when \ a2 when \ a3 when others; end archmux;

注意:WITH-SELECT-WHEN语句必须指明所有互斥条件,在这里即“s”的所有取值组合,因为“s”的类型为“std_logic_vector”,取值组合除了00,01,10,11外还有0x,0z,x1…等。虽然这些取值组合在实际电路中不出现,但也应列出。为避免此麻烦可以用“others”代替其他各种组合。

--采用WHEN-ELSE实现的结构体

134 — —

architecture archmux of mux4 is begin

y<= a0 when s=\ else a1 when s=\ else a2 when s=\ else a3 ; end archmux;

三、例化语句

即元件调用,可参见以下两节:“元件及元件例化” 及“配置”。

□ 顺序(Sequential)语句

最常用的顺序语句是IF-THEN-ELSE语句和CASE-WHEN语句。顺序语句总是处于进程(PROCESS)的内部,并且从仿真的角度来看是顺序执行的。

.IF-THEN-ELSE

IF-THEN-ELSE语句只在进程中使用,它根据一个或一组条件的布尔运算而选择某一特定的执行通道。例如:

architecture archmux of mux4 is begin

process(s,a0,a1,a2,a3) begin

if s=\ then y<=a0;

elsif s=\ then y<=a1;

elsif s=\ then y<=a2; else y<=a3; end if; end process; end archmux;

ELSIF可允许在一个语句中出现多重条件,每一个“IF” 语句都必须有一个对应的“END IF”语句。“IF” 语句可嵌套使用,即在一个IF语句中可在调用另一个“IF”语句。

.CASE-WHEN

135 — —

CAE-WHEN语句也只能在进程中使用。例如: architecture archmux of mux4 is begin

process(s,a0,a1,a2,a3) begin

case s is

when \=> y<=a0; when \=> y<=a1; when \=> y<=a2; when others => y<=a3; end case; end process; end archmux;

CAE-WHEN语句常用于状态机的描述中,详见第2节的例子。此外还有“for-loop”语句,可见第2节的例子“奇偶校验电路”,以及wait until ,wait on语句等。

4.1.9 元件及元件例化

元件声明是对VHDL模块(即底层设计,也是完整的VHDL设计)的说明,使之可在其他模块中被调用,元件声明可放在程序包中,也可在某个设计的结构体中声明。 元件例化指元件的调用。元件声明及元件例化的语法分别如下:

元件声明:

component<元件实体名>

port (<元件端口信息,同该元件实现时的实体的port部分>); end component;

--元件例化:

< 例化名>:<实体名,即元件名> port map (<端口列表>);

例如,在一个设计中调用一个模为10的计数器cntm10和一个七段译码器decode47构成如下电路,则该调用过程即元件例化的VHDL描述如下: library IEEE;

use IEEE.std_logic_1164.all;

entity cntvh10 IS port

( Rd,ci,clk :in std_logic; co : out std_logic; qout : out std_logic_vector(6 downto 0));

136 — —

end cntvh10;

ARCHITECTURE arch OF cntvh10 IS --元件声明

Component decode47 is port

(adr: in std_logic_vector(3 downto 0);

decodeout:out std_logic_vector(6 downto 0)); end Component;

Component cntm10 is port (ci : IN std_logic; nreset : IN std_logic; clk : IN std_logic; co : out std_logic; qcnt : buffer std_logic_vector(3 downto 0)); end Component;

signal qa : std_logic_vector(3 downto 0); BEGIN

u1: cntm10 port map(ci,Rd,clk,co,qa); --元件例化 u2: decode47 port map(decodeout=>qout, adr=>qa); END arch;

元件例化时的端口列表可按位置关联方法,如u1,这种方法要求的实参(该设计中连接到端口的实际信号,如ci,Rd等)所映射的形参(元件的对外接口信号)的位置同元件声明中一样;元件例化时的端口列表也可按名称关联方法映射实参与形参,如u2。格式为(形参1=>实参1,形参2=>实参2,….)。这种方法与位置无关。 其描述的电路为下图所示:

cntm10(模为10的计数器)及decode47(七段译码器)可参考“上机练习”

参数化元件可增加元件例化的灵活性。所谓参数化元件是指元件的规模(或特性)可以通过引用参数的形式指定的一类元件。例如,下面定义了一个位数可调的计数器: library ieee; use ieee.std_logic_1164.all;

137 — —

use ieee.std_logic_unsigned.all;

ENTITY cntnbits IS

generic(cntwidth:integer:=4); --定义了一个可调参数

PORT

(

ci : IN std_logic;

nreset : IN std_logic; clk : IN std_logic; co : out std_logic; qcnt : buffer std_logic_vector(cntwidth-1 downto 0)

);

END cntnbits;

ARCHITECTURE behave OF cntnbits IS

constant allis1:std_logic_vector(cntwidth-1 downto 0):=(others=>'1'); BEGIN

co<='1' when (qcnt=allis1 and ci='1') else '0'; PROCESS (clk,nreset) BEGIN IF(nreset='0') THEN qcnt<=(others=>'0'); ELSIF (clk'EVENT AND clk = '1') THEN if(ci='1') then qcnt<=qcnt+1; end if; END IF; END PROCESS; END behave;

我们可看到,该计数器同第一节中的四位计数器相比,改动不大,其中在实体处增加了一行:

generic(cntwidth:integer:=4);

该行定义了一个整数cntwidth并赋初值‘4‘,用它代替原来的固定的计数器长度,若想设计的计数器位数位8位,仅需将cntwidth的初值赋为8: generic(cntwidth:integer:=8);

若以此计数器为元件,则元件声明为:

Component cntnbits IS generic(cntwidth:integer:=4); PORT

138 — —

(

ci : IN std_logic;

nreset : IN std_logic; clk : IN std_logic; co : out std_logic; qcnt : buffer std_logic_vector(cntwidth-1 downto 0) );

END Component ;

元件例化时按如下格式:

< 例化名>:<实体名,即元件名>

generic map (<实际参数,如确定的总线宽度等>) port map (<端口列表>); 例如,例化为6位计数器:

u1: cntnbits generic map(6) port map(ci,Rd,clk,co,qa); --元件例化

在上述的可变位数计数器中,定义了一个常数“allis1 ”用于产生进位输出信号时的判断。它的值为各位都为‘1‘。此处,用了(others=>'1')赋值。(others=>'1')表示一个集合,集合中各元素用’,‘格开。表示各元素都为’1‘。others必须出现在集合的最后。 例: signal: sa:std_logic_vector(7 downto 0); sa<=(‘1’,’0’,others=>’1’)

其结果是给信号sa赋值“1011 1111 ”。

4.1.10 配置(Configuration)

前面说过,一个实体可用多个结构体描述,在具体综合时选择哪一个结构体来综合,则由配置来确定。即配置语句来安装连接具体设计(元件)到一个实体--结构体对。配置被看作是设计的零件清单, 它描述对每个实体用哪一种行为,所以它非常象一个描述设计每部分用哪一种零件的清单。 配置语句举例:

--这是一个两位相等比较器的例子,它用四种不同描述来实现,即有四个结构体。 ENTITY equ2 IS PORT (a,b : IN std_logic_vector(1 downto 0); equ : OUT std_logic ); END equ2;

--结构体一:用元件例化来实现,即网表形式: ARCHITECTURE netlist OF equ2 IS

139 — —

COMPONENT nor2

PORT (a, b : IN std_logic; C : OUT std_logic); END COMPONENT; COMPONENT xor2

PORT (a, b : IN std_logic; C : OUT std_logic); END COMPONENT; signal x : std_logic_vector(1 downto 0); BEGIN

U1: xor2 PORT MAP(a(0), b(0), x(0)); U2: xor2 PORT MAP(a(1), b(1), x(1)); U3: nor2 PORT MAP(x(0), x(1), equ);

END netlist;

--结构体二:用布尔方程来实现:

ARCHITECTURE equation of equ2 IS BEGIN

equ<=(a(0) XOR b(0)) NOR (a(1) XOR b(1)); END equation;

--结构体三:用行为描述来实现,采用并行语句: ARCHITECTURE con_behave of equ2 IS BEGIN

equ<=’1’ when a=b else ‘0’; END con_behave;

--结构体四:用行为描述来实现,采用顺序语句: ARCHITECTURE seq_behave of equ2 IS BEGIN

process(a,b) begin

if a=b then equ<=’1’; else equ<=0; end if; end process; END seq_behave;

140 — —

在上述的实例中,实体equ拥有四个结构体:netlist、equation、con_behave、seq_behave,若用其例化一个相等比较器aequb,那么实体究竟对应于哪个结构体呢?配置语句(CONFIGURATION)很灵活地解决了这个问题:

如选用结构体netlist,则用

CONFIGURATION aequb OF equ2 IS FOR netlist END FOR;

END CONFIGURATION;

如选用结构体con_behave, 则用

CONFIGURATION aequb OF equ2 IS FOR con_behave END FOR;

END CONFIGURATION;

注:以上四种结构体代表了三种描述方法:Netlist(网表)、Equation(方程)、Behavior(行为描述)。有时将它们称之为:Structural(结构描述)、Data flow(数据流描述)、Behavioral(行为描述)。 behavioral(行为描述)

反映一个设计的功能或算法,一般使用进程process,用顺序语句表达。 dataflow(数据流描述)

反映一个设计中数据从输入到输出的流向,使用并发语句描述。 structural(结构描述)

它最反映一个设计硬件方面特征,表达了内部元件间连接关系。使用元件例化来描述。

4.1.11 子程序

子程序由过程(PROCEDURE)和函数(FUNCTION)组成。函数只能用以计算数

值,而不能用以改变与函数形参相关的对象的值。因此,函数的参量只能是方式为IN的信号与常量,而过程的参量可以为IN, OUT, INOUT方式。过程能返回多个变量,函数只能有一个返回值。

函数和过程常见于面向逻辑综合的设计中,主要进行高层次的数值运算或类型转换、运

算符重载,也可用来元件例化。 语法如下: 函数:

FUNCTION (parameter types) RETURN IS BEGIN

<代码区>

141 — —

END ; 过程:

procedure

() is

begin --

<代码区>

end< procedure _name>;

函数举例:此函数返回两数中的较小数

FUNCTION Min(x, y : INTEGER) RETURN INTEGER IS BEGIN

IF x

RETURN y; END IF; END Min;

过程举例:此过程将向量转换成整数类型

USE ieee. std_logic_1164. ALL PROCEDURE vetor_to_int (z : IN std_logic_vector; x-flag :OUT BOOLEAN; q :INOUT INTEGER) IS BEGIN q :=0;

x-flag :=false;

FOR I IN z’ RANGE LOOP q :=q*2;

IF z (i) /=’0’ THEN q :=q+1;

ELSIF z(i) /=’0’ THEN x-flag := TRUE; END IF; END LOOP; END vector_to_int;

函数/过程可以在结构体的说明域中定义,在这种方式下同时包含了函数/过程的说明和定义。另外,也可以在程序包的说明和包体中,分别输入函数的说明和定义,并将其编译到库中以便在其他设计使用他们。在函数和过程中,所有语句都必须是顺序语句,并且不能在他们中说明信号。

4.1.12 其他:属性、时钟的表示

属性指的是关于实体、结构体、类型、信号的一些特征。有些属性对综合(设计)非常有用,如:值类属性、信号类属性、范围类属性。以下简单列出这些属性的含义:

142 — —

· 值类属性

值类属性分为’left, ‘right, ‘low, ‘high, ‘length。其中用符号“’”隔开对象名及其属性。left表示类型最左边的值;right表示类型最右边的值;low表示类型中最小的值;high表示类型中最大的值;length表示限定型数组中元素的个数。 例: sdown :in std_logic_vector(8 downto 0); sup :in std_logic_vector(0 to 8); 则这两个信号的各属性值如下:

sdown’left=8; sdown’right=0; sdown’low=0; sdown’high=8; sdown’length=9; sup’left=0; sup’right=8; sup’low=0; sup’high=8; sup’length=9; · 信号类属性

这里仅介绍一个对综合及模拟均很有用的信号类属性:’event,它的值为布尔型,如果刚好有事件发生在该属性所附着的信号上(即信号有变化),则其取值为Ture,否则为False。利用此属性可决定时钟边沿是否有效,即时钟是否发生。 例:时钟边沿表示

若有如下定义: signal clk :in std_logic;

则:clk=’1’ and clk’event 和 clk’event and clk=’1’表示时钟的上升沿。即时钟变化了,且其值为1,因此表示上升沿。

clk=’0’ and clk’event 和 clk’event and clk=’0’表示时钟的下降沿。即时钟变化了,且其值为1,因此表示下降沿。

此外,还可利用预定义好的两个函数来表示时钟的边沿。 rising_edge(clk) 表示时钟的上升沿 falling_edge(clk) 表示时钟的下降沿 · 范围类属性

‘range属性,其生成一个限制性数据对象的范围。 例如:signal data_bus : std_logic_vector(15 downto 0); data_bus’range=15 downto 0;

4.1.13 VHDL的模板

至此,我们已知道VHDL的大致构成。下面以VHDL的两个模板回顾一下VHDL的结构,一个是基本结构,一个是详细结构。其中黑体字为关键字。<>中内容为对用户不同设计所需填写的内容。

--VHDL Model Template (Overview)

143 — —

library;

use..all ;

entityis

end;

architectureofis --结构体声明区域

--声明结构体所用的内部信号及数据类型

--如果使用元件例化,则在此声明所用的元件 begin --以下开始结构体,用于描述设计的功能 --concurrent signal assignments并行语句信号赋值 --processes 进程(顺序语句描述设计) --component instantiations 元件例化 end;

--VHDL Model Template (Detailed) --列出用户定义的库及程序包

library;

use..all;

--实体描述了用户设计的接口

entityis

generic (<此处定义接口常数,如总线宽度、预定标计数器的计数模值等>); port (<列出端口信息>); end < entity_name >;

--结构体是描述/实现设计的部分

architectureofis --结构体声明区域

--声明结构体所用的信号及数据类型,及子程序 --如果使用元件例化,则在此声明所用的元件 --元件声明如下:

component<元件实体名> port (<元件端口信息>); end component;

144 — —

begin—结构体开始, 描述设计功能 --用并行语句描述设计的功能,

--最常用的并行语句是并行信号赋值,进程,元件例化。

--concurrent signal assignment (并行信号赋值的简单形式): <=;

--process:进程模块

process )

--此处声明局部变量,数据类型及其他局部声明(用于进程中)

begin --进程开始

--进程中为顺序语句,如:

--signal and variable assignments 信号与变量的赋值

--if and case statements --if-then-else语句 case-when语句 --while and for loops

--function and procedure calls 函数,过程调用 end process;

--元件例化,句法结构:

< 例化名>:<实体名,即元件名>

generic map (<实际参数,如确定的总线宽度等>) port map (<端口列表>);

end ;

4.1.14 常见错误

·隐含触发器

如以下代码:

library ieee;

use ieee.std_logic_1164.all; entity and2 is port

(a,b :in std_logic; c :out std_logic); end and2;

145 — —

architecture behave of and2 is begin

process(a,b)

begin

if(a='1' and b='1') then c<='1'; end if; end process; end behave;

设计指原意是设计一个二输入与门,但因“IF”语句中无“ELSE”语句,在对此语句逻辑综合时认为“ELSE”语句中为:“C<=C;”,即保持不便。因此可能形成的电路如下:

利用MAX+PLUSII软件仿真时,除了“a=1”及“b=1”时“c=1”外,其他时刻c的值都不确定。为改正此错误,仅需加上

else

c<=’0’; 语句即可。

这类错误在利用“IF-THEN-ELSE”语句设计组合电路时常犯的。

·时钟处理

如以下描述,是为了设计一个带计数使能的计数器,但其将falling_edge(clk)和 ci='1'放在一起,有些综合器可能会生成错误电路或不能综合。 IF (falling_edge(clk) and ci='1') THEN qcnt<=qcnt+1; END IF; 最好如下:

IF falling_edge(clk) THEN if(ci='1') then qcnt<=qcnt+1; end if; END IF;

此外,对于时钟电路,可省略“else”语句,它隐含表示“qcnt<=qcnt;”。可加上此句,

146 — —

但下面的描述则无法综合:

IF (falling_edge(clk)) THEN qcnt<=qcnt+1; else

qcnt<=datain; END IF; 综合时会出现如下错误信息:

“Else Clause following a Clock edge must hold the state of signal”

4.1.15. 保留字

如下为VHDL的保留字,又称关键字,在VHDL语言中有特殊的含义,不能作为标识符出现。此外,不同的综合系统还定义各自的子程序,子程序名也不能作为标识符出现。对于逻辑综合而言,并不是所有的保留字都有意义。 abs else nand then access elsif new severity after end next signal alias entity nor subtype all exit null then and file of to architecture for on transport array function open type assert generate or units attribute generic others util begin guarded process use block if range variable body in record wait buffer inout register when bus is rem while case label report with component library return xor configuration linkage select constant loop severity disconnect map signal downto mod subtype

147 — —

§4.2 常用电路描述

本节给出以下常见电路的VHDL描述。 ·加法器(全加器、BCD码加法器) ·译码器 ·编码器 ·比较器

·MUX数据选择器 ·奇偶校验电路 ·三态输出电路 ·同步化电路 ·M=60的计数器 ·移位寄存器

·状态机(Mealy和Moore型)

加法器(全加器、BCD码加法器)

一位BCD码加法器:

LIBRARY ieee;

USE ieee.std_logic_1164.all; USE ieee.std_logic_unsigned.all;

ENTITY bcdadder IS PORT (op1, op2 : in std_logic_vector(3 downto 0); result : out std_logic_vector(4 downto 0) ); END bcdadder;

ARCHITECTURE behavior OF bcdadder IS

signal binadd :std_logic_vector(4 downto 0);

BEGIN

binadd<=op1+op2; --保存二进制之和

--若出现宽度不匹配错误,可将该句改为:binadd<=(‘0’ & op1) +(‘0’ & op2); --即高位补零。 process(binadd) begin

148

.

if binadd>9 then --进行加6校正 result <= binadd+6; else

result <= binadd; end if;

end process; END behavior;

全加器(12位)

LIBRARY ieee;

USE ieee.std_logic_1164.all; USE ieee.std_logic_unsigned.all;

ENTITY adder14 IS PORT (op1, op2 : IN std_logic_vector (12 downto 0); ci : in bit; result : OUT std_logic_vector (13 downto 0)); END adder14;

ARCHITECTURE maxpld OF adder14 IS signal halfadd : std_logic_vector (13 downto 0); BEGIN

halfadd<=op1+op2;

result<=halfadd when ci='0' else halfadd+1; END maxpld;

译码器

带使能端的七端译码器

library ieee;

use ieee.std_logic_1164.all; entity decode47 is port (adr :in std_logic_vector(3 downto 0); en :in std_logic; decodeout :out std_logic_vector(6 downto 0)); end decode47;

149

.

architecture archmux of decode47 is begin

process(en,adr)

begin

if en='0' then

decodeout<=\可改为(others=>’0’) else

case adr is

when \ when \ when \ when \ when \ when \ when \ when \ when \ when others=> decodeout<= \ end case; end if;

end process; end archmux;

三-八译码器

LIBRARY ieee;

USE ieee.std_logic_1164.all; USE ieee.std_logic_unsigned.all;

entity decoder is port(adrin : in std_logic_vector(2 downto 0); deout : out std_logic_vector(7 downto 0) ); end decoder;

architecture behave of decoder is begin

process(adrin)

variable tmp:std_logic_vector(7 downto 0); --此处不能定义为信号150

.

begin

tmp:=(others=>'0'); --others=>’0’表示将tmp的各位赋相同值“0”。 tmp(conv_integer(adrin)):='1'; --conv_integer函数在程序包std_logic_unsigned中定义

deout<=tmp; end process; end behave;

编码器

优先编码器(Priority encoder)

LIBRARY ieee;

USE ieee.std_logic_1164.all;

entity encoder is

port(a,b,c,d,e,f,g,h : in std_logic; codeout : out std_logic_vector(2 downto 0) ); end encoder;

architecture behave of encoder is begin

codeout<=\when h='1' else \when g='1' else \when f='1' else \when e='1' else \when d='1' else \when c='1' else \when b='1' else \when a='1' else \end behave;

比较器

library ieee;

151

.

use ieee.std_logic_1164.all; ENTITY comp IS

PORT ( a,b :in std_logic_vector(3 downto 0); aqualb,agrdb,alessb :out std_logic ); END comp;

ARCHITECTURE behave OF comp IS BEGIN

aqualb<='1' when a=b else '0'; agrdb<='1' when a>b else '0'; alessb<='1' when a

MUX数据选择器

16路四选一

library ieee;

use ieee.std_logic_1164.all; entity v16mux4 is port

(datain0,datain1,datain2,datain3 :in std_logic_vector(15 downto 0); sel :in std_logic_vector(1 downto 0); dataout :out std_logic_vector(15 downto 0)); end v16mux4;

architecture archmux of v16mux4 is begin

with sel select

dataout<=datain0 when \ datain1 when \ datain2 when \ datain3 when others; end archmux;

152

.

奇偶校验电路

library ieee;

use ieee.std_logic_1164.all; entity parity is

generic(bussize:integer:=8); --在调用此设计时,可重新指定此值,或默认值8; port

(databus :in std_logic_vector(bussize-1 downto 0); even_num,odd_num :out std_logic); end parity;

architecture behave of parity is begin

process(databus)

variable tmp :std_logic;

begin

tmp:='0';

for i in databus'low to databus'high loop --for—loop语句 tmp:=tmp xor databus(i); end loop;

odd_num<=tmp; even_num<=not tmp; end process; end behave;

三态输出电路

library ieee;

use ieee.std_logic_1164.all; entity triout is

generic(bussize:integer:=8); port

(data_in:in std_logic_vector(bussize-1 downto 0); oe_en :in std_logic;

data_out:out std_logic_vector(bussize-1 downto 0)); end triout;

153

.

architecture behave of triout is

begin

data_out<=data_in when oe_en='1' else (others=>'Z'); --注意此处的“Z”要大写;

--因为在“std_logic”中作为枚举类型“Z”是以大写字母存在的。 end behave;

同步化电路

library ieee;

use ieee.std_logic_1164.all; ENTITY syncir IS

PORT ( sin,clk : IN std_logic; sout : out std_logic);

END syncir ;

ARCHITECTURE behave OF syncir IS signal q1,q0 : std_logic;

BEGIN

sout<=q0 and (not(q1)); PROCESS (clk) BEGIN IF (clk'EVENT AND clk = '1') THEN q0<=sin; q1<=q0; END IF; END PROCESS; END behave;

M=60的计数器

-- A asynchronous reset; synchronous load ;enable up; 8421BCD counter -- module=60; library ieee;

use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; ENTITY cntm60 IS PORT

154

.

( 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) ); END cntm60;

ARCHITECTURE behave OF cntm60 IS BEGIN

co<='1' when (qh=\and ql=\and ci='1') else '0'; PROCESS (clk,nreset) BEGIN IF(nreset='0') THEN qh<=\ ql<=\ ELSIF (clk'EVENT AND clk = '1') THEN if(load='1') then

qh<=d(7 downto 4); ql<=d(3 downto 0); elsif(ci='1') then if (ql=9) then ql<=\ if(qh=5) then qh<=\ else

qh<=qh+1; end if; else ql<=ql+1; end if;

END IF; --end if LOAD END IF; --end if _reset END PROCESS; END behave;

155

.

移位寄存器

--可左,右移,同步置数,同步清零 library ieee;

use ieee.std_logic_1164.all; ENTITY shifter IS

PORT (data :in std_logic_vector(7 downto 0); sl_in,sr_in,reset,clk : IN std_logic; mode :in std_logic_vector(1 downto 0); qout : buffer std_logic_vector(7 downto 0)); END shifter;

ARCHITECTURE behave OF shifter IS signal q1,q0 : std_logic;

BEGIN

PROCESS (clk) BEGIN IF (clk'EVENT AND clk = '1') THEN if(reset='1') then

qout<=(others=>'0'); --同步清零

else

case mode is when \

qout<=sr_in & qout(7 downto 1); --右移 when \

qout<=qout(6 downto 0) & sl_in; --左移

when \

qout<=data; --置数

when others=>null; --“NULL”表示无操作 end case; end if; END IF; END PROCESS; END behave;

156

.

堆栈(stack)

--该设计为一个有16个字,字长为8位的栈。

library ieee;

use ieee.std_logic_1164.all; use ieee.std_logic_signed.all;

ENTITY stack IS PORT ( datain : IN std_logic_vector(7 downto 0); push,pop,reset,clk : IN std_logic; stackfull : out std_logic; dataout : buffer std_logic_vector(7 downto 0)); END stack;

ARCHITECTURE a OF stack IS

type arraylogic is array (15 downto 0) of std_logic_vector(7 downto 0); signal data : arraylogic; --此处定义了data为一个数组16?8

signal stackflag:std_logic_vector(15 downto 0); BEGIN

stackfull<=stackflag(0);

PROCESS (clk,reset,pop,push)

variable selfunction : std_logic_vector(1 downto 0); BEGIN selfunction:=push & pop; if reset='1' then

stackflag<=(others=>'0'); dataout<=(others=>'0');

FOR i IN 0 to 15 LOOP data(i)<=(others=>'0'); END LOOP;

elsif clk'event and clk = '1' then case selfunction is

when \ --push data(15)<=datain;

stackflag<='1' & stackflag(15 downto 1); FOR i IN 0 to 14 LOOP data(i)<=data(i+1);

157

.

END LOOP; when \ --pop dataout<=data(15);

stackflag<=stackflag(14 downto 0) & '0';

FOR i IN 15 downto 1 LOOP data(i)<=data(i-1);

END LOOP;

when others=>NULL ;--in other cases, stack don't be changed end case; end if; END PROCESS; END a;

状态机(Mealy和Moore型)

如何进行状态编码可见2 Moore型状态机的设计部分。 1.Mealy型电路,以实现下面状态转移图为例

X/Z0/0reset=1,异步 1/11/01/01/0SASBSCSD0/00/0

单进程的状态机: library ieee;

use ieee.std_logic_1164.all;

ENTITY statem1 IS PORT( clk : IN STD_LOGIC; reset : IN STD_LOGIC; x : IN STD_LOGIC; z : OUT STD_LOGIC);

158

.

END statem1 ;

ARCHITECTURE behave OF statem1 IS TYPE STATE_TYPE IS (sa, sb, sc,sd); SIGNAL state: STATE_TYPE; BEGIN

PROCESS (clk,reset) BEGIN

IF reset = '1' THEN state <= sa;

ELSIF clk'EVENT AND clk = '1' THEN CASE state IS WHEN sa => IF x='1' THEN state <= sb; else

state<=sa; END IF;

WHEN sb => IF x='1' THEN state <= sc; else

state<=sa; END IF; WHEN sc => IF x='1' THEN

state<=sd; else

state<=sa; END IF; WHEN sd => IF x='1' THEN state <= sd; else

state<=sa; END IF; END CASE; END IF;

END PROCESS;

z<='1' when state=sd and x='1' else '0'; --输出不仅与状态有关,还与当前输入有关。 END behave;

159

.

本文来源:https://www.bwwdw.com/article/vny.html

Top