For synchronous logic, a timer and a counter are almost the same. After all, a timer counts clock units. That is why in many digital applications we see them called timers/counters.
The code below models a generic timer/counter, using unconstrained ports:
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity downcounter is port ( clk : in std_logic; rstn : in std_logic; -- inputs data_in : in unsigned; load : in std_logic; en : in std_logic; -- outputs data_out : out unsigned; done : out std_logic ); end downcounter; architecture rtl of downcounter is -- normalize the unconstrained input alias data_in_norm : std_logic_vector(data_in'length - 1 downto 0) is data_in; -- normalized unconstrained input begin counter_pr : process (clk) begin if (rising_edge(clk)) then if (rstn = '0') then data_out <= (others => '0'); done <= '0'; elsif (load = '1') then -- load counter data_out <= unsigned(data_in_norm); done <= '0'; -- start a new countdown - deassert done signal elsif (en = '1') then -- is counting enabled? if (data_out = 0) then -- check if counter reached zero done <= '1'; -- set done output else data_out <= data_out - 1; -- decrement counter end if; end if; end if; end process counter_pr; end rtl;
In the following waveform we analyze the counter behavior:
At t=45 ns, the counter is loaded. One clock later, the internal register value of the counter counter_reg shows us that it is counting down. At t=85 ns, en is de-asserted (goes low), so the counter stops. Two clocks later it reassumes the count and at t=125 ns the done output is asserted.
Question 1: counter_reg reaches zero one clock before done goes high. Why is that?
Finally, at t=185 ns the counter is loaded again but it doesn’t reach zero since at t=225 ns is reloaded.
Question 2: at t=225 ns, both load and en and asserted. The counter does not count, it is loaded. Can you tell why load has priority over en?
Proposed exercise – Make logic that will assert done exactly on the same clock that the counter reaches zero (see Question 1) – Hint: You have to check when counter_reg reaches the value one, and if en signal is asserted, on the next clock the counter will have the value zero.
The source code and the testbench used to generate the waveform can be found on GitHub