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
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 ports
E.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 place
Also, for simulation, these conversions will typically be called with vectors of
'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
Contrary to the vectorized types, integers don't have
'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
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
signed instead of integer, and therefore, usually stick to them.