3
\$\begingroup\$

I have a 100 Mhz clock and I need a 0.5 Khz clock. So I wrote this code:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity clkdiv is
    Port ( clk : in STD_LOGIC;
           reset : in STD_LOGIC;
           clkout : out STD_LOGIC);
end clkdiv;

architecture Behavioral of clkdiv is
signal temporal : std_logic := '0';
signal counter : integer range 0 to 99999 := 0;
begin
process (reset, clk) begin
if (reset = '1') then
       temporal <= '0';
       counter  <= 0;
elsif rising_edge(clk) then
    if (counter = 99999) then
        temporal <= not temporal;    
        counter <= 0;
    else
        counter <= counter + 1;
    end if;
end if;
end process;
clkout <= temporal;

end Behavioral;

And testbench for it:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;



entity testbench is
    
end testbench;

architecture Behavioral of testbench is
component clkdiv
Port ( clk : in STD_LOGIC;
           reset : in STD_LOGIC;
           clkout : out STD_LOGIC);
           end component;
 
signal clk : std_logic := '0';
signal reset : std_logic := '0';
signal clkout : std_logic;
constant clk_in_t : time := 10 ns;
        
begin
uut : clkdiv port map (
    clk => clk,
    reset => reset,
    clkout => clkout);
    
    process
    begin
    clk <= '0';
    wait for clk_in_t / 2;
    clk <= '1';
    wait for clk_in_t / 2;
    end process;
    
process
    begin
    reset <='1';
    wait for 100 ns;
    reset <= '0';
    wait;
    end process;
end;

However, testbench results are like that: enter image description here

Can anyone tell me what's wrong? Thank you all.

\$\endgroup\$
12
  • 1
    \$\begingroup\$ What did you expect to happen and how is the result different? \$\endgroup\$ – The Photon Sep 10 '20 at 17:54
  • 2
    \$\begingroup\$ A 0.5 kHz clock changes state once every millisecond, but you only ran the simulation for 1 microsecond. \$\endgroup\$ – The Photon Sep 10 '20 at 17:58
  • 2
    \$\begingroup\$ You do realise you can look at "counter" in the wave window to see if it's counting, right? \$\endgroup\$ – user_1818839 Sep 10 '20 at 19:09
  • 3
    \$\begingroup\$ This is bad practice. You do not divide clocks in logic fabric. What you do is periodically trigger things using a clock enable instead and have it running off the real clock. If you truly need a lower frequency clock then use the FPGA's PLL. \$\endgroup\$ – DKNguyen Sep 10 '20 at 21:32
  • 4
    \$\begingroup\$ To echo DKN, it's never a good idea to generate a low speed clock in FPGA. It looks easy, but it leads to all sorts of timing problems. Clock everything from the same system-wide high speed clock, and generate a 500 Hz clock enable signal to feed to your low speed logic, to tell it when to change, and when not to. \$\endgroup\$ – Neil_UK Sep 10 '20 at 21:49
3
\$\begingroup\$

I've rounded up all the good advice from the comments into an answer.

Clock Strobe

Generates a slower strobe from a faster clock.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity ClockStrobe is
    generic
    (
        CLOCK_PERIOD : time := 20 ns;
        STROBE_PERIOD: time := 2 ms
    );
    port
    (
        reset : in std_logic;
        clock : in std_logic;
        strobe: out std_logic
    );
end entity;

architecture V1 of ClockStrobe is

    constant MAX_COUNT: natural := STROBE_PERIOD / CLOCK_PERIOD - 1;
    signal counter: natural range 0 to MAX_COUNT := 0;  -- Specify the range to reduce number of bits that are synthesised.

begin

    process(all)
    begin
        if reset then
            strobe <= '0';
            counter <= 0;
        elsif rising_edge(clock) then
            if counter = MAX_COUNT then
                strobe <= '1';
                counter <= 0;
            else
                strobe <= '0';
                counter <= counter + 1;
            end if;
        end if;
    end process;

end architecture;

Test Bench

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;

entity ClockStrobe_TB is
end;

architecture V1 of ClockStrobe_TB is

    constant clock_period : time := 10 ns;
    constant STROBE_PERIOD: time := 2 ms;
    -- constant CLOCK_PERIOD : time := 10 ns;
    -- constant STROBE_PERIOD: time := 40 ns;

    signal halt_sys_clock: boolean := false;

    signal reset: std_logic := '0';
    signal clock: std_logic := '0';
    signal strobe: std_logic;

    component ClockStrobe is
        generic
        (
            CLOCK_PERIOD : time := 20 ns;
            STROBE_PERIOD: time := 2 ms
        );
        port
        (
            reset : in std_logic;
            clock : in std_logic;
            strobe: out std_logic
        );
    end component;

begin

    ClockGenerator:
    process
    begin
        while not halt_sys_clock loop
            clock <= not clock;
            wait for CLOCK_PERIOD / 2.0;
        end loop;
        wait;
    end process ClockGenerator;

    Stimulus:
    process
    begin
        -- Do reset.
        wait for CLOCK_PERIOD / 4;
        reset <= '1';
        wait for CLOCK_PERIOD / 2;
        reset <= '0';

        -- Wait for a couple of strobes.
        wait for 2.1 * STROBE_PERIOD;

        -- Halt simulation.
        halt_sys_clock <= true;
        wait;
    end process;

    CS:
        ClockStrobe
        generic map
        (
            CLOCK_PERIOD => CLOCK_PERIOD,
            STROBE_PERIOD => STROBE_PERIOD
        )
        port map
        (
            reset => reset,
            clock => clock,
            strobe => strobe
        );

end architecture;

Simulation Results

Clock Strobe Simulation Results

Figure 1 – Clock strobe simulation results: 100 MHz clock; 500 Hz strobe.

Using the Clock Strobe

And here is how to use the clock strobe for slow logic.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity SlowLogic is
    port
    (
        reset : in std_logic;
        clock : in std_logic;
        strobe: in std_logic
        -- Slow inputs and outputs here.
    );
end entity;

architecture V1 of SlowLogic is

begin

    process(all)
    begin
        if reset then
            -- Reset slow outputs, etc.
        elsif rising_edge(clock) then
            if strobe then
                -- Do slow logic on inputs and outputs.
            end if;
        end if;
    end process;

end architecture;
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Perhaps a remark: without any additional timing constraints for synthesis, the "slow logic" updates at the slow clock but is synthesized at 100MHz. \$\endgroup\$ – P2000 Sep 21 '20 at 20:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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