1
\$\begingroup\$

For a project, I need to write a binary counter in VHDL that starts at zero, counts to nine, and then resets to start at 0 again.

I wrote the file below, which seems like it should function correctly.

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.NUMERIC_STD.ALL;

    entity vhdlfilelab is
        Port ( clock : in STD_LOGIC;
               reset : inout STD_LOGIC
             );
    end vhdlfilelab; 

    architecture Behavioral of vhdlfilelab is
        signal timer : unsigned(3 downto 0);
    begin 

    process(clock, reset)
         if(reset = '0') then timer <= "0000";
         elsif(clock'event and clock = '1') then
              if (timer = "1010") then
                   timer <= "0000";
              else
                   timer <= timer + 1;
              end if;
         end if;
    end process;
    end Behavioral;

It seems to me that the counter should count to nine, but then be reset by the if statement. Instead, it counts to sixteen before resetting.

Why isn't the counter resetting when it reaches "1010"?

Also, not sure if this is relevant, but my "Force Clock" settings are below.

    add_force {/vhdlfilelab/clock} -radix bin {0 0ns} {1 25000ps} -repeat_every 50000ps
    add_force {/vhdlfilelab/timer[3]} -radix bin {0 0ns} {1 400000ps} -repeat_every 800000ps
    add_force {/vhdlfilelab/timer[2]} -radix bin {0 0ns} {1 200000ps} -repeat_every 400000ps
    add_force {/vhdlfilelab/timer[1]} -radix bin {0 0ns} {1 100000ps} -repeat_every 200000ps
    add_force {/vhdlfilelab/timer[0]} -radix bin {0 0ns} {1 50000ps} -repeat_every 100000ps
    run 800ns

Further testing revealed that the following file produces the same output as the above one.

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.NUMERIC_STD.ALL;

    entity vhdlfilelab is
        Port ( clock : in STD_LOGIC;
               reset : inout STD_LOGIC
             );
    end vhdlfilelab; 


    architecture Behavioral of vhdlfilelab is
        signal timer : unsigned(3 downto 0);
    begin 
        process(clock, reset)
        begin
             timer <= "0000";
        end process;
        end Behavioral;

Could the problem be with the force clock settings?

\$\endgroup\$
5
  • \$\begingroup\$ Script interfaces to simulators are not standardized while the VHDL language and it's simulation is. A testbench can be used universally. In this case I've also pointed out that timer is not reset, which can be overcome by an initial value. Also package numeric_std has an equality relational operator that can have unsigned and natural operands. Also note signals aren't updated while any process is executing, they occur elsewhere in the simulation cycle. This means when the count is 9 timer should be assigned to 0 on the clock edge. \$\endgroup\$ Jul 13 at 11:14
  • \$\begingroup\$ Thanks for your response. I tried implementing the recommended changes, but the file still doesn't work without forcing the clock, and forcing the clock provides the same results as before (the clock counts to 16 before restarting). Any other ideas? \$\endgroup\$ Jul 13 at 11:48
  • 2
    \$\begingroup\$ Simulate the testbench which instantiates the modified code. \$\endgroup\$ Jul 13 at 12:37
  • 1
    \$\begingroup\$ You have delcared a signal called timer, you haven't given it a starting value, it's good practice to assing it to all 0s so that when you add 1, you are adding it to a defined value. \$\endgroup\$
    – Puffafish
    Jul 13 at 13:43
  • \$\begingroup\$ You need to force clock and reset. You should not be forcing timer. It is an internal to your design. Going further, a real smart optimizing compiler will see that nothing anywhere can see the timer signals, so it will probably optimize those signals away - and hence, the equivalent circuit you showed - good optimization - unfortunate code. To get it to simulate, you may need to turn off some of the simulator optimizations. \$\endgroup\$
    – Jim Lewis
    Sep 13 at 1:59

3 Answers 3

-1
\$\begingroup\$

You are changing timer and then checking and reseting timer at the same time

    process(clock, reset)
    begin
        if(clock'event and clock = '1') then
            timer <= timer + 1;
            if (timer = "1010") then
                timer <= "0000";
            end if;
        end if;
    end process;

On a clock or reset event, it checks to see if it is a rising clock edge, if it is, it adds 1 to timer and at the same time says if timer is 1010, it'll change the value of timer. All these things happen at the same time in the process. So it doesn't work.

What you want to do is something more like:

    process(clock, reset)
    begin
        if(clock'event and clock = '1') then
            if (timer = "1010") then
                timer <= "0000";
            else
                timer <= timer + 1;
            end if;
        end if;
    end process;

That way timer is only changed once during the process. This does mean that 1010 will exist for a clock pulse, so you may want to change that to 1001 depending on your application.

You should also put in something to do on a reset event, otherwise why is it in the sensitivity list. But I'm guessing you knew that.

\$\endgroup\$
6
  • \$\begingroup\$ Thank you for your response. I tried implementing the suggested code, but the timer still doesn't reset at 9. Any idea why? \$\endgroup\$ Jul 13 at 10:41
  • \$\begingroup\$ @Puffafish: As a signal changes its value after the process has ended (and not during the process is running), you are not right. After the proccess has finished, the signal then changes to the last value which was assigned to it. So both code snippets you provided are correct and have exact the same behaviour. So please edit your answer. \$\endgroup\$ Jul 14 at 8:46
  • \$\begingroup\$ Why is this answer accepted? It is entirely incorrect. The two code blocks shown are identical. I think @puffafish is confusing programming code with HDL. \$\endgroup\$ Sep 11 at 18:22
  • \$\begingroup\$ Yes, I made a mistake, but I can't delete an accepted answer. \$\endgroup\$
    – Puffafish
    Sep 13 at 7:34
  • \$\begingroup\$ No worries. It happens. You could edit it, I suppose. Frankly, I think your comment to the OP regarding initializing the signal is probably the best answer :) \$\endgroup\$ Sep 28 at 14:09
2
\$\begingroup\$

How are you verifying that the counter is not working? Is it post-synthesis?

The counter doesn't drive anything, so all of its logic will be removed from the design during synthesis. From the point of view of the synthesizer, the architecture isn't needed for anything.

I would guess that the simulator is behaving similarly.

If you were to add an output to the entity, and drive it with the counter I suspect it will work.

Something like:

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

entity se_673827 is
    Port ( clock : in  std_logic;
           reset : in  std_logic;
           ofl   : out std_logic
         );
end se_673827; 

architecture Behavioral of se_673827 is
    signal timer : unsigned(3 downto 0);
begin 

    process(clock, reset)
    begin
        if (reset = '0') then
            ofl   <= '0';
            timer <= "0000";
        elsif (clock'event and clock = '1') then
            timer <= timer + 1;
            if (timer = "1010") then
                ofl   <= '1';
                timer <= "0000";
            end if;
        end if;
    end process;

end Behavioral;

My guess is that you are either forgetting that you have your reset signal set as an active-low reset (it should probably be called resetn), or your architecture is being removed from the design.

PS. This will count to 10. If you really want it to count to 9 (as you stated) you need to change your comparison to b"1001". Remember, these are clocked registers... if your if-statement sees "1010" it's because that's what your signal already is - not what it's going to be.

\$\endgroup\$
1
  • \$\begingroup\$ Also - I realize this post is quite old. \$\endgroup\$ Sep 11 at 19:16
0
\$\begingroup\$

Because you use std_logic_1164 together with std_logic_unsigned the operator "=" (in timer="1010") is defined twice. So the simulator does not know to pick which and does not pick any. That is the reason your simulation does not work. You should not use std_logic_arith and std_logic_unsigned at all, as they are not a norm and an old solution. numeric_std is the package which should be used and has a type unsigned which you should use for the signal timer.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Thank you for your response. I edited the code as suggested but it still has the same error. The counter counts to 16 before restarting. \$\endgroup\$ Jul 13 at 8:38

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.