libmicroemu 0.2.0
ARM Microcontroller Emulator Library
Loading...
Searching...
No Matches
mem_map_rw.h
1#pragma once
2
3#include "libmicroemu/internal/bus/mem/mem_traits.h"
4#include "libmicroemu/internal/bus/mem_access_results.h"
6#include "libmicroemu/internal/utils/bit_manip.h"
7#include "libmicroemu/logger.h"
8#include "libmicroemu/types.h"
9#include <tuple>
10
11namespace libmicroemu::internal {
12
13template <typename TCpuAccessor, typename TPeripheral, typename TLogger = NullLogger>
15public:
16 static_assert(has_kRegisters_v<TPeripheral>, "TPeripheral must have kRegisters");
17 static_assert(std::is_const_v<decltype(TPeripheral::kRegisters)>,
18 "kRegisters must be a constant");
19
20 using MapEnum = typename TPeripheral::MapEnum;
21
22 static constexpr u32 GetBeginPhysicalAddress() { return TPeripheral::GetBeginPhysicalAddress(); }
23 static constexpr u32 GetEndPhysicalAddress() { return TPeripheral::GetEndPhysicalAddress(); }
24
25 static constexpr auto kRegisters = TPeripheral::kRegisters;
26
27 template <typename T> static ReadResult<T> ReadRegister(TCpuAccessor &cpua, me_adr_t padr) {
28 return ReadRegisterRecursive<T, decltype(kRegisters)>(padr, cpua);
29 }
30
31 template <typename T>
32 static WriteResult<T> WriteRegister(TCpuAccessor &cpua, me_adr_t padr, T value) {
33 return WriteRegisterRecursive<T, decltype(kRegisters)>(padr, cpua, value);
34 }
35
36private:
37 template <typename T, typename Registers, std::size_t Index = 0U>
38 static ReadResult<T> ReadRegisterRecursive(const u32 &padr, TCpuAccessor &cpua) {
39 if constexpr (Index < std::tuple_size_v<Registers>) {
40 using TypeRegAccess = std::tuple_element_t<Index, Registers>;
41
42 auto constexpr pstart_adr = static_cast<me_adr_t>(TypeRegAccess::kAdr);
43 auto constexpr pend_adr = static_cast<me_adr_t>(pstart_adr + sizeof(u32) - 1U);
44 if (padr >= pstart_adr && padr <= pend_adr) {
45
46 const auto read_32 = TypeRegAccess::ReadRegister(cpua);
47 const me_adr_t start_byte = padr - pstart_adr;
48 T read_t = Bm32::ExtractType<T>(read_32, start_byte);
49 LOG_TRACE(TLogger, "READ: padr = 0x%X, width = %u, value = 0x%X", padr, sizeof(T), read_t);
50
51 return ReadResult<T>{read_t, ReadStatusCode::kOk};
52 } else {
53 return ReadRegisterRecursive<T, Registers, Index + 1U>(padr, cpua);
54 }
55 }
56 return ReadResult<T>{0x0U, ReadStatusCode::kReadNotAllowed};
57 }
58
59 template <
60 typename TRegAccess, typename T,
61 typename std::enable_if_t<!TRegAccess::kReadOnly && !TRegAccess::kUseReadModifyWrite, T> = 0>
62 static WriteResult<T> PerformWrite(const u32 &padr, TCpuAccessor &cpua, T value) {
63 u32 write_value{0x0U};
64 if constexpr (std::is_same_v<T, u32>) {
65 write_value = value;
66 } else {
67 me_adr_t start_byte = padr - static_cast<me_adr_t>(TRegAccess::kAdr);
68 write_value = Bm32::InsertType(0x0U, start_byte, value);
69 }
70
71 LOG_TRACE(TLogger, "WRITE (No read): padr = 0x%X, width = %u, value = 0x%X", padr, sizeof(T),
72 write_value);
73
74 TRegAccess::WriteRegister(cpua, write_value);
75
76 return WriteResult<T>{WriteStatusCode::kOk};
77 }
78
79 template <
80 typename TRegAccess, typename T,
81 typename std::enable_if_t<!TRegAccess::kReadOnly && TRegAccess::kUseReadModifyWrite, T> = 0>
82 static WriteResult<T> PerformWrite(const u32 &padr, TCpuAccessor &cpua, T value) {
83 u32 write_value{0x0U};
84
85 if constexpr (std::is_same_v<T, u32>) {
86 write_value = value;
87 } else {
88 me_adr_t start_byte = padr - static_cast<me_adr_t>(TRegAccess::kAdr);
89
90 // read modify write
91 const auto read_32 = TRegAccess::ReadRegister(cpua);
92 write_value = Bm32::InsertType(read_32, start_byte, value);
93 }
94
95 LOG_TRACE(TLogger, "WRITE: padr = 0x%X, width = %u, value = 0x%X", padr, sizeof(T),
96 write_value);
97
98 TRegAccess::WriteRegister(cpua, write_value);
99
100 return WriteResult<T>{WriteStatusCode::kOk};
101 }
102
103 template <
104 typename TRegAccess, typename T,
105 typename std::enable_if_t<TRegAccess::kReadOnly && !TRegAccess::kUseReadModifyWrite, T> = 0>
106 static WriteResult<T> PerformWrite(const u32 &padr, TCpuAccessor &cpua, T value) {
107 static_cast<void>(padr);
108 static_cast<void>(cpua);
109 static_cast<void>(value);
110 return WriteResult<T>{WriteStatusCode::kWriteNotAllowed};
111 }
112
113 template <typename T, typename Registers, std::size_t Index = 0U>
114 static WriteResult<T> WriteRegisterRecursive(const u32 &padr, TCpuAccessor &cpua, T value) {
115 if constexpr (Index < std::tuple_size_v<Registers>) {
116 using TypeRegAccess = std::tuple_element_t<Index, Registers>;
117
118 auto constexpr pstart_adr = static_cast<me_adr_t>(TypeRegAccess::kAdr);
119 auto constexpr pend_adr = static_cast<me_adr_t>(pstart_adr + sizeof(u32) - 1U);
120
121 if (padr >= pstart_adr && padr <= pend_adr) {
122 return PerformWrite<TypeRegAccess, T>(padr, cpua, value);
123 } else {
124 return WriteRegisterRecursive<T, Registers, Index + 1U>(padr, cpua, value);
125 }
126 }
127 return WriteResult<T>{WriteStatusCode::kWriteNotAllowed};
128 }
129};
130
131template <unsigned Id, unsigned VadrOffset, unsigned VadrRange, typename TCpuAccessor,
132 typename TExceptionTrigger, typename TLogger, typename... TPeripherals>
133class MemMapRw {
134public:
135 using ExcTrig = TExceptionTrigger;
136
140 MemMapRw() = default;
141
145 virtual ~MemMapRw() = default;
146
151 MemMapRw(const MemMapRw &r_src) = default;
152
157 MemMapRw &operator=(const MemMapRw &r_src) = default;
158
163 MemMapRw(MemMapRw &&r_src) = default;
164
169 MemMapRw &operator=(MemMapRw &&r_src) = default;
170
171 static constexpr bool kReadOnly = false;
172
173 // -------------------------------------------------
174 // Read from Peripheral List
175 // -------------------------------------------------
176
177 template <typename T, typename First, typename... Rest>
178 static ReadResult<T> ReadRegisters(TCpuAccessor &cpua, const u32 &padr) {
180
181 if (padr >= Type::GetBeginPhysicalAddress() && padr <= Type::GetEndPhysicalAddress()) {
182 const auto read_32 = Type::template ReadRegister<T>(cpua, padr);
183 return read_32;
184 } else {
185 return ReadRegisters<T, Rest...>(cpua, padr);
186 }
187 }
188
189 template <typename T> static ReadResult<T> ReadRegisters(TCpuAccessor &cpua, const u32 &padr) {
190 static_cast<void>(cpua);
191 static_cast<void>(padr);
192 return ReadResult<T>{0x0U, ReadStatusCode::kReadNotAllowed};
193 }
194
195 // -------------------------------------------------
196 // Write from Peripheral List
197 // -------------------------------------------------
198 template <typename T, typename First, typename... Rest>
199 static WriteResult<T> WriteRegisters(TCpuAccessor &cpua, const u32 &padr, const T &value) {
200 using Type = MemMapAccessPoint<TCpuAccessor, First, TLogger>;
201
202 if (padr >= Type::GetBeginPhysicalAddress() && padr <= Type::GetEndPhysicalAddress()) {
203 const auto write_32 = Type::template WriteRegister<T>(cpua, padr, value);
204 return write_32;
205 } else {
206 return WriteRegisters<T, Rest...>(cpua, padr, value);
207 }
208 }
209
210 template <typename T>
211 static WriteResult<T> WriteRegisters(TCpuAccessor &cpua, const u32 &padr, const T &value) {
212 static_cast<void>(cpua);
213 static_cast<void>(padr);
214 static_cast<void>(value);
215 return WriteResult<T>{WriteStatusCode::kWriteNotAllowed};
216 }
217
218 // -------------------------------------------------
219 // API Methods
220 // -------------------------------------------------
221 template <typename T> ReadResult<T> Read(TCpuAccessor &cpua, me_adr_t vadr) const {
222 // clang-format off
223 static_assert(
224 std::is_same<T, u32>::value ||
225 std::is_same<T, u16>::value ||
226 std::is_same<T, u8>::value,
227 "Read only allows u32, u16 and u8");
228 // clang-format on
229
230 const me_adr_t padr = ConvertToPhysicalAdr(vadr);
231 assert(IsPAdrInRange(padr) == true);
232 auto read_res = ReadRegisters<T, TPeripherals...>(cpua, padr);
233 return ReadResult<T>{static_cast<T>(read_res.content), read_res.status_code};
234 }
235
236 template <typename T>
237 WriteResult<T> Write(TCpuAccessor &cpua, me_adr_t vadr, const T &value) const {
238 // clang-format off
239 static_assert(
240 std::is_same<T, u32>::value ||
241 std::is_same<T, u16>::value ||
242 std::is_same<T, u8>::value,
243 "Write only allows u32, u16 and u8 types");
244 // clang-format on
245
246 const me_adr_t padr = ConvertToPhysicalAdr(vadr);
247 assert(IsPAdrInRange(padr) == true);
248
249 auto write_res = WriteRegisters<T, TPeripherals...>(cpua, padr, value);
250
251 return WriteResult<T>{write_res.status_code};
252 }
253
254 bool IsVAdrInRange(me_adr_t vadr) const {
255 const me_adr_t padr = ConvertToPhysicalAdr(vadr);
256 if (IsPAdrInRange(padr) == false) {
257 return false;
258 }
259 return true;
260 }
261
262private:
263 me_adr_t ConvertToPhysicalAdr(me_adr_t vadr) const { return vadr - VadrOffset; }
264 bool IsPAdrInRange(me_adr_t padr) const { return padr < VadrRange; }
265};
266
267} // namespace libmicroemu::internal
static U ExtractType(u32 value, u32 start_byte)
Definition bit_manip.h:152
static u32 InsertType(u32 value, u32 start_byte, U insert_val)
Definition bit_manip.h:167
MemMapRw & operator=(const MemMapRw &r_src)=default
Copy assignment operator for MemMapRw.
MemMapRw & operator=(MemMapRw &&r_src)=default
Move assignment operator for MemMapRw.
MemMapRw(const MemMapRw &r_src)=default
Copy constructor for MemMapRw.
virtual ~MemMapRw()=default
Destructor.
MemMapRw(MemMapRw &&r_src)=default
Move constructor for MemMapRw.
MemMapRw()=default
Constructor.
The libmicroemu::internal namespace contains all classes and functions of libmicroemu which are priva...
Definition bkpt_flags.h:6
Contains the Result class which is used to return the result of a function.
Definition mem_access_results.h:11
Definition mem_access_results.h:21