A modulo counter is a counter that wraps around when it reaches a certain value. For example, a counter modulo 5 will count 0, 1, 2, 3, 4, 0, 1, … ; namely, after 4 it will wrap around to 0. The reason the counter wraps at 4 is because, to count five clock pulses starting from zero, the maximum value of the counter must be (modulo-1).
Every VHDL counter is a modulo counter. If you define a two bit counter, it will wrap around automatically from 3 to 0 without the need of writing special logic for that.
But what if we want a modulo counter that is different from a power of 2? In that case we have to write special logic to achieve that.
The code below implements a modulo counter. The counter width is defined as a generic parameter. The modulo value is an input to the module. Tipically, this value will come from a registers blocks, updated by a processor host.
We may notice that the implementation is as a down-counter and not an up-counter. For Altera devices (at least for those I have tested), the implementation as a down-counter is more efficient (regarding HW resources utilization) than an implementation as up-counter.
The entity includes the DATA_W parameter, namely, the size of the counter. The max_cnt input is the modulo value. The component also has an enable input (en), and the zero output which is asserted when the counter value is zero.
Here we can see the implementation architecture of the modulo counter:
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity modulo_cnt is generic ( DATA_W : natural := 32 ); port ( clk: in std_logic; rst: in std_logic; -- inputs max_cnt: in std_logic_vector (DATA_W-1 downto 0); en: in std_logic; -- outputs zero: out std_logic ); end modulo_cnt; architecture rtl of modulo_cnt is signal cnt : unsigned(DATA_W-1 downto 0); signal zero_i : std_logic; begin zero_i <= '1' when cnt = 0 else '0'; zero <= zero_i; counter_pr: process (clk, rst) begin if (rst = '1') then cnt <= (others => '0'); elsif (rising_edge(clk)) then if (en = '1') then -- is counting enabled? if (zero_i = '1') then -- check if counter reached zero cnt <= unsigned(max_cnt) - 1; -- reload with modulo value else cnt <= cnt - 1; -- decrement counter end if; end if; end if; end process; end rtl;
The logic is very simple to follow. The counting logic is enabled by the en input. If en is asserted and the counter cnt reaches zero, it is re-loaded with the max_cnt input value. Otherwise, the cnt is decremented.
On the following waveform from the simulation we can see the operation of the modulo counter.
On the first cursor, the en input is asserted. From the next clock, we can see that the counter counts down until it reaches zero, where the zero ouput is asserted and the counting resumes from the (max_cnt-1) value.
On the second figure, the max_cnt is six. Exactly after the zero output is asserted the counter is disables (first cursor), so we see that for several clocks the counting value on cnt doesn’t change. The second cursor marks the time where the counter (now enabled for several clocks) reaches zero and wraps around to five (=max_cnt-1).
The sources, testbench files, waveform, simulation project files, etc., are released under Github.
Link for this project on Github
Link for all releases of this project under Github