| // Copyright lowRISC contributors. | |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. | |
| // SPDX-License-Identifier: Apache-2.0 | |
| #ifndef OPENTITAN_SW_DEVICE_LIB_BASE_MOCK_MMIO_TEST_UTILS_H_ | |
| #define OPENTITAN_SW_DEVICE_LIB_BASE_MOCK_MMIO_TEST_UTILS_H_ | |
| #include <initializer_list> | |
| #include <memory> | |
| #include <random> | |
| #include <stdint.h> | |
| #include <string.h> | |
| #include <vector> | |
| #include "gmock/gmock.h" | |
| #include "gtest/gtest.h" | |
| namespace mock_mmio { | |
| /** | |
| * Represents a single bit field in an integer, useable with EXPECT_* macros | |
| * defined in this file. | |
| * | |
| * An integer can be expressed as a list of BitField values, and can be more | |
| * convenient to use than 0b or 0x literals in some cases. For example, the | |
| * integer 0b0000'0000'1100'0101 could be expressed as | |
| * {{0x0, 1}, {0x2, 1}, {0x4, 12}} | |
| * This form makes it clearer to the reader that 0x0, 0x2, and 04 are indices | |
| * to bitfields, which are set to particular values. | |
| * | |
| * In practice, this might use generated register constants, and look like | |
| * {{FIELD_FOO_OFFSET, 1}, {FIELD_BAR_OFFSET, 1}, {FIELD_BAZ_OFFSET, 12}} | |
| * | |
| * This type does not specify the lengths of bitfields; MaskedBitField should be | |
| * used for that, instead. | |
| */ | |
| struct BitField { | |
| uintptr_t offset; | |
| uintptr_t value; | |
| }; | |
| /** | |
| * Represents a single bit field in an integer, similar to BitField. It can be | |
| * used in most places that need a BitField, as well as in `EXPECT_MASK` macros. | |
| * | |
| * Like with BitFields, we can express the integer 0b0000'0000'1100'0101 as a | |
| * list of BitFieldMasks: | |
| * {{0x0, 0x1, 1}, {0x1, 0x1, 0}, {0x2, 0x1, 1}, {0x3, 0x1, 0}, | |
| * {0x4, 0xff, 12}} | |
| * | |
| * In addition to showing how the integer is broken up, it also expresses | |
| * the lengths of fields, so it is clear that 0x0 and 0x2 are one-bit fields. | |
| * This also allows us to formally express that the fields 0x1 and 0x3 are | |
| * *unset*. | |
| * | |
| * In practice, this might use generated register constants, and look like | |
| * {{FIELD_FOO_OFFSET, FIELD_FOO_MASK, 1}, ...} | |
| */ | |
| struct MaskedBitField { | |
| uintptr_t offset; | |
| uintptr_t mask; | |
| uintptr_t value; | |
| }; | |
| /** | |
| * Implicit conversion guard around `char *`. See `LeInt()`. | |
| */ | |
| struct LittleEndianBytes { | |
| const char *bytes; | |
| }; | |
| /** | |
| * Converts the argument into an unsigned integer of type `Int`. | |
| * | |
| * This overload is simply the identity on integers, and allows integers to be | |
| * converted into themselves. This enables the basic EXPECT_* macros: | |
| * EXPECT_READ32(offset, 0xcafecafe); | |
| * | |
| * @param val an integer. | |
| * @return the value `val`. | |
| */ | |
| template <typename Int> | |
| Int ToInt(Int val) { | |
| return val; | |
| } | |
| /** | |
| * Converts the argument into an unsinged integer of type `Int`. | |
| * | |
| * This overload assumes that `str` is a valid pointer to a buffer of at least | |
| * `sizeof(Int)` bytes, which are memcpy'd out as an `Int`. This enables | |
| * memcpy-like EXPECT_* macros: | |
| * EXPECT_READ32(offset, LeInt("rv32")); | |
| * EXPECT_READ32(offset, LeInt("imc\0")); | |
| * | |
| * @param str a pointer to a valid buffer of length at least `sizeof(Int)`. | |
| * @return a value of type `Int` memcpy'd out of `str`. | |
| */ | |
| template <typename Int> | |
| Int ToInt(LittleEndianBytes str) { | |
| Int val; | |
| memcpy(&val, str.bytes, sizeof(Int)); | |
| return val; | |
| } | |
| /** | |
| * Converts the argument into an unsigned integer of type `Int`. | |
| * | |
| * This overload performs the shifts and ors described by `fields`. See | |
| * `BitField`'s documentation for details one what this means. This overload | |
| * enables bitfield EXPECT_* macros: | |
| * EXPECT_READ32(offset, {{A_OFFSET, 0x55}, {B_OFFSET, 0xaa}}); | |
| * EXPECT_READ32(offset, fields); | |
| * where `fields` is an `std::vector<BitField>`. | |
| * | |
| * @param fields a list of bit field entries. | |
| * @return a value of type `Int` built out of `fields`. | |
| */ | |
| template <typename Int> | |
| Int ToInt(std::vector<BitField> fields) { | |
| Int val = 0; | |
| for (auto field : fields) { | |
| // Due to the way that gtest ASSERT_* works, and the fact that this must be | |
| // a function (since we use function overloading), these cannot be ASSERTs, | |
| // and must be EXPECTs. | |
| EXPECT_LE(field.offset, sizeof(Int) * 8); | |
| val |= static_cast<Int>(field.value << field.offset); | |
| } | |
| return val; | |
| } | |
| } // namespace mock_mmio | |
| #endif // OPENTITAN_SW_DEVICE_LIB_BASE_MOCK_MMIO_TEST_UTILS_H_ |