diff --git a/src/base/bitfield.hh b/src/base/bitfield.hh index 9dc7722998..d47ab8c594 100644 --- a/src/base/bitfield.hh +++ b/src/base/bitfield.hh @@ -112,7 +112,9 @@ mask(unsigned first, unsigned last) } /** - * Sign-extend an N-bit value to 64 bits. + * Sign-extend an N-bit value to 64 bits. Assumes all bits past the sign are + * currently zero. For true sign extension regardless of the value of the sign + * bit, see szext. * * @ingroup api_bitfield */ @@ -126,6 +128,24 @@ sext(uint64_t val) return val; } +/** + * Sign-extend an N-bit value to 64 bits. Zero any bits past the sign if + * necessary. + * + * @ingroup api_bitfield + */ +template +constexpr inline uint64_t +szext(uint64_t val) +{ + bool sign_bit = bits(val, N - 1); + if (sign_bit) + val |= ~mask(N); + else + val &= mask(N); + return val; +} + /** * Returns val with bits first to last set to the LSBs of bit_val * diff --git a/src/base/bitfield.test.cc b/src/base/bitfield.test.cc index 8097415217..c2ef8d2b6f 100644 --- a/src/base/bitfield.test.cc +++ b/src/base/bitfield.test.cc @@ -164,7 +164,8 @@ TEST(BitfieldTest, MbitsEntireRange) /* * The following tests the "sext(X)" function. sext carries out a sign - * extention from N bits to 64 bits on value X. + * extention from N bits to 64 bits on value X. It does not zero bits past the + * sign bit if it was zero. */ TEST(BitfieldTest, SignExtendPositiveInput) { @@ -191,6 +192,36 @@ TEST(BitfieldTest, SignExtendNegativeInputOutsideRange) uint64_t output = 0xF800000010000008; EXPECT_EQ(output, sext<60>(val)); } +/* + * The following tests the "szext(X)" function. szext carries out a sign + * extention from N bits to 64 bits on value X. Will zero bits past the sign + * bit if it was zero. + */ +TEST(BitfieldTest, SignZeroExtendPositiveInput) +{ + int8_t val = 14; + int64_t output = 14; + EXPECT_EQ(output, szext<8>(val)); +} + +TEST(BitfieldTest, SignZeroExtendNegativeInput) +{ + int8_t val = -14; + uint64_t output = -14; + EXPECT_EQ(output, szext<8>(val)); +} + +TEST(BitfieldTest, SignZeroExtendPositiveInputOutsideRange) +{ + EXPECT_EQ(0, szext<8>(1 << 10)); +} + +TEST(BitfieldTest, SignZeroExtendNegativeInputOutsideRange) +{ + uint64_t val = 0x4800000010000008; + uint64_t output = 0xF800000010000008; + EXPECT_EQ(output, szext<60>(val)); +} /* The following tests "insertBits(A, B, C, D)". insertBits returns A * with bits B to C set to D's (B - C) LSBs. "insertBits(A, B, D)" overrides