61 ExceptionsOps() =
delete;
62 ~ExceptionsOps() =
delete;
63 ExceptionsOps &operator=(
const ExceptionsOps &r_src) =
delete;
64 ExceptionsOps(ExceptionsOps &&r_src) =
delete;
65 ExceptionsOps &operator=(ExceptionsOps &&r_src) =
delete;
66 ExceptionsOps(
const ExceptionsOps &r_src) =
delete;
68 static void SetProcessorMode(TCpuAccessor &cpua,
const ProcessorMode &mode) {
69 auto sys_ctrl = cpua.template ReadSpecialRegister<SId::kSysCtrl>();
72 sys_ctrl |= mode == ProcessorMode::kHandler ? SysCtrlRegister::kExecModeHandler
73 : SysCtrlRegister::kExecModeThread;
74 cpua.template WriteSpecialRegister<SId::kSysCtrl>(sys_ctrl);
77 static void LogImportantRegisters(TCpuAccessor &cpua,
const char *preamble,
79#if IS_LOGLEVEL_TRACE_ENABLED == true
81 const auto mode_str = is_handler_mode ?
"Handler" :
"Thread";
83 auto &exception_states = cpua.GetExceptionStates();
84 auto &selected_exception = exception_states.exception[
static_cast<u32
>(exception_type) - 1U];
86 auto apsr = cpua.template ReadSpecialRegister<SId::kApsr>();
87 auto ipsr = cpua.template ReadSpecialRegister<SId::kIpsr>();
88 auto epsr = cpua.template ReadSpecialRegister<SId::kEpsr>();
89 auto xpsr = cpua.template ReadSpecialRegister<SId::kXpsr>();
90 auto sp = cpua.template ReadRegister<RegisterId::kSp>();
96 "CurrentMode = \"%s\", "
102 preamble,
static_cast<uint32_t
>(exception_type), selected_exception.GetPriority(),
103 mode_str, apsr, ipsr, epsr, xpsr, sp, stack_type);
105 static_cast<void>(cpua);
106 static_cast<void>(preamble);
107 static_cast<void>(exception_type);
110 static void InitDefaultExceptionStates(TCpuAccessor &cpua) {
111 auto &exception_states = cpua.GetExceptionStates();
112 exception_states.pending_exceptions = 0U;
113 auto &exceptions = exception_states.exception;
114 for (u32 i = 0U; i < CountExceptions(); ++i) {
118 exceptions[i].SetPriority(-3);
122 exceptions[i].SetPriority(-2);
126 exceptions[i].SetPriority(-1);
135 exceptions[i].SetPriority(0);
139 exceptions[i].ClearFlags();
143 template <
typename ExcInstant,
typename TBus>
144 static Result<void> ExceptionEntry(TCpuAccessor &cpua, TBus &bus,
147#if IS_LOGLEVEL_TRACE_ENABLED == true
148 if (
constexpr auto instant = ExcInstant::kInstant; instant == ExecutionInstant::kPreFetch) {
149 LogImportantRegisters(cpua,
"[BEGIN] ExceptionEntry (PreFetch)", exception_type);
150 }
else if (instant == ExecutionInstant::kPostFetch) {
151 LogImportantRegisters(cpua,
"[BEGIN] ExceptionEntry (PostFetch)", exception_type);
153 LogImportantRegisters(cpua,
"[BEGIN] ExceptionEntry (PostExec)", exception_type);
157 TRY(
void, PushStack<ExcInstant>(cpua, bus, exception_type, context));
159 TRY(
void, ExceptionTaken(cpua, bus, exception_type));
161 LOG_TRACE(TLogger,
"[END] ExceptionEntry");
165 template <
typename ExcInstant,
typename TBus>
170 static_cast<void>(exception_type);
181 auto ccr = cpua.template ReadSpecialRegister<SId::kCcr>();
182 forcealign = (ccr & CcrRegister::kStkAlignMsk) >> CcrRegister::kStkAlignPos;
185 auto spmask = ~static_cast<u32>(forcealign << 2U);
187 u32 frameptralign{0U};
194 if (is_process_stack && is_thread_mode) {
195 auto sp_process = cpua.template ReadSpecialRegister<SId::kSpProcess>();
197 frameptralign = ((sp_process & 0x4U) >> 2U) & forcealign;
199 sp_process = (sp_process - framesize) & spmask;
200 LOG_TRACE(TLogger,
"Setting processes stack pointer to = 0x%08X", sp_process);
201 cpua.template WriteSpecialRegister<SId::kSpProcess>(sp_process);
207 frameptr = sp_process;
209 auto sp_main = cpua.template ReadSpecialRegister<SId::kSpMain>();
211 frameptralign = ((sp_main & 0x4U) >> 2U) & forcealign;
213 sp_main = (sp_main - framesize) & spmask;
214 LOG_TRACE(TLogger,
"Setting main stack pointer to = 0x%08X", sp_main);
215 cpua.template WriteSpecialRegister<SId::kSpMain>(sp_main);
223 const auto r0 = cpua.template ReadRegister<RegisterId::kR0>();
224 TRY(
void, bus.template WriteOrRaise<u32>(cpua, frameptr, r0, BusExceptionType::kRaiseUnstkerr));
227 const auto r1 = cpua.template ReadRegister<RegisterId::kR1>();
228 TRY(
void, bus.template WriteOrRaise<u32>(cpua, frameptr + 0x4U, r1,
229 BusExceptionType::kRaiseUnstkerr));
232 const auto r2 = cpua.template ReadRegister<RegisterId::kR2>();
233 TRY(
void, bus.template WriteOrRaise<u32>(cpua, frameptr + 0x8U, r2,
234 BusExceptionType::kRaiseUnstkerr));
237 const auto r3 = cpua.template ReadRegister<RegisterId::kR3>();
238 TRY(
void, bus.template WriteOrRaise<u32>(cpua, frameptr + 0xCU, r3,
239 BusExceptionType::kRaiseUnstkerr));
242 const auto r12 = cpua.template ReadRegister<RegisterId::kR12>();
243 TRY(
void, bus.template WriteOrRaise<u32>(cpua, frameptr + 0x10U, r12,
244 BusExceptionType::kRaiseUnstkerr));
247 const auto lr = cpua.template ReadRegister<RegisterId::kLr>();
248 TRY(
void, bus.template WriteOrRaise<u32>(cpua, frameptr + 0x14U, lr,
249 BusExceptionType::kRaiseUnstkerr));
252 const auto return_address = ReturnAddress<ExcInstant>(cpua, exception_type, context);
254 TRY(
void, bus.template WriteOrRaise<u32>(cpua, frameptr + 0x18U, return_address,
255 BusExceptionType::kRaiseUnstkerr));
259 const auto xpsr = cpua.template ReadSpecialRegister<SId::kXpsr>();
263 TRY(
void, bus.template WriteOrRaise<u32>(cpua, frameptr + 0x1CU, xpsr_adapt,
264 BusExceptionType::kRaiseUnstkerr));
267 "Pushed R0 = 0x%08X, "
273 "ReturnAddress = 0x%08X, "
275 r0, r1, r2, r3, r12, lr, return_address, xpsr_adapt);
298 if (is_handler_mode) {
301 LOG_TRACE(TLogger,
"Setting LR = 0x%08X (currently in Handler mode)", lr);
302 cpua.template WriteRegister<RegisterId::kLr>(lr);
305 const auto sctrl = cpua.template ReadSpecialRegister<SId::kSysCtrl>();
307 (sctrl & SysCtrlRegister::kControlSpSelMsk) >> SysCtrlRegister::kControlSpSelPos;
310 LOG_TRACE(TLogger,
"Setting LR = 0x%08X (currently in Thread mode)", lr);
311 cpua.template WriteRegister<RegisterId::kLr>(lr);
320 template <
typename ExcInstant,
321 typename std::enable_if_t<ExcInstant::kInstant == ExecutionInstant::kPreFetch, int> = 0>
322 static u32 ReturnAddress(TCpuAccessor &cpua,
const ExceptionType &exception_type,
324 static_cast<void>(cpua);
331 switch (exception_type) {
336 return context.return_adr;
340 if (
static_cast<u32
>(exception_type) >= 16U) {
341 return context.return_adr;
344 "Return address calculation of these exceptions should not be called at this point");
345 return context.return_adr;
351 template <
typename ExcInstant,
typename std::enable_if_t<
352 ExcInstant::kInstant == ExecutionInstant::kPostFetch,
int> = 0>
353 static u32 ReturnAddress(TCpuAccessor &cpua,
const ExceptionType &exception_type,
355 static_cast<void>(cpua);
356 static_cast<void>(context);
363 switch (exception_type) {
368 return context.return_adr;
373 "Return address calculation of these exceptions should not be called at this point");
374 return context.return_adr;
385 typename std::enable_if_t<ExcInstant::kInstant == ExecutionInstant::kPostExecution, int> = 0>
386 static u32 ReturnAddress(TCpuAccessor &cpua,
const ExceptionType &exception_type,
388 static_cast<void>(cpua);
395 switch (exception_type) {
401 return context.return_adr;
405 "Return address calculation of these exceptions should not be called at this point");
411 template <
typename TBus>
412 static Result<void> ExceptionTaken(TCpuAccessor &cpua, TBus &bus,
424 const auto vector_table = cpua.template ReadSpecialRegister<SId::kVtor>() << 7U;
428 bus.template Read<u32>(cpua, vector_table + 4U *
static_cast<u32
>(exception_type)));
431 const auto exception_address = tmp & 0xFFFFFFFEU;
432 LOG_TRACE(TLogger,
"Branching to exception address = 0x%08X", exception_address);
433 Pc::BranchTo(cpua, exception_address);
435 const auto tbit = tmp & 0x1U;
437 SetProcessorMode(cpua, ProcessorMode::kHandler);
441 auto ipsr = cpua.template ReadSpecialRegister<SId::kIpsr>();
445 const auto exception_number =
static_cast<u32
>(exception_type);
446 ipsr &= ~static_cast<u32>(IpsrRegister::kExceptionNumberMsk);
447 ipsr |= exception_number;
448 cpua.template WriteSpecialRegister<SId::kIpsr>(ipsr);
452 auto epsr = cpua.template ReadSpecialRegister<SId::kEpsr>();
453 epsr &= ~static_cast<u32>(EpsrRegister::kTMsk);
454 epsr |= tbit << EpsrRegister::kTPos;
455 epsr &= ~static_cast<u32>(EpsrRegister::kItMsk);
456 cpua.template WriteSpecialRegister<SId::kEpsr>(epsr);
458 auto sys_ctrl = cpua.template ReadSpecialRegister<SpecialRegisterId::kSysCtrl>();
460 sys_ctrl = cpua.template ReadSpecialRegister<SId::kSysCtrl>();
465 sys_ctrl &= ~static_cast<u32>(SysCtrlRegister::kControlSpSelMsk);
466 cpua.template WriteSpecialRegister<SId::kSysCtrl>(sys_ctrl);
470 SetExceptionActive(cpua, exception_type);
479 static constexpr bool IsExceptionSynchronous() {
484 template <
typename TBus>
485 static Result<void> ExceptionReturn(TCpuAccessor &cpua, TBus &bus, u32 exc_return) {
489 LOG_TRACE(TLogger,
"[BEGIN] ExceptionReturn: exc_return = 0x%08X", exc_return);
492 "ExceptionReturn should only be called in Handler mode");
499 if ((exc_return & 0x0FFFFFF0U) != 0x0FFFFFF0U) {
505 auto ret_exception_n =
506 cpua.template ReadSpecialRegister<SId::kIpsr>() & IpsrRegister::kExceptionNumberMsk;
524 switch (exc_return & 0xFU) {
526 frameptr = cpua.template ReadSpecialRegister<SId::kSpMain>();
527 SetProcessorMode(cpua, ProcessorMode::kHandler);
529 auto sys_ctrl = cpua.template ReadSpecialRegister<SpecialRegisterId::kSysCtrl>();
532 sys_ctrl &= ~static_cast<u32>(SysCtrlRegister::kControlSpSelMsk);
534 cpua.template WriteSpecialRegister<SpecialRegisterId::kSysCtrl>(sys_ctrl);
547 frameptr = cpua.template ReadSpecialRegister<SId::kSpMain>();
548 SetProcessorMode(cpua, ProcessorMode::kThread);
550 auto sys_ctrl = cpua.template ReadSpecialRegister<SpecialRegisterId::kSysCtrl>();
553 sys_ctrl &= ~static_cast<u32>(SysCtrlRegister::kControlSpSelMsk);
555 cpua.template WriteSpecialRegister<SpecialRegisterId::kSysCtrl>(sys_ctrl);
567 frameptr = cpua.template ReadSpecialRegister<SId::kSpProcess>();
568 SetProcessorMode(cpua, ProcessorMode::kThread);
570 auto sys_ctrl = cpua.template ReadSpecialRegister<SpecialRegisterId::kSysCtrl>();
573 sys_ctrl |=
static_cast<u32
>(SysCtrlRegister::kControlSpSelMsk);
575 cpua.template WriteSpecialRegister<SpecialRegisterId::kSysCtrl>(sys_ctrl);
579 assert(
false &&
"Not implemented");
589 ClearExceptionActive(cpua,
static_cast<ExceptionType>(ret_exception_n));
592 TRY(
void, PopStack(cpua, bus, frameptr, exc_return));
594 const auto ipsr_8_0 =
595 cpua.template ReadSpecialRegister<SId::kIpsr>() & IpsrRegister::kExceptionNumberMsk;
599 if (is_handler_mode && ipsr_8_0 == 0U) {
605 LOG_ERROR(TLogger,
"Returning to Handler mode with IPSR inconsistent");
610 if (is_thread_mode && ipsr_8_0 != 0U) {
616 LOG_ERROR(TLogger,
"Returning to Thread mode with IPSR inconsistent");
627#if IS_LOGLEVEL_TRACE_ENABLED == true
628 LogImportantRegisters(cpua,
"[END] ExceptionReturn",
631 static_cast<void>(ret_exception_n);
637 template <
typename TBus>
638 static Result<void> PopStack(TCpuAccessor &cpua, TBus &bus, u32 frameptr, u32 exc_return) {
639 static_cast<void>(bus);
646 LOG_TRACE(TLogger,
"Popping stack from 0x%08X", frameptr);
657 auto ccr = cpua.template ReadSpecialRegister<SId::kCcr>();
658 forcealign = (ccr & CcrRegister::kStkAlignMsk) >> CcrRegister::kStkAlignPos;
663 (bus.template ReadOrRaise<u32>(cpua, frameptr, BusExceptionType::kRaiseStkerr)));
665 LOG_TRACE(TLogger,
" R0 ADR = 0x%08X", frameptr);
666 cpua.template WriteRegister<RegisterId::kR0>(r0);
671 (bus.template ReadOrRaise<u32>(cpua, frameptr + 0x4U, BusExceptionType::kRaiseStkerr)));
672 cpua.template WriteRegister<RegisterId::kR1>(r1);
677 (bus.template ReadOrRaise<u32>(cpua, frameptr + 0x8U, BusExceptionType::kRaiseStkerr)));
678 cpua.template WriteRegister<RegisterId::kR2>(r2);
683 (bus.template ReadOrRaise<u32>(cpua, frameptr + 0xCU, BusExceptionType::kRaiseStkerr)));
684 cpua.template WriteRegister<RegisterId::kR3>(r3);
689 (bus.template ReadOrRaise<u32>(cpua, frameptr + 0x10U, BusExceptionType::kRaiseStkerr)));
690 cpua.template WriteRegister<RegisterId::kR12>(r12);
695 (bus.template ReadOrRaise<u32>(cpua, frameptr + 0x14U, BusExceptionType::kRaiseStkerr)));
696 cpua.template WriteRegister<RegisterId::kLr>(lr);
701 (bus.template ReadOrRaise<u32>(cpua, frameptr + 0x18U, BusExceptionType::kRaiseStkerr)));
702 Pc::BranchTo(cpua, return_adr);
707 (bus.template ReadOrRaise<u32>(cpua, frameptr + 0x1CU, BusExceptionType::kRaiseStkerr)));
711 "Popped R0 = 0x%08X, "
717 "ReturnAddress = 0x%08X, "
719 r0, r1, r2, r3, r12, lr, return_adr, psr);
738 switch (exc_return & 0xFU) {
741 auto sp_main = (cpua.template ReadSpecialRegister<SId::kSpMain>() + framesize) | spmask;
742 LOG_TRACE(TLogger,
"Returning to handler mode using main stack: SP_main = 0x%08X", sp_main);
743 cpua.template WriteSpecialRegister<SId::kSpMain>(sp_main);
748 auto sp_main = (cpua.template ReadSpecialRegister<SId::kSpMain>() + framesize) | spmask;
749 LOG_TRACE(TLogger,
"Returning to thread mode using main stack: SP_main = 0x%08X", sp_main);
750 cpua.template WriteSpecialRegister<SId::kSpMain>(sp_main);
755 auto sp_process = (cpua.template ReadSpecialRegister<SId::kSpProcess>() + framesize) | spmask;
756 LOG_TRACE(TLogger,
"Returning to thread mode using process stack: SP_process = 0x%08X",
758 cpua.template WriteSpecialRegister<SId::kSpProcess>(sp_process);
768 cpua.template WriteSpecialRegister<SId::kApsr>(psr_31_27 << ApsrRegister::kQPos);
776 auto ipsr_8_0 = psr & IpsrRegister::kExceptionNumberMsk;
778 cpua.template WriteSpecialRegister<SId::kIpsr>(ipsr_8_0);
782 << EpsrRegister::kTPos) |
784 << EpsrRegister::kItBit2Pos);
786 cpua.template WriteSpecialRegister<SId::kEpsr>(epsr_new);
791 static void SetExceptionPending(TCpuAccessor &cpua,
ExceptionType exception_type) {
793 switch (exception_type) {
796 LOG_ERROR(TLogger,
"Set HardFault exception pending");
799 LOG_ERROR(TLogger,
"Set MemoryManagementFault exception pending");
802 LOG_ERROR(TLogger,
"Set BusFault exception pending");
805 LOG_ERROR(TLogger,
"Set UsageFault exception pending");
813 assert(
static_cast<u32
>(exception_type) >= 1U);
814 assert(
static_cast<u32
>(exception_type) <= CountExceptions());
816 auto &exception_states = cpua.GetExceptionStates();
817 auto &selected_exception = exception_states.exception[
static_cast<u32
>(exception_type) - 1U];
820 if (selected_exception.IsPending() ==
false) {
821 exception_states.pending_exceptions += 1U;
824 selected_exception.SetPending();
826 LOG_TRACE(TLogger,
"SetExceptionPending: exception_type = %d, priority = %d",
827 static_cast<uint32_t
>(exception_type), selected_exception.GetPriority());
830 static void ClearExceptionPending(TCpuAccessor &cpua,
ExceptionType exception_type) {
831 assert(
static_cast<u32
>(exception_type) >= 1U);
832 assert(
static_cast<u32
>(exception_type) <= CountExceptions());
834 auto &exception_states = cpua.GetExceptionStates();
835 auto &selected_exception = exception_states.exception[
static_cast<u32
>(exception_type) - 1U];
838 assert(selected_exception.IsPending() ==
true);
840 selected_exception.ClearPending();
841 exception_states.pending_exceptions -= 1U;
843 LOG_TRACE(TLogger,
"ClearExceptionPending: exception_type = %d, priority = %d",
844 static_cast<uint32_t
>(exception_type), selected_exception.GetPriority());
847 static void SetExceptionActive(TCpuAccessor &cpua,
ExceptionType exception_type) {
848 assert(
static_cast<u32
>(exception_type) >= 1U);
849 assert(
static_cast<u32
>(exception_type) <= CountExceptions());
851 auto &exception_states = cpua.GetExceptionStates();
852 auto &selected_exception = exception_states.exception[
static_cast<u32
>(exception_type) - 1U];
853 assert(selected_exception.IsActive() ==
false);
854 selected_exception.SetActive();
856 LOG_TRACE(TLogger,
"SetExceptionActive: exception_type = %d, priority = %d",
857 static_cast<uint32_t
>(exception_type), selected_exception.GetPriority());
860 static void ClearExceptionActive(TCpuAccessor &cpua,
ExceptionType exception_type) {
861 assert(
static_cast<u32
>(exception_type) >= 1U);
862 assert(
static_cast<u32
>(exception_type) <= CountExceptions());
864 auto &exception_states = cpua.GetExceptionStates();
865 auto &selected_exception = exception_states.exception[
static_cast<u32
>(exception_type) - 1U];
866 assert(selected_exception.IsActive() ==
true);
867 selected_exception.ClearActive();
869 LOG_TRACE(TLogger,
"ClearExceptionActive: exception_type = %d, priority = %d",
870 static_cast<uint32_t
>(exception_type), selected_exception.GetPriority());
873 template <
typename ExcInstant,
874 typename std::enable_if_t<ExcInstant::kInstant == ExecutionInstant::kPreFetch, int> = 0>
875 static bool CanExceptionExecute(
const ExceptionType &exception_type) {
876 switch (exception_type) {
883 if (
static_cast<u32
>(exception_type) >= 16U) {
892 template <
typename ExcInstant,
typename std::enable_if_t<
893 ExcInstant::kInstant == ExecutionInstant::kPostFetch,
int> = 0>
894 static bool CanExceptionExecute(
const ExceptionType &exception_type) {
895 switch (exception_type) {
908 typename std::enable_if_t<ExcInstant::kInstant == ExecutionInstant::kPostExecution, int> = 0>
909 static bool CanExceptionExecute(
const ExceptionType &exception_type) {
910 switch (exception_type) {
922 template <
typename ExcInstant,
typename TBus>
923 static Result<bool> CheckExceptions(TCpuAccessor &cpua, TBus &bus,
925 auto &exception_states = cpua.GetExceptionStates();
926 auto &pending_exceptions = exception_states.pending_exceptions;
929 if (pending_exceptions == 0U) {
933 auto executing_exc_type =
934 cpua.template ReadSpecialRegister<SId::kIpsr>() & IpsrRegister::kExceptionNumberMsk;
936 i16 executing_exc_priority =
937 kLowestExceptionPriority + 1U;
939 if (executing_exc_type != 0U) {
940 assert(
static_cast<u32
>(executing_exc_type) >= 1U);
941 assert(
static_cast<u32
>(executing_exc_type) <= CountExceptions());
942 executing_exc_priority = exception_states.exception[executing_exc_type - 1U].GetPriority();
945 u32 preempt_exc_type = 0U;
946 i16 preempt_exc_priority = kLowestExceptionPriority + 1U;
948 for (
auto i = 0U; i < CountExceptions(); ++i) {
950 auto &exception = exception_states.exception[i];
952 if (exception.IsPending()) {
953 if (exception.IsActive()) {
958 if (exception.GetPriority() >= executing_exc_priority) {
964 if (exception.GetPriority() > preempt_exc_priority) {
971 preempt_exc_type = i + 1U;
972 preempt_exc_priority = exception.GetPriority();
977 if (preempt_exc_type == 0U) {
981 if (CanExceptionExecute<ExcInstant>(
static_cast<ExceptionType>(preempt_exc_type)) ==
false) {
986 auto e_preemp_exc_type =
static_cast<ExceptionType>(preempt_exc_type);
988 ClearExceptionPending(cpua, e_preemp_exc_type);
989 TRY(
bool, ExceptionEntry<ExcInstant>(cpua, bus, e_preemp_exc_type, context));