# Variables in VHDL conversion

Consider the following MyHDL code:

``````@always_comb
bx_sum = bx.signed() + bx.signed() + bx.signed()
ay_sum = ay.signed() + ay.signed()
result.next = (bx_sum << BX_SHIFT) - (ay_sum << AY_SHIFT)
``````

It converts to this piece of VHDL:

``````PREFIX_ADD: process (bx, ay) is
variable bx_sum: integer;
variable ay_sum: integer;
begin
bx_sum := to_integer((bx(0) + bx(1)) + bx(2));
ay_sum := to_integer(ay(0) + ay(1));
result <= to_signed(shift_left(bx_sum, 12) - shift_left(ay_sum, 0), 67);
``````

This won’t compile, because the compiler can’t determine whether the first argument of `shift_left()` is signed or unsigned. I think this is a bug in the VHDL conversion. To fix this, let’s try moving the shift to where the compiler can still infer the type:

``````@always_comb
bx_sum = bx.signed() + bx.signed() + bx.signed() << BX_SHIFT
ay_sum = ay.signed() + ay.signed() << AY_SHIFT
result.next = bx_sum - ay_sum
``````

Now we get this:

``````PREFIX_ADD: process (bx, ay) is
variable ay_sum: integer;
variable bx_sum: integer;
begin
bx_sum := to_integer(shift_left(((bx(0) + bx(1)) + bx(2)), 12));
ay_sum := to_integer(shift_left((ay(0) + ay(1)), 0));
result <= to_signed(bx_sum - ay_sum, 67);
``````

This compiles, but is it safe? Do vendor tools support arbitrarily large integer variables? Should I do this instead:

``````@always_comb
result.next = (
(bx.signed() + bx.signed() + bx.signed() << BX_SHIFT) -
(ay.signed() + ay.signed() << AY_SHIFT)
)
``````

This gives the following VHDL, which compiles and should definitely be safe:

``````result <= (shift_left(((bx(0) + bx(1)) + bx(2)), 12) - shift_left((ay(0) + ay(1)), 0));
``````

However, I think the first version (the one that doesn’t compile now) is the most readable.

What about the sign of bx_sum and ay_sum after the shift (independently of MyHDL/VHDL) ?

What about it? Both bx_sum and ay_sum are signed integers. Shifting doesn’t affect the sign. Is that what you meant?

That’s it.
“1010110” is negative.
“1010110” << 1 = “0101100” This is positive.

In Python, shifting doesn’t affect sign. The same is true for shifting signed types in VHDL. So as far as I know, “1010110” << 1 ≠ “0101100”.

Edit: I missed your point about the shifted value not being wider than the original, like it is in Python. As far as I know, this is the case also in VHDL, so the first bit would not be dropped.

Edit: Except I’m wrong:

function SHIFT_LEFT (ARG: SIGNED; COUNT: NATURAL) return SIGNED;
– Result subtype: SIGNED(ARG’LENGTH-1 downto 0)
– Result: Performs a shift-left on a SIGNED vector COUNT times.
– The vacated positions are filled with ‘0’.
The COUNT leftmost elements are lost.

So I actually want to concatenate, not shift.

Don’t forget that you can simulate code that is not convertible to VHDL/verilog. This is usefull but you must be careful about it.

That’s it (Have to type more than 20 char, so lets go…)

Except that in this case it does convert. It just doesn’t do the same thing, which is rather dangerous. I will need to review my code for erroneous uses of the shift operator.

This is why co-simulation exists.
I personally don’t use it. I check VHDL generated code when I have a doubt.

@mhavu Perhaps declare interim Signal avoiding the inference of variables. Unfortunately MyHDL will now wrongly complain that you are reading outputs of the `@always_comb` process back - I commented that out in my MHDL code base I also think that you can promote the variable by specifying it outside the `@always_comb` as an `intbv`, so the 32-bit limit of the integer (in VHDL) doesn’t bite.

I can get rid of the complaint by adding one more `@always_comb` process. This may be the cleanest option. It will also allow me to continue using left shift the way I have been doing. (Thanks for @DrPi for spotting the error!)

That won’t work because of Python’s duck typing. The assignment will just replace whatever `intbv` value the variable had by a new integer value. The VHDL conversion in MyHDL is not clever enough to intervene with that. (I don’t know whether that would even be possible.)

I think it works like this:

``````temp = intbv(0)[8:]

@always_comb
def comb():
temp[:] = something + whatever

``````

I almost never use variables Ah, true. That should work.

Should there be a `.next` in there?

Not if `temp` is not a `Signal`. If it is, `temp.next` will suffice. (The `[:]` is not necessary.)

Oh yeah, missed lack of a `Signal` TBH, I always use a signal explicitly. I’m very wary of variables because I keep getting burned by them inside the downstream tools.

1 Like