2.2.6 Modulo N Counter

May 27, 2025 ยท View on GitHub

Modulo N Counter

On each clock cycle, this counter adds 1 to the current value if the increment signal is high. If the current value equals n-1, it wraps around to 0.

Verilog

module modulo_n_counter #(
  parameter width = 4,
  parameter n = 12
) (
  input clock, clear, increment,
  output reg [width-1:0] q
);

  always @(posedge clock)
  begin
    if (clear) 
      q <= 0;
    else if (increment)
      if (q == (n-1)) q <= 0;
      else q <= q + 1;
  end

endmodule

VHDL

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

entity modulo_n_counter is
  generic (
    width : integer := 4;
    n : integer := 12
  );
  port (
    clock, clear, increment : in std_logic;
    q : out std_logic_vector(width-1 downto 0)
  );
end entity;

architecture rtl of modulo_n_counter is
    signal q_int : std_logic_vector(width-1 downto 0);
begin

  q <= q_int;

  process (clock) is 
  begin
    if rising_edge(clock) then
      if clear = '1' then
        q_int <= (others => '0');
      elsif increment = '1' then
       if (q_int = std_logic_vector(to_unsigned(n-1, q'length))) then
          q_int <= (others => '0');
        else
          q_int <= std_logic_vector(unsigned(q_int) +  1);
        end if;
      end if;
    end if;
  end process;

end architecture;

Hardcaml

Direct translation

  let modulo_n_counter_1 ~config:{ width; n } ~clock ~clear ~increment =
    let spec = Reg_spec.create ~clock ~clear () in
    let out = Always.Variable.reg spec ~width in
    Always.(
      compile
        [ when_
            increment
            [ if_ (out.value ==:. n - 1) [ out <--. 0 ] [ out <-- out.value +:. 1 ] ]
        ]);
    out.value
  ;;

Idiomatic Hardcaml

  let modulo_n_counter_2 ~config:{ width; n } ~clock ~clear ~increment =
    reg_fb
      (Reg_spec.create ~clock ~clear ())
      ~enable:increment
      ~width
      ~f:(mod_counter ~max:(n - 1))
  ;;

In this implementation the function mod_counter, provided by Comb.S, performs the increment function. It is a little smarter than the other versions in that it will detect if 2**width = n and rely on natural binary overflow to wrap to 0, eliding the comparison.