690 likes | 843 Views
复习. 3.5.2 块语句. 1.BLOCK 语句的表达格式如下 : 块标号: BLOCK [( 块保护表达式 )] [IS] [ 块头 ] ; [ 块声明 ] ; BEGIN 并行语句 A ; 并行语句 B ; … END BLOCK [ 块标号 ] ;. 3.5.3 并行信号赋值语句. 并行信号赋值语句有三种形式: 简单信号赋值语句 选择信号赋值语句 条件信号赋值语句 共同点是:赋值目标必须都是信号。. 1 简单信号赋值语句. 它语句格式如下: 赋值目标 <= 表达式;
E N D
复习 3.5.2 块语句 1.BLOCK语句的表达格式如下: 块标号:BLOCK [(块保护表达式)] [IS] [块头]; [块声明]; BEGIN 并行语句A; 并行语句B; … END BLOCK [块标号];
3.5.3 并行信号赋值语句 并行信号赋值语句有三种形式: • 简单信号赋值语句 • 选择信号赋值语句 • 条件信号赋值语句 共同点是:赋值目标必须都是信号。
1 简单信号赋值语句 它语句格式如下: 赋值目标<=表达式; 因为VHDL是强类型语言,所以目标信号的数据类型必须与赋值符号“<=”右边表达式的数据类型一致。
2 选择信号赋值语句 选择信号赋值语句格式如下: WITH 选择表达式 SELECT 赋值目标信号<=表达式1 WHEN 选择值1, 表达式2 WHEN 选择值2, …… 表达式n WHEN OTHERS;
3 条件信号赋值语句的格式如下: 赋值目标信号 <= 表达式1 WHEN 赋值条件1 ELSE 表达式2 WHEN 赋值条件2 ELSE … 表达式n WHEN 赋值条件n ELSE 表达式; 注意:条件赋值语句每一子句的结尾没有任何标点,只有最后的子句有分号。
例 条件信号赋值语句的用法 …… ARCHITECTURE ar_6 OF fzh_1 IS BEGIN y<= a WHEN q=″00″ELSE b WHEN q=″01″ELSE c WHEN q=″10″ELSE d ; END ar_6;
例程:8输入优先编码器 library ieee; use ieee.std_logic_1164.all; entity priority_encoder is port( I: in std_logic_vector(7 downto 0); A: out std_logic_vector(2 downto 0)); end; architecture dataflow of priority_encoder is begin A<=″111″ when I(7)=′1′else ″110″ when I(6)= ′1′else -- (I(7)=‘0’)AND( I(6)=‘1’)
″101″ when I(5)= ′1′ else ″100″ when I(4)= ′1′ else ″011″ when I(3)= ′1′ else ″010″ when I(2)= ′1′ else ″001″ when I(1)= ′1′ else ″000″ when I(0)= ′1′ else ″111″; End ;
3.5.5 元件例化语句 元件例化语句是实现层次化设计的重要方法。 层次化设计的核心思想有两个:一是模块化,二是元件重用(reuse)
元件例化的实质:就是引入一种连接关系,将预先设计好的设计实体定义为一个元件,然后利用特定的语句将此元件与当前的设计实体中的指定结点(或者端口)相连接,从而为当前设计实体引入一个新的低一级的设计(层次).元件例化的实质:就是引入一种连接关系,将预先设计好的设计实体定义为一个元件,然后利用特定的语句将此元件与当前的设计实体中的指定结点(或者端口)相连接,从而为当前设计实体引入一个新的低一级的设计(层次). 如果把当前设计实体看作一个较大的电路系统---一个电路板,所定义的例化元件就相当于一个要焊到这个电路系统板上的芯片(元件),电路板上要留出确定的位置.
元件例化语句的语法格式 元件例化语句由两部分组成:元件定义语句和元件例化语句,这两部分语句在元件化中都是必须同时存在。 -- 元件定义语句 COMPONENT 例化元件名 IS GENERIC (类属表); PORT(例化元件端口名表); END COMPONENT 例化元件名; --元件例化语句 元件例化名:例化元件名 PORT MAP( [例化元件端口名=>] 连接实体端口名,…);
例化元件的端口与当前系统端口的连接表达方式有两种:例化元件的端口与当前系统端口的连接表达方式有两种: ①名字关联方式:将例化元件的端口名与关联端口名通过关联(连接)符号“=>”一一对应地联系起来. ②位置关联方式:按例化元件端口的定义顺序将例化元件对应的连接实体端口名一一列出的一种关联方式. 例3.5.1 图3.21 ORD41逻辑原理图
两输入与非门的VHDL描述: LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY ND2 IS PORT(A,B:IN STD_LOGIC; C:OUT STD_LOGIC); END ENTITY ND2; ARCHITECTURE ARTND2 OF ND2 IS BEGIN C<=A NAND B; END ARCHITECTURE ARTND2;
LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY ORD41 IS PORT(A1,B1,C1,D1:IN STD_LOGIC; Z1:OUT STD_LOGIC); END ENTITY ORD41; ARCHITECTURE ARTORD41 OF ORD41 IS COMPONENT ND2 IS PORT(A,B:IN STD_LOGIC; C:OUT STD_LOGIC); END COMPONENT ND2; SIGNAL S1,S2:STD_LOGIC; BEGIN
U1:ND2 PORT MAP (A1,B1,S1);--位置关联方式 U2:ND2 PORT MAP (A=>C1,C=>S2,B=>D1); --名字关联方式 U3:ND2 PORT MAP (S1,S2,C=>Z1) ; --混合关联方式 END ARCHITECTURE ARTORD41;
BEGIN u1:FreDevider4 PORT MAP(Clkin=>Clk,Clkout=>Clkl); u2:FreDeviderl0 PORT MAP(Clkin=>CIk,Clkout=>Clk2); u3: MUX2 PORT MAP(DataA=>Clkl,DataB=>CIk2,Sel=>Sel,Dataout=>Clkout); END;
元件例化语句实现了系统的层次化和结构化设计,但也有缺点,那就是:如果有N个上层实体用到了同一个下层实体,那么在这N个上层实体的程序中,都必须对该下层实体进行元件定义。另外,如果一个程序中用到了很多元件,那么元件定义语句要占很大篇幅,使程序显得臃肿,降低程序的可读性。元件例化语句实现了系统的层次化和结构化设计,但也有缺点,那就是:如果有N个上层实体用到了同一个下层实体,那么在这N个上层实体的程序中,都必须对该下层实体进行元件定义。另外,如果一个程序中用到了很多元件,那么元件定义语句要占很大篇幅,使程序显得臃肿,降低程序的可读性。 解决上述两个问题的办法就是用程序包Package。
3.6 子程序(SUBPROGRAM) VHDL子程序可以用来描述一些重复使用的电路。在实际使用中必须注意,综合后的子程序将映射为目标芯片中的一个相应的电路模块,且每一次调用都将在硬件结构中产生具有相同结构的不同的模块,这一点与在普通的程序设计语言中子程序调用有很大的不同。
子程序分为两类:过程和函数。 • 3.6.1函数(FUNCTION) • 在硬件电路的设计过程中,我们可以把常用的或者重复使用的电路独立出来设计、测试,一旦完成之后即可存放起来以便往后自己或别人调用。本节所讨论的函数(function)就具有这种功能,在VHDL语言中,函数的使用可分成函数首(声明部分)和函数体(主体内容部分),其语法分别如下。
1 函数首 函数首就是函数声明部分,其语法格式如下: FUNCTION 函数名称 (输入参数1:数据类型; 输入参数2:数据类型; … 输入参数n:数据类型; ) RETURN输出参数的数据类型;
分析如下函数声明语句:function maximum (L,R:INTEGER )return INTEGER;
2 函数体(即函数的定义) 函数体的语法格式如下: FUNCTION 函数名称 (输入参数1:数据类型; 输入参数2:数据类型; … 输入参数n:数据类型; ) RETURN 输出参数的数据类型 IS [说明部分;] -- 局部变量声明区 BEGIN 顺序语句; RETURN 输出参数名称; END FUNCTION 函数名; --函数体结束
【例3.6.3】分析如下函数主体。 function maximum (L,R:INTEGER) return INTEGER is begin if L>R then return L; eIse return R; end if; end function maximum ;
函数(function)的使用分成两个部分,一个是函数的声明部分,另一个是函数的主体部分。此处我们要注意:如果函数的主体部分是定义在调用它的程序的结构(architecture)内时,那就表示此函数只有自己要使用(也许是要重复使用)。在这种情形之下函数声明部分就可以省略。但是如果所定义的函数是放在程序包(package)中供大家共同取用时,函数声明部分就必须存在。在程序包中定义函数,函数首和函数体都必需有。由此可见,函数首的作用只是作为程序包的有关此函数的一个接口界面。函数(function)的使用分成两个部分,一个是函数的声明部分,另一个是函数的主体部分。此处我们要注意:如果函数的主体部分是定义在调用它的程序的结构(architecture)内时,那就表示此函数只有自己要使用(也许是要重复使用)。在这种情形之下函数声明部分就可以省略。但是如果所定义的函数是放在程序包(package)中供大家共同取用时,函数声明部分就必须存在。在程序包中定义函数,函数首和函数体都必需有。由此可见,函数首的作用只是作为程序包的有关此函数的一个接口界面。
3.6.2重载函数(OVERLOADED FUNCTION) VHDL允许以相同的函数名定义函数,即重载函数。但要求函数中定义的操作数具有不同的数据类型,以便在调用函数时可以根据参数的数据类型确定调用哪一个同名函数。在不同数据类型操作数构成的同名函数中,以运算符重载函数最为常用。运算符重载函数可以方便不同数据类型之间的运算,VHDL中预定义的操作符如“+”、“AND”、“MOD”、“>”等运算符均可以被重载,以赋予新的数据类型操作功能。
【例3.6.4】给出了一个Synopsys公司的程序包STD_LOGIC_UNSIGNED中关于函数的部分内容。【例3.6.4】给出了一个Synopsys公司的程序包STD_LOGIC_UNSIGNED中关于函数的部分内容。 LIBRARY IEEE; --程序包首 USE IEEE.STD_LOGIC_1164.ALL; USE IEEE STD_LOGIC_ARITH.ALL;--定义了UNSIGNED、SIGNED以及SMALL_INT PACKAGE STD_LOGIC_UNSIGNED IS FUNCTION “+”(L:STD_LOGIC_VECTOR;R:INTEGER) RETURN STD_LOGIC_VECTOR; FUNCTION “+”(L:INTEGER; R:STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; FUNCTION “+”(L:STD_LOGIC_VECTOR;R:STD_LOGIC) RETURN STD_LOGIC_VECTOR; FUNCTION SHR(ARG:STD_LOGIC_VECTOR; COUNT:STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; … END PACKAGE STD_LOGIC_UNSIGNED;
LIBRARY IEEE; --程序包体 USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_ARITH.ALL; PACKAGE BODY STD_LOGIC_UNSIGNED IS FUNCTION MAXIMUM(L,R:INTEGER) RETURN INTEGER IS BEGIN IF L>R THEN RETURN L; ELSE RETURN R; END IF; END FUNCTION MAXIMUM;
FUNCTION “+”(L:STD_LOGIC_VECTOR;R:INTEGER) RETURN STD_LOGIC_VECTOR IS VARIABLE RESULT:STD_LOGIC_VECTOR(L'RANGE); BEGIN RESULT:= UNSIGNED(L)+R; RETURN STD_LOGIC_VECTOR(RESULT);--程序包体部分UNSIGNED()函数是从IEEE.STD_LOGIC_ARITH库中调用的 END FUNCT10N "+"; … END PACKAGE BODY STD_LOGIC_UNSIGNED; 通过此例,不仅可以看到在程序包中完整的函数表达形式,而且还将注意到,在函数首的三个函数名都是同名的,即都是以加法运算符“+”作为函数名。以这种方式定义函数即所谓运算符重载。对运算符重载(即对运算符重新定义)的函数称重载函数。
[例3.6.4]重载函数使用实例(4位二进制加法计数器)。[例3.6.4]重载函数使用实例(4位二进制加法计数器)。 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL;--注意此程序包的功能 ENTITY CNT4 IS PORT( CLK :IN STD_LOGIC; Q:BUFFER STD_LOGIC_VECTOR(3 DOWNTO 0)); END ENTITY CNT4; ARCHITECTURE ART OF CNT4 IS BEGIN PROCESS(CLK) IS
BEGIN IF CLK'EVENT AND CLK=‘1’THEN IF Q=15 THEN --Q两边的数据类型不一致, 程序自动调用了重载函数 Q<=“0000”; ELSE Q<=Q+1; --这里,程序自动调用了加号“+”的重载函数 END IF; END IF; END PROCESS; END ARCHITECTURE ART;
3.6.3 过程(PROCEDURE) 过程(procedure)的用途与函数(function)相似,它们的目的都是为了能重复使用某一个电路,或者将某些电路独立出来,以达到分工平行设计的目的。 但两者最大的不同点在于,函数(function)内的参数只能为输入,返回的信号只能有一个,而过程(procedure)的参数可以是输入(in)、输出(out)或输入输出(inout),其返回的信号没有限制为必定一个。 与函数(function)相同,在VHDL语言中,过程(procedure)的使用可以区分成过程首(声明部分)和过程体(主体内容(即定义)部分),其各自的语法分别如下。
1过程首--过程的声明过程首的语法格式如下所示:PROCEDURE 过程名称 (参数对象 参数名称 :模式 数据类型; 参数对象 参数名称 :模式 数据类型;…参数对象 参数名称 :模式 数据类型 ); 过程首示意方框图
注意:一般地,进程的参数可以工作在三种模式,即IN、OUT和INOUT。如果参数为IN模式,而没有定义参数的数据对象,则默认为常量;如果参数的工作模式为OUT或INOUT,则参数的数据对象是变量。注意:一般地,进程的参数可以工作在三种模式,即IN、OUT和INOUT。如果参数为IN模式,而没有定义参数的数据对象,则默认为常量;如果参数的工作模式为OUT或INOUT,则参数的数据对象是变量。
分析如下的过程声明语句。procedure DENUL2 (Signal D:in Std_logic;Signal S:in Std_logic;Signal Y:out Std_logic_Vector(0 to 1) );
【例3.6.5】 PROCEDURE PRO1(VARIABLE A,B:INOUT REAL); PROCEDURE PRO2 (CONSTANT A1:IN INTEGER; VARIABLE B1:OUT INTEGER); PROCEDURE PRO3 (SIGNAL S1:INOUT BIT);
2过程的主体 过程主体的语法如下所示: PROCEDURE 过程名称 (参数对象 参数名称 :模式 数据类型; 参数对象 参数名称 :模式 数据类型; … 参数对象 参数名称 :模式 数据类型; ) IS [说明部分;] --局部对象声明区 BEGIN 顺序语句; END PROCEDURE 过程名; --过程体结束
【例3.6.6】 PROCEDURE PRG1(VARIABLE V1:INOUT BIT_VECTOR(0 TO 3)) IS BEGIN CASE V1 IS WHEN“0000” => V1:=“0101”; WHEN“0101” => V1:=“0000”; WHEN OTHERS => V1:=“1111”; END CASE; END PROCEDURE PRG1; 这个过程对具有双向模式的变量V1做了一个数据转换运算。
与函数(function)的语句相同,如果过程(procedure)的主体部分是定义在调用程序的结构体(architecture)内时,那就表示此过程只有自己要使用,在这种情况下,过程的声明部分就可以省略;但是如果所定义的过程是放在程序包(package)内供大家取用时,过程的声明部分就必须存在。与函数(function)的语句相同,如果过程(procedure)的主体部分是定义在调用程序的结构体(architecture)内时,那就表示此过程只有自己要使用,在这种情况下,过程的声明部分就可以省略;但是如果所定义的过程是放在程序包(package)内供大家取用时,过程的声明部分就必须存在。
3.6.4 重载过程(OVERLOADED PROCEDURE) 有重载函数,也有重载过程。重载过程是指两个或两个以上且有相同过程名,而参数数据类型不同的过程称为重载过程。对于重载过程,也是靠辨别参数类型来确定究竟调用哪一个过程。 【例3.6.8】 PROCEDURE CAL(V1,V2:IN REAL; SIGNAL OUT1:INOUT INTEGER); PROCEDURE CAL(V1,V2:IN INTEGER; SIGNAL OUT1:INOUT REAL); … CAL(20.15,1.42,S1);--调用第一个重载过程CAL,S1为INOUT模式的整数信号 CAL(23,320,S2); --调用第二个重载过程CAL,S2为INOUT模式的实数信号
3.6.5 子程序调用语句 子程序分为两类:过程和函数。 若程序调用的是一个过程,就称为过程调用;若程序调用的是一个函数,则称为函数调用。过程调用和函数调用都是子程序调用。
子程序调用语句分为顺序子程序调用语句和并行子程序调用语句。这取决于子程序在结构体中所处的位置。子程序调用语句分为顺序子程序调用语句和并行子程序调用语句。这取决于子程序在结构体中所处的位置。 • 有一点应该清楚就是function的调用可以在architecture的任何位置,即函数调用与简单信号赋值语句类似,即可以作顺序语句也可以作为并行语句;但procedure的调用却一般放在process中,原因是out及inout的参数,其返回值一定要是variable,当然也有例外。
1.过程调用 过程调用将启动执行一个给定名字和参数的过程。过程调用语句的语法格式如下: 过程名 ( 形参名=> 实参表达式{,形参名=> 实参表达式}) ; 一个过程的调用有三个步骤:首先将IN和INOUT模式的实参值赋给欲调用过程中与它们相对应的形参;然后执行这个过程;最后将过程中OUT和INOUT模式的形参值赋还给对应的实参。
例3.5.14. PACKAGE DATA_TYPES IS --定义程序包 TYPE DTYPE1 IS INTEGER RANGE 0 TO 3; TYPE DTYPE2 IS ARRAY(1 TO 3) OF DTYPE1; END PACKAGE DATA_TYPES; USE WORK.DATA_TYPES.ALL; --打开以上建立在当前工作库的程序包DATA_TYPES ENTITY SORT IS PORT( SR:IN DTYPE2; SC:OUT DTYPE2); END ENTITY SORT;
ARCHITECTURE ART OF SORT IS BEGIN PROCESS (SR) IS --进程开始,设SR为敏感信号 PROCEDURE SWAP(DATA:INOUT DTYPE2; LOW,HIGH:IN INTEGER ) IS VARIABLE V1: DTYPE1; BEGIN --开始描述本过程的逻辑功能 IF(DATA(LOW)>DATA(HIGH))THEN --检测数据 V1:=DATA(LOW); DATA(LOW):=DATA(HIGH); DATA(HIGH):=V1; END IF; END PROCEDURE SWAP; --过程SWAP定义结束
VARIABLE V2:DTYPE2;--在本进程中定义变量V2 BEGIN --进程开始 V2:=SR; --将输入值读入变量 SWAP(V2,1,2);--V2、1、2是对应于DATA、LOW、HIGH的实参 SWAP(V2,2,3);--位置关联法调用,第2、第3元素交换 SWAP(V2,1,2);--第1、第2元素再次交换 SC<=V2; END PROCESS;
【例3.5.15】 … PROCEDURE ADDER(SIGNAL A,B:IN STD_LOGIC; SIGNAL SUM:OUT STD_LOGIC) IS … ADDER(A1,B1,SUM1);--并行过程调用在此,A1、B1、SUM1即为分别对应于A、B、SUM的关联参量名 … PROCESS(C1,C2) IS --进程语句执行 BEGIN ADDER(C1,C2,S1); --顺序过程调用,在此,C1、C2、S1即为分别对应于A、B、SUM的关联参量名 END PROCESS; 2函数调用 函数调用与过程调用是十分相似的,这里就不举例了。
3.4.7 其他语句和说明 其他语句是指:属性描述与定义语句、文本操作语句、断言语句、REPORT语句、决断函数。这里只介绍属性语句,其它的语句都不常用。 • 属性(ATTRIBUTE)描述与定义语句 在VHDL中有一些些预先定义好的属性(称为VHDL中预定义属性),这些属性的使用有的是程序中必要的,有的会增加程序的可读性,有的会使程序的设计更为方便。VHDL中可以具有属性的项目如下: 类型、子类型;过程、函数;信号、变量、常量;实体、结构体、配置、程序包;元件;语句标号。
属性的值与对象(信号、变量和常量)的值完全不同,在任一给定时刻,一个对象只能具有一个值,但却可以具有多个属性。VHDL还允许设计者自己定义属性。属性的值与对象(信号、变量和常量)的值完全不同,在任一给定时刻,一个对象只能具有一个值,但却可以具有多个属性。VHDL还允许设计者自己定义属性。