Software APIs
mock_mmio_test_utils.h
1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5#ifndef OPENTITAN_SW_DEVICE_LIB_BASE_MOCK_MMIO_TEST_UTILS_H_
6#define OPENTITAN_SW_DEVICE_LIB_BASE_MOCK_MMIO_TEST_UTILS_H_
7
8#include <initializer_list>
9#include <memory>
10#include <random>
11#include <stdint.h>
12#include <string.h>
13#include <vector>
14
15#include "gmock/gmock.h"
16#include "gtest/gtest.h"
17
18namespace mock_mmio {
19
20/**
21 * Represents a single bit field in an integer, useable with EXPECT_* macros
22 * defined in this file.
23 *
24 * An integer can be expressed as a list of BitField values, and can be more
25 * convenient to use than 0b or 0x literals in some cases. For example, the
26 * integer 0b0000'0000'1100'0101 could be expressed as
27 * {{0x0, 1}, {0x2, 1}, {0x4, 12}}
28 * This form makes it clearer to the reader that 0x0, 0x2, and 04 are indices
29 * to bitfields, which are set to particular values.
30 *
31 * In practice, this might use generated register constants, and look like
32 * {{FIELD_FOO_OFFSET, 1}, {FIELD_BAR_OFFSET, 1}, {FIELD_BAZ_OFFSET, 12}}
33 *
34 * This type does not specify the lengths of bitfields; MaskedBitField should be
35 * used for that, instead.
36 */
37struct BitField {
38 uintptr_t offset;
39 uintptr_t value;
40};
41
42/**
43 * Represents a single bit field in an integer, similar to BitField. It can be
44 * used in most places that need a BitField, as well as in `EXPECT_MASK` macros.
45 *
46 * Like with BitFields, we can express the integer 0b0000'0000'1100'0101 as a
47 * list of BitFieldMasks:
48 * {{0x0, 0x1, 1}, {0x1, 0x1, 0}, {0x2, 0x1, 1}, {0x3, 0x1, 0},
49 * {0x4, 0xff, 12}}
50 *
51 * In addition to showing how the integer is broken up, it also expresses
52 * the lengths of fields, so it is clear that 0x0 and 0x2 are one-bit fields.
53 * This also allows us to formally express that the fields 0x1 and 0x3 are
54 * *unset*.
55 *
56 * In practice, this might use generated register constants, and look like
57 * {{FIELD_FOO_OFFSET, FIELD_FOO_MASK, 1}, ...}
58 */
60 uintptr_t offset;
61 uintptr_t mask;
62 uintptr_t value;
63};
64
65/**
66 * Implicit conversion guard around `char *`. See `LeInt()`.
67 */
69 const char *bytes;
70};
71
72/**
73 * Converts the argument into an unsigned integer of type `Int`.
74 *
75 * This overload is simply the identity on integers, and allows integers to be
76 * converted into themselves. This enables the basic EXPECT_* macros:
77 * EXPECT_READ32(offset, 0xcafecafe);
78 *
79 * @param val an integer.
80 * @return the value `val`.
81 */
82template <typename Int>
83Int ToInt(Int val) {
84 return val;
85}
86
87/**
88 * Converts the argument into an unsinged integer of type `Int`.
89 *
90 * This overload assumes that `str` is a valid pointer to a buffer of at least
91 * `sizeof(Int)` bytes, which are memcpy'd out as an `Int`. This enables
92 * memcpy-like EXPECT_* macros:
93 * EXPECT_READ32(offset, LeInt("rv32"));
94 * EXPECT_READ32(offset, LeInt("imc\0"));
95 *
96 * @param str a pointer to a valid buffer of length at least `sizeof(Int)`.
97 * @return a value of type `Int` memcpy'd out of `str`.
98 */
99template <typename Int>
100Int ToInt(LittleEndianBytes str) {
101 Int val;
102 memcpy(&val, str.bytes, sizeof(Int));
103 return val;
104}
105
106/**
107 * Converts the argument into an unsigned integer of type `Int`.
108 *
109 * This overload performs the shifts and ors described by `fields`. See
110 * `BitField`'s documentation for details one what this means. This overload
111 * enables bitfield EXPECT_* macros:
112 * EXPECT_READ32(offset, {{A_OFFSET, 0x55}, {B_OFFSET, 0xaa}});
113 * EXPECT_READ32(offset, fields);
114 * where `fields` is an `std::vector<BitField>`.
115 *
116 * @param fields a list of bit field entries.
117 * @return a value of type `Int` built out of `fields`.
118 */
119template <typename Int>
120Int ToInt(std::vector<BitField> fields) {
121 Int val = 0;
122 for (auto field : fields) {
123 // Due to the way that gtest ASSERT_* works, and the fact that this must be
124 // a function (since we use function overloading), these cannot be ASSERTs,
125 // and must be EXPECTs.
126 EXPECT_LE(field.offset, sizeof(Int) * 8);
127 val |= static_cast<Int>(field.value << field.offset);
128 }
129 return val;
130}
131} // namespace mock_mmio
132
133#endif // OPENTITAN_SW_DEVICE_LIB_BASE_MOCK_MMIO_TEST_UTILS_H_