|  | // 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_ |