/* iwmmxt.c -- Intel(r) Wireless MMX(tm) technology co-processor interface.
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002-2019 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 2 of the License, or
+ 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <string.h>
#include "armdefs.h"
#include "armos.h"
/* #define DEBUG 1 */
-/* Intel(r) Wireless MMX(tm) technology co-processor.
+/* 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. */
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;
}
IwmmxtSaturateS16 (signed int val, int * sat)
{
signed short rv;
-
+
if (val < -0x8000)
{
rv = - 0x8000;
IwmmxtSaturateS32 (signed long long val, int * sat)
{
signed long rv;
-
+
if (val < -0x80000000LL)
{
rv = -0x80000000;
#ifdef DEBUG
fprintf (stderr, "tandc\n");
-#endif
+#endif
/* The Rd field must be r15. */
if (BITS (12, 15) != 15)
ARMul_UndefInstr (state, instr);
return ARMul_DONE;
}
-
+
ARMul_SetCPSR (state, cpsr);
return ARMul_DONE;
#ifdef DEBUG
fprintf (stderr, "tbcst\n");
-#endif
+#endif
Rn = state->Reg [BITS (12, 15)];
if (BITS (12, 15) == 15)
#ifdef DEBUG
fprintf (stderr, "textrc\n");
-#endif
+#endif
/* The Rd field must be r15. */
if (BITS (12, 15) != 15)
ARMul_UndefInstr (state, instr);
return ARMul_DONE;
}
-
+
cpsr |= wCBITS (wCASF, selector, selector + 3) << 28;
ARMul_SetCPSR (state, cpsr);
#ifdef DEBUG
fprintf (stderr, "textrm\n");
-#endif
+#endif
wRn = BITS (16, 19);
sign = BIT (3);
offset = BITS (0, 2);
-
+
switch (BITS (22, 23))
{
case Bqual:
switch (offset & 3)
{
- case 0: wR [wRd] = data | (wRBITS (wRd, 16, 63) << 16); break;
+ 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;
#ifdef DEBUG
fprintf (stderr, "tmcr\n");
-#endif
+#endif
if (BITS (0, 3) != 0)
return ARMul_CANT;
/* 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;
#ifdef DEBUG
fprintf (stderr, "tmcrr\n");
-#endif
+#endif
if ((BITS (16, 19) == 15) || (BITS (12, 15) == 15))
return ARMul_CANT;
#ifdef DEBUG
fprintf (stderr, "tmia\n");
-#endif
+#endif
if ((BITS (0, 3) == 15) || (BITS (12, 15) == 15))
{
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
+#endif
if (BITS (0, 3) == 15 || BITS (12, 15) == 15)
{
r = result;
r = EXTEND32 (r);
-
+
wR [BITS (5, 8)] += r;
a = SUBSTR (Rs, ARMword, 0, 15);
r = result;
r = EXTEND32 (r);
-
+
wR [BITS (5, 8)] += r;
wC [wCon] |= WCON_MUP;
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
+#endif
if (BITS (0, 3) == 15 || BITS (12, 15) == 15)
{
#ifdef DEBUG
fprintf (stderr, "tmovmsk\n");
-#endif
+#endif
/* The CRm field must be r0. */
if (BITS (0, 3) != 0)
#ifdef DEBUG
fprintf (stderr, "tmrc\n");
-#endif
+#endif
if (BITS (0, 3) != 0)
return ARMul_CANT;
#ifdef DEBUG
fprintf (stderr, "tmrrc\n");
-#endif
+#endif
if ((BITS (16, 19) == 15) || (BITS (12, 15) == 15) || (BITS (4, 11) != 0))
ARMul_UndefInstr (state, instr);
#ifdef DEBUG
fprintf (stderr, "torc\n");
-#endif
+#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;
ARMul_UndefInstr (state, instr);
return ARMul_DONE;
}
-
+
ARMul_SetCPSR (state, cpsr);
return ARMul_DONE;
#ifdef DEBUG
fprintf (stderr, "wacc\n");
-#endif
+#endif
wRn = BITS (16, 19);
#ifdef DEBUG
fprintf (stderr, "wadd\n");
-#endif
+#endif
/* Add two numbers using the specified function,
leaving setting the carry bit as required. */
wC [wCon] |= (WCON_MUP | WCON_CUP);
SET_wCSSFvec (satrv);
-
+
#undef ADDx
return ARMul_DONE;
#ifdef DEBUG
fprintf (stderr, "waligni\n");
-#endif
+#endif
if (shift)
wR [BITS (12, 15)] =
| (wRBITS (BITS (0, 3), 0, shift) << ((64 - shift)));
else
wR [BITS (12, 15)] = wR [BITS (16, 19)];
-
+
wC [wCon] |= WCON_MUP;
return ARMul_DONE;
}
#ifdef DEBUG
fprintf (stderr, "walignr\n");
-#endif
+#endif
if (shift)
wR [BITS (12, 15)] =
#ifdef DEBUG
fprintf (stderr, "wand\n");
-#endif
+#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);
#ifdef DEBUG
fprintf (stderr, "wandn\n");
-#endif
+#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);
#ifdef DEBUG
fprintf (stderr, "wavg2\n");
-#endif
+#endif
#define AVG2x(x, y, m) (((wRBITS (BITS (16, 19), (x), (y)) & (m)) \
+ (wRBITS (BITS ( 0, 3), (x), (y)) & (m)) \
#ifdef DEBUG
fprintf (stderr, "wcmpeq\n");
-#endif
+#endif
switch (BITS (22, 23))
{
#ifdef DEBUG
fprintf (stderr, "wcmpgt\n");
-#endif
+#endif
switch (BITS (22, 23))
{
for (i = 0; i < 8; i++)
{
signed char a, b;
-
+
a = wRBYTE (BITS (16, 19), i);
b = wRBYTE (BITS (0, 3), i);
{
signed long a, b;
- a = wRWORD (BITS (16, 19), i);
- b = wRWORD (BITS (0, 3), i);
+ 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);
}
/* Writeback into R15 is UNPREDICTABLE. */
#ifdef DEBUG
fprintf (stderr, "iWMMXt: writeback into r15\n");
-#endif
+#endif
* pFailed = 1;
}
else
{
#ifdef DEBUG
fprintf (stderr, "iWMMXt: undefined addressing mode\n");
-#endif
+#endif
* pFailed = 1;
}
}
Iwmmxt_Load_Double_Word (ARMul_State * state, ARMword address)
{
ARMdword value;
-
+
/* The address must be aligned on a 8 byte boundary. */
if (address & 0x7)
{
else
address &= ~ 3;
}
-
+
value = ARMul_LoadWordN (state, address);
if (state->Aborted)
#ifdef DEBUG
fprintf (stderr, "wldr\n");
-#endif
+#endif
address = Compute_Iwmmxt_Address (state, instr, & failed);
if (failed)
#ifdef DEBUG
fprintf (stderr, "wmac\n");
-#endif
+#endif
for (i = 0; i < 4; i++)
{
}
}
- if (BIT (20))
- wR [BITS (12, 15)] = 0;
+ if (BIT (21))
+ t = EXTEND32 (t);
+ else
+ t &= 0xffffffff;
- if (BIT (21)) /* Signed. */
- wR[BITS (12, 15)] += t;
+ if (BIT (20))
+ wR [BITS (12, 15)] = t;
else
- wR [BITS (12, 15)] += t;
+ wR[BITS (12, 15)] += t;
wC [wCon] |= WCON_MUP;
#ifdef DEBUG
fprintf (stderr, "wmadd\n");
-#endif
+#endif
for (i = 0; i < 2; i++)
{
#ifdef DEBUG
fprintf (stderr, "wmax\n");
-#endif
+#endif
switch (BITS (22, 23))
{
#ifdef DEBUG
fprintf (stderr, "wmin\n");
-#endif
+#endif
switch (BITS (22, 23))
{
wR [BITS (12, 15)] = r;
wC [wCon] |= WCON_MUP;
-
+
return ARMul_DONE;
}
#ifdef DEBUG
fprintf (stderr, "wmul\n");
-#endif
+#endif
for (i = 0; i < 4; i++)
if (BIT (21)) /* Signed. */
#ifdef DEBUG
fprintf (stderr, "wor\n");
-#endif
+#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);
#ifdef DEBUG
fprintf (stderr, "wpack\n");
-#endif
-
+#endif
+
switch (BITS (22, 23))
{
case Hqual:
#ifdef DEBUG
fprintf (stderr, "wror\n");
-#endif
+#endif
DECODE_G_BIT (state, instr, shift);
#ifdef DEBUG
fprintf (stderr, "wsad\n");
-#endif
+#endif
/* Z bit. */
r = BIT (20) ? 0 : (wR [BITS (12, 15)] & 0xffffffff);
#ifdef DEBUG
fprintf (stderr, "wshufh\n");
-#endif
+#endif
imm8 = (BITS (20, 23) << 4) | BITS (0, 3);
#ifdef DEBUG
fprintf (stderr, "wsll\n");
-#endif
+#endif
DECODE_G_BIT (state, instr, shift);
#ifdef DEBUG
fprintf (stderr, "wsra\n");
-#endif
+#endif
DECODE_G_BIT (state, instr, shift);
t = (wRWORD (BITS (16, 19), i) & 0x80000000) ? 0xffffffff : 0;
else
{
- t = wRWORD (BITS (16, 19), i);
+ t = EXTEND32 (wRWORD (BITS (16, 19), i));
t >>= shift;
}
s = t;
SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i);
}
break;
-
+
case Dqual:
if (shift > 63)
r = (wR [BITS (16, 19)] & 0x8000000000000000ULL) ? 0xffffffffffffffffULL : 0;
#ifdef DEBUG
fprintf (stderr, "wstr\n");
#endif
-
+
address = Compute_Iwmmxt_Address (state, instr, & failed);
if (failed)
return ARMul_CANT;
#ifdef DEBUG
fprintf (stderr, "wsub\n");
-#endif
+#endif
/* Subtract two numbers using the specified function,
leaving setting the carry bit as required. */
#ifdef DEBUG
fprintf (stderr, "wunpckeh\n");
-#endif
+#endif
switch (BITS (22, 23))
{
#ifdef DEBUG
fprintf (stderr, "wunpckel\n");
-#endif
+#endif
switch (BITS (22, 23))
{
#ifdef DEBUG
fprintf (stderr, "wunpckih\n");
-#endif
+#endif
switch (BITS (22, 23))
{
SIMD8_SET (psr, ZBIT8 (b), SIMD_ZBIT, (i * 2) + 1);
}
break;
-
+
case Hqual:
for (i = 0; i < 2; i++)
{
#ifdef DEBUG
fprintf (stderr, "wunpckil\n");
-#endif
+#endif
switch (BITS (22, 23))
{
#ifdef DEBUG
fprintf (stderr, "wxor\n");
-#endif
+#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);
status = WMADD (instr); break;
case 0x10e: case 0x50e: case 0x90e: case 0xd0e:
- status = WUNPCKIL (state, instr); break;
+ 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:
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 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 = 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:
+ 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;
int
ARMul_HandleIwmmxt (ARMul_State * state, ARMword instr)
-{
+{
int status = ARMul_BUSY;
if (BITS (24, 27) == 0xe)