1.57k likes | 2.04k Views
VHDL 硬件描述语言 ( 二 ). VHDL 硬件描述语言 ( 二 ). 2.1 VHDL 程序结构 2.2 VHDL 的语言元素 2.3 VHDL 的基本描述语句 2.4 VHDL 结构体的三种描述方法. 2.1 VHDL 程序结构. 2.1.1 VHDL 程序基本结构 2.1.2 VHDL 结构体的基本子结构. 例 1 一个 2 输入的与门的逻辑描述 LIBRARY ieee; -- 库说明语句
E N D
VHDL硬件描述语言(二) • 2.1 VHDL程序结构 • 2.2 VHDL的语言元素 • 2.3 VHDL的基本描述语句 • 2.4 VHDL结构体的三种描述方法
2.1 VHDL程序结构 • 2.1.1 VHDL程序基本结构 • 2.1.2 VHDL结构体的基本子结构
例1 一个2输入的与门的逻辑描述 LIBRARY ieee; --库说明语句 USE ieee.std_logic_1164.ALL; --程序包说明语句 ENTITY and2 IS PORT(a,b : IN STD_LOGIC; y : OUT STD_LOGIC); END and2; ARCHITECTURE and2x OF and2 IS BEGIN y<=a AND b; END and2x; 实体部分 结构体部分 2.1 VHDL程序结构 • 2.1.1 VHDL程序基本结构
实体部分描述设计系统的外部接口信号(即输入/输出信号)实体部分描述设计系统的外部接口信号(即输入/输出信号) 实体 (Entity) 结构体 (Architecture) VHDL设计文件的 两个基本组成部分 配置 (Configuration) 一个完整的 VHDL程序 包集合 (Package) 库 (Library) • 2.1.1 VHDL程序基本结构 结构体用于描述 系统的内部电路 配置用于从库中选取所需元件安装到设计单元的实体中 包集合存放各设计模块能共享的数据类型、常数、子程序等 库 用于存放已编译的实体、结构体、包集合和配置
a y and2 b 实体的一般格式为: ENTITY实体名 IS [类属参数说明]; [端口说明]; END; • 2.1.1.1 实体(ENTITY) • ENTITY、IS、END是VHDL的关键字(保留字)。 • 实体中的每一个I/O信号被称为端口,其功能对应于电路 图符号的一个引脚。端口说明则是对一个实体的一组端口的定义,即对基本设计实体与外部接口的描述。端口是设计实体和外部环境动态通信的通道。 • 类属参数说明是可选部分。如果需要,可使用以“GENERIC”语句来指定该设计单元的类属参数(如延时、功耗等)。 • 实体名、端口名等均应为符合VHDL命名规则 的标识符。
端口说明的一般格式为: PORT(端口名{,端口名}:端口模式 数据类型; 端口名{,端口名}:端口模式 数据类型); PORT (a,b : IN STD_LOGIC; y : OUT STD_LOGIC); • 端口模式用来说明数据传输通过该端口的方向。端口模式有以下几类: • IN(输入):仅允许数据流进入端口。主要用于时钟输入、控制输入、单向数据输入。 • OUT(输出):仅允许数据流由实体内部流出端口。该模式通常用于终端计数一类的输出,不能用于反馈。 • BUFFER(缓冲):该模式允许数据流出该实体和作为内部反馈时用,但不允许作为双向端口使用。 • INOUT(双向):可以允许数据流入或流出该实体。该模式也允许用于内部反馈。 • 如果端口模式没有指定,则该端口处于缺省模式为:IN。 • 数据类型原则上可以是任何标准的数据类型和用户自定义类型。
mode mode in out buffer in inout in out 模式及其信号源
类属参数说明的格式为: GENERIC(参数名:参数类型:=初始值); 例2:加入类属说明的2输入的与门的逻辑描述 ENTITY and2 IS GENERIC (m:TIME:=1ns); PORT(a,b : IN STD_LOGIC; y : OUT STD_LOGIC); END and2; ARCHITECTURE and2x OF and2 IS SIGNAL u: BIT; BEGIN u<=a AND b; y<=u after(m) when u=’1’ else u after(m) ; END and2x;
a[3..0] Sum[3..0] add4 b[3..0] Co Ci 例3: 四位加法器实体说明程序 ENTITY add4 IS PORT(a, b: IN STD_LOGIC_VECTOR(3 downto 0); Ci: IN STD_LOGIC; Sum: OUT STD_LOGIC_VECTOR(3 downto 0); Co: OUT STD_LOGIC); END add4; 由实体说明画出四位加法器add4的电路图如下所示。
2.1.1.2 结构体(ARCHITECTURE ) 结构体的一般格式如下: ARCHITECTURE结构体名 OF实体名 IS [结构体说明部分]; BEGIN [并发处理语句]; END结构体名; • 结构体说明是指对结构体需要使用的信号、常数、数据类 型和函数进行定义和说明。 • 并发处理语句位于BEGIN和END之间,这些语句具体地描述了构造体的行为。并发处理语句是功能描述的核心部分,也是变化最丰富的部分。并发处理语句可以使用赋值语句、进程语句、元件例化语句、块语句以及子程序等。需要注意的是,这些语句都是并发(同时)执行的,与排列顺序无关。
2.1.1.3 配置(CONFIGURATION) 配置的基本格式为: CONFIGURATION配置名 OF实体名 IS [配置说明]; END配置名; • 配置语句描述了层与层之间的连接关系,以及实体与构造体之间的连接关系。设计者可以利用配置语句选择不同的构造体,使其与要设计的实体相对应;在仿真某一个实体时,可以利用配置选择不同的构造体进行性能对比实验,以得到性能最佳的构造体。
配置语句根据不同情况,其说明语句有简有繁。最简单的缺省配置格式为:配置语句根据不同情况,其说明语句有简有繁。最简单的缺省配置格式为: CONFIGURATION配置名 OF实体名 IS FOR 选配结构体名 END FOR; END配置名; 例4:加入了配置的4位等值比较器设计文件 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY comp4 IS PORT(a, b: IN STD_LOGIC_VECTOR(3 downto 0); y: OUT STD_LOGIC); END comp4;
--结构体1: ARCHITECTURE behavior OF comp4 IS BEGIN Comp: PROCESS(a, b) BEGIN IF a=b THEN y<=’1’; ELSE y<=’0’; END IF; END PROCESS comp; END behavior; --结构体2: ARCHITECTURE dataflow OF comp4 IS BEGIN y<=’1’ WHEN(a=b) ELSE ’0’; END dataflow;
元件例化语句 --结构体3: ARCHITECTURE structural OF comp4 IS COMPONENT xnor2 PORT(in1, in2: IN STD_LOGIC; Out: OUT STD_LOGIC); END COMPONENT; COMPONENT and4 PORT(in1, in2, in3, in4: IN STD_LOGIC; Out: OUT STD-LOGIC); END COMPONENT; SIGNAL s: STD_LOGIC_VECTOR(0 to 3); BEGIN u0: xnor2 PORT MAP(a(0),b(0),s(0)); u1: xnor2 PORT MAP(a(1),b(1),s(1)); u2: xnor2 PORT MAP(a(2),b(2),s(2)); u3: xnor2 PORT MAP(a(3),b(3),s(3)); u4: and4 PORT MAP(s(0),s(1),s(2),s(3),y); END structural; 元件标号 元件型号
u0 a a0 s0 b0 b u1 a1 s1 u4 b1 y u2 a2 s2 b2 u3 a3 s3 b3 4位等值比较器 --配置 : CONFIGURATION comp4_con OF comp4 IS FOR behavior END FOR; END comp4_con;
包集合的语法结构如下: PACKAGE 包集合名 IS [包集合说明]; 包头 END包集合名; PACKAGE BODY包集合名 IS [包体内容]; 包体 END BODY; • 2.1.1.4 包集合(PACKAGE) • 包集合是一种使其中的类型、元件、函数和其它说明对其它设计单元可见的设计单元。与之相反,构造体中的这些说明仅仅对其自身可见。 • 包集合包括包头和包体两部分。包头 用来声明包中的类型、元件、函数和子程序;而包体 则用来存放说明中的函数和子程序。不含有子程序和函数的包集合不需要包体。
例6:描述三电平逻辑的包集合 PACKAGE logic IS TYPE three_level_logic IS (’0’,’1’,’Z’); --三电平逻辑 CONSTANT unknown_value: three_level_logic :=’0’; FUNCTION invert (input : three_level_logic) RETURN three_level_logic; END logic; PACKAGE BODY logic IS FUNCTION invert (input : hree_level_logic) RETURN hree_level_logic IS BEGIN CASE input IS WHEN ’0’=> RETURN ’1’; WHEN ’1’=> RETURN ’0’; WHEN ’Z’=> RETURN ’Z’; END CASE; END invert; END BODY;
2.1.1.5 库(LIBRARY) • 库是用来放置可编译的设计单元的地方,通过其目录可查询和调用。 VHDL中的库大致可归纳为5种:IEEE库、STD库、ASIC矢量库、WORK库和用户定义库。 • IEEE库。常用的资源库。IEEE库包含经过IEEE正式认可的STD_LOGIC_1164包集合和某些公司提供的一些包集合,如STD_LOGIC_ARITH(算术运算库)、STD_LOGIC_UNSIGNED等。 • STD库。VHDL的标准库。库中存放有称为“standard”的标准包集合,其中定义了多种常用的数据类型,均不加说明可直接引用。STD库中还包含有称为“textio”的包集合。在使用“textio”包集合中的数据时,应先说明库和包集合名,然后才可使用该包集合中的数据。 • ASIC矢量库。在VHDL语言中,为了进行门级仿真,各公司可提供面向ASIC的逻辑门库。在该库中存放着与逻辑门一一对应的实体。为了使用面向ASIC的库,对库进行说明是必要的。
WORK库。WORK库是现行作业库。设计者所描述的VHDL语句不需要任何说明,将都存放在WORK库中。WORK库对所有设计都是隐含可见的,因此在使用该库时无需进行任何说明。WORK库。WORK库是现行作业库。设计者所描述的VHDL语句不需要任何说明,将都存放在WORK库中。WORK库对所有设计都是隐含可见的,因此在使用该库时无需进行任何说明。 • 用户定义库。用户定义库简称用户库,是由用户自己创建并定义的库。设计者可以把自己经常使用的非标准(一般是自己开发的)包集合和实体等汇集成在一起定义成一个库,作为对VHDL标准库的补充。用户定义库在使用时同样要首先进行说明。 • VITAL库。
库说明语句的语法形式为: LIBRARY 库名; --说明使用什么库 USE包集合名; --说明使用库中哪一个包集合及包集 合中的项目(如过程名、函数名等) • 包集合名最多为三个层次,即 : library-name. packge-name. item-name • LIBRARY 语句和USE语句的作用范围: 仅限于紧跟起后的实体和结构体。
2.1.2 VHDL结构体的基本子结构 在规模较大的电路设计中,整个电路将被分成若干个相对独立的模块来描述。这样,一个结构体可以用几个子结构,即相对独立的几个模块来构成。VHDL语言有以下3种形式的子结构描述语句: • BLOCK 语句结构 • PROCESS 语句结构 • SUBPROGRAMS 结构
2.1.2.1 块( BLOCK) 一个大规模的电原理图通常可以分割成多张子原理图,以便于设计和存档。同样,在VHDL程序设计中,构造体对应整个电原理图,而构造体可由多个BLOCK块组成,每一个BLOCK块则对应一张子原理图。电原理图的分割关系和VHDL程序中用BLOCK块分割构造体的关系是一一对应的。 BLOCK语句的语法格式为: 块标号:BLOCK [(块保护条件)] [说明语句]; BEGIN [并发处理语句]; END BLOCK标号名; • 保护条件是可选项,它是一个布尔表达式。如果有保护条件,则该条件应用圆括号括起来,放在BLOCK之后。保护条件的作用是:只有当其为真时,该块中的语句才被启动执行;否则,该块中的语句不被执行。 • BLOCK语句中所描述的各个语句是可以并行执行的,它和书写顺序无关。
u1 tmp1 d0 u3 q tmp3 d1 tmp2 u2 sel 2选1 数据选择器 例7 用BLOCK语句描述2选1电路的程序。 ENTITY mux2_1 IS PORT(d0, d1, sel : IN STD_LOGIC; q : OUT STD_LOGIC); END mux2_1; ARCHITECTURE amux OF mux2_1 IS SIGNAL tmp1,tmp2,tmp3 : STD_LOGIC; BEGIN cale: BLOCK BEGIN tmp1<=d0 AND sel; tmp2<=d1 AND (not sel); tmp3<=tmp1 OR tmp2; q<=tmp3; END BLOCK cale; END amux; 上述结构体中只有一个 BLOCK块,若电路复杂时可由几个BLOCK块组成。
q nq Q D C clk d 例8 用带保护条件的BLOCK语句描述一个锁存器的结构。 ENTITY latch IS PORT(d, clk : IN STD_LOGIC; q, qn : OUT STD_LOGIC); END latch; ARCHITECTURE latch_a OF latch IS BEGIN g1:BLOCK(clk='1') BEGIN q<=guarded d after 5ns; qn<=guardednot(d) after 7ns; END BLOCK g1; END latch_a; • 在BLOCK块中的两个信号传送语句都写有前卫关键词guarded,表明只有clk=’1’为真时,这两个语句才能执行。 (注意 :这里的综合工具不支持 guarded block语句和after 短语。)
2.1.2.2 进程( PROCESS) PROCESS语句是VHDL中描述硬件系统并发行为的最常用、最基本的语句。 进程语句的一般格式为; [进程名:] PROCESS (敏感信号表) 进程说明语句 BEGIN 顺序描述语句; END PROCESS [进程名]; Example: PROCESS ( CLK ) BEGIN IF CLK'EVENT AND CLK = '1' THEN Q1<= D; END IF; Q<=Q1; END PROCESS;
关于 进程 ( PROCESS )的疑问? • 何时 PROCESS 被执行? • 何时 PROCESS 执行结束 ? • 可以有多个进程出现吗? • 多个进程之间如何通信? • 与C 代码中的函数 的区别 ?
何时 PROCESS 被执行?进程敏感量 • PROCESS ( CLK ) • BEGIN • IF CLK'EVENT AND CLK = '1' THEN • Q1 <= D; • END IF; • Q<=Q1; • END PROCESS; CLK 信号 发生变化时 PROCESS 被执行
看看此PROCESS的电路? • LIBARY IEEE; • USE IEEE.STD_LOGIC_1164.ALL; • ENTITY and2 IS • PORT ( a : IN STD_LOGIC; • b : IN STD_LOGIC; • q : OUT STD_LOGIC • ); • END ENTITY and2; • ARCHITECTURE bhv OF and2 IS • SIGNAL Q1 : STD_LOGIC; • BEGIN • P0: • process(a,b) • begin • q <= a and b; • end process p0; • END ARCHITECTURE bhv;
可以有多个进程出现吗? • …… • ARCHITECTURE BEHAV OF mul IS • SIGNAL temp : BIT • BEGIN • p_a: • PROCESS ( a, b, selx ) • BEGIN • IF ( selx ='0' ) THEN • temp <= a; • ELSE • temp <= b; • END IF; • END PROCESS p_a; • p_b: • PROCESS ( temp, c, sely ) • BEGIN • IF ( sely ='0' ) THEN • data_out<= temp; • ELSE • data_out<= datac; • END IF; • END PROCESS p_b; • END ARCHITECTURE BEHAV;
关于 进程 ( PROCESS )的小结 • 敏感信号表所标明的信号是用来启动进程的。敏感信号表中的信号无论哪一个发生变化(如由’0’变’1’或由’1’变’0’ )都将启动该PROCESS语句。一旦启动后, PROCESS中的语句将从上至下逐句执行一遍。当最后一个执行完毕以后,即返回到开始的PROCESS语句,等待下一次启动。因此,只要PROCESS中指定的信号变化一次,该PROCESS语句就会执行一遍。 • PROCESS内部各语句之间是顺序关系 。在系统仿真时, PROCESS语句是按书写顺序一条一条向下执行的。而不象BLOCK中的语句可以并行执行。 • 若构造体中有多个进程存在,各进程之间的关系是并行关系 ;进程之间的通信则一边通过接口由信号传递,一边并行地同步执行。
过程(PROCEDURE) 函数(FUNCTION) VHDL的子程序有两种类型: • 2.1.2.3 子程序( SUBPROGRAM)
过程(PROCEDURE) 过程语句的结构: PROCEDURE 过程名(参数1;参数2;… )IS [定义语句]; BEGIN [顺序处理语句]; END过程名; 过程语句的调用格式: 过程名(实际参数表);
例10 设计一个从两个整数中求取最大值的过程。 PROCEDURE max(a, b: IN INTEGER; y: OUT INTEGER) IS BEGIN IF (a<b) THEN y<=b; ELSE y<=a; END IF; END max; 过程的调用: max ( x, y, maxout ) ;
函数(FUNCTION) 函数语句的结构: FUNCTION函数名(输入参数表)RETUEN数据类型 IS [定义语句]; BEGIN [顺序处理语句]; RETUEN [返回变量名]; END [函数名]; 函数语句的调用格式: 函数名(实际参数表);
例11 用FUNCTION语句描述求取最大值的函数。 FUNCTION max(a:std_logic_vector;b:std_logic_vector) RETURN std_logic_vector IS VARIABLE tmp :std_logic_vector(a'range); BEGIN IF (a>b) THEN tmp:=a; ELSE tmp:=b; END IF; RETURN tmp; END max; • 函数的参数均为输入参数。 • 函数调用返回一个指定数据类型的值。
例11 在结构体中调用求最大值的函数。 LIBRARY ieee; USE ieee.std_logic_1164.ALL; ENTITY dpeak IS PORT(clk, set : IN STD_LOGIC; date : IN STD_LOGIC_VECTOR(5 downto 0); dout : OUT STD_LOGIC_VECTOR(5 downto 0)); END dpeak;
ARCHITECTURE rtl OF dpeak IS SIGNAL peak : STD_LOGIC_VECTOR(5 downto 0); BEGIN dout<=peak; PROCESS (clk) BEGIN IF (clk'event and clk='1') THEN IF (set='1') THEN peak<=date; ELSE peak<= max(date,peak); END IF; END IF; END PROCESS; END rtl;
子程序的特点: • 子程序可以在结构体或程序包的任何位置被调用,而且可以反复调用。 • 子程序是一个非重入的程序,即子程序返回后才能再被调用。在调用时子程序首先要进行初始化,执行结束后子程序终止;再调用时要再进行初始化。因此,子程序内部的值不能保持。 • VHDL的子程序具有可重载性,即允许有许多重名的子程序,但这些子程序的参数类型和返回数值类型是不同的。
2.2 VHDL的语言元素 • 2.2.1 标识符 • 2.2.2 数据对象 • 2.2.3 数据类型 • 2.2.4 运算符与操作符 • 2.2.5 属性
2.2.1 标识符 标识符规则: 标识符规则是在书写VHDL程序时的一般文字规则。基本标识符由字母、数字以及下划线字符组成,且具有以下特征要求: ● 第一个字符必须是字母; ● 最后一个字符不能是下划线; ● 不允许连续两个下划线; ● 在标识符中大、小写字母是等效的。 ● VHDL中的注释文字一律为2个连续的连接线“--”,可以出现在任一语句后面,也可以出现在独立行; ● VHDL的保留字(关键字)不能用于标识符;
例如:如下标识符是合法的: tx_clk Three_state_Enable sel7D HIT_1124 如下标识符是非法的: _ tx_clk 8B10B large#number link__bar select rx_clk_ --标识符必须起始于字母 --只能是字母、数字、下划线 --不能有连续两个下划线 --关键字(保留字)不能用于标识符 --最后字符不能是下划线
2.2.2 数据对象 在VHDL中,数据对象是可以赋予一个值的客体。常用的数据对象为常量、变量 和信号,在使用前必须给予说明。 ●常量(CONSTANT) 常量是指在设计描述中不会变化的值。在VHDL描述中,一般用常量名代替数值。 常量说明语句的一般格式为: CONSTANT常量名{,常量名}:数据类型 := 取值; • 常量所赋值和定义的数据类型应一致。 • 常量一旦赋值就不能再改变。 例如: CONSTANT width : integer : = 8 ;
●变量(VARIABLE) 变量是暂存数据的量。 变量说明语句的格式是: VARIABLE 变量名{,变量名}:数据类型 [:=初始值]; • 例如:VARIABLE count: INTEGER RANGE 0 TO 99 : =0 • 变量是一个局部量 ,它只用于进程和子程序。变量必须在进程或子程序的说明区域中加以说明。 • 变量赋值是直接的、非预设的 ,它在某一时刻仅包含一个值。变量的赋值立即生效,不存在延时行为。变量常用在实现某种运算的赋值语句中。 变量赋值语句格式为: 目标变量名:= 表达式; • 赋值语句中的表达式必须与目标变量具有相同的数据类型。
●信号(SIGNAL) 信号是电子电路内部硬件实体相互连接的抽象表示。信号能够代表连线,也可内连元件,端口也是信号。 信号说明语句的格式为: SIGNAL信号名{,信号名} :数据类型 [:=初始值]; • 例如: SIGNAL count: BIT_VECTOR(3 downto 0); • 信号包括I/O引脚信号以及IC内部缓冲信号,有硬件电路与之 对应,故信号之间的传递有实际的附加延时。 • 信号通常在构造体、包集合和实体中说明;信号不能在进程中 说明(但可以在进程中使用)。
信号赋值语句格式为: 目标信号名<= 表达式; • 赋值语句中的表达式必须与目标信号具有相同的数据类型。 • 硬件中的信号总是同时工作的,即信号同时在各个模块中流动,这就是硬件电路的并发性。HDL体现了实际电路中信号“同时”流动的这种基本特性。
信号和变量的主要区别: 1.变量 是一个局部量,只能用于进程或子程序中; 信号 是一个全局量,它可以用来进行进程之间的通信。 2. 变量赋值 立即生效,不存在延时行为; 信号赋值 具有非立即性,信号之间的传递具有延时性。 3. 变量 用作进程中暂存数据的单元; 信号 用作电路中的信号连线。 4. 信号赋值 可以出现在进程中,也可以直接出现在结构体中,但它们的运行含义不同:前者属顺序信号赋值,此时的赋值操作要视进程是否已被启动;后者属并行信号赋值,其赋值操作是各自独立并行发生的。
5. 在进程中变量和信号的赋值形式与操作过程不同: 在变量的赋值语句中,该语句一旦被执行,其值立即被赋予变量。在执行下一条语句时,该变量的值即为上一句新赋的值。 在信号的赋值语句中,该语句即使被执行,其值不会使信号立即发生代入,在下一条语句执行时,仍使用原来的信号值。直到进程结束之后,所有信号赋值的实际代入才顺序进行处理。因此,实际代入过程和赋值语句的执行是分开进行的。 如例12所示。