如何避免VHDL中简单流程语句输出的延迟

时间:2015-02-04 05:05:10

标签: vhdl

我是VHDL的初学者。我想知道为什么在下面的代码中有一个循环的延迟。以及如何避免它..同时在verilog声明总是@(posedge clk)没有任何延迟..如何做同样的事情VHDL

library IEEE;
 use IEEE.std_logic_1164.all;

   -- entity
entity t_ff_s is
port ( T,S,CLK : in std_logic;
Q : out std_logic);
 end t_ff_s;
 -- entity
 architecture my_t_ff_s of t_ff_s is
signal t_tmp : std_logic; -- intermediate signal declaration
  begin
    tff: process (S,rising_edge(clk))
     begin
        if (S = '0') then
     t_tmp <= '1';
      --elsif (rising_edge(CLK)) then
     else 
     t_tmp <= T XOR t_tmp; -- temp output assignment
     end if;
    end process tff;
     Q <= t_tmp; -- final output assignment
     end my_t_ff_s;

2 个答案:

答案 0 :(得分:3)

VHDL中的灵敏度列表不像Verilog那样采用边缘规范。 VHDL更灵活,您可以在流程中的任何位置自由使用'event信号属性来实现边缘触发行为。您可以混合使用级别和边缘敏感逻辑,而无需使用拆分块/进程或诸如negedge之类的黑客来进行重置。在敏感性列表中不允许使用rising_edge(clk)(实现clk'event的测试)等函数调用。它只包含信号名称。您的代码不会按原样编译。

如果您的代码的某些其他语法正确版本编译干净,您看到的延迟是模拟模型的工件或具有损坏的敏感性列表。如果您想要一个同步时钟驱动的过程,那么您只需要时钟信号,并可能需要在灵敏度列表中进行异步复位。

考虑以下过程:

tff: process(S, clk)
begin
  if S = '0' then -- Asynchronous reset (level sensitive)
    t_tmp <= '1';
  elsif rising_edge(clk) then -- Synchronous logic (edge sensitive)
    t_tmp <= T xor t_tmp;
  end if;
end process;

Q <= t_tmp;

Sclk上发生事件时,将执行此流程。如果S为'0',则执行重置条件优先于elsif子句(clk是无关紧要的)。对t_tmp的赋值对下一个delta周期生效,该周期仍与当前模拟时间相同。否则,如果rising_edge(clk)评估为真,则clk上发生一个事件,并且状态从'0'(或'L')变为'1'(或'H'),表明事件是上升的边缘。同步分配发生,新的xored t_tmp在下一个增量循环中生效。 T中的更改不会导致进程执行,因为它不是(也不应该)在敏感列表中。

因为没有无条件else子句,如果两个t_tmp条件都为假,则if信号会保留其最后指定的值。它会在下次Sclk上发生导致t_tmp新作业的事件时发生变化。这将是下一个时钟沿或重新应用异步复位。

Q的分配是连续的,与其敏感度列表中t_tmp的过程实际上相同。因此,对Q的赋值在t_tmp上的事件之后发生增量循环,这是在上升沿之后的两个增量循环。如果Q正在进入比边缘的第二个增量周期更早更新的逻辑,则它将需要额外的时钟周期才能传播。

在检查波形时,围绕增量周期的行为有时会产生令人困惑的结果。您可能有一个上升沿应捕获出现的数据输入,以便在同一时间步骤同时转换,实际上,数据在稍后的增量循环中转换,并且仅在下一个时钟边缘。

类似地,如果您构造一个没有任何时间延迟的简单门控时钟,它的边缘将同时发生,但是在后来的delta周期发生,而不是时钟的非门控版本。从“早期”非门控时钟驱动的数据将由门控逻辑捕获比结果预期更早的时钟周期。从另一个方向驱动的数据似乎会在一个时钟周期内出现意外延迟。

目前尚不清楚是什么原因造成了您所看到的问题,而没有关于您如何驾驶STclk信号的更多信息,但它可能已连接到模拟引擎的delta循环行为在某种程度上。

答案 1 :(得分:2)

问题

比凯文更简洁一点,rising_edge是一个表达而不是信号,灵敏度列表需要一个命名信号,一个事务,你可以继续执行暂停的进程。把elsif放回去,灵敏度列表中只有S和clk。

请注意,由于t_tmp不在敏感度列表中,因此您不会看到Q跟随t_tmp,直到导致您注意到延迟的下一个时钟事件。

固定语法过程:

     tff: process (S,clk) -- was (S, risingedge(CLK)), a syntax error)
     begin
        if (S = '0') then
     t_tmp <= '1';
      elsif (rising_edge(CLK)) then  -- put back
     -- else
     t_tmp <= T XOR t_tmp; -- temp output assignment
     end if;
      Q <= t_tmp; -- final output assignment
      end process tff;

显示t_tmp和Q之间的延迟:

t_ff_s half clock delay (点击)

通过使Q成为并发信号分配来修复它

为了解决半个时钟延迟问题,您可以为Q分配并发信号赋值语句(将其移到进程外)。

tff:
    process (S, clk)
    begin
        if S = '0' then
            t_tmp <= '1';
        elsif  rising_edge(clk) then
            t_tmp <= T xor t_tmp;
        end if;
    end process;
    Q <= t_tmp;   -- concurrent signal assignment

给出了:

make Q assignment concurrent (点击)

您可以在上面看到t_tmp和Q现在处于同步状态。

通过将t_tmp变为

来解决此问题

您还可以将t_tmp声明为进程dff中的变量而不是信号,并将切换分配给它,因为变量赋值也将固化t_tmp和Q之间的一个时钟延迟。

tff:
    process (S, clk)
        variable t_tmp:  std_logic;
    begin
        if S = '0' then
            t_tmp := '1';
        elsif  rising_edge(clk) then
            t_tmp := T xor t_tmp;
        end if;
        Q <= t_tmp;
    end process;

显示:

tmp a variable (可点击)

使用gtkwave的ghdl不输出变量或显示delta周期。你可以看到Q出现在时钟的上升沿。

使t_tmp变量也可以消除t_tmp上的事务和Q上的事务之间的增量循环。

消除delta周期使您的模型执行得更快(在当前模拟时发生)。在任何进程执行且变量赋值立即生效时,信号分配不会生效。

通过将t_tmp添加到敏感度列表

来修复它

另外,您可以将t_tmp添加到灵敏度列表中(以及S和clk)。

tff:
    process (S, clk, t_tmp)
    begin
        if S = '0' then
            t_tmp <= '1';
        elsif  rising_edge(clk) then
            t_tmp <= T xor t_tmp;
        end if;
        Q <= t_tmp;
    end process;

just add t_tmp to the sensitivity list (可点击)

这比所有其他修复都要慢,因为每次t_tmp有一个事件以及S或CLK时都会执行if语句。 rising_edge是一个函数调用,它动态地详细说明了它的接口列表,这是一个重要的模拟器性能损失,特别是如果你使用了很多这些原语。

这些是通过测试台完成的:

library IEEE;
 use IEEE.std_logic_1164.all;

   -- entity
entity t_ff_s is
port ( T,S,CLK : in std_logic;
Q : out std_logic);
 end entity t_ff_s;

architecture my_t_ff_s of t_ff_s is
signal t_tmp : std_logic; -- intermediate signal declaration
  begin
    tff: process (S,clk) -- was (S, risingedge(CLK)), a syntax error)
     begin
        if (S = '0') then
            t_tmp <= '1';
        elsif (rising_edge(CLK)) then  -- put back
        -- else
            t_tmp <= T XOR t_tmp; -- temp output assignment
        end if;
             Q <= t_tmp; -- final output assignment
    end process tff;
end my_t_ff_s;

architecture foe of t_ff_s is
    signal t_tmp: std_logic;
begin
tff:
    process (S, clk)
    begin
        if S = '0' then
            t_tmp <= '1';
        elsif  rising_edge(clk) then
            t_tmp <= T xor t_tmp;
        end if;
    end process;
    Q <= t_tmp;   -- concurrent signal assignment
end architecture;

architecture fie of t_ff_s is
begin
tff:
    process (S, clk)
        variable t_tmp:  std_logic;
    begin
        if S = '0' then
            t_tmp := '1';
        elsif  rising_edge(clk) then
            t_tmp := T xor t_tmp;
        end if;
        Q <= t_tmp;
    end process;
end architecture;

architecture fee of t_ff_s is
    signal t_tmp: std_logic;
begin
tff:
    process (S, clk, t_tmp)
    begin
        if S = '0' then
            t_tmp <= '1';
        elsif  rising_edge(clk) then
            t_tmp <= T xor t_tmp;
        end if;
        Q <= t_tmp;
    end process;
end architecture;

library ieee;
use ieee.std_logic_1164.all;

entity test_tff is
end entity;

architecture foo of test_tff is
    signal CLK: std_logic := '0';
    signal T:   std_logic := '0';
    signal S:   std_logic := '0';
    signal Q:   std_logic;

    component t_ff_s is
        port (
            signal CLK:     in  std_logic;
            signal T:       in  std_logic;
            signal S:       in  std_logic;
            signal Q:       out std_logic
        );
    end component;
begin

DUT: 
    t_ff_s
        port map (
            T => T,
            S => S,
            CLK => CLK,
            Q => Q
        );
CLOCK:
    process
    begin
        wait for 10 ns;
        CLK <= not CLK;
        if Now > 250 ns then
            wait;
        end if;
    end process;

SET:
    process
    begin
        S <= '0';
        wait for 20 ns;
        S <= '1';
        wait;
    end process;

TOGGLE:
    process
    begin
        wait for 20 ns;
        T <= '1';
        wait for 60 ns;
        T <= '0';
        wait for 40 ns;
        T <= '1';
        wait;
    end process;

end architecture;

configuration my_t_ff_s_config of test_tff is
    for foo 
        for  DUT: t_ff_s
            use entity work.t_ff_s(my_t_ff_s);
        end for;
    end for;
end configuration;

configuration concurrent_config of test_tff is
    for foo 
        for  DUT: t_ff_s
            use entity work.t_ff_s(foe);
        end for;
    end for;
end configuration;

configuration variable_config of test_tff is
    for foo 
        for  DUT: t_ff_s
            use entity work.t_ff_s(fie);
        end for;
    end for;
end configuration;

configuration sensitivity_config of test_tff is
    for foo 
        for  DUT: t_ff_s
            use entity work.t_ff_s(fee);
        end for;
    end for;
end configuration;

请注意使用配置

使用VHDL的配置声明允许使用多种体系结构。 (my_t_ff_s - 原始的,敌人 - 同时分配给Q,fie - 将t_tmp作为变量和费用 - 在灵敏度列表中使用t_tmp)。

令人惊讶的是,ghdl的分析器对于正确获取配置声明语法非常有帮助。一旦你拿到第一个,其他的很容易。

我们倾向于使用配置变得生疏,历史上通常不会通过综合工具支持它。但话说回来,这是模拟验证

对于那些有ghdl和gtkwave的人来说,这就是它的完成方式:

  

ghdl -a t_ff.vhdl
  ghdl -e my_t_ff_s_config
  ghdl -e concurrent_config
  ghdl -e concurrent_config
  ghdl -e sensitivity_config
  ghdl -r my_t_ff_s_config --wave = test_tff_my_t_ff_s.ghw
  ghdl -r concurrent_config --wave = test_tff_foe.ghw
  ghdl -r variable_config --wave = test_tff_fie.ghw
  ghdl -r sensitivity_config --wave = test_tff_fee.ghw

     

GHW是ghdl的原生波形转储文件格式,由gtkwave理解。

     

在gtkwave中:

     

打开t_ff_s.gtkw(读入test_tff_my_t_ff_s.ghw)
  (否则请阅读test_tff_my_t_ff_s.ghw并将信号添加到
  波形显示,格式化窗口,将保存文件保存到t_ff_s.gtkw)

     

新标签打开test_tff_foe.ghw
         读取保存文件打开t_ff_s.gtkw
     新标签打开test_tff_fie.ghw
         读取保存文件打开t_ff_s.gtkw
     新标签打开test_tff_fee.ghw
         读取保存文件打开t_ff_s.gtkw

     

注意ghdl不保存变量状态或delta周期,t_tmp不会出现在test_ff_fie.ghw的波形中。