当进程被调用两次时奇怪的延迟输出行为

Weird delayed-output behaviour when a process is invoked twice

我正在尝试编写一个具有输入(开始)和三个输出(tsy、tsr、tlg)的计数器,这些输出在 4、6 和 16 clk_period 之后针对 1 clk_period 断言分别。以下代码适用于单个启动断言。

library ieee ;
    use ieee.std_logic_1164.all ;
    use ieee.numeric_std.all ;

entity proj_test is
  port (
    clk, start : in bit;
    tsy, tsr, tlg : out bit
  ) ;
end entity ; -- proj_test

architecture behav of proj_test is

constant clk_period : time := 100 ns;

begin

process (start)
begin
    if (start='1') then
        tsy <= '1' after 4*clk_period, '0' after 5*clk_period;
        tsr <= '1' after 6*clk_period, '0' after 7*clk_period;
        tlg <= '1' after 16*clk_period, '0' after 17*clk_period;
    end if;
end process;

end architecture ; -- behav

Output for a single start

start 脉冲间隔 400 ns,由以下代码驱动:

library ieee ;
    use ieee.std_logic_1164.all ;
    use ieee.numeric_std.all ;

entity proj_test_test is
end entity proj_test_test; 

architecture behav of proj_test_test is
  constant clk_period : time := 100 ns;
  signal clk, start :  bit;
  signal tsy, tsr, tlg : bit;
begin

  P : entity work.proj_test port map (clk, start, tsy, tsr, tlg);

  start <= '0', 
           '1' after  2*clk_period,
           '0' after  3*clk_period,
           '1' after 6*clk_period,
           '0' after 7*clk_period,
           '1' after 42*clk_period;

end architecture behav;

https://www.edaplayground.com/x/52mP

或以下模拟器命令:

force -freeze sim:/proj_test/clk 0 0, 1 {50 ns} -r 100
force -freeze sim:/proj_test/start 1 0, 0 100, 1 400, 0 500

但是,当我第二次断言输入 start 时,tsy 跨越多个时钟周期。

Output for an added start

我正在尝试了解原因。我的猜测是第二个进程调用 "flushes" 第一个进程的分配。另外,有没有更好的方法来写这个计数器的行为?

VHDL 模拟器维护着一个事件队列。这是模拟器的 "To Do" 列表。执行带有 信号分配 的任何 VHDL 行的效果是修改事件队列。通常,事件被添加到事件队列中,但通常也可以删除事件。为了模拟 惯性延迟 ,将删除事件;在 VHDL 中,延迟默认是惯性的。

In order to model inertial delays, when an event is added to the event queue, any event that is scheduled to occur at the same time or earlier is removed, unless the effect of that event is the same as the effect of the new event being added.

当您的代码正在执行时,事件会通过后续的信号分配从事件队列中移除。我们需要详细分析事件队列。

因此,在时间 0 ns,事件队列为空。该行在时间 0

执行
start <= '0', 
         '1' after  2*clk_period,
         '0' after  3*clk_period,
         '1' after  6*clk_period,
         '0' after  7*clk_period,
         '1' after 42*clk_period;

将 6 个事件放入事件队列。事件队列现在如下所示:

TIME      DELTA   SIGNAL    VALUE
   0 ns   1       start     '0'
 200 ns   0       start     '1'
 300 ns   0       start     '0'
 600 ns   0       start     '1'
 700 ns   0       start     '0'
4200 ns   0       start     '1'

在 200 ns 时,start 被驱动到 '1',因此执行以下三行:

tsy <= '1' after 4*clk_period, '0' after 5*clk_period;
tsr <= '1' after 6*clk_period, '0' after 7*clk_period;
tlg <= '1' after 16*clk_period, '0' after 17*clk_period;

将另外 6 个事件放入事件队列。事件队列现在如下所示:

TIME      DELTA   SIGNAL    VALUE
 300 ns   0       start     '0'
 600 ns   0       start     '1'
 600 ns   0       tsy       '1'
 700 ns   0       start     '0'
 700 ns   0       tsy       '0'
 800 ns   0       tsr       '1'
 900 ns   0       tsr       '0'
1800 ns   0       tlg       '1'
1900 ns   0       tlg       '0'
4200 ns   0       start     '1'

然后在 300 ns start 被驱动到 '0' 所以事件队列现在看起来像这样:

TIME      DELTA   SIGNAL    VALUE
 600 ns   0       start     '1'
 600 ns   0       tsy       '1'
 700 ns   0       start     '0'
 700 ns   0       tsy       '0'
 800 ns   0       tsr       '1'
 900 ns   0       tsr       '0'
1800 ns   0       tlg       '1'
1900 ns   0       tlg       '0'
4200 ns   0       start     '1'

然后在 600 ns start 被驱动到 '1' (并且 tsy 也被驱动到 '1')所以事件队列现在看起来像这样:

TIME      DELTA   SIGNAL    VALUE
 700 ns   0       start     '0'
 700 ns   0       tsy       '0'
 800 ns   0       tsr       '1'
 900 ns   0       tsr       '0'
1800 ns   0       tlg       '1'
1900 ns   0       tlg       '0'
4200 ns   0       start     '1'

下面三行再次执行:

tsy <= '1' after 4*clk_period, '0' after 5*clk_period;
tsr <= '1' after 6*clk_period, '0' after 7*clk_period;
tlg <= '1' after 16*clk_period, '0' after 17*clk_period;

将另外 6 个事件放入事件队列:

TIME      DELTA   SIGNAL    VALUE
1000 ns   0       tsy       '1'
1100 ns   0       tsy       '0'
1200 ns   0       tsr       '1'
1300 ns   0       tsr       '0'
2200 ns   0       tlg       '1'
2300 ns   0       tlg       '0'

如果您遵循我上面给出的规则,您会看到事件队列如下所示:

TIME      DELTA   SIGNAL    VALUE
 700 ns   0       start     '0'
1000 ns   0       tsy       '1'
1100 ns   0       tsy       '0'
1200 ns   0       tsr       '1'
1300 ns   0       tsr       '0'
2200 ns   0       tlg       '1'
2300 ns   0       tlg       '0'
4200 ns   0       start     '1'

因为这五个事件被删除了:

TIME      DELTA   SIGNAL    VALUE
 700 ns   0       tsy       '0'
 800 ns   0       tsr       '1'  
 900 ns   0       tsr       '0'
1800 ns   0       tlg       '1'
1900 ns   0       tlg       '0'

如果您查看跟踪,您会发现这些事件正是发生的情况:

  • 删除tsy的下降沿(因此宽脉冲);
  • tsr 上的前两个事件被删除(因此只有一个脉冲);
  • tlg 上的前两个事件被删除(因此只有一个脉冲)。