Skip to main content
Logo image

Section 14.1 Parametrized designs

The VHDL model for a counter depends on two parameters: the width of the register and the maximum count value. For example, in a decade counter process that is part of an architecture:
architecture behavior of example is
    signal uy: unsigned(3 downto 0) := "0000";   -- 1, 2
begin
    process(clk)
    begin
       if rising_edge(clk) then
          if uy < 9 then                         -- 3
             uy <= uy+1;
          else
             uy <= "0000";                       -- 4
          end if;
       end if;
    end process;
...
end behavior;
There are four points in this model, marked by comments, where constant values are used:
  1. The length of the counter register (4 bits, indexed 3 downto 0)
  2. The initial state of the counter, "0000"
  3. The maximum value of the counter, 9
  4. The reset value, "0000"
All four of these numerical constants must be entered correctly in order for the counter to work as desired. If, at some future time, you want to change the counter from counting to 9 to counting to 11, you will have to change one number. If you want to change the maximum count to 23, you must modify all four points in the model: the length of uy from 4 to 5, the initial and reset values from "0000" to "00000", and the upper count limit from 9 to 23. If you miss one of these changes you’ll have a syntax error or a functional bug.
You know from prior programming experience that it is dangerous to have unnamed constants, sometimes called “magic numbers”, in your code. They often go undocumented and when changes have to be made, they are often overlooked, leading to costly rounds of debugging. These risks are mitigated by replacing the magic numbers with documented named constants. Here is how that would be done in the decade counter:
architecture behavior of example is
    constant REGSIZE: integer := 4;  -- register length
    constant MAXVAL: integer := 9;   -- maximum count

    signal uy: unsigned(REGSIZE-1 downto 0) := (others=>'0');   
begin
    process(clk)
    begin
       if rising_edge(clk) then
          if uy < MAXVAL then                         
             uy <= uy+1;
          else
             uy <= (others=>'0');                       
          end if;
       end if;
    end process;
end behavior;
In this version, the register length and the maximum count parameters are assigned to named constants, REGSIZE and MAXVAL at the beginning of the architecture. These named parameters replace the instances of the magic numbers in the model. Additionally, we have used the (others=>'0') construction to replace the "0000". This represents a string "0...0" of length that matches the vector it is assigned to. With these modifications, if you want to change the maximum count from 9 to 23, you only have to change REGSIZE and MAXVAL, and their values will propagate through the model. These two changes make the code easier to read, thus less prone to bugs, and also scalable, by changing the parameter values rather than by rewriting the code. Large designs often contain many registers of the same size. Making the register size a named constant parameter, and using that parameter throughout the design, makes it easy to scale the design to different register sizes in the future.