第四章 VHDL的主要描述语句
4.1 VHDL顺序语句
4.2 VHDL并行语句
用VHDL语言进行设计时,按描述语句的执行顺序进行分类,可将VHDL语句分为顺序执行语句(Sequential)和并行执行语句(Parallel)。
4.1 VHDL顺序语句
顺序语句是指完全按照程序中书写的顺序执行各语句,并且在结构层次中前面的语句执行结果会直接影响后面各语句的执行结果。顺序描述语句只能出现在进程或子程序中,用来定义进程或子程序的算法。顺序语句可以用来进行算术运算、逻辑运算、信号和变量的赋值、子程序调用等,还可以进行条件控制和迭代。
注意,这里的顺序是从仿真软件的运行和顺应VHDL语法的编程逻辑思路而言的,其相应的硬件逻辑工作方式未必如此。应该注意区分VHDL语言的软件行为与描述综合后的硬件行为的差异。
VHDL顺序语句主要包括:
·变量赋值语句(Variable Evaluate)
·信号赋值语句(Signal Evaluate)
·WAIT语句
·IF 语句
·CASE 语句
·LOOP 语句
·NEXT 语句
·EXIT 语句
·RETURN 语句
·NULL 语句
·过程调用语句(Procedure Call)
·断言语句(Assert)
·REPORT 语句
4.1.1 变量赋值语句
变量赋值语句语法格式为:
变量赋值目标 := 赋值表达式
例:
VARIABLE s:BIT := ‘0’;
PROCESS(s)
VARIABLE count:INTEGER := ‘0’ --变量说明
BEGIN
count := s+1 --变量赋值
END PROCESS;
4.1.2 信号赋值语句
在VHDL语言中,用符号“<=”为信号赋值。
信号赋值语句的规范书写格式如下:
目的信号量 <= [TRANSPORT][INERTIAL]信号变量表达式;
其中[TRANSPORT]表示传输延迟,[INERTIAL]表示惯性延迟。要求“<=”两边的信号变量类型和位长度应该一致。
例: s <=TRANSPORT t AFTER 10ns; --传输延迟
d <= INERTIAL 2 AFTER 3ns, 1 AFTER 8ns; --惯性延迟
例:s <= a NOR(b AND c); --信号赋值由敏感信号引起
3个敏感量a,b,c中任何一个发生变化,该语句都将被执行。
4.1.3 WAIT语句
WAIT语句在进程中起到与敏感信号一样重要的作用,敏感信号触发进程的执行,WAIT语句同步进程的执行,同步条件由WAIT语句指明。进程在仿真运行中处于执行或挂起两种状态之一。当进程执行到等待语句时,就将被挂起并设置好再次执行的条件。WAIT语句可以设置4种不同的条件:无限等待、时间到、条件满足以及敏感信号量变化。这几类WAIT语句可以混合使用。现分别介绍如下:
(1)WAIT --无限等待语句
这种形式的WAIT语句在关键字“WAIT”后面不带任何信息,是无限等待的情况。
(2)WAIT ON 信号表 --敏感信号等待语句
这种形式的WAIT语句使进程暂停,直到敏感信号表中某个信号值发生变化。WAIT ON语句后面跟着的信号表,在敏感信号表中列出等待语句的敏感信号。当进程处于等待状态时,其中敏感信号发生任何变化都将结束挂起,再次启动进程。
例[A]
PROCESS
BEGIN
y <= a AND b;
WAIT ON a,b;--a,b为敏感信号,由WAIT列出
END PROCESS;
例[B]
PROCESS(a,b)--a,b为敏感信号,由PROCESS列出
BEGIN
y <= a AND b;
END PROCESS;
在例[A]中执行所有语句后,进程将在WAIT语句处被挂起,直到a或b中任何一个信号发生变化,进程才重新开始。例[A]与例[B]是等价的。
需要注意的是,在使用WAIT ON语句的进程中,敏感信号量应写在进程中的WAIT ON语句后面;而在不使用WAIT ON语句的进程中,敏感信号量应在开头的关键词PROCESS后面的敏感信号表中列出。VHDL规定,已列出敏感信号表的进程不能使用任何形式的WAIT语句。
(3)WAIT UNTIL 条件 --条件等待语句
这种形式的WAIT语句使进程暂停,直到预期的条件为真。WAIT UNTIL后面跟的是布尔表达式,在布尔表达式中隐式地建立一个敏感信号量表,当表中任何一个信号量发生变化时,就立即对表达式进行一次测评。如果其结果使表达式返回一个“真”值,则进程脱离挂起状态,继续执行下面的语句。即WAIT UNTIL语句需满足以下条件:
·在条件表达式中所含的信号发生了变化;
·此信号改变后,且满足WAIT UNTIL语句中表达式的条件。
这两个条件缺一不可,且必须按照上述顺序来完成。
WAIT UNTIL语句有以下三种表达方式:
WAIT UNTIL 信号 = VALUE;
WAIT UNTIL 信号’EVENT AND信号 = VALUE;
WAIT UNTIL 信号’STABLE AND信号 = VALUE;
例如:
WAIT UNTIL clock = “1”;
WAIT UNTIL rising_edge(clk);
WAIT UNTIL clk =‘1’AND clk’ EVENT;
WAIT UNTIL NOT clk’ STABLE AND clk= “1”;
一般的,在一个进程中使用了WAIT语句后,综合器会综合产生时序逻辑电路。时序逻辑电路的运行依赖WAIT UNTIL表达式的条件,同时还具有数据存储的功能。
(4)WAIT FOR 时间表达式 --超时等待语句
例如:WAIT FOR 40 ns;
在该语句中,时间表达式为常数40ns,当进程执行到该语句时,将等待40ns,经过40ns之后,进程执行WAIT FOR的后继语句。
例如:WAIT FOR(a*(b+c));
在此语句中,(a*(b+c))为时间表达式,WAIT FOR语句在执行时,首先计算表达式的值,然后将计算结果返回作为该语句的等待时间。
4.1.4 IF语句
在VHDL语言中,IF语句的作用是根据指定的条件来确定语句的执行顺序。IF语句可用于选择器、比较器、编码器、译码器、状态机等的设计,是VHDL语言中最常用的语句之一。IF语句按其书写格式可分为以下3种。
1.门闩控制语句
这类语句书写格式为:
IF 条件 THEN
顺序语句
END IF;
当程序执行到这种门闩控制型IF语句时,首先判断语句中所指定的条件是否成立。如果条件成立,则程序继续执行IF语句中所含的顺序处理语句;如果条件不成立,程序将跳过IF语句所包含的顺序处理语句,而向下执行IF的后继语句。
例: 利用IF语句引入D触发器
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY dff IS
PORT(clk,d:IN STD_LOGIC;
q:OUT STD_LOGIC);
END dff;
ARCHITECTURE rtl OF dff IS
BEGIN
PROCESS (clk)
BEGIN
IF (clk’EVENT AND clk=’1’) THEN
q <= d;
END IF;
END PROCESS;
END rtl;
2.二选一控制语句
这种语句的书写格式为:
TF 条件 THEN
顺序语句
ELSE
顺序语句
END IF;
当IF条件成立时,程序执行THEN和ELSE之间的顺序语句部分;当IF语句的条件得不到满足时,程序执行ELSE和END IF之间的顺序处理语句。即依据IF所指定的条件是否满足,程序可以进行两条不同的执行路径。
例:二选一电路结构体的描述
ARCHITECTURE rtl OF mux2 IS
BEGIN
PROCESS (a,b,s)
BEGIN
IF (s =’1’) THEN
c <= a;
ELSE
c <= b;
END IF;
END PROCESS;
END rtl;
3.多选择控制语句
这种语句的书写格式为:
IF 条件 THEN
顺序语句
ELSIF
顺序语句
ELSIF
顺序语句
┇
ELSE
顺序语句
END IF;
这种多选择控制的IF语句,实际上就是条件嵌套。它设置了多个条件,当满足所设置的多个条件之一时,就执行该条件后的顺序处理语句。当所有设置的条件都不满足时,程序执行ELSE和END IF之间的顺序处理语句。
例: 利用多选控制语句设计的四选一多路选择器
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY mux4 IS
PORT(input:IN STD_LOGIC_VECTOR (3 DOWNTO 0);
sel:IN STD_LOGIC_VECTOR (1 DOWNTO 0);
y:OUT STD_LOGIC);
END mux4;
ARCHITECTURE rtl OF mux4 IS
BEGIN
PROCESS (input,sel)
BEGIN
IF (sel=“00”) THEN
y<= input(0);
ELSIF(sel=“01”)THEN
y<= input(1);
ELSIF(sel=“10”)THEN
y<= input(2);
ELSE
y<= input(3);
END IF;
END PROCESS;
END rtl;
4.1.5 CASE语句
CASE语句根据满足的条件直接选择多项顺序语句中的一项执行,它常用来描述总线行为、编码器、译码器等的结构。
CASE语句的结构为:
CASE 表达式 IS
WHEN 条件选择值 => 顺序语句,
┇
WHEN 条件选择值 => 顺序语句,
END CASE;
其中WHEN条件选择值可以有四种表达方式;
(1)单个普通数值,形如WHEN 选择值 => 顺序语句;
(2)并列数值,形如WHEN 值/值/值 => 顺序语句;
(3)数值选择范围,形如WHEN 值TO值 => 顺序语句;
(4)WHEN OTHERS => 顺序语句;
当执行到CASE语句时,首先计算CASE和IS之间的表达式的值,然后根据条件语句中与之相同的选择值,执行对应的顺序语句,最后结束CASE语句。
使用CASE语句需注意以下几点:
·CASE语句中每一条语句的选择值只能出现一次,即不能有相同选择值的条件语句出现。
·CASE语句执行中必须选中,且只能选中所列条件语句中的一条,即CASE语句至少包含一个条件语句。
·除非所有条件语句中的选择值能完全覆盖CASE语句中表达式的取值,否则最末一个条件语句中的选择必须用“OTHERS”表示,它代表已给出的所有条件语句中未能列出的其他可能的取值。关键词OTHERS只能出现一次,且只能作为最后一种条件取值。使用OTHERS是为了使条件语句中的所有选择值能覆盖表达式的所有取值,以免综合过程中插入不必要的锁存器。这一点对于定义为STD_LOGIC和STD_LOGIC_VECTOR数据类型的值尤为重要,因为这些数据对象的取值除了1、0之外,还可能出现输入高阻态Z,不定态X等取值。
例[1] CASE语句使用
CASE command IS
WHEN “00”=> c <= a; --适合4选1数据选择器
WHEN “01”=> c <= b;
WHEN “10”=> c <= e;
WHEN “11”=> c <= f;
WHEN OTHERS => NULL; --无效
END CASE;
例[2] CASE语句使用
CASE sel IS
WHEN 1TO 9 => c <= 1;
WHEN 11/12 => c <= 2;
WHEN OTHERS => c <= 3;
END CASE;
在例[2]中,第一个WHEN语句的意思是当sel 的值是从1到9 中任意一个数值时,信号c的值取1;第二个WHEN语句的意思是当sel 的值为11或12两者之一时,信号 c 的取值为2;第三个WHEN语句的意思是当sel 的值不为前面两种情况时,信号c 的取值为3。
例[3] 3-8译码器。
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY decoder3_8 IS
PORT(a,b,c,g1,g2a,g2b:IN STD_LOGIC;
y:OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
END decoder3_8;
ARCHITECTURE rtl OF decoder3_8 IS
SIGNAL indata:STD_LOGIC_VECTOR (2 DOWNTO 0);--说明
BEGIN
indata <= c & b & a;--合语句
PROCESS(indata,g1,g2a,g2b)
BEGIN
IF(g1=‘1’AND g2a=‘0’ AND g2b=‘0’)THEN
CASE indata IS
WHEN “000”=> y <=“11111110”;
WHEN “001”=> y <=“11111101”;
WHEN “010”=> y <=“11111011”;
WHEN “011”=> y <=“11110111”;
WHEN “100”=> y <=“11101111”;
WHEN “101”=> y <=“11011111”;
WHEN “110”=> y <=“10111111”;
WHEN “111”=> y <=“01111111”;
WHEN OTHERS => y <= “XXXXXXXX”; - -X:不定
END CASE;
ELSE --指不满足g1=‘1’AND g2a=‘0’ AND g2b=‘0’情况
y <=“11111111”;
END IF;
END PROCESS;
END rtl;
与IF语句相比,CASE语句组的程序语句是没有先后顺序的,所有表达式的值都并行处理。IF语句是有序的,先处理最起始、最优先的条件,后处理次优先的条件。
4.1.6 LOOP语句
LOOP语句就是循环语句,它可以使包含的一组顺序语句被循环执行,其执行的次数受迭代算法控制。在VHDL中常用来描述迭代电路的行为。
1.单个LOOP语句
单个LOOP语句的书写格式如下:
[标号:] LOOP
顺序语句
END LOOP[标号];
这种循环语句需引入其他控制语句(如EXIT)后才能确定,否则为无限循环。其中的标号是可选的。
例如:
loop1:LOOP
WAIT UNTIL clk=‘1’;
q <= d AFTER 2 ns;
END LOOP loop1;
2.FOR_LOOP语句
该语句语法格式为:
[标号:] FOR 循环变量 IN 离散范围 LOOP
顺序处理语句
END LOOP[标号];
例: 8位奇偶校验电路
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY parity_check IS
PORT(a:IN STD_LOGIC_VECTOR (7 DOWNTO 0);
y:OUT STD_LOGIC);
END parity_check ;
ARCHITECTURE rtl OF parity_check IS
BEGIN
PROCESS(a)
VARIABLE tmp:STD_LOGIC
BEGIN
tmp:=‘0’;
FOR i IN 0 TO 7 LOOP
tmp:= tmp XOR a(i);
END LOOP;
y <= tmp; - -y=1,a为奇数个‘1’。y=0, a为偶数个‘1’。
END PROCESS;
END rtl;
3.WHILE_LOOP语句
这种语句的书写格式为:
[标号:] WHILE 条件 LOOP
顺序处理语句
END LOOP[标号];
在该LOOP语句中,没有给出循环次数的范围,而是给出了循环执行顺序语句的条件;没有自动递增循环变量的功能,而是在顺序处理语句中增加了一条循环次数计算语句,用于循环语句的控制。循环控制条件为布尔表达式,当条件为“真”时,则进行循环,如果条件为“假”,则结束循环。
例:8位奇偶校验电路的WHILE_LOOP设计形式
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY parity_check IS
PORT(a:IN STD_LOGIC_VECTOR (7 DOWNTO 0);
y:OUT STD_LOGIC);
END parity_check ;
ARCHITECTURE behav OF parity_check IS
BEGIN
PROCESS(a)
VARIABLE tmp:STD_LOGIC
BEGIN
tmp := ‘0’;
i := 0;
WHILE (i < 8)LOOP
tmp := tmp XOR a(i);
i := i+1; --循环次数计算语句
END LOOP;
y <= tmp;
END PROCESS;
END behav;
4.1.7 NEXT语句
NEXT语句的书写格式为:
NEXT[标号][WHEN 条件]
该语句主要用于LOOP语句内部的循环控制。当NEXT语句后不跟[标号],NEXT语句作用于当前最内层循环,即从LOOP语句的起始位置进入下一个循环。若NEXT语句不跟[WHEN 条件],NEXT语句立即无条件跳出循环。
例:NEXT语句应用举例
┇
WHILE data >1 LOOP
data := data+1;
NEXT WHEN data=3 - -条件成立而无标号,跳出循环
data := data* data;
END LOOP;
N1:FOR i IN 10 DOWNTO 1 LOOP
N2:FOR j IN 0 TO i LOOP
NEXT N1 WHEN i=j; - -条件成立,跳到N1处
matrix(i,j):= j*i+1; - -条件不成立,继续内层循环N2
END LOOP N2;
END LOOP N1;
4.1.8 EXIT语句
EXIT语句的书写格式为:
EXIT[LOOP标号][WHEN条件];
EXIT语句也是用来控制LOOP的内部循环,与NEXT语句不同的是EXIT语句跳向LOOP终点,结束LOOP语句;而NEXT语句是跳向LOOP语句的起始点,结束本次循环,开始下一次循环。当EXIT语句中含有标号时,表明跳到标号处继续执行。含[WHEN条件]时,如果条件为“真”,跳出LOOP语句;如果条件为“假”,则继续执行LOOP循环。
EXIT语句不含标号和条件时,表明无条件结束LOOP语句的执行,因此,它为程序需要处理保护、出错和警告状态,提供了一种快捷、简便的调试方法。
例[]两个元素位矢量a、b进行比较,当发现a与b不同时,跳出循环比较程序并报告比较结果。
SIGNAL a,b:STD_LOGIC_VECTOR (0 TO 1);
SIGNAL a_less_than_b:BOOLEAN;
┇
a_less_than_b <= FALSE;
FOR i IN 1TO 0 LOOP
IF(a(i)=‘1’AND b(i)=‘0’)THEN - - a1a0 与 b1b0比较大小
a_less_than_b <= FALSE;
EXIT; --无条件跳出循环
ELSEIF(a(i)=‘0’AND b(i)=‘1’)THEN
a_less_than_b <= TRUE;
EXIT;
ELSE
NULL
END IF;
END LOOP;
4.1.9 返回语句 RETURN
RETURN语句是一段子程序结束后,返回主程序的控制语句。它只能用于函数与过程体内,并用来结束当前最内层函数或过程体的执行。
RETURN语句的书写格式为:
RETURN;
RETURN 表达式;
例:在函数体中使用RETURN语句
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY example IS
PORT(a,b:IN INTEGER;
y:OUT INTEGER);
END example ;
ARCHITECTURE rtl OF example IS
BEGIN
PROCESS(a,b) --进程语句
FUNCTION maximum --函数
(a,b:INTEGER)RETURN INTEGER IS --return integer
VARIABLE tmp:INTEGER;
BEGIN
IF(a > b)THEN
tmp := a;
ELSE
tmp := b;
END IF;
END maximum;
BEGIN
y <= maximum(a,b); --调用函数
END PROCESS;
END rtl;
上例是一个对两个输入整数取最大值的功能描述,在结构体的进程中定义了一个取最大值的函数。在函数体中正是通过RETURN语句将比较得到的最大值返回的,并结束该函数体的执行。
4.1.10 NULL语句
NULL语句是空操作语句,不完成任何操作,执行NULL语句只是让程序运行流程走到下一个语句。
NULL语句的书写格式为:
NULL;
NULL语句常用于CASE语句中,利用NULL来表示所余的不用的条件下的操作行为,以满足CASE语句对条件值全部列举的要求。
例:采用NULL语句的四选一数据选择器。
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY mux4 IS
PORT(d0 :IN STD_LOGIC_VECTOR (7 DOWNTO 1);
d1 :IN STD_LOGIC_VECTOR (7 DOWNTO 1);
d2 :IN STD_LOGIC_VECTOR (7 DOWNTO 1);
d3 :IN STD_LOGIC_VECTOR (7 DOWNTO 1);
s0 :IN STD_LOGIC;
s1 :IN STD_LOGIC;
y :OUT STD_LOGIC_VECTOR (7 DOWNTO 1) );
END mux4 ;
ARCHITECTURE behave OF mux4 IS
BEGIN
lable:PROCESS(d0,d1,d2,d3,s0,s1)
VARIABLE tmp:INTEGER;
BEGIN
tmp := 0;
IF(s0=‘1’)THEN
tmp := tmp+1;
END IF;
IF(s1=‘1’)THEN
tmp := tmp+2;
END IF;
CASE tmp IS
WHEN 0 => y <= d0;
WHEN 1 => y <= d1;
WHEN 2 => y <= d2;
WHEN 3 => y <= d3;
WHEN OTHERS => NULL;--为了满足CASE语句全部选择项,空语句
END CASE;
END PROCESS;
END behave;
上例是通过对用于选通8位总线的四选一多路选择器进行功能描述,具体说明NULL语句的使用。
4.1.11 过程调用语句(Procedure Call)
与其他高级程序设计语言相似,VHDL提供了子程序的概念。其中在进程、函数和过程中,可以使用过程调用语句,此时它是一种顺序语句。一个过程被调用时将去执行它的过程体。过程调用语句的书写格式为:
过程名(实参表);
例:
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
USE IEEE. STD_LOGIC_UNSIGNED.ALL;
ENTITY max IS
PORT(in1:IN STD_LOGIC_VECTOR (7 DOWNTO 0);
in2:IN STD_LOGIC_VECTOR (7 DOWNTO 0);
in3:IN STD_LOGIC_VECTOR (7 DOWNTO 0);
q:OUT STD_LOGIC_VECTOR (7 DOWNTO 0) );
END max ;
ARCHITECTURE rtl OF max IS
PROCEDURE maximum(a,b:IN STD_LOGIC_VECTOR;
c:OUT STD_LOGIC_VECTOR)IS
VARIABLE temp:STD_LOGIC_VECTOR(a’RANGE);
BEGIN
IF(a > b)THEN
temp := a;
ELSE
temp := b;
END IF;
c := temp;
END maximum;
BEGIN
PROCESS(in1,in2,in3)
VARIABLE tmp1,tmp2:STD_LOGIC_VECTOR (7 DOWNTO 0) ;
BEGIN
maximum(in1,in2,tmp1); - -过程调用
maximum(tmp1,in3,tmp2);
q <= tmp2;
END PROCESS;
END rtl;
上例是一个取三个输入位矢量最大值的功能描述,它在结构体中的进程语句中使用了两个过程调用语句。
4.1.12断言语句(Assert)
断言语句分为顺序断言语句和并行断言语句,顺序断言语句主要用于进程、函数和过程仿真、调试中的人机对话,它可以给出一个文字串作为警告和错误信息。断言语句的书写格式如下:
ASSERT 条件 [REPORT 报告信息] [SEVERITY 出错级别];
在执行过程中,断言语句对条件(布尔表达式)的真假进行判断,如果条件为“TURE”,则向下执行另外一条语句;如果条件为“FALSE”,则输出错误信息和错误严重程度的级别。在REPORT后面跟着的是设计者写的字符串,通常是说明错误的原因,字符串要用双引号括起来。SEVERITY后面跟着的是错误严重程度的级别,他们分别是:
·NOTE(注意)
·WARNING(警告)
·ERROR(错误)
·FAILURE(失败)
若REPORT子句缺省,则默认消息为“Assertion violation”;若SEVERITY子句缺省,则出错级别的默认值为“ERROR”。
例: RS触发器的VHDL描述中断言语句的使用
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY rsff IS
PORT(s :IN BIT;
r :IN BIT;
q :OUT BIT;
qb :OUT BIT);
END rsff;
ARCHITECTURE rtl OF rsff IS
BEGIN
PROCESS(s,r)
VARIABLE last_state :BIT;
BEGIN
ASSERT(NOT(s =‘1’AND r =‘1’))
REPORT “Both s and r equal to‘1’.”
SEVERITY ERROR;
IF(s =‘0’AND r =‘0’)THEN
last_state := last_state;
ELSIF(s =‘0’AND r =‘1’)THEN
last_state := 0;
ELSE
last_state := 1;
END IF;
q <= last_state;
qb <= not(last_state);
END PROCESS;
END rtl;
上例中,如果 r 和 s 都为‘1’时,表示一种不定状态。在进程中先是设定了一条断言语句,目的是:当判断 r 和 s 都为‘1’时,输出终端将显示字符串“Both s and r equal to‘1’.”,同时可能终止模拟过程,并显示错误的严重程度。接下来用IF语句判别触发器的其他三种情况,最后将值送到触发器的两个输出端口上。
4.1.13 REPORT 语句
REPORT语句不增加硬件任何功能,但提供顺序断言语句的短格式,在仿真时使用REPORT语句可以提高程序的可读性。
REPORT语句的书写格式为:
REPORT 输出信息 [SEVERITY 出错级别];
例: RS触发器的VHDL描述中REPORT语句的使用 (本例中,用REPORT语句代替上例进程中的断言语句。)
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY rsff IS
PORT(s :IN BIT;
r :IN BIT;
q :OUT BIT;
qb :OUT BIT);
END rsff;
ARCHITECTURE rtl OF rsff IS
BEGIN
PROCESS(s,r)
VARIABLE last_state :BIT;
BEGIN
IF(s =‘1’AND r =‘1’)THEN
REPORT “Both s and r equal to‘1’.”;
ELSIF (s =‘0’AND r =‘0’)THEN
last_state:= last_state;
ELSIF (s =‘0’AND r =‘1’)THEN
last_state := 0;
ELSE
last_state := 1;
END IF;
q <= last_state;
qb <= not(last_state);
END PROCESS;
END rtl;
4.2 VHDL并行语句
在VHDL中,并行语句在结构体中的执行是同时并发执行的,其书写次序与其执行顺序并无关联,并行语句的执行顺序是由他们的触发事件来决定的。
我们知道,实际的硬件系统中很多操作都是并发的,因此在对系统进行模拟时就要把这些并发性体现出来,并行语句正是用来表示这种并发行为的。
在结构体语句中,并行语句的位置是:
ARCHITECTURE 结构体名 OF 实体名 IS
说明语句
BEGIN
并行语句
END 结构体名;
其中并行语句主要有以下几种:
·PROCESS --进程语句
·BLOCK --块语句
·CONCURRENT SIGNAL ASSIGNMENT --并行信号代入语句
·CONDITIONAL SIGNAL ASSIGNMENT - -条件信号代入语句
·SELECTIVE SIGNAL ASSIGNMENT - -选择信号代入语句
·CONCURRENT PROCEDURE CALL --并行过程调用语句
·ASSERT - -并行断言语句
·GENERIC - -参数传递语句
·COMPONENT_INSTANT --元件例化语句
·GENERATE --生成语句
并行描述语句语句可以是结构性的,也可以是行为性的。下面对这些语句的应用加以介绍。
4.2.1 进程语句(PROCESS)
进程语句是最主要的并行语句,它在VHDL程序设计中使用频率最高,也是最能体现硬件描述语言特点的一条语句。进程语句的内部是是顺序语句,而进程语句本身是一种并行语句。进程语句的综合是比较复杂的,主要涉及这样一些问题:综合后的进程是用组合逻辑电路还是用时序逻辑电路来实现?进程中的对象是否有必要用寄存器、触发器、锁存器或是RAM等存储器件来实现。
进程语句结构中至少需要一个敏感信号量,否则除了初始化阶段,进程永远不会被再次激活。这个敏感量一般是一个同步控制信号,同步控制信号用在同步语句中,同步语句可以是敏感信号表、WAIT UNTIL语句或是WAIT ON语句。一般来说,只有一个同步点或者是具有多个同步点但都使用完全相同的同步控制信号的进程不需要“记忆”在哪一个同步点上被挂起时,不会形成存储器。如下例所示:
--综合后不需要存储器的VHDL进程
label1:PROCESS(a,b,c)
┇
BEGIN
┇ --其中没有其他同步描述
AND PROCESS label1;
--综合后需要存储器的VHDL进程
label2:PROCESS
┇
BEGIN
WAIT UNTIL clk’EVENT AND clk=‘1’;
s <=‘0’;
WAIT UNTIL clk’EVENT AND clk=‘1’;
s <=‘1’;
END PROCESS label2;
--不会形成存储器的变量
label3:PROCESS(a,b,c)
VARIABLE var:BIT;
BEGIN
var := a XOR b;
s <= var AND c;
END PROCESS label3;
--需要存储器的变量
label4:PROCESS
TYPE state_table IS (stop,go);
VARIABLE state:table_ state;
BEGIN
WAIT UNTIL clk’EVENT AND clk=‘1’;
CASE state IS - - state在赋值之前先被读访问
WHEN stop => state := go;
WHEN go => state := stop;- -这两个语句是并发关系
END CASE;
AND PROCESS label4;
--综合为触发器的进程
label5:PROCESS
BEGIN
WAIT UNTIL clk’EVENT AND clk=‘1’;
q <= d;
END PROCESS label5;
4.2.2 块语句(BLOCK)
块(BLOCK)语句可以看作是结构体中的子模块,块语句把许多并行语句组合在一起形成一个子模块,而它本身也是一个并行语句。
块语句的基本结构如下:
[块标号:] BLOCK [保护表达式]
[类属子句 [类属接口表;]];
[端口子句 [端口接口表;]];
[块说明部分]
BEGIN
<并行语句1>
<并行语句2>
┇
END BLOCK [块标号];
例: 利用块语句描述的全加器
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY add IS
PORT(A:IN STD_LOGIC;
B:IN STD_LOGIC;
Cin:IN STD_LOGIC;
Co:OUT STD_LOGIC;
S:OUT STD_LOGIC);
END add;
ARCHITECTURE dataflow OF add IS
BEGIN
ex : BLOCK
PORT(a_A:IN STD_LOGIC;
a_B:IN STD_LOGIC;
a_Cin:IN STD_LOGIC;
a_Co:OUT STD_LOGIC;
a_S:OUT STD_LOGIC);
PORT MAP(a_A=>A,a_B=>B,a_Cin=> Cin,
a_Co=> Co,a_S=>S);
SIGNAL tmp1,tmp2:STD_LOGIC;
BEGIN
label1:PROCESS(a_A,a_B)
BEGIN
tmp1<= a_A XOR a_B;
END PROCESS label1;
label2:PROCESS(tmp1,a_Cin)
BEGIN
tmp2<= tmp1AND a_Cin ;
END PROCESS label2;
label3:PROCESS(tmp1,a_Cin)
BEGIN
a_S <= tmp1XOR a_Cin ;
END PROCESS label3;
label4:PROCESS(a_A,a_B,tmp2)
BEGIN
a_Co <= tmp2 OR(a_A AND a_B);
END PROCESS label4;
END BLOCK ex;
END dataflow;
在上面的例子中,结构体内含有4个进程语句,这4个进程语句是并行关系,共同形成了一个块语句。
在实际应用中,一个块语句中又可以包含多个子块语句,这样循环嵌套以形成一个大规模的硬件电路。
4.2.3 并行信号代入语句
信号代入语句有两种:一种是在结构体中的进程内使用,此时它作为一种顺序语句出现;另一种是在结构体的进程之外使用,此时它是一种并行语句,因此称之为并行信号代入语句。
并行信号代入语句的语法格式为:
信号量 <= 敏感信号量表达式;
需要注意的是,一条信号代入语句与一个信号代入的进程语句是等价的,我们可以把一条信号代入语句改写成一个信号代入的进程语句。
例:
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY and_gat IS
PORT(a:IN STD_LOGIC;
b:IN STD_LOGIC;
y:OUT STD_LOGIC);
END and_gat;
ARCHITECTURE behave OF and_gat IS
BEGIN
y <= a AND b; --并行信号代入语句(在结构体进程之外)
AND behave;
本例是一个2输入与门的VHDL描述,在结构体中使用了并行信号代入语句。下面是2输入与门的另一种VHDL描述,在描述的结构体中采用了与上述并行信号代入语句等价的进程语句。
例:
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY and_gat IS
PORT(a:IN STD_LOGIC;
b:IN STD_LOGIC;
y:OUT STD_LOGIC);
END and_gat;
ARCHITECTURE behave OF and_gat IS
BEGIN
PROCESS (a,b)
BEGIN
y <= a AND b; --进程语句( 顺序语句)
END PROCESS;
AND behave;
通过对上述两个例子的分析可见:从并行信号代入语句描述来看,当代入符号“<=”右边的值发生任何变化时,信号代入语句的操作立即执行,将信号代入符号“<=”右边的表达式代入给左边的信号量;从进程语句的描述来看,当进程敏感信号表中的敏感信号量发生变化时,进程将被启动,顺序信号代入语句将被执行以完成信号的代入操作。
在VHDL中提供了三种并行信号代入语句:
·并发信号代入语句
·条件信号代入语句
·选择信号代入语句
(1) 并发信号代入语句
信号代入语句在进程内部执行时,它是一种顺序语句;信号代入语句在结构体的进程之外出现时,它作为并发语句的形式出现。作为并发信号代入语句,在结构体中他们是并行执行的,他们的执行顺序与书写无关。
并发信号代入语句是靠事件驱动的。对于并发信号代入语句来说,只有代入符号“<=”右边的对象有事件发生时才会执行该语句。
在实际设计中,并发信号代入语句常用来进行加法器、乘法器、除法器和比较器等多种逻辑电路的描述。下面是一个用VHDL并发语句描述的全加器的例子。
例:
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY add IS
PORT(A:IN STD_LOGIC;
B:IN STD_LOGIC;
Cin:IN STD_LOGIC;
Co:OUT STD_LOGIC;
S:OUT STD_LOGIC);
END add;
ARCHITECTURE dataflow OF add IS
SIGNAL tmp1,tmp2:STD_LOGIC;
BEGIN
tmp1 <= A XOR B;
tmp2 <= tmp1 AND Cin; --4条并发信号代入语句
S <= tmp1 XOR Cin;
Co <= tmp2 OR(A AND B);
AND dataflow;
在上例的结构体中有4条并发信号代入语句,他们的执行顺序与书写顺序是无关的,因此上面的4条并发信号代入语句可以任意颠倒书写顺序,不会对执行结果产生任何影响。上面提到的并发信号代入语句是事件驱动的,例如:
tmp2 <= tmp1 AND Cin;
S <= tmp1 XOR Cin;
两条语句,只要tmp1 和 Cin中的值有一个发生变化,即有事件发生,那么这两条语句就会立即并发执行。
(2)条件信号代入语句
条件信号代入语句也是一种并发描述语句,它是一种根据不同条件将不同的表达式代入目的信号的语句。条件信号代入语句的书写格式为:
目的信号 <= 表达式1 WHEN 条件1 ELSE
表达式2 WHEN 条件2 ELSE
表达式2 WHEN 条件3 ELSE
┇
表达式n-1 WHEN 条件 ELSE
表达式;
条件信号代入语句执行时要先进行条件判断,如果条件满足,就将条件前面的那个表达式的值代入目的信号;如果不满足条件,就去判断下一个条件;最后一个表达式没有条件,也就是说在前面的条件都不满足时,就将该表达式的值代入目的信号。
下面的例子是用条件信号代入语句来描述的七段显示译码器
例: 采用条件代入语句描述的七段显示译码器
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY se7 IS
PORT(input:IN STD_LOGIC_VECTOR (3 DOWNTO 0);
output:OUT STD_LOGIC_VECTOR (6 DOWNTO 0));
END se7;
ARCHITECTURE rtl OF se7 IS
BEGIN
output <=(‘0’,‘1’,‘1’,‘1’,‘1’,‘1’,‘1’) WHEN input =“0000”ELSE
(‘0’,‘0’,‘0’,‘0’,‘1’,‘1’,‘0’)WHEN input =“0001”ELSE
(‘1’,‘0’,‘1’,‘1’,‘0’,‘1’,‘1’)WHEN input =“0010”ELSE
(‘1’,‘0’,‘0’,‘1’,‘1’,‘1’,‘1’)WHEN input =“0011”ELSE
(‘1’,‘1’,‘0’,‘0’,‘1’,‘1’,‘0’)WHEN input =“0100”ELSE
(‘1’,‘1’,‘0’,‘1’,‘1’,‘0’,‘1’)WHEN input =“0101”ELSE
(‘1’,‘1’,‘1’,‘1’,‘1’,‘0’,‘1’)WHEN input =“0110”ELSE
(‘0’,‘0’,‘0’,‘0’,‘1’,‘1’,‘1’)WHEN input =“0111”ELSE
(‘1’,‘1’,‘1’,‘1’,‘1’,‘1’,‘1’)WHEN input =“1000”ELSE
(‘1’,‘1’,‘0’,‘1’,‘1’,‘1’,‘1’)WHEN input =“1001”ELSE
(‘1’,‘1’,‘1’,‘0’,‘1’,‘1’,‘1’)WHEN input =“1010”ELSE
(‘1’,‘1’,‘1’,‘1’,‘1’,‘0’,‘0’)WHEN input =“1011”ELSE
(‘0’,‘1’,‘1’,‘1’,‘0’,‘0’,‘1’)WHEN input =“1100”ELSE
(‘1’,‘0’,‘1’,‘1’,‘1’,‘1’,‘0’)WHEN input =“1101”ELSE
(‘1’,‘1’,‘1’,‘1’,‘0’,‘0’,‘1’)WHEN input =“1110”ELSE
(‘1’,‘1’,‘1’,‘0’,‘0’,‘0’,‘1’)WHEN input =“1111”ELSE
(‘0’,‘0’,‘0’,‘0’,‘0’,‘0’,‘0’); - -灭灯
END rtl;
在上例中,七段显示译码器有一个输入端口input和一个输出端口output。输入端口input是一个四位总线,表示3到0的四位逻辑向量,表示输入是一个四位二进制数。输出端口output也以总线形式表示,它表示6到0的7位逻辑向量,表示输出是一个七位二进制数,以驱动共阴极显示七段数码管。
在上例的结构体中,用一个条件代入语句来完成所有状态的显示译码。在保留字WHEN的前面是驱动显示数码管的七位位矢量,WHEN的后面是译码的条件。需要说明的是条件信号代入语句中的书写顺序不是固定的,位置是可以任意颠倒的,他们并不表示执行的先后顺序,实际上他们是并发执行的。
(3) 选择信号代入语句
选择信号代入语句的书写格式为:
WITH 表达式 SELECT
目的信号 <= 表达式1 WHEN 条件1;
表达式2 WHEN 条件2;
表达式3 WHEN 条件3;
┇
表达式n WHEN 条件n;
VHDL在执行选择信号代入语句时,目的信号是根据表达式的当前值来进行表达式代入的。当表达式的值符合某个条件时,就把该条件前的表达式代入目的信号;当表达式的值不符合条件时,语句就继续向下判断,直到找到满足的条件为止。选择信号代入语句与case语句相类似,都是对表达式进行测试,当表达式的值不同时,将把不同的表达式代入目的信号。需要注意的是,选择信号代入语句与case语句一样,必须把表达式的值在条件中都列出来,否则编译将会出错。
下面的例子是一个采用选择信号代入语句描述的选通8位总线的四选一多路选择器。
例:
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY mux4 IS
PORT(d0:IN STD_LOGIC_VECTOR (7 DOWNTO 0);
d1:IN STD_LOGIC_VECTOR (7 DOWNTO 0);
d2:IN STD_LOGIC_VECTOR (7 DOWNTO 0);
d3:IN STD_LOGIC_VECTOR (7 DOWNTO 0);
s0:IN STD_LOGIC;
s1:IN STD_LOGIC;
q:OUT STD_LOGIC_VECTOR (7 DOWNTO 0));
END mux4;
ARCHITECTURE rtl OF mux4 IS
SIGNAL comb:STD_LOGIC_VECTOR (1 DOWNTO 0);;
BEGIN
comb <= s1 & s0; --&运算
WITH comb SELECT - -用comb进行选择
q <= d0 WHEN “00”;
d1 WHEN “01”;
d2 WHEN “10”
d3 WHEN OTHERS; - -上面4条语句是并行执行的
END rtl;
4.2.4 并行过程调用语句
过程调用语句在进程内部执行时,它是一种顺序语句;过程调用语句在结构体的进程之外出现时,它作为并发语句的形式出现。作为并行过程调用语句,在结构体中他们是并行执行的,其执行顺序与书写顺序无关。
并行过程调用语句的一般书写格式如下:
PROCEDURE 过程名(参数1;参数2;┄)IS
[定义语句]; --变量定义
BEGIN
[顺序处理语句]
END 过程名; --当中没有PROCEDURE
下例是一个取三个输入位矢量最大值的功能描述,在它的结构体中使用了两个并行过程调用语句。
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
USE IEEE. STD_LOGIC_UNSIGNED.ALL;
ENTITY max IS
PORT(in1:IN STD_LOGIC_VECTOR (7 DOWNTO 0);
in2:IN STD_LOGIC_VECTOR (7 DOWNTO 0);
in3:IN STD_LOGIC_VECTOR (7 DOWNTO 0);
q:OUT STD_LOGIC_VECTOR (7 DOWNTO 0));
END max;
ARCHITECTURE rtl OF max IS
PROCEDURE maximun(a,b:IN STD_LOGIC_VECTOR;
SIGNAL c:OUT STD_LOGIC_VECTOR)IS
VARIABLE temp:STD_LOGIC_VECTOR (a’RANGE);
BEGIN - -temp矢量长度与a相同
IF (a > b) THEN
temp := a;
ELSE
temp := b;
END IF;
c <= temp;
END maximun;
SIGNAL tmp1,tmp2:OUT STD_LOGIC_VECTOR(7 DOWNTO 0);--此处需要OUT??
BEGIN
maximun(in1,in2,tmp1);--调用
maximun(tmp1,in3,tmp2);
q <= tmp2;
END rtl;
4.2.5并行断言语句
并行断言语句的书写格式为:
ASSERT 条件 [REPORT 报告信息] [SEVERITY 出错级别]
并行断言语句的书写格式与顺序断言语句的书写格式相同。顺序断言语句只能用在进程、函数和过程中,而并行断言语句用在结构体中。任何并行断言语句都对应着一个等价的被动进程语句,被动进程语句没有输出,因此并行断言语句的执行不会引起任何事件的发生,只是在断言条件为“false”时给出一条信息报告。 --等价的被动进程语句
例:
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
USE IEEE. STD_LOGIC_UNSIGNED.ALL;
ENTITY example IS
END example;
ARCHITECTURE behave OF example IS
SIGNAL comb: STD_LOGIC_VECTOR(1 DOWNTO 0);
BEGIN
ASSERT FALSE
REPORT“This entity is a example to descript assert statement”
SEVERITY NOTE;
END behave;
4.2.6 参数传递语句
参数传递语句(GENERIC)主要用来传递信息给设计实体的某个具体元件,如用来定义端口宽度、器件延迟时间等参数后并将这些参数传递给设计实体。使用参数传递语句易于使设计具有通用性,例如,在设计中有一些参数不能确定,为了简化设计和减少VHDL程序的书写,我们通常编写通用的VHDL程序。在设计程序中,这些参数是待定的,在模拟时,只要用GENERIC语句将待定参数初始化即可。
参数传递语句的书写格式为:
GENERIC(类属表);
例:
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY and2 IS
GENERIC(DELAY:TIME:= 10 ns);
PORT(a:IN STD_LOGIC;
b:IN STD_LOGIC;
c:OUT STD_LOGIC);
END and2;
ARCHITECTURE behave OF and2 IS
BEGIN
c <= a AND b AFTER(DELAY);
END behave;
4.2.7 元件例化语句
元件例化就是将预先设计好的设计实体定义为一个元件,然后利用映射语句将此元件与当前设计实体中的指定端口相连,从而为当前设计实体引入了一个低一级的设计层次。在结构体中,描述只表示元件(或模块)和元件(或模块)之间的互连,就象网表一样。当引用库中不存在的元件时,必须首先进行元件的创建,然后将其放在工作库中,通过调用工作库来引用元件。在引用元件时,要先在结构体中说明部分进行元件的说明,然后在使用元件时进行元件例化。
元件例化语句也是一种并行语句,各个例化语句的执行顺序与例化语句的书写顺序无关,而是按照驱动的事件并行执行的。
在进行元件例化时,首先要进行例化元件的说明,元件说明部分使用COMPONENT语句,COMPONENT语句用来说明在结构体中所要调用的模块。如果所调用的模块在元件库中并不存在时,设计人员必须首先进行元件的创建,然后将其放在工作库中通过调用工作库来引用该元件。
COMPONENT语句的一般书写格式如下:
COMPONENT <引用元件名>
[GENERIC <参数说明>;]
PORT <端口说明>;
END COMPONENT; - -元件说明语句
在上面的书写结构中,保留字COMPONENT后面的“引用元件名”用来指定要在结构体中例化的元件,该元件必须已经存在于调用的工作库中;如果在结构体中要进行参数传递,在COMPONENT语句中,就要有传递参数的说明,传递参数的说明语句以保留字GENERIC开始;然后是端口说明,用来对引用元件的端口进行说明;最后以保留字END COMPONENT来结束 COMPONENT语句。
如果在结构体中要引用上例中所定义的带延迟的二输入与门,首先在结构体中要用COMPONENT语句对该元件进行说明,说明如下:
COMPONENT and2 --元件名
GENERIC(DELAY:TIME);--参数说明
PORT(a:IN STD_LOGIC;
b:IN STD_LOGIC;
c:OUT STD_LOGIC);--端口说明
END COMPONENT;
用COMPONENT语句对要引用的元件进行说明之后,就可以在结构体中对元件进行例化以使用该元件。
元件例化语句的书写格式为:
<标号名:> <元件名> [GENERIC MAP(参数映射)]
PORT MAP(端口映射);
标号名是此元件例化的唯一标志,在结构体中标号名应该是唯一的,否则编译时将会给出错误信息;接下来就是映射语句,映射语句就是把元件的参数和端口与实际连接的信号对应起来,以进行元件的引用。
VHDL提供了两种映射方法:位置映射和名称映射。
位置映射就是PORT MAP语句中实际信号的书写顺序与COMPONENT语句中端口说明中的信号书写顺序保持一致,如下例所示:
位置映射示例:
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY example IS
PORT(in1,in2:IN STD_LOGIC;
out:OUT STD_LOGIC);
END example;
ARCHITECTURE structure OF example IS
COMPONENT and2 --元件说明
GENERIC(DELAY:TIME);
PORT(a:IN STD_LOGIC;
b:IN STD_LOGIC;
c:OUT STD_LOGIC);
END COMPONENT;
BEGIN
U1 : and2 GENERIC MAP(10 ns)- -参数映射 标号名U1元件名and2元件例化
PORT MAP(in1,in2,out); - -端口映射
END structure;
在上例中,元件U1 的端口 a 映射到信号in1,端口 b 映射到信号in2,端口c 映射到信号 out。
名称映射就是在PORT MAP语句中将引用的元件的端口信号名称赋给结构体中要使用的例化元件的信号,如下例所示:
例:名称映射
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY example IS
PORT(in1,in2:IN STD_LOGIC;
out:OUT STD_LOGIC);
END example;
ARCHITECTURE structure OF example IS
COMPONENT and2
GENERIC(DELAY:TIME);
PORT(a:IN STD_LOGIC;
b:IN STD_LOGIC;
c:OUT STD_LOGIC);
END COMPONENT;
BEGIN
U1:and2 GENERIC MAP(10 ns)
PORT MAP(a => in1,b=> in2,c => out);--名称映射
END structure;
注意:名称映射的书写顺序要求并不是很严格,只要把要映射的对应信号连接起来就可以了,顺序是可以颠倒的 .
4.2.9 生成语句
生成语句(GENERATE)是一种可以建立重复结构或者是在多个模块的表示形式之间进行选择的语句。由于生成语句可以用来产生多个相同的结构,因此使用生成语句就可以避免多段相同结构的VHDL程序的重复书写(相当于‘复制’)。
生成语句有两种形式:FOR- GENERATE模式和IF- GENERATE模式。
FOR- GENERATE 模式的生成语句
FOR- GENERATE 模式生成语句的书写格式为:
[标号:]FOR 循环变量 IN 离散范围 GENERATE
<并行处理语句>;
END GENERATE [标号];
其中循环变量的值在每次的循环中都将发生变化;离散范围用来指定循环变量的取值范围,循环变量的取值将从取值范围最左边的值开始并且递增到取值范围最右边的值,实际上也就限制了循环的次数;循环变量每取一个值就要执行一次GENERATE语句体中的并行处理语句;最后FOR- GENERATE模式生成语句以保留字END GENERATE [标号:];来结束GENERATE语句的循环。
生成语句的典型应用是存储器阵列和寄存器。下面以四位移位寄存器为例,说明FOR- GENERATE模式生成语句的优点和使用方法。
下图所示电路是由边沿D触发器组成的四位移位寄存器,其中第一个触发器的输入端用来接收四位移位寄存器的输入信号,其余的每一个触发器的输入端均与左面一个触发器的Q端相连。
图用D触发器构成的四位移位寄存器
根据上面的电路原理图,写出四位移位寄存器的VHDL描述如下。
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY shift_reg IS
PORT(di:IN STD_LOGIC;
cp:IN STD_LOGIC;
do:OUT STD_LOGIC);
END shift_reg;
ARCHITECTURE structure OF shift_reg IS
COMPONENT dff --元件说明
PORT(d:IN STD_LOGIC;
clk:IN STD_LOGIC;
q:OUT STD_LOGIC);
END COMPONENT;
SIGNAL q:STD_LOGIC_VECTOR(4 DOWNTO 0);
BEGIN
dff1:dff PORT MAP (di,cp,q(1)); --元件例化
dff2:dff PORT MAP (q(1),cp,q(2));
dff3:dff PORT MAP (q(2),cp,q(3));
dff4:dff PORT MAP (q(3),cp,do);
END structure;
在上例的结构体中有四条元件例化语句,这四条语句的结构十分相似。我们对上例再做适当修改,使结构体中这四条元件例化语句具有相同的结构,如下例所示:
例[]
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY shift_reg IS
PORT(di:IN STD_LOGIC;
cp:IN STD_LOGIC;
do:OUT STD_LOGIC);
END shift_reg;
ARCHITECTURE structure OF shift_reg IS
COMPONENT dff
PORT(d:IN STD_LOGIC;
clk:IN STD_LOGIC;
q:OUT STD_LOGIC);
END COMPONENT;
SIGNAL q:STD_LOGIC_VECTOR(4 DOWNTO 0);
BEGIN
q(0)<= di
dff1:dff PORT MAP (q(0),cp,q(1));
dff2:dff PORT MAP (q(1),cp,q(2));
dff3:dff PORT MAP (q(2),cp,q(3));
dff4:dff PORT MAP (q(3),cp,q(4));
do<= q(4)
END structure;
这样便可以使用FOR- GENERATE模式生成语句对上例中的规则体进行描述,如例[]所示。
例: FOR- GENERATE模式生成语句应用
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY shift_reg IS
PORT(di:IN STD_LOGIC;
cp:IN STD_LOGIC;
do:OUT STD_LOGIC);
END shift_reg;
ARCHITECTURE structure OF shift_reg IS
COMPONENT dff
PORT(d:IN STD_LOGIC;
clk:IN STD_LOGIC;
q:OUT STD_LOGIC);
END COMPONENT;
SIGNAL q:STD_LOGIC_VECTOR(4 DOWNTO 0);
BEGIN
q(0)<= di
label1:FOR i IN 0 TO 3 GENERATE
dffx:dff PORT MAP (q(i),cp,q(i+1));
END GENERATE label1;
do <= q(4)
END structure;
可以看出用FOR- GENERATE模式生成语句替代例[]中的四条元件例化语句,使VHDL程序变的更加简洁明了。在例[]的结构体中用了两条并发的信号代入语句和一条FOR- GENERATE模式生成语句,两条并发的信号代入语句用来将内部信号q和输入端口di、输出端口do连接起来,一条FOR- GENERATE模式生成语句用来产生具有相同结构的四个触发器。
IF- GENERATE模式生成语句
IF- GENERATE模式生成语句的书写格式如下:
[标号:]IF 条件 GENERATE
<并行处理语句>;
END GENERATE [标号];
IF- GENERATE模式生成语句主要用来描述一个结构中的例外情况,例如,某些边界条件的特殊性。当执行到该语句时首先进行条件判断,如果条件为“TRUE”才会执行生成语句中的并行处理语句;如果条件为“FALSE”,则不执行该语句。
例: IF- GENERATE模式生成语句应用
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
ENTITY shift_reg IS
PORT(di:IN STD_LOGIC;
cp:IN STD_LOGIC;
do:OUT STD_LOGIC);
END shift_reg;
ARCHITECTURE structure OF shift_reg IS
COMPONENT dff
PORT(d:IN STD_LOGIC;
clk:IN STD_LOGIC;
q:OUT STD_LOGIC);
END COMPONENT;
SIGNAL q:STD_LOGIC_VECTOR(3 DOWNTO 1);
BEGIN
label1:
FOR i IN 0 TO 3 GENERATE
IF(i=0)GENERATE
dffx:dff PORT MAP (di,cp,q(i+1));
END GENERATE;
IF(i=3)GENERATE
dffx:dff PORT MAP (q(i),cp,do);
END GENERATE;
IF((i /=0)AND(i /=3))GENERATE
dffx:dff PORT MAP (q(i),cp,q(i+1));
END GENERATE;
END GENERATE label1;
END structure;
在例[]的结构体中,FOR- GENERATE模式生成语句中使用了IF- GENERATE模式生成语句。IF- GENERATE模式生成语句首先进行条件i = 0和i = 3的判断,即判断所产生的D触发器是移位寄存器的第一级还是最后一级;如果是第一级触发器,就将寄存器的输入信号di代入到PORT MAP语句中;如果是最后一级触发器,就将寄存器的输出信号do代入到PORT MAP语句中。这样就解决了硬件电路中输入输出端口具有不规则性所带来的问题。