# Variables in VHDL conversion

#1

Consider the following MyHDL code:

``````@always_comb
bx_sum = bx[0].signed() + bx[1].signed() + bx[2].signed()
ay_sum = ay[0].signed() + ay[1].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[0].signed() + bx[1].signed() + bx[2].signed() << BX_SHIFT
ay_sum = ay[0].signed() + ay[1].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[0].signed() + bx[1].signed() + bx[2].signed() << BX_SHIFT) -
(ay[0].signed() + ay[1].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.

#2

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

#3

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

#4

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

#5

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.

#6

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.

#7

That’s it

(Have to type more than 20 char, so lets go…)

#8

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.

#9

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

#10

@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.

#11

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.)

#12

I think it works like this:

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

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

``````

I almost never use variables

#13

Ah, true. That should work.

#14

Should there be a `.next` in there?

#15

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

#16

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.