Reputation: 171
I have a generic value X which can exceed the positive maximum integer limit 2147483647. I was getting it in generic portion of the entity declaration:
X : integer := 3000000000;
Y : integer := 128; -- maximum 1024 (11 bits)
Z : integer := 1000 -- maximum 65535 (16 bits)
However, X is not directly used in the architecture but a constant named C is used. I define the constant in the architecture by:
constant C : unsigned(63 downto 0) := to_unsigned ( (X / Y) / 1000 * Z, 64);
However because X can exceed the integer limit, this solution is not feasible. Therefore, I have decided to use unsigned (I am using ieee.numeric_std library) in the entity decleration such as:
X : unsigned(63 downto 0) := x"00000000B2D05E00"; -- equivalent of 3000000000d
Y : integer := 128; -- maximum 1024 (11 bits)
Z : integer := 1000 -- maximum 65535 (16 bits)
Then, to calculate the constant:
constant C : unsigned(63 downto 0) := ((X / to_unsigned(Y, 11)) / to_unsigned(1000,10) * to_unsigned(Z, 21));
I choose the length of Z as 21 because Y and 1000d has total length of 21 (10+11).
However, Vivado gives me an error "mismatched array sizes in rhs and lhs of assignment."
How should I overcome this situation? What is the proper way of solving it? My way may be incorrect, I am open to any method.
Thanks.
Upvotes: 1
Views: 1280
Reputation: 156
Given the range of values that you indicate for Z and assuming a minimum of Y=1, I think you will have to use real
and then break it down into integer sized chunks since to_unsigned()
requires an integer. If your values fit in 64-bits this is actually pretty easy with the mod
operator.
constant x : real := 300000000.0; -- no constraints provided
constant y : real := 1.0; -- assumed minimum
constant z : real := 65535.0; -- stated maximum
constant c_real : real := x/y/1000.0*z; -- 19660500000.0
constant lower32 : unsigned(31 downto 0) := to_unsigned(integer(c_real mod 2.0**31), 32);
constant upper32 : unsigned(31 downto 0) := to_unsigned(integer(c_real / 2**31), 32);
signal counter : unsigned(63 downto 0) := shift_left(resize(upper32, 64), 31) + lower32;
Upvotes: 1
Reputation: 4461
Vivado is correct - the sizes do missmatch.
The result of the "/"
function returns the length of the left operand. So here, you have
(X / to_unsigned(Y, 11)
Which returns a 64 bit result
/ to_unsigned(1000,10)
returns another 64 bit result. And finally:
* to_unsigned(Z, 21));
Is a 64 bit value * 21 bit, giving a 85bit number. You will need to resize the result to 64 bits with the resize function:
resize(result, X'length);
There is no checking for overflow with this function other than an assertion warning, you need to ensure you will never overflow the 64 bit number.
Upvotes: 4