-
Notifications
You must be signed in to change notification settings - Fork 837
/
Copy pathmock_mmio_test_utils.h
133 lines (122 loc) · 4.17 KB
/
mock_mmio_test_utils.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright lowRISC contributors (OpenTitan project).
// 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_