libmicroemu 0.2.0
ARM Microcontroller Emulator Library
Loading...
Searching...
No Matches
bus.h
1#pragma once
2#include "libmicroemu/exception_type.h"
3#include "libmicroemu/internal/bus/mem_access_results.h"
5#include "libmicroemu/logger.h"
6#include "libmicroemu/register_details.h"
8#include "libmicroemu/types.h"
9#include <type_traits>
10
11namespace libmicroemu::internal {
12
13enum class BusExceptionType {
14 kRaiseNoException, // No exception has occurred.
15 kRaiseStkerr, // STKERR: A derived bus fault has occurred on exception entry.
16 kRaiseUnstkerr, // UNSTKERR: A derived bus fault has occurred on exception return.
17 kRaiseImpreciseDataBusError, // IMPRECISERR: An imprecise data bus error has occurred.
18 kRaisePreciseDataBusError, // PRECISERR: A precise data bus error has occurred.
19 kRaiseInstructionBusError, // IBUSERR: An instruction bus error has occurred.
20};
21
22template <typename TCpuAccessor, typename TExceptionTrigger, typename TLogger,
23 typename... TBusParticipant>
24class Bus : public TBusParticipant... {
25public:
26 using ExcTrig = TExceptionTrigger;
27
28 explicit Bus(const TBusParticipant &...participant) : TBusParticipant(participant)... {}
29
33 virtual ~Bus() = default;
34
39 Bus(const Bus &r_src) = default;
40
45 Bus &operator=(const Bus &r_src) = default;
46
51 Bus(Bus &&r_src) = default;
52
57 Bus &operator=(Bus &&r_src) = default;
58
59 template <typename T> Result<T> Read(TCpuAccessor &cpua, me_adr_t vadr) const {
60 auto read_result = ForwardRead<T, TBusParticipant...>(cpua, vadr);
61 switch (read_result.status_code) {
62 case ReadStatusCode::kOk: {
63 return Ok<T>(read_result.content);
64 }
65 case ReadStatusCode::kReadNotAllowed: {
66 // ExcTrig::SetPending(cpua, ExceptionType::kSysTick);
67 return Err<T>(StatusCode::kMemInaccesible);
68 }
69 default: {
70 return Err<T>(StatusCode::kUnexpected);
71 }
72 }
73 // not reachable
74 }
75
76 template <typename T>
77 Result<T> ReadOrRaise(TCpuAccessor &cpua, me_adr_t vadr, BusExceptionType exc_type) const {
78 auto read_res = ForwardRead<T, TBusParticipant...>(cpua, vadr);
79
80 if (read_res.status_code == ReadStatusCode::kOk) {
81 return Ok(read_res.content);
82 }
83
84 switch (exc_type) {
85 case BusExceptionType::kRaiseNoException: {
86 return Ok(read_res.content); // No exception to be triggered
87 }
88 case BusExceptionType::kRaiseStkerr: {
89 // Bfar will not be updated according to the ARMv7-M Architecture Reference Manual
90 // cpua.template WriteSpecialRegister<SpecialRegisterId::kBfar>(vadr);
91
92 auto cfsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kCfsr>();
93 // cfsr |= SReg::kCfsrBusFaultBfarValidMsk;
94 cfsr |= CfsrBusFault::kStkerrMsk;
95 cpua.template WriteSpecialRegister<SpecialRegisterId::kCfsr>(cfsr);
96
97 ExcTrig::SetPending(cpua, ExceptionType::kBusFault);
98 return Ok(read_res.content);
99 }
100 case BusExceptionType::kRaiseUnstkerr: {
101 // Bfar will not be updated according to the ARMv7-M Architecture Reference Manual
102 // cpua.template WriteSpecialRegister<SpecialRegisterId::kBfar>(vadr);
103
104 auto cfsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kCfsr>();
105 // cfsr |= SReg::kCfsrBusFaultBfarValidMsk;
106 cfsr |= CfsrBusFault::kUnstkerrMsk;
107 cpua.template WriteSpecialRegister<SpecialRegisterId::kCfsr>(cfsr);
108
109 ExcTrig::SetPending(cpua, ExceptionType::kBusFault);
110 return Ok(read_res.content);
111 }
112 case BusExceptionType::kRaiseImpreciseDataBusError: {
113 // cpua.template WriteSpecialRegister<SpecialRegisterId::kBfar>(vadr);
114
115 auto cfsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kCfsr>();
116 // cfsr |= SReg::kCfsrBusFaultBfarValidMsk;
117 cfsr |= CfsrBusFault::kImpreciseErrMsk;
118 cpua.template WriteSpecialRegister<SpecialRegisterId::kCfsr>(cfsr);
119
120 ExcTrig::SetPending(cpua, ExceptionType::kBusFault);
121 return Ok(read_res.content);
122 }
123 case BusExceptionType::kRaisePreciseDataBusError: {
124 cpua.template WriteSpecialRegister<SpecialRegisterId::kBfar>(vadr);
125
126 auto cfsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kCfsr>();
127 cfsr |= CfsrBusFault::kBfarValidMsk;
128 cfsr |= CfsrBusFault::kPreciseErrMsk;
129 cpua.template WriteSpecialRegister<SpecialRegisterId::kCfsr>(cfsr);
130
131 ExcTrig::SetPending(cpua, ExceptionType::kBusFault);
132 return Ok(read_res.content);
133 }
134 case BusExceptionType::kRaiseInstructionBusError: {
135 // cpua.template WriteSpecialRegister<SpecialRegisterId::kBfar>(vadr);
136 cpua.template WriteSpecialRegister<SpecialRegisterId::kBfar>(vadr);
137
138 auto cfsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kCfsr>();
139 // cfsr |= SReg::kCfsrBusFaultBfarValidMsk;
140 cfsr |= CfsrBusFault::kIbuErrMsk;
141 cpua.template WriteSpecialRegister<SpecialRegisterId::kCfsr>(cfsr);
142
143 ExcTrig::SetPending(cpua, ExceptionType::kBusFault);
144 return Ok(read_res.content);
145 }
146 }
147 // not reachable
148 return Err<T>(StatusCode::kUnexpected);
149 }
150
151 template <typename T> Result<void> Write(TCpuAccessor &cpua, me_adr_t vadr, T value) const {
152
153 auto write_res = ForwardWrite<T, TBusParticipant...>(cpua, vadr, value);
154 switch (write_res.status_code) {
155 case WriteStatusCode::kOk: {
156 return Ok();
157 }
158 case WriteStatusCode::kWriteNotAllowed: {
159 return Err(StatusCode::kMemInaccesible);
160 }
161 default: {
162 return Err(StatusCode::kUnexpected);
163 }
164 }
165
166 // not reachable
167 }
168
169 template <typename T>
170 Result<void> WriteOrRaise(TCpuAccessor &cpua, me_adr_t vadr, T value,
171 BusExceptionType exc_type) const {
172 auto write_res = ForwardWrite<T, TBusParticipant...>(cpua, vadr, value);
173 if (write_res.status_code == WriteStatusCode::kOk) {
174 return Ok();
175 }
176
177 switch (exc_type) {
178 case BusExceptionType::kRaiseNoException: {
179 return Ok(); // No exception to be triggered
180 }
181 case BusExceptionType::kRaiseStkerr: {
182 cpua.template WriteSpecialRegister<SpecialRegisterId::kBfar>(vadr);
183
184 auto cfsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kCfsr>();
185 cfsr |= CfsrBusFault::kBfarValidMsk;
186 cfsr |= CfsrBusFault::kStkerrMsk;
187
188 cpua.template WriteSpecialRegister<SpecialRegisterId::kCfsr>(cfsr);
189 ExcTrig::SetPending(cpua, ExceptionType::kBusFault);
190 return Ok();
191 }
192 case BusExceptionType::kRaiseUnstkerr: {
193 cpua.template WriteSpecialRegister<SpecialRegisterId::kBfar>(vadr);
194
195 ExcTrig::SetPending(cpua, ExceptionType::kBusFault);
196 auto cfsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kCfsr>();
197 cfsr |= CfsrBusFault::kBfarValidMsk;
198 cfsr |= CfsrBusFault::kUnstkerrMsk;
199
200 cpua.template WriteSpecialRegister<SpecialRegisterId::kCfsr>(cfsr);
201 return Ok();
202 }
203 case BusExceptionType::kRaiseImpreciseDataBusError: {
204 cpua.template WriteSpecialRegister<SpecialRegisterId::kBfar>(vadr);
205
206 ExcTrig::SetPending(cpua, ExceptionType::kBusFault);
207 auto cfsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kCfsr>();
208 cfsr |= CfsrBusFault::kBfarValidMsk;
209 cfsr |= CfsrBusFault::kImpreciseErrMsk;
210
211 cpua.template WriteSpecialRegister<SpecialRegisterId::kCfsr>(cfsr);
212 return Ok();
213 }
214 case BusExceptionType::kRaisePreciseDataBusError: {
215 cpua.template WriteSpecialRegister<SpecialRegisterId::kBfar>(vadr);
216
217 ExcTrig::SetPending(cpua, ExceptionType::kBusFault);
218 auto cfsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kCfsr>();
219 cfsr |= CfsrBusFault::kBfarValidMsk;
220 cfsr |= CfsrBusFault::kPreciseErrMsk;
221
222 cpua.template WriteSpecialRegister<SpecialRegisterId::kCfsr>(cfsr);
223 return Ok();
224 }
225 case BusExceptionType::kRaiseInstructionBusError: {
226 cpua.template WriteSpecialRegister<SpecialRegisterId::kBfar>(vadr);
227
228 ExcTrig::SetPending(cpua, ExceptionType::kBusFault);
229 auto cfsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kCfsr>();
230 cfsr |= CfsrBusFault::kBfarValidMsk;
231 cfsr |= CfsrBusFault::kIbuErrMsk;
232
233 cpua.template WriteSpecialRegister<SpecialRegisterId::kCfsr>(cfsr);
234 return Ok();
235 }
236 }
237 // not reachable
238 return Err(StatusCode::kUnexpected);
239 }
240
241private:
242 template <typename T, typename TAct, typename... Rest>
243 ReadResult<T> ForwardRead(TCpuAccessor &cpua, me_adr_t vadr) const {
244 if (!TAct::IsVAdrInRange(vadr)) {
245 return ForwardRead<T, Rest...>(cpua, vadr);
246 }
247 const auto read_result = TAct::template Read<T>(cpua, vadr);
248 return read_result;
249 }
250
251 template <typename T> ReadResult<T> ForwardRead(TCpuAccessor &cpua, me_adr_t vadr) const {
252 static_cast<void>(vadr);
253 static_cast<void>(cpua);
254 return ReadResult<T>{T{}, ReadStatusCode::kReadNotAllowed};
255 }
256
268 template <typename T, typename TAct, typename... Rest,
269 typename std::enable_if_t<TAct::kReadOnly, T> = 0>
270 WriteResult<T> ForwardWrite(TCpuAccessor &cpua, me_adr_t vadr, T value) const {
271 if (!TAct::IsVAdrInRange(vadr)) {
272 return ForwardWrite<T, Rest...>(cpua, vadr, value);
273 }
274 return WriteResult<T>{WriteStatusCode::kWriteNotAllowed};
275 }
276
288 template <typename T, typename TAct, typename... Rest,
289 typename std::enable_if_t<!TAct::kReadOnly, T> = 0>
290 WriteResult<T> ForwardWrite(TCpuAccessor &cpua, me_adr_t vadr, T value) const {
291 if (!TAct::IsVAdrInRange(vadr)) {
292 return ForwardWrite<T, Rest...>(cpua, vadr, value);
293 }
294 const auto write_res = TAct::template Write<T>(cpua, vadr, value);
295 return write_res;
296 }
297
298 template <typename T>
299 WriteResult<T> ForwardWrite(TCpuAccessor &cpua, me_adr_t vadr, T value) const {
300 static_cast<void>(vadr);
301 static_cast<void>(value);
302 static_cast<void>(cpua);
303 return WriteResult<T>{WriteStatusCode::kWriteNotAllowed};
304 }
305};
306
307} // namespace libmicroemu::internal
Bus & operator=(const Bus &r_src)=default
Copy assignment operator for Bus.
Bus & operator=(Bus &&r_src)=default
Move assignment operator for Bus.
virtual ~Bus()=default
Destructor.
Bus(const Bus &r_src)=default
Copy constructor for Bus.
Bus(Bus &&r_src)=default
Move constructor for Bus.
The libmicroemu::internal namespace contains all classes and functions of libmicroemu which are priva...
Definition bkpt_flags.h:6
@ kBusFault
Bus fault exception, triggered by bus errors on instruction fetches and data accesses.
Definition exception_type.h:27
@ kUnexpected
An unexpected error occurred.
Definition status_code.h:28
@ kMemInaccesible
Memory is inaccessible.
Definition status_code.h:53
Contains the Result class which is used to return the result of a function.
This file contains the declaration of the SpecialRegisterId enumeration and related functions.
Definition result.h:15