四、 顺序代码
在PROCESS, , PROCEDURE内部的代码都是顺序执行的,这样的语句包括IF,WAIT,CASE和LOOP。变量只能在顺序代码中使用,相对于信号而言,变量是局部的,所以它的值不能传递到PROCESS,和PROCEDURE的外部。
1. 进程(PROCESS)
进程内部经常使用IF,WAIT,CASE或LOOP语句。PROCESS具有敏感信号列表(sensitivity list),或者使用WAIT语句进行执行条件的判断。PROCESS必须包含在主代码段中,当敏感信号列表中的某个信号发生变化时(或者当WAIT语句的条件得到满足时),PROCESS内部的代码就顺序执行一次。语法结构如下:
[label: ] PROCESS (sensitivity list)
[VARIABLE name type [range] [ := initial_value; ]]
BEGIN
(顺序执行的代码)
END PROCESS [label];
如果要在PROCESS内部使用变量,则必须在关键字BEGIN之前的变量声明部分对其进行定义。变量的初始值是不可综合的,只用于仿真。在设计同步电路时,要对某些信号边沿的跳变进行监视(时钟的上升沿或下降沿)。通常使用EVENT属性来监视一个信号是否发生了变化。
2. 信号和变量
信号可在PACKAGE,ENTITY和ARCHITECTURE中声明,而变量只能在一段顺序描述代码的内部声明。因此,信号通常是全局的,变量通常是局部的。赋予变量的值是立刻生效的,在后续的代码中,此变量将使用新的变量值,而信号的值通常只有在整个PROCESS执行完毕后才开始生效。
3. IF语句
IF/ELSE语句在综合时可能会产生不必要的优先级解码电路。IF语句语法结构如下:
IF conditions THEN assignments;
ELSIF conditions THEN assignments;
ELSE assignments;
END IF;
————————————————————————————————
例:
IF (x < y) temp := “1111_1111”;
ELSIF (x = y AND w = ‘0’) THEN temp := “1111_0000”;
ELSE temp := (OTHERS => ‘0’);
4. WAIT语句
如果在process中使用了WAIT语句,就不能使用敏感信号列表了。WAIT语句使用以下3种形式的语法结构:
WAIT UNTIL signal_condition;
WAIT ON signal1 [, signal2, ...];
WAIT FOR time;
WAIT UNTIL 后面只有一个信号条件表达式,更适合于实现同步电路(将时钟的上升沿或下降沿作为条件),由于没有敏感信号列表,所以它必须是process的第一条语句。当WAIT UNTIL语句的条件满足是,process内部的代码就执行一遍。
–带有同步复位的8bit寄存器
process –没有敏感信号列表
begin
wait until (clk’event and clk = ‘1′);
if (rst = ‘1′) then
output <= (others => ‘0′);
elsif (clk’event and clk = ‘1′) then
output <= input;
end if;
end process;
WAIT ON 语句中可以出现多个信号,只要信号列表中的任何一个发生变化,process内的代码就开始执行。
–带异步复位的8bit寄存器
process
begin
wait on clk, rst;
if (rst = ‘1′) then
output <= (others => ‘0′);
elsif (clk’event and clk = ‘1′) then
output <= input;
end if;
end process;
WAIT FOR 语句只能用于仿真。
5. CASE 语句
CASE语句的语法结构如下:
CASE 表达式 IS
WHEN 条件表达式 => 顺序执行语句;
WHEN 条件表达式 => 顺序执行语句;
……
END CASE
例:
case control is
when “00″ => x <= a; y <= b;
when “01″ => x <= b; y <= c;
when others => x <= “0000″; y <= “zzzz”;
end case;
关键词OTHERS代表了所有未列出的可能情况,与Verilog中default相当。关键词NULL表示没有操作发生,如WHEN OTHERS => NULL.
CASE语句允许在每个测试条件下执行多个赋值操作,WHEN语句只允许执行一个赋值操作。
6. LOOP语句
LOOP语句用在需要多次重复执行时。语法结构有以下几种:
FOR/LOOP: 循环固定次数
[label: ] FOR 循环变量 IN 范围 LOOP
(顺序描述语句)
END LOOP [label];
WHILE/LOOP: 循环执行直到某个条件不再满足
[label: ] WHILE condition LOOP
(顺序描述语句)
END LOOP [label];
EXIT: 结束整个循环操作
[label: ] EXIT [label] [WHEN condition];
NEXT: 跳出本次循环
[label: ] NEXT [loop_label] [WHEN condition];
Example: FOR/LOOP
for i in 0 to 5 loop
x(i) <= enable and w(i+2);
y(0, i) <= w(i);
end loop
Example: WHILE/LOOP
while (i < 10) loop — 0~9
wait until clk’event and clk = ‘1′;
(其他语句)
end loop;
for i in 0 to data’range loop
case data(i) is
when ‘0′ => count := count + 1;
when others => null;
end case;
end loop;
7. CASE语句和IF语句的比较
IF语句和CASE语句编写的代码在综合、优化后最终生成的电路结构是一样的。
例:下面两段代码综合后可以得到结构相同的多路复用器
————with IF————–
if (sel = “00″) then x <= a;
elsif (sel = “01″) then x <= b;
elsif (sel = “10″) then x <= c;
else x <= d;
end if;
————-with case———–
case sel is
when “00″ => x <= a;
when “01″ => x <= b;
when “10″ => x <= c;
when others => x <= d;
end case;
8. CASE语句和WHEN语句的比较
case语句和when语句的不同之处在于,when语句是并发执行的,case语句是顺序实行的。
–下面两段代码的功能等效
——-with when——————
with sel select
x <= a when “000″,
b when “001″,
c when “101″,
unaffected when others;
——-with case——————
case sel is
when “000″ => x <= a;
when “001″ => x <= b;
when “101″ => x <= c;
when others => null;
end case;
9. 使用顺序代码设计组合逻辑电路
原则1:确保在process中用到的所有输入信号都出现在敏感信号列表中;
原则2:电路的真值表必须在代码中完整的反映出来。(否则会生成锁存器)
五、 信号和变量
常量和信号是全局的,既可以用在顺序执行的代码中,也可用在并发执行的代码中。变量是局部的,只能用在顺序代码中,并且它们的值是不能直接向外传递的。
1. 常量
CONSTANT name: type := value;
2. 信号-signal
VHDL中的signal代表的是逻辑电路中的“硬”连线,既可用于电路的输入/输出端口,也可用于电路内部各单元之间的连接。Entity的所有端口默认为signal。格式如下:
SIGNAL name: type [range] [:= initial value];
当信号用在顺序描述语句中时,其值不是立刻更新的,信号值是在相应的进程、函数或过程完成之后才进行更新的。对信号赋初值的操作时不可综合的。
3. 变量
变量仅用于局部电路的描述,只能在顺序执行的代码中使用,而且对它的赋值是立即生效的,所以新的值可在下一行代码中立即使用。格式:
VARIABLE name: type [range] [:= initial value];
对变量的赋初值操作也是不可综合的。
4. 寄存器的数量
当一个信号的赋值是以另一个信号的跳变为条件时,或者说当发生同步赋值时,该信号经过编译后就会生成寄存器。如果一个变量是在一个信号跳变时被赋值的,并且该值最终又被赋给了另外的信号,则综合后就会生成寄存器。如果一个信号在还没有进行赋值操作时已被使用,那么也会在综合时生成寄存器。
process (clk)
begin
if (clk’event and clk = ‘1′) then
output1 <= temp; – output1被寄存
output2 <= a; – output2被寄存
end if;
end process;
process (clk)
begin
if (clk’event and clk = ‘1′) then
output1 <= temp; – output1被寄存
end if;
output2 <= a; – output2未被寄存
end process;
process (clk)
variable temp: bit;
begin
if (clk’event and clk = ‘1′) then
temp <= a;
end if;
x <= temp; – temp促使x被寄存
end process;