Search code examples
genericsvhdlcountermodulo

modulo n generic counter


I am required to design a modulo "n" counter with generic parameters. I am having trouble fixing the length of the std_logic_vector which will hold the output. Firstly, I get errors regarding the use of airthmetic operators on numeric types. And secondly, I am not allowed to use a dynamic expression in the range specification of the vector. Here is my code so far:

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;  
use IEEE.math_real.all;

entity counter_mod is
  generic(n: integer range 1 to integer'right);
  port(clk,reset,load:in std_logic;
  data_in:in std_logic_vector(ceil(log2(1.0*n))-1 downto 0);
  q:out std_logic_vector(ceil(log2(1.0*n))-1 downto 0));
end counter_mod;

architecture behavioral of counter_mod is
begin
  process(clk,reset,load)
  variable count:std_logic_vector(ceil(log2(1.0*n))-1 downto 0):=(others=>'0');
  begin
      if(reset='1') then
          count:=(others=>'0');
      else if(load='1') then
          count:=data_in;
      else if(clk'event and clk='1') then
          if(conv_integer(count)=n-1) then
            count:=0;
          else
            count:=count+1;
          end if;
      end if;
      end if;
      end if;
      q<=count;
  end process;
end architecture;

Solution

  • Some suggestions:

    • Must change ceil(log2(1.0*n)) to natural(ceil(log2(real(n)))), to address the type mismatches

    • Must change count := 0 to count := (others => '0'), since it is not possible to assign 0 directly to std_logic_vector.

    • May change integer range 1 to integer'right to positive, since use of the standard package type states the intention clearly

    • May change range in variable declaration to data_in'range, since use of the VHDL attribute states the intention clearly

    • May change if(conv_integer(count)=n-1) then to if (count = n-1) then, since the conv_integer is not required when using ieee.std_logic_unsigned.all

    • May change if(...) then to if ... then, since () are not required in if because if is a statement and not a function

    • May change clk'event and clk = '1' to rising_edge(clk), since use of the std_logic_1164 package function states the intention clearly

    • May change the else if to use of elsif for a clearer and less verbose style

    The code can then be updated to:

    library IEEE;
    use IEEE.std_logic_1164.all;
    use IEEE.std_logic_unsigned.all;
    use IEEE.math_real.all;
    
    entity counter_mod is
      generic(n : positive);
      port(clk, reset, load : in  std_logic;
           data_in          : in  std_logic_vector(natural(ceil(log2(real(n))))-1 downto 0);
           q                : out std_logic_vector(natural(ceil(log2(real(n))))-1 downto 0));
    end counter_mod;
    
    architecture behavioral of counter_mod is
    begin
      process(clk, reset, load)
        variable count : std_logic_vector(data_in'range) := (others => '0');
      begin
        if reset = '1' then
          count := (others => '0');
        elsif load = '1' then
          count := data_in;
        elsif rising_edge(clk) then
          if count = n-1 then
            count := (others => '0');
          else
            count := count+1;
          end if;
        end if;
        q <= count;
      end process;
    end architecture;
    

    Consider changing ieee.std_logic_unsigned to ieee.numeric_std.all, since the ieee.std_logic_unsigned is not a standard package, so the place in the ieee library is misleading. It requires change in inner if to:

    if to_integer(unsigned(count)) = n-1 then
      count := (others => '0');
    else
      count := std_logic_vector(unsigned(count)+1);
    end if;