在VHDL中,使用信號(signal)或變量(variable)可以實現動態數值的傳遞,二者功能雖然類似,但在實現方式上卻有着很大的區別。對於初學者,理解信號和變量的差異是十分重要的。
1. 信號(signal)
信號是邏輯電路中的連接線,可以用於元件間和元件內部電路各單元間的連接。
信號使用”<=“符號賦值。
在順序描述語句中,信號的賦值不是即時更新的。只有在相應的進程、函數或過程完成之后,信號的值才會進行更新。
2. 變量(variable)
變量只用於局部電路的描述,只能在process、function和procedure內部使用。
變量使用”:=“符號賦值。
變量的賦值是立即生效的,可以在下一行代碼中立即使用新的變量值。
3. 信號與變量賦值的生效時刻
信號與變量的一個重要差異是賦值是否立即生效。對變量的賦值是立即生效的,而在順序描敘語句中對信號的賦值則不會立即生效,只有當信號所在的process內的操作全部完成一遍后,信號的值才會更新。
下面通過兩個例子說明信號與變量賦值的生效時刻。如下面所示的兩個計數器:
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_arith.ALL; use IEEE.STD_LOGIC_unsigned.ALL; entity counter is port( rst : in std_logic; clk : in std_logic; clk_cnt_1 : out std_logic_vector(3 downto 0); clk_cnt_2 : out std_logic_vector(3 downto 0) ); end counter; architecture Behavioral of counter is signal s_cnt : std_logic_vector(3 downto 0) := (others => '0'); begin p_signal_counter: process(rst, clk) begin if rst = '0' then clk_cnt_1 <= (others => '0'); s_cnt <= (others => '0'); elsif clk' event and clk = '1' then s_cnt <= s_cnt + 1; clk_cnt_1 <= s_cnt; end if; end process; p_variable_counter: process(rst, clk) variable v_cnt : std_logic_vector(3 downto 0) := (others => '0'); begin if rst = '0' then clk_cnt_2 <= (others => '0'); v_cnt := (others => '0'); elsif clk' event and clk = '1' then v_cnt := v_cnt + 1; clk_cnt_2 <= v_cnt; end if; end process; end Behavioral;
其中,p_signal_counter中使用信號v_cnt做計數,並更新clk_cnt_1;p_variable_counter中使用變量v_cnt做計數,並更新clk_cnt_2。仿真結果如圖1所示。
由圖1可見,clk_cnt_1得計數值比clk_cnt_2的值小1,clk_cnt_1更新的比clk_cnt_2慢,因為v_cnt是信號,"s_cnt <= s_cnt + 1;"對其的賦值需要等到p_signal_counter執行完畢后才生效,而v_cnt是變量,"v_cnt := v_cnt + 1;"對其的賦值是立即生效的。更進一步地把上面的計數器改寫如下:
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_arith.ALL; use IEEE.STD_LOGIC_unsigned.ALL; entity counter is port( rst : in std_logic; clk : in std_logic; clk_cnt_1 : out std_logic_vector(3 downto 0); clk_cnt_1_before_update : out std_logic_vector(3 downto 0); clk_cnt_2 : out std_logic_vector(3 downto 0); clk_cnt_2_before_update : out std_logic_vector(3 downto 0) ); end counter; architecture Behavioral of counter is signal s_cnt : std_logic_vector(3 downto 0) := (others => '0'); begin p_signal_counter: process(rst, clk) begin if rst = '0' then clk_cnt_1 <= (others => '0'); clk_cnt_1_before_update <= (others => '0'); s_cnt <= (others => '0'); elsif clk' event and clk = '1' then clk_cnt_1_before_update <= s_cnt; s_cnt <= s_cnt + 1; clk_cnt_1 <= s_cnt; end if; end process; p_variable_counter: process(rst, clk) variable v_cnt : std_logic_vector(3 downto 0) := (others => '0'); begin if rst = '0' then clk_cnt_2 <= (others => '0'); clk_cnt_2_before_update <= (others => '0'); v_cnt := (others => '0'); elsif clk' event and clk = '1' then clk_cnt_2_before_update <= v_cnt; v_cnt := v_cnt + 1; clk_cnt_2 <= v_cnt; end if; end process; end Behavioral;
其中,分別用clk_cnt_1_before_update和clk_cnt_2_before_update來觀測s_cnt和v_cnt在其更新語句前的狀態,仿真結果如圖2所示。
圖2
由圖2可見,clk_cnt_1_before_update與clk_cnt_1相同,說明"s_cnt <= s_cnt + 1;"語句執行后s_cnt並沒有更新;而clk_cnt_2_before_update的值比clk_cnt_2的值小1,說明"v_cnt := v_cnt+ 1;"語句執行后v_cnt立即得到了更新。