VHDL基本语法
目录
1.VHDL基本结构
- 实体(Entity) :描述所设计的系统的外部接口信号 ,定义电路设计中所有的输入和输出端口;
- 结构体 (Architecture) :描述系统内部的结构和行为;
- 包集合 (Package): 存放各设模块能共享的数据类型 、常数和子程序等 ;
- 配置 (Configuration): 指定实体所对应的结构体;
- 库 (Library): 存放已经编译的实体 、结构体 、包集合和配置。
VHDL的基本设计的基本设计单元结构:程序包说明 、实体说明和结构体说明三部分:
1.1.实体(Entity)
实体描述了设计单元的输入输出接口信号或引脚 ,是设计实体经封装后对外的一个通信界面。
定义方式:
ENTITY 实体名 IS
[ GENERIC( 常数名 :数据类型 :设定值) ]
PORT
( 端口名1: 端口方向 端口类型;
端口名2: 端口方向 端口类型;
.
.
端口名n: 端口方向 端口类 型
);
END [实体名];
注意:实体名由设计者自由命名 ,用来表示被设计电路芯片的名称 , 但是必须与VHDL程序的程序的文件名称相同。 要与文 件 名一 致 。
类属为设计实体与外界通信的静态信息提供通道 ,用来规定端口的大小、实体中子元件的数目和实体的定时特性等。
格 式 :
GENERIC( 常数名 :数据类型 :设定值;
∶
常数名 :数据类型 :设定值 );
例 如:
GENERIC (wide :integer:=32); -- 说明宽度为32
GENERIC (tmp :integer:=1ns); -- 说明延时1 ns
OUT” 和“BUFFER”都可定义输出端口;
注意:若实体内部需要反馈输出信号 ,则输出端口必须被设置为为“BUFFER”, 而不能为能为“OUT”。
- 同方向 、同类型的端口可放在同一个说明语句中。
1.2.结构体 (Architecture)
结构 体定义了设计单元具体的功能,描述了该基本设计单元的行为、 元件和内部的连接关系 .
定义方式:
ARCHITECTURE 结构体名 OF 实体名 IS
[声明语句]
BEGIN
功能描述语句
END [ 结构体名];
提示:
1.声明语句的作用:用于声明该结构体将用到的信号 、数据类型 、常数、子程序和元件等 。 声明的内容是局部的。
2.功能描述语句:具体描述结构体的功能和行为。
- 一 个实体可对应多个结构体 , 每个结构体代表该实体功能的不同实现方案或不同实现方式 。同一时刻只有一个结构体起作用,通过CONFIGURATION决定用哪个结构体进行仿真或综合。
- 在结构体描述中, 具体给出了输入 、 输出信号之间的逻辑关系 。
1.3.库、程序包的调用
方法:
LIBRARY 库名;
USE 库名. 程序包名.项目名;
例子:
LIBRARY IEEE;
USE IEEE.Std_Logic_1164.ALL;--调用此程序包的所有资源其他例子:
LIBRARY IEEE;
USE IEEE.Std_Logic_1164.ALL ;
USE IEEE.Std_Logic_Arith.ALL ;
USE IEEE.Std_Logic_Unsigned.ALL
1.4.VHDL语句
1.4.1.并行语句
在结构体中的执行是同时进行, 执行顺序与书写顺序无关。如下图所示
目标信号名 <= 表达式
注意:目标信号的数据类型与右边表达式一 致。
- 选择信号赋值语句
WITH 选择表达式 SELECT
赋值目标信号 <= 表达式1 WHEN 选择值 1,
表达式2 WHEN 选择值 1,
表达式n WHEN OTHERS;注意:
1.选择值要覆盖所有可能情况 , 若不能一一指定,用OTHERS为其他情况找个出口。
2.选择值必须互斥 ,不能出现条件重复或重叠的情况。
例子:
实现一个4X1多路选择器,当选择信号为00则输出信号为Data0的数据,选择为01输出Data1的信号,依次类推:
程序如下:
-
library ieee;
-
use ieee.std_logic_1164.all;
-
entity mux is
-
port
-
(Data0,Data1,Data2,Data3:IN std_logic_Vector(7 downto 0);
-
Sel : IN std_logic_vector(1 downto 0);
-
Dout: out std_logic_vector(7 downto 0)
-
);
-
end;
-
architecture DataFolw of mux is
-
begin
-
with Sel select
-
Dout<= Data0 WHEN "00",
-
Data1 WHEN "01",
-
Data2 WHEN "10",
-
Data3 WHEN "11",
-
"00000000" WHEN OTHERS;
-
end;
进行仿真测试:
- 条件信号赋值语句
赋值目标信号 <= 表达式1 WHEN 赋值条件1 ELSE
表达式2 WHEN 赋值条件2 ELSE
表达式n WHEN 赋值条件n ELSE
表达式;注意:
1.各赋值语句有优先级的差别 , 按书写顺序从高到低排列;
2.各赋值条件可以重叠。
例子:
实现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
-
"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;
进行仿真测试:
1.4.2.进程语句
进程语句定义顺序语句模块 ,用于将从外部获得的信号值 ,或内部的运算数据向其他的信号进行赋值 。
- 进程本身是并行语句, 但内部是顺序语句 ;
- 进程只有在特定的时刻 ( 敏感信号发生变化) 才会被激活。
语法:
[ 进程标号 :] ] PROCESS ( 敏感信号参数表 )
[声明区 ] ;
BEGIN
顺序语句
END PROCESS [进程标号] ;注意:
1.一 个进程可以有多个敏感信号 , 任一 敏感信号发生变化都会激活进程。
2.声明区的作用:在进程中起作用的局部变量。
注意事项:
1.进程挂起:则执行过程终止。
2.当某个敏感信号的值发生变化时,每个进程语句立即完成进程内顺序语句所定义的功能行为。
3.顺序语句所定义的功能行为的结果可以赋值给信号,并通过信号被其他简称读取或赋值。
在每个上升沿启动一次进程( 执行进程内所有的语句 ) 。
描述方法:
上升沿描述: Clock’ EVENT AND Clock=‘1’
下降沿描述: Clock’ EVENT AND Clock=‘0’
上升沿描述: rising_edge (Clock)
下降沿描述: falling_edge (Clock)
例子1:
把clock设为敏感信号,当clock上升沿时,输出时钟就进行取反一次。
程序如下:
-
library ieee;
-
use ieee.std_logic_1164.all;
-
entity FreDevider is
-
port
-
(Clock: in std_logic;
-
Clkout:out std_logic
-
);
-
end;
-
architecture Behavior of FreDevider is
-
Signal Clk:std_logic;
-
begin
-
process(Clock)
-
begin
-
if rising_edge(Clock) THEN
-
Clk<=NOT Clk;
-
end if;
-
end process;
-
Clkout<=Clk;
-
end;
仿真波形如下:
例子2:
本例子做一个自加器,没遇到一个clock的上升沿,num就自加1,加到3就自动清零,重新开始,循环进行,还有一个复位按钮,只要检测是reset的值为1,num的数值就清零,重新开始计数。
代码如下:
-
library ieee;
-
use ieee.std_logic_1164.all;
-
entity Counter is
-
port
-
(reset: in std_logic; --异步时钟复位信号
-
clock: in std_logic; --时钟信号
-
num :buffer integer range 0 to 3); --设置一个整形变量,范围从0到3
-
end;
-
architecture Behavior of Counter is
-
begin
-
process(reset,clock) --将复位,和时钟作为进程的敏感信号
-
begin
-
if reset='1' THEN
-
num<=0; --当检测到reset=1时,num清零
-
elsif rising_edge(clock) THEN
-
if num=3 THEN
-
num<=0; --如果num=3就,清零
-
else
-
num<=num+1; --否则自加1
-
end if;
-
end if;
-
end process;
-
end;
仿真结果如下:
例子:
ARCHITECTURE Behavior OF state IS
BEGIN
PROCESS -- 敏感信号列表为 空
BEGIN
wait until Clock; -- 等待clock激活进程
IF ( drive=‘1’) THEN
CASE output IS
WHEN s1 => output <= s2;
WHEN s2 => output <= s3;
WHEN s3 => output <= s4;
WHEN s4 => output <= s1;
END CASE;
END IF;
END PROCESS;
END;
- 进程本身是并行语句, 但内部为顺序语句 ;
- 进程在敏感信号发生变化时被激活 ,在使用了敏感表的进程中不能含wait 语句 ;
- 在同一进程中对同一信号多次赋值 , 只有最后一次生 效 ;
- 在不同进程中,不可对同一信号进行赋值;
- 一个进程不可同时对时钟上 、下沿敏感 。
- 进程中的信号赋值是在进程挂起时生效的,而变量赋值是即时生 效。
- 相对于结构体而言, 信号具有全局性 ,是进程间进行并行联系的重要途径 。
- 进程为综合器支持 ,且其建模方式直接影响仿真和综合结果 ,综合后对应于进程的硬件结构对进程中所有可读入信号都是敏感的。
1.5.元件例化语句
- 元件例化引入一种连接关系 , 将预先设计好的实体定义为元件 , 并将此元件与当前设计实体中的端口相连接 , 从而为当前设计实体引入一个新的低一级的设计层次 。
举例:把元件比喻成要插在电路系统板上的芯片,端口比喻成准备接受芯片的插座。
元件例化的方式:
元件定义语句:
Component 元件名
port ( 端口名表);
End component 元件名;元件例化语句:
例化名 : 元件名 port map ( [元件端口名=>]连接端口名 , …);注意:
1.port当中列出对外通信的各端口名。
2.端口的关联方式有两种,第一:名字关联法,port map的语句中位置可以随意,第二:位置关联法,端口名和关联连接符号可以省去,连接端口名的排列方式与所需例化的元件端口定义的端口名顺序相对应。
3.连接端口名:当前系统与准备接入的元件对应端口相连的通信端口。
例子:
设计一个四输入的与非门,如下图所示:
此时我们需要设计一个2输入的与非门,然后通过元件例化这个二输入的与非门,实现四输入与非门的功能。
1.在电脑本地新建两个文件夹,分别用于存放二输入与非门的文件,另一个是实现这个与非门例化实现功能的元件。
在我们电脑本地目录下:D:\QuartusII_Test,新建两个文件夹如下所示:
2.然后再QuartusII新建一个VHDL文件,实现二输入与非门的功能,具体代码如下:
-
library ieee;
-
use ieee.std_logic_1164.all;
-
entity nd2 is
-
port
-
(a,b :in std_logic;
-
c :out std_logic
-
);
-
end;
-
architecture nd2bhv of nd2 is
-
begin
-
c<=a nand b;
-
end;
3.然后保存到D:\QuartusII_Test\nd2中,工程也要命名为:nd2
4.编辑成功后,新建一个仿真波形图,如下功能仿真正确
5.新建一个工程,工程保存到D:\QuartusII_Test\ord41 ,然后命名为ord41
6.新建一个VHDL文件,使用二输入与非门的元件例化,代码编辑如下:
-
library ieee;
-
use ieee.std_logic_1164.all;
-
entity ord41 is
-
port
-
(a1,b1,c1,d1 :in std_logic;
-
z1 :out std_logic);
-
end ord41;
-
architecture ord41bhv of ord41 is
-
component nd2
-
port(a,b:in std_logic;
-
c :out std_logic);
-
end component;
-
signal x,y:std_logic;
-
begin
-
u1:nd2 port map(a1,b1,x);
-
u2:nd2 port map(a=>c1,c=>y,b=>d1);
-
u3:nd2 port map(x,y,c=>z1);
-
end ord41bhv;
附录:对上面例子的说明
7.保存,文件名为ord41
8.这一步很重要,如果没有这一步编译将会报错!!!
添加库刚刚nd2的库到这个工程。
点击assignment下拉菜单中的settings选项,并选中user libraries选项,则下图所示:
点击library name 后面的“…” 按钮,找到nd2文件夹,点击Add, 如下图所示:
9.点击编译按钮,对ord41工程进行编译,如果设置好第8步,而且语法没有错的话不会报错。
10.编译成功后,然后新建仿真图进行仿真,仿真结果如下: