VHDL: integers for synthesis?
Integers are fine in synthesis, I use them all the time.
I use std_logic at top level ports, but internally I was using ranged integers all over the place
That's fine!
Be aware:
- You are simulating first aren't you :) - Integer types don't automatically "roll-over" in simulation - it's an error to go out of the range you've specified for them. If you want roll-over behaviour, you have to code it explicitly.
- They are only specced to go from \$-(2^{31}-1)\$ to \$+2^{31}-1\$ (i.e. not quite the full range of a 32-bit integer, you can't use \$-2^{31}\$ and remain portable), which is a bit of a pain at times. If you need to use "big" numbers, you'll have to use
unsigned
andsigned
. - If you don't constrain them, you can sometimes end up with 32-bit counters where less would do (if the synth and subsequent tools can't "see" that they could optimise bits away).
On the upside:
- They are much faster to simulate than unsigned/signed vectors
- They don't automatically roll-over in simulation (yes, it's in both lists :). This is handy - for example you get early warning that your counter is too small.
When you do use vector types, you are using ieee.numeric_std
, not ieee.std_logic_arith
aren't you?
I use integer
s where I can, but if I explicitly want "roll-over n-bit counters", I tend to use unsigned
.
Jan Decaluwe wrote an entire white paper on the problems of integers versus bit vectors. I expect his answers would be to use integers whenever possible. http://www.jandecaluwe.com/hdldesign/counting.html
There's nothing wrong about using integers for RTL per se, but there are reasons that some avoid it. This really is a question about subjective "best practice" and you'll eventually have to find out yourself what you prefer. As a help to that, I'll share my experience and thoughts on this.
Principally , I'm in favour of using (constrained) integers, also when writing for synthesis. I sometimes do it, but in practice, usually I stick to signed
and unsigned
. I'll elaborate on why.
You will be forced to use a vectorized datatypes in part of your design anyway:
Hardly any vendor-IP or 3rd party-IP will use
integer
type for portsE.g. when sending data through BlockRam, even if you infer it and therefore never need to interface to any IP/macro/primitive, you'll most likely need to convert to vectorized type anyway
Even if neither of the above apply, you will mostly need to interface to something else at some point (a top-level port, if nothing else)
Since you can't use integer
for the full design, you might want to skip it all together, because:
At some points, you'll need to do the conversions anyway, and this takes away part of the point of using
integer
in the first placeAlso, for simulation, these conversions will typically be called with vectors of
'U'
or'X'
, either before reset, or at other times, and every single such function call will generate a warning messages from the package function, cluttering your simulation warnings/prompt
Drawbacks of using integer
:
Contrary to the vectorized types, integers don't have
'U'
and'X'
; I find those very helpful in simulations. You see how uninitialized signals propagate through the design, and you will probably react if you see a lot of uninitialized signals after the reset. This won't be the case if using integers.With integers, there's a greater risk of simulation/synthesis mis-match when adding or subtracting resulting in under-/overflow. (As already pointed out by someone else.)
Typical cases where I find integer
to really be a good option:
For debug signals/counters that you monitor through chipScope/signalTap etc.
Totally internal representation of counters, that never go into or out of your own code. Yes, there are such cases, e.g. if you're writing a FIFO and you are dead-reckoning writes/reads to form the signals
full
,empty
,almostFull
etc. (however arithmetics on the pointers is a better way than dead-reckoning in this case...)
My own conclusions: I do use integers sometimes, but sparingly, and mostly in the cases described above. I don't see much overhead in using unsigned
and signed
instead of integer, and therefore, usually stick to them.