mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-13 04:13:33 +08:00
1d506c26d9
This commit is the result of the following actions: - Running gdb/copyright.py to update all of the copyright headers to include 2024, - Manually updating a few files the copyright.py script told me to update, these files had copyright headers embedded within the file, - Regenerating gdbsupport/Makefile.in to refresh it's copyright date, - Using grep to find other files that still mentioned 2023. If these files were updated last year from 2022 to 2023 then I've updated them this year to 2024. I'm sure I've probably missed some dates. Feel free to fix them up as you spot them.
2069 lines
44 KiB
C
2069 lines
44 KiB
C
// -*- C -*-
|
|
|
|
// Simulator definition for the MIPS DSP ASE.
|
|
// Copyright (C) 2005-2024 Free Software Foundation, Inc.
|
|
// Contributed by MIPS Technologies, Inc. Written by Chao-ying Fu.
|
|
//
|
|
// This file is part of the MIPS sim
|
|
//
|
|
// 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/>.
|
|
|
|
|
|
// op: 0 = ADD, 1 = SUB, 2 = MUL
|
|
// sat: 0 = no saturation, 1 = saturation
|
|
:function:::void:do_ph_op:int rd, int rs, int rt, int op, int sat
|
|
{
|
|
int i;
|
|
int32_t h0 = 0;
|
|
int16_t h1, h2;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
uint32_t result = 0;
|
|
for (i = 0; i < 32; i += 16, v1 >>= 16, v2 >>= 16)
|
|
{
|
|
h1 = (int16_t)(v1 & 0xffff);
|
|
h2 = (int16_t)(v2 & 0xffff);
|
|
if (op == 0) // ADD
|
|
h0 = (int32_t)h1 + (int32_t)h2;
|
|
else if (op == 1) // SUB
|
|
h0 = (int32_t)h1 - (int32_t)h2;
|
|
else // MUL
|
|
h0 = (int32_t)h1 * (int32_t)h2;
|
|
if (h0 > (int32_t)0x7fff || h0 < (int32_t)0xffff8000)
|
|
{
|
|
if (op == 0 || op == 1) // ADD, SUB
|
|
DSPCR |= DSPCR_OUFLAG4;
|
|
else if (op == 2) // MUL
|
|
DSPCR |= DSPCR_OUFLAG5;
|
|
if (sat == 1)
|
|
{
|
|
if (h0 > (int32_t)0x7fff)
|
|
h0 = 0x7fff;
|
|
else
|
|
h0 = 0x8000;
|
|
}
|
|
}
|
|
result |= ((uint32_t)((uint16_t)h0) << i);
|
|
}
|
|
GPR[rd] = EXTEND32 (result);
|
|
}
|
|
|
|
// op: 0 = ADD, 1 = SUB
|
|
:function:::void:do_w_op:int rd, int rs, int rt, int op
|
|
{
|
|
int64_t h0;
|
|
int32_t h1, h2;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
h1 = (int32_t)v1;
|
|
h2 = (int32_t)v2;
|
|
if (op == 0) // ADD
|
|
h0 = (int64_t)h1 + (int64_t)h2;
|
|
else // SUB
|
|
h0 = (int64_t)h1 - (int64_t)h2;
|
|
if (((h0 & 0x100000000LL) >> 1) != (h0 & 0x80000000))
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG4;
|
|
if (h0 & 0x100000000LL)
|
|
h0 = 0x80000000;
|
|
else
|
|
h0 = 0x7fffffff;
|
|
}
|
|
GPR[rd] = EXTEND32 (h0);
|
|
}
|
|
|
|
// op: 0 = ADD, 1 = SUB
|
|
// sat: 0 = no saturation, 1 = saturation
|
|
:function:::void:do_qb_op:int rd, int rs, int rt, int op, int sat
|
|
{
|
|
int i;
|
|
uint32_t h0;
|
|
uint8_t h1, h2;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
uint32_t result = 0;
|
|
for (i = 0; i < 32; i += 8, v1 >>= 8, v2 >>= 8)
|
|
{
|
|
h1 = (uint8_t)(v1 & 0xff);
|
|
h2 = (uint8_t)(v2 & 0xff);
|
|
if (op == 0) // ADD
|
|
h0 = (uint32_t)h1 + (uint32_t)h2;
|
|
else // SUB
|
|
h0 = (uint32_t)h1 - (uint32_t)h2;
|
|
if (h0 & 0x100)
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG4;
|
|
if (sat == 1)
|
|
{
|
|
if (op == 0) // ADD
|
|
h0 = 0xff;
|
|
else // SUB
|
|
h0 = 0;
|
|
}
|
|
}
|
|
result |= ((uint32_t)((uint8_t)h0) << i);
|
|
}
|
|
GPR[rd] = EXTEND32 (result);
|
|
}
|
|
|
|
// op: 0 = left, 1 = right
|
|
:function:::void:do_qb_shift:int rd, int rt, int shift, int op
|
|
{
|
|
int i, j;
|
|
uint8_t h0;
|
|
uint32_t v1 = GPR[rt];
|
|
uint32_t result = 0;
|
|
for (i = 0; i < 32; i += 8, v1 >>= 8)
|
|
{
|
|
h0 = (uint8_t)(v1 & 0xff);
|
|
if (op == 0) // left
|
|
{
|
|
for (j = 7; j >= 8 - shift; j--)
|
|
{
|
|
if (h0 & (1<<j))
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG6;
|
|
break;
|
|
}
|
|
}
|
|
h0 = h0 << shift;
|
|
}
|
|
else // right
|
|
h0 = h0 >> shift;
|
|
result |= ((uint32_t)h0 << i);
|
|
}
|
|
GPR[rd] = EXTEND32 (result);
|
|
}
|
|
|
|
// op: 0 = left, 1 = right
|
|
// sat: 0 = no saturation/rounding, 1 = saturation/rounding
|
|
:function:::void:do_ph_shift:int rd, int rt, int shift, int op, int sat
|
|
{
|
|
int i, j;
|
|
int16_t h0;
|
|
uint32_t v1 = GPR[rt];
|
|
uint32_t result = 0;
|
|
int setcond;
|
|
for (i = 0; i < 32; i += 16, v1 >>= 16)
|
|
{
|
|
h0 = (int16_t)(v1 & 0xffff);
|
|
if (op == 0) // left
|
|
{
|
|
setcond = 0;
|
|
if (h0 & (1<<15))
|
|
{
|
|
for (j = 14; j >= 15 - shift; j--)
|
|
{
|
|
if (!(h0 & (1 << j)))
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG6;
|
|
setcond = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (j = 14; j >= 15 - shift; j--)
|
|
{
|
|
if (h0 & (1 << j))
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG6;
|
|
setcond = 2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
h0 = h0 << shift;
|
|
if (sat == 1)
|
|
{
|
|
if (setcond == 2)
|
|
h0 = 0x7fff;
|
|
else if (setcond == 1)
|
|
h0 = 0x8000;
|
|
}
|
|
}
|
|
else // right
|
|
{
|
|
if (sat == 1 && shift != 0 && (h0 & (1 << (shift-1))))
|
|
h0 = (h0 >> shift) + 1;
|
|
else
|
|
h0 = h0 >> shift;
|
|
}
|
|
|
|
result |= ((uint32_t)((uint16_t)h0) << i);
|
|
}
|
|
GPR[rd] = EXTEND32 (result);
|
|
}
|
|
|
|
:function:::void:do_w_shll:int rd, int rt, int shift
|
|
{
|
|
int i;
|
|
uint32_t v1 = GPR[rt];
|
|
uint32_t result = 0;
|
|
int setcond = 0;
|
|
if (v1 & (1 << 31))
|
|
{
|
|
for (i = 30; i >= 31 - shift; i--)
|
|
{
|
|
if (!(v1 & (1 << i)))
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG6;
|
|
setcond = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 30; i >= 31 - shift; i--)
|
|
{
|
|
if (v1 & (1 << i))
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG6;
|
|
setcond = 2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (setcond == 2)
|
|
result = 0x7fffffff;
|
|
else if (setcond == 1)
|
|
result = 0x80000000;
|
|
else
|
|
result = v1 << shift;
|
|
GPR[rd] = EXTEND32 (result);
|
|
}
|
|
|
|
:function:::void:do_ph_s_absq:int rd, int rt
|
|
{
|
|
int i;
|
|
int16_t h0;
|
|
uint32_t v1 = GPR[rt];
|
|
uint32_t result = 0;
|
|
for (i = 0; i < 32; i += 16, v1 >>= 16)
|
|
{
|
|
h0 = (int16_t)(v1 & 0xffff);
|
|
if (h0 == (int16_t)0x8000)
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG4;
|
|
h0 = 0x7fff;
|
|
}
|
|
else if (h0 & 0x8000)
|
|
h0 = -h0;
|
|
result |= ((uint32_t)((uint16_t)h0) << i);
|
|
}
|
|
GPR[rd] = EXTEND32 (result);
|
|
}
|
|
|
|
:function:::void:do_w_s_absq:int rd, int rt
|
|
{
|
|
uint32_t v1 = GPR[rt];
|
|
int32_t h0 = (int32_t)v1;
|
|
if (h0 == (int32_t)0x80000000)
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG4;
|
|
h0 = 0x7fffffff;
|
|
}
|
|
else if (h0 & 0x80000000)
|
|
h0 = -h0;
|
|
GPR[rd] = EXTEND32 (h0);
|
|
}
|
|
|
|
:function:::void:do_qb_s_absq:int rd, int rt
|
|
{
|
|
int i;
|
|
int8_t q0;
|
|
uint32_t v1 = GPR[rt];
|
|
uint32_t result = 0;
|
|
for (i = 0; i < 32; i += 8, v1 >>= 8)
|
|
{
|
|
q0 = (int8_t)(v1 & 0xff);
|
|
if (q0 == (int8_t)0x80)
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG4;
|
|
q0 = 0x7f;
|
|
}
|
|
else if (q0 & 0x80)
|
|
q0 = -q0;
|
|
result |= ((uint32_t)((uint8_t)q0) << i);
|
|
}
|
|
GPR[rd] = EXTEND32 (result);
|
|
}
|
|
|
|
:function:::void:do_addsc:int rd, int rs, int rt
|
|
{
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
uint64_t h0;
|
|
h0 = (uint64_t)v1 + (uint64_t)v2;
|
|
if (h0 & 0x100000000LL)
|
|
DSPCR |= DSPCR_CARRY;
|
|
GPR[rd] = EXTEND32 (h0);
|
|
}
|
|
|
|
:function:::void:do_addwc:int rd, int rs, int rt
|
|
{
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
uint64_t h0;
|
|
int32_t h1 = (int32_t) v1;
|
|
int32_t h2 = (int32_t) v2;
|
|
h0 = (int64_t)h1 + (int64_t)h2
|
|
+ (int64_t)((DSPCR >> DSPCR_CARRY_SHIFT) & DSPCR_CARRY_MASK);
|
|
if (((h0 & 0x100000000LL) >> 1) != (h0 & 0x80000000))
|
|
DSPCR |= DSPCR_OUFLAG4;
|
|
GPR[rd] = EXTEND32 (h0);
|
|
}
|
|
|
|
:function:::void:do_bitrev:int rd, int rt
|
|
{
|
|
int i;
|
|
uint32_t v1 = GPR[rt];
|
|
uint32_t h1 = 0;
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
if (v1 & (1 << i))
|
|
h1 |= (1 << (15 - i));
|
|
}
|
|
GPR[rd] = EXTEND32 (h1);
|
|
}
|
|
|
|
// op: 0 = EXTPV, 1 = EXTPDPV
|
|
:function:::void:do_extpv:int rt, int ac, int rs, int op
|
|
{
|
|
uint32_t size = GPR[rs] & 0x1f;
|
|
do_extp (SD_, rt, ac, size, op);
|
|
}
|
|
|
|
// op: 0 = EXTRV, 1 = EXTRV_R, 2 = EXTRV_RS
|
|
:function:::void:do_extrv:int rt, int ac, int rs, int op
|
|
{
|
|
uint32_t shift = GPR[rs] & 0x1f;
|
|
do_w_extr (SD_, rt, ac, shift, op);
|
|
}
|
|
|
|
:function:::void:do_extrv_s_h:int rt, int ac, int rs
|
|
{
|
|
uint32_t shift = GPR[rs] & 0x1f;
|
|
do_h_extr (SD_, rt, ac, shift);
|
|
}
|
|
|
|
:function:::void:do_insv:int rt, int rs
|
|
{
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
uint32_t pos = (DSPCR >> DSPCR_POS_SHIFT) & DSPCR_POS_MASK;
|
|
uint32_t size = (DSPCR >> DSPCR_SCOUNT_SHIFT) & DSPCR_SCOUNT_MASK;
|
|
uint32_t mask1, mask2, mask3, result;
|
|
if (size < 32)
|
|
mask1 = (1 << size) - 1;
|
|
else
|
|
mask1 = 0xffffffff;
|
|
mask2 = (1 << pos) - 1;
|
|
if (pos + size < 32)
|
|
mask3 = ~((1 << (pos + size)) - 1);
|
|
else
|
|
mask3 = 0;
|
|
result = (v2 & mask3) | ((v1 & mask1) << pos) | (v2 & mask2);
|
|
GPR[rt] = EXTEND32 (result);
|
|
}
|
|
|
|
// op: 0 = NORMAL, 1 = EXTEND16, 2 = EXTEND32
|
|
:function:::void:do_lxx:int rd, int base, int index, int op
|
|
{
|
|
if (op == 0)
|
|
GPR[rd] = do_load (SD_, AccessLength_BYTE, GPR[base], GPR[index]);
|
|
else if (op == 1)
|
|
GPR[rd] = EXTEND16 (do_load (SD_, AccessLength_HALFWORD, GPR[base], GPR[index]));
|
|
else if (op == 2)
|
|
GPR[rd] = EXTEND32 (do_load (SD_, AccessLength_WORD, GPR[base], GPR[index]));
|
|
}
|
|
|
|
:function:::void:do_modsub:int rd, int rs, int rt
|
|
{
|
|
uint32_t result = 0;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
uint32_t decr = v2 & 0xff;
|
|
uint32_t lastindex = (v2 & 0xffff00) >> 8;
|
|
if (v1 == 0)
|
|
result = lastindex;
|
|
else
|
|
result = v1 - decr;
|
|
GPR[rd] = EXTEND32 (result);
|
|
}
|
|
|
|
:function:::void:do_mthlip:int rs, int ac
|
|
{
|
|
uint32_t pos = (DSPCR >> DSPCR_POS_SHIFT) & DSPCR_POS_MASK;
|
|
DSPHI(ac) = DSPLO(ac);
|
|
DSPLO(ac) = GPR[rs];
|
|
if (pos >= 32)
|
|
Unpredictable ();
|
|
else
|
|
pos += 32;
|
|
DSPCR &= (~DSPCR_POS_SMASK);
|
|
DSPCR |= (pos & DSPCR_POS_MASK) << DSPCR_POS_SHIFT;
|
|
}
|
|
|
|
:function:::void:do_mulsaq_s_w_ph:int ac, int rs, int rt
|
|
{
|
|
int i;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
int16_t h1, h2;
|
|
int32_t result;
|
|
uint32_t lo = DSPLO(ac);
|
|
uint32_t hi = DSPHI(ac);
|
|
int64_t prod = (int64_t)((((uint64_t)hi) << 32) + (uint64_t)lo);
|
|
for (i = 0; i < 32; i += 16, v1 >>= 16, v2 >>= 16)
|
|
{
|
|
h1 = (int16_t)(v1 & 0xffff);
|
|
h2 = (int16_t)(v2 & 0xffff);
|
|
if (h1 == (int16_t)0x8000 && h2 == (int16_t)0x8000)
|
|
{
|
|
DSPCR |= (1 << (DSPCR_OUFLAG_SHIFT + ac));
|
|
result = (int32_t) 0x7fffffff;
|
|
}
|
|
else
|
|
result = ((int32_t)h1 * (int32_t)h2) << 1;
|
|
|
|
if (i == 0)
|
|
prod -= (int64_t) result;
|
|
else
|
|
prod += (int64_t) result;
|
|
}
|
|
DSPLO(ac) = EXTEND32 (prod);
|
|
DSPHI(ac) = EXTEND32 (prod >> 32);
|
|
}
|
|
|
|
:function:::void:do_ph_packrl:int rd, int rs, int rt
|
|
{
|
|
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
GPR[rd] = EXTEND32 ((v1 << 16) + (v2 >> 16));
|
|
}
|
|
|
|
:function:::void:do_qb_pick:int rd, int rs, int rt
|
|
{
|
|
int i, j;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
uint8_t h1, h2;
|
|
uint32_t result = 0;
|
|
for (i = 0, j = 0; i < 32; i += 8, j++, v1 >>= 8, v2 >>= 8)
|
|
{
|
|
h1 = (uint8_t)(v1 & 0xff);
|
|
h2 = (uint8_t)(v2 & 0xff);
|
|
if (DSPCR & (1 << (DSPCR_CCOND_SHIFT + j)))
|
|
result |= (uint32_t)(h1 << i);
|
|
else
|
|
result |= (uint32_t)(h2 << i);
|
|
}
|
|
GPR[rd] = EXTEND32 (result);
|
|
}
|
|
|
|
:function:::void:do_ph_pick:int rd, int rs, int rt
|
|
{
|
|
int i, j;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
uint16_t h1, h2;
|
|
uint32_t result = 0;
|
|
for (i = 0, j = 0; i < 32; i += 16, j++, v1 >>= 16, v2 >>= 16)
|
|
{
|
|
h1 = (uint16_t)(v1 & 0xffff);
|
|
h2 = (uint16_t)(v2 & 0xffff);
|
|
if (DSPCR & (1 << (DSPCR_CCOND_SHIFT + j)))
|
|
result |= (uint32_t)(h1 << i);
|
|
else
|
|
result |= (uint32_t)(h2 << i);
|
|
}
|
|
GPR[rd] = EXTEND32 (result);
|
|
}
|
|
|
|
// op: 0 = QBR, 1 = QBRA, 2 = QBL, 3 = QBLA
|
|
:function:::void:do_qb_ph_precequ:int rd, int rt, int op
|
|
{
|
|
uint32_t v1 = GPR[rt];
|
|
if (op == 0)
|
|
GPR[rd] = EXTEND32 ((v1 & 0xff00) << 15) | ((v1 & 0xff) << 7);
|
|
else if (op == 1)
|
|
GPR[rd] = EXTEND32 ((v1 & 0xff0000) << 7) | ((v1 & 0xff) << 7);
|
|
else if (op == 2)
|
|
GPR[rd] = EXTEND32 ((v1 & 0xff000000) >> 1) | ((v1 & 0xff0000) >> 9);
|
|
else if (op == 3)
|
|
GPR[rd] = EXTEND32 ((v1 & 0xff000000) >> 1) | ((v1 & 0xff00) >> 1);
|
|
}
|
|
|
|
// op: 0 = QBR, 1 = QBRA, 2 = QBL, 3 = QBLA
|
|
:function:::void:do_qb_ph_preceu:int rd, int rt, int op
|
|
{
|
|
uint32_t v1 = GPR[rt];
|
|
if (op == 0)
|
|
GPR[rd] = EXTEND32 ((v1 & 0xff00) << 8) | (v1 & 0xff);
|
|
else if (op == 1)
|
|
GPR[rd] = EXTEND32 ((v1 & 0xff0000) | (v1 & 0xff));
|
|
else if (op == 2)
|
|
GPR[rd] = EXTEND32 ((v1 & 0xff000000) >> 8) | ((v1 & 0xff0000) >> 16);
|
|
else if (op == 3)
|
|
GPR[rd] = EXTEND32 ((v1 & 0xff000000) >> 8) | ((v1 & 0xff00) >> 8);
|
|
}
|
|
|
|
// op: 0 = .PHL, 1 = PHR
|
|
:function:::void:do_w_preceq:int rd, int rt, int op
|
|
{
|
|
uint32_t v1 = GPR[rt];
|
|
if (op == 0)
|
|
GPR[rd] = EXTEND32 (v1 & 0xffff0000);
|
|
else if (op == 1)
|
|
GPR[rd] = EXTEND32 ((v1 & 0xffff) << 16);
|
|
}
|
|
|
|
:function:::void:do_w_ph_precrq:int rd, int rs, int rt
|
|
{
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
uint32_t tempu = (v1 & 0xffff0000) >> 16;
|
|
uint32_t tempv = (v2 & 0xffff0000) >> 16;
|
|
GPR[rd] = EXTEND32 ((tempu << 16) | tempv);
|
|
}
|
|
|
|
// sat: 0 = PRECRQ.QB.PH, 1 = PRECRQU_S.QB.PH
|
|
:function:::void:do_ph_qb_precrq:int rd, int rs, int rt, int sat
|
|
{
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
uint32_t tempu = 0, tempv = 0, tempw = 0, tempx = 0;
|
|
if (sat == 0)
|
|
{
|
|
tempu = (v1 & 0xff000000) >> 24;
|
|
tempv = (v1 & 0xff00) >> 8;
|
|
tempw = (v2 & 0xff000000) >> 24;
|
|
tempx = (v2 & 0xff00) >> 8;
|
|
}
|
|
else if (sat == 1)
|
|
{
|
|
if (v1 & 0x80000000)
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG6;
|
|
tempu = 0;
|
|
}
|
|
else if (!(v1 & 0x80000000) && ((v1 >> 16) > (uint32_t)0x7f80))
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG6;
|
|
tempu = 0xff;
|
|
}
|
|
else
|
|
tempu = (v1 & 0x7f800000) >> 23;
|
|
if (v1 & 0x8000)
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG6;
|
|
tempv = 0;
|
|
}
|
|
else if (!(v1 & 0x8000) && ((v1 & 0xffff) > (uint32_t)0x7f80))
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG6;
|
|
tempv = 0xff;
|
|
}
|
|
else
|
|
tempv = (v1 & 0x7f80) >> 7;
|
|
if (v2 & 0x80000000)
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG6;
|
|
tempw = 0;
|
|
}
|
|
else if (!(v2 & 0x80000000) && ((v2 >> 16) > (uint32_t)0x7f80))
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG6;
|
|
tempw = 0xff;
|
|
}
|
|
else
|
|
tempw = (v2 & 0x7f800000) >> 23;
|
|
if (v2 & 0x8000)
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG6;
|
|
tempx = 0;
|
|
}
|
|
else if (!(v2 & 0x8000) && ((v2 & 0xffff) > (uint32_t)0x7f80))
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG6;
|
|
tempx = 0xff;
|
|
}
|
|
else
|
|
tempx = (v2 & 0x7f80) >> 7;
|
|
}
|
|
GPR[rd] = EXTEND32 ((tempu << 24) | (tempv << 16) | (tempw << 8) | tempx);
|
|
}
|
|
|
|
:function:::void:do_w_ph_rs_precrq:int rd, int rs, int rt
|
|
{
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
int32_t h1 = (int32_t)v1;
|
|
int32_t h2 = (int32_t)v2;
|
|
int64_t temp1 = (int64_t)h1 + (int64_t)0x8000;
|
|
int32_t temp2;
|
|
int64_t temp3 = (int64_t)h2 + (int64_t)0x8000;
|
|
int32_t temp4;
|
|
if (((temp1 & 0x100000000LL) >> 1) != (temp1 & 0x80000000))
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG6;
|
|
temp2 = 0x7fff;
|
|
}
|
|
else
|
|
temp2 = (int32_t)((temp1 & 0xffff0000) >> 16);
|
|
if (((temp3 & 0x100000000LL) >> 1) != (temp3 & 0x80000000))
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG6;
|
|
temp4 = 0x7fff;
|
|
}
|
|
else
|
|
temp4 = (int32_t)((temp3 & 0xffff0000) >> 16);
|
|
GPR[rd] = EXTEND32 ((temp2 << 16) | temp4);
|
|
}
|
|
|
|
:function:::void:do_qb_w_raddu:int rd, int rs
|
|
{
|
|
int i;
|
|
uint8_t h0;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t result = 0;
|
|
for (i = 0; i < 32; i += 8, v1 >>= 8)
|
|
{
|
|
h0 = (uint8_t)(v1 & 0xff);
|
|
result += (uint32_t)h0;
|
|
}
|
|
GPR[rd] = EXTEND32 (result);
|
|
}
|
|
|
|
:function:::void:do_rddsp:int rd, int mask
|
|
{
|
|
uint32_t result = 0;
|
|
if (mask & 0x1)
|
|
{
|
|
result &= (~DSPCR_POS_SMASK);
|
|
result |= (DSPCR & DSPCR_POS_SMASK);
|
|
}
|
|
if (mask & 0x2)
|
|
{
|
|
result &= (~DSPCR_SCOUNT_SMASK);
|
|
result |= (DSPCR & DSPCR_SCOUNT_SMASK);
|
|
}
|
|
if (mask & 0x4)
|
|
{
|
|
result &= (~DSPCR_CARRY_SMASK);
|
|
result |= (DSPCR & DSPCR_CARRY_SMASK);
|
|
}
|
|
if (mask & 0x8)
|
|
{
|
|
result &= (~DSPCR_OUFLAG_SMASK);
|
|
result |= (DSPCR & DSPCR_OUFLAG_SMASK);
|
|
}
|
|
if (mask & 0x10)
|
|
{
|
|
result &= (~DSPCR_CCOND_SMASK);
|
|
result |= (DSPCR & DSPCR_CCOND_SMASK);
|
|
}
|
|
if (mask & 0x20)
|
|
{
|
|
result &= (~DSPCR_EFI_SMASK);
|
|
result |= (DSPCR & DSPCR_EFI_SMASK);
|
|
}
|
|
GPR[rd] = EXTEND32 (result);
|
|
}
|
|
|
|
// op: 0 = REPL.QB, 1 = REPLV.QB, 2 = REPL.PH, 3 = REPLV.PH
|
|
:function:::void:do_repl:int rd, int p2, int op
|
|
{
|
|
if (op == 0)
|
|
GPR[rd] = EXTEND32 ((p2 << 24) | (p2 << 16) | (p2 << 8) | p2);
|
|
else if (op == 1)
|
|
{
|
|
uint32_t v1 = GPR[p2] & 0xff;
|
|
GPR[rd] = EXTEND32 ((v1 << 24) | (v1 << 16) | (v1 << 8) | v1);
|
|
}
|
|
else if (op == 2)
|
|
{
|
|
int32_t v1 = p2;
|
|
if (v1 & 0x200)
|
|
v1 |= 0xfffffc00;
|
|
GPR[rd] = EXTEND32 ((v1 << 16) | (v1 & 0xffff));
|
|
}
|
|
else if (op == 3)
|
|
{
|
|
uint32_t v1 = GPR[p2];
|
|
v1 = v1 & 0xffff;
|
|
GPR[rd] = EXTEND32 ((v1 << 16) | v1);
|
|
}
|
|
}
|
|
|
|
:function:::void:do_shilov:int ac, int rs
|
|
{
|
|
int32_t shift = GPR[rs] & 0x3f;
|
|
do_shilo (SD_, ac, shift);
|
|
}
|
|
|
|
// op: 0 = SHLLV, 1 = SHRAV
|
|
// sat: 0 = normal, 1 = saturate/rounding
|
|
:function:::void:do_ph_shl:int rd, int rt, int rs, int op, int sat
|
|
{
|
|
uint32_t shift = GPR[rs] & 0xf;
|
|
do_ph_shift (SD_, rd, rt, shift, op, sat);
|
|
}
|
|
|
|
// op: 0 = SHLLV, 1 = SHRLV
|
|
:function:::void:do_qb_shl:int rd, int rt, int rs, int op
|
|
{
|
|
uint32_t shift = GPR[rs] & 0x7;
|
|
do_qb_shift (SD_, rd, rt, shift, op);
|
|
}
|
|
|
|
:function:::void:do_w_s_shllv:int rd, int rt, int rs
|
|
{
|
|
uint32_t shift = GPR[rs] & 0x1f;
|
|
do_w_shll (SD_, rd, rt, shift);
|
|
}
|
|
|
|
:function:::void:do_ph_shrlv:int rd, int rt, int rs
|
|
{
|
|
uint32_t shift = GPR[rs] & 0xf;
|
|
do_ph_shrl (SD_, rd, rt, shift);
|
|
}
|
|
|
|
:function:::void:do_w_r_shrav:int rd, int rt, int rs
|
|
{
|
|
uint32_t shift = GPR[rs] & 0x1f;
|
|
do_w_shra (SD_, rd, rt, shift);
|
|
}
|
|
|
|
:function:::void:do_wrdsp:int rs, int mask
|
|
{
|
|
uint32_t v1 = GPR[rs];
|
|
if (mask & 0x1)
|
|
{
|
|
DSPCR &= (~DSPCR_POS_SMASK);
|
|
DSPCR |= (v1 & DSPCR_POS_SMASK);
|
|
}
|
|
if (mask & 0x2)
|
|
{
|
|
DSPCR &= (~DSPCR_SCOUNT_SMASK);
|
|
DSPCR |= (v1 & DSPCR_SCOUNT_SMASK);
|
|
}
|
|
if (mask & 0x4)
|
|
{
|
|
DSPCR &= (~DSPCR_CARRY_SMASK);
|
|
DSPCR |= (v1 & DSPCR_CARRY_SMASK);
|
|
}
|
|
if (mask & 0x8)
|
|
{
|
|
DSPCR &= (~DSPCR_OUFLAG_SMASK);
|
|
DSPCR |= (v1 & DSPCR_OUFLAG_SMASK);
|
|
}
|
|
if (mask & 0x10)
|
|
{
|
|
DSPCR &= (~DSPCR_CCOND_SMASK);
|
|
DSPCR |= (v1 & DSPCR_CCOND_SMASK);
|
|
}
|
|
if (mask & 0x20)
|
|
{
|
|
DSPCR &= (~DSPCR_EFI_SMASK);
|
|
DSPCR |= (v1 & DSPCR_EFI_SMASK);
|
|
}
|
|
}
|
|
|
|
// round: 0 = no rounding, 1 = rounding
|
|
:function:::void:do_qb_shrav:int rd, int rt, int rs, int round
|
|
{
|
|
uint32_t shift = GPR[rs] & 0x7;
|
|
do_qb_shra (SD_, rd, rt, shift, round);
|
|
}
|
|
|
|
:function:::void:do_append:int rt, int rs, int sa
|
|
{
|
|
uint32_t v0 = GPR[rs];
|
|
uint32_t v1 = GPR[rt];
|
|
uint32_t result;
|
|
uint32_t mask = (1 << sa) - 1;
|
|
result = (v1 << sa) | (v0 & mask);
|
|
GPR[rt] = EXTEND32 (result);
|
|
}
|
|
|
|
:function:::void:do_balign:int rt, int rs, int bp
|
|
{
|
|
uint32_t v0 = GPR[rs];
|
|
uint32_t v1 = GPR[rt];
|
|
uint32_t result;
|
|
if (bp == 0)
|
|
result = v1;
|
|
else
|
|
result = (v1 << 8 * bp) | (v0 >> 8 * (4 - bp));
|
|
GPR[rt] = EXTEND32 (result);
|
|
}
|
|
|
|
:function:::void:do_ph_w_mulsa:int ac, int rs, int rt
|
|
{
|
|
int i;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
int16_t h1, h2;
|
|
int32_t result;
|
|
uint32_t lo = DSPLO(ac);
|
|
uint32_t hi = DSPHI(ac);
|
|
int64_t prod = (int64_t)((((uint64_t)hi) << 32) + (uint64_t)lo);
|
|
for (i = 0; i < 32; i += 16, v1 >>= 16, v2 >>= 16)
|
|
{
|
|
h1 = (int16_t)(v1 & 0xffff);
|
|
h2 = (int16_t)(v2 & 0xffff);
|
|
result = (int32_t)h1 * (int32_t)h2;
|
|
|
|
if (i == 0)
|
|
prod -= (int64_t) result;
|
|
else
|
|
prod += (int64_t) result;
|
|
}
|
|
DSPLO(ac) = EXTEND32 (prod);
|
|
DSPHI(ac) = EXTEND32 (prod >> 32);
|
|
}
|
|
|
|
:function:::void:do_ph_qb_precr:int rd, int rs, int rt
|
|
{
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
uint32_t tempu = (v1 & 0xff0000) >> 16;
|
|
uint32_t tempv = (v1 & 0xff);
|
|
uint32_t tempw = (v2 & 0xff0000) >> 16;
|
|
uint32_t tempx = (v2 & 0xff);
|
|
GPR[rd] = EXTEND32 ((tempu << 24) | (tempv << 16) | (tempw << 8) | tempx);
|
|
}
|
|
|
|
:function:::void:do_prepend:int rt, int rs, int sa
|
|
{
|
|
uint32_t v0 = GPR[rs];
|
|
uint32_t v1 = GPR[rt];
|
|
uint32_t result;
|
|
if (sa == 0)
|
|
result = v1;
|
|
else
|
|
result = (v0 << (32 - sa)) | (v1 >> sa);
|
|
GPR[rt] = EXTEND32 (result);
|
|
}
|
|
|
|
:function:::void:do_w_shra:int rd, int rt, int shift
|
|
{
|
|
uint32_t result = GPR[rt];
|
|
int32_t h0 = (int32_t)result;
|
|
if (shift != 0 && (h0 & (1 << (shift-1))))
|
|
h0 = (h0 >> shift) + 1;
|
|
else
|
|
h0 = h0 >> shift;
|
|
GPR[rd] = EXTEND32 (h0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,01010,010000:SPECIAL3:32::ADDQ.PH
|
|
"addq.ph r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_op (SD_, RD, RS, RT, 0, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,01110,010000:SPECIAL3:32::ADDQ_S.PH
|
|
"addq_s.ph r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_op (SD_, RD, RS, RT, 0, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,10110,010000:SPECIAL3:32::ADDQ_S.W
|
|
"addq_s.w r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_w_op (SD_, RD, RS, RT, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,00000,010000:SPECIAL3:32::ADDU.QB
|
|
"addu.qb r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_op (SD_, RD, RS, RT, 0, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,00100,010000:SPECIAL3:32::ADDU_S.QB
|
|
"addu_s.qb r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_op (SD_, RD, RS, RT, 0, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,01011,010000:SPECIAL3:32::SUBQ.PH
|
|
"subq.ph r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_op (SD_, RD, RS, RT, 1, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,01111,010000:SPECIAL3:32::SUBQ_S.PH
|
|
"subq_s.ph r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_op (SD_, RD, RS, RT, 1, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,10111,010000:SPECIAL3:32::SUBQ_S.W
|
|
"subq_s.w r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_w_op (SD_, RD, RS, RT, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,00001,010000:SPECIAL3:32::SUBU.QB
|
|
"subu.qb r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_op (SD_, RD, RS, RT, 1, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,00101,010000:SPECIAL3:32::SUBU_S.QB
|
|
"subu_s.qb r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_op (SD_, RD, RS, RT, 1, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,10000,010000:SPECIAL3:32::ADDSC
|
|
"addsc r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_addsc (SD_, RD, RS, RT);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,10001,010000:SPECIAL3:32::ADDWC
|
|
"addwc r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_addwc (SD_, RD, RS, RT);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,10010,010000:SPECIAL3:32::MODSUB
|
|
"modsub r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_modsub (SD_, RD, RS, RT);
|
|
}
|
|
|
|
011111,5.RS,00000,5.RD,10100,010000:SPECIAL3:32::RADDU.W.QB
|
|
"raddu.w.qb r<RD>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_qb_w_raddu (SD_, RD, RS);
|
|
}
|
|
|
|
011111,00000,5.RT,5.RD,01001,010010:SPECIAL3:32::ABSQ_S.PH
|
|
"absq_s.ph r<RD>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_s_absq (SD_, RD, RT);
|
|
}
|
|
|
|
011111,00000,5.RT,5.RD,10001,010010:SPECIAL3:32::ABSQ_S.W
|
|
"absq_s.w r<RD>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_w_s_absq (SD_, RD, RT);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,01100,010001:SPECIAL3:32::PRECRQ.QB.PH
|
|
"precrq.qb.ph r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_qb_precrq (SD_, RD, RS, RT, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,10100,010001:SPECIAL3:32::PRECRQ.PH.W
|
|
"precrq.ph.w r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_w_ph_precrq (SD_, RD, RS, RT);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,10101,010001:SPECIAL3:32::PRECRQ_RS.PH.W
|
|
"precrq_rs.ph.w r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_w_ph_rs_precrq (SD_, RD, RS, RT);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,01111,010001:SPECIAL3:32::PRECRQU_S.QB.PH
|
|
"precrqu_s.qb.ph r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_qb_precrq (SD_, RD, RS, RT, 1);
|
|
}
|
|
|
|
011111,00000,5.RT,5.RD,01100,010010:SPECIAL3:32::PRECEQ.W.PHL
|
|
"preceq.w.phl r<RD>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_w_preceq (SD_, RD, RT, 0);
|
|
}
|
|
|
|
011111,00000,5.RT,5.RD,01101,010010:SPECIAL3:32::PRECEQ.W.PHR
|
|
"preceq.w.phr r<RD>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_w_preceq (SD_, RD, RT, 1);
|
|
}
|
|
|
|
011111,00000,5.RT,5.RD,00100,010010:SPECIAL3:32::PRECEQU.PH.QBL
|
|
"precequ.ph.qbl r<RD>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_ph_precequ (SD_, RD, RT, 2);
|
|
}
|
|
|
|
011111,00000,5.RT,5.RD,00101,010010:SPECIAL3:32::PRECEQU.PH.QBR
|
|
"precequ.ph.qbr r<RD>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_ph_precequ (SD_, RD, RT, 0);
|
|
}
|
|
|
|
011111,00000,5.RT,5.RD,00110,010010:SPECIAL3:32::PRECEQU.PH.QBLA
|
|
"precequ.ph.qbla r<RD>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_ph_precequ (SD_, RD, RT, 3);
|
|
}
|
|
|
|
011111,00000,5.RT,5.RD,00111,010010:SPECIAL3:32::PRECEQU.PH.QBRA
|
|
"precequ.ph.qbra r<RD>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_ph_precequ (SD_, RD, RT, 1);
|
|
}
|
|
|
|
011111,00000,5.RT,5.RD,11100,010010:SPECIAL3:32::PRECEU.PH.QBL
|
|
"preceu.ph.qbl r<RD>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_ph_preceu (SD_, RD, RT, 2);
|
|
}
|
|
|
|
011111,00000,5.RT,5.RD,11101,010010:SPECIAL3:32::PRECEU.PH.QBR
|
|
"preceu.ph.qbr r<RD>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_ph_preceu (SD_, RD, RT, 0);
|
|
}
|
|
|
|
011111,00000,5.RT,5.RD,11110,010010:SPECIAL3:32::PRECEU.PH.QBLA
|
|
"preceu.ph.qbla r<RD>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_ph_preceu (SD_, RD, RT, 3);
|
|
}
|
|
|
|
011111,00000,5.RT,5.RD,11111,010010:SPECIAL3:32::PRECEU.PH.QBRA
|
|
"preceu.ph.qbra r<RD>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_ph_preceu (SD_, RD, RT, 1);
|
|
}
|
|
|
|
011111,00,3.SHIFT3,5.RT,5.RD,00000,010011:SPECIAL3:32::SHLL.QB
|
|
"shll.qb r<RD>, r<RT>, <SHIFT3>"
|
|
*dsp:
|
|
{
|
|
do_qb_shift (SD_, RD, RT, SHIFT3, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,00010,010011:SPECIAL3:32::SHLLV.QB
|
|
"shllv.qb r<RD>, r<RT>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_qb_shl (SD_, RD, RT, RS, 0);
|
|
}
|
|
|
|
011111,0,4.SHIFT4,5.RT,5.RD,01000,010011:SPECIAL3:32::SHLL.PH
|
|
"shll.ph r<RD>, r<RT>, <SHIFT4>"
|
|
*dsp:
|
|
{
|
|
do_ph_shift (SD_, RD, RT, SHIFT4, 0, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,01010,010011:SPECIAL3:32::SHLLV.PH
|
|
"shllv.ph r<RD>, r<RT>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_ph_shl (SD_, RD, RT, RS, 0, 0);
|
|
}
|
|
|
|
011111,0,4.SHIFT4,5.RT,5.RD,01100,010011:SPECIAL3:32::SHLL_S.PH
|
|
"shll_s.ph r<RD>, r<RT>, <SHIFT4>"
|
|
*dsp:
|
|
{
|
|
do_ph_shift (SD_, RD, RT, SHIFT4, 0, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,01110,010011:SPECIAL3:32::SHLLV_S.PH
|
|
"shllv_s.ph r<RD>, r<RT>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_ph_shl (SD_, RD, RT, RS, 0, 1);
|
|
}
|
|
|
|
011111,5.SHIFT5,5.RT,5.RD,10100,010011:SPECIAL3:32::SHLL_S.W
|
|
"shll_s.w r<RD>, r<RT>, <SHIFT5>"
|
|
*dsp:
|
|
{
|
|
do_w_shll (SD_, RD, RT, SHIFT5);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,10110,010011:SPECIAL3:32::SHLLV_S.W
|
|
"shllv_s.w r<RD>, r<RT>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_w_s_shllv (SD_, RD, RT, RS);
|
|
}
|
|
|
|
011111,00,3.SHIFT3,5.RT,5.RD,00001,010011:SPECIAL3:32::SHRL.QB
|
|
"shrl.qb r<RD>, r<RT>, <SHIFT3>"
|
|
*dsp:
|
|
{
|
|
do_qb_shift (SD_, RD, RT, SHIFT3, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,00011,010011:SPECIAL3:32::SHRLV.QB
|
|
"shrlv.qb r<RD>, r<RT>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_qb_shl (SD_, RD, RT, RS, 1);
|
|
}
|
|
|
|
011111,0,4.SHIFT4,5.RT,5.RD,01001,010011:SPECIAL3:32::SHRA.PH
|
|
"shra.ph r<RD>, r<RT>, <SHIFT4>"
|
|
*dsp:
|
|
{
|
|
do_ph_shift (SD_, RD, RT, SHIFT4, 1, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,01011,010011:SPECIAL3:32::SHRAV.PH
|
|
"shrav.ph r<RD>, r<RT>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_ph_shl (SD_, RD, RT, RS, 1, 0);
|
|
}
|
|
|
|
011111,0,4.SHIFT4,5.RT,5.RD,01101,010011:SPECIAL3:32::SHRA_R.PH
|
|
"shra_r.ph r<RD>, r<RT>, <SHIFT4>"
|
|
*dsp:
|
|
{
|
|
do_ph_shift (SD_, RD, RT, SHIFT4, 1, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,01111,010011:SPECIAL3:32::SHRAV_R.PH
|
|
"shrav_r.ph r<RD>, r<RT>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_ph_shl (SD_, RD, RT, RS, 1, 1);
|
|
}
|
|
|
|
011111,5.SHIFT5,5.RT,5.RD,10101,010011:SPECIAL3:32::SHRA_R.W
|
|
"shra_r.w r<RD>, r<RT>, <SHIFT5>"
|
|
*dsp:
|
|
{
|
|
do_w_shra (SD_, RD, RT, SHIFT5);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,10111,010011:SPECIAL3:32::SHRAV_R.W
|
|
"shrav_r.w r<RD>, r<RT>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_w_r_shrav (SD_, RD, RT, RS);
|
|
}
|
|
|
|
// loc: 0 = qhl, 1 = qhr
|
|
:function:::void:do_qb_muleu:int rd, int rs, int rt, int loc
|
|
{
|
|
int i;
|
|
uint32_t result = 0;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
uint16_t h1, h2;
|
|
uint32_t prod;
|
|
if (loc == 0)
|
|
v1 >>= 16;
|
|
for (i = 0; i < 32; i += 16, v1 >>= 8, v2 >>= 16)
|
|
{
|
|
h1 = (uint16_t)(v1 & 0xff);
|
|
h2 = (uint16_t)(v2 & 0xffff);
|
|
prod = (uint32_t)h1 * (uint32_t)h2;
|
|
if (prod > 0xffff)
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG5;
|
|
prod = 0xffff;
|
|
}
|
|
result |= ((uint32_t)prod << i);
|
|
}
|
|
GPR[rd] = EXTEND32 (result);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,00110,010000:SPECIAL3:32::MULEU_S.PH.QBL
|
|
"muleu_s.ph.qbl r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_muleu (SD_, RD, RS, RT, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,00111,010000:SPECIAL3:32::MULEU_S.PH.QBR
|
|
"muleu_s.ph.qbr r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_muleu (SD_, RD, RS, RT, 1);
|
|
}
|
|
|
|
// round: 0 = no rounding, 1 = rounding
|
|
:function:::void:do_ph_mulq:int rd, int rs, int rt, int round
|
|
{
|
|
int i;
|
|
uint32_t result = 0;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
int16_t h1, h2;
|
|
int32_t prod;
|
|
for (i = 0; i < 32; i += 16, v1 >>= 16, v2 >>= 16)
|
|
{
|
|
h1 = (int16_t)(v1 & 0xffff);
|
|
h2 = (int16_t)(v2 & 0xffff);
|
|
if (h1 == (int16_t)0x8000 && h2 == (int16_t)0x8000)
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG5;
|
|
prod = 0x7fffffff;
|
|
}
|
|
else
|
|
{
|
|
prod = ((int32_t)h1 * (int32_t)h2) << 1;
|
|
if (round == 1)
|
|
prod += (int32_t)0x8000;
|
|
}
|
|
result |= (((uint32_t)prod >> 16) << i);
|
|
}
|
|
GPR[rd] = EXTEND32 (result);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,11111,010000:SPECIAL3:32::MULQ_RS.PH
|
|
"mulq_rs.ph r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_mulq (SD_, RD, RS, RT, 1);
|
|
}
|
|
|
|
// loc: 0 = phl, 1 = phr
|
|
:function:::void:do_ph_muleq:int rd, int rs, int rt, int loc
|
|
{
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
int16_t h1, h2;
|
|
int32_t prod;
|
|
if (loc == 0)
|
|
{
|
|
h1 = (int16_t)(v1 >> 16);
|
|
h2 = (int16_t)(v2 >> 16);
|
|
}
|
|
else
|
|
{
|
|
h1 = (int16_t)(v1 & 0xffff);
|
|
h2 = (int16_t)(v2 & 0xffff);
|
|
}
|
|
if (h1 == (int16_t)0x8000 && h2 == (int16_t)0x8000)
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG5;
|
|
prod = 0x7fffffff;
|
|
}
|
|
else
|
|
prod = ((int32_t)h1 * (int32_t)h2) << 1;
|
|
GPR[rd] = EXTEND32 (prod);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,11100,010000:SPECIAL3:32::MULEQ_S.W.PHL
|
|
"muleq_s.w.phl r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_muleq (SD_, RD, RS, RT, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,11101,010000:SPECIAL3:32::MULEQ_S.W.PHR
|
|
"muleq_s.w.phr r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_muleq (SD_, RD, RS, RT, 1);
|
|
}
|
|
|
|
// op: 0 = DPAU 1 = DPSU
|
|
// loc: 0 = qbl, 1 = qbr
|
|
:function:::void:do_qb_dot_product:int ac, int rs, int rt, int op, int loc
|
|
{
|
|
int i;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
uint8_t h1, h2;
|
|
uint32_t lo = DSPLO(ac);
|
|
uint32_t hi = DSPHI(ac);
|
|
uint64_t prod = (((uint64_t)hi) << 32) + (uint64_t)lo;
|
|
if (loc == 0)
|
|
{
|
|
v1 >>= 16;
|
|
v2 >>= 16;
|
|
}
|
|
for (i = 0; i < 16; i += 8, v1 >>= 8, v2 >>= 8)
|
|
{
|
|
h1 = (uint8_t)(v1 & 0xff);
|
|
h2 = (uint8_t)(v2 & 0xff);
|
|
if (op == 0) // DPAU
|
|
prod += (uint64_t)h1 * (uint64_t)h2;
|
|
else // DPSU
|
|
prod -= (uint64_t)h1 * (uint64_t)h2;
|
|
}
|
|
DSPLO(ac) = EXTEND32 (prod);
|
|
DSPHI(ac) = EXTEND32 (prod >> 32);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,00011,110000:SPECIAL3:32::DPAU.H.QBL
|
|
"dpau.h.qbl ac<AC>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_dot_product (SD_, AC, RS, RT, 0, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,00111,110000:SPECIAL3:32::DPAU.H.QBR
|
|
"dpau.h.qbr ac<AC>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_dot_product (SD_, AC, RS, RT, 0, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,01011,110000:SPECIAL3:32::DPSU.H.QBL
|
|
"dpsu.h.qbl ac<AC>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_dot_product (SD_, AC, RS, RT, 1, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,01111,110000:SPECIAL3:32::DPSU.H.QBR
|
|
"dpsu.h.qbr ac<AC>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_dot_product (SD_, AC, RS, RT, 1, 1);
|
|
}
|
|
|
|
// op: 0 = DPAQ 1 = DPSQ
|
|
:function:::void:do_ph_dot_product:int ac, int rs, int rt, int op
|
|
{
|
|
int i;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
int16_t h1, h2;
|
|
int32_t result;
|
|
uint32_t lo = DSPLO(ac);
|
|
uint32_t hi = DSPHI(ac);
|
|
int64_t prod = (int64_t)((((uint64_t)hi) << 32) + (uint64_t)lo);
|
|
for (i = 0; i < 32; i += 16, v1 >>= 16, v2 >>= 16)
|
|
{
|
|
h1 = (int16_t)(v1 & 0xffff);
|
|
h2 = (int16_t)(v2 & 0xffff);
|
|
if (h1 == (int16_t)0x8000 && h2 == (int16_t)0x8000)
|
|
{
|
|
DSPCR |= (1 << (DSPCR_OUFLAG_SHIFT + ac));
|
|
result = (int32_t)0x7fffffff;
|
|
}
|
|
else
|
|
result = ((int32_t)h1 * (int32_t)h2) << 1;
|
|
|
|
if (op == 0) // DPAQ
|
|
prod += (int64_t)result;
|
|
else // DPSQ
|
|
prod -= (int64_t)result;
|
|
}
|
|
DSPLO(ac) = EXTEND32 (prod);
|
|
DSPHI(ac) = EXTEND32 (prod >> 32);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,00100,110000:SPECIAL3:32::DPAQ_S.W.PH
|
|
"dpaq_s.w.ph ac<AC>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_dot_product (SD_, AC, RS, RT, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,00101,110000:SPECIAL3:32::DPSQ_S.W.PH
|
|
"dpsq_s.w.ph ac<AC>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_dot_product (SD_, AC, RS, RT, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,00110,110000:SPECIAL3:32::MULSAQ_S.W.PH
|
|
"mulsaq_s.w.ph ac<AC>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_mulsaq_s_w_ph (SD_, AC, RS, RT);
|
|
}
|
|
|
|
// op: 0 = DPAQ 1 = DPSQ
|
|
:function:::void:do_w_dot_product:int ac, int rs, int rt, int op
|
|
{
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
int32_t h1, h2;
|
|
int64_t result;
|
|
uint32_t lo = DSPLO(ac);
|
|
uint32_t hi = DSPHI(ac);
|
|
uint32_t resultlo;
|
|
uint32_t resulthi;
|
|
uint32_t carry;
|
|
uint64_t temp1;
|
|
int64_t temp2;
|
|
h1 = (int32_t) v1;
|
|
h2 = (int32_t) v2;
|
|
if (h1 == 0x80000000 && h2 == 0x80000000)
|
|
{
|
|
DSPCR |= (1 << (DSPCR_OUFLAG_SHIFT + ac));
|
|
result = (int64_t) 0x7fffffffffffffffLL;
|
|
}
|
|
else
|
|
result = ((int64_t)h1 * (int64_t)h2) << 1;
|
|
resultlo = (uint32_t)(result);
|
|
resulthi = (uint32_t)(result >> 32);
|
|
if (op ==0) // DPAQ
|
|
{
|
|
temp1 = (uint64_t)lo + (uint64_t)resultlo;
|
|
carry = (uint32_t)((temp1 >> 32) & 1);
|
|
temp2 = (int64_t)((int32_t)hi) + (int64_t)((int32_t)resulthi) +
|
|
(int64_t)((int32_t)carry);
|
|
}
|
|
else // DPSQ
|
|
{
|
|
temp1 = (uint64_t)lo - (uint64_t)resultlo;
|
|
carry = (uint32_t)((temp1 >> 32) & 1);
|
|
temp2 = (int64_t)((int32_t)hi) - (int64_t)((int32_t)resulthi) -
|
|
(int64_t)((int32_t)carry);
|
|
}
|
|
if (((temp2 & 0x100000000LL) >> 1) != (temp2 & 0x80000000LL))
|
|
{
|
|
DSPCR |= (1 << (DSPCR_OUFLAG_SHIFT + ac));
|
|
if (temp2 & 0x100000000LL)
|
|
{
|
|
DSPLO(ac) = EXTEND32 (0x00000000);
|
|
DSPHI(ac) = EXTEND32 (0x80000000);
|
|
}
|
|
else
|
|
{
|
|
DSPLO(ac) = EXTEND32 (0xffffffff);
|
|
DSPHI(ac) = EXTEND32 (0x7fffffff);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DSPLO(ac) = EXTEND32 (temp1);
|
|
DSPHI(ac) = EXTEND32 (temp2);
|
|
}
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,01100,110000:SPECIAL3:32::DPAQ_SA.L.W
|
|
"dpaq_sa.l.w ac<AC>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_w_dot_product (SD_, AC, RS, RT, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,01101,110000:SPECIAL3:32::DPSQ_SA.L.W
|
|
"dpsq_sa.l.w ac<AC>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_w_dot_product (SD_, AC, RS, RT, 1);
|
|
}
|
|
|
|
// op: 0 = MAQ_S 1 = MAQ_SA
|
|
// loc: 0 = phl, 1 = phr
|
|
:function:::void:do_ph_maq:int ac, int rs, int rt, int op, int loc
|
|
{
|
|
int i;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
int16_t h1, h2;
|
|
int32_t result;
|
|
uint32_t lo = DSPLO(ac);
|
|
uint32_t hi = DSPHI(ac);
|
|
int64_t prod = (int64_t)((((uint64_t)hi) << 32) + (uint64_t)lo);
|
|
if (loc == 0)
|
|
{
|
|
h1 = (int16_t)(v1 >> 16);
|
|
h2 = (int16_t)(v2 >> 16);
|
|
}
|
|
else
|
|
{
|
|
h1 = (int16_t)(v1 & 0xffff);
|
|
h2 = (int16_t)(v2 & 0xffff);
|
|
}
|
|
if (h1 == (int16_t)0x8000 && h2 == (int16_t)0x8000)
|
|
{
|
|
DSPCR |= (1 << (DSPCR_OUFLAG_SHIFT + ac));
|
|
result = (int32_t)0x7fffffff;
|
|
}
|
|
else
|
|
result = ((int32_t)h1 * (int32_t)h2) << 1;
|
|
prod += (int64_t)result;
|
|
if (op == 1) // MAQ_SA
|
|
{
|
|
if (prod & 0x8000000000000000LL)
|
|
{
|
|
for (i = 62; i >= 31; i--)
|
|
{
|
|
if (!(prod & ((int64_t)1 << i)))
|
|
{
|
|
DSPCR |= (1 << (DSPCR_OUFLAG_SHIFT + ac));
|
|
prod = 0xffffffff80000000LL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 62; i >= 31; i--)
|
|
{
|
|
if (prod & ((int64_t)1 << i))
|
|
{
|
|
DSPCR |= (1 << (DSPCR_OUFLAG_SHIFT + ac));
|
|
prod = 0x7fffffff;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
DSPLO(ac) = EXTEND32 (prod);
|
|
DSPHI(ac) = EXTEND32 (prod >> 32);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,10100,110000:SPECIAL3:32::MAQ_S.W.PHL
|
|
"maq_s.w.phl ac<AC>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_maq (SD_, AC, RS, RT, 0, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,10110,110000:SPECIAL3:32::MAQ_S.W.PHR
|
|
"maq_s.w.phr ac<AC>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_maq (SD_, AC, RS, RT, 0, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,10000,110000:SPECIAL3:32::MAQ_SA.W.PHL
|
|
"maq_sa.w.phl ac<AC>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_maq (SD_, AC, RS, RT, 1, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,10010,110000:SPECIAL3:32::MAQ_SA.W.PHR
|
|
"maq_sa.w.phr ac<AC>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_maq (SD_, AC, RS, RT, 1, 1);
|
|
}
|
|
|
|
011111,00000,5.RT,5.RD,11011,010010:SPECIAL3:32::BITREV
|
|
"bitrev r<RD>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_bitrev (SD_, RD, RT);
|
|
}
|
|
|
|
011111,5.RS,5.RT,00000,00000,001100:SPECIAL3:32::INSV
|
|
"insv r<RT>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_insv (SD_, RT, RS);
|
|
}
|
|
|
|
011111,00,8.IMM8,5.RD,00010,010010:SPECIAL3:32::REPL.QB
|
|
"repl.qb r<RD>, <IMM8>"
|
|
*dsp:
|
|
{
|
|
do_repl (SD_, RD, IMM8, 0);
|
|
}
|
|
|
|
011111,00000,5.RT,5.RD,00011,010010:SPECIAL3:32::REPLV.QB
|
|
"replv.qb r<RD>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_repl (SD_, RD, RT, 1);
|
|
}
|
|
|
|
011111,10.IMM10,5.RD,01010,010010:SPECIAL3:32::REPL.PH
|
|
"repl.ph r<RD>, <IMM10>"
|
|
*dsp:
|
|
{
|
|
do_repl (SD_, RD, IMM10, 2);
|
|
}
|
|
|
|
011111,00000,5.RT,5.RD,01011,010010:SPECIAL3:32::REPLV.PH
|
|
"replv.ph r<RD>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_repl (SD_, RD, RT, 3);
|
|
}
|
|
|
|
// op: 0 = EQ, 1 = LT, 2 = LE
|
|
:function:::void:do_qb_cmpu:int rs, int rt, int op
|
|
{
|
|
int i, j;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
uint8_t h1, h2;
|
|
uint32_t mask;
|
|
for (i = 0, j = 0; i < 32; i += 8, j++, v1 >>= 8, v2 >>= 8)
|
|
{
|
|
h1 = (uint8_t)(v1 & 0xff);
|
|
h2 = (uint8_t)(v2 & 0xff);
|
|
mask = ~(1 << (DSPCR_CCOND_SHIFT + j));
|
|
DSPCR &= mask;
|
|
if (op == 0) // EQ
|
|
DSPCR |= ((h1 == h2) << (DSPCR_CCOND_SHIFT + j));
|
|
else if (op == 1) // LT
|
|
DSPCR |= ((h1 < h2) << (DSPCR_CCOND_SHIFT + j));
|
|
else // LE
|
|
DSPCR |= ((h1 <= h2) << (DSPCR_CCOND_SHIFT + j));
|
|
}
|
|
}
|
|
|
|
011111,5.RS,5.RT,00000,00000,010001:SPECIAL3:32::CMPU.EQ.QB
|
|
"cmpu.eq.qb r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_cmpu (SD_, RS, RT, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,00000,00001,010001:SPECIAL3:32::CMPU.LT.QB
|
|
"cmpu.lt.qb r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_cmpu (SD_, RS, RT, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,00000,00010,010001:SPECIAL3:32::CMPU.LE.QB
|
|
"cmpu.le.qb r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_cmpu (SD_, RS, RT, 2);
|
|
}
|
|
|
|
// op: 0 = EQ, 1 = LT, 2 = LE
|
|
:function:::void:do_qb_cmpgu:int rd, int rs, int rt, int op
|
|
{
|
|
int i, j;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
uint8_t h1, h2;
|
|
uint32_t result = 0;
|
|
for (i = 0, j = 0; i < 32; i += 8, j++, v1 >>= 8, v2 >>= 8)
|
|
{
|
|
h1 = (uint8_t)(v1 & 0xff);
|
|
h2 = (uint8_t)(v2 & 0xff);
|
|
if (op == 0) // EQ
|
|
result |= ((h1 == h2) << j);
|
|
else if (op == 1) // LT
|
|
result |= ((h1 < h2) << j);
|
|
else // LE
|
|
result |= ((h1 <= h2) << j);
|
|
}
|
|
GPR[rd] = EXTEND32 (result);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,00100,010001:SPECIAL3:32::CMPGU.EQ.QB
|
|
"cmpgu.eq.qb r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_cmpgu (SD_, RD, RS, RT, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,00101,010001:SPECIAL3:32::CMPGU.LT.QB
|
|
"cmpgu.lt.qb r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_cmpgu (SD_, RD, RS, RT, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,00110,010001:SPECIAL3:32::CMPGU.LE.QB
|
|
"cmpgu.le.qb r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_cmpgu (SD_, RD, RS, RT, 2);
|
|
}
|
|
|
|
// op: 0 = EQ, 1 = LT, 2 = LE
|
|
:function:::void:do_ph_cmpu:int rs, int rt, int op
|
|
{
|
|
int i, j;
|
|
uint32_t v1 = GPR[rs];
|
|
uint32_t v2 = GPR[rt];
|
|
int16_t h1, h2;
|
|
uint32_t mask;
|
|
for (i = 0, j = 0; i < 32; i += 16, j++, v1 >>= 16, v2 >>= 16)
|
|
{
|
|
h1 = (int16_t)(v1 & 0xffff);
|
|
h2 = (int16_t)(v2 & 0xffff);
|
|
mask = ~(1 << (DSPCR_CCOND_SHIFT + j));
|
|
DSPCR &= mask;
|
|
if (op == 0) // EQ
|
|
DSPCR |= ((h1 == h2) << (DSPCR_CCOND_SHIFT + j));
|
|
else if (op == 1) // LT
|
|
DSPCR |= ((h1 < h2) << (DSPCR_CCOND_SHIFT + j));
|
|
else // LE
|
|
DSPCR |= ((h1 <= h2) << (DSPCR_CCOND_SHIFT + j));
|
|
}
|
|
}
|
|
|
|
011111,5.RS,5.RT,00000,01000,010001:SPECIAL3:32::CMP.EQ.PH
|
|
"cmp.eq.ph r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_cmpu (SD_, RS, RT, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,00000,01001,010001:SPECIAL3:32::CMP.LT.PH
|
|
"cmp.lt.ph r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_cmpu (SD_, RS, RT, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,00000,01010,010001:SPECIAL3:32::CMP.LE.PH
|
|
"cmp.le.ph r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_cmpu (SD_, RS, RT, 2);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,00011,010001:SPECIAL3:32::PICK.QB
|
|
"pick.qb r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_qb_pick (SD_, RD, RS, RT);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,01011,010001:SPECIAL3:32::PICK.PH
|
|
"pick.ph r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_pick (SD_, RD, RS, RT);
|
|
}
|
|
|
|
011111,5.RS,5.RT,5.RD,01110,010001:SPECIAL3:32::PACKRL.PH
|
|
"packrl.ph r<RD>, r<RS>, r<RT>"
|
|
*dsp:
|
|
{
|
|
do_ph_packrl (SD_, RD, RS, RT);
|
|
}
|
|
|
|
// op: 0 = EXTR, 1 = EXTR_R, 2 = EXTR_RS
|
|
:function:::void:do_w_extr:int rt, int ac, int shift, int op
|
|
{
|
|
int i;
|
|
uint32_t lo = DSPLO(ac);
|
|
uint32_t hi = DSPHI(ac);
|
|
uint64_t prod = (((uint64_t)hi) << 32) + (uint64_t)lo;
|
|
int64_t result = (int64_t)prod;
|
|
int setcond = 0;
|
|
if (!(prod & 0x8000000000000000LL))
|
|
{
|
|
for (i = 62; i >= (shift + 31); i--)
|
|
{
|
|
if (prod & ((uint64_t)1 << i))
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG7;
|
|
setcond = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (((prod >> (shift - 1)) & 0xffffffffLL) == 0xffffffffLL)
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG7;
|
|
setcond = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 62; i >= (shift + 31); i--)
|
|
{
|
|
if (!(prod & ((uint64_t)1 << i)))
|
|
{
|
|
DSPCR |= DSPCR_OUFLAG7;
|
|
setcond = 2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (op == 0) // EXTR
|
|
result = result >> shift;
|
|
else if (op == 1) // EXTR_R
|
|
{
|
|
if (shift != 0)
|
|
result = ((result >> (shift - 1)) + 1) >> 1;
|
|
else
|
|
result = result >> shift;
|
|
}
|
|
else // EXTR_RS
|
|
{
|
|
if (setcond == 1)
|
|
result = 0x7fffffff;
|
|
else if (setcond == 2)
|
|
result = 0x80000000;
|
|
else
|
|
{
|
|
if (shift != 0)
|
|
result = ((result >> (shift - 1)) + 1) >> 1;
|
|
else
|
|
result = result >> shift;
|
|
}
|
|
}
|
|
GPR[rt] = EXTEND32 (result);
|
|
}
|
|
|
|
011111,5.SHIFT,5.RT,000,2.AC,00000,111000:SPECIAL3:32::EXTR.W
|
|
"extr.w r<RT>, ac<AC>, <SHIFT>"
|
|
*dsp:
|
|
{
|
|
do_w_extr (SD_, RT, AC, SHIFT, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,00001,111000:SPECIAL3:32::EXTRV.W
|
|
"extrv.w r<RT>, ac<AC>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_extrv (SD_, RT, AC, RS, 0);
|
|
}
|
|
|
|
011111,5.SHIFT,5.RT,000,2.AC,00100,111000:SPECIAL3:32::EXTR_R.W
|
|
"extr_r.w r<RT>, ac<AC>, <SHIFT>"
|
|
*dsp:
|
|
{
|
|
do_w_extr (SD_, RT, AC, SHIFT, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,00101,111000:SPECIAL3:32::EXTRV_R.W
|
|
"extrv_r.w r<RT>, ac<AC>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_extrv (SD_, RT, AC, RS, 1);
|
|
}
|
|
|
|
011111,5.SHIFT,5.RT,000,2.AC,00110,111000:SPECIAL3:32::EXTR_RS.W
|
|
"extr_rs.w r<RT>, ac<AC>, <SHIFT>"
|
|
*dsp:
|
|
{
|
|
do_w_extr (SD_, RT, AC, SHIFT, 2);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,00111,111000:SPECIAL3:32::EXTRV_RS.W
|
|
"extrv_rs.w r<RT>, ac<AC>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_extrv (SD_, RT, AC, RS, 2);
|
|
}
|
|
|
|
:function:::void:do_h_extr:int rt, int ac, int shift
|
|
{
|
|
uint32_t lo = DSPLO(ac);
|
|
uint32_t hi = DSPHI(ac);
|
|
uint64_t prod = (((uint64_t)hi) << 32) + (uint64_t)lo;
|
|
int64_t result = (int64_t)prod;
|
|
int64_t value = 0xffffffffffff8000LL;
|
|
result >>= shift;
|
|
if (result > 0x7fff)
|
|
{
|
|
result = 0x7fff;
|
|
DSPCR |= DSPCR_OUFLAG7;
|
|
}
|
|
else if (result < value)
|
|
{
|
|
result = value;
|
|
DSPCR |= DSPCR_OUFLAG7;
|
|
}
|
|
GPR[rt] = EXTEND32 (result);
|
|
}
|
|
|
|
011111,5.SHIFT,5.RT,000,2.AC,01110,111000:SPECIAL3:32::EXTR_S.H
|
|
"extr_s.h r<RT>, ac<AC>, <SHIFT>"
|
|
*dsp:
|
|
{
|
|
do_h_extr (SD_, RT, AC, SHIFT);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,01111,111000:SPECIAL3:32::EXTRV_S.H
|
|
"extrv_s.h r<RT>, ac<AC>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_extrv_s_h (SD_, RT, AC, RS);
|
|
}
|
|
|
|
// op: 0 = EXTP, 1 = EXTPDP
|
|
:function:::void:do_extp:int rt, int ac, int size, int op
|
|
{
|
|
int32_t pos = (DSPCR >> DSPCR_POS_SHIFT) & DSPCR_POS_MASK;
|
|
uint32_t lo = DSPLO(ac);
|
|
uint32_t hi = DSPHI(ac);
|
|
uint64_t prod = (((uint64_t)hi) << 32) + (uint64_t)lo;
|
|
uint64_t result = 0;
|
|
if (pos - (size + 1) >= -1)
|
|
{
|
|
prod >>= (pos - size);
|
|
result = prod & (((uint64_t)1 << (size + 1)) - 1);
|
|
DSPCR &= (~DSPCR_EFI_SMASK);
|
|
if (op == 1) // EXTPDP
|
|
{
|
|
if (pos - (size + 1) >= 0)
|
|
{
|
|
DSPCR &= (~DSPCR_POS_SMASK);
|
|
DSPCR |= ((pos - (size + 1)) & DSPCR_POS_MASK) << DSPCR_POS_SHIFT;
|
|
}
|
|
else if (pos - (size + 1) == -1)
|
|
{
|
|
DSPCR |= DSPCR_POS_SMASK;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DSPCR |= DSPCR_EFI;
|
|
Unpredictable ();
|
|
}
|
|
GPR[rt] = EXTEND32 (result);
|
|
}
|
|
|
|
011111,5.SIZE,5.RT,000,2.AC,00010,111000:SPECIAL3:32::EXTP
|
|
"extp r<RT>, ac<AC>, <SIZE>"
|
|
*dsp:
|
|
{
|
|
do_extp (SD_, RT, AC, SIZE, 0);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,00011,111000:SPECIAL3:32::EXTPV
|
|
"extpv r<RT>, ac<AC>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_extpv (SD_, RT, AC, RS, 0);
|
|
}
|
|
|
|
011111,5.SIZE,5.RT,000,2.AC,01010,111000:SPECIAL3:32::EXTPDP
|
|
"extpdp r<RT>, ac<AC>, <SIZE>"
|
|
*dsp:
|
|
{
|
|
do_extp (SD_, RT, AC, SIZE, 1);
|
|
}
|
|
|
|
011111,5.RS,5.RT,000,2.AC,01011,111000:SPECIAL3:32::EXTPDPV
|
|
"extpdpv r<RT>, ac<AC>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_extpv (SD_, RT, AC, RS, 1);
|
|
}
|
|
|
|
:function:::void:do_shilo:int ac, int shift
|
|
{
|
|
uint32_t lo = DSPLO(ac);
|
|
uint32_t hi = DSPHI(ac);
|
|
uint64_t prod = (((uint64_t)hi) << 32) + (uint64_t)lo;
|
|
if (shift > 31)
|
|
shift = shift - 64;
|
|
if (shift >= 0)
|
|
prod >>= shift;
|
|
else
|
|
prod <<= (-shift);
|
|
DSPLO(ac) = EXTEND32 (prod);
|
|
DSPHI(ac) = EXTEND32 (prod >> 32);
|
|
}
|
|
|
|
011111,6.SHIFT6,0000,000,2.AC,11010,111000:SPECIAL3:32::SHILO
|
|
"shilo ac<AC>, <SHIFT6>"
|
|
*dsp:
|
|
{
|
|
do_shilo (SD_, AC, SHIFT6);
|
|
}
|
|
|
|
011111,5.RS,00000,000,2.AC,11011,111000:SPECIAL3:32::SHILOV
|
|
"shilov ac<AC>, r<RS>"
|
|
*dsp:
|
|
{
|
|
do_shilov (SD_, AC, RS);
|
|
}
|
|
|
|
011111,5.RS,00000,000,2.AC,11111,111000:SPECIAL3:32::MTHLIP
|
|
"mthlip r<RS>, ac<AC>"
|
|
*dsp:
|
|
{
|
|
do_mthlip (SD_, RS, AC);
|
|
}
|
|
|
|
011111,5.RS,10.MASK10,10011,111000:SPECIAL3:32::WRDSP
|
|
"wrdsp r<RS>":MASK10 == 1111111111
|
|
"wrdsp r<RS>, <MASK10>"
|
|
*dsp:
|
|
{
|
|
do_wrdsp (SD_, RS, MASK10);
|
|
}
|
|
|
|
011111,10.MASK10,5.RD,10010,111000:SPECIAL3:32::RDDSP
|
|
"rddsp r<RD>":MASK10 == 1111111111
|
|
"rddsp r<RD>, <MASK10>"
|
|
*dsp:
|
|
{
|
|
do_rddsp (SD_, RD, MASK10);
|
|
}
|
|
|
|
011111,5.BASE,5.INDEX,5.RD,00110,001010:SPECIAL3:32::LBUX
|
|
"lbux r<RD>, r<INDEX>(r<BASE>)"
|
|
*dsp:
|
|
{
|
|
do_lxx (SD_, RD, BASE, INDEX, 0);
|
|
}
|
|
|
|
011111,5.BASE,5.INDEX,5.RD,00100,001010:SPECIAL3:32::LHX
|
|
"lhx r<RD>, r<INDEX>(r<BASE>)"
|
|
*dsp:
|
|
{
|
|
do_lxx (SD_, RD, BASE, INDEX, 1);
|
|
}
|
|
|
|
011111,5.BASE,5.INDEX,5.RD,00000,001010:SPECIAL3:32::LWX
|
|
"lwx r<RD>, r<INDEX>(r<BASE>)"
|
|
*dsp:
|
|
{
|
|
do_lxx (SD_, RD, BASE, INDEX, 2);
|
|
}
|
|
|
|
000001,00000,11100,16.OFFSET:REGIMM:32::BPOSGE32
|
|
"bposge32 <OFFSET>"
|
|
*dsp:
|
|
{
|
|
uint32_t pos = (DSPCR >> DSPCR_POS_SHIFT) & DSPCR_POS_MASK;
|
|
address_word offset = EXTEND16 (OFFSET) << 2;
|
|
if (pos >= 32)
|
|
{
|
|
DELAY_SLOT (NIA + offset);
|
|
}
|
|
}
|