同步计数器问题

时间:2014-05-05 12:39:22

标签: vhdl

我在某些同步计数器的VHDL代码中存在时序问题。我无法弄清楚为什么计数器以1个时钟脉冲前进两次。我已经尝试了一切,包括在D-flip上添加不必要的代码,试图让它正常工作。这是一个类,我们必须使用我们自己的模型而不是库块。我是一名软件程序员,参加这门课程并且有时会使用“即时”作业而不是程序中的“连续”作业。

如果有人能指出我正确的方向,我会很感激。谢谢

--D-FlipFlop

ENTITY D_flipflop IS 
  PORT ( D, Clock, Reset : IN STD_LOGIC ; 
                Q : OUT STD_LOGIC) ; 
END D_flipflop ;

ARCHITECTURE Behavior OF D_flipflop IS 

Signal Q_buff : STD_LOGIC := '0';

BEGIN
  Q <= Q_buff;

  PROCESS ( Clock, Reset ) 
  BEGIN
    IF (Reset = '0') THEN
      Q_buff <= '0';
    ElSE
      IF RISING_EDGE(Clock) THEN 
        IF (D = '1') THEN  -- Was D <=Q changed as a trial fix
           Q_buff <= '1';
        ELSE
           Q_buff <= '0';
        END IF;
      END IF;               
    END IF ; 
  END PROCESS ; 
END Behavior ; 

--4 bit Synchronous counter with load
entity SyncCounter is
  Port ( CLOCK : in  STD_LOGIC;
             D : in  STD_LOGIC_VECTOR (3 downto 0);
             Q : inout STD_LOGIC_VECTOR (3 downto 0);
            CE : in STD_LOGIC;
          Load : in STD_LOGIC;
           CEO : out STD_LOGIC;
         Reset : in  STD_LOGIC);
end SyncCounter;



architecture Behavioral of SyncCounter is

SIGNAL ND0, ND1, ND2, ND3, CE_CLOCK : STD_LOGIC := '0';

component D_flipflop IS 
  PORT ( D, CLOCK, RESET : IN STD_LOGIC ; 
         Q : OUT STD_LOGIC) ; 
END component ;

begin

CE_CLOCK <=  (CLOCK and (CE or Load));

ND0 <= (NOT Q(0) and NOT Load) 
    or (D(0) and Load);

SC_D0: D_flipflop PORT MAP ( ND0, CE_CLOCK, Reset, Q(0));

ND1 <= (((NOT Q(0) AND Q(1)) OR (Q(0) AND NOT Q(1))) and NOT LOAD)  -- (Q(0) XOR Q(1))
 or (D(1) and Load); 

SC_D1: D_flipflop PORT MAP ( ND1, CE_CLOCK, Reset, Q(1));

ND2 <= (((Q(0) and Q(1) and NOT Q(2)) or (Q(2) and (NOT Q(0) or NOT Q(1)))) AND NOT Load)
    or (D(2) and Load);

SC_D2: D_flipflop PORT MAP ( ND2, CE_CLOCK, Reset, Q(2));

ND3 <= ((((NOT Q(0) or NOT Q(1) or NOT Q(2)) AND Q(3)) OR (Q(0) and Q(1) and Q(2) and NOT Q(3))) AND NOT Load)
    or (D(3) and Load);

SC_D3: D_flipflop PORT MAP ( ND3, CE_CLOCK, Reset, Q(3));

CEO <=  Q(0) AND Q(1) AND Q(2) AND Q(3) AND CE;  --- CEO output

end Behavioral;

图如下所示。

enter image description here

2 个答案:

答案 0 :(得分:1)

问题可能是CE_CLOCK <= (CLOCK and (CE or Load));时钟逻辑的结果,因为这可能会为多个增量时间步骤创建多个时钟转换,但是在相同的仿真时间。

如果触发器更新必须是有条件的,那么在翻转流程上启用时钟,使用以下代码:

process (clk, rst) is
begin
    if rising_edge(clk) then
        if cen = '1' then  -- Clock Enable (cen)
            q <= d;
        end if;
    end if;
    if rst = '1' then
        q <= '0';
    end if;
end process;

答案 1 :(得分:1)

莫滕的回答并不是整个故事

为了与Morten的答案保持一致 - 使用启用,将计数器中的D FF视为具有HOLD(Q),TOGGLE(非Q)和LOAD(D)项的输入多路复用器。

在此示例中,等效多路复用器显示为cntdin:

library ieee;
use ieee.std_logic_1164.all;

entity cntr4 is
    port (
        d:          in  std_logic_vector (3 downto 0);
        load:       in  std_logic;
        reset:      in  std_logic;
        enable:     in  std_logic;
        clk:        in  std_logic;
        q:          out std_logic_vector (3 downto 0);
        enab_out:   out std_logic
    );
end ;

library ieee;
use ieee.std_logic_1164.all;

entity dff is
    port (
        d:      in  std_logic;
        clk:    in  std_logic;
        q:      out std_logic
    );
end entity;

architecture behave of dff is

begin
    process(clk)
    begin
        if rising_edge(clk) then
            q <= d;
        end if;
    end process;
end architecture;

architecture struct of cntr4 is

    component dff is
        port (
            d:      in  std_logic;
            clk:    in  std_logic;
            q:      out std_logic
        );
    end component;

    signal cntincr,cntd,cntq: std_logic_vector (q'range);

    begin

cnt_incr:         -- incrementer
    process(cntq)   
    begin
        cntincr(0) <= not cntq(0);
        cntincr(1) <= cntq(1) xor cntq(0);
        cntincr(2) <= cntq(2) xor (cntq(0) and cntq(1));
        cntincr(3) <= cntq(3) xor (cntq(0) and cntq(1) and cntq(2));
    end process;

cntdin:
    for i in cntd'range generate
        cntd(i) <= (cntq(i)    and not reset and not enable) or
                   (d(i)       and not reset and     enable and     load) or
                   (cntincr(i) and not reset and     enable and not load);
    end generate;

cntreg:
    for i in cntq'range generate
        D_FF: dff 
            port map (
                d => cntd(i),
                clk => clk,
                q => cntq(i)
            );
    end generate;

cntptr:
    q <= cntq;

en_out:
    enab_out <= enable and cntq(0) and cntq(1) and cntq(2) and cntq(3);    

end architecture;

在此示例中,您几乎可以免费获得同步复位(AND / OR中每个AND的一个输入)。它使用触发器而无需异步复位或启用。

借用cntr4的测试平台并添加not_reset以反转重置以匹配SyncCounter:

library ieee;
use ieee.std_logic_1164.all;

entity cntr4_tb is
end entity;

architecture foo of cntr4_tb is

    signal d:          std_logic_vector (3 downto 0);
    signal load:       std_logic;
    signal reset:      std_logic;
    signal enable:     std_logic;
    signal clk:        std_logic := '1';
    signal q:          std_logic_vector (3 downto 0);
    signal enab_out:   std_logic;
    signal reset_not:  std_logic;

begin

    reset_not <= not reset;

DUT:
    entity 
    work.SyncCounter
        port map (
                CLOCK => clk,
                D => d,
                Q => q,
                CE => enable,
                Load => load,
                Reset => reset_not,
                CEO => enab_out
        );

CLOCK:
    process
    begin
        wait for 10 ns;
        clk <= not clk;
        if Now > 720 ns then
            wait;
        end if;
    end process;

STIMULUS:
    process
    begin
        wait for 10 ns;
        reset <= '1';
        load <= '0';
        d <=  X"5";
        enable <= '0';
        wait for 30 ns;
        reset <= '0';
        wait for 30 ns;
        load <= '1';
        enable <= '1';
        wait for 20 ns;
        load <= '0';
        enable <= '0';
        wait for 20 ns;
        enable <= '1';
        wait for 80 ns;
        enable <= '0';
        wait for 20 ns;
        enable <= '1';
        wait;

    end process;
end architecture;

我们发现你的SyncCounter显然有效:

SyncCounter using cntr4_tb test bench

那为什么会有效?

如果您注意到所有输入激励有效地匹配时钟边沿,并且具有0 delta延迟差异,并且恰好在另一个时钟边沿上运行。

如果没有CE和负载上的增量周期相干转换,您可以获得由增量周期偏移引起的额外正时钟边沿。这里有几条消息。

  1. 门控时钟应该与恐惧一起使用。

  2. 时钟门的输出通常应为高电平,通常不像CE_CLOCK那样低。您将使用CLOCK的低波特率在CE_CLOCK上生成正转换,而不是使用CLOCK的Load或CE AND&d的正事务。

  3. 测试平台导致CE_CLOCK在安全时间内被门控,因此SyncCounter可以工作。

    您可以使用带有启用功能的触发器,包含启用的输入多路复用器或尝试切换CE_CLOCK空闲状态的意义。

    它没有意外复位,启用和加载启用通常是否定的。当门控时钟时,可以使用NOT AND NOT门(OR门De Morgan等效门)完成,从而节省门延迟。门控时钟的时钟偏差可以减少到一个门延迟。

    门控时钟的吸引力来自节电。

    如果你想合成计数器,你可能会发现使用门控时钟有点强烈不鼓励。

    显示时钟故障

    因为我们可能没有将delta delta循环粒度事件发布到波形转储的模拟器,所以两者 CE和早期加载1 nsec:

    both CE and Load 1 ns before clock edge

    在此波形捕获中,您可以清楚地看到故障以及计数器的位置是双倍的&#39;递增。

    您还可以注意到时钟上升沿由时钟边沿前1 ns的CE和Load,Q(3 downto 0)驱动。

    将CE_CLOCK更改为常高:

    -- CE_CLOCK <=  (CLOCK and (CE or Load));
    
       CE_CLOCK <= CLOCK or  not (CE or Load);
    

    失去毛刺,并在时钟边缘排列Q(3 downto 0)过渡:

    CE_CLOCK_STALLS HIGH