03-08-2021 07:28 AM
While working on a project, I found a strange behavior which I believe to be a bug. But I'm not sure. Here are the code snippets in question. The first snippet does not work as expected, the second does:
s3 <= resize(unsigned(subtrahend(15 downto 12)) * 1000, s3'length);
--Expected result is subtrahend*1000 resized to s3's length, where 1000 is a natural number
constant thousand : unsigned(11 downto 0) := x"3E8"; [...] s3 <= resize(unsigned(subtrahend(15 downto 12)) * thousand, s3'length);
--Expected result is subtrahend*1000, where 1000 is a natural number (but in this case is presented as unsigned type of 12 bits)
For background, according to the numeric_std package, the resize function supports unsigned, signed, and natural numbers in various configurations. In this case, resize(unsigned, natural) should return a vector of length natural of the unsigned type. s3'length should be a natural number, I believe.
Secondly, the "*" operator supports unsigned and natural inputs. From this, looking at the first code snippet (which doesn't work), we would expect the result to be a vector of length s3'length containing the value subtrahend(15 downto 12)*1000 where 1000 is one thousand, a natural number. In fact, the function returns subtrahend(15 downto 12) * 8, interpreting 1000 as 8 instead of 1000. This means something is treating 1000 as a vector of 1s and 0s, even though nothing about it presents as a binary vector. Meanwhile, the other version, with the unsigned constant thousand, works exactly as the code suggests it would.
This is quite bizarre, imo. Normally, to interpret a string of 1s and 0s as a vector of any type would require the quotation marks, or a typecast, or something like that. So the behavior I'm seeing seems like an error. It may be (I have not tested this) that the argument requires parentheses around, a la
s3 <= resize(unsigned((subtrahend(15 downto 12)) * 1000), s3'length);
because of some sort of grouping precedence issue in the resize function. But, on the other hand, I don't see how VHDL should ever treat 1000 as anything other than a natural number in this context. Therefore, I would expect an error here.
Altogether, the issue is quite minor, but I thought it was strange when I realized what was going on, and I'm wondering if it's a bug, or there's some other reason for these disparate outcomes.
04-06-2021 01:21 AM
Was this happening in synthesis or simulation? I agree, 1000 is 1000 and not "1000" and it must have taken you rather a while to figure out what it is doing.
I've seen that Vivado makes integers into 32-bit structures even when 3 bits would suffice, so I've learnt to be very explicit with how I treat integers and naturals to make sure it does what I intend.
I would have used "to_unsigned(1000, 12)"
04-06-2021 01:56 AM
When multiplying a vector by an integer, the integer is converted into a vector of the same width as the other operand !!!
As a consequence, the result’s width is forced to two times the width of the signed/unsigned vector.