if (cell->type.in(ID($xnor), ID($_XNOR_))) btor_op = "xnor";
log_assert(!btor_op.empty());
- int width = GetSize(cell->getPort(ID::Y));
- width = std::max(width, GetSize(cell->getPort(ID::A)));
- width = std::max(width, GetSize(cell->getPort(ID::B)));
+ int width_ay = std::max(GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::Y)));
+ int width = std::max(width_ay, GetSize(cell->getPort(ID::B)));
bool a_signed = cell->hasParam(ID::A_SIGNED) ? cell->getParam(ID::A_SIGNED).as_bool() : false;
bool b_signed = cell->hasParam(ID::B_SIGNED) ? cell->getParam(ID::B_SIGNED).as_bool() : false;
int sid = get_bv_sid(width);
int nid;
+ int nid_a;
+ if (cell->type.in(ID($shl), ID($shr), ID($shift), ID($shiftx)) && a_signed && width_ay < width) {
+ // sign-extend A up to the width of Y
+ int nid_a_padded = get_sig_nid(cell->getPort(ID::A), width_ay, a_signed);
+
+ // zero-extend the rest
+ int zeroes = get_sig_nid(Const(0, width-width_ay));
+ nid_a = next_nid++;
+ btorf("%d concat %d %d %d\n", nid_a, sid, zeroes, nid_a_padded);
+ } else {
+ nid_a = get_sig_nid(cell->getPort(ID::A), width, a_signed);
+ }
+
+ int nid_b = get_sig_nid(cell->getPort(ID::B), width, b_signed);
+
if (btor_op == "shift")
{
- int nid_a = get_sig_nid(cell->getPort(ID::A), width, false);
- int nid_b = get_sig_nid(cell->getPort(ID::B), width, b_signed);
-
int nid_r = next_nid++;
btorf("%d srl %d %d %d\n", nid_r, sid, nid_a, nid_b);
}
else
{
- int nid_a = get_sig_nid(cell->getPort(ID::A), width, a_signed);
- int nid_b = get_sig_nid(cell->getPort(ID::B), width, b_signed);
-
nid = next_nid++;
btorf("%d %s %d %d %d%s\n", nid, btor_op.c_str(), sid, nid_a, nid_b, getinfo(cell).c_str());
}
return result;
}
-static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, int direction, int result_len)
+// Shift `arg1` by `arg2` bits.
+// If `direction` is +1, `arg1` is shifted right by `arg2` bits; if `direction` is -1, `arg1` is shifted left by `arg2` bits.
+// If `signed2` is true, `arg2` is interpreted as a signed integer; a negative `arg2` will cause a shift in the opposite direction.
+// Any required bits outside the bounds of `arg1` are padded with `vacant_bits` unless `sign_ext` is true, in which case any bits outside the left
+// bounds are filled with the leftmost bit of `arg1` (arithmetic shift).
+static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, bool signed2, int direction, int result_len, RTLIL::State vacant_bits = RTLIL::State::S0)
{
int undef_bit_pos = -1;
- BigInteger offset = const2big(arg2, false, undef_bit_pos) * direction;
+ BigInteger offset = const2big(arg2, signed2, undef_bit_pos) * direction;
if (result_len < 0)
result_len = arg1.bits.size();
for (int i = 0; i < result_len; i++) {
BigInteger pos = BigInteger(i) + offset;
if (pos < 0)
- result.bits[i] = RTLIL::State::S0;
+ result.bits[i] = vacant_bits;
else if (pos >= BigInteger(int(arg1.bits.size())))
- result.bits[i] = sign_ext ? arg1.bits.back() : RTLIL::State::S0;
+ result.bits[i] = sign_ext ? arg1.bits.back() : vacant_bits;
else
result.bits[i] = arg1.bits[pos.toInt()];
}
{
RTLIL::Const arg1_ext = arg1;
extend_u0(arg1_ext, result_len, signed1);
- return const_shift_worker(arg1_ext, arg2, false, -1, result_len);
+ return const_shift_worker(arg1_ext, arg2, false, false, -1, result_len);
}
RTLIL::Const RTLIL::const_shr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
{
RTLIL::Const arg1_ext = arg1;
extend_u0(arg1_ext, max(result_len, GetSize(arg1)), signed1);
- return const_shift_worker(arg1_ext, arg2, false, +1, result_len);
-}
-
-RTLIL::Const RTLIL::const_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
-{
- if (!signed1)
- return const_shl(arg1, arg2, signed1, signed2, result_len);
- return const_shift_worker(arg1, arg2, true, -1, result_len);
+ return const_shift_worker(arg1_ext, arg2, false, false, +1, result_len);
}
-RTLIL::Const RTLIL::const_sshr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+RTLIL::Const RTLIL::const_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
{
- if (!signed1)
- return const_shr(arg1, arg2, signed1, signed2, result_len);
- return const_shift_worker(arg1, arg2, true, +1, result_len);
+ return const_shift_worker(arg1, arg2, signed1, false, -1, result_len);
}
-static RTLIL::Const const_shift_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool signed2, int result_len, RTLIL::State other_bits)
+RTLIL::Const RTLIL::const_sshr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
{
- int undef_bit_pos = -1;
- BigInteger offset = const2big(arg2, signed2, undef_bit_pos);
-
- if (result_len < 0)
- result_len = arg1.bits.size();
-
- RTLIL::Const result(RTLIL::State::Sx, result_len);
- if (undef_bit_pos >= 0)
- return result;
-
- for (int i = 0; i < result_len; i++) {
- BigInteger pos = BigInteger(i) + offset;
- if (pos < 0 || pos >= BigInteger(int(arg1.bits.size())))
- result.bits[i] = other_bits;
- else
- result.bits[i] = arg1.bits[pos.toInt()];
- }
-
- return result;
+ return const_shift_worker(arg1, arg2, signed1, false, +1, result_len);
}
RTLIL::Const RTLIL::const_shift(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{
- return const_shift_shiftx(arg1, arg2, signed1, signed2, result_len, RTLIL::State::S0);
+ RTLIL::Const arg1_ext = arg1;
+ extend_u0(arg1_ext, max(result_len, GetSize(arg1)), signed1);
+ return const_shift_worker(arg1_ext, arg2, false, signed2, +1, result_len);
}
-RTLIL::Const RTLIL::const_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+RTLIL::Const RTLIL::const_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool signed2, int result_len)
{
- return const_shift_shiftx(arg1, arg2, signed1, signed2, result_len, RTLIL::State::Sx);
+ return const_shift_worker(arg1, arg2, false, signed2, +1, result_len, RTLIL::State::Sx);
}
RTLIL::Const RTLIL::const_lt(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)