// -*- C -*-
// Simulator definition for the MIPS DSP ASE.
// Copyright (C) 2005-2015 Free Software Foundation, Inc.
// Contributed by MIPS Technologies, Inc. Written by Chao-ying Fu.
//
// This file is part of GDB, the GNU debugger.
//
// 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 .
// 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;
signed32 h0 = 0;
signed16 h1, h2;
unsigned32 v1 = GPR[rs];
unsigned32 v2 = GPR[rt];
unsigned32 result = 0;
for (i = 0; i < 32; i += 16, v1 >>= 16, v2 >>= 16)
{
h1 = (signed16)(v1 & 0xffff);
h2 = (signed16)(v2 & 0xffff);
if (op == 0) // ADD
h0 = (signed32)h1 + (signed32)h2;
else if (op == 1) // SUB
h0 = (signed32)h1 - (signed32)h2;
else // MUL
h0 = (signed32)h1 * (signed32)h2;
if (h0 > (signed32)0x7fff || h0 < (signed32)0xffff8000)
{
if (op == 0 || op == 1) // ADD, SUB
DSPCR |= DSPCR_OUFLAG4;
else if (op == 2) // MUL
DSPCR |= DSPCR_OUFLAG5;
if (sat == 1)
{
if (h0 > (signed32)0x7fff)
h0 = 0x7fff;
else
h0 = 0x8000;
}
}
result |= ((unsigned32)((unsigned16)h0) << i);
}
GPR[rd] = EXTEND32 (result);
}
// op: 0 = ADD, 1 = SUB
:function:::void:do_w_op:int rd, int rs, int rt, int op
{
signed64 h0;
signed32 h1, h2;
unsigned32 v1 = GPR[rs];
unsigned32 v2 = GPR[rt];
unsigned32 result = 0;
h1 = (signed32)v1;
h2 = (signed32)v2;
if (op == 0) // ADD
h0 = (signed64)h1 + (signed64)h2;
else // SUB
h0 = (signed64)h1 - (signed64)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;
unsigned32 h0;
unsigned8 h1, h2;
unsigned32 v1 = GPR[rs];
unsigned32 v2 = GPR[rt];
unsigned32 result = 0;
for (i = 0; i < 32; i += 8, v1 >>= 8, v2 >>= 8)
{
h1 = (unsigned8)(v1 & 0xff);
h2 = (unsigned8)(v2 & 0xff);
if (op == 0) // ADD
h0 = (unsigned32)h1 + (unsigned32)h2;
else // SUB
h0 = (unsigned32)h1 - (unsigned32)h2;
if (h0 & 0x100)
{
DSPCR |= DSPCR_OUFLAG4;
if (sat == 1)
{
if (op == 0) // ADD
h0 = 0xff;
else // SUB
h0 = 0;
}
}
result |= ((unsigned32)((unsigned8)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;
unsigned8 h0;
unsigned32 v1 = GPR[rt];
unsigned32 result = 0;
for (i = 0; i < 32; i += 8, v1 >>= 8)
{
h0 = (unsigned8)(v1 & 0xff);
if (op == 0) // left
{
for (j = 7; j >= 8 - shift; j--)
{
if (h0 & (1<> shift;
result |= ((unsigned32)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;
signed16 h0;
unsigned32 v1 = GPR[rt];
unsigned32 result = 0;
int setcond;
for (i = 0; i < 32; i += 16, v1 >>= 16)
{
h0 = (signed16)(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 |= ((unsigned32)((unsigned16)h0) << i);
}
GPR[rd] = EXTEND32 (result);
}
:function:::void:do_w_shll:int rd, int rt, int shift
{
int i;
unsigned32 v1 = GPR[rt];
unsigned32 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_w_shra:int rd, int rt, int shift
{
unsigned32 result = GPR[rt];
signed32 h0 = (signed32)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, r, r