My purpose is to store values from 0 to 3. From a synthesis point of view, which of the following would be more area efficient, when coding in VHDL ?

  1. signal a: integer;
  2. signal a: integer range 0 to 3;

Will the first choice take up a 32 bit register in the FPGA?

  • 1
    \$\begingroup\$ Depends how good the synthesis tool is, and the information you can provide about the range of values to the synth tool. But the ranged form guarantees area efficiency and documents what your design does. (should be natural range 0 to 3 to make it clear you'll never allow negative values). \$\endgroup\$
    – user16324
    Commented Nov 5, 2017 at 16:57
  • 1
    \$\begingroup\$ Without displaying your algorithm expressed in VHDL, an integer represents 32 bits and is signed in synthesis. Any uninvolved bits are eliminated during reduction. An integer subtype (strong typing) can be useful in describing numerical relationships that don't use more bits than necessary (e.g. a 17th value for what should be a 4 bit counter). \$\endgroup\$
    – user8352
    Commented Nov 5, 2017 at 16:58
  • 2
    \$\begingroup\$ The range of integer is -2*31+1 to 2**31-1. It depends on your optimizer to recognize if bits 4 to 31 are unused in your case. I recommend type unsigned(3 downto 0) to store values. \$\endgroup\$
    – Paebbels
    Commented Nov 5, 2017 at 16:58

1 Answer 1


It depends, but it is almost always preferable to specify the range.

For illustration, consider this example:

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

entity naturals is 
    Port ( clk    : in  std_logic;
           rst    : in  std_logic;
           count  : out std_logic_vector(2 downto 0));
end naturals;

architecture behavioral of naturals is
    signal count_intern : natural := 0;
    count <= std_logic_vector(to_unsigned(count_intern, count'length));
        if (rising_edge(clk)) then
            if (rst = '1') then
                count_intern <= 0;
            elsif (count_intern = 5) then
                count_intern <= 0;
                count_intern <= count_intern + 1;
            end if;
        end if;
    end process;
end behavioral;

This is a simple counter going from 0 to 5. It's simulation looks like this: simulation

However, I didn't limit the signal count_intern - so, internally it is 31-bits (integers are 32-bits, naturals are 31). Even though I am only actually using the lower 3 bits, all 31 end up in the addition and comparison operations. Why? Because on startup, the initial value of count_intern is undefined. It might, for instance, begin with a value of 7 - at which point, the counter will increment until all 31 bits fill up and overflow back to 0. The initialization (to 0) that I supplied in the code, only applies to simulation - it is ignored by the synthesizer.

The post-synthesis schematic, therefore, looks like this:


I realize the image is too large to make out its details - but that's the point. It's a mess; and for a very simple circuit.

Now, let's replace the single line:

signal count_intern : natural := 0;


signal count_intern : natural range 0 to 5 := 0;

Without proof, the simulation is exactly the same. However, the post-synthesis schematic now resolves to:


In fact, the results of this can be confirmed even post-implementation - where it truly counts:

Without limiting the natural range: post-implementation1

With range limit: post-implementation2

Notice the difference in flip-flops used.

While I used Naturals here, this (of course) extends to Integers as well.

Implementation results may vary. Here I am using the default settings in Vivado 2015. Either way, the point is - it is safer and preferable to always specify the range.

  • \$\begingroup\$ Does this apply to constants too, since the compiler should be able to deduce which bits will never be used? Like, if a constant is assigned a value of 10 but is declared with a range of 0 to 31. \$\endgroup\$ Commented Mar 3, 2019 at 1:17
  • 1
    \$\begingroup\$ @TisteAndii great question. I’ll give it a try on Monday. I would suspect that it doesn’t matter for constants, for the reason you stated. \$\endgroup\$ Commented Mar 3, 2019 at 1:22
  • 2
    \$\begingroup\$ @TisteAndii I did a few tests with constants, and it looks like your assumptions are correct. It makes sense. A constant can only ever have a single state- so there's never a reason to preserve unused or unnecessary bits from its value. \$\endgroup\$ Commented Mar 4, 2019 at 19:11
  • \$\begingroup\$ Thanks for taking the time. Was wondering if I should bother optimizing the size of some constants to the exact width needed \$\endgroup\$ Commented Mar 4, 2019 at 19:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.