做实验过程中发现的问题: 新建时工程文件夹建立了,但所建实体文件并没存放在其中 文件名不能用汉字 编译并不能检测设计实体的功能,仅能检测语法规则或布局布线等问题,比如本来两输入端的元器件有多于两个的输入端 仿真时务必设置仿真时间和网格大小,切记:不同的工作环境,菜单的具体内容不同 输入节点的参数设置问题:可单个设置,也可折叠设置
6. 警告可以忽略,但能解决的尽可能解决;错误必须改正。比如:如果在settings|files中添加过某实体文件,但该实体文件名被更改或删除,则可能出现警告,所以,只要将更名前的那个路径删除就可以 7. 提示硬件问题时,可尝试插紧并行口和JTAG口的插头 8. 下载后实验箱没反应时,要考虑引脚锁定后是否再次编译了 下载编程方式只需首次下载时设定,不必每次去设;下载时,要选中“program/configue”,其余可不选 提示工程不能打开时,将所在工程文件夹的只读属性去掉即可
第3章 VHDL •本章概要:本章介绍硬件描述语言VHDL的语言要素、程序结构以及描述风格,并介绍最基本、最典型的数字逻辑电路的VHDL描述,作为VHDL工程设计的基础。 •知识要点: (1)VHDL设计实体的基本结构。 (2)VHDL的语言要素。 (3)用VHDL实现各种类型电路及系统的方法。 (4)VHDL设计流程。
3.1 VHDL基本知识 VHDL作为IEEE标准的硬件描述语言和EDA的重要组成部分,经过十几年的发展、应用和完善,以其强大的系统描述能力、规范的程序设计结构、灵活的语言表达风格和多层次的仿真测试手段,在电子设计领域受到了普遍的认同和广泛的接受,成为现代EDA领域的首选硬件设计语言。专家认为,在新世纪中,VHDL与Verilog语言将承担起几乎全部的数字系统设计任务。
3.1.1 VHDL程序设计基本结构 库、程序包 设 实体(ENTITY) 计 实 体 结构体 (ARCHITECTURE) 进程 或其它并行结构 实体(ENTITY) 配置(CONFIGURATION) 库、程序包 设 计 实 体
设计实体 1、USE 2、PACKAGE 3、ENTITY 定义电路设计中全部的输入与输出信号 GENERIC PORT 打开程序包说明中的所有说明 2、PACKAGE 存放共享的数据类型、常数和子模块等 3、ENTITY 定义电路设计中全部的输入与输出信号 GENERIC PORT 4、ARCHITECTURE 描述电路内部的功能,说明电路执行的动作 COMPONENT SIGNAL assignments Behavior process Data flow Structure 5、CONFIGURATION VHDL的 描述风格
VHDL语言的描述风格 一般有四种常用描述风格: 行为描述:只描述电路的功能或行为,不 包含任何硬件信息等。 数据流描述(RTL描述):反映数据经过 一定的逻辑运算后在输入和输 出间的传递。 结构描述:以元件或已完成的功能模块为 基础,应用于采用元件例化的 VHDL程序设计中。 前三种的综合
【补充例1】 2选1多路选择器的行为描述程序。 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY mux21 IS PORT( a,b : IN STD_LOGIC; s: IN STD_LOGIC; y: OUT STD_LOGIC ); END ENTITY mux21; ARCHITECTURE behav OF mux21 IS BEGIN PROCESS(a,b,s) IF s='0' THEN y<=a; ELSE y<=b; END IF; END PROCESS; END ARCHITECTURE behav;
【补充例2】 2选1多路选择器数据流描述程序。 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY mux21 IS PORT( a,b : IN STD_LOGIC; s: IN STD_LOGIC; y: OUT STD_LOGIC ); END ENTITY mux21; ARCHITECTURE dataflow OF mux21 IS BEGIN y<=(a AND (NOT s)) OR (b AND s); END ARCHITECTURE dataflow;
] ] ] 【补充例3】 2选1多路选择器结构描述程序。 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY and21 IS --与门 PORT(i0,i1 : IN STD_LOGIC; q: OUT STD_LOGIC ); END ENTITY and21; ARCHITECTURE one OF and21 IS BEGIN q<=i0 AND i1; END ARCHITECTURE one; LIBRARY IEEE; ENTITY or21 IS --或门 END ENTITY or21; ARCHITECTURE one OF or21 IS q<=i0 OR i1; ENTITY inv21 IS --非门 PORT(i0 : IN STD_LOGIC; END ENTITY inv21; ARCHITECTURE one OF inv21 IS q<= (NOT i0); ] LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY mux21 IS PORT(a,b : IN STD_LOGIC; s: IN STD_LOGIC; y: OUT STD_LOGIC ); END ENTITY mux21; ARCHITECTURE struct OF mux21 IS COMPONENT and21 PORT (i0,i1 : IN STD_LOGIC; q: OUT STD_LOGIC); END COMPONENT; COMPONENT or21 COMPONENT inv21 PORT (i0: IN STD_LOGIC; SIGNAL tmp1,tmp2,tmp3:STD_LOGIC; BEGIN u1: and21 PORT MAP (b, s,tmp1); u2: inv21 PORT MAP(s,tmp2); u3: and21 PORT MAP (a,tmp2,tmp3); u4: or21 PORT MAP(tmp1,tmp3,y); END ARCHITECTURE struct; ] ]
3.1.1 库、程序包 库(LIBRARY)——存放预先设计好的程序包和数据的集合体。 程序包(PACKAGE)——将已定义的数据类型、元件调用说明及子程序收集在一起,供VHDL设计实体共享和调用,若干个包则形成库。 IEEE库包括:STD_LOGIC_1164 STD_LOGIC_ARITH——是SYNOPSYS公司加入IEEE库程序包,包括: STD_LOGIC_SIGNED(有符号数) STD_LOGIC_UNSIGNED(无符号数)
STD_LOGIC_SMALL_INT(小整型数) VHDL ’87版本使用IEEE STD 1076-1987 语法标准 VHDL ’93版本使用IEEE STD 1076-1993 语法标准 例:LIBRARY IEEE USE IEEE.STD_LOGIC_1164.ALL 描述器件的输入、输出端口数据类型中将要用到的IEEE的标准库中的STD_LOGIC_1164程序包。
3.1.2 实体(ENTITY)说明 格式: ENTITY 实体名 IS [类属参数说明] [端口说明] END 实体名; 规则:(1)类属参数说明必须放在端口说明之前,用于设计实体和外部环境通信的参数,传递静态信息,特别是用来规定一个实体的端口大小、元件的数量、实体的物理特性(如矢量位数、延迟时间)等参数。 (2)类属与常数不同,常数只能从设计实体的内部得到赋值,且不能改变,而类属的值可以由设计实体外部提供。通过修改类属参量,设计可很方便地改变一个设计的内部结构和规模。
例如 : GENERIC(m:TIME:=1 ns); --说明m是一个值为1ns的时间参数 则程序语句: tmp1 <= d0 AND se1 AFTER m; --表示d0 AND se1经1ns延迟后才送到tmp1。
【补充例】 n输入端与非门的实体描述: ENTITY nand_n IS GENERIC ( n : INTEGER ) ; PORT( a : IN STD_LOGIC_VECTOR(n-1 DOWNTO 0); s : OUT STD_LOGIC ); END ENTITY nand_n; 其中,n可以在定义时初始化,也可以在应用时利用类属映射语句来指定,如: nand_n:GENERIC MAP(n>=3);
(2)端口说明是描述器件的外部接口信号的说明,相当于器件的引脚说明。其格式为: PORT(端口名{,端口名}:方向 数据类型名; : 端口名{,端口名}:方向 数据类型名); 例如:PORT(a,b:IN STD_LOGIC; s:IN STD_LOGIC; y:OUT STD_LOGIC);
端口方向包括: IN; --输入, 符号: OUT; --输出, 符号: INOUT;--双向, 符号: BUFFER; --具有读功能的输出,符号为: D Q BUFFER 端口
out 和 buffer 的区别: 总之,只有当端口模式为IN、INOUT和BUFFER时,才能从该端口读数据,只有在端口模式为OUT、INOUT和BUFFER时,才能从该端口写数据。
3.1.3 结构体(ARCHITECTURE) 基本设计单元的实体,用于指明设计基本单元的行为、元件及内部连接关系,即定义设计单元的功能。 结构体的结构: ARCHITECTURE 结构体名 OF 实体名 IS [说明语句]; --为内部信号、常数、数据类型、函数定义 BEGIN [功能描述语句] END ARCHITECTURE 结构体名;
结构体 结构体说明 结构体功能描述 常数说明 数据类型说明 信号说明 例化元件说明 子程序说明 块语句 进程语句 信号赋值语句 子程序调用语句 元件例化语句
一个设计实体可有多个结构体,代表实体的多种实现方式。各个结构体的地位相同。 实体与结构体的关系: 一个设计实体可有多个结构体,代表实体的多种实现方式。各个结构体的地位相同。 结构体1 结构体2 结构体3 设计实体 . 结构体n
配置:从某个实体的多种结构体描述方式中选择特定的一个。 例如:或门的结构体 ARCHITECTURE or1 OF temp1 IS SIGNAL y:STD_LOGIC; BEGIN y<=a OR b; END ARCHITECTURE or1; 3.1.4 配置(CONFIGURATION)——把特定的结构体关联(指定给)一个确定的实体,为大型系统的设计提供管理和工程组织。 配置:从某个实体的多种结构体描述方式中选择特定的一个。
3.1.2 基本逻辑器件的描述 【例3.1】或门的描述 LIBRARY IEEE; USE IEEE.STD LOGIC 1164.ALL; 3.1.2 基本逻辑器件的描述 【例3.1】或门的描述 LIBRARY IEEE; USE IEEE.STD LOGIC 1164.ALL; ENTITY or1 IS PORT( a,b:IN STD_LOGIC; y:OUT STD LOGIC); END or1; ARCHITECTURE example1 OF or1 IS BEGIN y<=a OR b; END example1;
USE IEEE.STD_LOGIC_1164.ALL; ENTITY h_adder IS PORT(a,b:IN STD_LOGIC; so co 【例3.2】半加器的描述 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY h_adder IS PORT(a,b:IN STD_LOGIC; so,co:OUT STD_LOGIC); END h_adder; ARCHITECTURE example2 OF h_adder IS BEGIN so<=a XOR b; co<=a AND b; END example2;
PORT( a,b:IN STD LOGIC; s:IN STD LOGIC; y:OUT STD LOGIC); END mux21; 【例3.3】2选1数据选择器的描述 LIBRARY IEEE; USE IEEE.STD LOGIC 1164.ALL; ENTITY mux21 IS PORT( a,b:IN STD LOGIC; s:IN STD LOGIC; y:OUT STD LOGIC); END mux21; ARCHITECTURE example3 OF mux21 IS BEGIN y<=a WHEN s=’0’ ELSE b; END ARCHITECTURE example3;
【例3.4】锁存器的描述 q D Q ena d
LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY latch1 IS PORT ( d :IN STD_LOGIC; ena :IN STD_LOGIC; q :OUT STD_LOGIC); END latch1; ARCHITECTURE example4 OF latch1 IS SIGNAL sig_save: STD_LOGIC:=‘0’;
BEGIN PROCESS (d,ena) IF ena='1' THEN sig_save<=D; END IF; Q<=sig_save; END PROCESS; END example4; 返回
3.2 VHDL语言要素 VHDL具有计算机编程语言的一般特性,其语言要素是编程语句的基本单元。准确无误地理解和掌握VHDL语言要素的基本含义和用法,对正确地完成VHDL程序设计十分重要。
关键字(保留字) 与其他任何计算机语言一样,VHDL语言要求我们遵守定义了关键字(keyword)和语法(syntax)的一整套规则。“关键字”是在语言中具有特别含义的单词,它只能作为固定的用途,用户不能用保留字作为标识符。 如: abs,after, all, and, architecture, array, attribute, begin,body, buffer,case,component, constant, downto, else,elsif, end,entity,exit, file, for,function, generate, group, if,in,is, library,loop,map ,mod, nand,new,next,nor,not,of ,on,open ,or , others,out,package, process,procedure, range,record, rem, report, rol, ror, select, shared, signal,sla,sll,sra, subtype, then,to, type,use,until, variable,wait, when,while,with,xor,xnor等。
3.2.1 VHDL文字规则 1. 数字型文字——由数字、小数点和下划线组成 (1)整数文字 5,678,156E2,45_234_287(=45234287) (2)实数文字 188.993,88_670_551.453_909 (3)以数制基数表示的文字 格式:数制#数值# 例如: 10#170# 16#FE# 2#11010001# 8#376#
字符——以单引号括起来的数字、字母和符号(ASCII码) (4)物理量文字 例如:60s,100m 2. 字符串文字 字符——以单引号括起来的数字、字母和符号(ASCII码) 例如:’0’,’1’,’A’,’B’,’a’,’b’ 字符串——一维的字符数组,用双引号括起来。 (1)文字字符串 例如:”ABC”,”A BOY.”,”A”
(2)数值字符串——矢量 格式:数制基数符号“数值字符串” 其中: B——二进制基数符号; O——八进制基数符号; X——16进制基数符号; 例如: B“111011110”;矢量数组,长度为9 O“15”;等效B“001101”,长度为6 X“AD0”;等效B“101011010000”,长度为12
3. 标识符——是用户给常量、变量、信号、端口、子程序或参数定义的名字。VHDL的标识符由英文字母(A~Z,a~z)、数字(0~9)和下划线字符(_)组成。 短标识符必须遵守以下规则: (87标准) 首写必须为英文字母 不区分大小写 最后一个字符不能为下划线 不允许连续出现两个下划线 关键字不能做为标识符 标识符最长为32个字符
例如: h_adder,mux21,example为合法标识符; 2adder,_mux21,ful__adder,adder_为错误的标识符。
VHDL’93标准支持扩展标识符,以反斜杠来定界,允许: ◎允许以数字开头 ◎允许两个以上的下划号 ◎允许使用空格和包含图形符号,但没有任何意义 ◎允许使用VHDL保留字 ◎区分字母大小写 ◎扩展标识符与短标识符不同,如aa与\aa\是不同的 ◎扩展标识符中如果有一个反斜杠,则用相邻的两个反斜杠来代替它 如:\74LS163\、 \Si&g_ _#N\(等价于\Sig__N\)、 \entity\、\ENTITY\、\74LS\\138\等为合法的标识符。
4. 下标名——数组 格式:标识符(表达式) 例如:b(3) 5. 段名——多个下标名的组合 格式:标识符(表达式 方向 表达式) 方向:TO——下标序号由低到高 DOWNTO——下标序号由高到低 例如:D(7 DOWNTO 0);表示数据总线D7~D0 D(0 TO 7 );表示数据总线D0~D7 6. 注释:--注释语
3.2.2 VHDL数据对象 三种对象的物理含义: •常量代表数字电路中的电源、地、恒定逻 辑值等常数; ——存放各种类型数据的容器,包括变量、常量和信号 三种对象的物理含义: •常量代表数字电路中的电源、地、恒定逻 辑值等常数; •变量代表暂存某些值的载体,常用于描述算法; •信号代表物理设计中的某一条硬件连接线, 包括输入、输出端口。
规则:只能在进程(PROCESS)、函数(FUNCTION)和过程(PROCEDURE)中说明和使用的局域量。 1. 变量(VARIABLE) 规则:只能在进程(PROCESS)、函数(FUNCTION)和过程(PROCEDURE)中说明和使用的局域量。 定义格式: VARIABLE 变量名:数据类型[:=初始值] 例如:VARIABLE a:INTEGER VARIABLE b:INTEGER:=2; 注意:没有设定初始值的变量在仿真赋值时,系统会取默认值,字符型的取最大值,数值型的取最左或最小值。
变量赋值语句: 目标变量名:=表达式 例如:VARIABLE x,y:REAL VARIABLE a,b:BIT VECTOR(0 TO 7); x:=100.0; y:=1.5+x; a:=“1010101” a(3 TO 6):=(‘1’,‘1’,‘0’,‘1’); a(0 TO 5):=b(2 TO 7);
规则:信号是在结构体(ARCHITECTURE)、程序包(PACKAGE)和实体中说明的全局量。 2. 信号(SIGNAL) 规则:信号是在结构体(ARCHITECTURE)、程序包(PACKAGE)和实体中说明的全局量。 综合时初值被忽略 信号定义格式:SIGNAL 信号名:数据类型[:=初值]; 例如:SIGNAL temp:STD LOGIC:=‘0’; SIGNAL flaga,flagb:BIT SIGNAL data:STD LOGIC VECTOR(15 DOWNTO 0);
注意:1、信号是全局量,可在结构体、实体、块中说明和使用信号。而在进程和子程序中只能使用信号,不能说明信号。 信号赋值语句: 目标信号名<=表达式 例如:x<=9; y<=x; z<=x AFTER 5ns; 注意:1、信号是全局量,可在结构体、实体、块中说明和使用信号。而在进程和子程序中只能使用信号,不能说明信号。 2、端口是一种隐形的有方向的信号。即输出端口不能读数据,只能写入数据;输入端口不能写数据,只能读出数据。即:端口与信号的区别是in端口不能被赋值,out端口不能读数据。信号本身无方向,可读可写。
信号与变量的区别: (1)使用场合不同。变量只能在进程语句、函数语句和过程语句结构中说明和使用;信号通常在结构体、程序包和实体中说明。 (2)变量用“:=”号赋值,其值被立即使用(无时间延迟);而信号用“<=”赋值,其值一般经过一段时间的延迟后才能成为当前的赋值。 (3)变量不能表达“连线”或存储元件。 (4)信号代表连线,是电路内部硬件连接的抽象。作为连线,信号可以是逻辑门的输入或输出,也可以表达存储元件的状态。 (5)与变量不同,信号赋值可以利用after设置延时。
3. 常数(CONSTANT) 规则:常量必须在程序包、实体、结构体、块、子程序或进程的说明区域定义,且一旦被赋值就不能再改变。程序包中定义的常量可以在调用此程序包的所有设计实体(包括实体和结构体)中使用,具有最大的全局特征。 常数定义格式: CONSTANT 常数名:数据类型:=初值; 例如: CONSTANT fbus:BIT VECTOR:=“010111”; CONSTANT Vcc:REAL:=5.0; CONSTANT delay:TIME:=25ns;
练习题1: 画出下面VHDL程序描述对应实体——七段显示器的逻辑图符号: ENTITY dec17s IS PORT ( q :in bit_vector(3 downto 0); led7s: out bit_vector(7 downto 0)); END ENTITY dec17s;
练习题2: 请根据下面的说明写出8D锁存器的实体说明,并画出对应的实体图符号: d[7..0]是8位D锁存器数据输入端,clk是时钟输入端,oe是三态使能控制输入端,高电平有效,clr是清零端,低电平有效, q[7..0]是输出端。
ENTITY scq8 IS PORT ( d: in std_logic_vector(7 downto 0); oe, clr: in bit; clk: in std_logic; q: out std_logic_vector(7 downto 0)); END ENTITY scq8;
练习题3: 判断下列标识符哪些是合法的? 3mux and21 half_ _adder port _orgate q_0 \hello\2008\ 合法的:and21、q_0
3.2.3 VHDL数据类型 标量型(Scalar Type)——单元素的 最基本数据类型 (1)实数类型 (2)整数类型 (3)枚举类型 (4)时间类型 2. 复合类型(Composite Type) (1)数组型(Array) (2)记录型(Record)
存取类型(Access Type)——为数据对象提供存取方式 类似于C语言中的指针类型,此指针可以是指向字符串,也可以指向地址。 存取类型只能用于仿真,不能被综合。 文件类型(Files Type)——提供多值存取类型 类似于C语言中的指向文件的指针类型。可以读取文件、文件中的一行,还可以读取行中的某些数据量。
3.2.4 VHDL的预定义数据类型 ——在IEEE库中的标准程序包(STANDARD)中预先定义的数据类型。 1. 布尔(BOOLEAN)数据类型 包括逻辑“假”(FALSE)和逻辑“真”(TRUE),定义语句: TYPE BOOLEAN IS(FALSE,TRUE);--以枚举类型定义 2. 位(BIT)数据类型 包括‘0’和‘1’,定义语句: TYPE BIT IS(‘0’,‘1’)
3. 位矢量(BIT VECTOR)数据类型 位矢量是用双引号括起来的数字序列,如“0011”,X“00FD” 定义语句: TYPE BIT VECTOR IS ARRAY(Natural Range〈〉)OF BIT;--“〈〉”表示数据范围未定界 规则:使用位矢量必须注明位宽,例如: SIGNAL a:BIT VECTOR(7 DOWNTO 0);--定义a为由a(7)~a(0)构成矢量,左为a(7)右为a(0);
4. 字符(CHARACTER)数据类型 字符是用单引号括起来的ASCII码字符,如‘A’‘a’‘0’‘9’,字符类型区分大小写。 定义语句: TYPE CHARACTER IS(ASCII码字符表中的全部字符) 5. 整数(INTEGER)数据类型 整数包括:正整数、负整数和零 范围:32位带符号数原码,即-(231-1)~+(231-1) (-2147483647~+2147483647)
6.自然数(NATURAL)和正整数(POSITIVE)数据类型 自然数——包括0和正整数 正整数——不包括0的正整数 7. 实数(REAL)数据类型 由正、负、小数点和数字组成,如:-1.0,+2.5,-1.0E38 范围:-1.0E+38 TO +1.0E+38
8. 字符串(STRING)数据类型 字符串是用双引号括起来的字符序列,也称字符矢量或字符串数组。例如, “A BOY.”,“10100011” 9.时间(TIME)数据类型 时间是物理量数据,由整数数据和单位两部分组成,所有的物理类型数据均不能被VHDL综合器接受,综合时被忽略。 定义语句为:
TYPE TIME IS RANGE –2147483647 TO 2147483647 units fs;--飞秒(10-15S)VHDL中的最小时间单位 ps=1000fs;--皮秒 ns=1000ps;--纳秒 us=1000ns;--微秒 ms=1000us;--毫秒 sec=1000ms;--秒 min=60sec;--分 hr=60min;--时 END units;
10.错误等级(Severity Level) 错误等级数据用于表征系统的状态,包括:NOTE(注意),WARNING(警告),ERROR(出错),FAILURE(失败) 。在仿真过程中,可输出这4种值来提示被仿真系统当前的工作状态。其定义如下: TYPE severity_level IS(note,warning,error,failure);
3.2.5 IEEE预定义的标准逻辑位和矢量 1. 标准逻辑位(STD LOGIC)数据类型 TYPE STD LOGIC IS(‘U’--未初始化的 ‘X’--强未知的 ‘0’--强0 ‘1’--强1 ‘Z’--高阻态 ‘W’--弱未知的 ‘L’--弱0 ‘H’--弱1 ‘-’--忽略);
2. 标准逻辑矢量(STD LOGIC VECTOR)数据类型 TYPE STD LOGIC VECTOR IS ARRAY(Natural Range〈〉)OF STD LOGIC ;-- 〈〉表示范围未定
3.2.6 用户自定义数据类型方式 定义格式:TYPE 数据类型名 IS 数据类型定义 OF 基本数据类型 3.2.6 用户自定义数据类型方式 定义格式:TYPE 数据类型名 IS 数据类型定义 OF 基本数据类型 或:TYPE 数据类型名 IS 数据类型定义; 例如: TYPE st IS ARRAY(0 TO 15)OF STD LOGIC; TYPE week IS (sun,mon,tue,wed,thu,fri,sat); TYPE instruction IS (ADD,SUB,INC,SRL,SRF,LDA,LDB); TYPE month IS (jan,feb,mar,apr,may,jun,jul,agu,sep,oct,nov,dec);
1. 枚举类型(Enumerated) 定义格式:TYPE 数据类型名 IS 数据类型定义; 例如:TYPE week IS (sun,mon,tue,wed,thu,fri,sat); 2. 整数类型和实数类型 定义格式:TYPE 数据类型名 IS RANGE 范围; 例如:TYPE num1 IS RANGE 0 TO 100;
数组——是一组具有相同数据类型的元素的组合。 定义格式:TYPE 数组名 IS ARRAY (数据范围) OF 数据类型; 3. 数组类型 数组——是一组具有相同数据类型的元素的组合。 定义格式:TYPE 数组名 IS ARRAY (数据范围) OF 数据类型; 例如:TYPE data_bus IS ARRAY (7 DOWNTO 0) OF STD_LOGIC;--定义数据总线,下标由高到低,即D7位权值最高,D0位权值最低。 TYPE data_bus IS ARRAY (0 TO 7) OF STD_LOGIC;--定义数据总线,下标由低到高,即D0位权值最高,D7位权值最低。
4. 记录类型(Recode) 记录——是一组不同数据类型的元素的组合。 定义格式:TYPE 记录类型名 IS RECORD 元素名:元素数据类型; : END RECORD [记录类型名] ;
3.2.7 VHDL操作符 操作数 算术和逻辑运算表达式 逻辑操作符 关系操作符 算术操作符 符号操作符 操作符
类型 操作符 功能 操作数数据类型 算 术 操 作 符 + 加 整数 - 减 & 并 一维数组 * 乘 整数和实数 / 除 MOD 取模 REM 求余 SLL 逻辑左移 BIT或布尔型一维数组 SRL 逻辑右移
类型 操作符 功能 操作数数据类型 算 术 操 作 符 SLA 算术左移 BIT或布尔型一维数组 SRA 算术右移 ROL 逻辑循环左移 ROR 逻辑循环右移 ** 乘方 整数 ABS 取绝对值
类型 操作符 功能 操作数数据类型 关 系 操 作 符 = 等于 任何数据类型 /= 不等于 < 小于 枚举与整数及对应的一维数组 > 大于 同上 <= 小于等于 >= 大于等于
类型 操作符 功能 操作数数据类型 逻 辑 操 作 符 AND 与 BIT、BOOLEAN、STD LOGIC OR 或 同上 NAND 与非 NOR 或非 XOR 异或 XNOR 异或非 NOT 非
类型 操作符 功能 操作数数据类型 符号 + 正 整数 - 负 说明:(1)操作符的优先级:( )→(NOT,ABS,**)→(REM,MOD,/,*)→(+,-)→(关系运算符)→(逻辑运算符:XOR,NOR,NAND,OR,AND) (2)在逻辑运算表达式中若全部运算符相同,则可以不加括号;若运算符不同则加括号分隔; (3)并置操作符“&”可完成一维数组的位扩展
移位运算符 VHDL中共有 (SLL, SRL)、(SLA,SRA)、(ROL,ROR) 6种移位运算符。 D3D2D1D0 SLL 0 D3D2D1D0 SRL 0 逻辑移位运算符在进行移位操作时,空缺位补‘0’。
算术移位运算符在进行移位操作时,空缺位用当前位补充。 SLA D3D2D1D0 SRA D3D2D1D0 算术移位运算符在进行移位操作时,空缺位用当前位补充。 ROL D3D2D1D0 ROR D3D2D1D0 循环移位运算符在进行移位操作时,空缺位依次由移出位补充。
移位操作符应用举例 SIGNAL a : BIT_VECTOR:=“1001”; SIGNAL b : BIT_VECTOR:=“1101”; a <= a sll 2; b <=b srl 3; 返回结果为:a = “0100” b =“0001”
VHDL的类型转换函数 函数名 功能 std_logic_1164程序包 to_stdulogicvector(a) 函数名 功能 std_logic_1164程序包 to_stdulogicvector(a) 把bit_vector转换为std_logic_vector to_bitvector(a) 把std_logic_vector转换为bit_vector to_stdulogic(a) 把bit转换为std_logic to_bit(a) 把std_logic转换为bit std_logic_arith程序包 conv_std_logic_vector(a) 把integer、unsigned、signed转换为std_logic_vector conv_integer(a) 把unsigned、signed转换为integer std_logic_unsigned程序包 把std_logic_vector转换为integer
考虑: 现有赋值表达式 a <= “1010”; 请问”1010”是什么类型的数据? 根据上下文可判断某数据的类型,但有时也判断不出来,因此最好在数据前加上显式类型限定。即 a <= STD_LOGIC_VECTOR(“1010”);
3.2.8 属性(ATTRIBUTE)描述 与定义语句 功能:用于检出时钟边沿、完成定时检查、获得未约束的数据类型的范围等。 格式: 属性测试项目名‘属性标识符;--S‘属性标识符 VHDL的属性可归纳为:信号类属性、函数类属性、数值类属性、数据类型类属性和数据区间类(或说范围类)属性。这里主要介绍数值类属性及函数信号类属性。
数值类属性 数值类属性用于返回数组的边界或长度,首先举一例数组边界的例子说明类型属性。数值类属性的关键字是LEFT、RIGHT、HIGH、LOW、LENGTH等 <目标类型> ' <值类型属性> 例如:TYPE number IS INTEGER RANGE 9 DOWNTO 0; I:=number‘LEFT;--返回左边界,I=9 I:=number‘RIGTH;--返回右边界, I=0 I:=number‘HIGH;--返回上限值, I=9 I:=number‘LOW;--返回下限值, I=0
函数信号属性 函数信号属性用来返回有关信号行为功能的信息,它反映一个信号是否正好有值的变化或事件的发生,如clk′EVENT,这个属性为“EVENT”,对检查时钟边沿触发是很有效的。它用来检查一个刚刚发生变化的信号,即推断出在信号上发生了一个跳变。 clk’EVENT语句解释为一个布尔对象,若clk’EVENT的值为真,则意味着clk值已经改变;若clk’EVENT的值为假,则意味着clk值没有改变。当clk值已经改变,且时钟值clk=’1’时,可执行后续程序,否则不执行。
例如,时钟上升沿触发的描述语句为 IF (clk’EVENT AND clk=’1’) THEN …… 该语句说明,如果时钟值clk值已经改变,且clk的当前值为1时,可执行后续程序,否则不执行。 又如:时钟下降沿触发的描述语句为 IF (clk’EVENT AND clk=’0’) THEN 注意区分event和stable LAST_EVENT——从信号最近一次的发生至今所经历的时间,常用于检查定时时间、建立时间、保持时间和脉冲宽度等。
例:用VHDL语言描述如图所示的异步复位D触发器。 图所示的D触发器,具有异步复位的功能。它具有一个输入端d和一个时钟信号clk,还有一个复位输入端clr,输出端q。当clr=‘0’时,输出端q被强迫置为“0”。“clr”也称为清零输入端。
--表示注释
3.3 VHDL顺序语句 VHDL基本描述语句: 顺序语句——在进程(PROCESS)或过程(PROCEDURE)、函数(FUNCTION)中使用,按程序书写的顺序自上而下、一个一个语句地执行; 并行语句——出现在结构体中,各语句并行(同步)执行,与书写的顺序无关。
VHDL的三种描述方式 在VHDL中,有三种基本的建模方法,即三种描述方式:行为描述、数据流描述和结构描述。行为描述的实质就是对整个系统的数学模型的描述,抽象度很高;数据流描述方式,也称寄存器传输(RTL)描述方式,通过数据流描述,可以导出系统的逻辑表达式,从而进行逻辑综合;结构描述则是在多层次的设计中,高层次的设计模块调用低层次的设计模块,或者直接用门电路单元来构成一个复杂的逻辑电路的描述方法。
3.3.1 VHDL赋值语句 顺序语句只能出现在进程(PROCESS)、过程(PROCEDURE)和函数(FUNCTION)中,其特点与传统的计算机编程语句类似,是按程序书写的顺序自上而下、一条一条地执行。利用顺序语句可以描述数字逻辑系统中的组合逻辑电路和时序逻辑电路。VHDL的顺序语句有赋值语句、流程控制语句、等待语句、子程序调用语句、返回语句、空操作语句等六类。
1. 变量赋值语句 格式:目标变量名:=赋值源(表达式); 例如:variable x: real; x:=5.0; 2. 信号赋值语句 格式:目标信号名<=赋值源; 例如:signal y: bit; y<=‘1’; 说明:该语句若出现在进程或子程序中则是顺序语句,若出现在结构体中则是并行语句。
3. 数组元素赋值 例如: SIGNAL a,b:STD LOGIC VECTOR(1 TO 4); a<=“1101”; a(1 TO 2)<=“10”; a(1 TO 2)<=b(2 TO 3);
3.3.2 流程控制语句 流程控制语句通过条件控制来决定是否执行后面的操作。条件语句必须由BOOLEAN表达式构成,即只有条件成立或不成立两种情况。 共有IF语句、CASE语句、LOOP语句、NEXT语句、EXIT语句
流程控制语句一: 1. IF语句 格式1:IF 条件句 Then 顺序语句; END IF; 格式2:IF 条件句 Then 顺序语句; ELSE END IF; 如:2选1数据选择器的描述
格式3:IF 条件句 Then 顺序语句; ELSIF 条件句 Then … ELSE END IF; 如:4选1数据选择器的描述
请用IF_ELSIF_ELSE描述4选1数据选择器。 en y Mux41 4选1 电路
LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY mux4 IS PORT (I : IN std_logic_vector(3 downto 0); en : IN std_logic_vector(1 downto 0); y : out std_logic); END mux4; ARCHITECTURE rt1 OF mux4 IS BEGIN PROCESS (input, en) IF (en= "00") THEN y<=I(0); ELSIF(en= "01") THEN y<=I(1); ELSIF(en= "10") THEN y<=I(2); ELSE y<=I(3); END IF; END PROCESS; END rt1;
【例3.5】用VHDL语言描述下图硬件电路 c a b y a b c y 1
LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY control_stmts IS PORT(a,b,c:IN BOOLEAN; y:OUT BOOLEAN); END control_stmts; (待续)
ARCHITECTURE example1 OF control_stmts IS BEGIN PROCESS(a,b,c) VARIABLE n:BOOLEAN; IF a THEN n:=b; ELSE n:=c; END IF; y<=n; END PROCESS; END example1;
【例3.6】8线-3线优先编码器的设计 (真值表) 输入 输出 a0 a1 a2 a3 a4 a5 a6 a7 y0 y1 y2 x x x x x x x 0 1 1 1 x x x x x x 0 1 0 1 1 x x x x x 0 1 1 1 0 1 x x x x 0 1 1 1 0 0 1 x x x 0 1 1 1 1 1 1 0 x x 0 1 1 1 1 1 0 1 0 x 0 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 0 0 0
LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY coder IS PORT(a:IN STD_LOGIC_VECTOR(0 TO 7); y:OUT STD_LOGIC_VECTOR(2 downTO 0)); END coder; ARCHITECTURE example2 OF coder IS BEGIN
PROCESS(a) BEGIN IF (a(7)='0') THEN y<="111"; ELSIF (a(6)='0') THEN y<=“110"; ELSIF (a(5)='0') THEN y<="101"; ELSIF (a(4)='0') THEN y<=“100"; ELSIF (a(3)='0') THEN y<=“011"; ELSIF (a(2)='0') THEN y<="010"; ELSIF (a(1)='0') THEN y<=“001"; ELSE y<="000"; END IF; END PROCESS; END example2;
IF语句的嵌套结构 格式: IF 外部条件 THEN IF 内部条件1 THEN 顺序处理语句1; END IF; ELSE 顺序处理语句2;
例:带复位端的4选1数据选择器的设计 …… ARCHITECTURE rt1 OF mux4 IS BEGIN PROCESS (input, en, reset) IF (reset =‘1’) THEN IF (en= "00") THEN y<=input(0); ELSIF (en= "01") THEN y<=input(1); ELSIF (en= "10") THEN y<=input(2); ELSE y<=input(3); END IF; y<=‘0’; END IF; END PROCESS; END rt1;
When 选择值 =>顺序语句; When 选择值 =>顺序语句; 流程控制语句二: CASE语句 格式:CASE 表达式 IS When 选择值 =>顺序语句; When 选择值 =>顺序语句; … When OTHERS =>顺序语句; END CASE; 说明:“=>”不是运算符,相当“THEN”
◎数值选择范围,如(2 TO 4),表示取值为2、3或4。 ◎并列数值,如35,表示取值为3或者5。 ◎混合方式,以上三种方式的混合。 选择值可以有四种不同的表达方式: ◎单个普通数值,如6。 ◎数值选择范围,如(2 TO 4),表示取值为2、3或4。 ◎并列数值,如35,表示取值为3或者5。 ◎混合方式,以上三种方式的混合。 …… SIGNAL sel : INTEGER RANGE 0 TO 15; CASE sel IS WHEN 0 => z1<='1' ; -- 当sel=0时选中 WHEN 13 => z2<='1' ; -- 当sel为1或3时选中 WHEN 4 To 72 => z3<='1'; -- 当sel为2、4、5、6或7时选中 WHEN OTHERS => z4<='1' ; -- 当sel为8~15中任一值时选 END CASE ;
下面这几种情况非法: SIGNAL value : INTEGER RANGE 0 TO 15; SIGNAL out1 : STD_LOGIC ; ... CASE value IS -- 缺少以WHEN引导的条件句 END CASE; CASE value IS WHEN 0 => out1<= '1' ; -- value2~15的值未包括进去 WHEN 1 => out1<= '0' ; END CASE WHEN 0 TO 10 => out1<= '1'; -- 选择值中5~10的值有重叠 WHEN 5 TO 15 => out1<= '0'; END CASE;
【例3.7】用CASE语句描述4选1数据选择器 数 据 选 择 器 a s2 z b c d s1
LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY mux41 IS PORT(s1,s2:IN STD_LOGIC; a,b,c,d:IN STD_LOGIC; z:OUT STD_LOGIC); END mux41; ARCHITECTURE example3 OF mux41 IS SIGNAL s:STD_LOGIC_VECTOR(1 DOWNTO 0);
BEGIN s<=s1&s2; PROCESS(s1,s2,a,b,c,d) CASE s IS WHEN "00" => z <= a; WHEN "01" => z <= b; WHEN "10" => z <= c; WHEN "11" => z <= d; WHEN OTHERS => z <= 'X'; END CASE; END PROCESS; END example3;
方法2: IF (a= '1') THEN sel<=sel+1; end if; IF(b= '1') THEN case sel is when 0=>q<=i0; when 1=>q<=i1; when 2=>q<=i2; when 3=>q<=i3; end case; END PROCESS; END rt1; 方法2: LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY mux4 IS PORT (a,b,i0,i1,i2,i3 : IN std_logic; q : out std_logic); END mux4; ARCHITECTURE rt1 OF mux4 IS SIGNAL SEL : INTEGER RANGE 0 TO 3; BEGIN PROCESS (a,b,i0,i1,i2,i3) sel<=0;
又如:带有WHEN OTHERS的地址译码器: LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY decode_case IS PORT ( address: IN std_logic_vector(2 downto 0); decode : out std_logic_vector(7 downto 0)); END decode_case; ARCHITECTURE design OF decode_case IS BEGIN PROCESS (address) case address is when "001"=>decode<=X"11"; when "010"=>decode<=X"22"; when "101"=>decode<=X"44"; when "111"=>decode<=X"88"; when others=>decode<=X"00"; end case; END PROCESS; END design;
加强示例: 采用CASE语句设计3-8译码器 LIBRARY IEEE ; USE IEEE.STD_LOGIC_1164.ALL ; ENTITY cdecoder_3_8 IS PORT ( d : IN STD_LOGIC_VECTOR ( 2 DOWNTO 0 ) ; G1 : IN STD_LOGIC ; G2A, G2B : IN STD_LOGIC ; q : OUT STD_LOGIC_VECTOR ( 7 DOWNTO 0 ) ) ; END ENTITY cdecoder_3_8 ; -- VHDL 1993版可以这么用 ARCHITECTURE rtl_cdecoder_3_8 OF cdecoder_3_8 IS BEGIN PROCESS ( d, G1, G2A, G2B ) IF ( G1= '1' AND G2A= '0' AND G2B = '0' ) THEN -- 译码器的使能信号 -- 采用CASE语句描述3-8译码电路 CASE d IS -- CASE语句的控制表达式是位矢量 d WHEN "000" => q <= "11111110" ; WHEN "001" => q <= "11111101" ; WHEN "010" => q <= "11111011" ; WHEN "011" => q <= "11110111" ; WHEN "100" => q <= "11101111" ; WHEN "101" => q <= "11011111" ; WHEN "110" => q <= "10111111" ; WHEN "111" => q <= "01111111" ; WHEN OTHERS => q <= "XXXXXXXX" ; END CASE ; ELSE q <= "11111111" ; END IF ; END PROCESS ; END ARCHITECTURE rtl_cdecoder_3_8 ; 加强示例: 采用CASE语句设计3-8译码器
这里的循环变量可以直接用,而不必事先定义。 流程控制语句三: LOOP语句 格式1:FOR_LOOP [标号:] FOR 循环变量 IN 初值 TO 终值 LOOP 顺序语句; END LOOP[标号]; 此循坏变量由loop语句自动声明,只能作为赋值源,而不能被赋值。
它的使用需要引入其它控制语句,如next、exit 格式2:WHILE_LOOP [标号:] WHILE 循环控制条件 LOOP 顺序语句; --循环体 END LOOP[标号]; 格式3:单个LOOP语句 [标号:] LOOP 顺序语句; END LOOP [ LOOP标号 ]; 它的使用需要引入其它控制语句,如next、exit 用法示例如下: ... L2: LOOP a := a+1; EXIT L2 WHEN a >10 ; -- 当a大于10时跳出循环 END LOOP L2;
【例3.8】8位奇偶校验器的描述(for loop) a(0) z a(1) a(2) a(3) a(4) a(5) a(6) a(7) 8 位 奇 偶 校 验 器 z a(7..0)
LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY p_check IS PORT(a:IN STD_LOGIC_VECTOR(7 DOWNTO 0); y:OUT STD_LOGIC); END p_check; ARCHITECTURE example4 OF p_check IS BEGIN
PROCESS(a) VARIABLE temp:STD_LOGIC; BEGIN temp:='0'; FOR n IN 7 DOWNTO 0 LOOP temp:=temp XOR a(n); END LOOP; y<=temp; END PROCESS; END example4;
【例3.8】8位奇偶校验器的描述(while loop) PROCESS(a) VARIABLE temp:STD_LOGIC; VARIABLE n: integer; BEGIN temp:='0'; n := ‘0’; while n<8 LOOP temp:=temp XOR a(n); n:= n+1; END LOOP; y<=temp; END PROCESS;
加强补充:while loop语句的示例: …… process( …… ) variable sum_temp, i : integer :=‘0’; begin while ( i<100) loop sum_temp := sum_temp + i ; i := i + 1; end loop; end process;
格式:NEXT [标号][WHEN 条件]; 功能: (1)NEXT——无条件结束本次循环 类似于C中的continue语句 格式:NEXT [标号][WHEN 条件]; 功能: (1)NEXT——无条件结束本次循环 (2)NEXT 标号——结束本次循环,从“标号”规定的位置继续循环; (3)NEXT 标号 WHEN 条件表达式——当“条件”满足时结束本次循环,否则继续循环。
加强next语句: LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY p_check IS PORT(a:IN STD_LOGIC_VECTOR(7 DOWNTO 0); control:in std_logic; y:OUT STD_LOGIC); END p_check; ARCHITECTURE example4 OF p_check IS BEGIN PROCESS(a) VARIABLE temp:STD_LOGIC; temp:='0'; FOR n IN 7 DOWNTO 0 LOOP next when control =‘0’; temp:=temp XOR a(n); END LOOP; y<=temp; END PROCESS; END example4;
格式:EXIT [标号][WHEN 条件]; 功能: (1)EXIT——无条件跳出循环 类似于C中的break语句 格式:EXIT [标号][WHEN 条件]; 功能: (1)EXIT——无条件跳出循环 (2)EXIT 标号——跳出循环,从“标号”规定的位置开始循环; (3)EXIT WHEN 条件——当“条件”满足时跳出循环,否则继续循环。 当程序需要处理保护、出错和警告状态时,exit语句能提供一个快捷、简便的方法。
加强exit语句: …… ARCHITECTURE example OF circle_area IS constant pi := 3.1415926; BEGIN PROCESS(clk) VARIABLE areatemp : real := ‘0’; FOR i IN 1 TO 20 LOOP areatemp:=pi * real(i) * real(i) ; if integer(areatemp) > 150 then exit; end if; END LOOP; y<=temp; END PROCESS; END example;
3.3.3 WAIT语句 WAIT [ON 敏感信号表][UNTIL 条件表达式][FOR 时间表达式]; 即:WAIT; --表示用于挂起 WAIT ON 敏感信号表; WAIT UNTIL 条件表达式; WAIT FOR 时间表达式; 注意:wait语句可用于进程process中的任何地方,但若process (敏感量)列出了敏感量,则不能使用任何形式的wait语句。
格式1: WAIT ON 敏感信号表; 功能:将运行的程序挂起直至敏感信号表中的任一信号发生变化时结束挂起,重新执行程序。 例如:SIGNAL s1,s2:STD LOGIC; PROCESS … WAIT ON s1,s2; END PROCESS;
格式2:WAIT UNTIL 条件表达式; 功能:将运行的程序挂起直至表达式中的敏感信号发生变化,而且满足表达式设置的条件时结束挂起,重新执行程序。 例如:WAIT UNTIL enable=‘1’; 格式3:WAIT FOR 时间表达式 称为超时等待语句,从执行到当前的wait语句开始,在此时间段内,进程处于挂起状态,当超过这一时间段后,进程自动恢复执行。
(a) WAIT_UNTIL结构 ... Wait until enable ='1'; ... (b) WAIT_ON结构 LOOP Wait on enable; EXIT WHEN enable ='1'; END LOOP;
一般地,只有WAIT_UNTIL格式的等待语句可以被综合器接受(其余语句格式只能在VHDL仿真器中使用) ,WAIT_UNTIL语句有以下三种表达方式: WAIT UNTIL 信号=Value ; -- (1) WAIT UNTIL 信号’EVENT AND 信号=Value; -- (2) WAIT UNTIL NOT 信号’STABLE AND 信号=Value; -- (3) 如果设clock为时钟信号输入端,以下四条WAIT语句所设的进程启动条件都是时钟上跳沿,所以它们对应的硬件结构是一样的: WAIT UNTIL clock ='1'; WAIT UNTIL rising_edge(clock) ; WAIT UNTIL NOT clock’STABLE AND clock ='1'; WAIT UNTIL clock’EVENT AND clock ='1';
3.3.4 断言(ASSERT)语句 ASSERT语句只能在VHDL仿真器中使用,用于在仿真、调试程序时的人机对话。 格式:ASSERT 条件表达式 [ REPORT 字符串] [SEVERITY 错误等级] 功能:当条件为“真”时,向下执行另一个语句,为“假”时,则输出“字符串”信息并指出“错误等级”。
例如 ASSERT (S=‘1’AND R=‘1’) REPORT “Both values of S and R are equal ‘1’” SEVERITY ERROR; 错误等级:NOTE(注意),WARNING(警告),ERROR(出错),FAILURE(失败)
采用assert、wait、severity语句的综合示例 ARCHITECTURE behav_cassert OF cassert IS SIGNAL data0, data1 : STD_LOGIC ; BEGIN ctest_A : PROCESS data0 <= '0' ; WAIT UNTIL ( data1 = '1' ) FOR 2 us ; ASSERT ( data1 = '1' ) -- 当条件不成立时执行ASSERT语句 REPORT " data1 is timed out at data1 = '1' . " SEVERITY WARNING ; data0 <= '1' AFTER 30 ns ; WAIT UNTIL ( data1 = '0' ) FOR 3 us ; ASSERT ( data1 = '0' ) REPORT " data1 is timed out at data1 = '0'. " data0 <= '0' AFTER 40 ns ; END PROCESS ctest_A ;
采用assert、wait、severity语句的综合示例 ctest_B : PROCESS BEGIN WAIT UNTIL ( data0 = '0' ) FOR 2 us ; ASSERT ( data0 = '0' ) -- 当条件不成立时则执行ASSERT语句 REPORT " data0 is timed out at data0 = '0'. " SEVERITY WARNING ; data1 <= '0' AFTER 30 ns ; WAIT UNTIL ( data0 = '1' ) FOR 3 us ; ASSERT ( data0 = '1' ) REPORT " data0 is timed out at data0 = '1'. " data1 <= '1' AFTER 40 ns ; END PROCESS ctest_B ; END ARCHITECTURE behav_cassert ;
3.4 VHDL并行语句 并行语句——出现在结构体中,各语句并行(同步)运行,与书写的顺序无关。 并行语句的使用结构: ARCHITECTURE 结构体名 OF 实体名 IS 说明语句; BEGIN 并行语句; END ARCHITECTURE 结构体名;
ARCHITECTURE END ARCHITECTURE 并行语句的种类 ARCHITECTURE 生成语句 条件信号赋值语句 元件例化语句 选择信号赋值语句 块语句 进程语句 并行过程调用语句 信号 END ARCHITECTURE
3.4.1 进程语句 进程语句属于并行语句,它在VHDL中使用最频繁、最能体现VHDL风格。 进程语句格式: 3.4.1 进程语句 进程语句属于并行语句,它在VHDL中使用最频繁、最能体现VHDL风格。 进程语句格式: [进程标号:]PROCESS [(敏感信号参数表)] [IS] [进程说明部分] BEGIN 顺序描述语句 END PROCESS [进程标号];
PROCESS[(敏感信号参数表)] 敏感信号参数表中的任何信号的改变,都将启动进程,使进程内相应的顺序语句被执行一次。为了使VHDL的软件仿真与综合和硬件仿真对应起来,应当把进程中所有输入输出信号都列入敏感信号表中。
USE IEEE.STD_LOGIC_1164.ALL; ENTITY cnt10y IS PORT(clr:IN STD_LOGIC; 【例3.9】异步清除十进制加法计数器的描述 异步清除是指复位信号有效时,直接将计数器的状态清0。 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY cnt10y IS PORT(clr:IN STD_LOGIC; clk: IN STD_LOGIC; cnt: BUFFER INTEGER RANGE 9 DOWNTO 0); END cnt10y; ARCHITECTURE example9 OF cnt10y IS
BEGIN PROCESS(clr,clk) IF clr='0' THEN cnt<=0; ELSIF clk'EVENT AND clk='1' THEN IF (cnt=9) THEN cnt<=0; ELSE cnt<=cnt+1; END IF; END PROCESS; END example9;
补充例1:两进程并发执行。 label1:process begin wait until clk = ‘1’; q1<= d; end process; label2:process wait until clk = ‘0’; q2 <= d; End dataflow; 补充例1:两进程并发执行。 Library ieee; Use ieee.std_logic_1164.all; Entity example is port(d,clk:in std_logic; q1,q2:out std_logic); End example; Architecture dataflow of example is Begin
补充例2:两进程并发执行 Library ieee; Use ieee.std_logic_1164.all; Entity sync is port(clk:in std_logic; irq:out std_logic); End sync; Architecture rtl of sync is signal couter:std_logic_vector (3 downto 0); Begin label1:process begin wait until clk = ‘1’; counter <= counter +1; end process; label2:process begin wait until clk = ‘1’; if (counter = “1111”) then irq <= ‘0’; else irq <= ‘1’; end if; End rtl;
3.4.2 块语句 功能:将一个大系统程序分解为若干子系统(块)编写,便于程序的编写、调试和查错。 格式:块名:BLOCK [说明部分] 3.4.2 块语句 功能:将一个大系统程序分解为若干子系统(块)编写,便于程序的编写、调试和查错。 格式:块名:BLOCK [说明部分] BEGIN … --以并行语句构成的块体 END BLOCK 块名
【例3.10】假设CPU芯片由算术逻辑运算单元ALU和寄存器组REG8组成,REG8又由8个REG1、REG2、…子块构成,其程序结构为: LIBRARY IEEE; USE IEEE.STD LOGIC 1164.ALL ENTITY CPU IS PORT(clk,RESET:IN STD LOGIC; ADDERS:OUT STD LOGIC_VECTOR(31 DOWNTO 0); DATA:INOUT STD LOGIC VECTOR(7 DOWNTO 0); END CPU ;
ARCHITECTURE CPU_ALU_REG8 OF CPU IS SIGANL ibus,dbus:STD_LOGIC_VECTOR(31 DOWNTO 0); --定义全局量 BEGIN ALU:BLOCK SIGNAL Qbus:STD_LOGIC_VECTOR(31 DOWNTO 0);--定义局域量 --ALU块行为描述语句 END ALU;
REG8: BLOCK SIGNALZbus:STD_LOGIC_VECTOR(31 DOWNTO 0);--定义局域量 BEGIN REG1: BLOCK SIGNAL Zbus1:STD_LOGIC_VECTOR(31 DOWNTO 0);--定义子局域量 --REG1子块行为描述语句 END REG1
说明:在结构体中定义的全局量可以在各块结构中使用;块结构中定义局域量只能在本块及所属的子块中使用;子块中定义子局域量只能在子块中使用。 … END REG8 END CPU_ALU_REG8 说明:在结构体中定义的全局量可以在各块结构中使用;块结构中定义局域量只能在本块及所属的子块中使用;子块中定义子局域量只能在子块中使用。
补充例题: 二选一电路 ENTITY mux IS PORT (d0,d1,sel: IN BIT; q: OUT BIT); 补充例题: 二选一电路 ENTITY mux IS PORT (d0,d1,sel: IN BIT; q: OUT BIT); END mux; ARCHITECTURE connect OF mux IS SIGNAL tmp1,tmp2,tmp3: BIT; BEGIN cale: BLOCK tmp1<=d0 AND sel; tmp2<=d1 AND (NOT sel); tmp3<=tmp1 OR tmp2; q<=tmp3; END BLOCK cale; END connect;
Block模块中所描述的各个语句是可以并发执行的,和模块中的语句书写顺序无关。 有条件并发执行的Block称为Guarded Block(卫式Block) Block [控制条件的布尔表达式]
补充例题 : 当clk=‘1’为真时,该Block模块被启动执行,当控制条件为假时,该Block模块不被执行。 ENTITY dff IS PORT(d,clk:IN bit; g,gb:OUT bit); END dff; ARCHITECTURE dff_guarded OF dff IS BEGIN comA:Block (clk=‘1’) g<= GUARDED d AFTER 5ns; gb <= GUARDED NOT(d) AFTER 10ns; END Block comA; END dff_guarded;
3.4.3 并行信号赋值语句 1. 简单信号赋值语句 格式:赋值目标<=表达式; 例如:output1<=a AND b; 3.4.3 并行信号赋值语句 1. 简单信号赋值语句 格式:赋值目标<=表达式; 例如:output1<=a AND b; 规则: 赋值目标必须是信号,而且出现在结构体或块语句中
2. 条件信号赋值语句(WHEN_ELSE语句) 格式: 赋值目标<=表达式 WHEN 赋值条件 ELSE 表达式 WHEN 赋值条件 ELSE … 表达式;
例如:对4选1多路选择器的描述 b WHEN s=”01” ELSE c WHEN s=”10” ELSE d; ARCHITECTURE example OF mux41 IS SIGNAL S: BIT_VECTOR(1 DOWNTO 0); BEGIN s<=s1&s2; z<=a WHEN s=”00” ELSE b WHEN s=”01” ELSE c WHEN s=”10” ELSE d; END example;
加强示例:采用WHEN_ELSE描述异或门 LIBRARY IEEE ; USE IEEE.STD_LOGIC_1164.ALL ; ENTITY cxorgate IS PORT ( d0, d1 : IN STD_LOGIC ; q : OUT STD_LOGIC ) ; END ENTITY cxorgate ; ARCHITECTURE cxorgate_example OF cxorgate IS BEGIN q <='0' WHEN d0 ='0' AND d1 ='0' ELSE '1' WHEN d0 = '0' AND d1 = '1' ELSE '1' WHEN d0 = '1' AND d1 = '0' ELSE '0' WHEN d0 = '1' AND d1 = '1' ELSE '0' ; END ARCHITECTURE cxorgate_example ;
加强示例:采用WHEN_ELSE描述3-8译码器 LIBRARY IEEE ; USE IEEE.STD_LOGIC_1164.ALL ; ENTITY cdecoder_3_8 IS PORT ( d : IN STD_LOGIC_VECTOR ( 2 DOWNTO 0 ) ; G1, G2A, G2B : IN STD_LOGIC ; q : OUT STD_LOGIC_VECTOR ( 7 DOWNTO 0 ) ) ; END ENTITY cdecoder_3_8 ; ARCHITECTURE data_flow OF cdecoder_3_8 IS BEGIN q <="11111110" WHEN(G1='1' AND G2A='0' AND G2B ='0' AND d = "000" ) ELSE "11111101" WHEN(G1='1' AND G2A='0' AND G2B ='0' AND d = "001" ) ELSE "11111011" WHEN(G1='1' AND G2A='0' AND G2B ='0' AND d = "010" ) ELSE "11110111" WHEN(G1='1' AND G2A='0' AND G2B ='0' AND d = "011" ) ELSE "11101111" WHEN(G1= '1' AND G2A='0' AND G2B ='0' AND d = "100" ) ELSE "11011111" WHEN(G1='1' AND G2A='0' AND G2B ='0' AND d = "101" ) ELSE "10111111" WHEN(G1='1' AND G2A='0' AND G2B ='0' AND d = "110" ) ELSE "01111111" WHEN(G1='1' AND G2A='0' AND G2B ='0' AND d = "111" ) ELSE "11111111" ; END ARCHITECTURE data_flow ;
3. 选择信号赋值语句 (WITH _ SELECT语句) 格式: WITH 选择表达式 SELECT 赋值目标信号<=表达式 WHEN 选择值, --以“,”号分隔 表达式 WHEN 选择值, … 表达式 WHEN 选择值; --以“;”号结束
例如:4选1数据选择器的描述 WITH sel SELECT q<=i0 AFTER 10 ns WHEN 0, i1 AFTER 10 ns WHEN 1, i2 AFTER 10 ns WHEN 2, i3 AFTER 10 ns WHEN 3, ‘X’AFTER 10 ns WHEN OTHERS;
LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; ENTITY decoder IS PORT ( a, b, c : IN STD_LOGIC; data1,data2 : IN STD_LOGIC; dataout : OUT STD_LOGIC ); END decoder; ARCHITECTURE concunt OF decoder IS SIGNAL instruction : STD_LOGIC_VECTOR(2 DOWNTO 0); BEGIN instruction <= c & b & a; WITH instruction SELECT dataout <= data1 AND data2 WHEN "000" , data1 OR data2 WHEN "001" , data1 NAND data2 WHEN "010" , data1 NOR data2 WHEN "011" , data1 XOR data2 WHEN "100" , data1 XNOR data2 WHEN "101" , 'Z' WHEN OTHERS; END concunt;
加强示例:采用WITH_SELECT描述异或门 LIBRARY IEEE ; USE IEEE.STD_LOGIC_1164.ALL ; ENTITY cxorgate2 IS PORT ( d0, d1 : IN STD_LOGIC ; q : OUT STD_LOGIC ) ; END ENTITY cxorgate2 ; ARCHITECTURE cxorgate_example OF cxorgate2 IS SIGNAL data_input : STD_LOGIC_VECTOR (1 DOWNTO 0) ; BEGIN data_input <= d1 & d0 ; WITH data_input SELECT q <= '0' AFTER 7 ns WHEN "00" , '1' AFTER 7 ns WHEN "01" , '1' AFTER 7 ns WHEN "10" , '0' AFTER 7 ns WHEN "11" ; END ARCHITECTURE cxorgate_example ;
加强示例:采用WITH_SELECT、WHEN_ELSE 描述4选1数据选择器 LIBRARY IEEE ; USE IEEE.STD_LOGIC_1164.ALL ; ENTITY cselector_41 IS PORT ( d : IN STD_LOGIC_VECTOR ( 3 DOWNTO 0 ) ; sel : IN STD_LOGIC_VECTOR ( 1 DOWNTO 0 ) ; q : OUT STD_LOGIC ) ; END ENTITY cselector_41 ; ARCHITECTURE data_flow OF cselector_41 IS SIGNAL data_select : INTEGER RANGE 0 TO 4 ; BEGIN WITH data_select SELECT q <= d(0) AFTER 7 ns WHEN 0 , d(1) AFTER 7 ns WHEN 1 , d(2) AFTER 7 ns WHEN 2 , d(3) AFTER 7 ns WHEN 3 , 'X' WHEN OTHERS ; data_select <= 0 WHEN ( sel = "00" ) ELSE 1 WHEN ( sel = "01" ) ELSE 2 WHEN ( sel = "10" ) ELSE 3 WHEN ( sel = "11" ) ELSE 4 ; END ARCHITECTURE data_flow ;
3.4.4. 子程序和并行过程调用语句 子程序(SUBPROGRAM)是具有某一特定功能的程序段,能够被主程序调用。子程序被调用时,首先要初始化,执行处理功能后,将处理结果传递给主程序。 子程序内部的值不能保持,子程序返回后,才能被再次调用,再次初始化。 子程序包括两种: 过程(PROCEDURE) 函数(FUNCTION)
1. 过程(PROCEDURE)语句 过程调用前需要将过程的实质内容装入程序包(Package)中,过程分为过程首和过程体两部分。过程首是过程的索引,相当于一本书目录,便于快速地检索到相应过程体的内容。过程首的语句格式为: PROCEDURE 过程名 (参数表); 过程体是放在程序包的包体(Package Body)中,过程体的格式为:
PROCEDURE 过程名 (参数表)IS [声明部分] BEGIN 顺序语句; END PROCEDURE 过程名; 例如 PROCEDURE adder(SIGANL a,b: IN STD_LOGIC_VECTOR; Sum: OUT STD_LOGIC ); --过程首 PROCEDURE adder (SIGANL a,b: IN STD_LOGIC_VECTOR; Sum: OUT STD_LOGIC ) IS --过程体 BEGIN …; END adder;
例: Procedure vector_to_int (input :in bit_vector; flag :out boolean; q:inout interger) is Begin q := 0; flag := false; for I in input ‘ranger loop q:=q*2; if (input(I) =‘1’) then q:= q+1; elsif (input(I) /= ‘0’) then flag := true; end if; end loop; End vector_to_int;
2. 过程调用语句 格式:过程名(关联参数表); 例如:adder(a1,b1,sum1); 规则:(1)若过程在进程(PROCESS)中调用,则是顺序语句; (2)若过程调用出现在结构体(ARCHITECTURE)或块(BLOCK)中,则属于并行语句,相当一个进程,而且每调用一次过程,就相当插入一个元件。
3. 函数(FUNCTION)语句 格式:FUNCTION 函数名(参数表) RETURN 数据类型 IS [说明部分] BEGIN [顺序处理语句] RETURN [返回变量名]; END [函数名];
说明:函数程序通常是放在程序包(PACKAGE)中。 【例3.11】求最大值的函数: LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; PACKAGE bpac1 IS FUNCTION max(a,b:IN STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; --声明函数首 END ;
PACKAGE BODY bpac1 IS FUNCTION max(a,b: IN STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS --声明函数体 BEGIN IF (a>b) THEN RETURN a; ELSE RETURN b; END IF; END max; END bpac1;
4. 函数调用语句 格式:函数名(关联参数表); 规则:函数调用是出现在结构体的语句中。例如, peak<=max(data,peak);
(a,b: in std_logic_vector) return std_logic_vector is Library ieee; Use ieee.std_logic_1164.all; Entity example is port(a,b:in std_logic_vector(7 downto 0); q:out std_logic_vector(7 downto 0)); End example; Architecture rtl of example is Function maximum (a,b: in std_logic_vector) return std_logic_vector is variable temp:std_logic_vector(a’range); Begin if (a>b) then temp :=a; else 在结构体中定义函数并调用 temp := b; end if; return(temp); End maximum; Begin process(a,b) q<= maximum(a,b); End process; End rtl;
3.4.5 元件例化(COMPONENT)语句 格式: COMPONENT 元件名 GENERIC 说明;--参数说明 PORT 说明;--端口说明 END COMPONENT; 元件定义 例化名:元件名 PORT MAP(信号,…); -- 元件例化, 或称端口映射语句
说明: (1)COMPONENT语句可以在结构体(ARCHITECTURE)、程序包(PACKAGE)和块(BLOCK)的说明中使用;GENERIC用于该元件的可变参数的代入和赋值;PORT则说明该元件的输入输出端口的信号规定; (2) COMPONENT语句分为“元件定义”和“元件例化”两部分;“元件定义”完成元件的“封装”,“元件例化”完成电路板上的元件“插座”的定义,“例化名”(标号名)相当于“插座名”是不可缺少的;
(3)(信号,…)部分完成“元件”引脚与“插座”引脚的连接——“关联” 关联方法: ①位置影射法——上层元件端口说明语句中的信号名与PORT MAP()中的信号名书写顺序和位置一一对应。例如, u1:and1(a1,b1,y1); ②名称映射法——用“=>”号将上层元件端口说明语句中的信号名与PORT MAP()中的信号名关联起来。例如, u1:and1(a=>a1,b=>b1,y=>y1);
应用Component语句时要注意的几点: 高层文件调用低层文件时,主程序、程序包中出现的低层元件的名称(实体名)、IO端口名必须和低层元件定义时保持一致。 端口映射时,信号的个数与排列顺序必须与低层元件定义时的个数与排列顺序完全一致。
【例3.13】利用2输入端与非门元件,设计4输入端的与非电路。 a b c a1 b1 c1 d1 z1 u1 u2 u3 X Y a b c a b c a b c
第一步:设计2输入端与非门 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY nd2 IS PORT (a,b: IN STD_LOGIC; c: OUT STD_LOGIC); END nd2; ARCHITECTURE nd2behv OF nd2 IS BEGIN c<=a NAND b; END nd2behv;
第二步:将设计的元件声明装入my_pkg程序包中,包含2输入端与非门元件的my_pkg程序包的VHDL源程序如下: LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; PACKAGE my_pkg IS Component nd2 --元件声明 PORT (a,b: IN STD_LOGIC; c: OUT STD_LOGIC); END Component; END my_pkg;
第三步:用元件例化产生电路: LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE work.my_pkg.ALL; --打开程序包 ENTITY ord41 IS PORT (a1,b1,c1,d1: IN STD_LOGIC; z1: OUT STD_LOGIC); END ord41; ARCHITECTURE ord41behv OF ord41 IS --元件例化
SIGNAL x,y: STD_LOGIC; BEGIN u1:nd2 PORT MAP(a1,b1,x); --位置关联 u2:nd2 PORT MAP(a=>c1,b=>d1,c=>y);--名字关联 u3:nd2 PORT MAP(x,y,c=>z1); --混合关联 END ord41behv;
练习:用元件例化语句描述4位移位寄存器。 D Q >clk dout U1 U2 U3 U4 d4 d3 d2 d1 d0 clk din D触发器的设计可参见例3.4 教材P59
LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY shifter IS PORT(din,clk: IN bit; dout : out bit); END shifter; ARCHITECTURE a OF shifter IS component dff port(d,clk: in bit; q: out bit); end component dff; signal d: bit_vector(0 to 4); BEGIN d(0)<=din; u1:dff port map(d(0),clk,d(1)); u2:dff port map(d(1),clk,d(2)); u3:dff port map(d=>d(2),clk=>clk,q=>d(3)); u4:dff port map(d=>d(3),clk=>clk,q=>d(4)); dout<=d(4); END a;
思考题: 1、在1位半加器的基础上,考虑如何用component语句实现1位全加器?
3.4.6 生成语句 功能:复制一组完全相同的并行元件或设计单元电路结构。 [说明部分] BEGIN [并行语句]; 3.4.6 生成语句 功能:复制一组完全相同的并行元件或设计单元电路结构。 格式1:[标号:] FOR 循环变量 IN 取值范围 GENERATE [说明部分] BEGIN [并行语句]; END GENERATE [标号];
在很多情况下,电路模块的两端(即输入和输出)总是具有不规则性,无法用同一个结构表示,为了解决这种不规则电路的统一描述方法,就可以采用IF_GENERATE语句。 [说明部分] BEGIN [并行语句] END GENERATE [标号];
这两种语句格式的组成 用for或if语句结构,规定重复生成并行语句的方式 声明部分,对元件数据类型、子程序、数据对象进行局部声明 并行语句部分,用生成语句复制一组完全相同的并行元件。生成语句可以嵌套 标号可选项,在嵌套生成语句中尤为重要
例3.14:CT74373的设计 第一步:设计1位锁存器latch1.vhd LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY latch1 IS PORT ( d :IN STD_LOGIC; ena :IN STD_LOGIC; q :OUT STD_LOGIC); END latch1;
ARCHITECTURE example4 OF latch1 IS SIGNAL sig_save:STD_LOGIC:=‘0’; BEGIN PROCESS (d,ena) IF ena='1' THEN Sig_save<=D; END IF; Q<=sig_save; END PROCESS; END example4;
第二步:将已设计好的元件声明装入程序包 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; PACKAGE my_pkg IS COMPONENT latch1 PORT ( d :IN STD_LOGIC; ena :IN STD_LOGIC; q :OUT STD_LOGIC); END COMPONENT; END my_pkg;
第三步:在主程序中重复生成8个latch1,构成一个8D锁存器(即74373)。 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE WORK.my_pkg.ALL; ENTITY ct74373 IS PORT (d: IN STD_LOGIC_VECTOR(7 DOWNTO 0); oen, g: IN STD_LOGIC; q: OUT STD_LOGIC _VECTOR(7 DOWNTO 0)); END ct74373;
ARCHITECTURE one OF ct74373 IS SIGNAL sigsave: STD_LOGIC_VECTOR(7 DOWNTO 0); BEGIN Gelatch: for n in 0 to 7 GENERATE Latchx: latch1 port map(d(n),g,sigsave(n)); --关联 END GENERATE; Q<=sigsave when oen=‘0’ else “ZZZZZZZZ”; END one;
利用IF_GENERATE设计4位移位寄存器 第一步:设计1位D触发器 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY dff1 IS PORT (d, clk : IN STD_LOGIC; q : OUT STD_LOGIC); END dff1;
ARCHITECTURE dffstr OF dff1 IS SIGNAL sig_save:STD_LOGIC:='0'; BEGIN PROCESS (d,clk) IF (clk'event and clk='1') THEN sig_save<=D; END IF; Q<=sig_save; END PROCESS; END dffstr;
第二步:元件例化 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY shifter4 IS PORT ( din,clk:IN STD_LOGIC; dout :OUT STD_LOGIC); END shifter4; ARCHITECTURE str OF shifter4 IS COMPONENT dff1 PORT ( d,clk:IN STD_LOGIC; q :OUT STD_LOGIC); END COMPONENT; SIGNAL data: STD_LOGIC_VECTOR(3 DOWNTO 1);
BEGIN FORGEN: FOR I IN 0 TO 3 GENERATE if0: IF I=0 GENERATE dffx0: dff1 port map (din,clk,data(I+1)); END GENERATE; if3:IF I=3 GENERATE dffx3: dff1 port map (data(iI),clk,dout); ifx:IF (I/=0)AND(I/=3) GENERATE dffx: dff1 port map (data(I),clk,data(I+1)); END str;
SIGNAL data: STD_LOGIC_VECTOR(4 DOWNTO 0); BEGIN data(0)<=din; FORGEN: FOR i IN 0 TO 3 GENERATE ux: dff1 port map (data(i),clk,data(i+1)); END GENERATE; dout<=data(4); END str;
利用IF_GENERATE设计n位移位寄存器的示例 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY shifter_n IS GENERIC( length :integer); PORT (din, clk : IN STD_LOGIC; dout : OUT STD_LOGIC); END shifter_n; ARCHITECTURE str OF shifter_n IS COMPONENT dff1 PORT ( d,clk:IN STD_LOGIC; q :OUT STD_LOGIC); END COMPONENT; SIGNAL data: STD_LOGIC_VECTOR((length-1) DOWNTO 1); 续下页
续上页 BEGIN FORGEN: FOR I IN 0 TO (length-1) GENERATE if0: IF I=0 GENERATE dffx0: dff1 port map (din,clk,data(i+1)); END GENERATE; if3:IF I=(length-1) GENERATE dffx3: dff1 port map (data(i),clk,dout); ifx:IF (I/=0)AND(I/ =(length-1) ) GENERATE dffx: dff1 port map (data(i),clk,data(i+1)); END str;
补充例1:用VHDL语言描述如图所示的60进制同步计数器。 如图所示的60进制同步计数器,具有异步复位和同步置数功能的8421BCD码计数器。
LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_unsigned.all; ENTITY cnt60 IS PORT(ci,nreset,clk,load : IN STD_LOGIC; data: IN STD_LOGIC_VECTOR(7 DOWNTO 0); qh, ql : BUFFER STD_LOGIC_VECTOR(3 DOWNTO 0); co : out std_logic ); END CNT60;
ARCHITECTURE behave OF cnt60 IS BEGIN co<='1'when(qh="0101"and ql="1001" and ci='1') else '0'; PROCESS (clk,nreset) IF (nreset = '0') THEN qh <=“0000”; ql <=“0000”; --异步复位 ELSIF (clk'EVENT AND clk = '1') THEN IF (load = '1') THEN qh <=data(7 downto 4); ql<=data(3 downto 0); --同步置数 ELSIF (ci='1') then IF(ql=9) then ql<=“0000”; --模60的实现 IF(qh=5) then qh<="0000"; ELSE qh<=qh+1; --计数功能的实现 END IF; ELSE ql<=ql+1; END PROCESS; END behave;
补充例2:如图所示,用VHDL语言描述同步可逆计数器。 同步可逆计数器具有一个计数方式控制端ud。当ud=1时,计数器加法计数;当ud=0时,计数器减法计数。res是异步清零控制端,低电平有效。
LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_unsigned.all; ENTITY udcnt IS PORT(clk,res,ud : IN STD_LOGIC; q:out STD_LOGIC_VECTOR(3 DOWNTO 0)); END udcnt; ARCHITECTURE behave OF udcnt IS signal qn: STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN PROCESS (clk,res) IF (res = '0') THEN qn <="0000"; ELSIF (clk'EVENT AND clk = '1') THEN IF (ud = '1') THEN qn<=qn+1; else qn<=qn-1; END IF; END PROCESS; q<=qn; END behave;
3.5 VHDL的库和程序包 根据VHDL语法规则,在VHDL程序中使用的文字、数据对象、数据类型都需要预先定义。为了方便用VHDL编程和提高设计效率,可以将预先定义好的数据类型、元件调用说明以及一些常用子程序汇集在一起,形成程序包,供VHDL设计实体供调用,若干个程序包则形成库。
IEEE两个标准库STD和IEEE中的程序包 程序包名 定义的内容 库名 程序包名 定义的内容 STD STANDARD 定义VHDL的数据类型 TEXTIO TEXT读写控制数据类型和子程序等 I E STD_LOGIC_1164 定义std_logic、std_logic_vector等 STD_LOGIC_ARITH 定义有符号和无符号数据类型和基于这些数据类型的算术运算符。 STD_LOGIC_SIGNED 定义基于std_logic、std_logic_vector数据类型上的有符号的算术运算 STD_LOGIC_UNSIGNED 定义基于std_logic、std_logic_vector数据类型上的无符号的算术运算
3.5.1. VHDL库 常用VHDL库有IEEE标准库、STD库和WORK库。IEEE标准库包括STD_LOGIC_1164程序包和STD_LOGIC_ARITH程序包。其中,STD_LOGIC_ARITH程序包是SYNOPSYS公司加入IEEE标准库的程序包,它包括STD_LOGIC_SIGNED(有符号数)程序包、STD_LOGIC_UNSIGNED(无符号数)程序包和STD_LOGIC_SMALL_INT(小整型数)程序包。其中STD_LOGIC_1164是最重要和最常用的程序包,大部分数字系统设计都是以此程序包设定的标准为基础。
因此,在每个设计实体开始都有打开IEEE标准库和该程序包的语句: LIBRARY IEEE; USE IEEE STD_LOGIC_1164.ALL; STD库包含STANDARD和TEXTIO程序包,它们是文件输入/输出程序包,在VHDL的编译和综合过程中,系统都能自动调用这两个程序包中的任何内容。用户在进行电路设计时,可以不必如IEEE库那样打开该库以及它的程序包。
WORK库是用户设计的现行工作库,用于存放用户自己设计的工程项目。在PC机或工作站利用VHDL进行项目设计,不允许在根目录下进行,必须在根目录下为设计建立一个工程目录(即文件夹),VHDL综合器将此目录默认为WORK库。但“WORK”不是设计项目的目录名,而是一个逻辑名。VHDL标准规定WORK库总是可见的,因此在程序设计时不需要明确指定。
3.5.2 VHDL程序包 在设计实体中定义的数据类型、子程序或数据对象对于其他设计实体是不可再利用的。为了使已定义的数据类型、子程序、元件能被其他设计实体调用或共享,可以把它们汇集在程序包中。 VHDL程序包必须经过定义后才能使用,程序包的结构中包含Type Declaration(类型定义)、Subtype Declaration(子类型定义)、Constant Declaration(常量定义)、Signal Declaration(信号定义)、Component Declaration(元件定义)、Subprogram Declaration和(子程序定义)等内容,
程序包定义的格式为 PACKAGE 程序包名 IS Type Declaration(类型定义) Subtype Declaration(子类型定义) Constant Declaration(常量定义) Signal Declaration(信号定义) Component Declaration(元件定义) Subprogram Declaration(子程序定义) END 程序包名;
例如,定义my_pkg程序包的结构中,包含2输入端与非门nd2元件说明、1位锁存器Latch1元件说明和求最大值函数max的函数首说明以及它的函数体说明。 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; PACKAGE my_pkg IS Component nd2 PORT (a,b: IN STD_LOGIC; c: OUT STD_LOGIC); END Component;
Component latch1 PORT (d:IN STD_LOGIC; ena:IN STD_LOGIC; q:OUT STD_LOGIC); END Component; FUNCTION max(a,b:IN STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; END ; --函数首定义
PACKAGE BODY my_pkg IS --函数体定义 FUNCTION max(a,b: IN STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS BEGIN IF (a>b) THEN RETURN a; ELSE RETURN B; END IF; END max; END my_pkg;
由于程序包也是用VHDL语言编写的,所以其源程序也需要以. vhd文件类型保存,my_pkg的源程序名为my_pkg 由于程序包也是用VHDL语言编写的,所以其源程序也需要以.vhd文件类型保存,my_pkg的源程序名为my_pkg.vhd。为了使用my_pkg程序包中定义内容,在设计实体的开始,需要将其打开,打开my_pkg程序包的语句是: USE work. my_pkg.ALL; 注意:(1)程序包保存时文件名不一定要和程序包名相同; (2)程序包必须放在现行设计的工程文件夹中; (3)高层文件调用低层文件时,主程序、程序包中出现的低层元件的名称(实体名)、IO端口名必须和低层元件定义时保持一致。
3.6 VHDL设计流程 设计举例:计数显示译码电路的设计 计数显示译码电路的设计包括Cnt4e.vhd、Dec7s.vhd和TOP.gdf三个模块,其中Cnt4e.vhd和Dec7s.vhd是用VHDL编写的4位二进制计数器和共阴极7段显示译码器源程序,TOP. gdf则是以原理图输入法设计的顶层文件。在TOP. gdf原理图中以Cnt4e.vhd和Dec7s.vhd作为元件,设计一个8位计数显示译码电路。 (注:本节内容应结合实际操作讲述。)
设 计 流 程 编辑VHDL源文件 编译设计文件 编辑顶层设计文件 编译顶层设计文件 仿真顶层设计文件 锁定引脚 硬件调试 编程下载
3.6.1 编辑VHDL源文件 执行“File” → “New…”命令菜单或按“新建”按钮出现“New”对话框,选择“Text Editor file”,按“OK”
编辑四位二进制计数器的源程序Cnt4.vhd 。
七段数码显示译码器的源程序Decl7s.vhd 。
3.6.2 创建源文件TOP.GDF 计数显示译码电路设计需要的元件
TOP顶层设计结果图
3.6.3 编译顶层设计文件 执行“MAX+plus”的“Compiler”命令,可对顶层设计文件进行编译。在编译中,自动完成编译网表提取(Compiler Netlist Extractor)、数据库建立(Database Builder)、逻辑综合(Logic Synthesizer)、逻辑分割(Partitioner)、适配(Fitter)、延时网表提取(Timing SNF Extractor)和编程文件汇编(Assembler)等操作。 在完成对图形编辑文件的编译后,系统并没有为设计文件自动生成元件符号,若要生成元件符号,则还要执行“File”菜单下的“Create Default Symbol”命令。
3.6.4 仿真顶层设计文件 8位计数显示译码电路的仿真波形
3.6.5 引脚锁定 首先在“Device Family”中选择“MAX7000S”,在Device列表中选择“EPM7128SLC84-15”芯片型号。 然后在“Assign”的“Pin/Location/Chip…”的对话框中设置引脚。 引脚锁定后还可在floorplan中编辑修改,只是在编辑修改后要再次编译才会生效。
3.6.6 编程下载 执行“MAX+plus Ⅱ”的“Programmer”命令