2

I have a question about the process that I wrote to divider a 1MHz clock down to a 10kHz clock.

I don't know why my code always splits up like it does below, if someone can edit it to look better and let me know what I am doing wrong.

Now my question is how are the if and elsif statements inside the process performed? On the rising edge of the clock, the Count signal will be incremented by 1. But will the elsif statement ever be executed as the if statement will have to be true?

Include libraries / packages

Entity Clock_Divider is
 Port (Clock_in : in std_logic;
       Clock_out : out std_logic
      );
end Clock_Divider;

Architecture Behavioral of Clock_Divider is

signal Count : integer := 1;
    
signal Temp : std_logic := '0';

begin

    Process (Clock_in)

    begin

    if (rising_edge(Clock_in)) then
           Count  <= Count + 1;

        elsif (Count = 100000) then
              Temp <= not Temp;

        end if;

        Clock_out <= Temp;

    end Process;

end Behavioral;
David777
  • 1,548
  • 12
  • 29

3 Answers3

2

This will "work" in simulation, for a bad definition of "to work".

Assuming a normal clock, this are the process invocations:

  • Clock rises, if(rising_edge(clock_in)) is taken, you increment Count
  • Clock falls, the elsif is checked, if you reached the limit on the previous rising edge, you will toggle Temp and then update the out clock.

As you can see, you rely on the sensitivity list for logic, that's never a good idea. Both because it's more obscure code and because it likely won't do what you want post-synthesis, where most toolchains just ignore sensitivity lists alltogether (as they should).

A cleaner solution for a clock divider would be:

p_clock_div : process(clk_in)
  variable r_count : integer range 0 to c_count_max := c_count_max;
  variable r_clk_out_i : std_logic := '0';
begin
  if rising_edge(clk_in) then
    r_count := r_count - 1;
    if r_count = 0 then
      r_clk_out_i := not r_clk_out_i;
      r_count := c_count_max;
    end if;
  end if;
  clk_out <= r_clk_out_i;
end process;

Or, if you want that falling edge update, then show so in your code:

p_clock_div : process(clk_in)
  variable r_count : integer range 0 to c_count_max := c_count_max;
  variable r_clk_out_i : std_logic := '0';
begin
  if rising_edge(clk_in) then
    r_count := r_count - 1;
  elsif falling_edge(clk_in) then
    if r_count = 0 then
      r_clk_out_i := not r_clk_out_i;
      r_count := c_count_max;
    end if;
  end if;
  clk_out <= r_clk_out_i;
end process;

Note that some (mainly ASIC targetting) synthesizers don't like the clock_out <= r_clock_out_i line to be outside the if tree.

Also note that clock_out has an undefined startup state and this whole block would be cleaner if you had a clk_in-synchronized reset input signal.

DonFusili
  • 1,069
  • 7
  • 10
  • Thanks Don, I see how this is bad code. I don't intend to use the falling edge of the clock so I will change to have all the signal assignment inside the elsif ((rising_edge)). What is your opinion about having the clock_out assignment inside the process instead of outside of the process? – David777 Mar 03 '21 at 10:58
  • 1
    @David777 I think you should do everything inside a single process per clock domain in a module. If you do that and use variables instead of signals wherever possible, your code is easier to read and automatically avoids delta cycle issues. There are... philosophical arguments about the subject, however. – DonFusili Mar 03 '21 at 11:03
  • Ok, I suppose if the signal is synchronous with the clock it makes sense to include it inside the process body. – David777 Mar 03 '21 at 11:40
  • 2
    @DonFusili It always astonishes me that we are still using this language in an unintended way and using hacky workarounds to make it fit. Why not a language where you can *only* have a single process per clock domain in a module? – user253751 Mar 03 '21 at 11:42
  • 1
    @user253751 Tbf, the "description" in VHDL has been meaningless for a while now and most of the issues the language has as an implementation language disappear if you use it properly. Properly sadly being "the other way than most respected people in the field have taught themselves over the last few decades". But yeah, a clean language would probably be better... could be worse, though, could be verilog. – DonFusili Mar 03 '21 at 11:49
  • @DonFusili Within your process, on the rising edge of the clock the first if statement will obviously be true and r_count will be decremented by 1. Will the second if statement be checked even if the first if statement is true? I don't truly understand if statements in VHDL. – David777 Mar 03 '21 at 13:40
  • 1
    @David777 I'm not sure which of the two written processes you are talking about, but every `if` statement will be checked, unless they use an `elsif`, just like in any programming language. In the second process, I reset `r_count` on the falling edge of the clock. A signal cannot have a rising and a falling edge in the same delta cycle. – DonFusili Mar 03 '21 at 14:05
  • @DonFusili Ok, I see. I have edited my question above if you would like to read my new code. – David777 Mar 04 '21 at 13:10
  • @David777 Have you simulated that code? What do you see when you do? Also, you got answers to your original question and are misusing the SE format. – DonFusili Mar 04 '21 at 13:20
  • @DonFusili I will remove the edit then. – David777 Mar 04 '21 at 13:23
2

This won't work as it creates a latch on your Temp signal. You should perform all the signal manipulation within your if rising_edge(clk) then and last but not least you have to reset your Count. In addition it might make sense to have a reset signal. Use a counter signal with a defined width, I'd even prefer unsigned over integer. Then, to save some resources, it's easier to load the counter with the starting value and decrement instead of increment, then check for the MSB = '1' what will be the case if the counter overflows.

ARCHITECTURE behavioural OF clockdivider IS
  SIGNAL counter : std_logic_vector(log2_ceil(div_value)+1 DOWNTO 0);
  SIGNAL clk_int : std_logic;
BEGIN

  clk_out <= clk_int;

  clk_div : PROCESS(clk_i,rst_i)
  BEGIN
      IF div_value = 0 THEN
      clk_int <= clk_i;
  
    -- asynchronous reset
    ELSIF rst_i = '1' THEN
      counter <= std_logic_vector(to_unsigned(div_value-2, counter'LENGTH));
      clk_int <= '0';

    ELSIF rising_edge(clk_i) THEN
            IF enable = '1' THEN
                IF counter(counter'LEFT) = '1' THEN
                    clk_int <= NOT(clk_int);
                    counter <= std_logic_vector(to_unsigned(div_value-2, counter'LENGTH));
                ELSE
                    counter <= std_logic_vector(signed(counter) - 1);
                END IF;
            ELSE
                clk_int <= '0';
            END IF;

    END IF;
  END PROCESS clk_div;
  
END ARCHITECTURE behavioural;
po.pe
  • 2,548
  • 1
  • 10
  • 25
  • Why would you prefer `unsigned` over `integer`s? They simulate slower. I second the decrementing, though, it's a better pattern for counting in general. – DonFusili Mar 03 '21 at 09:45
  • Probably just personal preference, but it's easier to cast it into `std_logic_vector` – po.pe Mar 03 '21 at 09:47
2

For real implementation, better way is not to tweak the clock signal and to reroute it somewhere else, but to provide a "clock enable" signal that is enabled every 100'000 cycle.

Port the original clock (100 MHz) in the module that requires the 10 KHz clock. Modify the module so that its logic is enabled only if the clock_ena signal from the divider is high at the rising edge of original 100 MHz clock.

am9417
  • 123
  • 5
  • I am curious as to why this is better for 'real implementation'? So you mean to still keep the clock divider module and inside it produce a clock enable signal for the other module that needs the slow clock? – David777 Mar 20 '21 at 14:15