4
\$\begingroup\$

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

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

Will the first choice takes up 32 bit register inside FPGA?

\$\endgroup\$
  • 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\$ – Brian Drummond Nov 5 '17 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 Nov 5 '17 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 Nov 5 '17 at 16:58
8
\$\begingroup\$

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;
begin
    count <= std_logic_vector(to_unsigned(count_intern, count'length));
    process(clk)
    begin
        if (rising_edge(clk)) then
            if (rst = '1') then
                count_intern <= 0;
            elsif (count_intern = 5) then
                count_intern <= 0;
            else
                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:

post-synthesis1

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;

with

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:

post-synthesis2

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.

| improve this answer | |
\$\endgroup\$
  • \$\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\$ – SoreDakeNoKoto Mar 3 '19 at 1:17
  • \$\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\$ – Blair Fonville Mar 3 '19 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\$ – Blair Fonville Mar 4 '19 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\$ – SoreDakeNoKoto Mar 4 '19 at 19:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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