简体   繁体   中英

VHDL asynch ripple counter glitch

Here is a design for 4-bit asynchronous ripple counter (using T flip flop however I didn't define a component for Tff and just coded the behavior of circuit regarding T signals).

Following are the questions:

1.) inout ports, I first defined Q as inout (since it's obviously my output and the bits are also used as clk inputs to their following flip flops). Still, when I wanted to simulate my code, the Q output was UUUU which makes sense cause I had to initialize it with the number I wanted my count to begin with. Though I didn't know how to set an inout initial value (I tried Process ... Q <= "0000"; wait; end process but it didn't work)!

2.) In order to solve the above-mentioned problem I changed my inout port to out (Q_out) and defined Q as a signal, this worked BUT...my counter only changed the Q(0) bit and not the others...thus it counts like: 0,1,0,1,0,1,...

3.) I want to debug this code. I tried another style, instead of a 4-bit output I defined 4 1-bit output signals (Q_out1 to Q_out2) in addition to 4 internal signals Q0 to Q1 and this perfectly works I just want to know why the first style (Q as a 4_bit vector) didn't work out. thanks in advance for your help.

Here is my code and its test bench:

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;

--------------- Test Bench------------

     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;

When implementing counters in realisable hardware (either ASIC or FPGA) you should never use a ripple counter. By using the flip-flop output as a clock to the next you will have sub-optimal timing, the tools will not be able to accurately validate the setup and hold times and you are not able to take advantage of dedicated clock routing. In general asynchronous design is a bad idea for real implementations.

A true synchronous design will be much better for synthesis and is much easier to infer in the VHDL code.

Examples of Counter implementations

See the above link for both verilog and vhdl examples of counter implementation.

The TL;DR answer is that q(3) doesn't show up in your process sensitivity list.

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;

For your process sensitivity list you've discovered a feature in how the sensitivity list is constructed from the expression consisting of primaries - clk, q(0), q(1), q(2) .

From IEEE Std 1076 -1993, 8.1 Wait statement:

...
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 ...

...
This rule is also used to construct the sensitivity sets of the wait statements in the equivalent process statements for concurrent procedure call statements( 9.3 ), concurrent assertion statements ( 9.4 ), and concurrent signal assignment statements ( 9.5 ).

.
...

I only included elements of the rule that are of interest here, the first covers the clock the last element shown covers the std_logic_vector elements specified by selected names.

It helps to understand what is meant by the longest static prefix. This explained in -1993 6.1 Names.

The primaries (indexed names) are static names ( q(0), q(1), q(2) ), every expression that's part of each indexed name is static.

This means the longest static prefix is the indexed name comprising each primary.

And this leaves q(3) dangling in the breeze for the process signal assignment statement:

        q_out <= q;

Without sensitivity to q(3) the value of q_out is not updated until the next event in the sensitivity list, which happens to be on clk :

tb_counter

There are two ways to cure this, you could move the q_out assignment outside the process statement, where it becomes a concurrent signal assignment (with an elaborated equivalent process with a sensitivity list set to q ), or you can change the sensitivity list in the present process:

        process (clk, q)

So that q_out is updated for an event on q(3) (noting the last quoted paragraph in 8.1 above).

This behavior hold true for later revisions of the standard as well.

With the process sensitivity list is fixed:

固定灵敏度列表

Your counter behaves properly.

Also note I commented out the redundant else assignments to the q(0) , q(1) , q(2) and q(3) a signal will hold it's value until assigned and these are sequential (clocked) statements. Also eliminated the redundant parentheses pairs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM