diff --git a/kernel/yosys.cc b/kernel/yosys.cc index c7f5bebdab7..6ef9f4b4c4a 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -73,6 +73,10 @@ #include #include +#if __cplusplus >= 202002L +# include +#endif + #include "libs/json11/json11.hpp" YOSYS_NAMESPACE_BEGIN @@ -175,6 +179,41 @@ int ceil_log2(int x) #endif } +// Calculate the minimum number of bits required to store an unsigned integer value. +// Note that min_bit_width(0u) == 0. +int min_bit_width(unsigned x) +{ +#if __cplusplus >= 202002L + return std::bit_width(x); +#else + int width = 0; + while (x) { + width += 1; + x >>= 1; + } + return width; +#endif +} + +// Calculate the minimum number of bits required to store a signed integer value, +// using two's complement representation for negative values. +int min_bit_width(int x) +{ + int sgn = 0; + if (x < 0) { + // Compute two's complement of negative value. + // Negative numbers are represented in two's complement form + // in SystemVerilog, and this is also guaranteed by C++20. + // C++20 also makes integral conversion of unsigned integers + // to signed integers well defined. + x = -(unsigned)x; + // Add a bit for sign, except for the most negative number, + // whose two's complement is equal to itself, i.e. MSB is set. + sgn += (x >= 0); + } + return sgn + min_bit_width((unsigned)x); +} + int readsome(std::istream &f, char *s, int n) { int rc = int(f.readsome(s, n)); diff --git a/kernel/yosys.h b/kernel/yosys.h index 0a4641d1819..43cd756b56f 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -274,6 +274,8 @@ inline void memhasher() { if (memhasher_active) memhasher_do(); } void yosys_banner(); int ceil_log2(int x) YS_ATTRIBUTE(const); +int min_bit_width(unsigned x); +int min_bit_width(int x); inline std::string vstringf(const char *fmt, va_list ap) {