void set_cpsr_full(u32 cpsr) { if ((cpsr ^ arm.cpsr_low28) & 0x1F) { /* Switching to a different processor mode. Swap out registers of old mode */ if ((arm.cpsr_low28 & 0x1F) == MODE_FIQ) memcpy(arm.r8_fiq, &arm.reg[8], 20); else memcpy(arm.r8_usr, &arm.reg[8], 20); switch (arm.cpsr_low28 & 0x1F) { case MODE_USR: case MODE_SYS: memcpy(arm.r13_usr, &arm.reg[13], 8); break; case MODE_FIQ: memcpy(arm.r13_fiq, &arm.reg[13], 8); break; case MODE_IRQ: memcpy(arm.r13_irq, &arm.reg[13], 8); break; case MODE_SVC: memcpy(arm.r13_svc, &arm.reg[13], 8); break; case MODE_ABT: memcpy(arm.r13_abt, &arm.reg[13], 8); break; case MODE_UND: memcpy(arm.r13_und, &arm.reg[13], 8); break; default: error("Invalid previous processor mode (This can't happen)\n"); } /* Swap in registers of new mode */ if ((cpsr & 0x1F) == MODE_FIQ) memcpy(&arm.reg[8], arm.r8_fiq, 20); else memcpy(&arm.reg[8], arm.r8_usr, 20); switch (cpsr & 0x1F) { case MODE_USR: case MODE_SYS: memcpy(&arm.reg[13], arm.r13_usr, 8); break; case MODE_FIQ: memcpy(&arm.reg[13], arm.r13_fiq, 8); break; case MODE_IRQ: memcpy(&arm.reg[13], arm.r13_irq, 8); break; case MODE_SVC: memcpy(&arm.reg[13], arm.r13_svc, 8); break; case MODE_ABT: memcpy(&arm.reg[13], arm.r13_abt, 8); break; case MODE_UND: memcpy(&arm.reg[13], arm.r13_und, 8); break; default: error("Invalid new processor mode\n"); } /* If going to or from user mode, memory access permissions may be different */ if (!(arm.cpsr_low28 & 3) || !(cpsr & 3)) addr_cache_flush(); } if (cpsr & 0x01000000) error("J mode is not implemented"); arm.cpsr_n = cpsr >> 31 & 1; arm.cpsr_z = cpsr >> 30 & 1; arm.cpsr_c = cpsr >> 29 & 1; arm.cpsr_v = cpsr >> 28 & 1; arm.cpsr_low28 = cpsr & 0x090000FF; /* Mask off reserved bits */ cpu_int_check(); }
void emu_loop(bool reset) { #if OS_HAS_PAGEFAULT_HANDLER os_exception_frame_t seh_frame = { NULL, NULL }; os_faulthandler_arm(&seh_frame); #endif if(reset) { reset: emu_reset(); } gdbstub_reset(); addr_cache_flush(); flush_translations(); sched_update_next_event(0); exiting = false; // clang segfaults with that, for an iOS build :( #ifndef NO_SETJMP // Workaround for LLVM bug #18974 while(__builtin_setjmp(restart_after_exception)){}; #endif while (!exiting) { sched_process_pending_events(); while (!exiting && cycle_count_delta < 0) { if (cpu_events & EVENT_RESET) { gui_status_printf("Reset"); goto reset; } if (cpu_events & (EVENT_FIQ | EVENT_IRQ)) { // Align PC in case the interrupt occurred immediately after a jump if (arm.cpsr_low28 & 0x20) arm.reg[15] &= ~1; else arm.reg[15] &= ~3; if (cpu_events & EVENT_WAITING) arm.reg[15] += 4; // Skip over wait instruction arm.reg[15] += 4; cpu_exception((cpu_events & EVENT_FIQ) ? EX_FIQ : EX_IRQ); } cpu_events &= ~EVENT_WAITING; if (arm.cpsr_low28 & 0x20) cpu_thumb_loop(); else cpu_arm_loop(); } } #if OS_HAS_PAGEFAULT_HANDLER os_faulthandler_unarm(&seh_frame); #endif }