Consider the following MyHDL code:
@always_comb
def add():
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);
end process PREFIX_ADD;
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
def add():
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);
end process PREFIX_ADD;
This compiles, but is it safe? Do vendor tools support arbitrarily large integer variables? Should I do this instead:
@always_comb
def add():
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.