#include /* Copyright © 2020 Michal Schulz https://github.com/michalsc This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "support.h" #include "M68k.h" #include "RegisterAllocator.h" uint32_t * EMIT_JumpOnCondition(uint32_t *ptr, uint8_t m68k_condition, uint32_t distance) { uint8_t cond_tmp = 0xff; uint8_t cc = RA_GetCC(&ptr); switch (m68k_condition) { case M_CC_EQ: *ptr++ = tbnz(cc, SRB_Z, distance);//tst_immed(cc, 1, 31 & (32 - SRB_Z)); break; case M_CC_NE: *ptr++ = tbz(cc, SRB_Z, distance); break; case M_CC_CS: *ptr++ = tbnz(cc, SRB_Calt, distance); break; case M_CC_CC: *ptr++ = tbz(cc, SRB_Calt, distance); break; case M_CC_PL: *ptr++ = tbz(cc, SRB_N, distance); break; case M_CC_MI: *ptr++ = tbnz(cc, SRB_N, distance); break; case M_CC_VS: *ptr++ = tbnz(cc, SRB_Valt, distance); break; case M_CC_VC: *ptr++ = tbz(cc, SRB_Valt, distance); break; case M_CC_LS: /* C == 1 || Z == 1 */ *ptr++ = tst_immed(cc, 2, 31); // xnZCv *ptr++ = b_cc(A64_CC_NE, distance); break; case M_CC_HI: /* C == 0 && Z == 0 */ //cond_tmp = RA_AllocARMRegister(&ptr); //*ptr++ = mov_immed_u8(cond_tmp, SR_Z | SR_Calt); //*ptr++ = tst_reg(cc, cond_tmp, LSL, 0); *ptr++ = tst_immed(cc, 2, 31); // xnZCv *ptr++ = b_cc(A64_CC_EQ, distance); break; case M_CC_GE: /* N ==V -> (N==0 && V==0) || (N==1 && V==1) */ cond_tmp = RA_AllocARMRegister(&ptr); *ptr++ = ror(cond_tmp, cc, 4); *ptr++ = set_nzcv(cond_tmp); *ptr++ = b_cc(A64_CC_GE, distance); break; case M_CC_LT: cond_tmp = RA_AllocARMRegister(&ptr); *ptr++ = ror(cond_tmp, cc, 4); *ptr++ = set_nzcv(cond_tmp); *ptr++ = b_cc(A64_CC_LT, distance); break; case M_CC_GT: cond_tmp = RA_AllocARMRegister(&ptr); *ptr++ = ror(cond_tmp, cc, 4); *ptr++ = set_nzcv(cond_tmp); *ptr++ = b_cc(A64_CC_GT, distance); break; case M_CC_LE: cond_tmp = RA_AllocARMRegister(&ptr); *ptr++ = ror(cond_tmp, cc, 4); *ptr++ = set_nzcv(cond_tmp); *ptr++ = b_cc(A64_CC_LE, distance); break; default: kprintf("Default CC called! Can't be!\n"); *ptr++ = udf(0x0bcc); break; } RA_FreeARMRegister(&ptr, cond_tmp); return ptr; } uint8_t EMIT_TestCondition(uint32_t **pptr, uint8_t m68k_condition) { uint32_t *ptr = *pptr; uint8_t success_condition = 0; uint8_t cond_tmp = 0xff; uint8_t cc = RA_GetCC(&ptr); switch (m68k_condition) { case M_CC_EQ: *ptr++ = tst_immed(cc, 1, 31 & (32 - SRB_Z)); success_condition = A64_CC_NE; break; case M_CC_NE: *ptr++ = tst_immed(cc, 1, 31 & (32 - SRB_Z)); success_condition = A64_CC_EQ; break; case M_CC_CS: *ptr++ = tst_immed(cc, 1, 31 & (32 - SRB_Calt)); success_condition = A64_CC_NE; break; case M_CC_CC: *ptr++ = tst_immed(cc, 1, 31 & (32 - SRB_Calt)); success_condition = A64_CC_EQ; break; case M_CC_PL: *ptr++ = tst_immed(cc, 1, 31 & (32 - SRB_N)); success_condition = A64_CC_EQ; break; case M_CC_MI: *ptr++ = tst_immed(cc, 1, 31 & (32 - SRB_N)); success_condition = A64_CC_NE; break; case M_CC_VS: *ptr++ = tst_immed(cc, 1, 31 & (32 - SRB_Valt)); success_condition = A64_CC_NE; break; case M_CC_VC: *ptr++ = tst_immed(cc, 1, 31 & (32 - SRB_Valt)); success_condition = A64_CC_EQ; break; case M_CC_LS: /* C == 1 || Z == 1 */ //cond_tmp = RA_AllocARMRegister(&ptr); //*ptr++ = mov_immed_u8(cond_tmp, SR_Z | SR_Calt); //*ptr++ = tst_reg(cc, cond_tmp, LSL, 0); *ptr++ = tst_immed(cc, 2, 31); // xnZCv success_condition = A64_CC_NE; break; case M_CC_HI: /* C == 0 && Z == 0 */ //cond_tmp = RA_AllocARMRegister(&ptr); //*ptr++ = mov_immed_u8(cond_tmp, SR_Z | SR_Calt); //*ptr++ = tst_reg(cc, cond_tmp, LSL, 0); *ptr++ = tst_immed(cc, 2, 31); // xnZCv success_condition = A64_CC_EQ; break; case M_CC_GE: /* N ==V -> (N==0 && V==0) || (N==1 && V==1) */ cond_tmp = RA_AllocARMRegister(&ptr); *ptr++ = ror(cond_tmp, cc, 4); *ptr++ = set_nzcv(cond_tmp); success_condition = A64_CC_GE; break; case M_CC_LT: cond_tmp = RA_AllocARMRegister(&ptr); *ptr++ = ror(cond_tmp, cc, 4); *ptr++ = set_nzcv(cond_tmp); success_condition = A64_CC_LT; break; case M_CC_GT: cond_tmp = RA_AllocARMRegister(&ptr); *ptr++ = ror(cond_tmp, cc, 4); *ptr++ = set_nzcv(cond_tmp); success_condition = A64_CC_GT; break; case M_CC_LE: cond_tmp = RA_AllocARMRegister(&ptr); *ptr++ = ror(cond_tmp, cc, 4); *ptr++ = set_nzcv(cond_tmp); success_condition = A64_CC_LE; break; default: kprintf("Default CC called! Can't be!\n"); *ptr++ = udf(0x0bcc); break; } RA_FreeARMRegister(&ptr, cond_tmp); *pptr = ptr; return success_condition; } uint8_t EMIT_TestFPUCondition(uint32_t **pptr, uint8_t predicate) { uint32_t *ptr = *pptr; uint8_t success_condition = 0; uint8_t tmp_cc = 0xff; uint8_t fpsr = RA_GetFPSR(&ptr); /* Test predicate with masked signalling bit, operations are the same */ switch (predicate & 0x0f) { case F_CC_EQ: /* Z == 0 */ *ptr++ = tst_immed(fpsr, 1, 31 & (32 - FPSRB_Z)); success_condition = A64_CC_NE; break; case F_CC_NE: /* Z == 1 */ *ptr++ = tst_immed(fpsr, 1, 31 & (32 - FPSRB_Z)); success_condition = A64_CC_EQ; break; case F_CC_OGT: /* NAN == 0 && Z == 0 && N == 0 */ tmp_cc = RA_AllocARMRegister(&ptr); *ptr++ = mov_immed_u16(tmp_cc, (FPSR_Z | FPSR_N | FPSR_NAN) >> 16, 1); *ptr++ = tst_reg(fpsr, tmp_cc, LSL, 0); success_condition = ARM_CC_EQ; break; case F_CC_ULE: /* NAN == 1 || Z == 1 || N == 1 */ tmp_cc = RA_AllocARMRegister(&ptr); *ptr++ = mov_immed_u16(tmp_cc, (FPSR_Z | FPSR_N | FPSR_NAN) >> 16, 1); *ptr++ = tst_reg(fpsr, tmp_cc, LSL, 0); success_condition = ARM_CC_NE; break; case F_CC_OGE: // Z == 1 || (N == 0 && NAN == 0) tmp_cc = RA_AllocARMRegister(&ptr); *ptr++ = tst_immed(fpsr, 1, 31 & (32 - FPSRB_Z)); *ptr++ = b_cc(A64_CC_NE, 4); *ptr++ = orr_reg(tmp_cc, fpsr, fpsr, LSL, 3); // N | NAN -> N (== 0 only if N=0 && NAN=0) *ptr++ = eor_immed(tmp_cc, tmp_cc, 1, 31 & (32 - FPSRB_N)); // !N -> N *ptr++ = tst_immed(tmp_cc, 1, 31 & (32 - FPSRB_N)); success_condition = A64_CC_NE; break; case F_CC_ULT: // NAN == 1 || (N == 1 && Z == 0) tmp_cc = RA_AllocARMRegister(&ptr); *ptr++ = tst_immed(fpsr, 1, 31 & (32 - FPSRB_NAN)); *ptr++ = b_cc(A64_CC_NE, 4); *ptr++ = eor_immed(tmp_cc, fpsr, 1, 31 & (32 - FPSRB_Z)); // Invert Z *ptr++ = and_reg(tmp_cc, tmp_cc, tmp_cc, LSL, 1); // !Z & N -> N *ptr++ = tst_immed(tmp_cc, 1, 31 & (32 - FPSRB_N)); success_condition = A64_CC_NE; break; case F_CC_OLT: // N == 1 && (NAN == 0 && Z == 0) tmp_cc = RA_AllocARMRegister(&ptr); *ptr++ = bic_immed(tmp_cc, fpsr, 1, 31 & (32 - FPSRB_I)); *ptr++ = orr_reg(tmp_cc, tmp_cc, tmp_cc, LSL, 2); // NAN | Z -> Z *ptr++ = eor_immed(tmp_cc, tmp_cc, 1, 31 & (32 - FPSRB_N)); // Invert N *ptr++ = tst_immed(tmp_cc, 2, 31 & (32 - FPSRB_Z)); // Test N==0 && Z == 0 success_condition = A64_CC_EQ; break; case F_CC_UGE: // NAN == 1 || (Z == 1 || N == 0) tmp_cc = RA_AllocARMRegister(&ptr); *ptr++ = eor_immed(tmp_cc, fpsr, 1, 31 & (32 - FPSRB_N)); *ptr++ = bic_immed(tmp_cc, tmp_cc, 1, 31 & (32 - FPSRB_I)); *ptr++ = tst_immed(tmp_cc, 4, 31 & (32 - FPSRB_NAN)); success_condition = A64_CC_NE; break; case F_CC_OLE: // Z == 1 || (N == 1 && NAN == 0) tmp_cc = RA_AllocARMRegister(&ptr); *ptr++ = tst_immed(fpsr, 1, 31 & (32 - FPSRB_Z)); *ptr++ = b_cc(A64_CC_NE, 4); *ptr++ = eor_immed(tmp_cc, fpsr, 1, 31 & (32 - FPSRB_NAN)); // Invert NAN *ptr++ = and_reg(tmp_cc, tmp_cc, tmp_cc, LSL, 3); // !NAN & N -> N *ptr++ = tst_immed(tmp_cc, 1, 31 & (32 - FPSRB_N)); success_condition = A64_CC_NE; break; case F_CC_UGT: // NAN == 1 || (N == 0 && Z == 0) tmp_cc = RA_AllocARMRegister(&ptr); *ptr++ = tst_immed(fpsr, 1, 31 & (32 - FPSRB_NAN)); *ptr++ = b_cc(A64_CC_NE, 4); *ptr++ = orr_reg(tmp_cc, fpsr, fpsr, LSR, 1); *ptr++ = mvn_reg(tmp_cc, tmp_cc, LSL, 0); //eor_immed(tmp_cc, tmp_cc, 1, 31 & (32 - FPSRB_Z)); *ptr++ = tst_immed(tmp_cc, 1, 31 & (32 - FPSRB_Z)); success_condition = A64_CC_NE; break; case F_CC_OGL: tmp_cc = RA_AllocARMRegister(&ptr); *ptr++ = mov_immed_u16(tmp_cc, (FPSR_Z | FPSR_NAN) >> 16, 1); *ptr++ = tst_reg(fpsr, tmp_cc, LSL, 0); success_condition = A64_CC_EQ; break; case F_CC_UEQ: tmp_cc = RA_AllocARMRegister(&ptr); *ptr++ = mov_immed_u16(tmp_cc, (FPSR_Z | FPSR_NAN) >> 16, 1); *ptr++ = tst_reg(fpsr, tmp_cc, LSL, 0); success_condition = A64_CC_NE; break; case F_CC_OR: *ptr++ = tst_immed(fpsr, 1, 31 & (32 - FPSRB_NAN)); success_condition = A64_CC_EQ; break; case F_CC_UN: *ptr++ = tst_immed(fpsr, 1, 31 & (32 - FPSRB_NAN)); success_condition = A64_CC_NE; break; case F_CC_F: // This is NOP - handled one "if" before success_condition = A64_CC_NV; break; case F_CC_T: // Unconditional branch to target success_condition = A64_CC_AL; break; } RA_FreeARMRegister(&ptr, tmp_cc); *pptr = ptr; return success_condition; }