efe373
efe373

Reputation: 171

VHDL overcome maximum integer limit

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

Answers (2)

Ryan Tennill
Ryan Tennill

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

Tricky
Tricky

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

Related Questions