VHDL coding tips and tricks: VHDL: Difference between rising_edge(clk) and (clk'event and clk='1')

Thursday, April 8, 2010

VHDL: Difference between rising_edge(clk) and (clk'event and clk='1')

    Generally you might have noticed that there are two ways in which we can detect the edge of a clock. 
  1. rising_edge(clk) or falling_edge(clk).
  2. clk'event and clk='1' or clk'event and clk='0'

    You might have been using either of these methods without really understanding if there is a difference between them. But there is a difference between them and this article intends to bring clarity on this.

Consider the following VHDL snippet:

clk_process : process
begin
    clk <= '0';
    wait for clk_period/2; --for 0.5 ns signal is '0'.
    clk <= '1';
    wait for clk_period/2; --for next 0.5 ns signal is '1'.
end process;

process(clk)
begin
    if(rising_edge(clk)) then
        xr <= not xr;
    end if;

    if(clk'event and clk='1') then
        x0 <= not x0;
    end if;
end process;

When the value of clk goes from '0' to '1', that is when it changes from low to high, I toggle the bits, xr and x0. If you run the above code, the simulation waveform will look like this:

vhdl rising edge and clk'event difference

Now you may ask where is the difference? There is no difference in this particular case. But let us slightly change the code snippet as follows:

clk_process : process
begin
    clk <= 'Z';          ----------Here is the change('Z' instead of '0').
    wait for clk_period/2; --for 0.5 ns signal is 'Z'.
    clk <= '1';
    wait for clk_period/2; --for next 0.5 ns signal is '1'.
end process;

process(clk)
begin
    if(rising_edge(clk)) then
        xr<= not xr;
    end if;

    if(clk'event and clk='1') then
        x0 <= not x0;
    end if;
end process;

The only difference in the new code is that instead of clk toggling between '0' and '1', we toggle it between 'Z' and '1'. Lets look at the simulation waveform:

vhdl rising edge and clk'event difference

Does this ring any bells? You can see that the signal xr doesn't change at all, while x0 changes just like it did in the first snippet. Why? To know why, lets look at the definition of rising_edge function as implemented in std_logic_1164 library:

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;

    As you can see the function returns TRUE only when the present value is '1' and the last value is '0'. If the past value is something like 'Z','U' etc. then it will return FALSE. This makes the code bug free, because the function returns only valid clock transitions, that means '0' to '1'. All the rules and examples shared above equally apply to falling_edge() function also.

The statement clk'event and clk='1' results in TRUE when the present value is '1' and there is an edge transition in the clk. It doesnt check whether the previous value is '0' or not.

Note :- Use rising_edge() or falling_edge() functions instead of clk'event statements in your VHDL projects.

18 comments:

  1. you have explained it beautifully !!

    ReplyDelete
  2. Thanks, This helped me out a lot!

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. What is the mean of sentence "Does this ring any bells?".
    I am not a negative English.

    Your explain is very good.thank you very much!

    ReplyDelete
  5. In a practical sense, can this happen with a real clock 1, Z, 1, Z,...

    ReplyDelete
    Replies
    1. if tri-states are involved + your netlist has errors + you're running a cross-simulation (i.e. part of your design is the synthesized netlist and other part is an rtl) then you might see something similar.

      I've seen similar things during cross simulation.

      Regards,
      AR

      Delete
  6. good explanation.
    @solosys, if the clock has a weak pull-up, then your 'Z' will be '1', and in this case, there will not be any transition since it's a '1' to '1'. So (clk'event and clk='1') will fire, but again rising_edge(clk) will not fire, because the previous value was 'Z' (and at the board level, it's weakly pulled to '1'). So, rising_edge() and falling_edge() will really check if there is a transition from '0' to '1' (or '1' to '0'), and like vipin said, makes it safe and bug free.

    ReplyDelete
  7. But how do these two translate into gate level? Both the coding styles generate a rising/falling edge flip flop.
    Is there a type of flip flop which can detect a weak pull up?

    ReplyDelete
    Replies
    1. At gate level, you traditionally, with discrete devices,may use two inverters and a gate(could be xor for a positive pulse). the clock is coupled to the two inverters in series and at the same time to one of the inputs at the xor gate. In real life, the two inverters have more delay than a cable, so for the propagation delay time of two inverters, you will get a pulse from the xor gate. see more about this and how to implement it on google OR this site(quite good) :http://www.twyman.org.uk/clock_recovery/, go down to the edge detection part.

      Delete
  8. Only your simulation is 'bug free' by using rising_edge()/falling_edge(). The SYNTHESIZED logic will be deterministic. Here is a FAIL example where these functions will kick you in the face:
    In the case of an input used a a clock: a valid clock edge could also be 'L' to '1' and 'H' to '0'. These would be ignored by the rising_edge() and falling_edge() functions. An example of this would be a wire-or edge triggered interrupt input. So 'glitch free' becomes 'wrong'.

    ReplyDelete
    Replies
    1. This is not true, 'L' to '1' and 'H' to '0' transitions will be picked up by rising_edge() and falling_edge() due to the To_X01() conversion function which maps 0 -> 0, 1 -> 1, H -> 1, L -> 0 and others -> X thus 'L' to '1' and 'H' to '0' transitions will be seen by the functions as '0' to '1' and '1' to '0' transitions.

      Delete
  9. Actually dshawnw, I believe you might be wrong. If you look again at the definition of rising_edge/falling_edge functions, the signal is passed through a "To_X01" conversion table which converts 'H' to '1' and 'L' to '0' before the comparison is evaluated, so the comparisons still hold true for 'L' to '1' and 'H' to '0' transitions just as they do for '1' to '0' and '0' to '1'.

    ReplyDelete
  10. its realllllly good, great explaination, thank u for ur help

    ReplyDelete
  11. thanks for explaining superbly with an example! :)

    ReplyDelete
  12. Very good explanation. Thank you

    ReplyDelete