|  | /*  iwmmxt.c -- Intel(r) Wireless MMX(tm) technology co-processor interface. | 
|  | Copyright (C) 2002-2023 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 <http://www.gnu.org/licenses/>. */ | 
|  |  | 
|  | /* This must come before any other includes.  */ | 
|  | #include "defs.h" | 
|  |  | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #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, const 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]; | 
|  | } | 
|  | } |