|
1 | 1 | #include "radix.h" |
2 | 2 | #include "absl/strings/str_format.h" |
| 3 | +#include <optional> |
3 | 4 |
|
4 | 5 | namespace sv { |
5 | | -std::string FormatValue(const std::string &bin, Radix radix, |
6 | | - bool leading_zeroes, bool drop_size) { |
| 6 | + |
| 7 | +namespace { |
| 8 | + |
| 9 | +int64_t SignExtend(uint64_t val, int bits) { |
| 10 | + if (val & (1ull << (bits - 1))) return val | (static_cast<uint64_t>(-1) << bits); |
| 11 | + return val; |
| 12 | +} |
| 13 | + |
| 14 | +template <typename T> |
| 15 | +std::optional<T> BinStringCast(std::string_view bin) { |
| 16 | + std::optional<uint64_t> val_or = BinStringToUnsigned(bin); |
| 17 | + if (!val_or) return std::nullopt; |
| 18 | + const uint64_t val = *val_or; |
| 19 | + T t; |
| 20 | + memcpy(&t, &val, sizeof(T)); |
| 21 | + return t; |
| 22 | +} |
| 23 | + |
| 24 | +} // namespace |
| 25 | + |
| 26 | +std::optional<uint64_t> BinStringToUnsigned(std::string_view bin) { |
| 27 | + if (bin.size() > 64) return std::nullopt; |
| 28 | + uint64_t val = 0; |
| 29 | + for (char ch : bin) { |
| 30 | + if (ch != '0' && ch != '1') return std::nullopt; |
| 31 | + val <<= 1; |
| 32 | + val |= ch == '1'; |
| 33 | + } |
| 34 | + return val; |
| 35 | +} |
| 36 | + |
| 37 | +std::optional<float> BinStringToFp32(std::string_view bin) { return BinStringCast<float>(bin); } |
| 38 | + |
| 39 | +std::optional<double> BinStringToFp64(std::string_view bin) { return BinStringCast<double>(bin); } |
| 40 | + |
| 41 | +std::optional<int64_t> BinStringToSigned(std::string_view bin) { |
| 42 | + std::optional<uint64_t> val_or = BinStringToUnsigned(bin); |
| 43 | + if (!val_or) return std::nullopt; |
| 44 | + return SignExtend(*val_or, bin.size()); |
| 45 | +} |
| 46 | + |
| 47 | +std::string FormatValue(const std::string &bin, Radix radix, bool leading_zeroes, bool drop_size) { |
7 | 48 | if (radix == Radix::kUnsignedDecimal || radix == Radix::kSignedDecimal || |
8 | 49 | radix == Radix::kFloat) { |
9 | 50 | // These formats can use a real machine type and therefore take advantage of |
10 | 51 | // printf style formatting. |
11 | | - uint64_t val = 0; |
12 | | - for (int i = 0; i < bin.size(); ++i) { |
13 | | - const char ch = std::tolower(bin[bin.size() - 1 - i]); |
14 | | - if (ch == 'z' || ch == 'x') return "x"; |
15 | | - if (bin[bin.size() - 1 - i] == '1') val |= 1ull << i; |
16 | | - } |
| 52 | + std::optional<uint64_t> maybe_val = BinStringToUnsigned(bin); |
| 53 | + if (!maybe_val) return "x"; |
| 54 | + uint64_t val = *maybe_val; |
17 | 55 | if (radix == Radix::kUnsignedDecimal) { |
18 | | - return (drop_size ? "" : absl::StrFormat("%d'd", bin.size())) + |
19 | | - absl::StrFormat("%lu", val); |
| 56 | + return (drop_size ? "" : absl::StrFormat("%d'd", bin.size())) + absl::StrFormat("%lu", val); |
20 | 57 | } else if (radix == Radix::kSignedDecimal) { |
21 | | - return (drop_size ? "" : absl::StrFormat("%d'sd", bin.size())) + |
22 | | - absl::StrFormat("%ld", val); |
| 58 | + int64_t sval = SignExtend(val, bin.size()); |
| 59 | + return (drop_size ? "" : absl::StrFormat("%d'sd", bin.size())) + absl::StrFormat("%ld", sval); |
23 | 60 | } else if (bin.size() == 32) { |
24 | 61 | float f; |
25 | 62 | memcpy(&f, &val, sizeof(float)); |
|
0 commit comments