#include #include /* Copyright © 2020 Michal Schulz https://github.com/michalsc This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "support.h" #include "M68k.h" #include "RegisterAllocator.h" uint32_t *EMIT_Exception(uint32_t *ptr, uint16_t exception, uint8_t format, ...) { va_list args; uint8_t ctx = RA_TryCTX(&ptr); //RA_GetCTX(&ptr); uint8_t sp = RA_MapM68kRegister(&ptr, 15); uint8_t vbr = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); int need_free_ctx = 0; if (ctx == 0xff) { need_free_ctx = 1; ctx = RA_GetCTX(&ptr); } va_start(args, format); RA_SetDirtyM68kRegister(&ptr, 15); /* In case of privilege violation there is no need to check if we were in supervisor mode. We were not! */ if (exception == VECTOR_PRIVILEGE_VIOLATION) { // Store USP *ptr++ = mov_reg_to_simd(31, TS_S, 1, sp); /* Check if we need to load ISP or MSP */ *ptr++ = tbnz(cc, SRB_M, 3); /* Load ISP to A7 */ *ptr++ = mov_simd_to_reg(sp, 31, TS_S, 2); *ptr++ = b(2); /* Load MSP to A7 */ *ptr++ = mov_simd_to_reg(sp, 31, TS_S, 3); } else { /* Check if we are changing stack due to user->supervisor transition */ *ptr++ = tbnz(cc, SRB_S, 6); /* We were in user mode. Store A7 as USP */ *ptr++ = mov_reg_to_simd(31, TS_S, 1, sp); /* Check if we need to load ISP or MSP */ *ptr++ = tbnz(cc, SRB_M, 3); /* Load ISP to A7 */ *ptr++ = mov_simd_to_reg(sp, 31, TS_S, 2); *ptr++ = b(2); /* Load MSP to A7 */ *ptr++ = mov_simd_to_reg(sp, 31, TS_S, 3); } if (format == 2 || format == 3) { /* Format 2 and 3, store Address / Effective address */ uint32_t ea = va_arg(args, uint32_t); *ptr++ = movw_immed_u16(vbr, ea & 0xffff); if ((ea >> 16) != 0) *ptr++ = movt_immed_u16(vbr, ea >> 16); *ptr++ = str_offset_preindex(sp, vbr, -4); } else if (format == 4) { /* Format 4, store Effective address and address of faulting instruction */ uint32_t ea = va_arg(args, uint32_t); uint32_t fault = va_arg(args, uint32_t); *ptr++ = movw_immed_u16(vbr, fault & 0xffff); if ((fault >> 16) != 0) *ptr++ = movt_immed_u16(vbr, fault >> 16); *ptr++ = str_offset_preindex(sp, vbr, -8); *ptr++ = movw_immed_u16(vbr, ea & 0xffff); if ((ea >> 16) != 0) *ptr++ = movt_immed_u16(vbr, ea >> 16); *ptr++ = str_offset(sp, vbr, 4); } uint8_t cc_copy = RA_AllocARMRegister(&ptr); /* Reverse C and V */ *ptr++ = mov_reg(cc_copy, cc); *ptr++ = rbit(vbr, cc); *ptr++ = bfxil(cc_copy, vbr, 30, 2); /* Store SR */ *ptr++ = strh_offset_preindex(sp, cc_copy, -8); RA_FreeARMRegister(&ptr, cc_copy); /* Store program counter */ *ptr++ = stur_offset(sp, REG_PC, 2); /* Store exception vector and type */ *ptr++ = mov_immed_u16(vbr, (format << 12) | (exception & 0xfff), 0); *ptr++ = strh_offset(sp, vbr, 6); /* Clear trace flags, set supervisor */ *ptr++ = bic_immed(cc, cc, 2, 32 - SRB_T0); *ptr++ = orr_immed(cc, cc, 1, 32 - SRB_S); /* Load VBR */ *ptr++ = ldr_offset(ctx, vbr, __builtin_offsetof(struct M68KState, VBR)); *ptr++ = ldr_offset(vbr, REG_PC, exception); RA_FreeARMRegister(&ptr, vbr); if (need_free_ctx) { RA_FlushCTX(&ptr); } va_end(args); return ptr; }