Search code examples
vhdlmodelsimquartus

What's wrong with this VHDL code - BCD Counter?


I'm studying VHDL right now, and I have a pretty simple homework assignment - I need to build a synchronous BCD counter that will count from 0 to 9 and when it reaches 9, will go back to 0. I wanted to experiment a little so I decided not to do the code in a (at least the way I see it) traditional way (with if, elseif) but with the when-else statement (mostly due to the fact that counter is from 0 to 9 and has to go back to 0 once it hits 9).

library IEEE;
    use IEEE.std_logic_1164.all;

Entity sync_counter is
    port (rst, clk: in std_logic);
end Entity;

Architecture implement of sync_counter is
    signal counter: integer range 0 to 10;
Begin
        counter <=    0 when (rst = '1') else
                      counter + 1 when (clk='1' and clk'event) else
                      0 when (counter = 10);
end Architecture;

So everything compiles, but in the simulation, initially counter jumps from 0 to 2, but after a cycle (0-9 - 0) it is acting normal, meaning counter goes from 0 to 1 as it should be. Same if you force rst = '1'.

Simulation image: BCD Counter simulation

Why does it jump from 0 to 2 in the start?

Thank you.


Solution

  • It may not explain why it goes from 0 to 2. Please post your testbench code on that front. However, your code is bad. This code translate to this, with comments:

    process(rst, clk, counter)
    begin
        if rst = '1' then -- Asynchronous reset, so far so good
            counter <= 0;
        elsif clk'event and clk = '1' then -- Rising edge, we got an asynchronous flip-flop?
            counter <= counter + 1;
        elsif counter = 10 then -- What is this!?! not an asynchronous reset, not a synchronous reset, not a clock. How does this translate to hardware?
            counter <= 0;
        end if;
    end process;
    

    I'm not sure if this would work in hardware, but I can't quickly figure out how it would be implemented, what you want is this:

    process(rst, clk)
    begin
        if rst = '1' then -- Asynchronous reset
            counter <= 0;
        elsif clk'event and clk = '1' then
            if counter = 9 then -- Synchronous reset
                counter <= 0;
            else
                counter <= counter + 1;
            end if;
        end if;
    end process;
    

    I leave the "when-else" statements for purely combinational code, or at most to the single line reg <= value when rising_edge(clk).