VHDL 异步纹波计数器毛刺

VHDL asynch ripple counter glitch

这是一个 4 位异步纹波计数器的设计(使用 T 触发器,但我没有为 Tff 定义组件,只是编写了关于 T 信号的电路行为)。

问题如下:

1.) inout 端口,我首先定义Q为inout(因为它显然是我的输出并且这些位也被用作clk 输入到他们的后续触发器)。尽管如此,当我想模拟我的代码时,Q 输出是 UUUU,这是有道理的,因为我必须用我希望计数开始的数字来初始化它。虽然我不知道如何设置 inout 初始值(我试过 Process ... Q <= "0000"; wait; end process 但它没有用)!

2.) 为了解决上述问题,我将我的 inout 端口更改为 out (Q_out) 并将 Q 定义为信号,这有效但是......我的计数器只改变了 Q (0) 位而不是其他位...因此它的计数如下:0,1,0,1,0,1,...

3.) 我想调试这段代码。我尝试了另一种风格,除了 4 个内部信号 Q0 到 Q1 之外,我定义了 4 个 1 位输出信号(Q_out1 到 Q_out2)而不是 4 位输出,这非常有效 我只想知道为什么第一种样式(Q 作为 4_bit 向量)没有成功。 预先感谢您的帮助。

这是我的代码及其测试平台:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;


entity four_bit_Asynch_Counter is
    Port ( T0,T1,T2,T3 : in  STD_LOGIC;
           clk : in  STD_LOGIC;
              Q_out: out STD_LOGIC_VECTOR (3 downto 0));
end four_bit_Asynch_Counter;

architecture Behavioral of four_bit_Asynch_Counter is   

signal Q : STD_LOGIC_VECTOR (3 downto 0) := "0000";

begin
    Process (clk,Q(0),Q(1),Q(2))
        begin
            if (falling_edge(clk)) then
                if (T0 = '1') then
                    Q(0) <= not Q(0);
                else 
                    Q(0) <= Q(0);
                end if;
            end if;

            if (falling_edge(Q(0))) then
                if (T1 = '1') then
                    Q(1) <= not Q(1);
                else 
                    Q(1) <= Q(1);
                end if;
            end if;

            if (falling_edge(Q(1))) then
                if (T2 = '1') then
                    Q(2) <= not Q(2);
                else 
                    Q(2) <= Q(2);
                end if;
            end if;

            if (falling_edge(Q(2))) then
                if (T3 = '1') then
                    Q(3) <= not Q(3);
                else 
                    Q(3) <= Q(3);
                end if;
            end if;

            Q_out <= Q;
    end Process;
end Behavioral;

----------------测试台------------

     LIBRARY ieee;
    USE ieee.std_logic_1164.ALL;


    ENTITY tb_counter IS
    END tb_counter;

    ARCHITECTURE behavior OF tb_counter IS 

    -- Component Declaration for the Unit Under Test (UUT)

    COMPONENT four_bit_Asynch_Counter
    PORT(
         T0 : IN  std_logic;
         T1 : IN  std_logic;
         T2 : IN  std_logic;
         T3 : IN  std_logic;
         clk : IN  std_logic;
         Q_out : OUT  std_logic_vector(3 downto 0)
        );
    END COMPONENT;


   --Inputs
   signal T0 : std_logic := '1';
   signal T1 : std_logic := '1';
   signal T2 : std_logic := '1';
   signal T3 : std_logic := '1';
   signal clk : std_logic := '0';

    --Outputs
   signal Q_out : std_logic_vector(3 downto 0);

   -- Clock period definitions
   constant clk_period : time := 10 ns;

BEGIN

    -- Instantiate the Unit Under Test (UUT)
   uut: four_bit_Asynch_Counter PORT MAP (
          T0 => T0,
          T1 => T1,
          T2 => T2,
          T3 => T3,
          clk => clk,
          Q_out => Q_out
        );

   -- Clock process definitions
   clk_process :process
   begin
        clk <= '0';
        wait for clk_period/2;
        clk <= '1';
        wait for clk_period/2;
   end process;


   -- Stimulus process
   stim_proc: process
   begin        
      -- hold reset state for 100 ns.
      wait for 100 ns;  

      wait for clk_period*10;

      -- insert stimulus here 

      wait;
   end process;

END;

在可实现的硬件(ASIC 或 FPGA)中实现计数器时,永远不要使用纹波计数器。通过将触发器输出用作下一个时钟,您将获得次优时序,这些工具将无法准确验证设置和保持时间,并且您无法利用专用时钟路由。一般来说,异步设计对于实际实现来说是个坏主意。

真正的同步设计更适合综合,并且更容易在 VHDL 代码中推断。

Examples of Counter implementations

有关计数器实现的 verilog 和 vhdl 示例,请参阅上面的 link。

TL;DR 的答案是 q(3) 没有出现在您的过程敏感度列表中。

architecture behavioral of four_bit_asynch_counter is   
    signal q:  std_logic_vector (3 downto 0) := "0000";
begin
    process (clk, q(0), q(1), q(2))
    begin
        if  falling_edge(clk) then
            if t0 = '1' then
                q(0) <= not q(0);
            -- else
            --     q(0) <= q(0);
            end if;
        end if;

        if  falling_edge(q(0)) then
            if t1 = '1' then
                q(1) <= not q(1);
            -- else
            --     q(1) <= q(1);
           end if;
        end if;

        if falling_edge(q(1)) then
            if t2 = '1' then
                q(2) <= not q(2);
            -- else
            --     q(2) <= q(2);
            end if;
        end if;

        if falling_edge(q(2)) then
            if t3 = '1' then
                q(3) <= not q(3);
            -- else
            --     q(3) <= q(3);
            end if;
        end if;

        q_out <= q;

    end process;
end  architecture behavioral;

对于您的过程敏感度列表,您发现了敏感度列表是如何从由主要元素组成的表达式构建的一个特征 - clk, q(0), q(1), q(2)

来自 IEEE Std 1076 -1993,8.1 等待语句:

...
The sensitivity set is initially empty. For each primary in the condition of the condition clause, if the primary is

-- A simple name that denotes a signal, add the longest static prefix of the name to the sensitivity set

-- A selected name whose prefix denotes a signal, add the longest static prefix of the name to the sensitivity set

-- An expanded name whose prefix denotes a signal, add the longest static prefix of the name to the sensitivity set

-- An indexed name whose prefix denotes a signal, add the longest static prefix of the name to the sensitivity set and apply this rule to all expressions in the indexed name ...

...
此规则还用于在并发过程调用语句 ( 9.3 )、并发断言语句 ( 9.4 ) 和并发信号分配语句 ( 9.5 ) 的等效过程语句中构造等待语句的敏感度集。

如果表示复合类型信号的信号名称出现在灵敏度列表中,则效果就好像该信号的每个标量子元素的名称都出现在列表中一样.
...

我只包含了此处感兴趣的规则元素,第一个包含时钟,显示的最后一个元素包含所选名称指定的 std_logic_vector 个元素。

有助于理解最长静态前缀的含义。这在 -1993 6.1 名称中进行了解释。

主要(索引名称)是静态名称(q(0), q(1), q(2)),每个索引名称中的每个表达式都是静态的。

这意味着最长的静态前缀是包含每个主要名称的索引名称。

这让 q(3) 悬而未决的过程信号分配语句:

        q_out <= q;

如果对 q(3) 不敏感,q_out 的值直到敏感列表中的下一个事件才更新,该事件恰好在 clk:

有两种方法可以解决这个问题,您可以将 q_out 赋值移动到流程语句之外,在那里它成为并发信号赋值(具有详细的等效流程,敏感度列表设置为 q), 或者你可以在当前进程中更改敏感列表:

        process (clk, q)

以便为 q(3) 上的事件更新 q_out(注意上面 8.1 中引用的最后一段)。

此行为也适用于标准的后续修订版。

随着进程的敏感度列表是固定的:

您的计数器运行正常。

另请注意,我注释掉了对 q(0)q(1)q(2)q(3) 的冗余 else 分配,信号将保持其值直到分配,这些是顺序(时钟)语句。还删除了多余的括号对。