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 (modulo1).
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 downcounter and not an upcounter. For Altera devices (at least for those I have tested), the implementation as a downcounter is more efficient (regarding HW resources utilization) than an implementation as upcounter.
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 reloaded 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_cnt1) value.
On the second figure, the max_cnt is six. Exactly after the zero output is asserted the counter is disabled (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_cnt1).
The sources, testbench files, waveform, simulation project files, etc., are released under Github.