blob: 265f7d12e1dda0dd96291699929a2724da39aae2 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <zircon/assert.h>
#include <atomic>
#include <cstdint>
#include <fbl/bits.h>
#include <zxtest/zxtest.h>
namespace {
TEST(ExtractBitsTest, BasicCases) {
EXPECT_EQ(0b1001u, (fbl::ExtractBits<3, 0, uint8_t>(0b10101001u)));
EXPECT_EQ(0b1u, (fbl::ExtractBit<0, uint8_t>(0b10101001u)));
EXPECT_EQ(0b0u, (fbl::ExtractBit<2, uint8_t>(0b10101001u)));
EXPECT_EQ(0b1001u, (fbl::ExtractBits<5, 2, uint8_t>(0b1010100100u)));
EXPECT_EQ(0b1001u, (fbl::ExtractBits<63, 60, uint64_t>(0x9000000000000000u)));
EXPECT_EQ(0xe7c07357u, (fbl::ExtractBits<63, 32, uint32_t>(0xe7c0735700000000)));
}
const uint64_t test_val_3b = 0b101;
const uint64_t test_val_4b = 0b1001;
const uint64_t test_val_5b = 0b10001;
const uint64_t test_val_8b = 0b10000001;
const uint64_t test_val_13b = 0b1000000000001;
FBL_BITFIELD_DEF_START(TestBFuint64, uint64_t)
FBL_BITFIELD_MEMBER(m0_3bits, 0, 3);
FBL_BITFIELD_MEMBER(m1_4bits, 3, 4);
FBL_BITFIELD_MEMBER(m2_8bits, 7, 8);
FBL_BITFIELD_MEMBER(m3_13bits, 15, 13);
FBL_BITFIELD_MEMBER(m4_5bits, 28, 5);
FBL_BITFIELD_MEMBER(unused, 33, 31);
FBL_BITFIELD_DEF_END();
TEST(BitfieldTest, ReadWriteUint64) {
TestBFuint64 bf;
ASSERT_EQ(bf.value, 0u);
ASSERT_EQ(bf.m0_3bits.maximum(), 7);
ASSERT_EQ(bf.m1_4bits.maximum(), 15);
ASSERT_EQ(bf.m2_8bits.maximum(), 255);
ASSERT_EQ(bf.m3_13bits.maximum(), 8191);
ASSERT_EQ(bf.m4_5bits.maximum(), 31);
uint64_t test_val = 0;
test_val |= test_val_3b << 0;
test_val |= test_val_4b << 3;
test_val |= test_val_8b << 7;
test_val |= test_val_13b << 15;
test_val |= test_val_5b << 28;
bf.value = test_val;
ASSERT_EQ(bf.m0_3bits, test_val_3b);
ASSERT_EQ(bf.m1_4bits, test_val_4b);
ASSERT_EQ(bf.m2_8bits, test_val_8b);
ASSERT_EQ(bf.m3_13bits, test_val_13b);
ASSERT_EQ(bf.m4_5bits, test_val_5b);
ASSERT_EQ(bf.unused, 0u);
bf.m0_3bits = 0u;
ASSERT_EQ(bf.m0_3bits, 0u);
ASSERT_EQ(bf.m1_4bits, test_val_4b);
ASSERT_EQ(bf.m2_8bits, test_val_8b);
ASSERT_EQ(bf.m3_13bits, test_val_13b);
ASSERT_EQ(bf.m4_5bits, test_val_5b);
ASSERT_EQ(bf.unused, 0u);
bf.value = test_val;
bf.m1_4bits = 0u;
ASSERT_EQ(bf.m0_3bits, test_val_3b);
ASSERT_EQ(bf.m1_4bits, 0u);
ASSERT_EQ(bf.m2_8bits, test_val_8b);
ASSERT_EQ(bf.m3_13bits, test_val_13b);
ASSERT_EQ(bf.m4_5bits, test_val_5b);
ASSERT_EQ(bf.unused, 0u);
bf.value = test_val;
bf.m2_8bits = 0u;
ASSERT_EQ(bf.m0_3bits, test_val_3b);
ASSERT_EQ(bf.m1_4bits, test_val_4b);
ASSERT_EQ(bf.m2_8bits, 0u);
ASSERT_EQ(bf.m3_13bits, test_val_13b);
ASSERT_EQ(bf.m4_5bits, test_val_5b);
ASSERT_EQ(bf.unused, 0u);
bf.value = test_val;
bf.m3_13bits = 0u;
ASSERT_EQ(bf.m0_3bits, test_val_3b);
ASSERT_EQ(bf.m1_4bits, test_val_4b);
ASSERT_EQ(bf.m2_8bits, test_val_8b);
ASSERT_EQ(bf.m3_13bits, 0u);
ASSERT_EQ(bf.m4_5bits, test_val_5b);
ASSERT_EQ(bf.unused, 0u);
bf.value = test_val;
bf.m4_5bits = 0u;
ASSERT_EQ(bf.m0_3bits, test_val_3b);
ASSERT_EQ(bf.m1_4bits, test_val_4b);
ASSERT_EQ(bf.m2_8bits, test_val_8b);
ASSERT_EQ(bf.m3_13bits, test_val_13b);
ASSERT_EQ(bf.m4_5bits, 0u);
ASSERT_EQ(bf.unused, 0u);
}
TEST(BitfieldTest, AssignFromBitField) {
TestBFuint64 bf1, bf2;
ASSERT_EQ(bf1.value, 0u);
ASSERT_EQ(bf2.value, 0u);
bf1.m1_4bits = test_val_4b;
bf2.m2_8bits = test_val_8b;
bf1.m2_8bits = bf2.m2_8bits;
// |bf1.m1_4bits| should not be overwritten.
ASSERT_EQ(bf1.m1_4bits, test_val_4b);
ASSERT_EQ(bf1.m2_8bits, test_val_8b);
}
constexpr TestBFuint64 cex_bf_uint64;
static_assert(sizeof(cex_bf_uint64.m0_3bits) == sizeof(uint64_t));
union Rights {
uint32_t raw_value = 0u;
fbl::BitFieldMember<uint32_t, 0, 1> read;
fbl::BitFieldMember<uint32_t, 1, 1> write;
fbl::BitFieldMember<uint32_t, 2, 1> admin;
fbl::BitFieldMember<uint32_t, 3, 1> execute;
constexpr Rights() {}
constexpr static Rights ReadExec() {
Rights rights;
rights.read = true;
rights.execute = true;
return rights;
}
};
TEST(BitfieldTest, AssignMultipleValuesThenRead) {
auto rights = Rights::ReadExec();
// (read | execute) should be (1 | 8) == 9. gcc 8.3 produced the value 8 for this
// scenario when not using std::memcpy() to assign values: https://godbolt.org/z/YBBCKz
ASSERT_EQ(rights.raw_value, 9);
}
union ByteBitfield {
uint8_t value = 0;
fbl::BitFieldMember<uint8_t, 0, 4> low_nibble;
fbl::BitFieldMember<uint8_t, 7, 1> high_bit;
};
TEST(BitfieldTest, ReadWriteUint8) {
ByteBitfield byte;
ASSERT_EQ(byte.value, 0);
byte.value = 0xFC;
ASSERT_EQ(byte.low_nibble, 0x0C);
ASSERT_EQ(byte.high_bit, 1);
byte.high_bit = 0;
byte.low_nibble = 0x05;
ASSERT_EQ(byte.value, 0x75);
}
#ifndef ASSERT_DEATH
#define ASSERT_DEATH(...) // Not available on host.
#endif
TEST(BitfieldTest, WriteOverflowCrashes) {
ByteBitfield byte;
ASSERT_EQ(byte.value, 0);
ASSERT_DEATH(
[&byte]() { byte.low_nibble = 0xFF; },
"Assert should have fired after writing a value that is too big into a BitFieldElement\n");
}
} // namespace