Skip to main content
Logo image

Section 14.3 Counters: integer or unsigned?

Another way to make a scalable counter is to use a signal of integer type rather than unsigned. The parametrized decade counter looks like this:
library IEEE;
use IEEE.std_logic_1164.all;                     -- 1

...                                     

architecture behavior of example is
    constant MAXVAL: integer := 9;              
    signal iy: integer range 0 to MAXVAL := 0;  -- 2, 3

begin 
    process(clk)
    begin
       if rising_edge(clk) then
          if iy < MAXVAL then                         
             iy <= uy+1;
          else
             iy <= 0;                          -- 3                       
          end if;
       end if;
    end process;
end behavior;
Listing 14.3.1. Decade counter using integer datatype. Comments are keyed to explanations in the text.
The differences from the unsigned counter, indicated by comments, are:
  1. The numeric_std library is not needed. The integer data type and all its arithmetic operations are part of original VHDL.
  2. The count is declared to be of integer type. The size of the integer is specified by its numeric range rather than by a number of bits.
  3. The initial value and reset value of iy are the integer constant 0 rather than the bit string "0000".
The integer counter is easily scaled by changing the value of MAXVAL, without the complication of calculating the size of a register. An integer counter can, in principle, perform the same tasks as an unsigned counter. However, there are reasons to prefer one over the other in particular situations:
  • If a counter is used as a timer or clock divider, where the only output is a terminal count signal, then the integer counter is preferable.
  • If the counter’s value is to be used only as an array index, e.g., generating sequential memory addresses, then the integer counter is preferable. Array indices are also of integer type and no type conversion is required. An unsigned count will have to be converted to integer type to be used as an index: to_integer(uy).
  • If the actual value of the count is needed, e.g., to display the time in a stopwatch, then the integer count must be converted to a std_logic_vector with an explicit length: std_logic_vector(to_unsigned(iy, REGSIZE)). In this case, it seems cleaner to hold the count in an unsigned vector, with size calculated from the maximum value as shown earlier.
If you are using an integer counter you must be careful not to omit the range specification in the declaration of the count signal. By default, a signal of integer type is 32 bits long, and without a range specification it will be synthesized as a 32-bit register, likely wasting resources. With the range restriction, when the counter is synthesized, iy will be assigned a register of length appropriate to hold MAXVAL.
It is also important to note that unsigned and integer counters behave differently in simulation. An integer counter with range 0 to 9 will not naturally roll over from 9 to 0, but will throw an “out of range” error when it tries to increment from 9 to 10. A four-bit unsigned counter will naturally increment from 9 to 10 and roll over from 15 to 0 if the count is not compared to the maximum value. This only applies to simulation. In synthesis, both counters will be synthesized with four-bit registers and, in the absence of an explicit maximum value check, both will naturally roll over from 15 to 0.
The uses and inter-relationships of the integer, signed/unsigned, and std_logic_vector types are illustrated in the graphic shown in Figure 14.3.2.
described in detail following the image
Bubble-and-arrow flowchart
Figure 14.3.2. Relationships among integer, signed/unsigned, and std_logic_vector data types [22].

Checkpoint 14.3.3. Integer counter with TC output.

Modify the integer counter, Listing 14.3.1, to generate a terminal count (TC) output. Verify your design by simulation. Here is a design and testbench
 1 
www.edaplayground.com/x/24AE
, in EDA Playground, to get you started.

Checkpoint 14.3.4. Integer counter vs unsigned.

Using Xilinx Vivado, write complete VHDL models and testbenches for the integer and unsigned decade counters. Compare their behavior in simulation. Run both models through synthesis and compare the resource usage. Remove the range constraint from the integer counter declaration and observe the effect on simulation and synthesis.