发布时间:2025-12-09 14:05:23 浏览次数:4
VHDL的全称为VHSIC硬件描述语言(VHSIC Hardware Description Language),VHSIC: Very High Speed Integrated Circuit
1980 – 美国国防部设立一个基金,在VHSIC项目之下开设了一个子课题,研究标准的硬件描述语言,1982诞生VHDL。
1987 – IEEE 将其修正为 IEEE 标准:1076
1993 – 修正了VHDL语言,升级至IEEE 1076-1993
为什么使用VHDL ?原理图图形化设计缺点?
答:
大型设计,原理图连接太复杂,检查错误太困难
通过使用高级语言对你的设计做描述,可以分析语法错误,综合后效率可能更高,时间成本更好。
VHDL的基本设计单元结构:程序包说明、实体说明、结构体说明三部分。
-- 库、程序包的说明调用Library IEEE;use IEEE.Std_Logic_1164.ALL;-- 实体声明Entity FreDevider isport( Clock: IN Std_logic; Clkout: OUT Std_logic);END;-- 结构体定义Architecture Behavior Of FreDevider issignal Clk:Std_Logic; -- 中间临时变量begin process(Clock) begin IF rising_edge(Clock) THEN Clk <= NOT Clk; END IF; END process; Clkout <= Clk;END
库是专门用于存放预先编译好的程序包的地方,对应一个文件目录,程序包的文件就放在此目录中,其功能相当于共享资源的仓库,所有已完成的设计资源只有存入某个“库”内才可以被其他实体共享。库的说明总是放在设计单元的最前面,表示该库资源对以下的设计单元开放。库语句格式如下:
LIBRARY 库名;
常用的库有IEEE库、STD库和WORK库:
库的作用范围:
库说明语句的作用范围从一个实体说明开始到它所属的构造体、配置为止。当一个源程序中出现两个以上的实体时,两条作为使用库的说明语句应在每个实体说明语句前重复书写。
(1)示例1:
自定义一个库:
(2)示例2:
程序包是用VHDL语言编写的一段程序,可以供其他设计单元调用和共享,相当于公用的“工具箱”,各种数据类型、子程序等一旦放入了程序包,就成为共享的“工具”,类似于C语言的头文件,使用它可以减少代码的输入量,使程序结构清晰。在一个设计中,实体部分所定义的数据类型、常量和子程序可以在相应的结构体中使用,但在一个实体的声明部分和结构体部分中定义的数据类型、常量及子程序却不能被其他设计单元使用。因此,程序包的作用是可以使一组数据类型、常量和子程序能够被多个设计单元使用。
程序包分为包头和包体两部分。包头(也称程序包说明)是对包中使用的数据类型、元件、函数和子程序进行定义,其形式与实体定义类似。包体规定了程序包的实际功能,存放函数和过程的程序体,而且还允许建立内部的子程序、内部变量和数据类型。包头、包体均以关键字PACKAGE开头。程序包格式如下:
--包头格式:PACKAGE 程序包名 IS[包头说明语句]END 程序包名;--包体格式:PACKAGE BODY 程序包名 IS[包体说明语句]END 程序包名;
调用程序包的通用模式为:
USE 库名.程序包名.ALL;
常用预定义程序包有以下四个:
自定义包的实现见2.1.1节库的示例。
实体描述了设计单元的输入输出接口信号或引脚,是设计实体经封装后对外的一个通信界面。
ENTITY 实体名 IS -- 引导语句[GENERIC (常数名: 数据类型: 设定值)] -- 类属表PORT -- 端口表( 端口名1: 端口方向 端口类型; 端口名2: 端口方向 端口类型; 端口名3: 端口方向 端口类型; ...... 端口名n: 端口方向 端口类型 -- 最后一个一定不能加";",不然会报next process的")" expect ";" or ",");END [实体名]; -- 结束语句
注意:
类属说明的书写格式是:
GENERIC(常数名:数据类型:设定值);
其他
类属 GENERIC 参量是一种端口界面常数,常以一种说明的形式放在实体或块结构体前的说明部分。比较常见的情况是利用类属来动态规定一个实体的端口的大小,或设计实体的物理特性,或结构体中的总线宽度,或设计实体中底层中同种元件的例化数量等等。一般在结构体中,类属的应用与常数是一样的,其中的常数名是由设计者确定的类属常数名,数据类型通常取 INTEGER 或TIME 等类型,设定值即为常数名所代表的数值,但需注意 VHDL 综合器仅支持数据类型为整数的类属值。例如:
ENTITY mcu1 ISGENERIC (addrwidth : INTEGER := 16);PORT( add_bus : OUT STD_LOGIC_VECTOR(addrwidth-1 DOWNTO 0) ); ...
在这里 GENERIC 语句对实体 mcu1 作为地址总线的端口 add_bus 的数据类型和宽度作了定义 即定义 add_bus 为一个 16 位的标准位矢量 定义 addrwidth 的数据类型是整数INTEGER 其中 常数名addrwidth减 1 即为 15 所以这类似于将上例端口表写成PORT (add_bus : OUT STD_LOGIC_VECTOR (15 DOWNTO 0));
PORT(端口信号名:端口模式 数据类型;端口信号名:端口模式 数据类型);
结构体的任务是:定义结构体中的各项内部使用元素,如数据类型(TYPE),常数(CONSTAND),信号(SIGNAL),元件(COMPONENT),过程(POCEDURE),变量(VARIABLE)和进程(PROCESS)等。通过VHDL语句描述实体所要求的具体行为和逻辑功能。描述各元件之间的连接。
Architecture 结构体名 OF 实体名 IS定义语句法;BEGIN功能描述语句法;END 结构体名称;
结构化描述、数据流描述、行为描述、混合。
原件和内联,通过低级器件的内联实现。
特点:
描述数据在系统中的流动过程,数据流使用一系列的并发语句实现逻辑,数据流的描述是在控制逻辑函数已经获得的条件下实现,数据流代码亦称为并发代码。
注意:并发语句在编译中被同时评估,因此语句的顺序无关紧要。
特点:
举例:
y1 <= x1 AND x2; y2 = NOT x1; y3 <= x3 OR x2;
顺序和并发语句,通过输入输出响应描述。
特点:
举例:
if x1 = '0' theny1 <= x2 and x3; elsif ... esle ... end if;
entity equ2 isport(a,b:in std_logic_vector(1 downto 0);equ:out std_logic);end equ2;--结构体结构描述:用元件例化,即网表形式来实现;architecture netlist of equ2 is-- nor 或非
component nor2port(a,b :in std_logic;c :out std_logic);end component;component xor2
-- xor 异或port(a,b :in std_logic;c :out std_logic);end component;signal x: std_logic_vector(1 downto 0);beginU1:xor2 port map(a(0),b(0),x(0));U2:xor2 port map(a(1),b(1),x(1));U3:nor2 port map(x(0),x(1),equ);end netlist;--结构体数据流描述:用布尔方程来实现:architecture equation of equ2 isbeginequ<=(a(0) xor b(0)) nor(a(1) xor b(1));end equation;--结构体行为描述:用顺序语句来实现:architecture con_behave of equ2 isbeginprocess(a,b)beginif a=b thenequ<='1';elseequ<='0';end if;end procerss;end con_behave;--结构体行为描述:用并行语句来实现:architecture seq_behave of equ2 isbeginequ<='1' when a=b else '0';end sqq_behave;
用行为描述方式设计的全加器
LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;ENTITY onebitadder ISPORT(a,b,cin:IN BIT;Sum,count:OUT BIT);END onebitadder;ARCHITECTURE behavior OF onebitadder ISBEGINPROCESS(a,b,cin)BEGINSum<= a XOR b XOR cin;Count<=(a AND b) OR ((a XOR b) AND cin);END PROCESS;END behavior;
块结构名:BLOCK 端口说明 类属说明BEGIN并行语句END BLOCK 块结构名;
进程名:PROCESS(敏感信号表) IS进程说明BEGIN顺序描述语句END PROCESS 进程名;
Configuration 配置名 of 实体名 IS for 结构体名 end for;end;-- 1076-1987 versionend Configuration;-- 1076-1993 versionConfiguration <identifier> of <entity_name> IS for <architecture_name> end for;end;-- 1076-1987 versionend Configuration;-- 1076-1993 version
能被主程序反复调用并能将处理结果传送到主程序的程序模块,子程序分为过程语句(Procedure)和函数(Functure)两种。子程序中的参数说明是局部的,只能在子程序体内起作用。
PROCEDURE 过程名(参数1;参数2;----) IS定义语句;BEGIN顺序处理语句;END 过程名;
FUNCTION 函数名(参数1;参数2;----)RETURN 数据类型 IS定义语句;BEGIN顺序处理语句;RETURN 返回变量名;
标识符用来定义常数、变量、信号、端口、子程序或者参数的名字。由字母(A~Z, a~z)、数组(0~9)和下划线(_)字符组成。
关键字(keyboard)是VHDL中具有特别含义的单词,只能作为固定的用途,用户不能用其做为标识符。
为全局变量,在程序包说明、实体说明、结构体描述中使用,用于声明内部信号,而非外部信号(外部信号为IN、OUT、INOUT、BUFFER),其在元件之间起互联作用,可以赋值给外部信号。
定义格式:
SIGNAL 信号名: 数据类型[:= 初始值];举例:SIGANL brdy: BIT;SIGANL output: INTEGER:= 2;
赋值格式:
目标信号名<=表达式
常在结构体中用赋值语句完成对信号赋初值的任务,因为综合器往往忽略信号声名时所赋的值。
只在给定的进程(process)中用于声明局部值或用于子程序中,变量的赋值符号为“:=”,和信号不同,信号是实际的,是内部的一个存储元件(SIGNAL)或者是外部输入(IN、OUT、INOUT、BUFFER),而变量是虚的,仅是为了书写方便而引入的一个名称,常用在实现某种算法的赋值语句当中。
定义格式:
VARIABLE 变量名: 数据类型[:= 初始值];举例:VARIABLE opcode: BIT_VECTOR(3 downto 0):= "0000";VARIABLE freq: INTEGER;
变量赋值符号”:=”,变量赋值立刻更新。
在结构体描述、程序包说明、实体说明、过程说明、函数调用说明和进程说明中使用,在设计中描述某一规定类型的特定值不变,如利用它可设计不同模值的计数器,模值存于一常量中,对不同的设计,改变模值仅需改变此常量即可,就如参数化元件。
定义格式:
CONSTANT 常数名:数据类型:= 初始值;举例:CONSTANT rise_fall_time: TIME:= 2ns;CONSTANT data_bus: INTEGER:= 16;
信号与变量最大的不同在于,如果在一个进程中多次为一个信号赋值,只有最后一个值会起作用,而当为变量赋值时,变量的值改变是立即发生的。
VHDL是一种强类型语言,对于每一个常数、变量、信号、函数及设定的各种参量的数据类型(DATA TYPES)都有严格要求,相同数据类型的变量才能互相传递和作用,标准定义的数据类型都在VHDL标准程序表STD中定义,实际使用中,不需要用USE语句以显式调用。
VHDL常用的数据类型有三种:
Type BOOLEAN IS (FALSE, TRUE);
取值为FALSE和TRUE,不是数值,不能运算,一般用于关系运算符
TYPE BIT IS (‘0’, ‘1’);
取值为0和1,用于逻辑运算
TYPE BIT_VECTOR IS ARRAY(Natural range<>) OF BIT;
基于Bit类型的数组,用于逻辑运算
SIGNAL a: Bit_Vector (0 to 7); Signal a: Bit_Vector (7 to 0);
TYPE CHARACTER IS (NUL, SOH, STX, …, ”, ‘!’, …);
通常用”引号引起来,区分大小写
通常用””双引号引起来,区分大小写
VARIABLE string_var: STING (1 to 7);
string_var := “ABCD”
取值范围,可用32位的有符号的二进制数表示
VARIABLE a: INTEGER -63 to 63
在实际应用中,VHDL仿真器将ITEGER作为有符号数处理,而VHDL综合器将Integer作为无符号数处理
要求用range子句为所定义的数限定范围,以便根据范围来决定表示此信号或变量的二进制的位数。
实数类型仅能在VHDL仿真器中使用,综合器不支持
取值范围
物理量数据,包括整数和单位两个部分
时间类型仅能在VHDL仿真器中使用,综合器不支持
范围从
表达方法包含数字、(空格)单位两部分,如(10 PS)
常用单位:fs,ps,ns,us,ms,sec,min,hr
表示系统状态
该类型仅能在VHDL仿真器中使用,综合器不支持
TYPE severity_lever IS (NOTE, WARNING, ERROR, FAILURE)
STD_LOGIC:工业标准的逻辑类型,取值为‘0’(强制为高)、‘1’(强制为低)、‘Z’(高阻态)、‘X’(强未知)、‘W’(弱未知;弱信号不定)、‘L’(弱0;弱低)、‘H’(弱1;若高)、‘-’(忽略;不关心)、‘U’(未初始化),只有前四种具有实际物理意义,其他的是为了与模拟环境相容才保留的。STD_LOGIC_VECTOR:工业标准的逻辑类型集,STD_LOGIC的组合。TYPE 数据类型名 IS (枚举文字,枚举文字,. . . .)
TYPE 数据类型名 IS RANGE 约束范围;(如-10到+10)
TYPE 数据类型名 IS ARRAY(下限 TO 上限) OF 类型名称
TYPE 记录类型名 IS RECODE元素名: 数据类型名;元素名: 数据类型名;END RECODE
关于运算符的分类暂不详究。。。
顺序语句和并行语句是VHDL程序设计中两大基本描述语句系列。顺序语句(Sequential Statements)用来实现模型的算法描述;并行语句(Concurrent Statements)用来表示各模型算法描述之间的连接关系,这些语句从多侧面完整地描述数字系统的硬件结构和基本逻辑功能,其中包括通信的方式、信号的赋值、多层次的元件例化以及系统行为等。
Architecture <architecture_name> of <entity_name> is说明语句;begin 并行语句;end architecture 结构体名;
<signal_name> <= <expression>;Example:q <= input1 or input2;q <= input1 and input2;-- 最终执行 q <= input1 and input2;
格式:
<signal_name> <= <signal/value> when <condition1> else <signal/value> when <condition2> else . . . <signal/value> when <conditionN> else <signal/value>;
示例:
with <expression> select<signal_name> <= <signal/value> when <condition1>, <signal/value> when <condition2>, <signal/value> when others
有人说:从本质上讲VHDL的所有语句都是并行语句。进程(process)语句是用来给并行的硬件提供顺序语句,一个结构体可以包含多个进程,多个进程之间并行运行。进程内部的语句顺序执行。
(1)进程的工作原理:
(2)进程与时钟:
(3)敏感表和wait语句
wait until condition;
architecture arc2 of process_wait is begin process begin wait until clk'event and clk = '1'; q<=d; end process;end architecture;
wait on sensitivity list;
wait on (a,b,c); --敏感表
(4)注意:
process(a,b,s) begin --final results: s<=a+b y<=a+b+1 y<=s+1; s<=a; s=a+b; end process;
process(a,b) variable ss: std_logic_vector(3 downto 0); begin ss:=a; y<=ss+1; ss:=a+b; end process;--结果:由于y<=ss+1写在ss:=a之后,所以将a+1的值赋给y
块(BLOCK)语句是一种将结构体中的并行描述语句进行组合的方法,它的主要目的是改善并行语句及其结构的可读性,或是利用BLOCK的保护表达式关闭某些信号。
块标号:BLOCK [(块保护表达式)] [IS]接口说明;类属说明;BEGIN并行语句; END BLOCK [块标号];
COMPONENT 元件名 [IS] [GENERIC(类属表)说明;] [PORT (端口名表)说明;] END COMPONENT 元件名;
[标号:] for 循环变量 in 取值范围 generate [声明部分] begin 并行语句; end generate [标号];
取值范围: 表达式 to 表达式 或者 表达式 downto 表达式
(1)过程
参数可以是 in, out, inout 模式
输入参数(in)的默认数据类型是constant
输出参数(out)或者inout参数默认数据类型variable
PROCEDURE procedure_name (mode_parameters) IS [声明部分] BEGIN 顺序语句; END [PROCEDURE ] [procedure_name];
(2)函数
FUNCTION function_name (input_parameters) RETURN data_type IS [声明部分]; BEGIN 顺序语句; RETURN 声明名; END [FUNCTION] [function_name];
函数一般定义在包中(声明及实现)
(3)过程与函数的区别:
顺序语句的特点是执行顺序和书写顺序基本一致 。
(1)进程中的顺序信号赋值语句:
(2)进程中的顺序变量赋值语句:
示例:
示例:
with 语句是不能在process 内的。
(1)无限 loop 。Loop 将无限执行,除非 EXIT 语句存在 。
(2)WHILE LOOP 。条件满足,则循环 。
(3)FOR LOOP。迭代 loop 。
示例:
四位左移:
Return语句是一段子程序结束后,返回主程序的语句。
格式:
return;--只能用于过程,它后面不要有表达式 return 表达式;--只用于函数,它后面必须有表达式,函数结束必须用return语句
示例:
空操作。
格式:
NULL;
示例:
(1)异步复位(清零)
process(clk, reset, a)begin if clk'event and clk = '1' then q <= a + 1;
-- 高位复位 elsif reset = '1' then q <= '0'; end if;end process;
(2)同步复位(清零)
process(clk, reset, a)begin
-- 高位复位
if clk'event and clk = '1' then if reset = '1' then q <= '0' else q <= a + 1; end if;end process;
示例
(1)使用异步reset的8-bit寄存器
-- 使用异步reset的8-bit寄存器 LIBRARY ieee;USE ieee.std_logic_1164.all; ENTITY reg8 IS PORT (D : IN STD_LOGIC_VECTOR(7 DOWNTO 0); Resetn, Clock : IN STD_LOGIC; Q : OUT STD_LOGIC_VECTOR(7 DOWNTO 0) ); END reg8; ARCHITECTURE behavioral OF reg8 IS BEGIN PROCESS ( Resetn, Clock ) BEGIN IF Resetn = '0' THEN Q <= "00000000"; ELSIF rising_edge(Clock) THEN Q <= D; END IF; END PROCESS; END behavioral;`
(2)使用异步reset的N-bit寄存器
-- 使用异步reset的N-bit寄存器 LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY regn IS GENERIC ( N : INTEGER := 16 ); PORT ( D : IN STD_LOGIC_VECTOR(N-1 DOWNTO 0); Resetn, Clock : IN STD_LOGIC; Q : OUT STD_LOGIC_VECTOR(N-1 DOWNTO 0) ); END regn; ARCHITECTURE behavioral OF regn IS BEGIN PROCESS ( Resetn, Clock ) BEGIN IF Resetn = '0' THEN Q <= (OTHERS => '0'); -- 给Q的所有位赋0,方便用于多位信号的赋值操作 ELSIF rising_edge(Clock) THEN Q <= D; END IF; END PROCESS ; END behavioral ;
(1)使用变量的计数器
示例:
(1)数据流描述
(2)4-bit 带进位全加器 (结构化描述)
(3)4-bit 带进位全加器 (行为描述)
library IEEE;use IEEE.std_logic_1164.all;use IEEE.std_logic_unsigned.all;entity adder4_full is port( a : in std_logic_vector(3 downto 0); b : in std_logic_vector(3 downto 0); ci : in std_logic; s : out std_logic_vector(3 downto 0); co : out std_logic; ); end adder4_full;architecture RTL of adder4_full isbegin process(a, b, ci) variable a_t, b_t, c_t, s_t : std_logic_vector(4 downto 0); begin -- & 拼接运算符 a_t:='0'&a; b_t:='0'&b; c_t:="0000"&ci; s_t:=a_t + b_t + c_t; co<=s_t(4); s<=s_t(3 downto 0); end process;end RTL;
在一个进程中,可以有多个语句
需要考虑的问题:
当敏感表中的信号发生变化,此进程将被激活。一旦被激活,在进程中的所有语句都将顺序执行一次。
进程中对信号的任何赋值在进程之外是不可见的,直到进程执行结束,才会更新信号。
如果有多个语句对同一个信号赋值,只有最后一个是可见的,或有效的 。
状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作,完成特定操作的控制中心。
状态机分为摩尔(Moore)型状态机和米莉(Mealy)型状态机。
示例:
(1)单进程的Moore FSM
(2)双进程的Moore FSM
(3)三进程的Moore FSM
示例1:
示例2: