四、        顺序代码

在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;