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_TEMPF0_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 模拟器在两个交替阶段运行:

  1. 语句执行,其中触发的语句(如流程语句)被评估,事件(如信号分配)被放入队列
  2. 事件处理,处理队列中的事件。

因此如果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 语句处,因为引入了时间延迟。