/* iwmmxt.c -- Intel(r) Wireless MMX(tm) technology co-processor interface. Copyright (C) 2002-2020 Free Software Foundation, Inc. Contributed by matthew green (mrg@redhat.com). This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "armdefs.h" #include "armos.h" #include "armemu.h" #include "ansidecl.h" #include "iwmmxt.h" /* #define DEBUG 1 */ /* Intel(r) Wireless MMX(tm) technology co-processor. It uses co-processor numbers (0 and 1). There are 16 vector registers wRx and 16 control registers wCx. Co-processors 0 and 1 are used in MCR/MRC to access wRx and wCx respectively. */ static ARMdword wR[16]; static ARMword wC[16] = { 0x69051010 }; #define SUBSTR(w,t,m,n) ((t)(w << ((sizeof (t) * 8 - 1) - (n))) \ >> (((sizeof (t) * 8 - 1) - (n)) + (m))) #define wCBITS(w,x,y) SUBSTR (wC[w], ARMword, x, y) #define wRBITS(w,x,y) SUBSTR (wR[w], ARMdword, x, y) #define wCID 0 #define wCon 1 #define wCSSF 2 #define wCASF 3 #define wCGR0 8 #define wCGR1 9 #define wCGR2 10 #define wCGR3 11 /* Bits in the wCon register. */ #define WCON_CUP (1 << 0) #define WCON_MUP (1 << 1) /* Set the SIMD wCASF flags for 8, 16, 32 or 64-bit operations. */ #define SIMD8_SET(x, v, n, b) (x) |= ((v != 0) << ((((b) + 1) * 4) + (n))) #define SIMD16_SET(x, v, n, h) (x) |= ((v != 0) << ((((h) + 1) * 8) + (n))) #define SIMD32_SET(x, v, n, w) (x) |= ((v != 0) << ((((w) + 1) * 16) + (n))) #define SIMD64_SET(x, v, n) (x) |= ((v != 0) << (32 + (n))) /* Flags to pass as "n" above. */ #define SIMD_NBIT -1 #define SIMD_ZBIT -2 #define SIMD_CBIT -3 #define SIMD_VBIT -4 /* Various status bit macros. */ #define NBIT8(x) ((x) & 0x80) #define NBIT16(x) ((x) & 0x8000) #define NBIT32(x) ((x) & 0x80000000) #define NBIT64(x) ((x) & 0x8000000000000000ULL) #define ZBIT8(x) (((x) & 0xff) == 0) #define ZBIT16(x) (((x) & 0xffff) == 0) #define ZBIT32(x) (((x) & 0xffffffff) == 0) #define ZBIT64(x) (x == 0) /* Access byte/half/word "n" of register "x". */ #define wRBYTE(x,n) wRBITS ((x), (n) * 8, (n) * 8 + 7) #define wRHALF(x,n) wRBITS ((x), (n) * 16, (n) * 16 + 15) #define wRWORD(x,n) wRBITS ((x), (n) * 32, (n) * 32 + 31) /* Macro to handle how the G bit selects wCGR registers. */ #define DECODE_G_BIT(state, instr, shift) \ { \ unsigned int reg; \ \ reg = BITS (0, 3); \ \ if (BIT (8)) /* G */ \ { \ if (reg < wCGR0 || reg > wCGR3) \ { \ ARMul_UndefInstr (state, instr); \ return ARMul_DONE; \ } \ shift = wC [reg]; \ } \ else \ shift = wR [reg]; \ \ shift &= 0xff; \ } /* Index calculations for the satrv[] array. */ #define BITIDX8(x) (x) #define BITIDX16(x) (((x) + 1) * 2 - 1) #define BITIDX32(x) (((x) + 1) * 4 - 1) /* Sign extension macros. */ #define EXTEND8(a) ((a) & 0x80 ? ((a) | 0xffffff00) : (a)) #define EXTEND16(a) ((a) & 0x8000 ? ((a) | 0xffff0000) : (a)) #define EXTEND32(a) ((a) & 0x80000000ULL ? ((a) | 0xffffffff00000000ULL) : (a)) /* Set the wCSSF from 8 values. */ #define SET_wCSSF(a,b,c,d,e,f,g,h) \ wC[wCSSF] = (((h) != 0) << 7) | (((g) != 0) << 6) \ | (((f) != 0) << 5) | (((e) != 0) << 4) \ | (((d) != 0) << 3) | (((c) != 0) << 2) \ | (((b) != 0) << 1) | (((a) != 0) << 0); /* Set the wCSSR from an array with 8 values. */ #define SET_wCSSFvec(v) \ SET_wCSSF((v)[0],(v)[1],(v)[2],(v)[3],(v)[4],(v)[5],(v)[6],(v)[7]) /* Size qualifiers for vector operations. */ #define Bqual 0 #define Hqual 1 #define Wqual 2 #define Dqual 3 /* Saturation qualifiers for vector operations. */ #define NoSaturation 0 #define UnsignedSaturation 1 #define SignedSaturation 3 /* Prototypes. */ static ARMword Add32 (ARMword, ARMword, int *, int *, ARMword); static ARMdword AddS32 (ARMdword, ARMdword, int *, int *); static ARMdword AddU32 (ARMdword, ARMdword, int *, int *); static ARMword AddS16 (ARMword, ARMword, int *, int *); static ARMword AddU16 (ARMword, ARMword, int *, int *); static ARMword AddS8 (ARMword, ARMword, int *, int *); static ARMword AddU8 (ARMword, ARMword, int *, int *); static ARMword Sub32 (ARMword, ARMword, int *, int *, ARMword); static ARMdword SubS32 (ARMdword, ARMdword, int *, int *); static ARMdword SubU32 (ARMdword, ARMdword, int *, int *); static ARMword SubS16 (ARMword, ARMword, int *, int *); static ARMword SubS8 (ARMword, ARMword, int *, int *); static ARMword SubU16 (ARMword, ARMword, int *, int *); static ARMword SubU8 (ARMword, ARMword, int *, int *); static unsigned char IwmmxtSaturateU8 (signed short, int *); static signed char IwmmxtSaturateS8 (signed short, int *); static unsigned short IwmmxtSaturateU16 (signed int, int *); static signed short IwmmxtSaturateS16 (signed int, int *); static unsigned long IwmmxtSaturateU32 (signed long long, int *); static signed long IwmmxtSaturateS32 (signed long long, int *); static ARMword Compute_Iwmmxt_Address (ARMul_State *, ARMword, int *); static ARMdword Iwmmxt_Load_Double_Word (ARMul_State *, ARMword); static ARMword Iwmmxt_Load_Word (ARMul_State *, ARMword); static ARMword Iwmmxt_Load_Half_Word (ARMul_State *, ARMword); static ARMword Iwmmxt_Load_Byte (ARMul_State *, ARMword); static void Iwmmxt_Store_Double_Word (ARMul_State *, ARMword, ARMdword); static void Iwmmxt_Store_Word (ARMul_State *, ARMword, ARMword); static void Iwmmxt_Store_Half_Word (ARMul_State *, ARMword, ARMword); static void Iwmmxt_Store_Byte (ARMul_State *, ARMword, ARMword); static int Process_Instruction (ARMul_State *, ARMword); static int TANDC (ARMul_State *, ARMword); static int TBCST (ARMul_State *, ARMword); static int TEXTRC (ARMul_State *, ARMword); static int TEXTRM (ARMul_State *, ARMword); static int TINSR (ARMul_State *, ARMword); static int TMCR (ARMul_State *, ARMword); static int TMCRR (ARMul_State *, ARMword); static int TMIA (ARMul_State *, ARMword); static int TMIAPH (ARMul_State *, ARMword); static int TMIAxy (ARMul_State *, ARMword); static int TMOVMSK (ARMul_State *, ARMword); static int TMRC (ARMul_State *, ARMword); static int TMRRC (ARMul_State *, ARMword); static int TORC (ARMul_State *, ARMword); static int WACC (ARMul_State *, ARMword); static int WADD (ARMul_State *, ARMword); static int WALIGNI (ARMword); static int WALIGNR (ARMul_State *, ARMword); static int WAND (ARMword); static int WANDN (ARMword); static int WAVG2 (ARMword); static int WCMPEQ (ARMul_State *, ARMword); static int WCMPGT (ARMul_State *, ARMword); static int WLDR (ARMul_State *, ARMword); static int WMAC (ARMword); static int WMADD (ARMword); static int WMAX (ARMul_State *, ARMword); static int WMIN (ARMul_State *, ARMword); static int WMUL (ARMword); static int WOR (ARMword); static int WPACK (ARMul_State *, ARMword); static int WROR (ARMul_State *, ARMword); static int WSAD (ARMword); static int WSHUFH (ARMword); static int WSLL (ARMul_State *, ARMword); static int WSRA (ARMul_State *, ARMword); static int WSRL (ARMul_State *, ARMword); static int WSTR (ARMul_State *, ARMword); static int WSUB (ARMul_State *, ARMword); static int WUNPCKEH (ARMul_State *, ARMword); static int WUNPCKEL (ARMul_State *, ARMword); static int WUNPCKIH (ARMul_State *, ARMword); static int WUNPCKIL (ARMul_State *, ARMword); static int WXOR (ARMword); /* This function does the work of adding two 32bit values together, and calculating if a carry has occurred. */ static ARMword Add32 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr, ARMword sign_mask) { ARMword result = (a1 + a2); unsigned int uresult = (unsigned int) result; unsigned int ua1 = (unsigned int) a1; /* If (result == a1) and (a2 == 0), or (result > a2) then we have no carry. */ * carry_ptr = ((uresult == ua1) ? (a2 != 0) : (uresult < ua1)); /* Overflow occurs when both arguments are the same sign, but the result is a different sign. */ * overflow_ptr = ( ( (result & sign_mask) && !(a1 & sign_mask) && !(a2 & sign_mask)) || (!(result & sign_mask) && (a1 & sign_mask) && (a2 & sign_mask))); return result; } static ARMdword AddS32 (ARMdword a1, ARMdword a2, int * carry_ptr, int * overflow_ptr) { ARMdword result; unsigned int uresult; unsigned int ua1; a1 = EXTEND32 (a1); a2 = EXTEND32 (a2); result = a1 + a2; uresult = (unsigned int) result; ua1 = (unsigned int) a1; * carry_ptr = ((uresult == a1) ? (a2 != 0) : (uresult < ua1)); * overflow_ptr = ( ( (result & 0x80000000ULL) && !(a1 & 0x80000000ULL) && !(a2 & 0x80000000ULL)) || (!(result & 0x80000000ULL) && (a1 & 0x80000000ULL) && (a2 & 0x80000000ULL))); return result; } static ARMdword AddU32 (ARMdword a1, ARMdword a2, int * carry_ptr, int * overflow_ptr) { ARMdword result; unsigned int uresult; unsigned int ua1; a1 &= 0xffffffff; a2 &= 0xffffffff; result = a1 + a2; uresult = (unsigned int) result; ua1 = (unsigned int) a1; * carry_ptr = ((uresult == a1) ? (a2 != 0) : (uresult < ua1)); * overflow_ptr = ( ( (result & 0x80000000ULL) && !(a1 & 0x80000000ULL) && !(a2 & 0x80000000ULL)) || (!(result & 0x80000000ULL) && (a1 & 0x80000000ULL) && (a2 & 0x80000000ULL))); return result; } static ARMword AddS16 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) { a1 = EXTEND16 (a1); a2 = EXTEND16 (a2); return Add32 (a1, a2, carry_ptr, overflow_ptr, 0x8000); } static ARMword AddU16 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) { a1 &= 0xffff; a2 &= 0xffff; return Add32 (a1, a2, carry_ptr, overflow_ptr, 0x8000); } static ARMword AddS8 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) { a1 = EXTEND8 (a1); a2 = EXTEND8 (a2); return Add32 (a1, a2, carry_ptr, overflow_ptr, 0x80); } static ARMword AddU8 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) { a1 &= 0xff; a2 &= 0xff; return Add32 (a1, a2, carry_ptr, overflow_ptr, 0x80); } static ARMword Sub32 (ARMword a1, ARMword a2, int * borrow_ptr, int * overflow_ptr, ARMword sign_mask) { ARMword result = (a1 - a2); unsigned int ua1 = (unsigned int) a1; unsigned int ua2 = (unsigned int) a2; /* A borrow occurs if a2 is (unsigned) larger than a1. However the carry flag is *cleared* if a borrow occurs. */ * borrow_ptr = ! (ua2 > ua1); /* Overflow occurs when a negative number is subtracted from a positive number and the result is negative or a positive number is subtracted from a negative number and the result is positive. */ * overflow_ptr = ( (! (a1 & sign_mask) && (a2 & sign_mask) && (result & sign_mask)) || ((a1 & sign_mask) && ! (a2 & sign_mask) && ! (result & sign_mask))); return result; } static ARMdword SubS32 (ARMdword a1, ARMdword a2, int * borrow_ptr, int * overflow_ptr) { ARMdword result; unsigned int ua1; unsigned int ua2; a1 = EXTEND32 (a1); a2 = EXTEND32 (a2); result = a1 - a2; ua1 = (unsigned int) a1; ua2 = (unsigned int) a2; * borrow_ptr = ! (ua2 > ua1); * overflow_ptr = ( (! (a1 & 0x80000000ULL) && (a2 & 0x80000000ULL) && (result & 0x80000000ULL)) || ((a1 & 0x80000000ULL) && ! (a2 & 0x80000000ULL) && ! (result & 0x80000000ULL))); return result; } static ARMword SubS16 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) { a1 = EXTEND16 (a1); a2 = EXTEND16 (a2); return Sub32 (a1, a2, carry_ptr, overflow_ptr, 0x8000); } static ARMword SubS8 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) { a1 = EXTEND8 (a1); a2 = EXTEND8 (a2); return Sub32 (a1, a2, carry_ptr, overflow_ptr, 0x80); } static ARMword SubU16 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) { a1 &= 0xffff; a2 &= 0xffff; return Sub32 (a1, a2, carry_ptr, overflow_ptr, 0x8000); } static ARMword SubU8 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) { a1 &= 0xff; a2 &= 0xff; return Sub32 (a1, a2, carry_ptr, overflow_ptr, 0x80); } static ARMdword SubU32 (ARMdword a1, ARMdword a2, int * borrow_ptr, int * overflow_ptr) { ARMdword result; unsigned int ua1; unsigned int ua2; a1 &= 0xffffffff; a2 &= 0xffffffff; result = a1 - a2; ua1 = (unsigned int) a1; ua2 = (unsigned int) a2; * borrow_ptr = ! (ua2 > ua1); * overflow_ptr = ( (! (a1 & 0x80000000ULL) && (a2 & 0x80000000ULL) && (result & 0x80000000ULL)) || ((a1 & 0x80000000ULL) && ! (a2 & 0x80000000ULL) && ! (result & 0x80000000ULL))); return result; } /* For the saturation. */ static unsigned char IwmmxtSaturateU8 (signed short val, int * sat) { unsigned char rv; if (val < 0) { rv = 0; *sat = 1; } else if (val > 0xff) { rv = 0xff; *sat = 1; } else { rv = val & 0xff; *sat = 0; } return rv; } static signed char IwmmxtSaturateS8 (signed short val, int * sat) { signed char rv; if (val < -0x80) { rv = -0x80; *sat = 1; } else if (val > 0x7f) { rv = 0x7f; *sat = 1; } else { rv = val & 0xff; *sat = 0; } return rv; } static unsigned short IwmmxtSaturateU16 (signed int val, int * sat) { unsigned short rv; if (val < 0) { rv = 0; *sat = 1; } else if (val > 0xffff) { rv = 0xffff; *sat = 1; } else { rv = val & 0xffff; *sat = 0; } return rv; } static signed short IwmmxtSaturateS16 (signed int val, int * sat) { signed short rv; if (val < -0x8000) { rv = - 0x8000; *sat = 1; } else if (val > 0x7fff) { rv = 0x7fff; *sat = 1; } else { rv = val & 0xffff; *sat = 0; } return rv; } static unsigned long IwmmxtSaturateU32 (signed long long val, int * sat) { unsigned long rv; if (val < 0) { rv = 0; *sat = 1; } else if (val > 0xffffffff) { rv = 0xffffffff; *sat = 1; } else { rv = val & 0xffffffff; *sat = 0; } return rv; } static signed long IwmmxtSaturateS32 (signed long long val, int * sat) { signed long rv; if (val < -0x80000000LL) { rv = -0x80000000; *sat = 1; } else if (val > 0x7fffffff) { rv = 0x7fffffff; *sat = 1; } else { rv = val & 0xffffffff; *sat = 0; } return rv; } /* Intel(r) Wireless MMX(tm) technology Acessor functions. */ unsigned IwmmxtLDC (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword data) { return ARMul_CANT; } unsigned IwmmxtSTC (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword * data) { return ARMul_CANT; } unsigned IwmmxtMRC (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword * value) { return ARMul_CANT; } unsigned IwmmxtMCR (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword value) { return ARMul_CANT; } unsigned IwmmxtCDP (ARMul_State * state, unsigned type, ARMword instr) { return ARMul_CANT; } /* Intel(r) Wireless MMX(tm) technology instruction implementations. */ static int TANDC (ARMul_State * state, ARMword instr) { ARMword cpsr; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "tandc\n"); #endif /* The Rd field must be r15. */ if (BITS (12, 15) != 15) return ARMul_CANT; /* The CRn field must be r3. */ if (BITS (16, 19) != 3) return ARMul_CANT; /* The CRm field must be r0. */ if (BITS (0, 3) != 0) return ARMul_CANT; cpsr = ARMul_GetCPSR (state) & 0x0fffffff; switch (BITS (22, 23)) { case Bqual: cpsr |= ( (wCBITS (wCASF, 28, 31) & wCBITS (wCASF, 24, 27) & wCBITS (wCASF, 20, 23) & wCBITS (wCASF, 16, 19) & wCBITS (wCASF, 12, 15) & wCBITS (wCASF, 8, 11) & wCBITS (wCASF, 4, 7) & wCBITS (wCASF, 0, 3)) << 28); break; case Hqual: cpsr |= ( (wCBITS (wCASF, 28, 31) & wCBITS (wCASF, 20, 23) & wCBITS (wCASF, 12, 15) & wCBITS (wCASF, 4, 7)) << 28); break; case Wqual: cpsr |= ((wCBITS (wCASF, 28, 31) & wCBITS (wCASF, 12, 15)) << 28); break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } ARMul_SetCPSR (state, cpsr); return ARMul_DONE; } static int TBCST (ARMul_State * state, ARMword instr) { ARMdword Rn; int wRd; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "tbcst\n"); #endif Rn = state->Reg [BITS (12, 15)]; if (BITS (12, 15) == 15) Rn &= 0xfffffffc; wRd = BITS (16, 19); switch (BITS (6, 7)) { case Bqual: Rn &= 0xff; wR [wRd] = (Rn << 56) | (Rn << 48) | (Rn << 40) | (Rn << 32) | (Rn << 24) | (Rn << 16) | (Rn << 8) | Rn; break; case Hqual: Rn &= 0xffff; wR [wRd] = (Rn << 48) | (Rn << 32) | (Rn << 16) | Rn; break; case Wqual: Rn &= 0xffffffff; wR [wRd] = (Rn << 32) | Rn; break; default: ARMul_UndefInstr (state, instr); break; } wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int TEXTRC (ARMul_State * state, ARMword instr) { ARMword cpsr; ARMword selector; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "textrc\n"); #endif /* The Rd field must be r15. */ if (BITS (12, 15) != 15) return ARMul_CANT; /* The CRn field must be r3. */ if (BITS (16, 19) != 3) return ARMul_CANT; /* The CRm field must be 0xxx. */ if (BIT (3) != 0) return ARMul_CANT; selector = BITS (0, 2); cpsr = ARMul_GetCPSR (state) & 0x0fffffff; switch (BITS (22, 23)) { case Bqual: selector *= 4; break; case Hqual: selector = ((selector & 3) * 8) + 4; break; case Wqual: selector = ((selector & 1) * 16) + 12; break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } cpsr |= wCBITS (wCASF, selector, selector + 3) << 28; ARMul_SetCPSR (state, cpsr); return ARMul_DONE; } static int TEXTRM (ARMul_State * state, ARMword instr) { ARMword Rd; int offset; int wRn; int sign; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "textrm\n"); #endif wRn = BITS (16, 19); sign = BIT (3); offset = BITS (0, 2); switch (BITS (22, 23)) { case Bqual: offset *= 8; Rd = wRBITS (wRn, offset, offset + 7); if (sign) Rd = EXTEND8 (Rd); break; case Hqual: offset = (offset & 3) * 16; Rd = wRBITS (wRn, offset, offset + 15); if (sign) Rd = EXTEND16 (Rd); break; case Wqual: offset = (offset & 1) * 32; Rd = wRBITS (wRn, offset, offset + 31); break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } if (BITS (12, 15) == 15) ARMul_UndefInstr (state, instr); else state->Reg [BITS (12, 15)] = Rd; return ARMul_DONE; } static int TINSR (ARMul_State * state, ARMword instr) { ARMdword data; ARMword offset; int wRd; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "tinsr\n"); #endif wRd = BITS (16, 19); data = state->Reg [BITS (12, 15)]; offset = BITS (0, 2); switch (BITS (6, 7)) { case Bqual: data &= 0xff; switch (offset) { case 0: wR [wRd] = data | (wRBITS (wRd, 8, 63) << 8); break; case 1: wR [wRd] = wRBITS (wRd, 0, 7) | (data << 8) | (wRBITS (wRd, 16, 63) << 16); break; case 2: wR [wRd] = wRBITS (wRd, 0, 15) | (data << 16) | (wRBITS (wRd, 24, 63) << 24); break; case 3: wR [wRd] = wRBITS (wRd, 0, 23) | (data << 24) | (wRBITS (wRd, 32, 63) << 32); break; case 4: wR [wRd] = wRBITS (wRd, 0, 31) | (data << 32) | (wRBITS (wRd, 40, 63) << 40); break; case 5: wR [wRd] = wRBITS (wRd, 0, 39) | (data << 40) | (wRBITS (wRd, 48, 63) << 48); break; case 6: wR [wRd] = wRBITS (wRd, 0, 47) | (data << 48) | (wRBITS (wRd, 56, 63) << 56); break; case 7: wR [wRd] = wRBITS (wRd, 0, 55) | (data << 56); break; } break; case Hqual: data &= 0xffff; switch (offset & 3) { case 0: wR [wRd] = data | (wRBITS (wRd, 16, 63) << 16); break; case 1: wR [wRd] = wRBITS (wRd, 0, 15) | (data << 16) | (wRBITS (wRd, 32, 63) << 32); break; case 2: wR [wRd] = wRBITS (wRd, 0, 31) | (data << 32) | (wRBITS (wRd, 48, 63) << 48); break; case 3: wR [wRd] = wRBITS (wRd, 0, 47) | (data << 48); break; } break; case Wqual: if (offset & 1) wR [wRd] = wRBITS (wRd, 0, 31) | (data << 32); else wR [wRd] = (wRBITS (wRd, 32, 63) << 32) | data; break; default: ARMul_UndefInstr (state, instr); break; } wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int TMCR (ARMul_State * state, ARMword instr) { ARMword val; int wCreg; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "tmcr\n"); #endif if (BITS (0, 3) != 0) return ARMul_CANT; val = state->Reg [BITS (12, 15)]; if (BITS (12, 15) == 15) val &= 0xfffffffc; wCreg = BITS (16, 19); switch (wCreg) { case wCID: /* The wCID register is read only. */ break; case wCon: /* Writing to the MUP or CUP bits clears them. */ wC [wCon] &= ~ (val & 0x3); break; case wCSSF: /* Only the bottom 8 bits can be written to. The higher bits write as zero. */ wC [wCSSF] = (val & 0xff); wC [wCon] |= WCON_CUP; break; default: wC [wCreg] = val; wC [wCon] |= WCON_CUP; break; } return ARMul_DONE; } static int TMCRR (ARMul_State * state, ARMword instr) { ARMdword RdHi = state->Reg [BITS (16, 19)]; ARMword RdLo = state->Reg [BITS (12, 15)]; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "tmcrr\n"); #endif if ((BITS (16, 19) == 15) || (BITS (12, 15) == 15)) return ARMul_CANT; wR [BITS (0, 3)] = (RdHi << 32) | RdLo; wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int TMIA (ARMul_State * state, ARMword instr) { signed long long a, b; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "tmia\n"); #endif if ((BITS (0, 3) == 15) || (BITS (12, 15) == 15)) { ARMul_UndefInstr (state, instr); return ARMul_DONE; } a = state->Reg [BITS (0, 3)]; b = state->Reg [BITS (12, 15)]; a = EXTEND32 (a); b = EXTEND32 (b); wR [BITS (5, 8)] += a * b; wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int TMIAPH (ARMul_State * state, ARMword instr) { signed long a, b, result; signed long long r; ARMword Rm = state->Reg [BITS (0, 3)]; ARMword Rs = state->Reg [BITS (12, 15)]; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "tmiaph\n"); #endif if (BITS (0, 3) == 15 || BITS (12, 15) == 15) { ARMul_UndefInstr (state, instr); return ARMul_DONE; } a = SUBSTR (Rs, ARMword, 16, 31); b = SUBSTR (Rm, ARMword, 16, 31); a = EXTEND16 (a); b = EXTEND16 (b); result = a * b; r = result; r = EXTEND32 (r); wR [BITS (5, 8)] += r; a = SUBSTR (Rs, ARMword, 0, 15); b = SUBSTR (Rm, ARMword, 0, 15); a = EXTEND16 (a); b = EXTEND16 (b); result = a * b; r = result; r = EXTEND32 (r); wR [BITS (5, 8)] += r; wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int TMIAxy (ARMul_State * state, ARMword instr) { ARMword Rm; ARMword Rs; long long temp; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "tmiaxy\n"); #endif if (BITS (0, 3) == 15 || BITS (12, 15) == 15) { ARMul_UndefInstr (state, instr); return ARMul_DONE; } Rm = state->Reg [BITS (0, 3)]; if (BIT (17)) Rm >>= 16; else Rm &= 0xffff; Rs = state->Reg [BITS (12, 15)]; if (BIT (16)) Rs >>= 16; else Rs &= 0xffff; if (Rm & (1 << 15)) Rm -= 1 << 16; if (Rs & (1 << 15)) Rs -= 1 << 16; Rm *= Rs; temp = Rm; if (temp & (1 << 31)) temp -= 1ULL << 32; wR [BITS (5, 8)] += temp; wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int TMOVMSK (ARMul_State * state, ARMword instr) { ARMdword result; int wRn; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "tmovmsk\n"); #endif /* The CRm field must be r0. */ if (BITS (0, 3) != 0) return ARMul_CANT; wRn = BITS (16, 19); switch (BITS (22, 23)) { case Bqual: result = ( (wRBITS (wRn, 63, 63) << 7) | (wRBITS (wRn, 55, 55) << 6) | (wRBITS (wRn, 47, 47) << 5) | (wRBITS (wRn, 39, 39) << 4) | (wRBITS (wRn, 31, 31) << 3) | (wRBITS (wRn, 23, 23) << 2) | (wRBITS (wRn, 15, 15) << 1) | (wRBITS (wRn, 7, 7) << 0)); break; case Hqual: result = ( (wRBITS (wRn, 63, 63) << 3) | (wRBITS (wRn, 47, 47) << 2) | (wRBITS (wRn, 31, 31) << 1) | (wRBITS (wRn, 15, 15) << 0)); break; case Wqual: result = (wRBITS (wRn, 63, 63) << 1) | wRBITS (wRn, 31, 31); break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } state->Reg [BITS (12, 15)] = result; return ARMul_DONE; } static int TMRC (ARMul_State * state, ARMword instr) { int reg = BITS (12, 15); if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "tmrc\n"); #endif if (BITS (0, 3) != 0) return ARMul_CANT; if (reg == 15) ARMul_UndefInstr (state, instr); else state->Reg [reg] = wC [BITS (16, 19)]; return ARMul_DONE; } static int TMRRC (ARMul_State * state, ARMword instr) { if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "tmrrc\n"); #endif if ((BITS (16, 19) == 15) || (BITS (12, 15) == 15) || (BITS (4, 11) != 0)) ARMul_UndefInstr (state, instr); else { state->Reg [BITS (16, 19)] = wRBITS (BITS (0, 3), 32, 63); state->Reg [BITS (12, 15)] = wRBITS (BITS (0, 3), 0, 31); } return ARMul_DONE; } static int TORC (ARMul_State * state, ARMword instr) { ARMword cpsr = ARMul_GetCPSR (state); if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "torc\n"); #endif /* The Rd field must be r15. */ if (BITS (12, 15) != 15) return ARMul_CANT; /* The CRn field must be r3. */ if (BITS (16, 19) != 3) return ARMul_CANT; /* The CRm field must be r0. */ if (BITS (0, 3) != 0) return ARMul_CANT; cpsr &= 0x0fffffff; switch (BITS (22, 23)) { case Bqual: cpsr |= ( (wCBITS (wCASF, 28, 31) | wCBITS (wCASF, 24, 27) | wCBITS (wCASF, 20, 23) | wCBITS (wCASF, 16, 19) | wCBITS (wCASF, 12, 15) | wCBITS (wCASF, 8, 11) | wCBITS (wCASF, 4, 7) | wCBITS (wCASF, 0, 3)) << 28); break; case Hqual: cpsr |= ( (wCBITS (wCASF, 28, 31) | wCBITS (wCASF, 20, 23) | wCBITS (wCASF, 12, 15) | wCBITS (wCASF, 4, 7)) << 28); break; case Wqual: cpsr |= ((wCBITS (wCASF, 28, 31) | wCBITS (wCASF, 12, 15)) << 28); break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } ARMul_SetCPSR (state, cpsr); return ARMul_DONE; } static int WACC (ARMul_State * state, ARMword instr) { int wRn; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wacc\n"); #endif wRn = BITS (16, 19); switch (BITS (22, 23)) { case Bqual: wR [BITS (12, 15)] = wRBITS (wRn, 56, 63) + wRBITS (wRn, 48, 55) + wRBITS (wRn, 40, 47) + wRBITS (wRn, 32, 39) + wRBITS (wRn, 24, 31) + wRBITS (wRn, 16, 23) + wRBITS (wRn, 8, 15) + wRBITS (wRn, 0, 7); break; case Hqual: wR [BITS (12, 15)] = wRBITS (wRn, 48, 63) + wRBITS (wRn, 32, 47) + wRBITS (wRn, 16, 31) + wRBITS (wRn, 0, 15); break; case Wqual: wR [BITS (12, 15)] = wRBITS (wRn, 32, 63) + wRBITS (wRn, 0, 31); break; default: ARMul_UndefInstr (state, instr); break; } wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int WADD (ARMul_State * state, ARMword instr) { ARMdword r = 0; ARMdword x; ARMdword s; ARMword psr = 0; int i; int carry; int overflow; int satrv[8]; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wadd\n"); #endif /* Add two numbers using the specified function, leaving setting the carry bit as required. */ #define ADDx(x, y, m, f) \ (*f) (wRBITS (BITS (16, 19), (x), (y)) & (m), \ wRBITS (BITS ( 0, 3), (x), (y)) & (m), \ & carry, & overflow) switch (BITS (22, 23)) { case Bqual: for (i = 0; i < 8; i++) { switch (BITS (20, 21)) { case NoSaturation: s = ADDx ((i * 8), (i * 8) + 7, 0xff, AddS8); satrv [BITIDX8 (i)] = 0; r |= (s & 0xff) << (i * 8); SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i); SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i); SIMD8_SET (psr, carry, SIMD_CBIT, i); SIMD8_SET (psr, overflow, SIMD_VBIT, i); break; case UnsignedSaturation: s = ADDx ((i * 8), (i * 8) + 7, 0xff, AddU8); x = IwmmxtSaturateU8 (s, satrv + BITIDX8 (i)); r |= (x & 0xff) << (i * 8); SIMD8_SET (psr, NBIT8 (x), SIMD_NBIT, i); SIMD8_SET (psr, ZBIT8 (x), SIMD_ZBIT, i); if (! satrv [BITIDX8 (i)]) { SIMD8_SET (psr, carry, SIMD_CBIT, i); SIMD8_SET (psr, overflow, SIMD_VBIT, i); } break; case SignedSaturation: s = ADDx ((i * 8), (i * 8) + 7, 0xff, AddS8); x = IwmmxtSaturateS8 (s, satrv + BITIDX8 (i)); r |= (x & 0xff) << (i * 8); SIMD8_SET (psr, NBIT8 (x), SIMD_NBIT, i); SIMD8_SET (psr, ZBIT8 (x), SIMD_ZBIT, i); if (! satrv [BITIDX8 (i)]) { SIMD8_SET (psr, carry, SIMD_CBIT, i); SIMD8_SET (psr, overflow, SIMD_VBIT, i); } break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } } break; case Hqual: satrv[0] = satrv[2] = satrv[4] = satrv[6] = 0; for (i = 0; i < 4; i++) { switch (BITS (20, 21)) { case NoSaturation: s = ADDx ((i * 16), (i * 16) + 15, 0xffff, AddS16); satrv [BITIDX16 (i)] = 0; r |= (s & 0xffff) << (i * 16); SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); SIMD16_SET (psr, carry, SIMD_CBIT, i); SIMD16_SET (psr, overflow, SIMD_VBIT, i); break; case UnsignedSaturation: s = ADDx ((i * 16), (i * 16) + 15, 0xffff, AddU16); x = IwmmxtSaturateU16 (s, satrv + BITIDX16 (i)); r |= (x & 0xffff) << (i * 16); SIMD16_SET (psr, NBIT16 (x), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (x), SIMD_ZBIT, i); if (! satrv [BITIDX16 (i)]) { SIMD16_SET (psr, carry, SIMD_CBIT, i); SIMD16_SET (psr, overflow, SIMD_VBIT, i); } break; case SignedSaturation: s = ADDx ((i * 16), (i * 16) + 15, 0xffff, AddS16); x = IwmmxtSaturateS16 (s, satrv + BITIDX16 (i)); r |= (x & 0xffff) << (i * 16); SIMD16_SET (psr, NBIT16 (x), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (x), SIMD_ZBIT, i); if (! satrv [BITIDX16 (i)]) { SIMD16_SET (psr, carry, SIMD_CBIT, i); SIMD16_SET (psr, overflow, SIMD_VBIT, i); } break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } } break; case Wqual: satrv[0] = satrv[1] = satrv[2] = satrv[4] = satrv[5] = satrv[6] = 0; for (i = 0; i < 2; i++) { switch (BITS (20, 21)) { case NoSaturation: s = ADDx ((i * 32), (i * 32) + 31, 0xffffffff, AddS32); satrv [BITIDX32 (i)] = 0; r |= (s & 0xffffffff) << (i * 32); SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); SIMD32_SET (psr, carry, SIMD_CBIT, i); SIMD32_SET (psr, overflow, SIMD_VBIT, i); break; case UnsignedSaturation: s = ADDx ((i * 32), (i * 32) + 31, 0xffffffff, AddU32); x = IwmmxtSaturateU32 (s, satrv + BITIDX32 (i)); r |= (x & 0xffffffff) << (i * 32); SIMD32_SET (psr, NBIT32 (x), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (x), SIMD_ZBIT, i); if (! satrv [BITIDX32 (i)]) { SIMD32_SET (psr, carry, SIMD_CBIT, i); SIMD32_SET (psr, overflow, SIMD_VBIT, i); } break; case SignedSaturation: s = ADDx ((i * 32), (i * 32) + 31, 0xffffffff, AddS32); x = IwmmxtSaturateS32 (s, satrv + BITIDX32 (i)); r |= (x & 0xffffffff) << (i * 32); SIMD32_SET (psr, NBIT32 (x), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (x), SIMD_ZBIT, i); if (! satrv [BITIDX32 (i)]) { SIMD32_SET (psr, carry, SIMD_CBIT, i); SIMD32_SET (psr, overflow, SIMD_VBIT, i); } break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } } break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } wC [wCASF] = psr; wR [BITS (12, 15)] = r; wC [wCon] |= (WCON_MUP | WCON_CUP); SET_wCSSFvec (satrv); #undef ADDx return ARMul_DONE; } static int WALIGNI (ARMword instr) { int shift = BITS (20, 22) * 8; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "waligni\n"); #endif if (shift) wR [BITS (12, 15)] = wRBITS (BITS (16, 19), shift, 63) | (wRBITS (BITS (0, 3), 0, shift) << ((64 - shift))); else wR [BITS (12, 15)] = wR [BITS (16, 19)]; wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int WALIGNR (ARMul_State * state, ARMword instr) { int shift = (wC [BITS (20, 21) + 8] & 0x7) * 8; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "walignr\n"); #endif if (shift) wR [BITS (12, 15)] = wRBITS (BITS (16, 19), shift, 63) | (wRBITS (BITS (0, 3), 0, shift) << ((64 - shift))); else wR [BITS (12, 15)] = wR [BITS (16, 19)]; wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int WAND (ARMword instr) { ARMdword result; ARMword psr = 0; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wand\n"); #endif result = wR [BITS (16, 19)] & wR [BITS (0, 3)]; wR [BITS (12, 15)] = result; SIMD64_SET (psr, (result == 0), SIMD_ZBIT); SIMD64_SET (psr, (result & (1ULL << 63)), SIMD_NBIT); wC [wCASF] = psr; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static int WANDN (ARMword instr) { ARMdword result; ARMword psr = 0; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wandn\n"); #endif result = wR [BITS (16, 19)] & ~ wR [BITS (0, 3)]; wR [BITS (12, 15)] = result; SIMD64_SET (psr, (result == 0), SIMD_ZBIT); SIMD64_SET (psr, (result & (1ULL << 63)), SIMD_NBIT); wC [wCASF] = psr; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static int WAVG2 (ARMword instr) { ARMdword r = 0; ARMword psr = 0; ARMdword s; int i; int round = BIT (20) ? 1 : 0; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wavg2\n"); #endif #define AVG2x(x, y, m) (((wRBITS (BITS (16, 19), (x), (y)) & (m)) \ + (wRBITS (BITS ( 0, 3), (x), (y)) & (m)) \ + round) / 2) if (BIT (22)) { for (i = 0; i < 4; i++) { s = AVG2x ((i * 16), (i * 16) + 15, 0xffff) & 0xffff; SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); r |= s << (i * 16); } } else { for (i = 0; i < 8; i++) { s = AVG2x ((i * 8), (i * 8) + 7, 0xff) & 0xff; SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i); r |= s << (i * 8); } } wR [BITS (12, 15)] = r; wC [wCASF] = psr; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static int WCMPEQ (ARMul_State * state, ARMword instr) { ARMdword r = 0; ARMword psr = 0; ARMdword s; int i; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wcmpeq\n"); #endif switch (BITS (22, 23)) { case Bqual: for (i = 0; i < 8; i++) { s = wRBYTE (BITS (16, 19), i) == wRBYTE (BITS (0, 3), i) ? 0xff : 0; r |= s << (i * 8); SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i); SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i); } break; case Hqual: for (i = 0; i < 4; i++) { s = wRHALF (BITS (16, 19), i) == wRHALF (BITS (0, 3), i) ? 0xffff : 0; r |= s << (i * 16); SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); } break; case Wqual: for (i = 0; i < 2; i++) { s = wRWORD (BITS (16, 19), i) == wRWORD (BITS (0, 3), i) ? 0xffffffff : 0; r |= s << (i * 32); SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); } break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } wC [wCASF] = psr; wR [BITS (12, 15)] = r; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static int WCMPGT (ARMul_State * state, ARMword instr) { ARMdword r = 0; ARMword psr = 0; ARMdword s; int i; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wcmpgt\n"); #endif switch (BITS (22, 23)) { case Bqual: if (BIT (21)) { /* Use a signed comparison. */ for (i = 0; i < 8; i++) { signed char a, b; a = wRBYTE (BITS (16, 19), i); b = wRBYTE (BITS (0, 3), i); s = (a > b) ? 0xff : 0; r |= s << (i * 8); SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i); SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i); } } else { for (i = 0; i < 8; i++) { s = (wRBYTE (BITS (16, 19), i) > wRBYTE (BITS (0, 3), i)) ? 0xff : 0; r |= s << (i * 8); SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i); SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i); } } break; case Hqual: if (BIT (21)) { for (i = 0; i < 4; i++) { signed int a, b; a = wRHALF (BITS (16, 19), i); a = EXTEND16 (a); b = wRHALF (BITS (0, 3), i); b = EXTEND16 (b); s = (a > b) ? 0xffff : 0; r |= s << (i * 16); SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); } } else { for (i = 0; i < 4; i++) { s = (wRHALF (BITS (16, 19), i) > wRHALF (BITS (0, 3), i)) ? 0xffff : 0; r |= s << (i * 16); SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); } } break; case Wqual: if (BIT (21)) { for (i = 0; i < 2; i++) { signed long a, b; a = EXTEND32 (wRWORD (BITS (16, 19), i)); b = EXTEND32 (wRWORD (BITS (0, 3), i)); s = (a > b) ? 0xffffffff : 0; r |= s << (i * 32); SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); } } else { for (i = 0; i < 2; i++) { s = (wRWORD (BITS (16, 19), i) > wRWORD (BITS (0, 3), i)) ? 0xffffffff : 0; r |= s << (i * 32); SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); } } break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } wC [wCASF] = psr; wR [BITS (12, 15)] = r; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static ARMword Compute_Iwmmxt_Address (ARMul_State * state, ARMword instr, int * pFailed) { ARMword Rn; ARMword addr; ARMword offset; ARMword multiplier; * pFailed = 0; Rn = BITS (16, 19); addr = state->Reg [Rn]; offset = BITS (0, 7); multiplier = BIT (8) ? 4 : 1; if (BIT (24)) /* P */ { /* Pre Indexed Addressing. */ if (BIT (23)) addr += offset * multiplier; else addr -= offset * multiplier; /* Immediate Pre-Indexed. */ if (BIT (21)) /* W */ { if (Rn == 15) { /* Writeback into R15 is UNPREDICTABLE. */ #ifdef DEBUG fprintf (stderr, "iWMMXt: writeback into r15\n"); #endif * pFailed = 1; } else state->Reg [Rn] = addr; } } else { /* Post Indexed Addressing. */ if (BIT (21)) /* W */ { /* Handle the write back of the final address. */ if (Rn == 15) { /* Writeback into R15 is UNPREDICTABLE. */ #ifdef DEBUG fprintf (stderr, "iWMMXt: writeback into r15\n"); #endif * pFailed = 1; } else { ARMword increment; if (BIT (23)) increment = offset * multiplier; else increment = - (offset * multiplier); state->Reg [Rn] = addr + increment; } } else { /* P == 0, W == 0, U == 0 is UNPREDICTABLE. */ if (BIT (23) == 0) { #ifdef DEBUG fprintf (stderr, "iWMMXt: undefined addressing mode\n"); #endif * pFailed = 1; } } } return addr; } static ARMdword Iwmmxt_Load_Double_Word (ARMul_State * state, ARMword address) { ARMdword value; /* The address must be aligned on a 8 byte boundary. */ if (address & 0x7) { fprintf (stderr, "iWMMXt: At addr 0x%x: Unaligned double word load from 0x%x\n", (state->Reg[15] - 8) & ~0x3, address); #ifdef DEBUG #endif /* No need to check for alignment traps. An unaligned double word load with alignment trapping disabled is UNPREDICTABLE. */ ARMul_Abort (state, ARMul_DataAbortV); } /* Load the words. */ if (! state->bigendSig) { value = ARMul_LoadWordN (state, address + 4); value <<= 32; value |= ARMul_LoadWordN (state, address); } else { value = ARMul_LoadWordN (state, address); value <<= 32; value |= ARMul_LoadWordN (state, address + 4); } /* Check for data aborts. */ if (state->Aborted) ARMul_Abort (state, ARMul_DataAbortV); else ARMul_Icycles (state, 2, 0L); return value; } static ARMword Iwmmxt_Load_Word (ARMul_State * state, ARMword address) { ARMword value; /* Check for a misaligned address. */ if (address & 3) { if ((read_cp15_reg (1, 0, 0) & ARMul_CP15_R1_ALIGN)) ARMul_Abort (state, ARMul_DataAbortV); else address &= ~ 3; } value = ARMul_LoadWordN (state, address); if (state->Aborted) ARMul_Abort (state, ARMul_DataAbortV); else ARMul_Icycles (state, 1, 0L); return value; } static ARMword Iwmmxt_Load_Half_Word (ARMul_State * state, ARMword address) { ARMword value; /* Check for a misaligned address. */ if (address & 1) { if ((read_cp15_reg (1, 0, 0) & ARMul_CP15_R1_ALIGN)) ARMul_Abort (state, ARMul_DataAbortV); else address &= ~ 1; } value = ARMul_LoadHalfWord (state, address); if (state->Aborted) ARMul_Abort (state, ARMul_DataAbortV); else ARMul_Icycles (state, 1, 0L); return value; } static ARMword Iwmmxt_Load_Byte (ARMul_State * state, ARMword address) { ARMword value; value = ARMul_LoadByte (state, address); if (state->Aborted) ARMul_Abort (state, ARMul_DataAbortV); else ARMul_Icycles (state, 1, 0L); return value; } static void Iwmmxt_Store_Double_Word (ARMul_State * state, ARMword address, ARMdword value) { /* The address must be aligned on a 8 byte boundary. */ if (address & 0x7) { fprintf (stderr, "iWMMXt: At addr 0x%x: Unaligned double word store to 0x%x\n", (state->Reg[15] - 8) & ~0x3, address); #ifdef DEBUG #endif /* No need to check for alignment traps. An unaligned double word store with alignment trapping disabled is UNPREDICTABLE. */ ARMul_Abort (state, ARMul_DataAbortV); } /* Store the words. */ if (! state->bigendSig) { ARMul_StoreWordN (state, address, value); ARMul_StoreWordN (state, address + 4, value >> 32); } else { ARMul_StoreWordN (state, address + 4, value); ARMul_StoreWordN (state, address, value >> 32); } /* Check for data aborts. */ if (state->Aborted) ARMul_Abort (state, ARMul_DataAbortV); else ARMul_Icycles (state, 2, 0L); } static void Iwmmxt_Store_Word (ARMul_State * state, ARMword address, ARMword value) { /* Check for a misaligned address. */ if (address & 3) { if ((read_cp15_reg (1, 0, 0) & ARMul_CP15_R1_ALIGN)) ARMul_Abort (state, ARMul_DataAbortV); else address &= ~ 3; } ARMul_StoreWordN (state, address, value); if (state->Aborted) ARMul_Abort (state, ARMul_DataAbortV); } static void Iwmmxt_Store_Half_Word (ARMul_State * state, ARMword address, ARMword value) { /* Check for a misaligned address. */ if (address & 1) { if ((read_cp15_reg (1, 0, 0) & ARMul_CP15_R1_ALIGN)) ARMul_Abort (state, ARMul_DataAbortV); else address &= ~ 1; } ARMul_StoreHalfWord (state, address, value); if (state->Aborted) ARMul_Abort (state, ARMul_DataAbortV); } static void Iwmmxt_Store_Byte (ARMul_State * state, ARMword address, ARMword value) { ARMul_StoreByte (state, address, value); if (state->Aborted) ARMul_Abort (state, ARMul_DataAbortV); } static int WLDR (ARMul_State * state, ARMword instr) { ARMword address; int failed; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wldr\n"); #endif address = Compute_Iwmmxt_Address (state, instr, & failed); if (failed) return ARMul_CANT; if (BITS (28, 31) == 0xf) { /* WLDRW wCx */ wC [BITS (12, 15)] = Iwmmxt_Load_Word (state, address); } else if (BIT (8) == 0) { if (BIT (22) == 0) /* WLDRB */ wR [BITS (12, 15)] = Iwmmxt_Load_Byte (state, address); else /* WLDRH */ wR [BITS (12, 15)] = Iwmmxt_Load_Half_Word (state, address); } else { if (BIT (22) == 0) /* WLDRW wRd */ wR [BITS (12, 15)] = Iwmmxt_Load_Word (state, address); else /* WLDRD */ wR [BITS (12, 15)] = Iwmmxt_Load_Double_Word (state, address); } wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int WMAC (ARMword instr) { int i; ARMdword t = 0; ARMword a, b; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wmac\n"); #endif for (i = 0; i < 4; i++) { if (BIT (21)) { /* Signed. */ signed long s; a = wRHALF (BITS (16, 19), i); a = EXTEND16 (a); b = wRHALF (BITS (0, 3), i); b = EXTEND16 (b); s = (signed long) a * (signed long) b; t = t + (ARMdword) s; } else { /* Unsigned. */ a = wRHALF (BITS (16, 19), i); b = wRHALF (BITS ( 0, 3), i); t += a * b; } } if (BIT (21)) t = EXTEND32 (t); else t &= 0xffffffff; if (BIT (20)) wR [BITS (12, 15)] = t; else wR[BITS (12, 15)] += t; wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int WMADD (ARMword instr) { ARMdword r = 0; int i; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wmadd\n"); #endif for (i = 0; i < 2; i++) { ARMdword s1, s2; if (BIT (21)) /* Signed. */ { signed long a, b; a = wRHALF (BITS (16, 19), i * 2); a = EXTEND16 (a); b = wRHALF (BITS (0, 3), i * 2); b = EXTEND16 (b); s1 = (ARMdword) (a * b); a = wRHALF (BITS (16, 19), i * 2 + 1); a = EXTEND16 (a); b = wRHALF (BITS (0, 3), i * 2 + 1); b = EXTEND16 (b); s2 = (ARMdword) (a * b); } else /* Unsigned. */ { unsigned long a, b; a = wRHALF (BITS (16, 19), i * 2); b = wRHALF (BITS ( 0, 3), i * 2); s1 = (ARMdword) (a * b); a = wRHALF (BITS (16, 19), i * 2 + 1); b = wRHALF (BITS ( 0, 3), i * 2 + 1); s2 = (ARMdword) a * b; } r |= (ARMdword) ((s1 + s2) & 0xffffffff) << (i ? 32 : 0); } wR [BITS (12, 15)] = r; wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int WMAX (ARMul_State * state, ARMword instr) { ARMdword r = 0; ARMdword s; int i; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wmax\n"); #endif switch (BITS (22, 23)) { case Bqual: for (i = 0; i < 8; i++) if (BIT (21)) /* Signed. */ { int a, b; a = wRBYTE (BITS (16, 19), i); a = EXTEND8 (a); b = wRBYTE (BITS (0, 3), i); b = EXTEND8 (b); if (a > b) s = a; else s = b; r |= (s & 0xff) << (i * 8); } else /* Unsigned. */ { unsigned int a, b; a = wRBYTE (BITS (16, 19), i); b = wRBYTE (BITS (0, 3), i); if (a > b) s = a; else s = b; r |= (s & 0xff) << (i * 8); } break; case Hqual: for (i = 0; i < 4; i++) if (BIT (21)) /* Signed. */ { int a, b; a = wRHALF (BITS (16, 19), i); a = EXTEND16 (a); b = wRHALF (BITS (0, 3), i); b = EXTEND16 (b); if (a > b) s = a; else s = b; r |= (s & 0xffff) << (i * 16); } else /* Unsigned. */ { unsigned int a, b; a = wRHALF (BITS (16, 19), i); b = wRHALF (BITS (0, 3), i); if (a > b) s = a; else s = b; r |= (s & 0xffff) << (i * 16); } break; case Wqual: for (i = 0; i < 2; i++) if (BIT (21)) /* Signed. */ { int a, b; a = wRWORD (BITS (16, 19), i); b = wRWORD (BITS (0, 3), i); if (a > b) s = a; else s = b; r |= (s & 0xffffffff) << (i * 32); } else { unsigned int a, b; a = wRWORD (BITS (16, 19), i); b = wRWORD (BITS (0, 3), i); if (a > b) s = a; else s = b; r |= (s & 0xffffffff) << (i * 32); } break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } wR [BITS (12, 15)] = r; wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int WMIN (ARMul_State * state, ARMword instr) { ARMdword r = 0; ARMdword s; int i; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wmin\n"); #endif switch (BITS (22, 23)) { case Bqual: for (i = 0; i < 8; i++) if (BIT (21)) /* Signed. */ { int a, b; a = wRBYTE (BITS (16, 19), i); a = EXTEND8 (a); b = wRBYTE (BITS (0, 3), i); b = EXTEND8 (b); if (a < b) s = a; else s = b; r |= (s & 0xff) << (i * 8); } else /* Unsigned. */ { unsigned int a, b; a = wRBYTE (BITS (16, 19), i); b = wRBYTE (BITS (0, 3), i); if (a < b) s = a; else s = b; r |= (s & 0xff) << (i * 8); } break; case Hqual: for (i = 0; i < 4; i++) if (BIT (21)) /* Signed. */ { int a, b; a = wRHALF (BITS (16, 19), i); a = EXTEND16 (a); b = wRHALF (BITS (0, 3), i); b = EXTEND16 (b); if (a < b) s = a; else s = b; r |= (s & 0xffff) << (i * 16); } else { /* Unsigned. */ unsigned int a, b; a = wRHALF (BITS (16, 19), i); b = wRHALF (BITS ( 0, 3), i); if (a < b) s = a; else s = b; r |= (s & 0xffff) << (i * 16); } break; case Wqual: for (i = 0; i < 2; i++) if (BIT (21)) /* Signed. */ { int a, b; a = wRWORD (BITS (16, 19), i); b = wRWORD (BITS ( 0, 3), i); if (a < b) s = a; else s = b; r |= (s & 0xffffffff) << (i * 32); } else { unsigned int a, b; a = wRWORD (BITS (16, 19), i); b = wRWORD (BITS (0, 3), i); if (a < b) s = a; else s = b; r |= (s & 0xffffffff) << (i * 32); } break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } wR [BITS (12, 15)] = r; wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int WMUL (ARMword instr) { ARMdword r = 0; ARMdword s; int i; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wmul\n"); #endif for (i = 0; i < 4; i++) if (BIT (21)) /* Signed. */ { long a, b; a = wRHALF (BITS (16, 19), i); a = EXTEND16 (a); b = wRHALF (BITS (0, 3), i); b = EXTEND16 (b); s = a * b; if (BIT (20)) r |= ((s >> 16) & 0xffff) << (i * 16); else r |= (s & 0xffff) << (i * 16); } else /* Unsigned. */ { unsigned long a, b; a = wRHALF (BITS (16, 19), i); b = wRHALF (BITS (0, 3), i); s = a * b; if (BIT (20)) r |= ((s >> 16) & 0xffff) << (i * 16); else r |= (s & 0xffff) << (i * 16); } wR [BITS (12, 15)] = r; wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int WOR (ARMword instr) { ARMword psr = 0; ARMdword result; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wor\n"); #endif result = wR [BITS (16, 19)] | wR [BITS (0, 3)]; wR [BITS (12, 15)] = result; SIMD64_SET (psr, (result == 0), SIMD_ZBIT); SIMD64_SET (psr, (result & (1ULL << 63)), SIMD_NBIT); wC [wCASF] = psr; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static int WPACK (ARMul_State * state, ARMword instr) { ARMdword r = 0; ARMword psr = 0; ARMdword x; ARMdword s; int i; int satrv[8]; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wpack\n"); #endif switch (BITS (22, 23)) { case Hqual: for (i = 0; i < 8; i++) { x = wRHALF (i < 4 ? BITS (16, 19) : BITS (0, 3), i & 3); switch (BITS (20, 21)) { case UnsignedSaturation: s = IwmmxtSaturateU8 (x, satrv + BITIDX8 (i)); break; case SignedSaturation: s = IwmmxtSaturateS8 (x, satrv + BITIDX8 (i)); break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } r |= (s & 0xff) << (i * 8); SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i); SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i); } break; case Wqual: satrv[0] = satrv[2] = satrv[4] = satrv[6] = 0; for (i = 0; i < 4; i++) { x = wRWORD (i < 2 ? BITS (16, 19) : BITS (0, 3), i & 1); switch (BITS (20, 21)) { case UnsignedSaturation: s = IwmmxtSaturateU16 (x, satrv + BITIDX16 (i)); break; case SignedSaturation: s = IwmmxtSaturateS16 (x, satrv + BITIDX16 (i)); break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } r |= (s & 0xffff) << (i * 16); SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); } break; case Dqual: satrv[0] = satrv[1] = satrv[2] = satrv[4] = satrv[5] = satrv[6] = 0; for (i = 0; i < 2; i++) { x = wR [i ? BITS (0, 3) : BITS (16, 19)]; switch (BITS (20, 21)) { case UnsignedSaturation: s = IwmmxtSaturateU32 (x, satrv + BITIDX32 (i)); break; case SignedSaturation: s = IwmmxtSaturateS32 (x, satrv + BITIDX32 (i)); break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } r |= (s & 0xffffffff) << (i * 32); SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); } break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } wC [wCASF] = psr; wR [BITS (12, 15)] = r; SET_wCSSFvec (satrv); wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static int WROR (ARMul_State * state, ARMword instr) { ARMdword r = 0; ARMdword s; ARMword psr = 0; int i; int shift; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wror\n"); #endif DECODE_G_BIT (state, instr, shift); switch (BITS (22, 23)) { case Hqual: shift &= 0xf; for (i = 0; i < 4; i++) { s = ((wRHALF (BITS (16, 19), i) & 0xffff) << (16 - shift)) | ((wRHALF (BITS (16, 19), i) & 0xffff) >> shift); r |= (s & 0xffff) << (i * 16); SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); } break; case Wqual: shift &= 0x1f; for (i = 0; i < 2; i++) { s = ((wRWORD (BITS (16, 19), i) & 0xffffffff) << (32 - shift)) | ((wRWORD (BITS (16, 19), i) & 0xffffffff) >> shift); r |= (s & 0xffffffff) << (i * 32); SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); } break; case Dqual: shift &= 0x3f; r = (wR [BITS (16, 19)] >> shift) | (wR [BITS (16, 19)] << (64 - shift)); SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT); SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT); break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } wC [wCASF] = psr; wR [BITS (12, 15)] = r; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static int WSAD (ARMword instr) { ARMdword r; int s; int i; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wsad\n"); #endif /* Z bit. */ r = BIT (20) ? 0 : (wR [BITS (12, 15)] & 0xffffffff); if (BIT (22)) /* Half. */ for (i = 0; i < 4; i++) { s = (wRHALF (BITS (16, 19), i) - wRHALF (BITS (0, 3), i)); r += abs (s); } else /* Byte. */ for (i = 0; i < 8; i++) { s = (wRBYTE (BITS (16, 19), i) - wRBYTE (BITS (0, 3), i)); r += abs (s); } wR [BITS (12, 15)] = r; wC [wCon] |= WCON_MUP; return ARMul_DONE; } static int WSHUFH (ARMword instr) { ARMdword r = 0; ARMword psr = 0; ARMdword s; int i; int imm8; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wshufh\n"); #endif imm8 = (BITS (20, 23) << 4) | BITS (0, 3); for (i = 0; i < 4; i++) { s = wRHALF (BITS (16, 19), ((imm8 >> (i * 2) & 3)) & 0xff); r |= (s & 0xffff) << (i * 16); SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); } wC [wCASF] = psr; wR [BITS (12, 15)] = r; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static int WSLL (ARMul_State * state, ARMword instr) { ARMdword r = 0; ARMdword s; ARMword psr = 0; int i; unsigned shift; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wsll\n"); #endif DECODE_G_BIT (state, instr, shift); switch (BITS (22, 23)) { case Hqual: for (i = 0; i < 4; i++) { if (shift > 15) s = 0; else s = ((wRHALF (BITS (16, 19), i) & 0xffff) << shift); r |= (s & 0xffff) << (i * 16); SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); } break; case Wqual: for (i = 0; i < 2; i++) { if (shift > 31) s = 0; else s = ((wRWORD (BITS (16, 19), i) & 0xffffffff) << shift); r |= (s & 0xffffffff) << (i * 32); SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); } break; case Dqual: if (shift > 63) r = 0; else r = ((wR[BITS (16, 19)] & 0xffffffffffffffffULL) << shift); SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT); SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT); break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } wC [wCASF] = psr; wR [BITS (12, 15)] = r; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static int WSRA (ARMul_State * state, ARMword instr) { ARMdword r = 0; ARMdword s; ARMword psr = 0; int i; unsigned shift; signed long t; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wsra\n"); #endif DECODE_G_BIT (state, instr, shift); switch (BITS (22, 23)) { case Hqual: for (i = 0; i < 4; i++) { if (shift > 15) t = (wRHALF (BITS (16, 19), i) & 0x8000) ? 0xffff : 0; else { t = wRHALF (BITS (16, 19), i); t = EXTEND16 (t); t >>= shift; } s = t; r |= (s & 0xffff) << (i * 16); SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); } break; case Wqual: for (i = 0; i < 2; i++) { if (shift > 31) t = (wRWORD (BITS (16, 19), i) & 0x80000000) ? 0xffffffff : 0; else { t = EXTEND32 (wRWORD (BITS (16, 19), i)); t >>= shift; } s = t; r |= (s & 0xffffffff) << (i * 32); SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); } break; case Dqual: if (shift > 63) r = (wR [BITS (16, 19)] & 0x8000000000000000ULL) ? 0xffffffffffffffffULL : 0; else r = ((signed long long) (wR[BITS (16, 19)] & 0xffffffffffffffffULL) >> shift); SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT); SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT); break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } wC [wCASF] = psr; wR [BITS (12, 15)] = r; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static int WSRL (ARMul_State * state, ARMword instr) { ARMdword r = 0; ARMdword s; ARMword psr = 0; int i; unsigned int shift; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wsrl\n"); #endif DECODE_G_BIT (state, instr, shift); switch (BITS (22, 23)) { case Hqual: for (i = 0; i < 4; i++) { if (shift > 15) s = 0; else s = ((unsigned) (wRHALF (BITS (16, 19), i) & 0xffff) >> shift); r |= (s & 0xffff) << (i * 16); SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); } break; case Wqual: for (i = 0; i < 2; i++) { if (shift > 31) s = 0; else s = ((unsigned long) (wRWORD (BITS (16, 19), i) & 0xffffffff) >> shift); r |= (s & 0xffffffff) << (i * 32); SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); } break; case Dqual: if (shift > 63) r = 0; else r = (wR [BITS (16, 19)] & 0xffffffffffffffffULL) >> shift; SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT); SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT); break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } wC [wCASF] = psr; wR [BITS (12, 15)] = r; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static int WSTR (ARMul_State * state, ARMword instr) { ARMword address; int failed; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wstr\n"); #endif address = Compute_Iwmmxt_Address (state, instr, & failed); if (failed) return ARMul_CANT; if (BITS (28, 31) == 0xf) { /* WSTRW wCx */ Iwmmxt_Store_Word (state, address, wC [BITS (12, 15)]); } else if (BIT (8) == 0) { if (BIT (22) == 0) /* WSTRB */ Iwmmxt_Store_Byte (state, address, wR [BITS (12, 15)]); else /* WSTRH */ Iwmmxt_Store_Half_Word (state, address, wR [BITS (12, 15)]); } else { if (BIT (22) == 0) /* WSTRW wRd */ Iwmmxt_Store_Word (state, address, wR [BITS (12, 15)]); else /* WSTRD */ Iwmmxt_Store_Double_Word (state, address, wR [BITS (12, 15)]); } return ARMul_DONE; } static int WSUB (ARMul_State * state, ARMword instr) { ARMdword r = 0; ARMword psr = 0; ARMdword x; ARMdword s; int i; int carry; int overflow; int satrv[8]; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wsub\n"); #endif /* Subtract two numbers using the specified function, leaving setting the carry bit as required. */ #define SUBx(x, y, m, f) \ (*f) (wRBITS (BITS (16, 19), (x), (y)) & (m), \ wRBITS (BITS ( 0, 3), (x), (y)) & (m), & carry, & overflow) switch (BITS (22, 23)) { case Bqual: for (i = 0; i < 8; i++) { switch (BITS (20, 21)) { case NoSaturation: s = SUBx ((i * 8), (i * 8) + 7, 0xff, SubS8); satrv [BITIDX8 (i)] = 0; r |= (s & 0xff) << (i * 8); SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i); SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i); SIMD8_SET (psr, carry, SIMD_CBIT, i); SIMD8_SET (psr, overflow, SIMD_VBIT, i); break; case UnsignedSaturation: s = SUBx ((i * 8), (i * 8) + 7, 0xff, SubU8); x = IwmmxtSaturateU8 (s, satrv + BITIDX8 (i)); r |= (x & 0xff) << (i * 8); SIMD8_SET (psr, NBIT8 (x), SIMD_NBIT, i); SIMD8_SET (psr, ZBIT8 (x), SIMD_ZBIT, i); if (! satrv [BITIDX8 (i)]) { SIMD8_SET (psr, carry, SIMD_CBIT, i); SIMD8_SET (psr, overflow, SIMD_VBIT, i); } break; case SignedSaturation: s = SUBx ((i * 8), (i * 8) + 7, 0xff, SubS8); x = IwmmxtSaturateS8 (s, satrv + BITIDX8 (i)); r |= (x & 0xff) << (i * 8); SIMD8_SET (psr, NBIT8 (x), SIMD_NBIT, i); SIMD8_SET (psr, ZBIT8 (x), SIMD_ZBIT, i); if (! satrv [BITIDX8 (i)]) { SIMD8_SET (psr, carry, SIMD_CBIT, i); SIMD8_SET (psr, overflow, SIMD_VBIT, i); } break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } } break; case Hqual: satrv[0] = satrv[2] = satrv[4] = satrv[6] = 0; for (i = 0; i < 4; i++) { switch (BITS (20, 21)) { case NoSaturation: s = SUBx ((i * 16), (i * 16) + 15, 0xffff, SubU16); satrv [BITIDX16 (i)] = 0; r |= (s & 0xffff) << (i * 16); SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); SIMD16_SET (psr, carry, SIMD_CBIT, i); SIMD16_SET (psr, overflow, SIMD_VBIT, i); break; case UnsignedSaturation: s = SUBx ((i * 16), (i * 16) + 15, 0xffff, SubU16); x = IwmmxtSaturateU16 (s, satrv + BITIDX16 (i)); r |= (x & 0xffff) << (i * 16); SIMD16_SET (psr, NBIT16 (x & 0xffff), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (x), SIMD_ZBIT, i); if (! satrv [BITIDX16 (i)]) { SIMD16_SET (psr, carry, SIMD_CBIT, i); SIMD16_SET (psr, overflow, SIMD_VBIT, i); } break; case SignedSaturation: s = SUBx ((i * 16), (i * 16) + 15, 0xffff, SubS16); x = IwmmxtSaturateS16 (s, satrv + BITIDX16 (i)); r |= (x & 0xffff) << (i * 16); SIMD16_SET (psr, NBIT16 (x), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (x), SIMD_ZBIT, i); if (! satrv [BITIDX16 (i)]) { SIMD16_SET (psr, carry, SIMD_CBIT, i); SIMD16_SET (psr, overflow, SIMD_VBIT, i); } break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } } break; case Wqual: satrv[0] = satrv[1] = satrv[2] = satrv[4] = satrv[5] = satrv[6] = 0; for (i = 0; i < 2; i++) { switch (BITS (20, 21)) { case NoSaturation: s = SUBx ((i * 32), (i * 32) + 31, 0xffffffff, SubU32); satrv[BITIDX32 (i)] = 0; r |= (s & 0xffffffff) << (i * 32); SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); SIMD32_SET (psr, carry, SIMD_CBIT, i); SIMD32_SET (psr, overflow, SIMD_VBIT, i); break; case UnsignedSaturation: s = SUBx ((i * 32), (i * 32) + 31, 0xffffffff, SubU32); x = IwmmxtSaturateU32 (s, satrv + BITIDX32 (i)); r |= (x & 0xffffffff) << (i * 32); SIMD32_SET (psr, NBIT32 (x), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (x), SIMD_ZBIT, i); if (! satrv [BITIDX32 (i)]) { SIMD32_SET (psr, carry, SIMD_CBIT, i); SIMD32_SET (psr, overflow, SIMD_VBIT, i); } break; case SignedSaturation: s = SUBx ((i * 32), (i * 32) + 31, 0xffffffff, SubS32); x = IwmmxtSaturateS32 (s, satrv + BITIDX32 (i)); r |= (x & 0xffffffff) << (i * 32); SIMD32_SET (psr, NBIT32 (x), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (x), SIMD_ZBIT, i); if (! satrv [BITIDX32 (i)]) { SIMD32_SET (psr, carry, SIMD_CBIT, i); SIMD32_SET (psr, overflow, SIMD_VBIT, i); } break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } } break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } wR [BITS (12, 15)] = r; wC [wCASF] = psr; SET_wCSSFvec (satrv); wC [wCon] |= (WCON_CUP | WCON_MUP); #undef SUBx return ARMul_DONE; } static int WUNPCKEH (ARMul_State * state, ARMword instr) { ARMdword r = 0; ARMword psr = 0; ARMdword s; int i; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wunpckeh\n"); #endif switch (BITS (22, 23)) { case Bqual: for (i = 0; i < 4; i++) { s = wRBYTE (BITS (16, 19), i + 4); if (BIT (21) && NBIT8 (s)) s |= 0xff00; r |= (s & 0xffff) << (i * 16); SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); } break; case Hqual: for (i = 0; i < 2; i++) { s = wRHALF (BITS (16, 19), i + 2); if (BIT (21) && NBIT16 (s)) s |= 0xffff0000; r |= (s & 0xffffffff) << (i * 32); SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); } break; case Wqual: r = wRWORD (BITS (16, 19), 1); if (BIT (21) && NBIT32 (r)) r |= 0xffffffff00000000ULL; SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT); SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT); break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } wC [wCASF] = psr; wR [BITS (12, 15)] = r; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static int WUNPCKEL (ARMul_State * state, ARMword instr) { ARMdword r = 0; ARMword psr = 0; ARMdword s; int i; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wunpckel\n"); #endif switch (BITS (22, 23)) { case Bqual: for (i = 0; i < 4; i++) { s = wRBYTE (BITS (16, 19), i); if (BIT (21) && NBIT8 (s)) s |= 0xff00; r |= (s & 0xffff) << (i * 16); SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); } break; case Hqual: for (i = 0; i < 2; i++) { s = wRHALF (BITS (16, 19), i); if (BIT (21) && NBIT16 (s)) s |= 0xffff0000; r |= (s & 0xffffffff) << (i * 32); SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); } break; case Wqual: r = wRWORD (BITS (16, 19), 0); if (BIT (21) && NBIT32 (r)) r |= 0xffffffff00000000ULL; SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT); SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT); break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } wC [wCASF] = psr; wR [BITS (12, 15)] = r; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static int WUNPCKIH (ARMul_State * state, ARMword instr) { ARMword a, b; ARMdword r = 0; ARMword psr = 0; ARMdword s; int i; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wunpckih\n"); #endif switch (BITS (22, 23)) { case Bqual: for (i = 0; i < 4; i++) { a = wRBYTE (BITS (16, 19), i + 4); b = wRBYTE (BITS ( 0, 3), i + 4); s = a | (b << 8); r |= (s & 0xffff) << (i * 16); SIMD8_SET (psr, NBIT8 (a), SIMD_NBIT, i * 2); SIMD8_SET (psr, ZBIT8 (a), SIMD_ZBIT, i * 2); SIMD8_SET (psr, NBIT8 (b), SIMD_NBIT, (i * 2) + 1); SIMD8_SET (psr, ZBIT8 (b), SIMD_ZBIT, (i * 2) + 1); } break; case Hqual: for (i = 0; i < 2; i++) { a = wRHALF (BITS (16, 19), i + 2); b = wRHALF (BITS ( 0, 3), i + 2); s = a | (b << 16); r |= (s & 0xffffffff) << (i * 32); SIMD16_SET (psr, NBIT16 (a), SIMD_NBIT, (i * 2)); SIMD16_SET (psr, ZBIT16 (a), SIMD_ZBIT, (i * 2)); SIMD16_SET (psr, NBIT16 (b), SIMD_NBIT, (i * 2) + 1); SIMD16_SET (psr, ZBIT16 (b), SIMD_ZBIT, (i * 2) + 1); } break; case Wqual: a = wRWORD (BITS (16, 19), 1); s = wRWORD (BITS ( 0, 3), 1); r = a | (s << 32); SIMD32_SET (psr, NBIT32 (a), SIMD_NBIT, 0); SIMD32_SET (psr, ZBIT32 (a), SIMD_ZBIT, 0); SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, 1); SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, 1); break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } wC [wCASF] = psr; wR [BITS (12, 15)] = r; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static int WUNPCKIL (ARMul_State * state, ARMword instr) { ARMword a, b; ARMdword r = 0; ARMword psr = 0; ARMdword s; int i; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wunpckil\n"); #endif switch (BITS (22, 23)) { case Bqual: for (i = 0; i < 4; i++) { a = wRBYTE (BITS (16, 19), i); b = wRBYTE (BITS ( 0, 3), i); s = a | (b << 8); r |= (s & 0xffff) << (i * 16); SIMD8_SET (psr, NBIT8 (a), SIMD_NBIT, i * 2); SIMD8_SET (psr, ZBIT8 (a), SIMD_ZBIT, i * 2); SIMD8_SET (psr, NBIT8 (b), SIMD_NBIT, (i * 2) + 1); SIMD8_SET (psr, ZBIT8 (b), SIMD_ZBIT, (i * 2) + 1); } break; case Hqual: for (i = 0; i < 2; i++) { a = wRHALF (BITS (16, 19), i); b = wRHALF (BITS ( 0, 3), i); s = a | (b << 16); r |= (s & 0xffffffff) << (i * 32); SIMD16_SET (psr, NBIT16 (a), SIMD_NBIT, (i * 2)); SIMD16_SET (psr, ZBIT16 (a), SIMD_ZBIT, (i * 2)); SIMD16_SET (psr, NBIT16 (b), SIMD_NBIT, (i * 2) + 1); SIMD16_SET (psr, ZBIT16 (b), SIMD_ZBIT, (i * 2) + 1); } break; case Wqual: a = wRWORD (BITS (16, 19), 0); s = wRWORD (BITS ( 0, 3), 0); r = a | (s << 32); SIMD32_SET (psr, NBIT32 (a), SIMD_NBIT, 0); SIMD32_SET (psr, ZBIT32 (a), SIMD_ZBIT, 0); SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, 1); SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, 1); break; default: ARMul_UndefInstr (state, instr); return ARMul_DONE; } wC [wCASF] = psr; wR [BITS (12, 15)] = r; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } static int WXOR (ARMword instr) { ARMword psr = 0; ARMdword result; if ((read_cp15_reg (15, 0, 1) & 3) != 3) return ARMul_CANT; #ifdef DEBUG fprintf (stderr, "wxor\n"); #endif result = wR [BITS (16, 19)] ^ wR [BITS (0, 3)]; wR [BITS (12, 15)] = result; SIMD64_SET (psr, (result == 0), SIMD_ZBIT); SIMD64_SET (psr, (result & (1ULL << 63)), SIMD_NBIT); wC [wCASF] = psr; wC [wCon] |= (WCON_CUP | WCON_MUP); return ARMul_DONE; } /* This switch table is moved to a separate function in order to work around a compiler bug in the host compiler... */ static int Process_Instruction (ARMul_State * state, ARMword instr) { int status = ARMul_BUSY; switch ((BITS (20, 23) << 8) | BITS (4, 11)) { case 0x000: status = WOR (instr); break; case 0x011: status = TMCR (state, instr); break; case 0x100: status = WXOR (instr); break; case 0x111: status = TMRC (state, instr); break; case 0x300: status = WANDN (instr); break; case 0x200: status = WAND (instr); break; case 0x810: case 0xa10: status = WMADD (instr); break; case 0x10e: case 0x50e: case 0x90e: case 0xd0e: status = WUNPCKIL (state, instr); break; case 0x10c: case 0x50c: case 0x90c: case 0xd0c: status = WUNPCKIH (state, instr); break; case 0x012: case 0x112: case 0x412: case 0x512: status = WSAD (instr); break; case 0x010: case 0x110: case 0x210: case 0x310: status = WMUL (instr); break; case 0x410: case 0x510: case 0x610: case 0x710: status = WMAC (instr); break; case 0x006: case 0x406: case 0x806: case 0xc06: status = WCMPEQ (state, instr); break; case 0x800: case 0x900: case 0xc00: case 0xd00: status = WAVG2 (instr); break; case 0x802: case 0x902: case 0xa02: case 0xb02: status = WALIGNR (state, instr); break; case 0x601: case 0x605: case 0x609: case 0x60d: status = TINSR (state, instr); break; case 0x107: case 0x507: case 0x907: case 0xd07: status = TEXTRM (state, instr); break; case 0x117: case 0x517: case 0x917: case 0xd17: status = TEXTRC (state, instr); break; case 0x401: case 0x405: case 0x409: case 0x40d: status = TBCST (state, instr); break; case 0x113: case 0x513: case 0x913: case 0xd13: status = TANDC (state, instr); break; case 0x01c: case 0x41c: case 0x81c: case 0xc1c: status = WACC (state, instr); break; case 0x115: case 0x515: case 0x915: case 0xd15: status = TORC (state, instr); break; case 0x103: case 0x503: case 0x903: case 0xd03: status = TMOVMSK (state, instr); break; case 0x106: case 0x306: case 0x506: case 0x706: case 0x906: case 0xb06: case 0xd06: case 0xf06: status = WCMPGT (state, instr); break; case 0x00e: case 0x20e: case 0x40e: case 0x60e: case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e: status = WUNPCKEL (state, instr); break; case 0x00c: case 0x20c: case 0x40c: case 0x60c: case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c: status = WUNPCKEH (state, instr); break; case 0x204: case 0x604: case 0xa04: case 0xe04: case 0x214: case 0x614: case 0xa14: case 0xe14: status = WSRL (state, instr); break; case 0x004: case 0x404: case 0x804: case 0xc04: case 0x014: case 0x414: case 0x814: case 0xc14: status = WSRA (state, instr); break; case 0x104: case 0x504: case 0x904: case 0xd04: case 0x114: case 0x514: case 0x914: case 0xd14: status = WSLL (state, instr); break; case 0x304: case 0x704: case 0xb04: case 0xf04: case 0x314: case 0x714: case 0xb14: case 0xf14: status = WROR (state, instr); break; case 0x116: case 0x316: case 0x516: case 0x716: case 0x916: case 0xb16: case 0xd16: case 0xf16: status = WMIN (state, instr); break; case 0x016: case 0x216: case 0x416: case 0x616: case 0x816: case 0xa16: case 0xc16: case 0xe16: status = WMAX (state, instr); break; case 0x002: case 0x102: case 0x202: case 0x302: case 0x402: case 0x502: case 0x602: case 0x702: status = WALIGNI (instr); break; case 0x01a: case 0x11a: case 0x21a: case 0x31a: case 0x41a: case 0x51a: case 0x61a: case 0x71a: case 0x81a: case 0x91a: case 0xa1a: case 0xb1a: case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a: status = WSUB (state, instr); break; case 0x01e: case 0x11e: case 0x21e: case 0x31e: case 0x41e: case 0x51e: case 0x61e: case 0x71e: case 0x81e: case 0x91e: case 0xa1e: case 0xb1e: case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e: status = WSHUFH (instr); break; case 0x018: case 0x118: case 0x218: case 0x318: case 0x418: case 0x518: case 0x618: case 0x718: case 0x818: case 0x918: case 0xa18: case 0xb18: case 0xc18: case 0xd18: case 0xe18: case 0xf18: status = WADD (state, instr); break; case 0x008: case 0x108: case 0x208: case 0x308: case 0x408: case 0x508: case 0x608: case 0x708: case 0x808: case 0x908: case 0xa08: case 0xb08: case 0xc08: case 0xd08: case 0xe08: case 0xf08: status = WPACK (state, instr); break; case 0x201: case 0x203: case 0x205: case 0x207: case 0x209: case 0x20b: case 0x20d: case 0x20f: case 0x211: case 0x213: case 0x215: case 0x217: case 0x219: case 0x21b: case 0x21d: case 0x21f: switch (BITS (16, 19)) { case 0x0: status = TMIA (state, instr); break; case 0x8: status = TMIAPH (state, instr); break; case 0xc: case 0xd: case 0xe: case 0xf: status = TMIAxy (state, instr); break; default: break; } break; default: break; } return status; } /* Process a possibly Intel(r) Wireless MMX(tm) technology instruction. Return true if the instruction was handled. */ int ARMul_HandleIwmmxt (ARMul_State * state, ARMword instr) { int status = ARMul_BUSY; if (BITS (24, 27) == 0xe) { status = Process_Instruction (state, instr); } else if (BITS (25, 27) == 0x6) { if (BITS (4, 11) == 0x0 && BITS (20, 24) == 0x4) status = TMCRR (state, instr); else if (BITS (9, 11) == 0x0) { if (BIT (20) == 0x0) status = WSTR (state, instr); else if (BITS (20, 24) == 0x5) status = TMRRC (state, instr); else status = WLDR (state, instr); } } if (status == ARMul_CANT) { /* If the instruction was a recognised but illegal, perform the abort here rather than returning false. If we return false then ARMul_MRC may be called which will still abort, but which also perform the register transfer... */ ARMul_Abort (state, ARMul_UndefinedInstrV); status = ARMul_DONE; } return status == ARMul_DONE; } int Fetch_Iwmmxt_Register (unsigned int regnum, unsigned char * memory) { if (regnum >= 16) { memcpy (memory, wC + (regnum - 16), sizeof wC [0]); return sizeof wC [0]; } else { memcpy (memory, wR + regnum, sizeof wR [0]); return sizeof wR [0]; } } int Store_Iwmmxt_Register (unsigned int regnum, unsigned char * memory) { if (regnum >= 16) { memcpy (wC + (regnum - 16), memory, sizeof wC [0]); return sizeof wC [0]; } else { memcpy (wR + regnum, memory, sizeof wR [0]); return sizeof wR [0]; } }