第 3 章 VHDL 入门
实践表明,VHDL 入门的最有效的方法是通过具体电路实例引出对应的 VHDL 表述,
通过这些有针对性的表述进而学习相关的语句语法,再通过多个类似实例的学习,逐步完备 VHDL 的基本语法知识和提高电路的描述和设计能力。据此,全章通过数个简单、完整而典型的 VHDL 设计示例,使读者初步了解用 VHDL 表达和设计电路的方法,并对由此而引出的 VHDL 语言现象和语句规则能逐步趋向系统的了解。
由于用硬件描述语言来对电子线路的表达和设计是 EDA 建模和实现技术中最基本和最重要的方法,其它的许多方法都是建筑在这 一基础之上的,如使用 MATLAB/DSP Builder
的设计方案、图形方式的状态机输入法、原理图输入法等等。因此 VHDL 的学习在 EDA
技术的掌握中具有十分重要的地位。
3.1 简单组合电路的 VHDL 描述
2 选 1 多路选择器是典型的组合电路,本章以此电路的 VHDL 表述与设计为例,引出相关的 VHDL 结构、语句表述、数据规则和语法特点,并加以详细说明。
3.1.1 多路选择器的 VHDL 描述
2 选 1 多路选择器的电路模型,或元件图如图 3-1所示。例 3-1 是其 VHDL 的完整描述,即可使用 VHDL 综合器直接综合出实现 即定功能的逻辑电路,对应的逻辑电路如图 3-2 所示,因而可以认为是此 多路选择器的内部电路结构。
图 3-1 mux21a 实体 图 3-2 mux21a 结构体
注意,电路的功能可以是唯一的,但其电路的结构方式不是唯一的,它决定于综合器的基本元件库的来源、优化方向和约束的选择、目标器件(指 FPGA/CPLD)的结构特点等等。
图中,a和 b 分别为两个数据输入端的端口名,s 为通道选择控制信号输入端的端口名,y
为输出端的端口 名。,mux21a”是设计者为此器件取的名称(好的名称应该体现器件的基第 3 章 VHDL 入门
71
本功能特点)。
【例 3-1】
ENTITY mux21a IS
PORT ( a,b,IN BIT;
s,IN BIT;
y,OUT BIT );
END ENTITY mux21a;
ARCHITECTURE one OF mux21a IS
BEGIN
y <= a WHEN s = '0' ELSE b ;
END ARCHITECTURE one ;
由例 3-1 可见,此电路的 VHDL 描述由两大部分组成,
(1) 以关键词 ENTITY 引导,END ENTITY mux21a 结尾的语句部分,称为实体。
VHDL 的实体描述了电路器件的外部情况及各信号端口的基本性质,如信号流动的方向,流动在其上的信号结构方式和数据类型等。图 3-1 可以认为是实体的图形表达。
(2) 以关键词 ARCHITECTURE 引导,END ARCHITECTURE one 结尾 的语句部分,
称为结构体。结构体负责描述电路器件的内部逻辑功能和电路结构。图 3-2 是此结构体 的某种可能的电路原理图表达。
在 VHDL 结构体中用于描述逻辑功能和电路结构的语句分为顺序语句和并行语句两部分。顺序语句的执行方式类似于普通软件语言的程序执行方式,是按照语句的前后排列方式逐条顺序执行的。而在结构体中的并行语句,无论有多少行语句,都是同时执行的,与语句的前后次序无关(姑且暂时这样认为,以后将给予详细说明)。
例 3-1 中的逻辑描述是用 WHEN_ELSE 结构的并行语句表达的。它的含义是,当满足条件 s ='0',即 s 为低电平时,a 输入端的信号传送至 y,否则 (即 s 为高电平时 )b 输入端的信号传送至 y。
也可以用其他的语句形式来描述以上相同的逻辑行为。例 3-2 中的功能描述语句都用了并行语句,是用布尔方程的表达式来描述的。其中的,AND”、,OR”、,NOT”分别是“与”、
“或”、“非”的逻辑操作符号。
例 3-3 则给出了用顺序语句 IF_THEN_ELSE 表达的功能描述。
以上 3 例用不同的表达方式描述了相同的逻辑功能,其电路功能可以从图 3-3 的时序波形( QuartusII 仿真波形)中看出,分别向 a 和 b 端输入两个不同频率的信号 fa 和 fb(fa >
fb),当 s 为高电平时,y 输出 fb,而当 s 为低电平时,y 输出 fa。显然,图 3-3 的波型证实了 VHDL 逻辑设计的正确性。
注意,以上各例的实体和结构体分别是以,END ENTITY xxx,和,END
ARCHITECTURE xx,语句结尾的,这是符合 VHDL 的 IEEE STD 1076_1993 版的语法要求的。若根据 VHDL’87 版本,即 IEEE STD 1076_1987 的语法要求,这两条结尾语句只需写成,END;”或,END xx”。但考虑到目前绝大多数常用的 EDA 工具中的 VHDL 综合器都兼容两种 VHDL 版本的语法规则,且许多最新的 VHDL 方面的资料,仍然使用 VHDL’87
版本语言规则,因此,出于实用的目的,对于以后出现的示例,不再特意指出 VHDL 两种版本的语法差异处。但对于不同的 EDA 工具,仍需根据设计程序不同的 VHDL 版本表述,
EDA 技术 与 VHDL
72
在综合前作相应的设置。
【例 3-2】
ENTITY mux21a IS
PORT ( a,b,IN BIT;
s,IN BIT;
y,OUT BIT );
END ENTITY mux21a;
ARCHITECTURE one OF mux21a IS
SIGNAL d,e,BIT;
BEGIN
d <= a AND (NOT S) ;
e <= b AND s ;
y <= d OR e ;
END ARCHITECTURE one ;
【例 3-3】
ENTITY mux21a IS
PORT ( a,b,s,IN BIT;
y,OUT BIT );
END ENTITY mux21a;
ARCHITECTURE one OF mux21a IS
BEGIN
PROCESS (a,b,s)
BEGIN
IF s = '0' THEN
y <= a ; ELSE
y <= b ;
END IF;
END PROCESS;
END ARCHITECTURE one ;
图 3-3 mux21a功能时序波形
3.1.2 相关语句结构和语法说明
以下将对例 3-1 至例 3-3 中出现的相关语句结构和语法含义作出说明,
1,实体表达
VHDL 完整的、可综合的程序结构必须能完整地表达一片专用集成电路 ASIC 器件的端口结构和电路功能,即无论是一 片 74LS138 还是一片 CPU,都必须包含实体和结构体两第 3 章 VHDL 入门
73
个最基本的语言结构。这里将含有完整程序结构 (包含实体和结构体 )的 VHDL 表述称为 设计实体 。如前所述,实体描述的是电路器件的端口构成和信号属性,它的最简表式如下,
【例 3-4】
ENTITY e_name IS
PORT ( p_name,port_m data_type;
,.,
p_namei,port_mi data_type );
END ENTITY e_name;
上式中,ENTITY,IS,PORT 和 END ENTITY 都是描述实体的关键词,在实体描述中必须包含这些关键词。在编辑中,关键词不分大写和小写。
2,实体名
例 3-4 中的 e_name 是实体名,是标识符,具体取名由设计者自定。由于实体名实际上表达的应该设计电路的器件名,所以最好根据相应电路的功能来确定,如 4 位二进制计数器,实体名可取为 counter4b; 8 位二进制加法器,实体名可取为 adder8b,等等。但应注意,
不应用数字或中文定义实体名,也不应用与 EDA 工具库 中已定义好的元件名作为实体名,
如 or2,latch 等,且不能用数字起头的实体名,如 74LSxx。
3,端口 语句和端口信号名
描述电路的端口及其端口信号必须用端口语句 PORT( )引导,并在语句结尾处加分号
“;”。例 3-4 中的 p_name 是端口信号名,如例 3-1 中的端口信号名分别是 a,b,s 和 y。
4,端口模式
在例 3-1的实体描述中,用 IN和 OUT分别定义端口 a,b和 s为信号输入端口,y为信号输出端口。一般,可综合的端口模式有四种,它们分别是,IN”、,OUT”、,INOUT”
和,BUFFER”,用于定 义端口上数据的流动方向和方式,
IN:输入端口,定义的通道为单向只读模式。规定数据只能由此端口被读入实体。
OUT:输出端口,定义的通道为单向输出模式。规定数据只能通过此端口从实体向外流出,或者说可以将实体中的数据向此端口赋值。
INOUT:定义的通道确定为输入输出双向端口。即从端口的内部看,可以对此端口进行赋值,或通过此端口读入外部的数据信息;而从端口的外部看,信号既可由此端口流出,也可向此端口输入信号。如 RAM 的数据口,单片机的 I/O 口等。
BUFFER:缓冲端口,其功能与 INOUT 类似,区别在于当需要 输入数据时,只允许内部回读输出的信号,即允许反馈。如计数器设计,可将计数器输出的计数信号回读,以作下一计数值的初值。与 INOUT 模式相比,BUFFER 回读的信号不是由外部输入的,而是由内部产生,向外输出的信号。
5,数据类型
例 3-4 中的 data_type 是数据类型名。例 3-1 中,端口信号 a,b,s 和 y 的数据类型都定义为 BIT。由于 VHDL 中任何一种数据对象的应用都必须严格限定其取值范围和数值类
EDA 技术 与 VHDL
74
型,即对其传输或存储的数据的类型要作明确的界定,因此,在 VHDL 设计中,必须预先定义好要使用的数据类型,这对于大 规模电路描述的排错是十分有益的。相关的数据类型有 INTEGER 类型,BOOLEAN 类型,STD_LOGIC 类型和 BIT 类型等。
BIT 数据类型的信号规定的取值范围是逻辑位 '1'和 '0'。在 VHDL 中,逻辑位 0 和 1 的表达必须加单引号,否则 VHDL 综合器将 0 和 1 解释为整数数据类型 INTEGER。
BIT 数据类型可以参与逻辑运算或算术运算,其结果仍是位的数据类型。 VHDL 综合器用一个二进制位表示 BIT。将例 3-1 中的端口信号 a,b,s 和 y 的数据类型都定义为 BIT
表示,a,b,s 和 y 的取值范围,或者说数据范围都被限 定在逻辑位 '1'和 '0'的二值范围内。
6,结构体表达
结构体的一般表达如例 3-5 所示。
【例 3-5】
ARCHITECTURE arch_name OF e_name IS
[说明语句 ]
BEGIN
(功能描述语句 )
END ARCHITECTURE arch_name ;
上式中,ARCHITECTURE,OF,IS,BEGIN和 END ARCHITECTURE都是描述结构体的关键词,在描述中必须包含它们。 arch_name 是结构体名,是 标识符 。
[说明语句 ]包括在结构体中,用以说明和定义数据 对象、数据类型、元件调用声明等等。 [说明语句 ]并非是必须的,(功能描述语句 )则不同,结构体中必须给出相应的电路功能描述语句,可以是并行语句,顺序语句或它们的混合。
一般地,一个可综合的,完整的 VHDL 程序有比较固定的结构。设计实体中,一般首先出现的是各类库及其程序包的使用声明,包括未以显式表达的工作库 WORK 库的使用声明,然后是实体描述,最后是结构体描述,而在结构体中可以含有不同的逻辑表达语句结构。如前所述,在此把一个完整的可综合的 VHDL 程序设计构建为 设计实体 (独立的电路功能结构),而其程序代码常被称为 VHDL 的 RTL 描述。
7,赋值符号和数据比较符号
例 3-1 中的表达式 y<= a 表示输入端口 a 的数据向输出端口 y 传输;但也可以解释为信号 a 向信号 y 赋值。在 VHDL 仿真中赋值操作 y<= a并非立即发生的,而是要经历一个模拟器的最小分辨时间?后,才将 a 的值赋予 y 。在此不妨将? 看成是实际电路存在的固有延时量。 VHDL 要求赋值符,<=”两边的信号的数据类型必须一致。
例 3-1 中,条件判断语句 WHEN_ELSE 通过测定表式 s='0' 的比较结果,以确定由哪一端口向 y 赋值。条件语句 WHEN_ELSE 的判定依据是表 式 s='0' 输出的结果。表式中的等号,=”没有赋值的含义,只是一种数据比较符号。其表式输出结果的数据类型是布尔数据类型 BOOLEAN。 BOOLEAN 类型的取值分别是,true(真 )和 false(伪 )。即当 s
为高电平时,表式 s='0' 输出,false”;当 s 为低电平时,表式 s ='0' 输出,true”。
在 VHDL 综合器或仿真器中分别用 '1'和 '0'表达 true 和 false。 布尔数据不是数值,只第 3 章 VHDL 入门
75
能用于逻辑操作或条件判断。
用于条件语句的判断表达式可以是一个值,也可以是更复杂的逻辑或运算表达式,如,
IF a THEN,.,-- 注意,a的数据类型必须是 boolean
IF (s1='0')AND(s2='1')OR(c<b+1) THEN,,
8,逻辑操作符
例 3-2 中出现的文字 AND,OR 和 NOT 是逻辑操作符号。 VHDL 共有 7 种基本逻辑操作符,它们是 AND(与 ),OR(或 ),NAND(与非 ),NOR(或非 ),XOR(异或 ),XNOR(同或 )
和 NOT(取反 )。信号在这些操作符的作用下可构成组合逻辑。逻辑操作符所要求的操作数
(操作对象 )的数据类型有 3 种,即 BIT,BOOLEAN 和 STD_LOGIC。
注意,与其他 HDL 用某种符号表达逻辑操作符不同,VHDL 中直接用对应的英语文字表达逻辑操作符号,这更明确显示了 VHDL 作为硬件行为描述语言的特征。
9,条件语句
例 3-3 利用 IF_THEN_ELSE 表达的 VHDL 顺序语句的方式,同样描述了一个多路选择器的电路行为。其结构体中的 IF 语句的执行顺序类似于软件语言,首先判断如果 s 为低电平,则执行 y<=a 语句,否则 (当 s 为高电平 ),则执行语句 y<=b。由此可见 VHDL 的顺序语句同样能描述并行运行的组合电路。注意,IF 语句必须以语 句,END IF;”结束。
10,WHEN_ELSE 条件信号赋值语句
例 3-1 中出现的是条件信号赋值语句,这是一种并行赋值语句,其表达方式如下,
赋值目标 <= 表达式 WHEN 赋值条件 ELSE
表达式 WHEN 赋值条件 ELSE
,.,
表达式 ;
在结构体中的条件信号赋值语句的功能与在进程中的 IF 语句相同,在执行条件信号语句时,每一“赋值条件”是按书写的先后关系逐项测定的,一旦发现 (赋值条件 = true),立即将“表达式”的值赋给“赋值目标”信号。
注意,由于条件测试的顺序性,条 件信号赋值语句中的第一子句具有最高赋值优先级,
第二句其次,如此类推。例如在以下程序中,如果当 p1 和 p2 同时为 '1'时,z 获得的赋值是
a 而不可能是 b 。还应该注意,相对于在同一结构体中的其它语句,此类赋值语句作为一个完整的语句,属于并行语句。
z <= a WHEN p1 = '1' ELSE
b WHEN p2 = '1' ELSE
c ;
11,进程语句和顺序语句
由例 3-3 可见,顺序语句,IF_THEN_ELSE_END IF;”是放在由,PROCESS..,END
PROCESS”引导的语句中的。由 PROCESS 引导的语句称为进程语句。在 VHDL 中,所有
EDA 技术 与 VHDL
76
合法的顺序描述语句都必须放在进程语句中。
PROCESS 旁的 (a,b,s)称为进程的敏感信号表,通常要求将进程中所有的输入信号都放在敏感信号表中。例如,例 3-3 中的输入信号是 a,b 和 s,所以将它们全部列入敏感信号表中。由于 PROCESS 语句的执行依赖于敏感信号的变化(或称发生事件),当某一敏感信号 (如 a)从原来的 '1'跳变到 '0',或者从原来的 '0'跳变到 '1'时,就将启动此进程语句,于是此 PROCESS 至 END PROCESS 引导的语句(包括其中的顺序语句)被执行一遍,然后返回进程的起始端,进入等待状态,直到下一次敏感信号表中某一信号或某些信号发生事件才再次进入“启动-运行”状态。
在一个结构体中可以包含任意个进程语句,所有的进程语句都是并行语句,而由任一进程 PROCESS 引导的语句(包含在其中的语句)结构属于顺序语句。
12,文件取名和存盘
如果用 QuartusII 提供的 VHDL 文本编辑器编辑 VHDL 代码文件,在保存文件时,必须赋给一个正确的文件名。一般地,文件名可以由设计者任意给定,但文件后缀扩展名必须是,.vhd”,如 adder_f.vhd。但考虑到某些 EDA 软件的限制和 VHDL 程序的特点,以及调用的方便性,因此建议程序的文件名尽可能与该程序的实体名一致,如例 3-1 的文件名应该是,mux21a.vhd。原则上文件名不分大小写,但推荐使用小写,特别是后缀。
3.2 简单时序电路的 VHDL 描述
与其他硬件描述语言相比,在时序电路的描述上,VHDL 具有许多独特之处。最明显的是 VHDL 主要通过对时序器件功能和逻辑行为的描述,而非结构上的描述使得计算机综合出符合要求的时序电路,从而充分体现了 VHDL 电路系统行为描述 的强大功能。
以下将对一个典型的时序元件 D 触发器的 VHDL 描述进行详细分析,从而得出时序电路描述的一般规律和设计方法。
3.2.1 D 触发器
最简单、最常用,并最具代表性的时序电路是 D 触发器,它是现代数字系统设计中最基本的时序单元和底层元件。 D 触发器的描述包含了 VHDL 对时序电路的最基本和典型的表达方式,同时也包含了 VHDL 中许多最具特色的语言现象。例 3-6 是对 D 触发器元件图
3-4 的描述。从 VHDL 的描述上看,与例 3-3 相比,例 3-6 多了 4 个部分,
(1) 由 LIBRARY 引导的库的说明部分。
(2) 使用了另一种数据类型,STD_LOGIC。
(3) 定义了一个内部节点信号,SIGNAL。
(4) 使用了一种新的条件判断表式,CLK'EVENT AND CLK = '1'。
第 3 章 VHDL 入门
77
除此之外,虽然例 3-3 描述的是组合电路,而例 3-6 描述的是时序电路,如果不详细分析其中的表述含义,二例在语句结构和语言应用上没有明显的差异,也不存在如其他硬件描述语言 (如 ABEL,AHDL)那样包含用于表示时序或组合逻辑的特征语句,更没有与特定的软件或硬件相关的特征属性语句。这也充分表明了 VHDL 电路描 述与设计平台和硬件实现对象无关性的优秀特点。
【例 3-6】
LIBRARY IEEE ;
USE IEEE.STD_LOGIC_1164.ALL ;
ENTITY DFF1 IS
PORT (CLK,IN STD_LOGIC ;
D,IN STD_LOGIC ;
Q,OUT STD_LOGIC );
END ;
ARCHITECTURE bhv OF DFF1 IS
SIGNAL Q1,STD_LOGIC ; --类似于在芯片 内部定义一个数据的暂存节点
BEGIN
PROCESS (CLK,Q1)
BEGIN
IF CLK'EVENT AND CLK = '1'
THEN Q1 <= D ;
END IF;
END PROCESS ;
Q <= Q1 ; --将内部的暂存数据向端口输出(双横线 --是注释符号)
END bhv;
3.2.2 D 触发器 VHDL 描述的语言现象说明
以下对例 3-6 中出现的新的语句语 言现象作出说明。
1,标准逻辑位数据类型 STD_LOGIC
从例 3-6 可见,D 触发器的 3 个信号端口 CLK,D 和 Q 的数据类型都被定义为
STD_LOGIC(例 3-1 中,端口信号的数据类型被定义为 BIT)。就数字系统设计来说,类型
STD_LOGIC 比 BIT 包含的内容丰富和完整得多,当然也包含了 BIT 类型。试比较以下
STD_LOGIC 和 BIT 两种数据类型的程序包定义表式 (其中 TYPE 是数据类型定义语句 )。
BIT 数据类型定义,
TYPE BIT IS('0','1'); --只有两种取值
STD_LOGIC 数据类型定义,
TYPE STD_LOGIC IS ('U','X','0','1','Z','W','L','H','-');
STD_LOGIC 所定义的 9 种数据的含义是,'U'表示未初始化的; 'X'表示强未知的; '0'
表示强逻辑 0; '1'表示强逻辑 1; 'Z'表示高阻态; 'W' 表示弱未知的; 'L'表示弱逻辑 0; 'H'
表示弱逻辑 1; '-'表示忽略。
图 3-4 D 触发器
EDA 技术 与 VHDL
78
它们完整地概括了数字系统中所有可能的数据表现形式,所以 例 3-6 中的 CLK,D 和
Q 比例 3-1 中的 a,b,s 具有更宽的取值范围,因而其描述和实际电路 有更好的适应性。
在仿真和综合中,将信号或其他数据对象定义为 STD_LOGIC 数据类型是非常重要的,
它可以使设计者精确地模拟一些未知的和具有高阻态的线路情况。对于综合器,高阻态 'Z'
和 '-'忽略态 (有的综合器用 'X')可用于三态的描述。 STD_LOGIC 型数据在数字器件中实现的只有其中的 4 到 5 种值,即 'X' (或 /和 '- '),'0','1'和 'Z',其他类型通常不可综合。
注意,此例中给出的 STD_LOGIC 数据类型的定义主要是借以学习一种新的语法现象,
而非 D 触发器等时序电路必须使用此类数据类型。
2,设 计库和标准程序包
有许多数据类型的说明,及类似的函数是预先仿在 VHDL 综合器附带的设计库和程序包中的。如 BIT 数据类型的定义是包含在 VHDL 标准程序包 STANDARD 中的,而程序包
STANDARD 包含于 VHDL 标准库 STD 中。一般,为了使用 BIT 数据类型,应该在例 3-1
的程序上面增加如下 3 句说明语句,
LIBRARY WORK ;
LIBRARY STD ;
USE STD.STANDARD.ALL ;
第 2 句中的 LIBRARY 是关键词,LIBRARY STD 表示打开 STD 库;第 3 句的 USE 和
ALL 是关键词,全句表示允许使用 STD 库中 STANDARD 程序包中的所有内容 (.ALL),如类型定义、函数、过程、常量等。
此外,由于要求 VHDL 设计文件保存在某一文件夹,如 d:\myfile 中,并指定为工程 PROJECT 的文件所在的目录,VHDL 工具就将此路径指定的文件夹默认工作库 (WORK
LIBRARY),于是在 VHDL程序前面还应该增加,LIBRARY WORK;”语句,VHDL 工具才能调用此路径中相关的元件和程序包。
但是,由于 VHDL 标准中规定标准库 STD 和工作库 WORK 都是默认打开的,因此就可以像例 3-1 那样,不必将上述库和程序包的使用语句以显式表达在 VHDL 程序中。除非如例 3-6 那样,需要使用一些特殊的程序包。
使用库和程序包的一般定义表式是,
LIBRARY <设计库名 >;
USE < 设计库名 >.<程序包名 >.ALL ;
STD_LOGIC 数据类型定义在被称为 STD_LOGIC_1164 的程序包中,此包由 IEEE 定义,而且此程序包所在的程序库的库名被取名为 IEEE。由于 IEEE 库不属于 VHDL 标准库,
所以在使用其库中内容前,必须事先给予声明。即如例 3-6 最上的两句语句,
LIBRARY IEEE ;
USE IEEE.STD_LOGIC_1164.ALL ;
正是出于需要定义端口信号的数据类型为 STD_LOGIC的目的,当然也可以定义为 BIT
类型或其他数据类型,但一般应用中推荐定义 STD_LOGIC 类型。
第 3 章 VHDL 入门
79
3,信号定义和数据对象
例 3- 6 中的语句,SIGNAL Q1,STD_LOGIC;”表示在描述的器件 DFF1 内部定义标识符 Q1 的数据对象为信号 SIGNAL,其数据类型为 STD_LOGIC。由于 Q1 被定义为器件的内部节点信号,数据的进出不像端口信号那样受限制,所以不必定义其端口模式 (如 IN、
OUT 等 )。定义 Q1 的目的是为了在设计更大的电路时使用由此引入的时序电路的信号,这是一种常用的时序电路设计的方式。事实上,如果在例 3-6 中不作 Q1 的定义,其结构体 (如将其中的赋值语句 Q1 <= D 改为 Q <= D)同样能综合出相同的结果,但不推荐这种设计方式。
语句,SIGNAL Q1,STD_LOGIC;,中的 SIGNAL 是定义某标识符为 信号 的关键词。
在 VHDL 中,数据对象 (Data Objects)类似于一种容器,它接受不同数据类型的赋值。数据对象有 3 类,即信号 (SIGNAL)、变量 (VARIABLE)和常量 (CONSTANT)。在 VHDL
中,被定义的标识符必须确定为某类数据对象,同时还必须被定义为某种数据类型。如例
3-6 中的 Q1,对它规定的数据对象是信号,而数据类型是 STD_LOGIC,前者规定了 Q1 的行为方式和功能特点,后者限定了 Q1 的取值范围。 VHDL 规定,Q1 作为信号,它可以如同一根连线那样在整个结构体中传递信息,也可以根据程序的功能描述构成一个时序元件;
但 Q1 传递或存储的数据的类型只能包含在 STD_LOGIC 的定义中。
需要注意的是,语句,SIGNAL Q1,STD_LOGIC;,仅规 定了 Q1 的属性特征,而其功能定位需要由结构体中的语句描述具体确定。如果将 Q1 比喻为一瓶葡萄酒,则其特定形状的酒瓶就是其数据对象,瓶中的葡萄酒 (而非其他酒 )就是其数据类型,而这瓶酒的用处(功能)只能由拥有这酒的人来确定,即结构体中的具体描述。
4,上升沿检测表式和信号属性函数 EVENT
例 3-6 中的条件语句的判断表式,CLK'EVENT AND CLK='1'” 是用于检测时钟信号
CLK 的上升沿的,即如果检测到 CLK 的上升沿,此表达式将输出,true”。
关键词 EVENT 是信号属性函数,用来获得信号行为信息的 函数称为信号属性函数。
VHDL 通过以下表式来测定某信号的跳变情况,
< 信号名 > 'EVENT
短语,clock'EVENT”就是对 clock 标识符的信号在当前的一个极小的时间段? 内发生事件的情况进行检测。所谓发生事件,就是 clock 在其数据类型的取值范围内发生变化,
从一种取值转变到另一种取值(或电平方式)。如果 clock 的数据类型定义为 STD_LOGIC,
则在? 时间段内,clock 从其数据类型允许的 9 种值中的任何一个值向另一值跳变,如由 '0'
变成 '1'、由 '1'变成 '0'或由 'Z'变成 '0',都认为发生 了事件,于是此表式将输出一个布尔值 true,
否则为 false。
如果将以上短语 clock'EVENT 改成语句,clock'EVENT AND clock='1',则表示一旦,clock'EVENT”在? 时间内测得 clock 有一个跳变,而此小时间段? 之后又测得 clock 为高电平 '1',即满足此语句右侧的 clock ='1'的条件,于是两者相与 (AND)
后返回值为 true,由此便可以从当前的 clock ='1'推断在此前的? 时间段内,clock
必为 '0' (设 clock 的数据类型是 BIT)。因此,以上的 表达式就可以用来对信号 clock
EDA 技术 与 VHDL
80
的上升沿进行检测,于是语句 clock’ EVENT AND clock ='1'就成了边沿测试语句 。
5,不完整条件语句与时序电路
现在来分析例 3-6 中对 D 触发器功能的描述。
首先考察时钟信号 CLK上升沿出现的情况(即满足 IF 语句条件的情况)。当 CLK 发生变化时,PROCESS 语句被启动,IF 语句将测定条件表式,CLK'EVENT AND CLK='1'”
是否满足条件,如果 CLK 的确出现了上升沿,则满足条件表式对是上升沿检测,于是执行语句 Q1<=D,即将 D 的数据向内部信 号 Q1 赋值,即更新 Q1,并结束 IF 语句,最后将 Q1
的值向端口信号 Q 输出。至此,是否可以认为,CLK 上升沿测定语句 CLK'EVENT AND
CLK='1'就成为综合器构建时序电路的必要条件呢?回答显然是否定的。
其次再考察如果 CLK 没有发生变化,或者说 CLK没有出现上升沿方式的跳变时 IF 语句的行为。这时由于 IF 语句不满足条件,即条件表式给出,FALSE”,于是将跳过赋值表式 Q1<=D,不执行此赋值表式而结束 IF 语句。由于在此,IF 语句中没有利用通常的 ELSE
语句明确指出当 IF 语句不满足条件时作何操作。显然这是一种 不完整的条件语句 (即在条件语句中,没有将所有可能发生的条件给出对应的处理方式 )。对于这种语言现象,VHDL
综合器理解为,对于不满足条件,跳过赋值语句 Q1<=D 不予执行,即意味着保持 Q1 的原值不变(保持前一次时钟上升沿后 Q1 被更新的值)。对于数字电路来说,试图保持一个值不变,就意味着具有存储功能的元件的使用,就是必须引进时序元件来保存 Q1 中的原值,
直到满足 IF 语句的判断条件后才能更新 Q1 中的值。
显然,时序电路构建的关键在于利用这种不完整的条件语句的描述。这种构成时序电路的方式是 VHDL 描述时序电路最重要的途 径。通常,完整的条件语句只能构成组合逻辑电路,如例 3-3 中,IF_THEN_ELSE 语句指明了 s 为 '1'和 '0'全部可能的条件下的赋值操作,
从而产生了多路选择器组合电路模块。
然而必须注意,虽然在构成时序电路方面,可以利用不完整的条件语句所具有的独特功能构成时序电路,但在利用条件语句进行纯组合电路设计时,如果没有充分考虑电路中所有可能出现的问题,即没有列全所有的条件及其对应的处理方法,将导致不完整的条件语句的出现,从而产生设计者不希望的组合与时序电路的混合体。在此,不妨比较例 3-7
和例 3-8 的综合结果。可以 认为例 3-7 的原意是要设计一个纯组合电路的比较器,但是由于在条件语句中漏掉了给出当 a1= b1 时 q1 作何操作的表述,结果导致了一个不完整的条件语句。这时,综合器将对例 3-7 的条件表述解释为:当条件 a1= b1 时对 q1 不作任何赋值操作,即在此情况下保持 q1 的原值,这便意味着必须为 q1 配置一个寄存器,以便保存它的原值。图 3-5 所示的电路图即为例 3-7 的综合结果。不难发现综合器已为比较结果配置了一个寄存器。通常在仿真时,对这类电路的测试,很难发现在电路中已被插入了不必要的时序元件,这样浪费了逻辑资源,降低了电路的工作 速度,影响了电路的可靠性。因此,设计者应该尽量避免此类电路的出现。
例 3-8 是对例 3-7 的改进,其中的,ELSE q1<='0'”语句即已交代了当 a1 小于等于 b1
情况下,q1 作何赋值行为,从而能产生图 3-6 所示的简洁的组合电路。
第 3 章 VHDL 入门
81
现在已不难发现,引入时序电路结构的必要条件和关键所在并非是边沿检测表述
,clock'EVENT AND clock='1'” 的应用或是其他什么语句结构,而是不完整的任何形式的条件语句的出现,且不局限于 IF 语句。
【例 3-7】
ENTITY COMP_BAD IS
PORT( a1,b1,IN BIT;
q1,OUT BIT );
END ;
ARCHITECTURE one OF COMP_BAD IS
BEGIN
PROCESS (a1,b1)
BEGIN
IF a1 > b1 THEN q1 <= '1' ;
ELSIF a1 < b1 THEN q1 <= '0' ;-- 未提及当 a1=b1时,q1作何操作
END IF;
END PROCESS ;
END ;
【例 3-8】
..,
IF a1 > b1 THEN q1 <= '1' ;
ELSE q1 <= '0' ; END IF;
..,
图 3-5 例 3-7的电路图( Synplify综合) 图 3-6 例 3-8的电路图( Synplify综合)
3.2.3 实现时序电路的不同表述
例 3-6 通过利用表式,CLK'EVENT AND CLK='1'” 来检测 CLK的上升沿,从而实现了边沿触发寄存器的设计。事实上,VHDL 还有其他多种 实现时序元件的方式。
严格地说,如果信号 CLK 的数据类型是 STD_LOGIC,则它可能的取值有 9 种,而
CLK'EVENT 为真的条件是 CLK 在 9 种数据中的任何两种间的跳变,因而当表式,
CLK'EVENT AND CLK='1'
为真时,并不能推定 CLK 在? 时刻前是 '0' (例如,它可以从 'Z'变到 '1'),从而即使 CLK 有“事件”发生也不能肯定 CLK 发生了一次由 '0'到 '1'的上升沿的跳变。为了确保此 CLK 发生的是一次上升沿的跳变,例 3-9 采用了如下的条件判断表式,
CLK'EVENT AND (CLK='1') AND (CLK'LAST_VALUE='0')
EDA 技术 与 VHDL
82
与 ‘ EVENT 一样,’LAST_VALUE 也属于预定义的信号属性函数,它表示最近一次事件发生前的值。 CLK’LAST_VALUE='0'为 TRUE,表示 CLK 在? 时刻前为 '0'。
CLK'EVENT AND CLK='1'和 CLK’ LAST_VALUE='0'相与为真的话,则保证了 CLK
在? 时刻内的跳变是从 '0'变到 '1'的。例 3-9,3-10,3-11 都有相同的用意,只是例 3-11 调用了一个测定 CLK 上升沿的函数 rising edge( )。
rising edge( )是 VHDL 在 IEEE 库中标准程序包 STD_LOGIC_1164 内的预定义函数,
这条语句只能用于标准逻辑位数据类型 STD_LOGIC 的信号。因此必须打开 IEEE 库和程序包 STD_LOGIC_1164,然后定义相关的信号 (如 CLK)的数据类型为标准逻辑位数据类型
STD_LOGIC。在此 CLK 的数据类型必须是 STD_LOGIC。
测下降沿可用的语句有,falling edge( ),CLK'EVENT AND (CLK='0'),
CLK='0' AND CLK'LAST_VALUE='1' 等。
【例 3-9】
..,
PROCESS (CLK)
BEGIN
IF CLK'EVENT AND (CLK='1') AND (CLK'LAST_VALUE='0')
THEN Q <= D ; --确保 CLK的变化是一次上升沿的跳变
END IF;
END PROCESS ;
【例 3-10】
..,
PROCESS (CLK)
BEGIN
IF CLK='1' AND CLK'LAST_VALUE='0' --同例 3-9
THEN Q <= D ;
END IF;
END PROCESS ;
【例 3-11】
LIBRARY IEEE ;
USE IEEE.STD_LOGIC_1164.ALL ;
ENTITY DFF3 IS
PORT (CLK,D,IN STD_LOGIC ;
Q,OUT STD_LOGIC );
END ;
ARCHITECTURE bhv OF DFF3 IS
SIGNAL Q1,STD_LOGIC;
BEGIN
PROCESS (CLK)
BEGIN
IF rising_edge(CLK) -- 必须打开 STD_LOGIC_1164程序包
THEN Q1 <= D ;
END IF;
END PROCESS ;
Q <= Q1 ; --在此,赋值语句可以放在进程外,作为并行赋值语句
第 3 章 VHDL 入门
83
END ;
例 3-12 则是利用了一条 wait until 语句实现时序电路设计的,含义是如果 CLK 当前的值不是 '1',就等待并保持 Q 的原值不变,直到 CLK 变为 '1'时才对 Q 进行赋值更新。 VHDL
要求,当进程语句中使用 wait 语句后,就不必列出敏感信号。
例 3-13 描述的 D 触发器的 CLK边沿检测是由 PROCESS 语句和 IF 语句相结合实现的。
其原理是:当 CLK 为 '0'时,PROCESS 语句处于等待状态,直到发生一次由 '0'到 '1'的跳变才启动进程语句,而在执行 IF 语句时,又满足了 CLK 为 '1'的条件,于是对 Q 进行赋值更新,而此前,Q 一直保持原值不变,直到下一次上跳时钟边沿的到来。因此例 3-9 至例 3-13
描述的都是相同的 D 触发器,其电路的仿真测试波形如图 3-7 所示。由波形可见,Q 的变化仅发生于 CLK 的上升沿后。
与例 3-13 相比,例 3-14 仅在敏感信号表中多加了电路输入信号 D,但综合后的电路功能却发生了很大的变化。由时序图 3-8 可见,它表现的是电平式触发的锁存器功能,与图
3-7 表现的波形有很大的区别。在 CLK 处于高电平时,输出 Q 随 D 的变化而变化,而 CLK
仅在低电平时保持数据不变。
由例 3-14 的语句分析可知,当 CLK为 '1'不变时,输入数据 D 的任何变化都会启动进程 PROCESS,从而实现输出信号 Q 的更新,而当 CLK 原来为 '0'时,即使由于 D 的变化启动了 PROCESS,但由于不满足 IF 语句的条件,Q 仍然必须处于数据原值保存的状态。显然,例 3-14 提供了一个电平型触发的时序元件 (锁存器 )的设计方法。
但需要指出,此类功能只有 MaxplusII,QuartusII 等 EDA 工具中含有,许多其他 VHDL
综合器不承认这类语法表述,它们都要求将进程中的所有输入信号都列进敏感信号表中,
否则给予警告信息。因此,对于这种综合器,无法利用此类表述实现电平型触发的时序元件,显然,具体情况需要根据设计者使用的 EDA 软件的功能具体确定。在一般情况下,不推荐使用例 3-14 的表达方式产生时序电路 。
由例 3-9 至例 3-14 可见,时序电路的建立只能利用进程中的顺序语句来建立。此外,
考虑到多数综合器并不理会边沿检测语句中的信号的 STD_LOGIC 数据类型,因此最常用和通用的边沿检测表式仍然是 CLK'EVENT AND CLK='1'。
【例 3-12】
..,
PROCESS
BEGIN
wait until CLK = '1' ; --利用 wait语句
Q <= D ;
END PROCESS;
【例 3-13】
..,
PROCESS (CLK)
BEGIN
IF CLK = '1'
THEN Q <= D ; --利用进程的启动特性产生对 CLK的边沿检测
END IF;
EDA 技术 与 VHDL
84
END PROCESS ;
【例 3-14】
..,
PROCESS (CLK,D) BEGIN
IF CLK = '1' --电平触发型寄存器
THEN Q <= D ;
END IF;
END PROCESS ;
图 3-7 例 3-13 的时序波形 图 3-8 例 3-14 的时序波形
3.2.4 异步时序电路设计
可以将构成时序电路的进程称为时钟进程。在时序电路设计中应注意,一个时钟进程只能构成对应单一时钟信号的时序电路,如果在进程中需要构成多触发器时序电路,也只能产生对应某个单一时钟的同步时序逻辑。异步逻辑最好用多个时钟进程语句来构成。例
3-15 用两个时钟进程描述了一个异步时序电路,综合后的电路如图 3-9 所示。
其中,进程标号 PRO1 和 PRO2 只是一种标注符号,不参加综合。程序中,时钟进程
PRO1 的赋值信号 Q1 成了时钟进程 PRO2 的敏感信号及时钟信 号。这两个时钟进程通过
Q1 进行通信联系。显然,尽管两个进程都是并行语句,但它们被执行(启动)的时刻并非同时,因为根据敏感信号的设置,进程 PRO1 总是先于 PRO2 被启动。
【例 3-15】
,.,
ARCHITECTURE bhv OF MULTI_DFF IS
SIGNAL Q1,Q2,STD_LOGIC;
BEGIN
PRO1,PROCESS (CLK)
BEGIN
IF CLK'EVENT AND CLK='1'
THEN Q1 <= NOT (Q2 OR A);
END IF;
END PROCESS ;
PRO2,PROCESS (Q1)
BEGIN
IF Q1'EVENT AND Q1='1'
THEN Q2 <= D;
END IF;
END PROCESS ;
QQ <= Q2 ;
,.,
第 3 章 VHDL 入门
85
图 3-9 例 3-15 综合后的电路( Synplify 综合)
3.3 含有层次结构的 VHDL 描述
以下通过一个全加器的设计流程,介绍含有层次结构的 VHDL 程序,其中包含两个重要的语句,元件调用声明语句和元件例化语句。
3.3.1 半加器描述和 CASE 语句
由图 3-11 可见,1 位全加器可以由两个半加器和一个或门连接而成,因而可根据半加器的电路原理图 (图 3-10)或真值表写出或门和半加器的 VHDL 描述:例 3-16、例 3-17。然后根据图
3-11 写出全加器的顶层 VHDL 描述:例 3-19。以下详细说明程序中语句的含义和用法。
co
a
sob
10
010
1
011
000
1
1
0
0
cosoba
not xnor2
and2
图 3-10 半加器 h_adder 电路图及其真 值表
aincout cout
ain bin
sumcin
bin sum
cin
f_adder
or2a
f
e
d
u3
u2
u1
b
a c
co
soB
co
soB
h_adder
A
h_adder
A
图 3-11 全加器 f_adder 电路图及其实体模块
【例 3-16】
LIBRARY IEEE; --半加器描述 (1):布尔方程描述方法
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY h_adder IS
PORT (a,b,IN STD_LOGIC;
co,so,OUT STD_LOGIC);
END ENTITY h_adder;
EDA 技术 与 VHDL
86
ARCHITECTURE fh1 OF h_adder is
BEGIN
so <= NOT(a XOR (NOT b)) ; co <= a AND b ;
END ARCHITECTURE fh1;
【例 3-17】
LIBRARY IEEE; --半加器描述 (2):真值表描述方法
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY h_adder IS
PORT (a,b,IN STD_LOGIC;
co,so,OUT STD_LOGIC);
END ENTITY h_adder;
ARCHITECTURE fh1 OF h_adder is
SIGNAL abc,STD_LOGIC_VECTOR(1 DOWNTO 0) ; --定义标准逻辑位矢量数据类型
BEGIN
abc <= a & b ; --a相并 b,即 a与 b并置操作
PROCESS(abc)
BEGIN
CASE abc IS --类似于真值表的 CASE语句
WHEN "00" => so<='0'; co<='0' ;
WHEN "01" => so<='1'; co<='0' ;
WHEN "10" => so<='1'; co<='0' ;
WHEN "11" => so<='0'; co<='1' ;
WHEN OTHERS => NULL ;
END CASE;
END PROCESS;
END ARCHITECTURE fh1 ;
【例 3-18】
LIBRARY IEEE ; --或门逻辑描述
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY or2a IS
PORT (a,b,IN STD_LOGIC;
c,OUT STD_LOGIC );
END ENTITY or2a;
ARCHITECTURE one OF or2a IS
BEGIN
c <= a OR b ;
END ARCHITECTURE fu1;
【例 3-19】
LIBRARY IEEE; --1位二进制全加器顶层设计描述
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY f_adder IS
PORT (ain,bin,cin,IN STD_LOGIC;
cout,sum,OUT STD_LOGIC );
END ENTITY f_adder;
ARCHITECTURE fd1 OF f_adder IS
COMPONENT h_adder --调用半加器声明语句
PORT ( a,b,IN STD_LOGIC;
第 3 章 VHDL 入门
87
co,so,OUT STD_LOGIC);
END COMPONENT ;
COMPONENT or2a
PORT (a,b,IN STD_LOGIC;
c,OUT STD_LOGIC);
END COMPONENT;
SIGNAL d,e,f,STD_LOGIC; --定义 3个信号作为内部的连接线。
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,or2a PORT MAP(a=>d,b=>f,c=>cout);
END ARCHITECTURE fd1;
3.3.2 半加器描述
半加器可以有多种表达方式。例 3-16 是根据电路原理图图 3-10 写出的,是用并行赋值语句表达的,其中逻辑操作符 XOR 是异或逻辑操作符。双横线,--”是注释符,在 VHDL
程序的任何一行中,双横线,--”后的文字都不参加编译和综合。例 3-17 的表达方式与半加器的逻辑真值表(图 3-10 右)相似。利用 CASE 语 句来直接表达电路的逻辑真值表是一种十分有效和直观的方法。以下将对一些新的语言现象给予说明。
1,CASE 语句
CASE 语句属于顺序语句,因此必须放在进程语句中使用。 CASE 语句的一般表述是,
CASE <表达式 > IS
When <选择值或标识符 > => <顺序语句 >;,.,; <顺序语句 > ;
When <选择值或标识符 > => <顺序语句 >;,.,; <顺序语句 > ;
..,
WHEN OTHERS => <顺序语句 >;
END CASE ;
当执行到 CASE 语句时,首先计算 <表达式 > 的值,然后根据 WHEN 条件句中与之相同的 <选择值或表识符 >,执行对应的 <顺序语句 >,最后结束 CASE 语句。条件句中的 =>
不是操作符,它的含义相当于 THEN(或“于是” )。 CASE 语句使用中应该注意以下几点,
WHEN 条件句中的选择值或标识符所代表的值必须在表达式的取值范围内。
除非所有条件句中的选择值能完整覆盖 CASE 语句中表达式的取值,否则最末一个条件句中的选择必须加上最后一句,WHEN OTHERS => <顺序语句 >;。 关键词
OTHERS 表示以上已列的所有条件句中未能列出的其他可能的取值。 OTHERS 只能出 现一次,且只能作为最后一种条件取值。使用 OTHERS 的目的是为了使条件句中的所有选择值能涵盖表达式的所有取值,以免综合器会插入不必要的锁存器。
关键词 NULL 表示不作任何操作。
CASE 语句中的选择值只能出现一次,不允许有相同选择值的条件语句出现。
CASE 语句执行中必须选中,且只能选中所列条件语句中的一条。
例 3-17 中的 CASE 语句的功能是,当 CASE 语句的表达式 abc 由输入信号 a 和 b 分
EDA 技术 与 VHDL
88
别获得 '0'和 '0'时,即当 abc="00"时,so 输出 '0',即 so<='0'; co 输出 '0',即
co<='0';当 abc="01"时,so 输出 '1'; co 输出 '0',以此类推。
2,标准逻辑矢量数据类型
标准逻辑矢量数据类型 STD_LOGIC_VECTOR 与 STD_LOGIC 一样,都定义在
STD_LOGIC_1164 程序包中,但 STD_LOGIC 属于标准位类型,而 STD_LOGIC_VECTOR
被定义为标准一维数组,数组中的每一个元素的数据类型都是标准逻辑位 STD_LOGIC。使用 STD_LOGIC_VECTOR 可以表达电路中并列的多通道端口或节点,或者总线 BUS。
在使用 STD_LOGIC_VECTOR 中,必须注明其 数组宽度,即位宽,如,
B,OUT STD_LOGIC_VECTOR(7 DOWNTO 0) ;
或 SIGNAL A,STD_LOGIC_VECTOR(1 TO 4)
上句表明标识符 B 的数据类型被定义为一个具有 8 位位宽的矢量或总线端口信号,它的最左位,即最高位是 B(7),通过数组元素排列指示关键词,DOWNTO”向右依次递减为
B(6),B(5)… B(0)。根据以上两式的定义,A 和 B 的赋值方式如下,
B <= "01100010" ; -- B(7)为 '0'
B(4 DOWNTO 1) <= "1101" ; -- B(4)为 '1'
B(7 DOWNTO 4) <= A ; -- B(6)等于 A(2)
其中的,01100010”表示二进制数 (矢量位 ),必须加双引号,如,01” ;而单一二进制数则用单引号,如 '1'。
语句 SIGNAL A,STD_LOGIC_VECTOR(1 TO 4)中的 A 的数据类型被定义为 4 位位宽总线,数据对象是信号 SIGNAL,其最左位是 A(1),通过关键词,TO”向右依次递增为 A(2),A(3)和 A(4)。
与 STD_LOGIC_VECTOR 对应的是 BIT_VECTOR 位矢量数据类型,其每一个元素的数据类型都是逻辑位 BIT,使用方法与 STD_LOGIC_VECTOR 相同,如,
SIGNAL C,BIT_VECTOR(3 DOWNTO 0);
例 3-17 中的的内部信号被定义为二元素的 STD_LOGIC_VECTOR 数据类型,高位是
abc(1),低位是 abc(0)。
3,并置操作符?
在例 3-17 中的操作符? 表示将操作数 (如逻辑位 '1' 或 '0' )或是数组合并起来形 成新的数组。例如,VH”?,DL”的结果为,VHDL”; '0'? '1'? '1'的结果为 ''011''。
显然,语句 abc <= a & b 的作用是令,abc(1)<= a; abc(0)<= b 。
因此,利用并置符,可以有多种方式来建立新的数组,如可以将一个单元素并置于一个数的左端或右端形成更长的数组,或将两个数组并置成一个新数组等,在实际运算过程中,要注意并置操作前后的数组长度应一致。以下是一些并置操作示例,
SIGNAL a,STD_LOGIC_VECTOR (3 DOWNTO 0) ;
SIGNAL d,STD_LOGIC_VECTOR (1 DOWNTO 0) ;
..,
a <= '1'? '0'? d(1)? '1' ; -- 元素与元素并置,并置后的数组长度为 4
第 3 章 VHDL 入门
89
..,
IF a? d = "101011" THEN,.,–- 在 IF条件句中可以使用并置符
3.3.3 全加器描述和例化语句
例 3-19 是按照图 3-11 的连接方式完成的全加器的 VHDL 顶层文件。为了达到连接底层元件形成更高层次的电路设计结构,文件中使用了例化语句。文件在实体中首先定义了全加器顶层设计元件的端 口信号,然后在 ARCHITECTURE 和 BEGIN 之间利用
COMPONENT 语句对准备调用的元件 (或门和半加器 )作了声明,并定义了 d,e,f 三个信号作为器件内部的连接线 (见图 3-11)。最后利用端口映射语句 PORT MAP( )将两个半加器和一个或门连接起来构成一个完整的全加器。
元件例化就是引入一种连接关系,将预先设计好的设计实体定义为一个元件,然后利用特定的语句将此元件与当前的设计实体中的指定端口相连接,从而为当前设计实体引进一个新的低一级的设计层次。在这里,当前设计实体 (如例 3-19 描述的全加器 )相当 于一个较大的电路系统,所定义的例化元件相当于一个要插在这个电路系统板上的芯片,而当前设计实体中指定的端口则相当于这块电路板上准备接受此芯片的一个插座。元件例化是使 VHDL 设计实体构成自上而下层次化设计的一种重要途径。
元件例化是可以多层次的,一个调用了较低层次元件的顶层设计实体本身也可以被更高层次设计实体所调用,成为该设计实体中的一个元件。任何一个被例化语句声明并调用的设计实体可以以不同的形式出现,它可以是一个设计好的 VHDL 设计文件 (即一个设计实体 ),可以是来自 FPGA 元件库中的元件或是 FPGA 中器件中的 嵌入式元件功能块,或是以别的硬件描述语言,如 AHDL 或 Verilog 设计的元件,还可以是 IP 核。
元件例化语句由两部分组成,第一部分是对一个现成的设计实体定义为一个元件,语句的功能是对待调用的元件作出调用声明,它的最简表达式如下所示,
COMPONENT 元件名 IS
PORT (端口名表 ) ;
END COMPONENT 文件名 ;
这一部分可以称为是元件定义语句,相当于对一个现成的设计实体进行封装,使其只留出对外的接口界面。就像一个集成芯片只留几个引脚在外一样,端口名表需要列出该元件对外通信的各端口 名。命名方式与实体中的 PORT( )语句一致。元件定义语句必须放在结构体的 ARCHITECTURE 和 BEGIN 之间。另外应注意,尽管例 3-19 中对或门和半加器的调用声明的端口说明中使用了与原来元件( VHDL 描述)相同的端口符号,但这并非是唯一的表达方式,如可以作如下表达(注意,数据类型的定义则必须与原文件一致),
COMPONENT h_adder
PORT ( c,d,IN STD_LOGIC;
e,f,OUT STD_LOGIC);
元件例化语句的第二部分则是此元 件与当前设计实体 (顶层文件 )中元件间及端口的连接说明。语句的表达式如下,
EDA 技术 与 VHDL
90
例化名,元件名 PORT MAP( [端口名 =>] 连接端口名,...);
其中的例化名是必须存在的,它类似于标在当前系统 (电路板 )中的一个插座名,而元件名则是准备在此插座上插入的、已定义好的元件名,即为待调用的 VHDL 设计实体的实体名。对应于例 3-19 中的元件名 h_adder 和 or2a,其例化名分别为 u1,u2 和 u3。 PORT MAP
是端口映射的意思,或者说端口连接。其中的“端口名”是在元件定义语句中的端口名表中已定义好的元 件端口的名字,或者说是顶层文件中待连接的各个元件本身的端口名;“连接端口名”则是顶层系统中,准备与接入的元件的端口相连的通信线名,或者是顶层系统的端口名。
以例 3-19 中的例化名为 u1 的端口映射语句为例,其中 a=>ain 表示元件 h_adder 的内部端口信号 a(端口名 )与系统的外部端口名 ain 相连; co=>d 则表示元件 h_adder 的内部端口信号 co(端口名 )与元件外部的连线 d(定义在内部的信号线 )相连,如此等等。
注意,这里的符号,=>”是连接符号,其左面放置内部元件的端口名,右面放置内部元件以外需要连接的 端口名或信号名,这种位置排列方式是固定的,但连接表达式 (如 co=>d)在 PORT MAP 语句中的位置是任意的。
在例 3-18 中将一个简单的或门用一个完整的文件描述出来,主要是借此说明多层次设计和元件例化的设计流程和方法。在实际设计中完全没有必要如此繁琐。
3.4 计数器设计
在了解了 D 触发器的 VHDL 基本语言现象和设计方法后,对于计数器的设计就比较容易理解了。例 3-20 所示的是 4 位二进制加法计数器的 VHDL 描述,下面对此例的设计原理和例中出现的一些新的语法现象在作一些补充说明。
【例 3-20】
ENTITY CNT4 IS
PORT ( CLK,IN BIT ;
Q,BUFFER INTEGER RANGE 15 DOWNTO 0 ) ;
END ;
ARCHITECTURE bhv OF CNT4 IS
BEGIN
PROCESS (CLK)
BEGIN
IF CLK'EVENT AND CLK = '1' THEN
Q <= Q + 1 ;
END IF;
END PROCESS ;
END bhv;
3.4.1 4 位加法计数器
第 3 章 VHDL 入门
91
例 3-20 电路的输入端口只有一个:计数时钟信号 CLK;数据类型是二进制逻辑位 BIT;
输出端口 Q 的端口模式定义为 BUFFER,其数据类型定义为整数类型 INTEGER。
由例 3-20 中的计数器累加表式 Q<=Q + 1 可见,在符号 <=的两边都出现了 Q,表明 Q
应当具有输入和输出两种端口模式特性,同时它的输入特性应该是反馈方式,即传输符,<=”
右边的 Q 来自左边的 Q(输出信号 )的反馈。显然,Q 的端口模式与 BUFFER 是最吻合的,
因而定义 Q 为 BUFFER 模式。
注意,表面上 BUFFER 具有双向端口 INOUT 的功能,但实际上其输入功能是不完整的,它只能将自己输出的信号再反馈回来,并不含有 IN 的功能。
VHDL 规定加、减等算术操作符 +、- 对应的操作数,如式 a + b 中的 a 和 b 的数据类型只能是 INTEGER(除非对算术操作符有一些特殊的说明,如重载函数的利用 )。因此如果定义 Q 为 INTEGER,表式 Q <= Q + 1的运算和数据传输都能满足 VHDL 对加、
减等算术操作的基本要求,即式中的 Q 和 1 都是整数,满足符号,<=,两边都是整数,
加号,+,两边也都是整数的条件 。
例 3-20 中的时序电路描 述与例 3-6 中的 D 触发器描述是基本一致的,也使用了 IF 语句的不完整描述,使得当不满足时钟上升沿条件,即,CLK'EVENT AND CLK='1'” 表式的返回值是,false”时,不执行语句 Q <= Q + 1,即将 上一时钟上升沿的赋值 Q+1 仍保留在左面的 Q 中,直到满足检测到 CLK 的新的上升沿才得以更新数据。
注意,表式 Q <= Q + 1 的右项与左项并非处于相同的时刻内,对于时序电路,除了传输延时外,前者的结果出现于当前时钟周期;后者,即左项要获得当前的 Q + 1,
需等待下一个时钟周期。
3.4.2 整数类型
整数类型 INTEGER 的元素包含正整数、负整数和零。在 VHDL 中,整数的取值范围是- 2147483647~+ 2147483647,即可用 32 位有符号的二进制数表示。注意,通常 VHDL
仿真器将 INTEGER 类型作为有符号数处理,而 VHDL 综合器则将 INTEGER 作为无符号数处理。在使用整数时,VHDL 综合器要求必须使用,RANGE”子句为所定义的数限定范围,然后根据所限定的范围来决定表示此信号或变量的二进制数的位数,因为 VHDL 综合器无法综合未限定范围的整数类型的信号或变量。例 3-20 中的语句,
Q,BUFFER INTEGER RANGE 15 DOWNTO 0;
即限定 Q 的取值范围是 0~ 15,共 16 个值,可用 4 位二进制数来表示。因此,VHDL
综合器即将 Q 综合成由四条信号线构成的总线式信号,Q(3),Q(2),Q(1)和 Q(0)。
整数常量的书写方式示例如下,
1 十进制整数
0 十进制整数
35 十进制整数
10E3 十进制整数,等于十进制整数 1000
16#D9# 十六进制整数,等于十六进制整数 D9H
EDA 技术 与 VHDL
92
8#720# 八进制整数,等于八进制整数 720O
2#11010010# 二进制整数,等于二进制整数 11010010B
注意,在语句中,整数的表达不加引号,如,1,0,25 等;而逻辑位的数据必须加引号,如 '1','0',"10","100111"。
自然数类型 NATURAL 是整数类型的一个子类型,它包含 0 和所有正整数。
如果对例 3-20 的 Q 定义为 NATURAL 类型,综合的结果不变,语句可表达为,
Q,BUFFER NATURAL RANGE 15 DOWNTO 0;
正整数类型 POSITIVE 也是整数类型的一个子类型,它只比 NATURAL 类型少一个 0。
尽管如此,对于许多综合器来说,如 果定义上例的 Q 为 POSITIVE RANGE 15 DOWNTO 0,
仍然能综合出相同的计数器电路来。
与 BIT,BIT_VECTOR 一样,数据类型 INTEGER,NATURAL 和 POSITIVE 都定义在
VHDL 标准程序包 STANDARD 中。由于是默认打开的,所以在例 3-20 中,没有以显式打开 STD 库和程序包 STANDARD。
3.4.3 计数器设计的另一种表述
例 3-21 是一种更为常用的计数器表达方式,在表述形式上比例 3-20 更接近例 3-6,主要表现在电路所有端口的数据类型都定义为标准逻辑位或位矢量,且 定义了中间节点信号。
这种设计方式的好处是,比较容易与其他电路模块接口。以下讨论其中新的语言现象。
【例 3-21】
LIBRARY IEEE ;
USE IEEE.STD_LOGIC_1164.ALL ;
USE IEEE.STD_LOGIC_UNSIGNED.ALL ;
ENTITY CNT4 IS
PORT ( CLK,IN STD_LOGIC ;
Q,OUT STD_LOGIC_VECTOR(3 DOWNTO 0) ) ;
END ;
ARCHITECTURE bhv OF CNT4 IS
SIGNAL Q1,STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
PROCESS (CLK)
BEGIN
IF CLK'EVENT AND CLK = '1' THEN
Q1 <= Q1 + 1 ;
END IF;
END PROCESS ;
Q <= Q1 ;
END bhv;
与例 3-20 相比,此例有如下一 些新的内容,
(1) 输入信号 CLK定义为标准逻辑位 STD_LOGIC,输出信号 Q 的数据类型明确定义为 4 位标准逻辑位矢量 STD_LOGIC_VECTOR(3 DOWNTO 0),因此,必须利用 LIBRARY
语句和 USE 语句,打开 IEEE 库的程序包 STD_LOGIC_1164。
第 3 章 VHDL 入门
93
(2) Q 的端口模式是 OUT。由于 Q 没有输入的端口模式特性,因此 Q 不能如例 3-20
那样直接用在表式 Q<=Q + 1 中。但考虑到计数器必须建立一个用于计数累加的寄存器,因此在计数器内部先定义一个信号 SIGNAL(类似于节点 ),语句表达上 可以在结构体的
ARCHITECTURE 和 BEGIN 之间定义一个信号,其用意和定义方式与例 3-6 中对 Q1 的定义相同,即,SIGNAL Q1,STD_LOGIC_VECTOR(3 DOWNTO 0);
由于 Q1 是内部的信号,不必像端口信号那样需要定义它们的端口模式,即 Q1 的数据流动是不受方向限制的,因此可以在 Q1<=Q1 + 1 中用信号 Q1 来完成累加的任务,然后将累加的结果用表式 Q<=Q1 向端口 Q 输出。于是在例 3-21 的不完整的 IF 条件语句中,Q1
变成了内部加法计数器的数据端口。
(3) 考虑到 VHDL 不允 许在不同数据类型的操作数间进行直接操作或运算,而表式
Q1<=Q1 + 1 中数据传输符 <=右边加号的两个操作数分属不同的数据类型,Q1(逻辑矢量 ) +
1(整数 ),不满足算术符,+”对应的操作数必须是整数类型,且相加和也为整数类型的要求,因此必须对表式 Q1<=Q1 + 1 中的加号,+”赋予新的功能,以便使之允许不同数据类型的数据可以相加,且相加和必须为标准逻辑矢量。
方法之一就是调用一个函数,以便赋予加号,+”具备新的数据类型的操作功能,这就是所谓的运算符重载,这个函数称为运算符重载函数。
为了方便各种不同数 据类型间的运算操作,VHDL 允许用户对原有的基本操作符重新定义,赋予新的含义和功能,从而建立一种新的操作符。
事实上,VHDL 的 IEEE 库中的 STD_LOGIC_UNSIGNED 程序包中预先定义的操作符如,+”、“-”、,*”、,=”、,>=”、,<=”、,>”、,<”、,/=”、,AND”和,MOD”等,对相应的数据类型 INTEGRE,STD_LOGIC 和 STD_LOGIC_VECTOR 的操作作了重载,赋予了新的数据类型操作功能,即通过重新定义运算符的方式,允许被重载的运算符能够对新的数据类型进行操作,或 者允许不同的数据类型之间用此运算符进行运算。
例 3-21 中第 3 行使用语句,USE IEEE.STD_LOGIC_UNSIGNED.ALL 的目的就在于此。使用此程序包就是允许当遇到此例中的 +号时,调用 +号的算符重载函数。
例 3-20 和例 3-21 的综合结果是相同的,其 RTL 电路如图 3-11 所示,其工作时序如图
3-13 所示,图中的 Q 显示的波形是以总线方式表达的,其数据格式是 16 进制,是 Q(3)、
Q(2),Q(1)和 Q(0)时序的迭加,如 16 进制数值,A”即为,1010”。
由图 3-12 可见,4 位加法计数器由两大部 分组成,
Q[3:0]
[3:0]Q[3:0][1:4] D[3:0]
un2_q1[1:4]
+
[3:0]
[1:4]
1
Q[3:0][3:0]
CLK
锁存信号输出反馈组合电路加1器
4位锁存器
图 3-12 4位加法计数器 RTL 电路( Synplify 综合)
(1) 完成加 1 操作的纯组合电路加法器,它右端输出的数始终比左端给的数多 1,如输
EDA 技术 与 VHDL
94
入为,1001”,则输出为,1010”。因此换一种角度看,此加法器等同于一个译码器,它完成的是一个二进制码的转换功能,其转换的时间即为此加法器的运算延迟时间。
(2) 4 位边沿触发方式锁存器,这是一个纯时序电路,计数信号 CLK 实际上是其锁存允许信号。
此外在输出端还有一个反馈通道,它一方面将锁存器中 的数据向外输出,另一方面将此数反馈回加 1 器,以作为下一次累加的基数。不难发现,尽管例 3-20 和例 3-21 中设定的输出信号的端口模式是不同的,前者是 BUFFER,而后者是 OUT,但综合后的输出电路结构是相同的,这表明缓冲模式 BUFFER 并非某种特定端口电路结构,它只是对端口具有某种特定工作方式的描述,对此,BUFFER 与其他 3 种端口模式有较大的不同,读者应注意体会。
1.0μs 1.5μs 2.0μs 2.5μs 3.0μs 3.5μs
图 3-13 4位加法计数器工作时序
从计数器的表面上看,计数器仅对 CLK 的脉冲进行 计数,但电路结构却显示了 CLK
的真实功能只是锁存数据,而真正完成加法操作的是组合电路加 1 器。从电路优化的角度看,4 位锁存器只是由 4 个基本的 D 触发器组成,它是 FPGA 或 CPLD 器件最底层的电路结构,或是 ASIC 设计中标准单元库中仅次于版图级的标准单元基本元件,因此,就 VHDL
描述层次来说,它的电路结构优化范围比较小,对于特定的硬件电路、器件规格或 ASIC
设计工艺,无论在速度还是资源面积方面,锁存器的优化潜力都比较有限。由此可见真正决定计数器工作性能的是其中的加法器。由纯组合电路构成的加法器在电路结构、进位方式 和资源利用等多个侧面的优化还有许多工作可做。
3.5 一般加法计数器设计
例 3-22 给出的是一个带有异步复位和同步时钟使能的十进制加法计数器。在对此计数器进行功能分析和设计原理介绍前首先对程序中出现的新的语法现象作简要说明。
【例 3-22】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY CNT10 IS
PORT (CLK,RST,EN,IN STD_LOGIC;
CQ,OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
第 3 章 VHDL 入门
95
COUT,OUT STD_LOGIC );
END CNT10;
ARCHITECTURE behav OF CNT10 IS
BEGIN
PROCESS(CLK,RST,EN)
VARIABLE CQI,STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
IF RST = '1' THEN CQI,= (OTHERS =>'0') ; --计数器异步复位
ELSIF CLK'EVENT AND CLK='1' THEN --检测时钟上升沿
IF EN = '1' THEN --检测是否允许计数(同步使能)
IF CQI < 9 THEN CQI,= CQI + 1; --允许计数,检测是否小于 9
ELSE CQI,= (OTHERS =>'0'); --大于 9,计数值清零
END IF;
END IF;
END IF;
IF CQI = 9 THEN COUT <= '1'; --计数大于 9,输出进位信号
ELSE COUT <= '0';
END IF;
CQ <= CQI; --将计数值向端口输出
END PROCESS;
END behav;
3.5.1 相关语法说明
1,变量
变量 VARIABLE 与信号 SIGNAL 一样,都属于数据对象,在此程序中的功能与信号相似。但变量的赋值符号与信号的赋值符号是不同的,信号的赋值符号是,<=”,而变量的赋值符号是,:=,。例如 a 为变量,对其赋值可以写为,a:= ’1’。
示例中的语句,VARIABLE CQI,STD_LOGIC_VECTOR(3 DOWNTO 0),定义标识符 CQI 为变量 VARIABLE,其数 据类型是 4 元素的标准逻辑矢量。变量的功能主要用于数据的暂存 。
2,省略赋值操作符 (OTHERS=>X)
例 3-22 中的 CQI:=(OTHERS=>’0’)等效于向变量 CQI 赋值,0000”,即,
CQI,= "0000"
为了简化表达才使用短语,(OTHERS=>X)”,这是一个省略赋值操作符,它可以在较多位的位矢量赋值中作省略化的赋值,如以下语句,
SIGNAL d1,STD_LOGIC_VECTOR(4 DOWNTO 0);
VARIABLE a1,STD_LOGIC_VECTOR(15 DOWNTO 0);
,.,
d1 <= (OTHERS=>'0'); a1,= (OTHERS=>'0') ;
这条语句等同于 d1<=,00000” ; a1:=,0000000000000000”。其优点是在给大的位
EDA 技术 与 VHDL
96
矢量赋值时简化了表述,明确了含义,这种表述与位矢量长度无关。
利用,(OTHERS=>X)” 还可以给位矢量的某一部分位赋值之后再使用 OTHERS 给剩余的位赋值,如,d2 <= (1=>'1',4=>'1',OTHERS=>'0'),此句的意义是给位矢量 d2 的第 1
位和第 4 位赋值为 '1',而其余位赋值为 '0'。
下例是用省略赋值操作符,(OTHERS=>X)”给 d2 赋其他信号的值,
d1 <= (1=>e(3),3=>e(5),OTHERS=>e(1) );
这个矢量赋值语句也可以改写为下面的使用连接符的语句 (假设 d1 的长度为 5 位 ),
f <= e(1) & e(5) & e(1) & e(3) & e(1) ;
显然,利用,(OTHERS=>X)”的描述方法要优于用,&”的描述方法,因为后者的缺点是赋值依赖于矢量 的长度,当长度改变时必须重新排序。
3.5.2 程序分析
例 3-22 描述的是一个带有异步复位和同步时钟使能的十进制加法计数器,这种计数器有许多实际的用处,例如后面将要介绍的频率计设计。所谓同步或异步都是相对于时钟信号而言的。不依赖于时钟而有效的信号称为异步信号,否则称为同步信号。
例 3-22 的进程语句中含有两个独立的 IF 语句,第一个 IF 语句是非完整性条件语句,
因而将产生计数器时序电路;第二个 IF 语句产生一个纯组合逻辑的多路选择器。
从结构上讲,更一般的表述是将这两个独立的 IF 语句用两个独立的进程语句来表达,
一个为时序进程(或称时钟进程);另一个为组合进程。读者不妨对此类表述一试。
例 3-22 程序功能是这样的:当时钟信号 CLK、复位信号 RST 或时钟使能信号 EN 中任一信号发生变化,都将启动进程语句 PROCESS。此时如果 RST 为 '1',将对计数器清零,
即复位。这项操作是独立于 CLK 的,因而称异步;如果 RST 为 '0',则看是否有时钟信号的上升沿;如果此时有 CLK 信号,又测得 EN='1',即允许计数器计数,此时若满足计数值小于 9,即 CQI<9,计数器将进行正常计数,即执行语句 CQI:=CQI+1,否则对 CQI 清零,
但如果测得 EN='0',则跳出 IF 语句,使 CQI 保持原值,并将计数值向端口输出,CQ<=CQI。
第二个 IF 语句的功能是当计数器 CQI 的计数值达到 9 时,输出高电平,作为十进制计数的进位溢出信号,而当 CQI 为其他值时,输出低电平 '0'。
此外从此例可以注意到,为了形成内部的寄存器时序电路,将 CQI 定义为变量,而没有按通常的方法定义成信号。虽然变量的一般功能是作为进程中数据的暂存单元(这主要针对 VHDL 仿真而言的,对于 VHDL 综合不完全是这样),但不完整的 IF 条件语句中,变量赋值语句 CQI:=CQI+1 同样 能综合出时序电路。
读者可能已从此例注意到,在 IF 的条件语句 CQI < 9和 CQI = 9 的比较符号两边都出现了数据类型不相同的现象,这只能通过自动调用 程序包 STD_LOGIC_UNSIGNED 中的 运算符重载函数才能解决。
例 3-22 综合的 RTL 电路图如图 3-14 所示,电路含有比较器、组合电路加 1 器,2 选 1
多路选择器,4 位锁存器各一个及两个与门。语句与电路器件的对应情况如下,
(1) 第一个 IF 语句中的条件句 IF CQI<9 THEN 构成了比较器;
第 3 章 VHDL 入门
97
(2) 语句 IF RST='1'THEN CQI:= (OTHERS=>'0')构成 RST 在锁存器上的异步清零端,R”;
(3) 语句 ELSE CQI:=(OTHERS=>'0')构成 2 选 1 的多路选择器;
(4) 语句 IF EN='1'THEN 构成了 2 输入的与门;
(5) 不完整的条件语句与语句 CQI:=CQI+1 构成了加法器和锁存器 ;
(6) 第二个 IF 语句构成了 4 输入与门。
图 3-15 是例 3-22 描述的电路的工作时序。由分析可知,程序所描述的功能与图 3-15
的波形是完全一致的,而且从图 3-14 的电路图也能得到相同的结果,图中,
(1) 当 RST 为高电平,EN 为低电平时,CQ 输出为 0,即计数清零,并禁止计数;
(2) 当 RST 为低电平,EN 为高电平时,每一个 CLK 的上升沿后,CQ 输出加 1,而当
CQ 输出为 9 时,COUT 输出高电平进位信号;
(3) 当 EN 为低电平时,计数器保持原有的计数,2”,当 EN 为高电平则继续计数。
图 3-14 例 3-22 的 RTL 电路( Synplify 综合)
1.0μs 1.5μs 2.0μs 2.5μs 3.0μs 3.5μs
图 3-15 例 3-22 的工作时序
3.5.3 含并行置位的移位寄存器设计
以下再介绍另一种类型的有实用意义的时序电路 。
例 3-23 是一个带有同步并行预置功能的 8 位右移移位寄存器。 CLK 是移位时钟信号,
DIN 是 8 位并行预置数据端口,LOAD 是并行数据预置使能信号,QB 是串行输出端口。
此移位寄存器的工作原理是:当 CLK 的上升沿到来时进程被启动,如果这时预置使能
LOAD 为高电平,则将输入端口的 8 位二进制数并行置入移位寄存器中,作为串行右移输出的初始值;如果预置使能 LOAD 为低电平,则执行语句,REG8(6 DOWNTO 0):= REG8(7
DOWNTO 1)。 此语句表明,
①一个时钟周期后将上一时钟周期移位寄存器中的高 7 位二进制数 (当前值 REG8(7
EDA 技术 与 VHDL
98
DOWNTO 1) )赋给此寄存器的低 7 位 REG8(6 DOWNTO 0);
②将上一时钟周期移位寄存器中的最低位,即当前值 REG(0)向 QB 输出。
随着 CLK 脉冲的到来,就完成了将并行预置输入的数据逐位向右串行输出的功能,即将寄存器中的最低位首先输出。
【例 3-23】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY SHFRT IS -- 8位右移寄存器
PORT ( CLK,LOAD,IN STD_LOGIC;
DIN,IN STD_LOGIC_VECTOR(7 DOWNTO 0);
QB,OUT STD_LOGIC );
END SHFRT;
ARCHITECTURE behav OF SHFRT IS
BEGIN
PROCESS (CLK,LOAD)
VARIABLE REG8,STD_LOGIC_VECTOR(7 DOWNTO 0);
BEGIN
IF CLK'EVENT AND CLK = '1' THEN
IF LOAD = '1' THEN REG8,= DIN; --由( LOAD='1')装载新数据
ELSE REG8(6 DOWNTO 0),= REG8(7 DOWNTO 1);
END IF;
END IF;
QB <= REG8(0); -- 输出最低位
END PROCESS;
END behav;
例 3-23 的工作时序如图 3-16 所示。波形时序说明如下,
1.0μs 1.5μs 2.0μs 2.5μs 3.0μs 3.5μs 4.0μs 4.5μs
图 3-16 例 3-23 的工作时序
在第 1 个时钟到来时,LOAD 恰为高电平,此时 DIN 口上的 8 位数据 9A,即,10011010”
被锁入 REG8 中 ;
第 2 个时钟,以及以后的时钟信号都是移位时钟。但应该注意的是,由于例 3-23 中赋值语句 QB<=REG8(0)在 IF 语句结构的外面,因此它的执行并非需要当前的时钟信号,属于异步方式。即在当前的时钟信号到来前,由于 IF 语句不满足时钟条件而跳出 IF 语句,
于是便执行其后的语句 QB<=REG8(0)。这一点可以从图 3-16 中 清楚地看出:在第一个执行并行数据加载的时钟后,QB 即输出了被加载的第 1 位右移数 '0',而此时的 REG8 内仍然是,9A” ;
第 2 个时钟后,QB 输出了右移出的第 2 个位 '1',此时的 REG8 内变为,CD”,其最第 3 章 VHDL 入门
99
高位被填为 '1'。如此进行下去,直到第 8 个 CLK 后,右移出了所有 8 位二进制数,最后一位是 '1',此时 REG8 内是,FF”,即全部被 DIN 的最高位 '1' 填满。
3.6 VHDL 语句结构与语法小节
这里对本章中出现过的 VHDL 语句结构、基本概念和语言现象作简要一归纳,
实体,以 ENTITY.,,END ENTITY e_name 描述器件的端口特性。
结构体,以 ARCHITECTURE,.,END ARCHITECTURE 给出器件的逻辑功
能和行为。
端口定义,以 PORT()语句定义器件端口及其数据类型。
端口模式,IN,OUT,INOUT,BUFFER 描述端口数据的流向特征。
数据类型,数据对象承载数据的类别,INTEGER,BOOLEAN,STD_LOGIC,
BIT,STD_LOGIC_VECTOR。
信号赋值符:,<=”,用于信号数据的传输,仿真传输延时最短为一个?。
条件比较符:,=”,在条件语句表式中用于比较待测数据的关系。
延时,模拟器最小分辨时间?,或称延时? 。
逻辑操作符,AND,OR,NOT,NAND,XOR,XNOR。
IF 条件语句,IF_THEN_ELSE 语句作为顺序语句。
并行条件语句,WHEN_ELSE 条件信号赋值语句。
进程语句,以 PROCESS,..END PROCESS 引导的语句结构。
顺序语句,由进程语句引导的,以顺序方式执行的语句。
并行语句,在结构体中以并行 方式执行的语句。
文件取名,建议文件名与 VHDL 设计的实体名一致,后缀是,vhd。
文件存盘,VHDL 设计文件必须存于指定为工程的目录中,此目录将被设定为
WORK 库,WORK 库的路径即为此目录的路径。
VHDL 库,LIBRARY语句打开 VHDL库,IEEE库、标准库 STD、工作库 WORK,,,
程序包,USE 语句声明使用程序包,STD_LOGIC_1164,
STD_LOGIC_UNSIGNED,STANDARD 等程序。
数据对象,信号,SIGNAL,变量,VERIABLE,常数,CONSTANT
信号属性函数,信号属性函数 EVENT,LAST_VALUE。
时钟检测,时钟检测上升沿检测表式,CLK'EVENT AND CLK='1',
RISING_EDGE(),FALLING_EDGE()等。
时序电路,不完整条件语句产生时序电路,IF … THEN … END IF,IF …
THEN … ELSIF … THEN … END IF
真值表表达:表达方法之一是用 CASE_WHEN 语句,但要注意 OTHERS 的应用。
并置操作符:并置操作符? 可用于合并两个或多个逻辑矢量,构建成新的数组。
EDA 技术 与 VHDL
100
元件例化:由元件调用声明语句 COMPONENT 和映射语句 PORT MAP( )构成。
运算符重载概念:当进行非整数类型数据运算操作时需要调用运算符重载函数,
这可以打开程序包 STD_LOGIC_UNSIGNED。
习 题
3-1,画出与下例实体描述对应的原理图符号元件,
ENTITY buf3s IS -- 实体 1,三态缓冲器
PORT (input,IN STD_LOGIC ; -- 输入端
enable,IN STD_LOGIC ; -- 使能端
output,OUT STD_LOGIC ) ; -- 输出端
END buf3x ;
ENTITY mux21 IS --实体 2,2选 1多路选择器
PORT (in0,in1,sel,IN STD_LOGIC;
output,OUT STD_LOGIC);
3-2,图 3-17 所示的是 4 选 1 多路选择器,试分别用 IF_THEN 语句和 CASE 语句的表达方式写出此电路的 VHDL程序。选择控制的信 号 s1 和 s0 的数据类型为 STD_LOGIC_VECTOR;当 s1='0',s0='0'; s1='0',
s0='1'; s1='1',s0='0'和 s1='1',s0='1'分别执行 y<=a,y<=b,y<=c,y<=d。
3-3,图 3-18 所示的是双 2 选 1 多路选择器构成的电路 MUXK,对于其中 MUX21A,当 s='0'和 '1'时,
分别有 y<='a'和 y<='b'。试在一个结构体中用两个进程来表达此电路,每个进程中用 CASE 语句描述一个
2 选 1 多路选择器 MUX21A。
图 3-17 4选 1 多路选 择器 图 3-18 双 2 选 1 多路选择器
3-4,图 3-19 是一个含有上升沿触发的 D 触发器的时序电路,试写出此电路的 VHDL 设计文件。
图 3-19 时序电路图
3-5,给出 1 位全减器的 VHDL 描述。要求,
(1) 首先设计 1 位半减器,然后用例化语句将它们连接起来,图 3-20 中 h_suber 是半减器,diff 是输出差,s_out 是借位输出,sub_in 是借位输入。
第 3 章 VHDL 入门
101
(2) 以 1 位全减器为基本硬件,构成串行借位的 8 位减法器,要求用例化语句来完成此项设计 (减法运算是 x – y - sun_in = diffr)。
3-6,根据图 3-21,写出顶层文件 MX3256.VHD 的 VHDL 设计文件。
3-7,设计含有异步清零和计数使能的 16 位二进制加减可控计数器。
图 3-20 1位全减器
图 3-21 题 3-6 电路图