0
\$\begingroup\$

enter image description hereI'm making a frequency divider and the easiest way is to use a johnon's counter with D flip flop. The point is that if I make the clk start high, the counter has undefined output, while if I make the clk start low, it all should be ok.

Code of ring johnson's counter ("divide_by is unusued at the moment"):

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity double_period is
    port(
        clk : in std_logic;
        --i 3 bit seguenti rappresentano 8 stati (stato 0 : divisione frequenza per     2, stato 1: divione per 4, stato 3 : divione per 6, etc...)
        divide_by : in std_logic_vector(2 downto 0);
        out_clk : out std_logic
    );
end double_period;

architecture double_period_behaviour of double_period is
signal filoFlottante : std_logic;
component ffd is
    port(
        clk : in std_logic;
        din : in std_logic;
        dout : out std_logic
    );
end component;
signal dInternal : std_logic_vector(8 downto 0);
signal dFirst : std_logic;
begin
dFirst <= not(dInternal(2));
f0 : ffd port map(clk, dFirst, dInternal(0));
f1 : ffd port map(clk, dInternal(0), dInternal(1));
f2 : ffd port map(clk, dInternal(1), dInternal(2));
--f3 : ffd port map(clk, dInternal(2), dInternal(3));
--f4 : ffd port map(clk, dInternal(3), dInternal(4));
--f5 : ffd port map(clk, dInternal(4), dInternal(5));
--f6 : ffd port map(clk, dInternal(5), dInternal(6));
--f7 : ffd port map(clk, dInternal(6), dInternal(7));
--f8 : ffd port map(clk, dInternal(7), dInternal(8));
out_clk <= dInternal(0);
end double_period_behaviour;

D FLIP FLOP CODE:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity ffd is
    port(
        clk : in std_logic;
        din : in std_logic;
        dout : out std_logic
    );
end ffd;

architecture ffd_behaviour of ffd is
begin
process(clk)
variable qvar : std_logic := '0';
begin
    if clk'event and clk='1' then
        qvar := din;
    end if;
dout <= qvar;
end process;
end ffd_behaviour;

The following is the TESTBENCH:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity double_periodTB is

end double_periodTB;

architecture double_periodTB_behaviour of double_periodTB is
component double_period is
    port(
        clk : in std_logic;

        divide_by : in std_logic_vector(2 downto 0);
        out_clk : out std_logic
    );
end component;
signal clk : std_logic;
signal out_clk : std_logic;
signal divide_by : std_logic_vector(2 downto 0);
begin
process
begin
clk <= '1'; wait for 10 ns;
clk <= '0'; wait for 10 ns;
end process;
process
begin
divide_by(0) <= '0'; wait for 10 ns;
divide_by(0) <= '0'; wait for 10 ns;
end process;
process
begin
divide_by(1) <= '0'; wait for 10 ns;
divide_by(1) <= '0'; wait for 10 ns;
end process;
process
begin
divide_by(2) <= '0'; wait for 10 ns;
divide_by(2) <= '0'; wait for 10 ns;
end process;
sg : double_period port map(clk, divide_by, out_clk);
end double_periodTB_behaviour;

"DIVIDE_BY" IS UNUSUED AT THE MOMENT!!!!

\$\endgroup\$
0

1 Answer 1

1
\$\begingroup\$

Is it normal that a clock divider made with ring johnson counter has output Undefined if clk starts high?

The short answer is Yes.

You get an event on clk assigning an initial value of '1', satisfying the if condition, assigning the value of din to qvar.

In the case of your three flip flops f0, f1 and f2 the din ports are association with either dInternal elements or the not expression of dInternal(2) using the intermediary signal dFirst.

If you were to display delta cycles in your waveform you'd see that the cause of your problem is that the assignment to dFirst occurs one delta cycle later.

For those of us who can't display delta cycles we can see that dFirst (not dInternal(2)) propagated a 'U' into the state of dbInternal because of the delta cycle delay:

double_periodtb.png (clickable)

Once in that 'U' recirculates.

You can correct the problem by using the rising_edge function found in package std_logic_1164 in your flip flop model:

library ieee;
use ieee.std_logic_1164.all;

entity ffd is
    port (
        clk:    in  std_logic;
        din:    in  std_logic;
        dout:   out std_logic
    );
end entity ffd;

architecture foo of ffd is
begin
    process (clk)
       variable qvar: std_logic := '0';
    begin
        if rising_edge(clk) then -- clk'event and clk = '1' then
            qvar := din;
        end if;
        dout <= qvar;
    end process;
end architecture;

The rising_edge function qualifies it's input with a call to function TO_01 and uses the 'LAST_VALUE attribute to determine there's actually a rising edge which means it won't trigger erroneously:

    FUNCTION rising_edge  (SIGNAL s : std_ulogic) RETURN BOOLEAN IS
    BEGIN
        RETURN (s'EVENT AND (To_X01(s) = '1') AND
                            (To_X01(s'LAST_VALUE) = '0'));
    END;

This gives:

double_periodtb_fixed_ff.png (clickable)

Just in case you were ever wondering why the rising_edge and falling_edge functions were included in package std_logic_1164, now you have a concrete example.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.