diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 2d313537895..0d2ddf42888 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -28,6 +28,7 @@ #include #include +#include YOSYS_NAMESPACE_BEGIN @@ -280,6 +281,52 @@ int RTLIL::Const::as_int(bool is_signed) const return ret; } +size_t RTLIL::Const::get_min_size(bool is_signed) const +{ + if (bits.empty()) return 0; + + // back to front (MSB to LSB) + RTLIL::State leading_bit; + if (is_signed) + leading_bit = (bits.back() == RTLIL::State::Sx) ? RTLIL::State::S0 : bits.back(); + else + leading_bit = RTLIL::State::S0; + + size_t idx = bits.size(); + while (idx > 0 && bits[idx -1] == leading_bit) { + idx--; + } + + // signed needs one leading bit + if (is_signed && idx < bits.size()) { + idx++; + } + // must be at least one bit + return (idx == 0) ? 1 : idx; +} + +void RTLIL::Const::compress(bool is_signed) +{ + size_t idx = get_min_size(is_signed); + bits.erase(bits.begin() + idx, bits.end()); +} + +std::optional RTLIL::Const::as_int_compress(bool is_signed) const +{ + size_t size = get_min_size(is_signed); + if(size == 0 || size > 32) + return std::nullopt; + + int32_t ret = 0; + for (size_t i = 0; i < size && i < 32; i++) + if (bits[i] == State::S1) + ret |= 1 << i; + if (is_signed && bits[size-1] == State::S1) + for (size_t i = size; i < 32; i++) + ret |= 1 << i; + return ret; +} + std::string RTLIL::Const::as_string() const { std::string ret; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index c49734cd08b..c5a02458536 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -703,6 +703,14 @@ struct RTLIL::Const return ret; } + // find the MSB without redundant leading bits + size_t get_min_size(bool is_signed) const; + + // compress representation to the minimum required bits + void compress(bool is_signed = false); + + std::optional as_int_compress(bool is_signed) const; + void extu(int width) { bits.resize(width, RTLIL::State::S0); }