/* Copyright © 2019 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" #include "cache.h" static uint32_t *EMIT_ASR_mem(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) __attribute__((alias("EMIT_ASL_mem"))); static uint32_t *EMIT_ASL_mem(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t direction = (opcode >> 8) & 1; uint8_t dest = 0xff; uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t ext_words = 0; ptr = EMIT_LoadFromEffectiveAddress(ptr, 0, &dest, opcode & 0x3f, *m68k_ptr, &ext_words, 1, NULL); /* Pre-decrement mode */ if ((opcode & 0x38) == 0x20) { *ptr++ = ldrsh_offset_preindex(dest, tmp, -2); } else { *ptr++ = ldrsh_offset(dest, tmp, 0); } if (update_mask & (SR_C | SR_X)) { if (direction) { *ptr++ = tst_immed(tmp, 1, 32 - 15); } else { *ptr++ = tst_immed(tmp, 1, 0); } } if (direction) { *ptr++ = lsl(tmp, tmp, 1); } else { *ptr++ = asr(tmp, tmp, 1); } if ((opcode & 0x38) == 0x18) { *ptr++ = strh_offset_postindex(dest, tmp, 2); } else { *ptr++ = strh_offset(dest, tmp, 0); } ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); uint8_t tmp2 = RA_AllocARMRegister(&ptr); uint8_t alt_mask = update_mask; if ((alt_mask & 3) != 0 && (alt_mask & 3) < 3) alt_mask ^= 3; ptr = EMIT_ClearFlags(ptr, cc, alt_mask); if (update_mask & (SR_C | SR_X)) { *ptr++ = b_cc(A64_CC_EQ, 3); *ptr++ = mov_immed_u16(tmp2, SR_Calt | SR_X, 0); *ptr++ = orr_reg(cc, cc, tmp2, LSL, 0); } if (update_mask & (SR_Z | SR_N)) { *ptr++ = cmn_reg(31, tmp, LSL, 16); if (update_mask & SR_Z) { *ptr++ = b_cc(A64_CC_EQ ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, (32 - SRB_Z) & 31); } if (update_mask & SR_N) { *ptr++ = b_cc(A64_CC_MI ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, (32 - SRB_N) & 31); } } RA_FreeARMRegister(&ptr, tmp2); // V flag can have non-zero value only for left shifting if ((update_mask & SR_V) && direction) { *ptr++ = eor_reg(tmp, tmp, tmp, LSL, 1); *ptr++ = tbz(tmp, 16, 2); *ptr++ = orr_immed(cc, cc, 1, (32 - SRB_Valt) & 31); } } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, dest); return ptr; } static uint32_t *EMIT_LSR_mem(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) __attribute__((alias("EMIT_LSL_mem"))); static uint32_t *EMIT_LSL_mem(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t direction = (opcode >> 8) & 1; uint8_t dest = 0xff; uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t ext_words = 0; ptr = EMIT_LoadFromEffectiveAddress(ptr, 0, &dest, opcode & 0x3f, *m68k_ptr, &ext_words, 1, NULL); /* Pre-decrement mode */ if ((opcode & 0x38) == 0x20) { *ptr++ = ldrh_offset_preindex(dest, tmp, -2); } else { *ptr++ = ldrh_offset(dest, tmp, 0); } if (update_mask & (SR_C | SR_X)) { if (direction) { *ptr++ = tst_immed(tmp, 1, 32 - 15); } else { *ptr++ = tst_immed(tmp, 1, 0); } } if (direction) { *ptr++ = lsl(tmp, tmp, 1); } else { *ptr++ = lsr(tmp, tmp, 1); } if ((opcode & 0x38) == 0x18) { *ptr++ = strh_offset_postindex(dest, tmp, 2); } else { *ptr++ = strh_offset(dest, tmp, 0); } ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); uint8_t tmp2 = RA_AllocARMRegister(&ptr); uint8_t alt_mask = update_mask; if ((alt_mask & 3) != 0 && (alt_mask & 3) < 3) alt_mask ^= 3; ptr = EMIT_ClearFlags(ptr, cc, alt_mask); if (update_mask & (SR_C | SR_X)) { *ptr++ = b_cc(A64_CC_EQ, 3); *ptr++ = mov_immed_u16(tmp2, SR_Calt | SR_X, 0); *ptr++ = orr_reg(cc, cc, tmp2, LSL, 0); } RA_FreeARMRegister(&ptr, tmp2); if (update_mask & (SR_Z | SR_N)) { *ptr++ = cmn_reg(31, tmp, LSL, 16); if (update_mask & SR_Z) { *ptr++ = b_cc(A64_CC_EQ ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, (32 - SRB_Z) & 31); } if (update_mask & SR_N) { *ptr++ = b_cc(A64_CC_MI ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, (32 - SRB_N) & 31); } } } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, dest); return ptr; } static uint32_t *EMIT_ROXR_mem(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) __attribute__((alias("EMIT_ROXL_mem"))); static uint32_t *EMIT_ROXL_mem(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t direction = (opcode >> 8) & 1; uint8_t dest = 0xff; uint8_t ext_words = 0; uint8_t tmp = RA_AllocARMRegister(&ptr); ptr = EMIT_LoadFromEffectiveAddress(ptr, 0, &dest, opcode & 0x3f, *m68k_ptr, &ext_words, 1, NULL); uint8_t cc = RA_ModifyCC(&ptr); if ((opcode & 0x38) == 0x20) { *ptr++ = ldrh_offset_preindex(dest, tmp, -2); } else { *ptr++ = ldrh_offset(dest, tmp, 0); } /* Test X flag, push the flag value into tmp register */ *ptr++ = tst_immed(cc, 1, 32 - SRB_X); *ptr++ = b_cc(A64_CC_EQ, 2); if (direction) { *ptr++ = orr_immed(tmp, tmp, 1, 1); *ptr++ = ror(tmp, tmp, 31); } else { *ptr++ = orr_immed(tmp, tmp, 1, 16); *ptr++ = ror(tmp, tmp, 1); } if ((opcode & 0x38) == 0x18) { *ptr++ = strh_offset_postindex(dest, tmp, 2); } else { *ptr++ = strh_offset(dest, tmp, 0); } ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; if (update_mask) { uint8_t tmp2 = RA_AllocARMRegister(&ptr); uint8_t update_mask_copy = update_mask; if (update_mask & (SR_Z | SR_N)) { *ptr++ = cmn_reg(31, tmp, LSL, 16); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } else if (update_mask & SR_V) { *ptr++ = bic_immed(cc, cc, 1, 32 - SRB_Valt); } kprintf("[ERROR] ROXL mem not yet fixed!\n"); if (update_mask_copy & SR_XC) { if (direction) { *ptr++ = bfxil(tmp, tmp, 16, 1); *ptr++ = bfi(cc, tmp, 1, 1); } else { *ptr++ = bfxil(tmp, tmp, 31, 1); *ptr++ = bfi(cc, tmp, 1, 1); } if (update_mask_copy & SR_X) { *ptr++ = ror(0, cc, 1); *ptr++ = bfi(cc, 0, 4, 1); } } RA_FreeARMRegister(&ptr, tmp2); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, dest); return ptr; } static uint32_t *EMIT_ROR_mem(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) __attribute__((alias("EMIT_ROL_mem"))); static uint32_t *EMIT_ROL_mem(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t direction = (opcode >> 8) & 1; uint8_t dest = 0xff; uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t ext_words = 0; ptr = EMIT_LoadFromEffectiveAddress(ptr, 0, &dest, opcode & 0x3f, *m68k_ptr, &ext_words, 1, NULL); if ((opcode & 0x38) == 0x20) { *ptr++ = ldrh_offset_preindex(dest, tmp, -2); } else { *ptr++ = ldrh_offset(dest, tmp, 0); } *ptr++ = bfi(tmp, tmp, 16, 16); if (direction) { *ptr++ = ror(tmp, tmp, 32 - 1); } else { *ptr++ = ror(tmp, tmp, 1); } if ((opcode & 0x38) == 0x18) { *ptr++ = strh_offset_postindex(dest, tmp, 2); } else { *ptr++ = strh_offset(dest, tmp, 0); } ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; if (update_mask) { uint8_t tmp2 = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); if (update_mask & (SR_Z | SR_N)) { *ptr++ = cmn_reg(31, tmp, LSL, 16); } uint8_t alt_flags = update_mask; if ((alt_flags & 3) != 0 && (alt_flags & 3) < 3) alt_flags ^= 3; ptr = EMIT_ClearFlags(ptr, cc, alt_flags); if (update_mask & SR_Z) { *ptr++ = b_cc(A64_CC_EQ ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, (32 - SRB_Z) & 31); } if (update_mask & SR_N) { *ptr++ = b_cc(A64_CC_MI ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, (32 - SRB_N) & 31); } if (update_mask & (SR_C)) { if (direction) { *ptr++ = tst_immed(tmp, 1, 16); } else { *ptr++ = tst_immed(tmp, 1, 1); } *ptr++ = b_cc(A64_CC_EQ, 2); *ptr++ = orr_immed(cc, cc, 1, 31 & (32 - SRB_Calt)); } RA_FreeARMRegister(&ptr, tmp2); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, dest); return ptr; } static uint32_t *EMIT_ASR_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) __attribute__((alias("EMIT_ASL_reg"))); static uint32_t *EMIT_ASL_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t cc = RA_ModifyCC(&ptr); uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t shift = (opcode >> 9) & 7; uint8_t size = 1 << ((opcode >> 6) & 3); uint8_t reg = RA_MapM68kRegister(&ptr, opcode & 7); uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t direction = (opcode >> 8) & 1; uint32_t *tmpptr_1; uint32_t *tmpptr_2; uint8_t shiftreg_orig = RA_AllocARMRegister(&ptr); uint8_t reg_orig = RA_AllocARMRegister(&ptr); uint8_t mask = RA_AllocARMRegister(&ptr); RA_SetDirtyM68kRegister(&ptr, opcode & 7); uint8_t shiftreg = RA_MapM68kRegister(&ptr, shift); // Check shift size 0 - in that case no bit shifting is necessary, clear VC flags, update NZ, leave X *ptr++ = ands_immed(shiftreg_orig, shiftreg, 6, 0); tmpptr_1 = ptr; *ptr++ = b_cc(A64_CC_NE, 0); // If N and/or Z need to be updated, do it and clear CV. No further actions are necessary if (update_mask & SR_NZ) { uint8_t update_mask_copy = update_mask; switch (size) { case 4: *ptr++ = cmn_reg(31, reg, LSL, 0); break; case 2: *ptr++ = cmn_reg(31, reg, LSL, 16); break; case 1: *ptr++ = cmn_reg(31, reg, LSL, 24); break; } ptr = EMIT_GetNZ00(ptr, cc, &update_mask_copy); } else if (update_mask & SR_VC) { // Only V or C need to be updated. Clear both *ptr++ = bic_immed(cc, cc, 2, 0); } tmpptr_2 = ptr; // Skip further bit shifting totally *ptr++ = b_cc(A64_CC_AL, 0); if ((ptr - tmpptr_1) != 2) { *tmpptr_1 = b_cc(A64_CC_NE, ptr - tmpptr_1); } else { ptr--; tmpptr_2--; tmpptr_1 = NULL; } if (direction) { if (update_mask & SR_V) { *ptr++ = mov64_immed_u16(mask, 0x8000, 3); *ptr++ = asrv64(mask, mask, shiftreg_orig); switch (size) { case 4: *ptr++ = lsr64(mask, mask, 32); *ptr++ = mov_reg(reg_orig, reg); break; case 2: *ptr++ = lsr64(mask, mask, 32+16); *ptr++ = and_immed(reg_orig, reg, 16, 0); break; case 1: *ptr++ = lsr64(mask, mask, 32 + 24); *ptr++ = and_immed(reg_orig, reg, 8, 0); break; } } switch(size) { case 4: *ptr++ = lslv64(tmp, reg, shiftreg); *ptr++ = mov_reg(reg, tmp); if (update_mask & (SR_C | SR_X)) { *ptr++ = tst64_immed(tmp, 1, 32, 1); } break; case 2: *ptr++ = lslv64(tmp, reg, shiftreg); if (update_mask & (SR_C | SR_X)) { *ptr++ = tst_immed(tmp, 1, 16); } *ptr++ = bfi(reg, tmp, 0, 16); break; case 1: *ptr++ = lslv64(tmp, reg, shiftreg); if (update_mask & (SR_C | SR_X)) { *ptr++ = tst_immed(tmp, 1, 24); } *ptr++ = bfi(reg, tmp, 0, 8); break; } } else { uint8_t mask = RA_AllocARMRegister(&ptr); if (update_mask & (SR_C | SR_X)) { uint8_t t = RA_AllocARMRegister(&ptr); *ptr++ = sub_immed(t, shiftreg, 1); *ptr++ = mov_immed_u16(mask, 1, 0); *ptr++ = lslv64(mask, mask, t); RA_FreeARMRegister(&ptr, t); } switch (size) { case 4: *ptr++ = sxtw64(tmp, reg); if (update_mask & (SR_C | SR_X)) { *ptr++ = ands64_reg(31, tmp, mask, LSL, 0); } *ptr++ = asrv64(tmp, tmp, shiftreg); *ptr++ = mov_reg(reg, tmp); break; case 2: *ptr++ = sxth64(tmp, reg); if (update_mask & (SR_C | SR_X)) { *ptr++ = ands64_reg(31, tmp, mask, LSL, 0); } *ptr++ = asrv64(tmp, tmp, shiftreg); *ptr++ = bfi(reg, tmp, 0, 16); break; case 1: *ptr++ = sxtb64(tmp, reg); if (update_mask & (SR_C | SR_X)) { *ptr++ = ands64_reg(31, tmp, mask, LSL, 0); } *ptr++ = asrv64(tmp, tmp, shiftreg); *ptr++ = bfi(reg, tmp, 0, 8); break; } RA_FreeARMRegister(&ptr, mask); } if (update_mask) { uint8_t tmp2 = RA_AllocARMRegister(&ptr); uint8_t alt_flags = update_mask; if ((alt_flags & 3) != 0 && (alt_flags & 3) < 3) alt_flags ^= 3; ptr = EMIT_ClearFlags(ptr, cc, alt_flags); if (update_mask & (SR_C | SR_X)) { *ptr++ = b_cc(A64_CC_EQ, 3); *ptr++ = mov_immed_u16(tmp2, SR_Calt | SR_X, 0); *ptr++ = orr_reg(cc, cc, tmp2, LSL, 0); } RA_FreeARMRegister(&ptr, tmp2); if (direction && (update_mask & SR_V)) { *ptr++ = ands_reg(31, reg_orig, mask, LSL, 0); *ptr++ = b_cc(A64_CC_EQ, 7); *ptr++ = cmp_immed(shiftreg_orig, size == 4 ? 32 : (size == 2 ? 16 : 8)); *ptr++ = b_cc(A64_CC_GE, 4); *ptr++ = eor_reg(reg_orig, reg_orig, mask, LSL, 0); *ptr++ = ands_reg(31, reg_orig, mask, LSL, 0); *ptr++ = b_cc(A64_CC_EQ, 2); *ptr++ = orr_immed(cc, cc, 1, 31 & (32 - SRB_Valt)); } if (update_mask & (SR_Z | SR_N)) { switch(size) { case 4: *ptr++ = cmn_reg(31, reg, LSL, 0); break; case 2: *ptr++ = cmn_reg(31, tmp, LSL, 16); break; case 1: *ptr++ = cmn_reg(31, tmp, LSL, 24); break; } if (update_mask & SR_Z) { *ptr++ = b_cc(A64_CC_EQ ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, (32 - SRB_Z) & 31); } if (update_mask & SR_N) { *ptr++ = b_cc(A64_CC_MI ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, (32 - SRB_N) & 31); } } } if (tmpptr_1 != NULL) { *tmpptr_2 = b_cc(A64_CC_AL, ptr - tmpptr_2); } else { *tmpptr_2 = b_cc(A64_CC_EQ, ptr - tmpptr_2); } ptr = EMIT_AdvancePC(ptr, 2); RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask); RA_FreeARMRegister(&ptr, shiftreg_orig); RA_FreeARMRegister(&ptr, reg_orig); return ptr; } static uint32_t *EMIT_ASR(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) __attribute__((alias("EMIT_ASL"))); static uint32_t *EMIT_ASL(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t shift = (opcode >> 9) & 7; uint8_t size = 1 << ((opcode >> 6) & 3); uint8_t reg = RA_MapM68kRegister(&ptr, opcode & 7); uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t direction = (opcode >> 8) & 1; uint8_t cc = RA_ModifyCC(&ptr); RA_SetDirtyM68kRegister(&ptr, opcode & 7); if (!shift) shift = 8; if (direction && (update_mask & SR_V)) { uint8_t tmp_reg = RA_AllocARMRegister(&ptr); int rot = (size == 4) ? 0 : (size == 2) ? 16 : 24; int width = shift + 1; if (size == 1 && width > 8) width = 8; *ptr++ = bic_immed(cc, cc, 1, 31 & (32 - SRB_Valt)); *ptr++ = ands_immed(tmp_reg, reg, width, width + rot); *ptr++ = b_cc(A64_CC_EQ, (size == 1 && shift == 8) ? 2 : 5); if (!(size == 1 && shift == 8)) { *ptr++ = eor_immed(tmp_reg, tmp_reg, width, width + rot); *ptr++ = ands_immed(tmp_reg, tmp_reg, width, width + rot); *ptr++ = b_cc(A64_CC_EQ, 2); } *ptr++ = orr_immed(cc, cc, 1, 31 & (32 - SRB_Valt)); update_mask &= ~SR_V; RA_FreeARMRegister(&ptr, tmp_reg); } if (update_mask & (SR_C | SR_X)) { if (direction) { switch (size) { case 4: *ptr++ = tst_immed(reg, 1, shift); break; case 2: *ptr++ = tst_immed(reg, 1, 16 + shift); break; case 1: *ptr++ = tst_immed(reg, 1, 31 & (24 + shift)); break; } } else { *ptr++ = tst_immed(reg, 1, 31 & (33 - shift)); } } if (direction) { switch (size) { case 4: *ptr++ = lsl(reg, reg, shift); break; case 2: *ptr++ = lsl(tmp, reg, shift); *ptr++ = bfi(reg, tmp, 0, 16); break; case 1: *ptr++ = lsl(tmp, reg, shift); *ptr++ = bfi(reg, tmp, 0, 8); break; } } else { switch (size) { case 4: *ptr++ = asr(reg, reg, shift); break; case 2: *ptr++ = sxth(tmp, reg); *ptr++ = asr(tmp, tmp, shift); *ptr++ = bfi(reg, tmp, 0, 16); break; case 1: *ptr++ = sxtb(tmp, reg); *ptr++ = asr(tmp, tmp, shift); *ptr++ = bfi(reg, tmp, 0, 8); break; } } ptr = EMIT_AdvancePC(ptr, 2); if (update_mask) { uint8_t tmp2 = RA_AllocARMRegister(&ptr); uint8_t clear_mask = update_mask; /* Swap C and V flags in immediate */ if ((clear_mask & 3) != 0 && (clear_mask & 3) < 3) clear_mask ^= 3; ptr = EMIT_ClearFlags(ptr, cc, clear_mask); if (update_mask & (SR_C | SR_X)) { *ptr++ = b_cc(A64_CC_EQ, 3); *ptr++ = mov_immed_u16(tmp2, SR_Calt | SR_X, 0); *ptr++ = orr_reg(cc, cc, tmp2, LSL, 0); } RA_FreeARMRegister(&ptr, tmp2); if (update_mask & (SR_Z | SR_N)) { switch(size) { case 4: *ptr++ = cmn_reg(31, reg, LSL, 0); break; case 2: *ptr++ = cmn_reg(31, tmp, LSL, 16); break; case 1: *ptr++ = cmn_reg(31, tmp, LSL, 24); break; } if (update_mask & SR_Z) { *ptr++ = b_cc(A64_CC_EQ ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, (32 - SRB_Z) & 31); } if (update_mask & SR_N) { *ptr++ = b_cc(A64_CC_MI ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, (32 - SRB_N) & 31); } } } RA_FreeARMRegister(&ptr, tmp); return ptr; } static uint32_t *EMIT_LSR_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) __attribute__((alias("EMIT_LSL_reg"))); static uint32_t *EMIT_LSL_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t cc = RA_ModifyCC(&ptr); uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t direction = (opcode >> 8) & 1; uint8_t shift = (opcode >> 9) & 7; uint8_t size = 1 << ((opcode >> 6) & 3); uint8_t reg = RA_MapM68kRegister(&ptr, opcode & 7); uint8_t tmp = RA_AllocARMRegister(&ptr); uint32_t *tmpptr_1; uint32_t *tmpptr_2; RA_SetDirtyM68kRegister(&ptr, opcode & 7); uint8_t shiftreg = RA_MapM68kRegister(&ptr, shift); // Check shift size 0 - in that case no bit shifting is necessary, clear VC flags, update NZ, leave X *ptr++ = ands_immed(31, shiftreg, 6, 0); tmpptr_1 = ptr; *ptr++ = b_cc(A64_CC_NE, 0); // If V and/or Z need to be updated, do it and clear CV. No further actions are necessary if (update_mask & SR_NZ) { uint8_t update_mask_copy = update_mask; switch (size) { case 4: *ptr++ = cmn_reg(31, reg, LSL, 0); break; case 2: *ptr++ = cmn_reg(31, reg, LSL, 16); break; case 1: *ptr++ = cmn_reg(31, reg, LSL, 24); break; } ptr = EMIT_GetNZ00(ptr, cc, &update_mask_copy); } else if (update_mask & SR_VC) { // Only V or C need to be updated. Clear both *ptr++ = bic_immed(cc, cc, 2, 0); } tmpptr_2 = ptr; // Skip further bit shifting totally *ptr++ = b_cc(A64_CC_AL, 0); if ((ptr - tmpptr_1) != 2) { *tmpptr_1 = b_cc(A64_CC_NE, ptr - tmpptr_1); } else { ptr--; tmpptr_2--; tmpptr_1 = NULL; } if (direction) { switch (size) { case 4: *ptr++ = lslv64(tmp, reg, shiftreg); *ptr++ = mov_reg(reg, tmp); if (update_mask & (SR_C | SR_X)) { *ptr++ = tst64_immed(tmp, 1, 32, 1); } break; case 2: *ptr++ = lslv64(tmp, reg, shiftreg); if (update_mask & (SR_C | SR_X)) { *ptr++ = tst_immed(tmp, 1, 16); } *ptr++ = bfi(reg, tmp, 0, 16); break; case 1: *ptr++ = lslv64(tmp, reg, shiftreg); if (update_mask & (SR_C | SR_X)) { *ptr++ = tst_immed(tmp, 1, 24); } *ptr++ = bfi(reg, tmp, 0, 8); break; } } else { uint8_t mask = RA_AllocARMRegister(&ptr); if (update_mask & (SR_C | SR_X)) { uint8_t t = RA_AllocARMRegister(&ptr); /* *ptr++ = sub_immed(t, shiftreg, 1); *ptr++ = mov_immed_u16(mask, 1, 0); *ptr++ = lslv64(mask, mask, t); */ RA_FreeARMRegister(&ptr, t); } switch (size) { case 4: *ptr++ = mov_reg(tmp, reg); if (update_mask & (SR_C | SR_X)) { //*ptr++ = ands_reg(31, tmp, mask, LSL, 0); *ptr++ = rorv64(0, tmp, shiftreg); *ptr++ = tst64_immed(0, 1, 1, 1); } *ptr++ = lsrv64(tmp, tmp, shiftreg); *ptr++ = mov_reg(reg, tmp); break; case 2: *ptr++ = uxth(tmp, reg); if (update_mask & (SR_C | SR_X)) { //*ptr++ = ands_reg(31, tmp, mask, LSL, 0); *ptr++ = rorv64(0, tmp, shiftreg); *ptr++ = tst64_immed(0, 1, 1, 1); } *ptr++ = lsrv64(tmp, tmp, shiftreg); *ptr++ = bfi(reg, tmp, 0, 16); break; case 1: *ptr++ = uxtb(tmp, reg); if (update_mask & (SR_C | SR_X)) { //*ptr++ = ands_reg(31, tmp, mask, LSL, 0); *ptr++ = rorv64(0, tmp, shiftreg); *ptr++ = tst64_immed(0, 1, 1, 1); } *ptr++ = lsrv64(tmp, tmp, shiftreg); *ptr++ = bfi(reg, tmp, 0, 8); break; } RA_FreeARMRegister(&ptr, mask); } if (update_mask) { uint8_t tmp2 = RA_AllocARMRegister(&ptr); /* C/X condition is already pre-computed. Insert the flags now! */ if (update_mask & (SR_C | SR_X)) { if ((update_mask & SR_XC) == SR_XC) { *ptr++ = mov_immed_u16(tmp2, SR_Calt | SR_X, 0); *ptr++ = bic_reg(0, cc, tmp2, LSL, 0); *ptr++ = orr_reg(tmp2, cc, tmp2, LSL, 0); *ptr++ = csel(cc, 0, tmp2, A64_CC_EQ); } else if ((update_mask & SR_XC) == SR_X) { *ptr++ = cset(0, A64_CC_NE); *ptr++ = bfi(cc, 0, SRB_X, 1); } else { *ptr++ = cset(0, A64_CC_NE); *ptr++ = bfi(cc, 0, SRB_Calt, 1); } /* Done with C and/or X */ update_mask &= ~(SR_XC); } RA_FreeARMRegister(&ptr, tmp2); uint8_t clear_mask = update_mask; /* Swap C and V flags in immediate */ if ((clear_mask & 3) != 0 && (clear_mask & 3) < 3) clear_mask ^= 3; ptr = EMIT_ClearFlags(ptr, cc, clear_mask); if (update_mask & (SR_Z | SR_N)) { switch(size) { case 4: *ptr++ = cmn_reg(31, reg, LSL, 0); break; case 2: *ptr++ = cmn_reg(31, tmp, LSL, 16); break; case 1: *ptr++ = cmn_reg(31, tmp, LSL, 24); break; } if (update_mask & SR_Z) { *ptr++ = b_cc(A64_CC_EQ ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, (32 - SRB_Z) & 31); } if (update_mask & SR_N) { *ptr++ = b_cc(A64_CC_MI ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, (32 - SRB_N) & 31); } } } if (tmpptr_1 != NULL) { *tmpptr_2 = b_cc(A64_CC_AL, ptr - tmpptr_2); } else { *tmpptr_2 = b_cc(A64_CC_EQ, ptr - tmpptr_2); } ptr = EMIT_AdvancePC(ptr, 2); RA_FreeARMRegister(&ptr, tmp); return ptr; } static uint32_t *EMIT_LSR(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) __attribute__((alias("EMIT_LSL"))); static uint32_t *EMIT_LSL(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t direction = (opcode >> 8) & 1; uint8_t shift = (opcode >> 9) & 7; uint8_t size = 1 << ((opcode >> 6) & 3); uint8_t reg = RA_MapM68kRegister(&ptr, opcode & 7); uint8_t tmp = RA_AllocARMRegister(&ptr); RA_SetDirtyM68kRegister(&ptr, opcode & 7); if (!shift) shift = 8; if (update_mask & (SR_C | SR_X)) { if (direction) { switch (size) { case 4: *ptr++ = tst_immed(reg, 1, shift); break; case 2: *ptr++ = tst_immed(reg, 1, 16 + shift); break; case 1: *ptr++ = tst_immed(reg, 1, 31 & (24 + shift)); break; } } else { *ptr++ = tst_immed(reg, 1, 31 & (33 - shift)); } } if (direction) { switch (size) { case 4: *ptr++ = lsl(reg, reg, shift); break; case 2: *ptr++ = lsl(tmp, reg, shift); *ptr++ = bfi(reg, tmp, 0, 16); break; case 1: *ptr++ = lsl(tmp, reg, shift); *ptr++ = bfi(reg, tmp, 0, 8); break; } } else { switch (size) { case 4: *ptr++ = lsr(reg, reg, shift); break; case 2: *ptr++ = uxth(tmp, reg); *ptr++ = lsr(tmp, tmp, shift); *ptr++ = bfi(reg, tmp, 0, 16); break; case 1: *ptr++ = uxtb(tmp, reg); *ptr++ = lsr(tmp, tmp, shift); *ptr++ = bfi(reg, tmp, 0, 8); break; } } ptr = EMIT_AdvancePC(ptr, 2); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); uint8_t alt_flags = update_mask; if ((alt_flags & 3) != 0 && (alt_flags & 3) < 3) alt_flags ^= 3; ptr = EMIT_ClearFlags(ptr, cc, alt_flags); uint8_t tmp2 = RA_AllocARMRegister(&ptr); /* C/X condition is already pre-computed. Insert the flags now! */ if (update_mask & (SR_C | SR_X)) { if ((update_mask & SR_XC) == SR_XC) { *ptr++ = mov_immed_u16(tmp2, SR_Calt | SR_X, 0); *ptr++ = orr_reg(tmp2, cc, tmp2, LSL, 0); *ptr++ = csel(cc, cc, tmp2, A64_CC_EQ); } else if ((update_mask & SR_XC) == SR_X) { *ptr++ = cset(0, A64_CC_NE); *ptr++ = bfi(cc, 0, SRB_X, 1); } else { *ptr++ = cset(0, A64_CC_NE); *ptr++ = bfi(cc, 0, SRB_Calt, 1); } /* Done with C and/or X */ update_mask &= ~(SR_XC); } RA_FreeARMRegister(&ptr, tmp2); if (update_mask & (SR_Z | SR_N)) { switch(size) { case 4: *ptr++ = cmn_reg(31, reg, LSL, 0); break; case 2: *ptr++ = cmn_reg(31, tmp, LSL, 16); break; case 1: *ptr++ = cmn_reg(31, tmp, LSL, 24); break; } if (update_mask & SR_Z) { *ptr++ = orr_immed(0, cc, 1, (32 - SRB_Z) & 31); *ptr++ = csel(cc, 0, cc, A64_CC_EQ); } if (update_mask & SR_N) { *ptr++ = orr_immed(0, cc, 1, (32 - SRB_N) & 31); *ptr++ = csel(cc, 0, cc, A64_CC_MI); } } } RA_FreeARMRegister(&ptr, tmp); return ptr; } static uint32_t *EMIT_ROR_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) __attribute__((alias("EMIT_ROL"))); static uint32_t *EMIT_ROL_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) __attribute__((alias("EMIT_ROL"))); static uint32_t *EMIT_ROR(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) __attribute__((alias("EMIT_ROL"))); static uint32_t *EMIT_ROL(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t direction = (opcode >> 8) & 1; uint8_t shift = (opcode >> 9) & 7; uint8_t shift_orig = 0xff; uint8_t size = 1 << ((opcode >> 6) & 3); uint8_t regshift = (opcode >> 5) & 1; uint8_t reg = RA_MapM68kRegister(&ptr, opcode & 7); uint8_t tmp = RA_AllocARMRegister(&ptr); RA_SetDirtyM68kRegister(&ptr, opcode & 7); if (regshift) { if (direction) { uint8_t shift_mod = RA_AllocARMRegister(&ptr); shift = RA_MapM68kRegister(&ptr, shift); if (update_mask & SR_C) { shift_orig = RA_AllocARMRegister(&ptr); *ptr++ = and_immed(shift_orig, shift, 6, 0); } *ptr++ = neg_reg(shift_mod, shift, LSL, 0); *ptr++ = add_immed(shift_mod, shift_mod, 32); shift = shift_mod; } else { shift = RA_CopyFromM68kRegister(&ptr, shift); if (update_mask & SR_C) { shift_orig = RA_AllocARMRegister(&ptr); *ptr++ = and_immed(shift_orig, shift, 6, 0); } } switch (size) { case 4: *ptr++ = rorv(reg, reg, shift); break; case 2: *ptr++ = mov_reg(tmp, reg); *ptr++ = bfi(tmp, tmp, 16, 16); *ptr++ = rorv(tmp, tmp, shift); *ptr++ = bfi(reg, tmp, 0, 16); break; case 1: *ptr++ = mov_reg(tmp, reg); *ptr++ = bfi(tmp, tmp, 8, 8); *ptr++ = bfi(tmp, tmp, 16, 16); *ptr++ = rorv(tmp, tmp, shift); *ptr++ = bfi(reg, tmp, 0, 8); break; } RA_FreeARMRegister(&ptr, shift); } else { if (!shift) shift = 8; if (direction) { shift = 32 - shift; } switch (size) { case 4: *ptr++ = ror(reg, reg, shift); break; case 2: *ptr++ = mov_reg(tmp, reg); *ptr++ = bfi(tmp, tmp, 16, 16); *ptr++ = ror(tmp, tmp, shift); *ptr++ = bfi(reg, tmp, 0, 16); break; case 1: *ptr++ = mov_reg(tmp, reg); *ptr++ = bfi(tmp, tmp, 8, 8); *ptr++ = bfi(tmp, tmp, 16, 16); *ptr++ = ror(tmp, tmp, shift); *ptr++ = bfi(reg, tmp, 0, 8); break; } } ptr = EMIT_AdvancePC(ptr, 2); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); switch(size) { case 4: *ptr++ = cmn_reg(31, reg, LSL, 0); break; case 2: *ptr++ = cmn_reg(31, tmp, LSL, 16); break; case 1: *ptr++ = cmn_reg(31, tmp, LSL, 24); break; } uint8_t old_mask = update_mask & SR_C; ptr = EMIT_GetNZ00(ptr, cc, &update_mask); update_mask |= old_mask; if (update_mask & SR_Z) ptr = EMIT_SetFlagsConditional(ptr, cc, SR_Z, ARM_CC_EQ); if (update_mask & SR_N) ptr = EMIT_SetFlagsConditional(ptr, cc, SR_N, ARM_CC_MI); if (update_mask & SR_C) { if (regshift) { if (!direction) *ptr++ = cbz(shift_orig, 3); else *ptr++ = cbz(shift_orig, 2); RA_FreeARMRegister(&ptr, shift_orig); } if (!direction) { switch(size) { case 4: *ptr++ = bfxil(tmp, reg, 31, 1); *ptr++ = bfi(cc, tmp, 1, 1); break; case 2: *ptr++ = bfxil(tmp, reg, 15, 1); *ptr++ = bfi(cc, tmp, 1, 1); break; case 1: *ptr++ = bfxil(tmp, reg, 7, 1); *ptr++ = bfi(cc, tmp, 1, 1); break; } } else { *ptr++ = bfi(cc, reg, 1, 1); } } } RA_FreeARMRegister(&ptr, tmp); return ptr; } static uint32_t *EMIT_ROXR_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) __attribute__((alias("EMIT_ROXL"))); static uint32_t *EMIT_ROXL_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) __attribute__((alias("EMIT_ROXL"))); static uint32_t *EMIT_ROXR(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) __attribute__((alias("EMIT_ROXL"))); static uint32_t *EMIT_ROXL(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); int dir = opcode & 0x100; uint8_t cc = RA_ModifyCC(&ptr); int size = (opcode >> 6) & 3; uint8_t dest = RA_MapM68kRegister(&ptr, opcode & 7); RA_SetDirtyM68kRegister(&ptr, opcode & 7); if (opcode & 0x20) { // REG/REG mode uint8_t amount_reg = RA_MapM68kRegister(&ptr, (opcode >> 9) & 7); uint8_t amount = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t tmp2 = RA_AllocARMRegister(&ptr); uint32_t *tmp_ptr; // Limit rotate amount to 0..63, depending on size calculate modulo 9, 17, 33, depending on size *ptr++ = ands_immed(tmp, amount_reg, 6, 0); // If Z flag is set, don't bother with further ROXL/ROXR - size 0, no reg change // Only update CPU flags in that case tmp_ptr = ptr; *ptr++ = 0; if (update_mask & SR_NZV) { switch (size) { case 0: *ptr++ = cmn_reg(31, dest, LSL, 24); break; case 1: *ptr++ = cmn_reg(31, dest, LSL, 16); break; case 2: *ptr++ = cmn_reg(31, dest, LSL, 0); break; } uint8_t tmp_mask = update_mask; ptr = EMIT_GetNZ00(ptr, cc, &tmp_mask); } if (update_mask & SR_C) { *ptr++ = lsr(0, cc, 4); *ptr++ = bfi(cc, 0, 1, 1); } *ptr++ = 0; *tmp_ptr = b_cc(A64_CC_NE, ptr - tmp_ptr); tmp_ptr = ptr - 1; // Continue calculating modulo *ptr++ = mov_immed_u16(tmp2, size == 0 ? 9 : (size == 1 ? 17 : 33), 0); *ptr++ = udiv(amount, tmp, tmp2); *ptr++ = msub(amount, tmp, amount, tmp2); // Copy data from dest register switch (size) { case 0: *ptr++ = and_immed(tmp, dest, 8, 0); break; case 1: *ptr++ = and_immed(tmp, dest, 16, 0); break; case 2: *ptr++ = mov_reg(tmp, dest); break; } kprintf("[ERROR] ROXL not yet fixed!\n"); // Fill the temporary register with repetitions of X and dest *ptr++ = tst_immed(cc, 1, 32 - SRB_X); if (dir) { // Rotate left switch (size) { case 0: // byte *ptr++ = neg_reg(amount, amount, LSR, 0); *ptr++ = add_immed(amount, amount, 32); *ptr++ = b_cc(A64_CC_EQ, 2); *ptr++ = orr_immed(tmp, tmp, 1, 32 - 8); *ptr++ = bfi(tmp, tmp, 32 - 9, 9); *ptr++ = rorv(tmp, tmp, amount); *ptr++ = bfi(dest, tmp, 0, 8); break; case 1: // word *ptr++ = neg_reg(amount, amount, LSR, 0); *ptr++ = add_immed(amount, amount, 64); *ptr++ = b_cc(A64_CC_EQ, 2); *ptr++ = orr_immed(tmp, tmp, 1, 32 - 16); *ptr++ = bfi64(tmp, tmp, 64 - 17, 17); *ptr++ = rorv64(tmp, tmp, amount); *ptr++ = bfi(dest, tmp, 0, 16); break; case 2: // long *ptr++ = b_cc(A64_CC_EQ, 2); *ptr++ = orr64_immed(tmp, tmp, 1, 32, 1); *ptr++ = cbz(amount, 13); *ptr++ = neg_reg(amount, amount, LSR, 0); *ptr++ = add_immed(amount, amount, 64); *ptr++ = cmp_immed(amount, 32); *ptr++ = b_cc(A64_CC_EQ, 6); *ptr++ = lsl64(tmp, tmp, 31); *ptr++ = bfxil64(tmp, tmp, 31, 32); *ptr++ = rorv64(tmp, tmp, amount); *ptr++ = mov_reg(dest, tmp); *ptr++ = b(4); *ptr++ = bfi64(tmp, tmp, 33, 10); *ptr++ = ror64(tmp, tmp, 1); *ptr++ = mov_reg(dest, tmp); break; default: break; } } else { // Rotate right - pattern in temp register: ...... X | DEST | X | DEST switch (size) { case 0: // byte *ptr++ = b_cc(A64_CC_EQ, 2); *ptr++ = orr_immed(tmp, tmp, 1, 32 - 8); *ptr++ = bfi(tmp, tmp, 9, 9); *ptr++ = rorv(tmp, tmp, amount); *ptr++ = bfi(dest, tmp, 0, 8); break; case 1: // word *ptr++ = b_cc(A64_CC_EQ, 2); *ptr++ = orr_immed(tmp, tmp, 1, 32 - 16); *ptr++ = bfi64(tmp, tmp, 17, 17); *ptr++ = rorv64(tmp, tmp, amount); *ptr++ = bfi(dest, tmp, 0, 16); break; case 2: // long *ptr++ = b_cc(A64_CC_EQ, 2); *ptr++ = orr64_immed(tmp, tmp, 1, 64 - 32, 1); *ptr++ = cmp_immed(amount, 31); *ptr++ = b_cc(A64_CC_HI, 5); *ptr++ = bfi64(tmp, tmp, 33, 31); *ptr++ = rorv64(tmp, tmp, amount); *ptr++ = mov_reg(dest, tmp); *ptr++ = b(6); *ptr++ = lsr64(tmp, tmp, 32); *ptr++ = sub_immed(amount, amount, 32); *ptr++ = bfi64(tmp, dest, 1, 32); *ptr++ = rorv64(tmp, tmp, amount); *ptr++ = mov_reg(dest, tmp); break; default: break; } } if (update_mask & SR_NZV) { switch (size) { case 0: *ptr++ = cmn_reg(31, tmp, LSL, 24); break; case 1: *ptr++ = cmn_reg(31, tmp, LSL, 16); break; case 2: *ptr++ = cmn_reg(31, tmp, LSL, 0); break; } uint8_t tmp_mask = update_mask; ptr = EMIT_GetNZ00(ptr, cc, &tmp_mask); } if (update_mask & SR_XC) { switch(size) { case 0: *ptr++ = bfxil(tmp, tmp, 8, 1); *ptr++ = bfi(cc, tmp, 1, 1); break; case 1: *ptr++ = bfxil(tmp, tmp, 16, 1); *ptr++ = bfi(cc, tmp, 1, 1); break; case 2: *ptr++ = bfxil64(tmp, tmp, 32, 1); *ptr++ = bfi(cc, tmp, 1, 1); break; } if (update_mask & SR_X) { *ptr++ = ror(0, cc, 1); *ptr++ = bfi(cc, 0, 4, 1); } } *tmp_ptr = b(ptr - tmp_ptr); RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, tmp2); RA_FreeARMRegister(&ptr, amount); } else { uint8_t tmp = RA_AllocARMRegister(&ptr); int amount = (opcode >> 9) & 7; if (amount == 0) amount = 8; if (dir) { // rotate left switch (size) { // Rotate left byte, 1 to 8 positions // temporary register layout // X7654321 0....... ........ 76543210 // After rotation copy the 31th bit into X and C case 0: // byte *ptr++ = mov_reg(tmp, dest); *ptr++ = bic_immed(tmp, tmp, 1, 1); *ptr++ = tbz(cc, SRB_X, 2); *ptr++ = orr_immed(tmp, tmp, 1, 1); *ptr++ = bfi(tmp, tmp, 31-8, 8); *ptr++ = ror(tmp, tmp, 32 - amount); *ptr++ = bfi(dest, tmp, 0, 8); break; // Rotate left word, 1 to 8 positions // temporary register layout // Xfedcba9 87654321 fedcba98 76543210 // After rotation copy the 31th bit into X and C case 1: // word *ptr++ = mov_reg(tmp, dest); *ptr++ = bic_immed(tmp, tmp, 1, 1); *ptr++ = tbz(cc, SRB_X, 2); *ptr++ = orr_immed(tmp, tmp, 1, 1); *ptr++ = bfi64(tmp, tmp, 31-16, 16); *ptr++ = ror(tmp, tmp, 32 - amount); *ptr++ = bfi(dest, tmp, 0, 16); break; // Rotate left long, 1 to 8 positions // Use 64bit temporary register for the operation // bits 64-32: X(1f)(1e)...(00) // bits 31-0: source register case 2: // long *ptr++ = lsl64(tmp, dest, 31); *ptr++ = bic64_immed(tmp, tmp, 1, 1, 1); *ptr++ = tbz(cc, SRB_X, 2); *ptr++ = orr64_immed(tmp, tmp, 1, 1, 1); *ptr++ = bfxil64(tmp, tmp, 31, 32); *ptr++ = ror64(tmp, tmp, 64 - amount); *ptr++ = mov_reg(dest, tmp); break; } } else { // rotate right switch (size) { case 0: // byte *ptr++ = mov_reg(tmp, dest); *ptr++ = bic_immed(tmp, tmp, 1, 32 - 8); *ptr++ = tbz(cc, SRB_X, 2); *ptr++ = orr_immed(tmp, tmp, 1, 32 - 8); *ptr++ = bfi(tmp, tmp, 9, 9); *ptr++ = ror(tmp, tmp, amount); *ptr++ = bfi(dest, tmp, 0, 8); break; case 1: // word *ptr++ = mov_reg(tmp, dest); *ptr++ = bic_immed(tmp, tmp, 1, 32 - 16); *ptr++ = tbz(cc, SRB_X, 2); *ptr++ = orr_immed(tmp, tmp, 1, 32 - 16); *ptr++ = bfi64(tmp, tmp, 17, 17); *ptr++ = ror64(tmp, tmp, amount); *ptr++ = bfi(dest, tmp, 0, 16); break; case 2: // long *ptr++ = lsl64(tmp, dest, 33); *ptr++ = bfi64(tmp, dest, 0, 32); *ptr++ = tbz(cc, SRB_X, 4); *ptr++ = orr64_immed(tmp, tmp, 1, 32, 1); *ptr++ = b(2); *ptr++ = bic64_immed(tmp, tmp, 1, 32, 1); *ptr++ = ror64(tmp, tmp, amount); *ptr++ = mov_reg(dest, tmp); break; } } if (update_mask & SR_NZV) { switch (size) { case 0: *ptr++ = cmn_reg(31, tmp, LSL, 24); break; case 1: *ptr++ = cmn_reg(31, tmp, LSL, 16); break; case 2: *ptr++ = cmn_reg(31, tmp, LSL, 0); break; } uint8_t tmp_mask = update_mask; ptr = EMIT_GetNZ00(ptr, cc, &tmp_mask); } if (update_mask & SR_XC) { if (dir) { switch(size) { case 0: *ptr++ = bfxil(tmp, tmp, 31, 1); *ptr++ = bfi(cc, tmp, 1, 1); break; case 1: *ptr++ = bfxil(tmp, tmp, 31, 1); *ptr++ = bfi(cc, tmp, 1, 1); break; case 2: *ptr++ = bfxil64(tmp, tmp, 63, 1); *ptr++ = bfi(cc, tmp, 1, 1); break; } } else { switch(size) { case 0: *ptr++ = bfxil(tmp, tmp, 8, 1); *ptr++ = bfi(cc, tmp, 1, 1); break; case 1: *ptr++ = bfxil(tmp, tmp, 16, 1); *ptr++ = bfi(cc, tmp, 1, 1); break; case 2: *ptr++ = bfxil64(tmp, tmp, 32, 1); *ptr++ = bfi(cc, tmp, 1, 1); break; } } if (update_mask & SR_X) { *ptr++ = ror(0, cc, 1); *ptr++ = bfi(cc, 0, 4, 1); } } RA_FreeARMRegister(&ptr, tmp); } ptr = EMIT_AdvancePC(ptr, 2); return ptr; } enum BF_OP { OP_EOR, OP_SET, OP_CLR, OP_TST, OP_INS, OP_EXTS, OP_EXTU, OP_FFO }; static inline uint32_t *EMIT_BFxxx_II(uint32_t *ptr, uint8_t base, enum BF_OP op, uint8_t Do, uint8_t Dw, uint8_t update_mask, uint8_t data) { uint8_t width = (Dw == 0) ? 32 : Dw; uint8_t base_offset = Do >> 3; uint8_t bit_offset = Do & 7; uint8_t data_reg = 0; uint8_t test_reg = 1; uint8_t fetched_size = 0; uint8_t data_offset = 0; /* IF bit offset + width <= 8, fetch a byte */ if ((bit_offset + width) <= 8) { *ptr++ = ldurb_offset(base, data_reg, base_offset); fetched_size = 1; data_offset = 56; } /* bit offset + width <= 16: fetch a word */ else if ((bit_offset + width) <= 16) { *ptr++ = ldurh_offset(base, data_reg, base_offset); fetched_size = 2; data_offset = 48; } /* bit offset + width <= 32: fetch a long */ else if ((bit_offset + width) <= 32) { *ptr++ = ldur_offset(base, data_reg, base_offset); fetched_size = 4; data_offset = 32; } /* Worst case otherwise - fetch 64bit */ else { *ptr++ = ldur64_offset(base, data_reg, base_offset); fetched_size = 8; } /* For insert mode the inserted data is checked for NZ flags, otherwise existing bitfield */ if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); if (op == OP_INS) { /* Test inserted data */ *ptr++ = cmn_reg(31, data, LSL, 32 - width); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } else if (op != OP_EXTS && op != OP_EXTU && op != OP_FFO) { /* Test bitfield */ *ptr++ = lsl64(test_reg, data_reg, data_offset + bit_offset); *ptr++ = ands64_immed(test_reg, test_reg, width, width, 1); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } } if (op != OP_TST) { switch (op) { case OP_EOR: // Exclusive-or all bits *ptr++ = eor64_immed(data_reg, data_reg, width, width + data_offset + bit_offset, 1); break; case OP_SET: // Set all bits *ptr++ = orr64_immed(data_reg, data_reg, width, width + data_offset + bit_offset, 1); break; case OP_CLR: // Clear all bits *ptr++ = bic64_immed(data_reg, data_reg, width, width + data_offset + bit_offset, 1); break; case OP_INS: switch (fetched_size) { case 1: *ptr++ = bfi(data_reg, data, 8 - (width + bit_offset), width); break; case 2: *ptr++ = bfi(data_reg, data, 16 - (width + bit_offset), width); break; case 4: *ptr++ = bfi(data_reg, data, 32 - (width + bit_offset), width); break; case 8: *ptr++ = bfi64(data_reg, data, 64 - (width + bit_offset), width); break; } break; case OP_EXTS: case OP_EXTU: { *ptr++ = lsl64(test_reg, data_reg, data_offset + bit_offset); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = ands64_immed(test_reg, test_reg, width, width, 1); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } if (op == OP_EXTU) { *ptr++ = lsr64(data, test_reg, 64 - width); } else { *ptr++ = asr64(data, test_reg, 64 - width); } } break; case OP_FFO: { /* Shift bitfield to the left */ *ptr++ = lsl64(test_reg, data_reg, data_offset + bit_offset); if (update_mask) { /* Test bitfield if necessary */ uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = ands64_immed(test_reg, test_reg, width, width, 1); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } /* Set lower bits to 1, so that CLZ can catch such cases */ *ptr++ = orr64_immed(test_reg, test_reg, 64 - width, 0, 1); *ptr++ = clz64(data, test_reg); *ptr++ = add_immed(data, data, Do); } break; default: break; } if (op != OP_EXTS && op != OP_EXTU && op != OP_FFO) { /* Store data back... */ switch (fetched_size) { case 1: *ptr++ = sturb_offset(base, data_reg, base_offset); break; case 2: *ptr++ = sturh_offset(base, data_reg, base_offset); break; case 4: *ptr++ = stur_offset(base, data_reg, base_offset); break; case 8: *ptr++ = stur64_offset(base, data_reg, base_offset); break; } } } return ptr; } static inline uint32_t *EMIT_BFxxx_IR(uint32_t *ptr, uint8_t base, enum BF_OP op, uint8_t Do, uint8_t Dw, uint8_t update_mask, uint8_t data) { uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t width_reg_orig = Dw; uint8_t width_reg = 3; uint8_t data_reg = 0; uint8_t test_reg = 1; uint8_t insert_reg = test_reg; uint8_t base_offset = Do >> 3; uint8_t bit_offset = Do & 7; /* Build up the mask from reg value */ *ptr++ = and_immed(width_reg, width_reg_orig, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); /* Move mask to the topmost bits of 64-bit mask_reg */ *ptr++ = rbit64(mask_reg, mask_reg); /* Fetch the data */ /* Width == 1? Fetch byte */ *ptr++ = cmp_immed(width_reg, 1); *ptr++ = b_cc(A64_CC_NE, 4); *ptr++ = ldurb_offset(base, data_reg, base_offset); *ptr++ = ror64(data_reg, data_reg, 8); *ptr++ = b(12); /* Width <= 8? Fetch half word */ *ptr++ = cmp_immed(width_reg, 8); *ptr++ = b_cc(A64_CC_GT, 4); *ptr++ = ldurh_offset(base, data_reg, base_offset); *ptr++ = ror64(data_reg, data_reg, 16); *ptr++ = b(7); /* Width <= 24? Fetch long word */ *ptr++ = cmp_immed(width_reg, 24); *ptr++ = b_cc(A64_CC_GT, 4); *ptr++ = ldur_offset(base, data_reg, base_offset); *ptr++ = ror64(data_reg, data_reg, 32); *ptr++ = b(2); *ptr++ = ldur64_offset(base, data_reg, base_offset); /* In case of INS, prepare the source data accordingly */ if (op == OP_INS) { /* Put inserted value to topmost bits of 64bit reg */ *ptr++ = rorv64(insert_reg, data, width_reg); /* CLear with insert mask, set condition codes */ *ptr++ = ands64_reg(insert_reg, insert_reg, mask_reg, LSL, 0); /* If XNZVC needs to be set, do it now */ if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } } else if (op != OP_EXTS && op != OP_EXTU && op != OP_FFO) { /* Shall bitfield be investigated before? */ if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = lsl64(test_reg, data_reg, bit_offset); *ptr++ = ands64_reg(31, mask_reg, test_reg, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } } /* For all operations other than TST perform the action */ if (op != OP_TST) { switch (op) { case OP_EOR: // Exclusive-or all bits *ptr++ = eor64_reg(data_reg, data_reg, mask_reg, LSR, bit_offset); break; case OP_SET: // Set all bits *ptr++ = orr64_reg(data_reg, data_reg, mask_reg, LSR, bit_offset); break; case OP_CLR: // Clear all bits *ptr++ = bic64_reg(data_reg, data_reg, mask_reg, LSR, bit_offset); break; case OP_INS: // Clear all bits *ptr++ = bic64_reg(data_reg, data_reg, mask_reg, LSR, bit_offset); // Insert data *ptr++ = orr64_reg(data_reg, data_reg, insert_reg, LSR, bit_offset); break; case OP_EXTU: case OP_EXTS: { /* Shift data left as much as possible */ *ptr++ = lsl64(test_reg, data_reg, bit_offset); /* If mask is to be updated do it now*/ if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = ands64_reg(31, mask_reg, test_reg, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } /* Compute how far do we shift right: 64 - width */ *ptr++ = neg_reg(width_reg, width_reg, LSL, 0); *ptr++ = add_immed(width_reg, width_reg, 64); if (op == OP_EXTS) { *ptr++ = asrv64(data, test_reg, width_reg); } else { *ptr++ = lsrv64(data, test_reg, width_reg); } } break; case OP_FFO: { *ptr++ = lsl64(test_reg, data_reg, bit_offset); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = ands64_reg(31, mask_reg, test_reg, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } // invert mask *ptr++ = mvn64_reg(mask_reg, mask_reg, LSL, 0); *ptr++ = orr64_reg(test_reg, test_reg, mask_reg, LSL, 0); *ptr++ = clz64(data, test_reg); *ptr++ = add_immed(data, data, Do); } break; default: break; } if (op != OP_EXTS && op != OP_EXTU && op != OP_FFO) { /* Store the data back */ /* Width == 1? Fetch byte */ *ptr++ = cmp_immed(width_reg, 1); *ptr++ = b_cc(A64_CC_NE, 4); *ptr++ = ror64(data_reg, data_reg, 64 - 8); *ptr++ = sturb_offset(base, data_reg, base_offset); *ptr++ = b(12); /* Width <= 8? Fetch half word */ *ptr++ = cmp_immed(width_reg, 8); *ptr++ = b_cc(A64_CC_GT, 4); *ptr++ = ror64(data_reg, data_reg, 64 - 16); *ptr++ = sturh_offset(base, data_reg, base_offset); *ptr++ = b(7); /* Width <= 24? Fetch long word */ *ptr++ = cmp_immed(width_reg, 24); *ptr++ = b_cc(A64_CC_GT, 4); *ptr++ = ror64(data_reg, data_reg, 32); *ptr++ = stur_offset(base, data_reg, base_offset); *ptr++ = b(2); *ptr++ = stur64_offset(base, data_reg, base_offset); } } RA_FreeARMRegister(&ptr, mask_reg); return ptr; } static inline uint32_t *EMIT_BFxxx_RI(uint32_t *ptr, uint8_t base, enum BF_OP op, uint8_t Do, uint8_t Dw, uint8_t update_mask, uint8_t data) { uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = 2; uint8_t off_reg = RA_AllocARMRegister(&ptr); uint8_t csel_1 = 0; uint8_t csel_2 = 1; //uint8_t insert_reg = 3; uint8_t width = Dw; uint8_t off_reg_orig = Do; uint8_t base_orig = base; int base_allocated = 0; if (width == 0) width = 32; // Adjust base register according to the offset // If base register is m68k register (directly), make a copy and do adjustment there! if (RA_IsM68kRegister(base)) { base = RA_AllocARMRegister(&ptr); base_allocated = 1; } /* If base was allocated, it will differ from base_orig so the adjustment will be correct in *any* case */ *ptr++ = add_reg(base, base_orig, off_reg_orig, ASR, 3); *ptr++ = and_immed(off_reg, off_reg_orig, 3, 0); if (width == 1) { // Build up a mask *ptr++ = orr_immed(mask_reg, 31, width, 24 + width); // Load data *ptr++ = ldrb_offset(base, tmp, 0); // Shift mask to correct position *ptr++ = lsrv(mask_reg, mask_reg, off_reg); /* In case of INS, prepare the source data accordingly */ if (op == OP_INS) { /* If XNZVC needs to be set, do it now */ if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); uint8_t alt_flags = update_mask; if ((alt_flags & 3) != 0 && (alt_flags & 3) < 3) alt_flags ^= 3; ptr = EMIT_ClearFlags(ptr, cc, alt_flags); *ptr++ = ands_immed(31, data, 1, 0); *ptr++ = orr_immed(csel_1, cc, 1, 32 - SRB_N); *ptr++ = orr_immed(csel_2, cc, 1, 32 - SRB_Z); *ptr++ = csel(cc, csel_2, csel_1, A64_CC_EQ); } } else if (op != OP_EXTS && op != OP_EXTU && op != OP_FFO) { if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); uint8_t alt_flags = update_mask; if ((alt_flags & 3) != 0 && (alt_flags & 3) < 3) alt_flags ^= 3; ptr = EMIT_ClearFlags(ptr, cc, alt_flags); *ptr++ = ands_reg(31, tmp, mask_reg, LSL, 0); *ptr++ = orr_immed(csel_1, cc, 1, 32 - SRB_N); *ptr++ = orr_immed(csel_2, cc, 1, 32 - SRB_Z); *ptr++ = csel(cc, csel_2, csel_1, A64_CC_EQ); } } if (op != OP_TST) { switch(op) { case OP_EOR: // Exclusive-or all bits *ptr++ = eor_reg(tmp, tmp, mask_reg, LSL, 0); break; case OP_SET: // Set all bits *ptr++ = orr_reg(tmp, tmp, mask_reg, LSL, 0); break; case OP_CLR: // Clear all bits *ptr++ = bic_reg(tmp, tmp, mask_reg, LSL, 0); break; case OP_INS: /* If update mask was not tested, test data, bit 0 now */ if (!update_mask) { *ptr++ = ands_immed(31, data, 1, 0); } *ptr++ = bic_reg(csel_1, tmp, mask_reg, LSL, 0); *ptr++ = orr_reg(csel_2, tmp, mask_reg, LSL, 0); *ptr++ = csel(tmp, csel_1, csel_2, A64_CC_EQ); break; case OP_EXTU: case OP_EXTS: { *ptr++ = ands_reg(31, tmp, mask_reg, LSL, 0); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); uint8_t alt_flags = update_mask; if ((alt_flags & 3) != 0 && (alt_flags & 3) < 3) alt_flags ^= 3; ptr = EMIT_ClearFlags(ptr, cc, alt_flags); *ptr++ = orr_immed(csel_1, cc, 1, 32 - SRB_N); *ptr++ = orr_immed(csel_2, cc, 1, 32 - SRB_Z); *ptr++ = csel(cc, csel_2, csel_1, A64_CC_EQ); } if (op == OP_EXTU) { *ptr++ = csinc(data, 31, 31, A64_CC_EQ); } else { *ptr++ = csinv(data, 31, 31, A64_CC_EQ); } } break; case OP_FFO: { *ptr++ = ands_reg(31, tmp, mask_reg, LSL, 0); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); uint8_t alt_flags = update_mask; if ((alt_flags & 3) != 0 && (alt_flags & 3) < 3) alt_flags ^= 3; ptr = EMIT_ClearFlags(ptr, cc, alt_flags); *ptr++ = orr_immed(csel_1, cc, 1, 32 - SRB_N); *ptr++ = orr_immed(csel_2, cc, 1, 32 - SRB_Z); *ptr++ = csel(cc, csel_2, csel_1, A64_CC_EQ); } *ptr++ = add_immed(csel_2, off_reg_orig, 1); *ptr++ = csel(data, csel_2, off_reg_orig, A64_CC_EQ); } break; default: break; } if (op != OP_EXTS && op != OP_EXTU && op != OP_FFO) { // Store back *ptr++ = strb_offset(base, tmp, 0); } } } else if (width <= 8) { // Build up a mask *ptr++ = orr_immed(mask_reg, 31, width, 16 + width); // Load data *ptr++ = ldrh_offset(base, tmp, 0); if (op == OP_INS) { if (update_mask) { uint8_t testreg = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); // Test input data *ptr++ = ror(testreg, data, width); *ptr++ = ands_immed(31, testreg, width, width); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } } else if (op != OP_EXTS && op != OP_EXTU && op != OP_FFO) { if (update_mask) { uint8_t testreg = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); // Shift source to correct position *ptr++ = lslv(testreg, tmp, off_reg); *ptr++ = lsl(testreg, testreg, 16); // Mask the bitfield, update condition codes *ptr++ = ands_reg(31, testreg, mask_reg, LSL, 16); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } } if (op != OP_TST) { // Shift mask to correct position if (op != OP_EXTU && op != OP_EXTS && op != OP_FFO) { *ptr++ = lsrv64(mask_reg, mask_reg, off_reg); } switch(op) { case OP_EOR: // Exclusive-or all bits *ptr++ = eor_reg(tmp, tmp, mask_reg, LSL, 0); break; case OP_SET: // Set all bits *ptr++ = orr_reg(tmp, tmp, mask_reg, LSL, 0); break; case OP_CLR: // Clear all bits *ptr++ = bic_reg(tmp, tmp, mask_reg, LSL, 0); break; case OP_INS: // Rotate source data *ptr++ = ror(csel_1, data, 16 + width); *ptr++ = lsrv(csel_1, csel_1, off_reg); // Mask non-insert bits *ptr++ = and_reg(csel_1, csel_1, mask_reg, LSL, 0); // Clear all bits in target *ptr++ = bic_reg(tmp, tmp, mask_reg, LSL, 0); // Merge fields *ptr++ = orr_reg(tmp, tmp, csel_1, LSL, 0); break; case OP_EXTU: case OP_EXTS: { uint8_t testreg = RA_AllocARMRegister(&ptr); // Shift source to correct position *ptr++ = lslv(testreg, tmp, off_reg); *ptr++ = lsl(testreg, testreg, 16); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); // Mask the bitfield, update condition codes *ptr++ = ands_reg(31, testreg, mask_reg, LSL, 16); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } if (op == OP_EXTU) { *ptr++ = lsr(data, testreg, 32 - width); } else { *ptr++ = asr(data, testreg, 32 - width); } RA_FreeARMRegister(&ptr, testreg); } break; case OP_FFO: { uint8_t testreg = RA_AllocARMRegister(&ptr); // Shift source to correct position *ptr++ = lslv(testreg, tmp, off_reg); *ptr++ = lsl(testreg, testreg, 16); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); // Mask the bitfield, update condition codes *ptr++ = ands_reg(31, testreg, mask_reg, LSL, 16); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } *ptr++ = orr_immed(testreg, testreg, 32 - width, 0); *ptr++ = clz(testreg, testreg); *ptr++ = add_reg(data, testreg, off_reg_orig, LSL, 0); RA_FreeARMRegister(&ptr, testreg); } break; default: break; } if (op != OP_EXTS && op != OP_EXTU && op != OP_FFO) { // Store back *ptr++ = strh_offset(base, tmp, 0); } } } else if (width <= 24) { // Build up a mask *ptr++ = orr_immed(mask_reg, 31, width, width); // Load data *ptr++ = ldr_offset(base, tmp, 0); if (op == OP_INS) { if (update_mask) { uint8_t testreg = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); // Test input data *ptr++ = ror(testreg, data, width); *ptr++ = ands_immed(31, testreg, width, width); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } } else if (op != OP_EXTS && op != OP_EXTU && op != OP_FFO) { if (update_mask) { uint8_t testreg = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); // Shift source to correct position *ptr++ = lslv(testreg, tmp, off_reg); // Mask the bitfield, update condition codes *ptr++ = ands_reg(31, testreg, mask_reg, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } } if (op != OP_TST) { // Shift mask to correct position if (op != OP_EXTU && op != OP_EXTS && op != OP_FFO) { *ptr++ = lsrv64(mask_reg, mask_reg, off_reg); } switch(op) { case OP_EOR: // Exclusive-or all bits *ptr++ = eor_reg(tmp, tmp, mask_reg, LSL, 0); break; case OP_SET: // Set all bits *ptr++ = orr_reg(tmp, tmp, mask_reg, LSL, 0); break; case OP_CLR: // Clear all bits *ptr++ = bic_reg(tmp, tmp, mask_reg, LSL, 0); break; case OP_INS: // Rotate source data *ptr++ = ror(csel_1, data, width); *ptr++ = lsrv(csel_1, csel_1, off_reg); // Mask non-insert bits *ptr++ = and_reg(csel_1, csel_1, mask_reg, LSL, 0); // Clear all bits in target *ptr++ = bic_reg(tmp, tmp, mask_reg, LSL, 0); // Merge fields *ptr++ = orr_reg(tmp, tmp, csel_1, LSL, 0); break; case OP_EXTU: case OP_EXTS: { uint8_t testreg = RA_AllocARMRegister(&ptr); // Shift source to correct position *ptr++ = lslv(testreg, tmp, off_reg); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); // Mask the bitfield, update condition codes *ptr++ = ands_reg(31, testreg, mask_reg, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } if (op == OP_EXTU) { *ptr++ = lsr(data, testreg, 32 - width); } else { *ptr++ = asr(data, testreg, 32 - width); } RA_FreeARMRegister(&ptr, testreg); } break; case OP_FFO: { uint8_t testreg = RA_AllocARMRegister(&ptr); // Shift source to correct position *ptr++ = lslv(testreg, tmp, off_reg); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); // Mask the bitfield, update condition codes *ptr++ = ands_reg(31, testreg, mask_reg, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } *ptr++ = orr_immed(testreg, testreg, 32 - width, 0); *ptr++ = clz(testreg, testreg); *ptr++ = add_reg(data, testreg, off_reg_orig, LSL, 0); RA_FreeARMRegister(&ptr, testreg); } break; default: break; } if (op != OP_EXTS && op != OP_EXTU && op != OP_FFO) { // Store back *ptr++ = str_offset(base, tmp, 0); } } } else { // Build up a mask *ptr++ = orr64_immed(mask_reg, 31, width, width, 1); // Load data and shift it left according to reminder in offset reg *ptr++ = ldr64_offset(base, tmp, 0); if (op == OP_INS) { if (update_mask) { uint8_t testreg = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); // Test input data if (width != 32) { *ptr++ = ror(testreg, data, width); *ptr++ = ands_immed(31, testreg, width, width); } else { *ptr++ = cmn_immed(data, 0); } ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } } else if (op != OP_EXTS && op != OP_EXTU && op != OP_FFO) { if (update_mask) { uint8_t testreg = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); // Shift source to correct position *ptr++ = lslv64(testreg, tmp, off_reg); // Mask the bitfield, update condition codes *ptr++ = ands64_reg(31, testreg, mask_reg, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } } if (op != OP_TST) { // Shift mask to correct position if (op != OP_EXTU && op != OP_EXTS && op != OP_FFO) { *ptr++ = lsrv64(mask_reg, mask_reg, off_reg); } switch(op) { case OP_EOR: // Exclusive-or all bits *ptr++ = eor64_reg(tmp, tmp, mask_reg, LSL, 0); break; case OP_SET: // Set all bits *ptr++ = orr64_reg(tmp, tmp, mask_reg, LSL, 0); break; case OP_CLR: // Clear all bits *ptr++ = bic64_reg(tmp, tmp, mask_reg, LSL, 0); break; case OP_INS: // Rotate source data *ptr++ = ror64(csel_1, data, width); *ptr++ = lsrv64(csel_1, csel_1, off_reg); // Mask non-insert bits *ptr++ = and64_reg(csel_1, csel_1, mask_reg, LSL, 0); // Clear all bits in target *ptr++ = bic64_reg(tmp, tmp, mask_reg, LSL, 0); // Merge fields *ptr++ = orr64_reg(tmp, tmp, csel_1, LSL, 0); break; case OP_EXTU: case OP_EXTS: { uint8_t testreg = RA_AllocARMRegister(&ptr); // Shift source to correct position *ptr++ = lslv64(testreg, tmp, off_reg); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); // Mask the bitfield, update condition codes *ptr++ = ands64_reg(31, testreg, mask_reg, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } if (op == OP_EXTU) { *ptr++ = lsr64(data, testreg, 64 - width); } else { *ptr++ = asr64(data, testreg, 64 - width); } RA_FreeARMRegister(&ptr, testreg); } break; case OP_FFO: { uint8_t testreg = RA_AllocARMRegister(&ptr); // Shift source to correct position *ptr++ = lslv64(testreg, tmp, off_reg); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); // Mask the bitfield, update condition codes *ptr++ = ands64_reg(31, testreg, mask_reg, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } *ptr++ = orr64_immed(testreg, testreg, 64 - width, 0, 1); *ptr++ = clz64(testreg, testreg); *ptr++ = add_reg(data, testreg, off_reg_orig, LSL, 0); RA_FreeARMRegister(&ptr, testreg); } break; default: break; } if (op != OP_EXTS && op != OP_EXTU && op != OP_FFO) { // Store back *ptr++ = str64_offset(base, tmp, 0); } } } if (base_allocated) { RA_FreeARMRegister(&ptr, base); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, off_reg); return ptr; } static inline uint32_t *EMIT_BFxxx_RR(uint32_t *ptr, uint8_t base, enum BF_OP op, uint8_t Do, uint8_t Dw, uint8_t update_mask, uint8_t data) { uint8_t width_reg_orig = Dw; uint8_t off_reg_orig = Do; uint8_t width_reg = 3; uint8_t mask_reg = 2; uint8_t test_reg = 1; uint8_t insert_reg = test_reg; uint8_t off_reg = RA_AllocARMRegister(&ptr); uint8_t data_reg = 0; uint8_t base_orig = base; int base_allocated = 0; /* Build up the mask from reg value */ *ptr++ = and_immed(width_reg, width_reg_orig, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); /* Move mask to the topmost bits of 64-bit mask_reg */ *ptr++ = rbit64(mask_reg, mask_reg); // Adjust base register according to the offset // If base register is m68k register (directly), make a copy and do adjustment there! if (RA_IsM68kRegister(base)) { base = RA_AllocARMRegister(&ptr); base_allocated = 1; } /* If base was allocated, it will differ from base_orig so the adjustment will be correct in *any* case */ *ptr++ = add_reg(base, base_orig, off_reg_orig, ASR, 3); *ptr++ = and_immed(off_reg, off_reg_orig, 3, 0); /* Fetch the data */ /* Width == 1? Fetch byte */ *ptr++ = cmp_immed(width_reg, 1); *ptr++ = b_cc(A64_CC_NE, 4); *ptr++ = ldrb_offset(base, data_reg, 0); *ptr++ = ror64(data_reg, data_reg, 8); *ptr++ = b(12); /* Width <= 8? Fetch half word */ *ptr++ = cmp_immed(width_reg, 8); *ptr++ = b_cc(A64_CC_GT, 4); *ptr++ = ldrh_offset(base, data_reg, 0); *ptr++ = ror64(data_reg, data_reg, 16); *ptr++ = b(7); /* Width <= 24? Fetch long word */ *ptr++ = cmp_immed(width_reg, 24); *ptr++ = b_cc(A64_CC_GT, 4); *ptr++ = ldr_offset(base, data_reg, 0); *ptr++ = ror64(data_reg, data_reg, 32); *ptr++ = b(2); *ptr++ = ldr64_offset(base, data_reg, 0); /* In case of INS, prepare the source data accordingly */ if (op == OP_INS) { /* Put inserted value to topmost bits of 64bit reg */ *ptr++ = rorv64(insert_reg, data, width_reg); /* CLear with insert mask, set condition codes */ *ptr++ = ands64_reg(insert_reg, insert_reg, mask_reg, LSL, 0); /* If XNZVC needs to be set, do it now */ if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } } else if (op != OP_EXTS && op != OP_EXTU && op != OP_FFO) { /* Shall bitfield be investigated before? */ if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = lslv64(test_reg, data_reg, off_reg); *ptr++ = ands64_reg(31, mask_reg, test_reg, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } } /* For all operations other than TST perform the action */ if (op != OP_TST) { // Shift mask to correct position if (op != OP_EXTU && op != OP_EXTS && op != OP_FFO) { *ptr++ = lsrv64(mask_reg, mask_reg, off_reg); } switch (op) { case OP_EOR: // Exclusive-or all bits *ptr++ = eor64_reg(data_reg, data_reg, mask_reg, LSL, 0); break; case OP_SET: // Set all bits *ptr++ = orr64_reg(data_reg, data_reg, mask_reg, LSL, 0); break; case OP_CLR: // Clear all bits *ptr++ = bic64_reg(data_reg, data_reg, mask_reg, LSL, 0); break; case OP_INS: // Move inserted value to location *ptr++ = lsrv64(insert_reg, insert_reg, off_reg); // Clear all bits *ptr++ = bic64_reg(data_reg, data_reg, mask_reg, LSL, 0); // Insert data *ptr++ = orr64_reg(data_reg, data_reg, insert_reg, LSL, 0); break; case OP_EXTU: case OP_EXTS: { /* Shift data left as much as possible */ *ptr++ = lslv64(test_reg, data_reg, off_reg); /* If mask is to be updated do it now*/ if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = ands64_reg(31, mask_reg, test_reg, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } /* Compute how far do we shift right: 64 - width */ *ptr++ = neg_reg(width_reg, width_reg, LSL, 0); *ptr++ = add_immed(width_reg, width_reg, 64); if (op == OP_EXTS) { *ptr++ = asrv64(data, test_reg, width_reg); } else { *ptr++ = lsrv64(data, test_reg, width_reg); } } break; case OP_FFO: { *ptr++ = lslv64(test_reg, data_reg, off_reg); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = ands64_reg(31, mask_reg, test_reg, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } // invert mask *ptr++ = mvn64_reg(mask_reg, mask_reg, LSL, 0); *ptr++ = orr64_reg(test_reg, test_reg, mask_reg, LSL, 0); *ptr++ = clz64(test_reg, test_reg); *ptr++ = add_reg(data, test_reg, off_reg_orig, LSL, 0); } break; default: break; } if (op != OP_EXTS && op != OP_EXTU && op != OP_FFO) { /* Store the data back */ /* Width == 1? Fetch byte */ *ptr++ = cmp_immed(width_reg, 1); *ptr++ = b_cc(A64_CC_NE, 4); *ptr++ = ror64(data_reg, data_reg, 64 - 8); *ptr++ = strb_offset(base, data_reg, 0); *ptr++ = b(12); /* Width <= 8? Fetch half word */ *ptr++ = cmp_immed(width_reg, 8); *ptr++ = b_cc(A64_CC_GT, 4); *ptr++ = ror64(data_reg, data_reg, 64 - 16); *ptr++ = strh_offset(base, data_reg, 0); *ptr++ = b(7); /* Width <= 24? Fetch long word */ *ptr++ = cmp_immed(width_reg, 24); *ptr++ = b_cc(A64_CC_GT, 4); *ptr++ = ror64(data_reg, data_reg, 32); *ptr++ = str_offset(base, data_reg, 0); *ptr++ = b(2); *ptr++ = str64_offset(base, data_reg, 0); } } if (base_allocated) { RA_FreeARMRegister(&ptr, base); } RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, off_reg); return ptr; } static uint32_t *EMIT_BFTST_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); uint8_t src = RA_MapM68kRegister(&ptr, opcode & 7); /* Direct offset and width */ if ((opcode2 & 0x0820) == 0) { uint8_t offset = (opcode2 >> 6) & 0x1f; uint8_t width = (opcode2) & 0x1f; /* If offset == 0 and width == 0 the register value from Dn is already extracted bitfield, otherwise extract bitfield */ if (offset != 0 || width != 0) { uint8_t tmp = RA_AllocARMRegister(&ptr); // Get the source, expand to 64 bit to allow rotating *ptr++ = lsl64(tmp, src, 32); *ptr++ = orr64_reg(tmp, tmp, src, LSL, 0); // Get width if (width == 0) width = 32; // Extract bitfield *ptr++ = sbfx64(tmp, tmp, 64 - (offset + width), width); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = cmn_reg(31, tmp, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } RA_FreeARMRegister(&ptr, tmp); } else { /* Emit empty bftst just in case no flags need to be tested */ *ptr++ = cmn_reg(31, src, LSL, 0); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } } } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t offset = (opcode2 >> 6) & 31; // Shift left by offset + 32 bits *ptr++ = lsl64(tmp, src, 32 + offset); *ptr++ = orr64_reg(tmp, tmp, src, LSL, offset); // Build up a mask *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = rorv64(mask_reg, mask_reg, width_reg); // Mask the bitfield, update condition codes *ptr++ = ands64_reg(tmp, tmp, mask_reg, LSL, 0); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, mask_reg); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t off_reg = RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t width = opcode2 & 31; *ptr++ = and_immed(off_reg, off_reg, 5, 0); if (width == 0) width = 32; // Build up a mask *ptr++ = orr64_immed(mask_reg, 31, width, width, 1); // Load data and shift it left according to reminder in offset reg *ptr++ = lsl64(tmp, src, 32); *ptr++ = orr64_reg(tmp, tmp, src, LSL, 0); *ptr++ = lslv64(tmp, tmp, off_reg); // Mask the bitfield, update condition codes *ptr++ = ands64_reg(tmp, tmp, mask_reg, LSL, 0); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, off_reg); } // Do == REG, Dw == REG else if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t off_reg = RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); *ptr++ = and_immed(off_reg, off_reg, 5, 0); // Build up a mask *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = rorv64(mask_reg, mask_reg, width_reg); // Load data and shift it left according to reminder in offset reg *ptr++ = lsl64(tmp, src, 32); *ptr++ = orr64_reg(tmp, tmp, src, LSL, 0); *ptr++ = lslv64(tmp, tmp, off_reg); // Mask the bitfield, update condition codes *ptr++ = ands64_reg(tmp, tmp, mask_reg, LSL, 0); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, off_reg); } ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static uint32_t *EMIT_BFTST(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); uint8_t base = 0xff; // Get EA address into a temporary register ptr = EMIT_LoadFromEffectiveAddress(ptr, 0, &base, opcode & 0x3f, *m68k_ptr, &ext_words, 1, NULL); // Do == Immed, Dw == immed if (!(opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t offset = (opcode2 >> 6) & 31; uint8_t width = opcode2 & 31; ptr = EMIT_BFxxx_II(ptr, base, OP_TST, offset, width, update_mask, -1); } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t offset = (opcode2 >> 6) & 31; uint8_t width_reg = RA_MapM68kRegister(&ptr, opcode2 & 7); ptr = EMIT_BFxxx_IR(ptr, base, OP_TST, offset, width_reg, update_mask, -1); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t off_reg = RA_MapM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width = opcode2 & 31; ptr = EMIT_BFxxx_RI(ptr, base, OP_TST, off_reg, width, update_mask, -1); } // Do == REG, Dw == REG else if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t off_reg = RA_MapM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width_reg = RA_MapM68kRegister(&ptr, opcode2 & 7); ptr = EMIT_BFxxx_RR(ptr, base, OP_TST, off_reg, width_reg, update_mask, -1); } RA_FreeARMRegister(&ptr, base); ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static uint32_t *EMIT_BFEXTU_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); /* IMPORTANT: Although it is not mentioned in 68000 PRM, the bitfield operations on source register are in fact rotation instructions. Bitfield is eventually masked, but the temporary contents of source operand for the Dn addressing mode are actually rotated. */ uint8_t src = RA_MapM68kRegister(&ptr, opcode & 7); /* Direct offset and width */ if ((opcode2 & 0x0820) == 0) { uint8_t dest = RA_MapM68kRegister(&ptr, (opcode2 >> 12) & 7); uint8_t offset = (opcode2 >> 6) & 0x1f; uint8_t width = (opcode2) & 0x1f; RA_SetDirtyM68kRegister(&ptr, (opcode2 >> 12) & 7); // Get width if (width == 0) width = 32; /* If offset == 0 and width == 0 the register value from Dn is already extracted bitfield, otherwise extract bitfield */ if (offset != 0 || width != 32) { uint8_t tmp = RA_AllocARMRegister(&ptr); // Get the source, expand to 64 bit to allow rotating *ptr++ = lsl64(tmp, src, 32); *ptr++ = orr64_reg(tmp, tmp, src, LSL, 0); // Extract bitfield *ptr++ = ubfx64(dest, tmp, 64 - (offset + width), width); RA_FreeARMRegister(&ptr, tmp); } else { *ptr++ = mov_reg(dest, src); } if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = cmn_reg(31, dest, LSL, 32 - width); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t offset = (opcode2 >> 6) & 31; // Shift left by offset + 32 bits *ptr++ = lsl64(tmp, src, 32 + offset); *ptr++ = orr64_reg(tmp, tmp, src, LSL, offset); // Build up a mask *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = rorv64(mask_reg, mask_reg, width_reg); // Mask the bitfield, update condition codes *ptr++ = ands64_reg(tmp, tmp, mask_reg, LSL, 0); // Arithmetic shift right 64-width bits *ptr++ = mov_immed_u16(mask_reg, 64, 0); *ptr++ = sub_reg(width_reg, mask_reg, width_reg, LSL, 0); *ptr++ = lsrv64(tmp, tmp, width_reg); // Move to destination register *ptr++ = mov_reg(dest, tmp); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, mask_reg); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t off_reg = RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t width = opcode2 & 31; *ptr++ = and_immed(off_reg, off_reg, 5, 0); if (width == 0) width = 32; // Build up a mask *ptr++ = orr64_immed(mask_reg, 31, width, width, 1); // Load data and shift it left according to reminder in offset reg *ptr++ = lsl64(tmp, src, 32); *ptr++ = orr64_reg(tmp, tmp, src, LSL, 0); *ptr++ = lslv64(tmp, tmp, off_reg); // Mask the bitfield, update condition codes *ptr++ = ands64_reg(tmp, tmp, mask_reg, LSL, 0); // Arithmetic shift right 64-width bits *ptr++ = lsr64(tmp, tmp, 64 - width); // Move to destination register *ptr++ = mov_reg(dest, tmp); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, off_reg); } // Do == REG, Dw == REG else if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t off_reg = RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); *ptr++ = and_immed(off_reg, off_reg, 5, 0); // Build up a mask *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = rorv64(mask_reg, mask_reg, width_reg); // Load data and shift it left according to reminder in offset reg *ptr++ = lsl64(tmp, src, 32); *ptr++ = orr64_reg(tmp, tmp, src, LSL, 0); *ptr++ = lslv64(tmp, tmp, off_reg); // Mask the bitfield, update condition codes *ptr++ = ands64_reg(tmp, tmp, mask_reg, LSL, 0); // Arithmetic shift right 64-width bits *ptr++ = mov_immed_u16(off_reg, 64, 0); *ptr++ = sub_reg(width_reg, off_reg, width_reg, LSL, 0); *ptr++ = lsrv64(tmp, tmp, width_reg); // Move to destination register *ptr++ = mov_reg(dest, tmp); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, off_reg); } ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static uint32_t *EMIT_BFEXTU(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); uint8_t base = 0xff; // Get EA address into a temporary register ptr = EMIT_LoadFromEffectiveAddress(ptr, 0, &base, opcode & 0x3f, *m68k_ptr, &ext_words, 1, NULL); // Do == Immed, Dw == immed if (!(opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t offset = (opcode2 >> 6) & 31; uint8_t width = opcode2 & 31; ptr = EMIT_BFxxx_II(ptr, base, OP_EXTU, offset, width, update_mask, dest); } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t width_reg = RA_MapM68kRegisterForWrite(&ptr, opcode2 & 7); uint8_t offset = (opcode2 >> 6) & 31; ptr = EMIT_BFxxx_IR(ptr, base, OP_EXTU, offset, width_reg, update_mask, dest); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t off_reg = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 6) & 7); uint8_t width = opcode2 & 31; ptr = EMIT_BFxxx_RI(ptr, base, OP_EXTU, off_reg, width, update_mask, dest); } // Do == REG, Dw == REG if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t off_reg = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 6) & 7); uint8_t width_reg = RA_MapM68kRegisterForWrite(&ptr, opcode2 & 7); ptr = EMIT_BFxxx_RR(ptr, base, OP_EXTU, off_reg, width_reg, update_mask, dest); } RA_FreeARMRegister(&ptr, base); ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static uint32_t *EMIT_BFEXTS_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); uint8_t src = RA_MapM68kRegister(&ptr, opcode & 7); /* Direct offset and width */ if ((opcode2 & 0x0820) == 0) { uint8_t dest = RA_MapM68kRegister(&ptr, (opcode2 >> 12) & 7); uint8_t offset = (opcode2 >> 6) & 0x1f; uint8_t width = (opcode2) & 0x1f; RA_SetDirtyM68kRegister(&ptr, (opcode2 >> 12) & 7); /* If offset == 0 and width == 0 the register value from Dn is already extracted bitfield, otherwise extract bitfield */ if (offset != 0 || width != 0) { uint8_t tmp = RA_AllocARMRegister(&ptr); // Get the source, expand to 64 bit to allow rotating *ptr++ = lsl64(tmp, src, 32); *ptr++ = orr64_reg(tmp, tmp, src, LSL, 0); // Get width if (width == 0) width = 32; // Extract bitfield *ptr++ = sbfx64(tmp, tmp, 64 - (offset + width), width); *ptr++ = mov_reg(dest, tmp); RA_FreeARMRegister(&ptr, tmp); } else { *ptr++ = mov_reg(dest, src); } if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = cmn_reg(31, dest, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t offset = (opcode2 >> 6) & 31; // Shift left by offset + 32 bits *ptr++ = lsl64(tmp, src, 32 + offset); *ptr++ = orr64_reg(tmp, tmp, src, LSL, offset); // Build up a mask *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = rorv64(mask_reg, mask_reg, width_reg); // Mask the bitfield, update condition codes *ptr++ = ands64_reg(tmp, tmp, mask_reg, LSL, 0); // Arithmetic shift right 64-width bits *ptr++ = mov_immed_u16(mask_reg, 64, 0); *ptr++ = sub_reg(width_reg, mask_reg, width_reg, LSL, 0); *ptr++ = asrv64(tmp, tmp, width_reg); // Move to destination register *ptr++ = mov_reg(dest, tmp); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, mask_reg); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t off_reg = RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t width = opcode2 & 31; *ptr++ = and_immed(off_reg, off_reg, 5, 0); if (width == 0) width = 32; // Build up a mask *ptr++ = orr64_immed(mask_reg, 31, width, width, 1); // Load data and shift it left according to reminder in offset reg *ptr++ = lsl64(tmp, src, 32); *ptr++ = orr64_reg(tmp, tmp, src, LSL, 0); *ptr++ = lslv64(tmp, tmp, off_reg); // Mask the bitfield, update condition codes *ptr++ = ands64_reg(tmp, tmp, mask_reg, LSL, 0); // Arithmetic shift right 64-width bits *ptr++ = asr64(tmp, tmp, 64 - width); // Move to destination register *ptr++ = mov_reg(dest, tmp); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, off_reg); } // Do == REG, Dw == REG else if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t off_reg = RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); *ptr++ = and_immed(off_reg, off_reg, 5, 0); // Build up a mask *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = rorv64(mask_reg, mask_reg, width_reg); // Load data and shift it left according to reminder in offset reg *ptr++ = lsl64(tmp, src, 32); *ptr++ = orr64_reg(tmp, tmp, src, LSL, 0); *ptr++ = lslv64(tmp, tmp, off_reg); // Mask the bitfield, update condition codes *ptr++ = ands64_reg(tmp, tmp, mask_reg, LSL, 0); // Arithmetic shift right 64-width bits *ptr++ = mov_immed_u16(off_reg, 64, 0); *ptr++ = sub_reg(width_reg, off_reg, width_reg, LSL, 0); *ptr++ = asrv64(tmp, tmp, width_reg); // Move to destination register *ptr++ = mov_reg(dest, tmp); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, off_reg); } ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static uint32_t *EMIT_BFEXTS(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); uint8_t base = 0xff; // Get EA address into a temporary register ptr = EMIT_LoadFromEffectiveAddress(ptr, 0, &base, opcode & 0x3f, *m68k_ptr, &ext_words, 1, NULL); // Do == Immed, Dw == immed if (!(opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t offset = (opcode2 >> 6) & 31; uint8_t width = opcode2 & 31; ptr = EMIT_BFxxx_II(ptr, base, OP_EXTS, offset, width, update_mask, dest); } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t width_reg = RA_MapM68kRegisterForWrite(&ptr, opcode2 & 7); uint8_t offset = (opcode2 >> 6) & 31; ptr = EMIT_BFxxx_IR(ptr, base, OP_EXTS, offset, width_reg, update_mask, dest); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t off_reg = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 6) & 7); uint8_t width = opcode2 & 31; ptr = EMIT_BFxxx_RI(ptr, base, OP_EXTS, off_reg, width, update_mask, dest); } // Do == REG, Dw == REG if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t off_reg = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 6) & 7); uint8_t width_reg = RA_MapM68kRegisterForWrite(&ptr, opcode2 & 7); ptr = EMIT_BFxxx_RR(ptr, base, OP_EXTS, off_reg, width_reg, update_mask, dest); } RA_FreeARMRegister(&ptr, base); ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static uint32_t *EMIT_BFFFO_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); uint8_t src = RA_MapM68kRegister(&ptr, opcode & 7); /* Direct offset and width */ if ((opcode2 & 0x0820) == 0) { uint8_t offset = (opcode2 >> 6) & 0x1f; uint8_t width = (opcode2) & 0x1f; uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); /* If offset == 0 and width == 0 the register value from Dn is already extracted bitfield, otherwise extract bitfield */ if (offset != 0 || width != 0) { uint8_t tmp = RA_AllocARMRegister(&ptr); // Get the source, expand to 64 bit to allow rotating *ptr++ = lsl64(tmp, src, 32 + offset); *ptr++ = orr64_reg(tmp, tmp, src, LSL, offset); // Get width if (width == 0) width = 32; // Test bitfield and count zeros *ptr++ = ands64_immed(tmp, tmp, width, width, 1); *ptr++ = orr64_immed(tmp, tmp, 64 - width, 0, 1); // Perform BFFFO counting now *ptr++ = clz64(dest, tmp); // Add offset *ptr++ = add_immed(dest, dest, offset); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } RA_FreeARMRegister(&ptr, tmp); } else { *ptr++ = clz(dest, src); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = cmn_reg(31, src, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } } } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t offset = (opcode2 >> 6) & 31; // Shift left by offset + 32 bits *ptr++ = lsl64(tmp, src, 32 + offset); *ptr++ = orr64_reg(tmp, tmp, src, LSL, offset); // Build up a mask *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = rorv64(mask_reg, mask_reg, width_reg); // Mask the bitfield, update condition codes *ptr++ = ands64_reg(tmp, tmp, mask_reg, LSL, 0); // Invert the mask and orr it with tmp reg *ptr++ = orn64_reg(tmp, tmp, mask_reg, LSL, 0); // Perform BFFFO counting now *ptr++ = clz64(dest, tmp); // Add offset *ptr++ = add_immed(dest, dest, offset); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, mask_reg); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t off_reg = RA_AllocARMRegister(&ptr); uint8_t off_orig = ((opcode2 >> 6) & 7) == ((opcode2 >> 12) & 7) ? RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7):RA_MapM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t width = opcode2 & 31; *ptr++ = and_immed(off_reg, off_orig, 5, 0); if (width == 0) width = 32; // Build up a mask *ptr++ = orr64_immed(mask_reg, 31, width, width, 1); // Load data and shift it left according to reminder in offset reg *ptr++ = lsl64(tmp, src, 32); *ptr++ = orr64_reg(tmp, tmp, src, LSL, 0); *ptr++ = lslv64(tmp, tmp, off_reg); // Mask the bitfield, update condition codes *ptr++ = ands64_reg(tmp, tmp, mask_reg, LSL, 0); // Invert the mask and orr it with tmp reg *ptr++ = orn64_reg(tmp, tmp, mask_reg, LSL, 0); // Perform BFFFO counting now *ptr++ = clz64(dest, tmp); // Add offset *ptr++ = add_reg(dest, dest, off_orig, LSL, 0); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, off_reg); RA_FreeARMRegister(&ptr, off_orig); } // Do == REG, Dw == REG else if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t off_reg = RA_AllocARMRegister(&ptr); uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t off_orig = ((opcode2 >> 6) & 7) == ((opcode2 >> 12) & 7) ? RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7):RA_MapM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); *ptr++ = and_immed(off_reg, off_orig, 5, 0); // Build up a mask *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = rorv64(mask_reg, mask_reg, width_reg); // Load data and shift it left according to reminder in offset reg *ptr++ = lsl64(tmp, src, 32); *ptr++ = orr64_reg(tmp, tmp, src, LSL, 0); *ptr++ = lslv64(tmp, tmp, off_reg); // Mask the bitfield, update condition codes *ptr++ = ands64_reg(tmp, tmp, mask_reg, LSL, 0); // Invert the mask and orr it with tmp reg *ptr++ = orn64_reg(tmp, tmp, mask_reg, LSL, 0); // Perform BFFFO counting now *ptr++ = clz64(dest, tmp); // Add offset *ptr++ = add_reg(dest, dest, off_orig, LSL, 0); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, off_reg); RA_FreeARMRegister(&ptr, off_orig); } ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static uint32_t *EMIT_BFFFO(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); uint8_t base = 0xff; // Get EA address into a temporary register ptr = EMIT_LoadFromEffectiveAddress(ptr, 0, &base, opcode & 0x3f, *m68k_ptr, &ext_words, 1, NULL); // Do == Immed, Dw == immed if (!(opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t offset = (opcode2 >> 6) & 31; uint8_t width = opcode2 & 31; ptr = EMIT_BFxxx_II(ptr, base, OP_FFO, offset, width, update_mask, dest); } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t width_reg = RA_MapM68kRegister(&ptr, opcode2 & 7); uint8_t offset = (opcode2 >> 6) & 31; ptr = EMIT_BFxxx_IR(ptr, base, OP_FFO, offset, width_reg, update_mask, dest); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t width = opcode2 & 31; uint8_t off_reg = RA_MapM68kRegister(&ptr, (opcode2 >> 6) & 7); ptr = EMIT_BFxxx_RI(ptr, base, OP_FFO, off_reg, width, update_mask, dest); } // Do == REG, Dw == REG else if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t dest = RA_MapM68kRegisterForWrite(&ptr, (opcode2 >> 12) & 7); uint8_t width_reg = RA_MapM68kRegister(&ptr, opcode2 & 7); uint8_t off_reg = RA_MapM68kRegister(&ptr, (opcode2 >> 6) & 7); ptr = EMIT_BFxxx_RR(ptr, base, OP_FFO, off_reg, width_reg, update_mask, dest); } RA_FreeARMRegister(&ptr, base); ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static uint32_t *EMIT_BFCHG_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); uint8_t src = RA_MapM68kRegister(&ptr, opcode & 7); RA_SetDirtyM68kRegister(&ptr, opcode & 7); /* Direct offset and width */ if ((opcode2 & 0x0820) == 0) { uint8_t offset = (opcode2 >> 6) & 0x1f; uint8_t width = (opcode2) & 0x1f; /* If offset == 0 and width == 0 the register value from Dn is already extracted bitfield, otherwise extract bitfield */ if (offset != 0 || width != 0) { uint8_t tmp = RA_AllocARMRegister(&ptr); // Get width if (width == 0) width = 32; // If condition codes needs to be updated, do it now if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = ror(tmp, src, 31 & (32 - offset)); if (width != 32) *ptr++ = ands_immed(31, tmp, width, width); else *ptr++ = cmn_reg(31, tmp, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } if (width != 32) { *ptr++ = eor_immed(src, src, width, 31 & (width + offset)); } else { *ptr++ = mvn_reg(src, src, LSL, 0); } RA_FreeARMRegister(&ptr, tmp); } else { if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = cmn_reg(31, src, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } *ptr++ = mvn_reg(src, src, LSL, 0); } } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t offset = (opcode2 >> 6) & 31; // Build up a mask *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = rorv(mask_reg, mask_reg, width_reg); if (update_mask) { uint8_t testreg = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); // If offset != 0, shift left by offset bits if (offset != 0) { *ptr++ = ror(testreg, src, 31 & (32 - offset)); // Mask the bitfield, update condition codes *ptr++ = ands_reg(31, testreg, mask_reg, LSL, 0); } else { *ptr++ = ands_reg(31, src, mask_reg, LSL, 0); } ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } // Set the mask bits to zero if (offset != 0) *ptr++ = eor_reg(src, src, mask_reg, ROR, offset); else *ptr++ = eor_reg(src, src, mask_reg, LSL, 0); RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, mask_reg); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t off_reg = RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t width = opcode2 & 31; *ptr++ = and_immed(off_reg, off_reg, 5, 0); if (width == 0) width = 32; // Build mask if (width != 32) { *ptr++ = orr_immed(mask_reg, 31, width, width); } // Update condition codes if necessary if (update_mask) { uint8_t testreg = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = mov_immed_u16(testreg, 32, 0); *ptr++ = sub_reg(testreg, testreg, off_reg, LSL, 0); *ptr++ = rorv(testreg, src, testreg); if (width != 32) { *ptr++ = ands_immed(31, testreg, width, width); } else { *ptr++ = cmn_reg(31, testreg, LSL, 0); } ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } if (width != 32) { // Shift mask *ptr++ = rorv(mask_reg, mask_reg, off_reg); // Clear bitfield *ptr++ = eor_reg(src, src, mask_reg, LSL, 0); } else { *ptr++ = mvn_reg(src, src, LSL, 0); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, off_reg); } // Do == REG, Dw == REG else if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t off_reg = RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); *ptr++ = and_immed(off_reg, off_reg, 5, 0); // Build up a mask *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = rorv(mask_reg, mask_reg, width_reg); // Update condition codes if necessary if (update_mask) { uint8_t testreg = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = mov_immed_u16(testreg, 32, 0); *ptr++ = sub_reg(testreg, testreg, off_reg, LSL, 0); *ptr++ = rorv(testreg, src, testreg); *ptr++ = ands_reg(31, testreg, mask_reg, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } // Rotate mask to correct position *ptr++ = rorv(mask_reg, mask_reg, off_reg); // Set bits in field to zeros *ptr++ = eor_reg(src, src, mask_reg, LSL, 0); RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, off_reg); } ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static uint32_t *EMIT_BFCHG(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); uint8_t base = 0xff; // Get EA address into a temporary register ptr = EMIT_LoadFromEffectiveAddress(ptr, 0, &base, opcode & 0x3f, *m68k_ptr, &ext_words, 1, NULL); // Do == Immed, Dw == immed if (!(opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t offset = (opcode2 >> 6) & 31; uint8_t width = opcode2 & 31; ptr = EMIT_BFxxx_II(ptr, base, OP_EOR, offset, width, update_mask, -1); } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t offset = (opcode2 >> 6) & 31; uint8_t width_reg = RA_MapM68kRegister(&ptr, opcode2 & 7); ptr = EMIT_BFxxx_IR(ptr, base, OP_EOR, offset, width_reg, update_mask, -1); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t off_reg = RA_MapM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width = opcode2 & 31; ptr = EMIT_BFxxx_RI(ptr, base, OP_EOR, off_reg, width, update_mask, -1); } // Do == REG, Dw == REG else if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t off_reg = RA_MapM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width_reg = RA_MapM68kRegister(&ptr, opcode2 & 7); ptr = EMIT_BFxxx_RR(ptr, base, OP_EOR, off_reg, width_reg, update_mask, -1); } RA_FreeARMRegister(&ptr, base); ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static uint32_t *EMIT_BFSET_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); uint8_t src = RA_MapM68kRegister(&ptr, opcode & 7); RA_SetDirtyM68kRegister(&ptr, opcode & 7); /* Direct offset and width */ if ((opcode2 & 0x0820) == 0) { uint8_t offset = (opcode2 >> 6) & 0x1f; uint8_t width = (opcode2) & 0x1f; /* If offset == 0 and width == 0 the register value from Dn is already extracted bitfield, otherwise extract bitfield */ if (offset != 0 || width != 0) { uint8_t tmp = RA_AllocARMRegister(&ptr); // Get width if (width == 0) width = 32; // If condition codes needs to be updated, do it now if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = ror(tmp, src, 31 & (32 - offset)); if (width != 32) *ptr++ = ands_immed(31, tmp, width, width); else *ptr++ = cmn_reg(31, tmp, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } if (width != 32) { *ptr++ = orr_immed(src, src, width, 31 & (width + offset)); } else { *ptr++ = movn_immed_u16(src, 0, 0); } RA_FreeARMRegister(&ptr, tmp); } else { if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = cmn_reg(31, src, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } *ptr++ = movn_immed_u16(src, 0, 0); } } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t offset = (opcode2 >> 6) & 31; // Build up a mask *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = rorv(mask_reg, mask_reg, width_reg); if (update_mask) { uint8_t testreg = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); // If offset != 0, shift left by offset bits if (offset != 0) { *ptr++ = ror(testreg, src, 31 & (32 - offset)); // Mask the bitfield, update condition codes *ptr++ = ands_reg(31, testreg, mask_reg, LSL, 0); } else { *ptr++ = ands_reg(31, src, mask_reg, LSL, 0); } ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } // Set the mask bits to one if (offset != 0) *ptr++ = orr_reg(src, src, mask_reg, ROR, offset); else *ptr++ = orr_reg(src, src, mask_reg, LSL, 0); RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, mask_reg); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t off_reg = RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t width = opcode2 & 31; *ptr++ = and_immed(off_reg, off_reg, 5, 0); if (width == 0) width = 32; // Build mask if (width != 32) { *ptr++ = orr_immed(mask_reg, 31, width, width); } // Update condition codes if necessary if (update_mask) { uint8_t testreg = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = mov_immed_u16(testreg, 32, 0); *ptr++ = sub_reg(testreg, testreg, off_reg, LSL, 0); *ptr++ = rorv(testreg, src, testreg); if (width != 32) { *ptr++ = ands_immed(31, testreg, width, width); } else { *ptr++ = cmn_reg(31, testreg, LSL, 0); } ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } if (width != 32) { // Shift mask *ptr++ = rorv(mask_reg, mask_reg, off_reg); // Or with source *ptr++ = orr_reg(src, src, mask_reg, LSL, 0); } else { *ptr++ = movn_immed_u16(src, 0, 0); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, off_reg); } // Do == REG, Dw == REG else if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t off_reg = RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); *ptr++ = and_immed(off_reg, off_reg, 5, 0); // Build up a mask *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = rorv(mask_reg, mask_reg, width_reg); // Update condition codes if necessary if (update_mask) { uint8_t testreg = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = mov_immed_u16(testreg, 32, 0); *ptr++ = sub_reg(testreg, testreg, off_reg, LSL, 0); *ptr++ = rorv(testreg, src, testreg); *ptr++ = ands_reg(31, testreg, mask_reg, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } // Rotate mask to correct position *ptr++ = rorv(mask_reg, mask_reg, off_reg); // Set bits in field to ones *ptr++ = orr_reg(src, src, mask_reg, LSL, 0); RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, off_reg); } ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static uint32_t *EMIT_BFSET(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); uint8_t base = 0xff; // Get EA address into a temporary register ptr = EMIT_LoadFromEffectiveAddress(ptr, 0, &base, opcode & 0x3f, *m68k_ptr, &ext_words, 1, NULL); // Do == Immed, Dw == immed if (!(opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t offset = (opcode2 >> 6) & 31; uint8_t width = opcode2 & 31; ptr = EMIT_BFxxx_II(ptr, base, OP_SET, offset, width, update_mask, -1); } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t offset = (opcode2 >> 6) & 31; uint8_t width_reg = RA_MapM68kRegister(&ptr, opcode2 & 7); ptr = EMIT_BFxxx_IR(ptr, base, OP_SET, offset, width_reg, update_mask, -1); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t off_reg = RA_MapM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width = opcode2 & 31; ptr = EMIT_BFxxx_RI(ptr, base, OP_SET, off_reg, width, update_mask, -1); } // Do == REG, Dw == REG else if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t off_reg = RA_MapM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width_reg = RA_MapM68kRegister(&ptr, opcode2 & 7); ptr = EMIT_BFxxx_RR(ptr, base, OP_SET, off_reg, width_reg, update_mask, -1); } RA_FreeARMRegister(&ptr, base); ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static uint32_t *EMIT_BFCLR_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); uint8_t src = RA_MapM68kRegister(&ptr, opcode & 7); RA_SetDirtyM68kRegister(&ptr, opcode & 7); /* Direct offset and width */ if ((opcode2 & 0x0820) == 0) { uint8_t offset = (opcode2 >> 6) & 0x1f; uint8_t width = (opcode2) & 0x1f; /* If offset == 0 and width == 0 the register value from Dn is already extracted bitfield, otherwise extract bitfield */ if (offset != 0 || width != 0) { uint8_t tmp = RA_AllocARMRegister(&ptr); // Get width if (width == 0) width = 32; // If condition codes needs to be updated, do it now if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = ror(tmp, src, 31 & (32 - offset)); if (width != 32) *ptr++ = ands_immed(31, tmp, width, width); else *ptr++ = cmn_reg(31, tmp, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } if (width != 32) { *ptr++ = bic_immed(src, src, width, 31 & (width + offset)); } else { *ptr++ = mov_immed_u16(src, 0, 0); } RA_FreeARMRegister(&ptr, tmp); } else { if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = cmn_reg(31, src, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } *ptr++ = mov_immed_u16(src, 0, 0); } } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t offset = (opcode2 >> 6) & 31; // Build up a mask *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = rorv(mask_reg, mask_reg, width_reg); if (update_mask) { uint8_t testreg = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); // If offset != 0, shift left by offset bits if (offset != 0) { *ptr++ = ror(testreg, src, 31 & (32 - offset)); // Mask the bitfield, update condition codes *ptr++ = ands_reg(31, testreg, mask_reg, LSL, 0); } else { *ptr++ = ands_reg(31, src, mask_reg, LSL, 0); } ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } // Set the mask bits to zero if (offset != 0) *ptr++ = bic_reg(src, src, mask_reg, ROR, offset); else *ptr++ = bic_reg(src, src, mask_reg, LSL, 0); RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, mask_reg); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t off_reg = RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t width = opcode2 & 31; *ptr++ = and_immed(off_reg, off_reg, 5, 0); if (width == 0) width = 32; // Build mask if (width != 32) { *ptr++ = orr_immed(mask_reg, 31, width, width); } // Update condition codes if necessary if (update_mask) { uint8_t testreg = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = mov_immed_u16(testreg, 32, 0); *ptr++ = sub_reg(testreg, testreg, off_reg, LSL, 0); *ptr++ = rorv(testreg, src, testreg); if (width != 32) { *ptr++ = ands_immed(31, testreg, width, width); } else { *ptr++ = cmn_reg(31, testreg, LSL, 0); } ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } if (width != 32) { // Shift mask *ptr++ = rorv(mask_reg, mask_reg, off_reg); // Clear bitfield *ptr++ = bic_reg(src, src, mask_reg, LSL, 0); } else { *ptr++ = mov_immed_u16(src, 0, 0); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, off_reg); } // Do == REG, Dw == REG else if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t off_reg = RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); *ptr++ = and_immed(off_reg, off_reg, 5, 0); // Build up a mask *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = rorv(mask_reg, mask_reg, width_reg); // Update condition codes if necessary if (update_mask) { uint8_t testreg = RA_AllocARMRegister(&ptr); uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = mov_immed_u16(testreg, 32, 0); *ptr++ = sub_reg(testreg, testreg, off_reg, LSL, 0); *ptr++ = rorv(testreg, src, testreg); *ptr++ = ands_reg(31, testreg, mask_reg, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } // Rotate mask to correct position *ptr++ = rorv(mask_reg, mask_reg, off_reg); // Set bits in field to zeros *ptr++ = bic_reg(src, src, mask_reg, LSL, 0); RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, off_reg); } ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static uint32_t *EMIT_BFCLR(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); uint8_t base = 0xff; // Get EA address into a temporary register ptr = EMIT_LoadFromEffectiveAddress(ptr, 0, &base, opcode & 0x3f, *m68k_ptr, &ext_words, 1, NULL); // Do == Immed, Dw == immed if (!(opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t offset = (opcode2 >> 6) & 31; uint8_t width = opcode2 & 31; ptr = EMIT_BFxxx_II(ptr, base, OP_CLR, offset, width, update_mask, -1); } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t offset = (opcode2 >> 6) & 31; uint8_t width_reg = RA_MapM68kRegister(&ptr, opcode2 & 7); ptr = EMIT_BFxxx_IR(ptr, base, OP_CLR, offset, width_reg, update_mask, -1); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t off_reg = RA_MapM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width = opcode2 & 31; ptr = EMIT_BFxxx_RI(ptr, base, OP_CLR, off_reg, width, update_mask, -1); } // Do == REG, Dw == REG else if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t off_reg = RA_MapM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width_reg = RA_MapM68kRegister(&ptr, opcode2 & 7); ptr = EMIT_BFxxx_RR(ptr, base, OP_CLR, off_reg, width_reg, update_mask, -1); } RA_FreeARMRegister(&ptr, base); ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static uint32_t *EMIT_BFINS_reg(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); uint8_t dest = RA_MapM68kRegister(&ptr, opcode & 7); uint8_t src = RA_MapM68kRegister(&ptr, (opcode2 >> 12) & 7); RA_SetDirtyM68kRegister(&ptr, opcode & 7); /* Direct offset and width */ if ((opcode2 & 0x0820) == 0) { uint8_t offset = (opcode2 >> 6) & 0x1f; uint8_t width = (opcode2) & 0x1f; /* If offset == 0 and width == 0 the register value from Dn is already extracted bitfield, otherwise extract bitfield */ if (offset != 0 || width != 0) { uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t masked_src = RA_AllocARMRegister(&ptr); // Get width if (width == 0) width = 32; // Get source bitfield, clip to requested size if (width != 32) { *ptr++ = ands_immed(masked_src, src, width, 0); } else { *ptr++ = mov_reg(masked_src, src); } // Rotate source bitfield so that the MSB is at offset if (((offset + width) & 31) != 0) *ptr++ = ror(masked_src, masked_src, 31 & (offset + width)); // If condition codes needs to be updated, do it now if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); uint8_t testreg = RA_AllocARMRegister(&ptr); if (offset != 0) { *ptr++ = ror(testreg, masked_src, 31 & (32 - offset)); *ptr++ = cmn_reg(31, testreg, LSL, 0); } else { *ptr++ = cmn_reg(31, masked_src, LSL, 0); } ptr = EMIT_GetNZ00(ptr, cc, &update_mask); RA_FreeARMRegister(&ptr, testreg); } // Clear destination if (width != 32) { *ptr++ = bic_immed(dest, dest, width, 31 & (width + offset)); // Insert bitfield *ptr++ = orr_reg(dest, dest, masked_src, LSL, 0); } else { *ptr++ = mov_reg(dest, masked_src); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, masked_src); } else { if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = cmn_reg(31, src, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } *ptr++ = mov_reg(dest, src); } } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t masked_src = RA_AllocARMRegister(&ptr); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t offset = (opcode2 >> 6) & 31; // Build up a mask and mask out source bitfield *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = ands_reg(masked_src, src, mask_reg, LSL, 0); *ptr++ = rorv(mask_reg, mask_reg, width_reg); *ptr++ = rorv(masked_src, masked_src, width_reg); if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = cmn_reg(31, masked_src, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } // Set the mask bits to zero and insert sorce if (offset != 0) { *ptr++ = bic_reg(dest, dest, mask_reg, ROR, offset); *ptr++ = orr_reg(dest, dest, masked_src, ROR, offset); } else { *ptr++ = bic_reg(dest, dest, mask_reg, LSL, 0); *ptr++ = orr_reg(dest, dest, masked_src, LSL, 0); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, masked_src); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t off_reg = RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); uint8_t width = opcode2 & 31; uint8_t masked_src = RA_AllocARMRegister(&ptr); *ptr++ = and_immed(off_reg, off_reg, 5, 0); if (width == 0) width = 32; // Get source bitfield, clip to requested size if (width != 32) { *ptr++ = ands_immed(masked_src, src, width, 0); *ptr++ = ror(masked_src, masked_src, width); } else { *ptr++ = mov_reg(masked_src, src); } // Build mask if (width != 32) { *ptr++ = orr_immed(mask_reg, 31, width, width); } // Update condition codes if necessary if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = cmn_reg(31, masked_src, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } if (width != 32) { // Shift mask *ptr++ = rorv(mask_reg, mask_reg, off_reg); // Shift source *ptr++ = rorv(masked_src, masked_src, off_reg); // Clear bitfield *ptr++ = bic_reg(dest, dest, mask_reg, LSL, 0); // Insert *ptr++ = orr_reg(dest, dest, masked_src, LSL, 0); } else { // Width == 32. Just rotate the source into destination *ptr++ = rorv(dest, masked_src, off_reg); } RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, off_reg); RA_FreeARMRegister(&ptr, masked_src); } // Do == REG, Dw == REG else if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t off_reg = RA_CopyFromM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width_reg = RA_CopyFromM68kRegister(&ptr, opcode2 & 7); uint8_t mask_reg = RA_AllocARMRegister(&ptr); uint8_t masked_src = RA_AllocARMRegister(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); *ptr++ = and_immed(off_reg, off_reg, 5, 0); // Build up a mask and mask out source bitfield *ptr++ = and_immed(width_reg, width_reg, 5, 0); *ptr++ = cbnz(width_reg, 2); *ptr++ = mov_immed_u16(width_reg, 32, 0); *ptr++ = mov_immed_u16(mask_reg, 1, 0); *ptr++ = lslv64(mask_reg, mask_reg, width_reg); *ptr++ = sub64_immed(mask_reg, mask_reg, 1); *ptr++ = ands_reg(masked_src, src, mask_reg, LSL, 0); *ptr++ = rorv(mask_reg, mask_reg, width_reg); *ptr++ = rorv(masked_src, masked_src, width_reg); // Update condition codes if necessary if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); *ptr++ = cmn_reg(31, masked_src, LSL, 0); ptr = EMIT_GetNZ00(ptr, cc, &update_mask); } // Rotate mask to correct position *ptr++ = rorv(mask_reg, mask_reg, off_reg); // Rotate source to correct position *ptr++ = rorv(masked_src, masked_src, off_reg); // Set bits in field to zeros *ptr++ = bic_reg(dest, dest, mask_reg, LSL, 0); // Insert field *ptr++ = orr_reg(dest, dest, masked_src, LSL, 0); RA_FreeARMRegister(&ptr, tmp); RA_FreeARMRegister(&ptr, mask_reg); RA_FreeARMRegister(&ptr, width_reg); RA_FreeARMRegister(&ptr, off_reg); RA_FreeARMRegister(&ptr, masked_src); } ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static uint32_t *EMIT_BFINS(uint32_t *ptr, uint16_t opcode, uint16_t **m68k_ptr) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t ext_words = 1; uint16_t opcode2 = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); uint8_t base = 0xff; uint8_t src = RA_MapM68kRegister(&ptr, (opcode2 >> 12) & 7); // Get EA address into a temporary register ptr = EMIT_LoadFromEffectiveAddress(ptr, 0, &base, opcode & 0x3f, *m68k_ptr, &ext_words, 1, NULL); // Do == Immed, Dw == immed if (!(opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t offset = (opcode2 >> 6) & 31; uint8_t width = opcode2 & 31; ptr = EMIT_BFxxx_II(ptr, base, OP_INS, offset, width, update_mask, src); } // Do == immed, Dw == reg else if (!(opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t offset = (opcode2 >> 6) & 31; uint8_t width_reg = RA_MapM68kRegister(&ptr, opcode2 & 7); ptr = EMIT_BFxxx_IR(ptr, base, OP_INS, offset, width_reg, update_mask, src); } // Do == REG, Dw == immed else if ((opcode2 & (1 << 11)) && !(opcode2 & (1 << 5))) { uint8_t off_reg = RA_MapM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width = opcode2 & 31; ptr = EMIT_BFxxx_RI(ptr, base, OP_INS, off_reg, width, update_mask, src); } // Do == REG, Dw == REG else if ((opcode2 & (1 << 11)) && (opcode2 & (1 << 5))) { uint8_t off_reg = RA_MapM68kRegister(&ptr, (opcode2 >> 6) & 7); uint8_t width_reg = RA_MapM68kRegister(&ptr, opcode2 & 7); ptr = EMIT_BFxxx_RR(ptr, base, OP_INS, off_reg, width_reg, update_mask, src); } RA_FreeARMRegister(&ptr, base); ptr = EMIT_AdvancePC(ptr, 2 * (ext_words + 1)); (*m68k_ptr) += ext_words; return ptr; } static struct OpcodeDef InsnTable[4096] = { [00000 ... 00007] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 8, Byte, Dn [00010 ... 00017] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [00020 ... 00027] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [00030 ... 00037] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 1 }, [00040 ... 00047] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D0 [00050 ... 00057] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [00060 ... 00067] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [00070 ... 00077] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [00100 ... 00107] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 8, Word, Dn [00110 ... 00117] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [00120 ... 00127] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [00130 ... 00137] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 2 }, [00140 ... 00147] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D0 [00150 ... 00157] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [00160 ... 00167] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [00170 ... 00177] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [00200 ... 00207] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 8, Long, Dn [00210 ... 00217] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [00220 ... 00227] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [00230 ... 00237] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 4 }, [00240 ... 00247] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D0 [00250 ... 00257] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [00260 ... 00267] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [00270 ... 00277] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [01000 ... 01007] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 1, Byte, Dn [01010 ... 01017] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [01020 ... 01027] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [01030 ... 01037] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 1 }, [01040 ... 01047] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D1 [01050 ... 01057] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [01060 ... 01067] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [01070 ... 01077] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [01100 ... 01107] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 1, Word, Dn [01110 ... 01117] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [01120 ... 01127] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [01130 ... 01137] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 2 }, [01140 ... 01147] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D1 [01150 ... 01157] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [01160 ... 01167] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [01170 ... 01177] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [01200 ... 01207] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 1, Long, Dn [01210 ... 01217] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [01220 ... 01227] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [01230 ... 01237] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 4 }, [01240 ... 01247] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D1 [01250 ... 01257] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [01260 ... 01267] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [01270 ... 01277] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [02000 ... 02007] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 2, Byte, Dn [02010 ... 02017] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [02020 ... 02027] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [02030 ... 02037] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 1 }, [02040 ... 02047] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D2 [02050 ... 02057] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [02060 ... 02067] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [02070 ... 02077] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [02100 ... 02107] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 2, Word, Dn [02110 ... 02117] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [02120 ... 02127] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [02130 ... 02137] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 2 }, [02140 ... 02147] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D2 [02150 ... 02157] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [02160 ... 02167] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [02170 ... 02177] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [02200 ... 02207] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 2, Long, Dn [02210 ... 02217] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [02220 ... 02227] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [02230 ... 02237] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 4 }, [02240 ... 02247] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D2 [02250 ... 02257] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [02260 ... 02267] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [02270 ... 02277] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [03000 ... 03007] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 3, Byte, Dn [03010 ... 03017] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [03020 ... 03027] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [03030 ... 03037] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 1 }, [03040 ... 03047] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D3 [03050 ... 03057] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [03060 ... 03067] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [03070 ... 03077] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [03100 ... 03107] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 3, Word, Dn [03110 ... 03117] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [03120 ... 03127] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [03130 ... 03137] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 2 }, [03140 ... 03147] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D3 [03150 ... 03157] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [03160 ... 03167] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [03170 ... 03177] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [03200 ... 03207] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 3, Long, Dn [03210 ... 03217] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [03220 ... 03227] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [03230 ... 03237] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 4 }, [03240 ... 03247] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D3 [03250 ... 03257] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [03260 ... 03267] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [03270 ... 03277] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [04000 ... 04007] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 4, Byte, Dn [04010 ... 04017] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [04020 ... 04027] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [04030 ... 04037] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 1 }, [04040 ... 04047] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D4 [04050 ... 04057] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [04060 ... 04067] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [04070 ... 04077] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [04100 ... 04107] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 4, Word, Dn [04110 ... 04117] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [04120 ... 04127] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [04130 ... 04137] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 2 }, [04140 ... 04147] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D4 [04150 ... 04157] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [04160 ... 04167] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [04170 ... 04177] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [04200 ... 04207] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 4, Long, Dn [04210 ... 04217] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [04220 ... 04227] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [04230 ... 04237] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 4 }, [04240 ... 04247] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D4 [04250 ... 04257] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [04260 ... 04267] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [04270 ... 04277] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [05000 ... 05007] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 5, Byte, Dn [05010 ... 05017] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [05020 ... 05027] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [05030 ... 05037] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 1 }, [05040 ... 05047] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D5 [05050 ... 05057] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [05060 ... 05067] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [05070 ... 05077] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [05100 ... 05107] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 5, Word, Dn [05110 ... 05117] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [05120 ... 05127] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [05130 ... 05137] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 2 }, [05140 ... 05147] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D5 [05150 ... 05157] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [05160 ... 05167] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [05170 ... 05177] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [05200 ... 05207] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 5, Long, Dn [05210 ... 05217] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [05220 ... 05227] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [05230 ... 05237] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 4 }, [05240 ... 05247] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D5 [05250 ... 05257] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [05260 ... 05267] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [05270 ... 05277] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [06000 ... 06007] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 6, Byte, Dn [06010 ... 06017] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [06020 ... 06027] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [06030 ... 06037] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 1 }, [06040 ... 06047] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D6 [06050 ... 06057] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [06060 ... 06067] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [06070 ... 06077] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [06100 ... 06107] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 6, Word, Dn [06110 ... 06117] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [06120 ... 06127] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [06130 ... 06137] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 2 }, [06140 ... 06147] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D6 [06150 ... 06157] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [06160 ... 06167] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [06170 ... 06177] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [06200 ... 06207] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 6, Long, Dn [06210 ... 06217] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [06220 ... 06227] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [06230 ... 06237] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 4 }, [06240 ... 06247] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D6 [06250 ... 06257] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [06260 ... 06267] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [06270 ... 06277] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [07000 ... 07007] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 7, Byte, Dn [07010 ... 07017] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [07020 ... 07027] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [07030 ... 07037] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 1 }, [07040 ... 07047] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D7 [07050 ... 07057] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [07060 ... 07067] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [07070 ... 07077] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [07100 ... 07107] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 7, Word, Dn [07110 ... 07117] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [07120 ... 07127] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [07130 ... 07137] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 2 }, [07140 ... 07147] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D7 [07150 ... 07157] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [07160 ... 07167] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR , 1, 0, 2}, [07170 ... 07177] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [07200 ... 07207] = { { EMIT_ASR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 7, Long, Dn [07210 ... 07217] = { { EMIT_LSR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [07220 ... 07227] = { { EMIT_ROXR }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [07230 ... 07237] = { { EMIT_ROR }, NULL, 0, SR_NZVC, 1, 0, 4 }, [07240 ... 07247] = { { EMIT_ASR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D7 [07250 ... 07257] = { { EMIT_LSR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [07260 ... 07267] = { { EMIT_ROXR_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [07270 ... 07277] = { { EMIT_ROR_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [00320 ... 00371] = { { EMIT_ASR_mem }, NULL, SR_X, SR_CCR, 1, 1, 2 }, //Shift #1, (memory only) [01320 ... 01371] = { { EMIT_LSR_mem }, NULL, SR_X, SR_CCR, 1, 1, 2 }, [02320 ... 02371] = { { EMIT_ROXR_mem }, NULL, SR_X, SR_CCR, 1, 1, 2 }, [03320 ... 03371] = { { EMIT_ROR_mem }, NULL, 0, SR_NZVC, 1, 1, 2 }, [00400 ... 00407] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 8, Byte, Dn [00410 ... 00417] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [00420 ... 00427] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [00430 ... 00437] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 1 }, [00440 ... 00447] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D0 [00450 ... 00457] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [00460 ... 00467] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [00470 ... 00477] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [00500 ... 00507] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 8, Word, Dn [00510 ... 00517] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [00520 ... 00527] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [00530 ... 00537] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 2 }, [00540 ... 00547] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D0 [00550 ... 00557] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [00560 ... 00567] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [00570 ... 00577] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [00600 ... 00607] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 8, Long, Dn [00610 ... 00617] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [00620 ... 00627] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [00630 ... 00637] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 4 }, [00640 ... 00647] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D0 [00650 ... 00657] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [00660 ... 00667] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [00670 ... 00677] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [01400 ... 01407] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 1, Byte, Dn [01410 ... 01417] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [01420 ... 01427] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [01430 ... 01437] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 1 }, [01440 ... 01447] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D1 [01450 ... 01457] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [01460 ... 01467] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [01470 ... 01477] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [01500 ... 01507] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 1, Word, Dn [01510 ... 01517] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [01520 ... 01527] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [01530 ... 01537] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 2 }, [01540 ... 01547] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D1 [01550 ... 01557] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [01560 ... 01567] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [01570 ... 01577] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [01600 ... 01607] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 1, Long, Dn [01610 ... 01617] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [01620 ... 01627] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [01630 ... 01637] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 4 }, [01640 ... 01647] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D1 [01650 ... 01657] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [01660 ... 01667] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [01670 ... 01677] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [02400 ... 02407] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 2, Byte, Dn [02410 ... 02417] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [02420 ... 02427] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [02430 ... 02437] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 1 }, [02440 ... 02447] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D2 [02450 ... 02457] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [02460 ... 02467] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [02470 ... 02477] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [02500 ... 02507] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 2, Word, Dn [02510 ... 02517] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [02520 ... 02527] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [02530 ... 02537] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 2 }, [02540 ... 02547] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D2 [02550 ... 02557] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [02560 ... 02567] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [02570 ... 02577] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [02600 ... 02607] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 2, Long, Dn [02610 ... 02617] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [02620 ... 02627] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [02630 ... 02637] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 4 }, [02640 ... 02647] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D2 [02650 ... 02657] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [02660 ... 02667] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [02670 ... 02677] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [03400 ... 03407] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 3, Byte, Dn [03410 ... 03417] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [03420 ... 03427] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [03430 ... 03437] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 1 }, [03440 ... 03447] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D3 [03450 ... 03457] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [03460 ... 03467] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [03470 ... 03477] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [03500 ... 03507] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 3, Word, Dn [03510 ... 03517] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [03520 ... 03527] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [03530 ... 03537] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 2 }, [03540 ... 03547] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D3 [03550 ... 03557] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [03560 ... 03567] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [03570 ... 03577] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [03600 ... 03607] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 3, Long, Dn [03610 ... 03617] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [03620 ... 03627] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [03630 ... 03637] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 4 }, [03640 ... 03647] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D3 [03650 ... 03657] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [03660 ... 03667] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [03670 ... 03677] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [04400 ... 04407] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 4, Byte, Dn [04410 ... 04417] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [04420 ... 04427] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [04430 ... 04437] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 1 }, [04440 ... 04447] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D4 [04450 ... 04457] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [04460 ... 04467] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [04470 ... 04477] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [04500 ... 04507] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 4, Word, Dn [04510 ... 04517] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [04520 ... 04527] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [04530 ... 04537] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 2 }, [04540 ... 04547] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D4 [04550 ... 04557] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [04560 ... 04567] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [04570 ... 04577] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [04600 ... 04607] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 4, Long, Dn [04610 ... 04617] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [04620 ... 04627] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [04630 ... 04637] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 4 }, [04640 ... 04647] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D4 [04650 ... 04657] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [04660 ... 04667] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [04670 ... 04677] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [05400 ... 05407] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 5, Byte, Dn [05410 ... 05417] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [05420 ... 05427] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [05430 ... 05437] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 1 }, [05440 ... 05447] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D5 [05450 ... 05457] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [05460 ... 05467] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [05470 ... 05477] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [05500 ... 05507] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 5, Word, Dn [05510 ... 05517] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [05520 ... 05527] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [05530 ... 05537] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 2 }, [05540 ... 05547] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D5 [05550 ... 05557] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [05560 ... 05567] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [05570 ... 05577] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [05600 ... 05607] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 5, Long, Dn [05610 ... 05617] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [05620 ... 05627] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [05630 ... 05637] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 4 }, [05640 ... 05647] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D5 [05650 ... 05657] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [05660 ... 05667] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [05670 ... 05677] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [06400 ... 06407] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 6, Byte, Dn [06410 ... 06417] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [06420 ... 06427] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [06430 ... 06437] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 1 }, [06440 ... 06447] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D6 [06450 ... 06457] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [06460 ... 06467] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [06470 ... 06477] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [06500 ... 06507] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 6, Word, Dn [06510 ... 06517] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [06520 ... 06527] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [06530 ... 06537] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 2 }, [06540 ... 06547] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D6 [06550 ... 06557] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [06560 ... 06567] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [06570 ... 06577] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [06600 ... 06607] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 6, Long, Dn [06610 ... 06617] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [06620 ... 06627] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [06630 ... 06637] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 4 }, [06640 ... 06647] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D6 [06650 ... 06657] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [06660 ... 06667] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [06670 ... 06677] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [07400 ... 07407] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //immediate 7, Byte, Dn [07410 ... 07417] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [07420 ... 07427] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [07430 ... 07437] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 1 }, [07440 ... 07447] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, //D7 [07450 ... 07457] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [07460 ... 07467] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 1 }, [07470 ... 07477] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 1 }, [07500 ... 07507] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //immediate 7, Word, Dn [07510 ... 07517] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [07520 ... 07527] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [07530 ... 07537] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 2 }, [07540 ... 07547] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, //D7 [07550 ... 07557] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [07560 ... 07567] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 2 }, [07570 ... 07577] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 2 }, [07600 ... 07607] = { { EMIT_ASL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //immediate 7, Long, Dn [07610 ... 07617] = { { EMIT_LSL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [07620 ... 07627] = { { EMIT_ROXL }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [07630 ... 07637] = { { EMIT_ROL }, NULL, 0, SR_NZVC, 1, 0, 4 }, [07640 ... 07647] = { { EMIT_ASL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, //D7 [07650 ... 07657] = { { EMIT_LSL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [07660 ... 07667] = { { EMIT_ROXL_reg }, NULL, SR_X, SR_CCR, 1, 0, 4 }, [07670 ... 07677] = { { EMIT_ROL_reg }, NULL, 0, SR_NZVC, 1, 0, 4 }, [00720 ... 00771] = { { EMIT_ASL_mem }, NULL, SR_X, SR_CCR, 1, 1, 2 }, //Shift #1, (memory only) [01720 ... 01771] = { { EMIT_LSL_mem }, NULL, SR_X, SR_CCR, 1, 1, 2 }, [02720 ... 02771] = { { EMIT_ROXL_mem }, NULL, SR_X, SR_CCR, 1, 1, 2 }, [03720 ... 03771] = { { EMIT_ROL_mem }, NULL, 0, SR_NZVC, 1, 1, 2 }, [04300 ... 04307] = { { EMIT_BFTST_reg }, NULL, 0, SR_NZVC, 2, 0, 0 }, [04320 ... 04327] = { { EMIT_BFTST }, NULL, 0, SR_NZVC, 2, 0, 0 }, [04350 ... 04373] = { { EMIT_BFTST }, NULL, 0, SR_NZVC, 2, 1, 0 }, [05300 ... 05307] = { { EMIT_BFCHG_reg }, NULL, 0, SR_NZVC, 2, 0, 0 }, [05320 ... 05327] = { { EMIT_BFCHG }, NULL, 0, SR_NZVC, 2, 0, 0 }, [05350 ... 05371] = { { EMIT_BFCHG }, NULL, 0, SR_NZVC, 2, 1, 0 }, [06300 ... 06307] = { { EMIT_BFCLR_reg }, NULL, 0, SR_NZVC, 2, 0, 0 }, [06320 ... 06327] = { { EMIT_BFCLR }, NULL, 0, SR_NZVC, 2, 0, 0 }, [06350 ... 06371] = { { EMIT_BFCLR }, NULL, 0, SR_NZVC, 2, 1, 0 }, [07300 ... 07307] = { { EMIT_BFSET_reg }, NULL, 0, SR_NZVC, 2, 0, 0 }, [07320 ... 07327] = { { EMIT_BFSET }, NULL, 0, SR_NZVC, 2, 0, 0 }, [07350 ... 07371] = { { EMIT_BFSET }, NULL, 0, SR_NZVC, 2, 1, 0 }, [04700 ... 04707] = { { EMIT_BFEXTU_reg }, NULL, 0, SR_NZVC, 2, 0, 0 }, [04720 ... 04727] = { { EMIT_BFEXTU }, NULL, 0, SR_NZVC, 2, 0, 0 }, [04750 ... 04773] = { { EMIT_BFEXTU }, NULL, 0, SR_NZVC, 2, 1, 0 }, [05700 ... 05707] = { { EMIT_BFEXTS_reg }, NULL, 0, SR_NZVC, 2, 0, 0 }, [05720 ... 05727] = { { EMIT_BFEXTS }, NULL, 0, SR_NZVC, 2, 0, 0 }, [05750 ... 05773] = { { EMIT_BFEXTS }, NULL, 0, SR_NZVC, 2, 1, 0 }, [06700 ... 06707] = { { EMIT_BFFFO_reg }, NULL, 0, SR_NZVC, 2, 0, 0 }, [06720 ... 06727] = { { EMIT_BFFFO }, NULL, 0, SR_NZVC, 2, 0, 0 }, [06750 ... 06773] = { { EMIT_BFFFO }, NULL, 0, SR_NZVC, 2, 1, 0 }, [07700 ... 07707] = { { EMIT_BFINS_reg }, NULL, 0, SR_NZVC, 2, 0, 0 }, [07720 ... 07727] = { { EMIT_BFINS }, NULL, 0, SR_NZVC, 2, 0, 0 }, [07750 ... 07771] = { { EMIT_BFINS }, NULL, 0, SR_NZVC, 2, 1, 0 }, }; uint32_t *EMIT_lineE(uint32_t *ptr, uint16_t **m68k_ptr, uint16_t *insn_consumed) { uint16_t opcode = cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]); (*m68k_ptr)++; *insn_consumed = 1; /* Special case: the combination of RO(R/L).W #8, Dn; SWAP Dn; RO(R/L).W, Dn this is replaced by REV instruction */ if (((opcode & 0xfef8) == 0xe058) && cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[0]) == (0x4840 | (opcode & 7)) && (cache_read_16(ICACHE, (uintptr_t)&(*m68k_ptr)[1]) & 0xfeff) == (opcode & 0xfeff)) { uint8_t update_mask = M68K_GetSRMask(&(*m68k_ptr)[-1]); uint8_t reg = RA_MapM68kRegister(&ptr, opcode & 7); RA_SetDirtyM68kRegister(&ptr, opcode & 7); *insn_consumed = 3; *ptr++ = rev(reg, reg); ptr = EMIT_AdvancePC(ptr, 6); *m68k_ptr += 2; if (update_mask) { uint8_t cc = RA_ModifyCC(&ptr); uint8_t tmp = RA_AllocARMRegister(&ptr); *ptr++ = cmn_reg(31, reg, LSL, 0); uint8_t alt_flags = update_mask; if ((alt_flags & 3) != 0 && (alt_flags & 3) < 3) alt_flags ^= 3; *ptr++ = mov_immed_u16(tmp, alt_flags, 0); *ptr++ = bic_reg(cc, cc, tmp, LSL, 0); if (update_mask & SR_Z) { *ptr++ = b_cc(A64_CC_EQ ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, (32 - SRB_Z) & 31); } if (update_mask & SR_N) { *ptr++ = b_cc(A64_CC_MI ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, (32 - SRB_N) & 31); } if (update_mask & (SR_C | SR_X)) { *ptr++ = b_cc(A64_CC_CS ^ 1, 3); *ptr++ = mov_immed_u16(tmp, SR_Calt | SR_X, 0); *ptr++ = orr_reg(cc, cc, tmp, LSL, 0); } RA_FreeARMRegister(&ptr, tmp); } return ptr; } else if (InsnTable[opcode & 0xfff].od_Emit) { ptr = InsnTable[opcode & 0xfff].od_Emit(ptr, opcode, m68k_ptr); } else { ptr = EMIT_FlushPC(ptr); ptr = EMIT_InjectDebugString(ptr, "[JIT] opcode %04x at %08x not implemented\n", opcode, *m68k_ptr - 1); *ptr++ = svc(0x100); *ptr++ = svc(0x101); *ptr++ = svc(0x103); *ptr++ = (uint32_t)(uintptr_t)(*m68k_ptr - 8); *ptr++ = 48; ptr = EMIT_Exception(ptr, VECTOR_ILLEGAL_INSTRUCTION, 0); *ptr++ = INSN_TO_LE(0xffffffff); } return ptr; } uint32_t GetSR_LineE(uint16_t opcode) { /* If instruction is in the table, return what flags it needs (shifted 16 bits left) and flags it sets */ if (InsnTable[opcode & 0xfff].od_Emit) { return (InsnTable[opcode & 0xfff].od_SRNeeds << 16) | InsnTable[opcode & 0xfff].od_SRSets; } /* Instruction not found, i.e. it needs all flags and sets none (ILLEGAL INSTRUCTION exception) */ else { kprintf("Undefined LineE\n"); return SR_CCR << 16; } } int M68K_GetLineELength(uint16_t *insn_stream) { uint16_t opcode = cache_read_16(ICACHE, (uintptr_t)insn_stream); int length = 0; int need_ea = 0; int opsize = 0; if (InsnTable[opcode & 0xfff].od_Emit) { length = InsnTable[opcode & 0xfff].od_BaseLength; need_ea = InsnTable[opcode & 0xfff].od_HasEA; opsize = InsnTable[opcode & 0xfff].od_OpSize; } if (need_ea) { length += SR_GetEALength(&insn_stream[length], opcode & 0x3f, opsize); } return length; }