VHDL 在时钟边沿使用输入值
VHDL use input value at clock edge
我有一个环形计数器,它有一个启用和一个计数启用。碰巧在我更大的设计中,计数使能与时钟同步(我的意思是控制它的电路在上升沿拉回到 0)。
观察:
F0 和 F1 输出应在 t = 130 ns 的上升沿发生变化。但是,count_en 输入在环形计数器读取它的同时被拉低。
如何从 VHDL 获得正确的行为?这是我的代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ring_counter_top is
Port ( CLK : in STD_LOGIC;
RING_EN : in STD_LOGIC;
COUNT_EN : in STD_LOGIC;
F0 : out STD_LOGIC;
F1 : OUT STD_LOGIC
);
end ring_counter_top;
architecture Behavioral of ring_counter_top is
signal shift_reg : STD_LOGIC_VECTOR(1 downto 0) := "01";
signal F0_temp : STD_LOGIC := '1';
signal F1_temp : STD_LOGIC := '0';
signal count_tmp : std_logic;
begin
count_tmp <= COUNT_EN;
-- ring counter
process (CLK, RING_EN, COUNT_EN)
begin
if (RISING_EDGE(CLK)) then
if (count_tmp = '1') then
shift_reg(1) <= shift_reg(0);
shift_reg(0) <= shift_reg(1);
F0_temp <= shift_reg(0);
F1_temp <= shift_reg(1);
end if;
end if;
end process;
F0 <= F0_temp and RING_EN;
F1 <= F1_temp and RING_EN;
end Behavioral;
该代码完全符合其描述:
在 clk
的上升沿:
- 将
shift_reg(0)
的值赋给shift_reg(1)
和F0_temp
- 将
shift_reg(1)
的值赋给shift_reg(0)
和F0_temp
您无法在 过程中更改信号 的值(不使用时间延迟,如 wait
语句)。您只能指示模拟器在下一个增量周期更改它。
如果确实需要在进程内改变值,你应该使用变量而不是信号。 但我非常不鼓励这样做,除非您知道自己在做什么!如果使用不当,变量可能会在逻辑综合过程中出现问题。
只需对您的代码做一点小改动:如果 F1_TEMP
和 F0_TEMP
:
切换初始化值
示例代码:
library ieee; use ieee.std_logic_1164.all;
entity counter is
port (
clk : in std_logic;
count_en : in std_logic;
f0 : out std_logic;
f1 : out std_logic
);
end entity;
architecture rtl of counter is
signal shift_reg : std_logic_vector(1 downto 0) := "01";
signal f0_int : std_logic := '0';
signal f1_int : std_logic := '1';
begin
-- ring counter
process (clk)
begin
if rising_edge(clk) then
if count_en = '1' then
shift_reg <= shift_reg(0)&shift_reg(1);
f0_int <= shift_reg(0);
f1_int <= shift_reg(1);
end if;
end if;
end process;
f0 <= f0_int;
f1 <= f1_int;
end architecture;
library ieee; use ieee.std_logic_1164.all;
entity counter_tb is end entity;
architecture behavioral of counter_tb is
signal clk, count_en, f0, f1 : std_logic := '0';
begin
dut: entity work.counter port map(clk, count_en, f0, f1);
clk <= not clk after 10 ns;
count_proc: process begin
count_en <= '0';
wait for 99 ns;
wait until rising_edge(clk);
count_en <= '1';
wait until rising_edge(clk);
count_en <= '0';
wait;
end process;
end architecture;
编辑:
VHDL 模拟器在两个交替阶段运行:
- 语句执行,其中触发的语句(如流程语句)被评估,事件(如信号分配)被放入队列
- 事件处理,处理队列中的事件。
因此如果x
是一个信号并且你在一个进程中写入x <= y;
,那么x
的值不会立即改变:它只会被排队。直到下一个增量周期才会处理所有实际分配,这将在一段时间延迟后发生:在这种情况下,在过程完全评估之后,因为没有 wait
语句。在testbenches中,你可以在一个进程中有多个wait
语句,这会导致时间延迟并因此触发赋值。
更详细:在应用中。说:
entity foo is end entity;
architecture bar of foo is
signal x : bit := '1';
signal y : bit;
begin
process begin
x <= '0';
y <= x;
wait;
end process;
end architecture;
模拟结束后(1-2个增量循环)x
将是'0'
而y
将是'1'
,因为'0'
的赋值到 x
直到下一个增量循环才会发生,在这种情况下,这将发生在无限 wait
语句处,因为引入了时间延迟。
我有一个环形计数器,它有一个启用和一个计数启用。碰巧在我更大的设计中,计数使能与时钟同步(我的意思是控制它的电路在上升沿拉回到 0)。
观察:
F0 和 F1 输出应在 t = 130 ns 的上升沿发生变化。但是,count_en 输入在环形计数器读取它的同时被拉低。
如何从 VHDL 获得正确的行为?这是我的代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ring_counter_top is
Port ( CLK : in STD_LOGIC;
RING_EN : in STD_LOGIC;
COUNT_EN : in STD_LOGIC;
F0 : out STD_LOGIC;
F1 : OUT STD_LOGIC
);
end ring_counter_top;
architecture Behavioral of ring_counter_top is
signal shift_reg : STD_LOGIC_VECTOR(1 downto 0) := "01";
signal F0_temp : STD_LOGIC := '1';
signal F1_temp : STD_LOGIC := '0';
signal count_tmp : std_logic;
begin
count_tmp <= COUNT_EN;
-- ring counter
process (CLK, RING_EN, COUNT_EN)
begin
if (RISING_EDGE(CLK)) then
if (count_tmp = '1') then
shift_reg(1) <= shift_reg(0);
shift_reg(0) <= shift_reg(1);
F0_temp <= shift_reg(0);
F1_temp <= shift_reg(1);
end if;
end if;
end process;
F0 <= F0_temp and RING_EN;
F1 <= F1_temp and RING_EN;
end Behavioral;
该代码完全符合其描述:
在 clk
的上升沿:
- 将
shift_reg(0)
的值赋给shift_reg(1)
和F0_temp
- 将
shift_reg(1)
的值赋给shift_reg(0)
和F0_temp
您无法在 过程中更改信号 的值(不使用时间延迟,如 wait
语句)。您只能指示模拟器在下一个增量周期更改它。
如果确实需要在进程内改变值,你应该使用变量而不是信号。 但我非常不鼓励这样做,除非您知道自己在做什么!如果使用不当,变量可能会在逻辑综合过程中出现问题。
只需对您的代码做一点小改动:如果 F1_TEMP
和 F0_TEMP
:
示例代码:
library ieee; use ieee.std_logic_1164.all;
entity counter is
port (
clk : in std_logic;
count_en : in std_logic;
f0 : out std_logic;
f1 : out std_logic
);
end entity;
architecture rtl of counter is
signal shift_reg : std_logic_vector(1 downto 0) := "01";
signal f0_int : std_logic := '0';
signal f1_int : std_logic := '1';
begin
-- ring counter
process (clk)
begin
if rising_edge(clk) then
if count_en = '1' then
shift_reg <= shift_reg(0)&shift_reg(1);
f0_int <= shift_reg(0);
f1_int <= shift_reg(1);
end if;
end if;
end process;
f0 <= f0_int;
f1 <= f1_int;
end architecture;
library ieee; use ieee.std_logic_1164.all;
entity counter_tb is end entity;
architecture behavioral of counter_tb is
signal clk, count_en, f0, f1 : std_logic := '0';
begin
dut: entity work.counter port map(clk, count_en, f0, f1);
clk <= not clk after 10 ns;
count_proc: process begin
count_en <= '0';
wait for 99 ns;
wait until rising_edge(clk);
count_en <= '1';
wait until rising_edge(clk);
count_en <= '0';
wait;
end process;
end architecture;
编辑:
VHDL 模拟器在两个交替阶段运行:
- 语句执行,其中触发的语句(如流程语句)被评估,事件(如信号分配)被放入队列
- 事件处理,处理队列中的事件。
因此如果x
是一个信号并且你在一个进程中写入x <= y;
,那么x
的值不会立即改变:它只会被排队。直到下一个增量周期才会处理所有实际分配,这将在一段时间延迟后发生:在这种情况下,在过程完全评估之后,因为没有 wait
语句。在testbenches中,你可以在一个进程中有多个wait
语句,这会导致时间延迟并因此触发赋值。
更详细:在应用中。说:
entity foo is end entity;
architecture bar of foo is
signal x : bit := '1';
signal y : bit;
begin
process begin
x <= '0';
y <= x;
wait;
end process;
end architecture;
模拟结束后(1-2个增量循环)x
将是'0'
而y
将是'1'
,因为'0'
的赋值到 x
直到下一个增量循环才会发生,在这种情况下,这将发生在无限 wait
语句处,因为引入了时间延迟。