INTEGER CONSTANT Question

A

Analog_Guy

Here's a two part question:

Q#1:
If a CONSTANT is defined of type INTEGER (i.e. CONSTANT counter_bits
: INTEGER := 1;), does a range need to be specified? For synthesis, it
is generally good practice to constrain INTEGERs. However, I can see
that this makes sense for VARIABLES and SIGNALS, but does it also apply
to CONSTANTS?

Q#2:
Is it acceptable coding style to define a STD_LOGIC_VECTOR counter load
as an INTEGER CONSTANT (where conversion functions need to be called
when the counter is loaded), or can this lead to any synthesis issues?

CONSTANT counter_bits : INTEGER := 6;
CONSTANT counter_load : INTEGER := 59;
SIGNAL counter : STD_LOGIC_VECTOR(counter_bits - 1 DOWNTO 0);

strobe: PROCESS (reset_n, CLOCK)
BEGIN
IF (reset_n = '0') THEN
counter <= CONV_STD_LOGIC_VECTOR(counter_load, counter_bits);
ELSIF (CLOCK = '1' AND CLOCK'EVENT) THEN
IF (counter /= 0) THEN
counter <= counter - '1';
ELSE
counter <= CONV_STD_LOGIC_VECTOR(counter_load, counter_bits);
END IF;
END IF;
END PROCESS strobe;
 
J

Jonathan Bromley

Here's a two part question:

Q#1:
If a CONSTANT is defined of type INTEGER (i.e. CONSTANT counter_bits
: INTEGER := 1;), does a range need to be specified? For synthesis, it
is generally good practice to constrain INTEGERs. However, I can see
that this makes sense for VARIABLES and SIGNALS, but does it also apply
to CONSTANTS?

It depends on what you do with the constant. If the constant
appears in a data path, you may (note *may*) end up with a 32-bit
data path that you didn't want. Typical examples here might be the
use of constants as the coefficients in a digital filter.
Providing a suitable range on the integer constant will tell the
synthesis tool how many bits to use for it. The best way to
do this is to define a subtype:

subtype UNSIGNED_10_BIT is integer range 0 to 1023;

and then you can use that new subtype for your constants:

constant Coeff_1 : UNSIGNED_10_BIT := 55;


By contrast, if the constant is used only to determine some
parameter of the design or part of it - for example, it's used
to set the size of a vector, or a subscript - then it doesn't appear
in the physical data path, but is used only to determine what
signals are used in any given situation. In that case, plain integers
are just fine.

Q#2:
Is it acceptable coding style to define a STD_LOGIC_VECTOR counter load
as an INTEGER CONSTANT (where conversion functions need to be called
when the counter is loaded), or can this lead to any synthesis issues?
[snip example]

I can't see any problem with this, except for the obvious one that the
code is ugly; all the usual vector<->integer conversions simply map on
to a bunch of wires in synthesis. I'd be tempted, though, to make
the datapath constant a vector:
CONSTANT counter_bits : INTEGER := 6;
CONSTANT counter_load : INTEGER := 59;

CONSTANT counter_load_vec: std_logic_vector :=
conv_std_logic_vector(counter_load, counter_bits);

and now you can use "counter_load_vec" directly in your code,
without needing to place multiple calls to the conversion function.

By the way, please consider using the numeric_std package instead
of the clunky and poorly-standardised STD_LOGIC_UNSIGNED
and its various obsolescent friends. Plenty of discussion on that
in the recent past on this group.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
(e-mail address removed)
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
A

Analog_Guy

Thank you very much for your responses.


Jonathan said:
It depends on what you do with the constant. If the constant
appears in a data path, you may (note *may*) end up with a 32-bit
data path that you didn't want. Typical examples here might be the
use of constants as the coefficients in a digital filter.
Providing a suitable range on the integer constant will tell the
synthesis tool how many bits to use for it. The best way to
do this is to define a subtype:

subtype UNSIGNED_10_BIT is integer range 0 to 1023;

and then you can use that new subtype for your constants:

constant Coeff_1 : UNSIGNED_10_BIT := 55;
In this case, I would still have to set the range based on the number
of bits of my counter. Is there any difference in using the following?
CONSTANT counter_load : INTEGER RANGE 58 TO 60 := 59;

I'd be tempted, though, to make the datapath constant a vector:

CONSTANT counter_load_vec: std_logic_vector :=
conv_std_logic_vector(counter_load, counter_bits);

and now you can use "counter_load_vec" directly in your code,
without needing to place multiple calls to the conversion function.
That's actually a lot cleaner ... thanks!
 
J

Jonathan Bromley

CONSTANT counter_load : INTEGER RANGE 58 TO 60 := 59;

I think you'll find most tools would give you a 6-bit (0 to 63)
constant here, even though the integer range needs only
two bits to describe it completely.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
(e-mail address removed)
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
A

Andy

Most synthesis tools create storage for the largest number in the range
(for non-negative ranges). For signed integer subtypes, they assume
the number of bits necessary to store 2x the largest of the absolute
values of the ranges.

However, I believe Jonathan is mistaken when it comes to constant
subtypes' effect on bit widths in synthesis.

Sub-range bit widths are enforced only upon storage, not during
operations. Since a constant never "stores" anything in the hardware
context (it is never written to), its range is irrelevant, only its
value is important.

For example, the following code works very well for natural subtypes:

process (clk)
variable count : natural range 0 to 12;
begin
if rising_edge(clk) then
if count - 1 < 0 then
count := 12;
rollover <= true;
else
count := count - 1;
rollover <= false;
end if;
end if;
end process;

Even though count cannot contain a negative number, the subtraction
operation returns a 32 bit signed number, and it can be tested for less
than zero.

Note that the synthesis tool automatically optimizes out bits that are
not stored or otherwise used. It only stores 4 bits, but uses a 5th
(combinatorially, not registered) for the borrow out, used to control
the reload mux on the counter. Actually, Synplify only creates a mux
for the bits that would not roll over to that value anyway, i.e. those
bits that are not one in the load value.

The above example will not work for vector based arithmetic! The
subtraction operator for unsigned and natural returns an unsigned type,
which by definition is never less than zero. The synthesizer dutifully
recognnizes that, and optimizes out the load completely, which is
probably not what you wanted, but exactly what you said!

That is not to say that ranges on constants aren't sometimes
beneficial. They remind me of the possible range of values that can be
used for that constant, especially if the constant is declared in a
package, away from where it is used.

Andy
 
J

Jonathan Bromley

However, I believe Jonathan is mistaken when it comes to constant
subtypes' effect on bit widths in synthesis.

Sub-range bit widths are enforced only upon storage, not during
operations. Since a constant never "stores" anything in the hardware
context (it is never written to), its range is irrelevant, only its
value is important.

On reflection, I'm pretty much convinced that you're right.
Thanks for the correction.

As you say, it's the value of the constant that determines how
it's implemented if it happens to appear in the datapath.

Nevertheless I would tend to use integer range subtypes in
situations where they are meaningful. It protects me against
certain kinds of stupidity. For example, if I wanted to use
Xilinx embedded multipliers to multiply by an arbitrary
constant, it would be a good idea to declare that
constant to have a subtype of "-(2**17) to 2**17-1"
so that the compiler would complain if I tried to use
a constant that was bigger than signed 18-bit - as you
mentioned at the end of your post.

Thanks again, and apologies if I misled anyone
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
(e-mail address removed)
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top