VHDL中信号与变量的差异
在VHDL中,使用信号(signal)或变量(variable)可以实现动态数值的传递,二者功能虽然类似,但在实现方式上却有着很大的区别。对于初学者,理解信号和变量的差异是十分重要的。
Contents [show]
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;
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;
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;
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;
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可见,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 立即得到了更新。