mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-12-04 10:24:13 +00:00
01737f42d8
common, igen: Fix MP related bugs.
1299 lines
26 KiB
Plaintext
1299 lines
26 KiB
Plaintext
// Media Instructions
|
|
// ------------------
|
|
|
|
// Ref: http://www.sgi.com/MIPS/arch/ISA5/MDMXspec.pdf
|
|
|
|
// Note: For OB instructions, the sel field is deduced by special
|
|
// handling of the "vt" operand.
|
|
// If vt is:
|
|
// of the form $vt[0], then sel is 0000
|
|
// of the form $vt[1], then sel is 0001
|
|
// of the form $vt[2], then sel is 0010
|
|
// of the form $vt[3], then sel is 0011
|
|
// of the form $vt[4], then sel is 0100
|
|
// of the form $vt[5], then sel is 0101
|
|
// of the form $vt[6], then sel is 0110
|
|
// of the form $vt[7], then sel is 0111
|
|
// Normal register specifier, then sel is 1011
|
|
// Constant, then sel is 1111
|
|
//
|
|
// VecAcc is the Vector Accumulator.
|
|
// This accumulator is organized as 8X24 bit (192 bit) register.
|
|
// This accumulator holds only signed values.
|
|
|
|
|
|
// Verify that the instruction is valid for the curent Architecture
|
|
// If valid, return the scale (log nr bits) of a vector element
|
|
// as determined by SEL.
|
|
|
|
:function:::int:get_scale:int sel
|
|
{
|
|
#if 0
|
|
switch (my_index X STATE_ARCHITECTURE)
|
|
{
|
|
}
|
|
#endif
|
|
switch (sel & 0x7)
|
|
{
|
|
case 0:
|
|
case 2:
|
|
case 4:
|
|
case 6:
|
|
/* octal byte - ssss0 */
|
|
return 0;
|
|
case 1:
|
|
case 5:
|
|
/* quad halfword - sss01 */
|
|
return 1;
|
|
case 3:
|
|
/* bi word - ss011 */
|
|
semantic_illegal (CPU_, cia);
|
|
return 2;
|
|
case 7:
|
|
/* long - ss111 */
|
|
semantic_illegal (CPU_, cia);
|
|
return 3;
|
|
default:
|
|
abort ();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
// Fetch/Store VALUE in ELEMENT of vector register FPR.
|
|
// The the of the element determined by SCALE.
|
|
|
|
:function:::signed:value_vr:int scale, int fpr, int el
|
|
{
|
|
switch (FPR_STATE[fpr])
|
|
{
|
|
case fmt_uninterpreted:
|
|
FPR_STATE[fpr] = fmt_long;
|
|
break;
|
|
case fmt_long:
|
|
case fmt_unknown:
|
|
break;
|
|
default:
|
|
sim_io_eprintf (SD, "Vector %d format invalid (PC = 0x%08lx)\n",
|
|
fpr, (long) CIA);
|
|
FPR_STATE[fpr] = fmt_unknown;
|
|
}
|
|
switch (scale)
|
|
{
|
|
case 0:
|
|
{
|
|
signed8 value = *A1_8 (&FGR[fpr], 7 - el);
|
|
return value;
|
|
}
|
|
case 1:
|
|
{
|
|
signed16 value = *A2_8 (&FGR[fpr], 3 - el);
|
|
return value;
|
|
}
|
|
default:
|
|
abort;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
:function:::void:store_vr:int scale, int fpr, int element, signed value
|
|
{
|
|
switch (FPR_STATE[fpr])
|
|
{
|
|
case fmt_uninterpreted:
|
|
FPR_STATE[fpr] = fmt_long;
|
|
break;
|
|
case fmt_long:
|
|
case fmt_unknown:
|
|
break;
|
|
default:
|
|
sim_io_eprintf (SD, "Vector %d format invalid (PC = 0x%08lx)\n",
|
|
fpr, (long) cia);
|
|
FPR_STATE[fpr] = fmt_unknown;
|
|
}
|
|
switch (scale)
|
|
{
|
|
case 0:
|
|
{
|
|
*A1_8 (&FGR[fpr], 7 - element) = value;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
*A2_8 (&FGR[fpr], 3 - element) = value;
|
|
break;
|
|
}
|
|
default:
|
|
abort ();
|
|
}
|
|
}
|
|
|
|
|
|
// Select a value from onr of FGR[VT][ELEMENT], VT and GFR[VT][CONST]
|
|
// according to SEL
|
|
|
|
:function:::unsigned:select_vr:int sel, int vt, int element
|
|
{
|
|
switch (sel)
|
|
{
|
|
/* element select - 0xxxx */
|
|
case 0x00: /* 0 xxx 0 */
|
|
case 0x02:
|
|
case 0x04:
|
|
case 0x06:
|
|
case 0x08:
|
|
case 0x0a:
|
|
case 0x0c:
|
|
case 0x0e:
|
|
return value_vr (SD_, 0, vt, sel >> 1);
|
|
case 0x01: /* 0 xx 01 */
|
|
case 0x05:
|
|
case 0x09:
|
|
case 0x0d:
|
|
return value_vr (SD_, 1, vt, sel >> 2);
|
|
case 0x03: /* 0 x 011 */
|
|
case 0x0b:
|
|
return value_vr (SD_, 2, vt, sel >> 3);
|
|
case 0x07: /* 0 x 111 */
|
|
case 0x0f:
|
|
return value_vr (SD_, 3, vt, sel >> 4);
|
|
|
|
/* select vector - 10xxx */
|
|
case 0x16: /* 10 11 0 */
|
|
return value_vr (SD_, 0, vt, element);
|
|
case 0x15: /* 10 1 01 */
|
|
return value_vr (SD_, 1, vt, element);
|
|
case 0x13: /* 10 011 */
|
|
return value_vr (SD_, 2, vt, element);
|
|
case 0x17: /* 10 111 */
|
|
return value_vr (SD_, 3, vt, element);
|
|
|
|
/* select immediate - 11xxx */
|
|
case 0x1e: /* 11 11 0 */
|
|
case 0x1d: /* 11 1 01 */
|
|
case 0x1b: /* 11 011 */
|
|
case 0x1f: /* 11 111 */
|
|
return vt;
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Saturate (clamp) the signed value to (8 << SCALE) bits.
|
|
|
|
:function:::signed:Clamp:int scale, signed value
|
|
{
|
|
switch (scale)
|
|
{
|
|
case 0:
|
|
{
|
|
if (value != (signed8) value)
|
|
{
|
|
if (value > 0)
|
|
return 0x7f;
|
|
else
|
|
return 0x80;
|
|
}
|
|
return value & 0xff;
|
|
}
|
|
case 1:
|
|
{
|
|
if (value != (signed16) value)
|
|
{
|
|
if (value > 0)
|
|
return 0x7fff;
|
|
else
|
|
return 0x8000;
|
|
}
|
|
return value & 0xffff;
|
|
}
|
|
default:
|
|
abort ();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
// Access a single bit of the floating point CC register.
|
|
|
|
:function:::void:store_cc:int i, int value
|
|
{
|
|
SETFCC (i, value);
|
|
}
|
|
|
|
:function:::int:value_cc:int i
|
|
{
|
|
return GETFCC (i);
|
|
}
|
|
|
|
|
|
// Read/write the accumulator
|
|
|
|
:function:::signed64:value_acc:int scale, int element
|
|
{
|
|
signed64 value = 0;
|
|
switch (scale)
|
|
{
|
|
case 0:
|
|
value |= (unsigned64) (unsigned8) CPU->acc [element * 3 + 0];
|
|
value |= (unsigned64) (unsigned8) CPU->acc [element * 3 + 1] << 8;
|
|
value |= (signed64) (signed8) CPU->acc [element * 3 + 2] << 16;
|
|
break;
|
|
case 1:
|
|
value |= (unsigned64) (unsigned8) CPU->acc [element * 3 + 0];
|
|
value |= (unsigned64) (unsigned8) CPU->acc [element * 3 + 1] << 8;
|
|
value |= (unsigned64) (unsigned8) CPU->acc [element * 3 + 2] << 16;
|
|
value |= (unsigned64) (unsigned8) CPU->acc [element * 3 + 3] << 24;
|
|
value |= (unsigned64) (unsigned8) CPU->acc [element * 3 + 4] << 32;
|
|
value |= (signed64) (signed8) CPU->acc [element * 3 + 5] << 40;
|
|
break;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
:function:::void:store_acc:int scale, int element, signed64 value
|
|
{
|
|
switch (scale)
|
|
{
|
|
case 0:
|
|
CPU->acc [element * 3 + 0] = value >> 0;
|
|
CPU->acc [element * 3 + 1] = value >> 8;
|
|
CPU->acc [element * 3 + 2] = value >> 16;
|
|
break;
|
|
case 1:
|
|
CPU->acc [element * 3 + 0] = value >> 0;
|
|
CPU->acc [element * 3 + 1] = value >> 8;
|
|
CPU->acc [element * 3 + 2] = value >> 16;
|
|
CPU->acc [element * 3 + 3] = value >> 24;
|
|
CPU->acc [element * 3 + 4] = value >> 32;
|
|
CPU->acc [element * 3 + 5] = value >> 40;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// Formatting
|
|
|
|
:%s::::VT:int sel, int vt
|
|
{
|
|
static char buf[20];
|
|
if (sel < 8)
|
|
sprintf (buf, "v%d[%d]", vt, sel);
|
|
else if (sel == 0x13)
|
|
sprintf (buf, "v%d", vt);
|
|
else if (sel == 0x1f)
|
|
sprintf (buf, "%d", vt);
|
|
else
|
|
sprintf (buf, "(invalid)");
|
|
return buf;
|
|
}
|
|
|
|
:%s::::SEL:int sel
|
|
{
|
|
switch (sel & 7)
|
|
{
|
|
case 0:
|
|
case 2:
|
|
case 4:
|
|
case 6:
|
|
return "ob";
|
|
case 1:
|
|
case 5:
|
|
return "qh";
|
|
case 3:
|
|
return "bw";
|
|
default:
|
|
return "l";
|
|
}
|
|
}
|
|
|
|
|
|
// Vector Add.
|
|
|
|
010010,5.SEL,5.VT,5.VS,5.VD,001011::::ADD.fmt
|
|
"add.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
Clamp (SD_, scale,
|
|
(value_vr (SD_, scale, VS, i)
|
|
+ select_vr (SD_, SEL, VT, i))));
|
|
}
|
|
|
|
|
|
// Accumulate Vector Add
|
|
|
|
010010,5.SEL,5.VT,5.VS,1,0000,110111::::ADDA.fmt
|
|
"adda.%s<SEL> v<VD>, v<VS>"
|
|
*mdmx:
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_acc (SD_, scale, i,
|
|
(value_acc (SD_, scale, i)
|
|
+ (signed64) value_vr (SD_, scale, VS, i)
|
|
+ (signed64) select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
// Load Vector Add
|
|
|
|
010010,5.SEL,5.VT,5.VS,0,0000,110111::::ADDA.fmt
|
|
"addl.%s<SEL> v<VD>, v<VS>"
|
|
*mdmx:
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_acc (SD_, scale, i,
|
|
((signed64) value_vr (SD_, scale, VS, i)
|
|
+ (signed64) select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Vector align, Constant Alignment
|
|
|
|
:function:::void:ByteAlign:int vd, int imm, int vs, int vt
|
|
{
|
|
int s = imm * 8;
|
|
unsigned64 rs = ValueFPR (vs, fmt_long);
|
|
unsigned64 rt = ValueFPR (vt, fmt_long);
|
|
unsigned64 rd;
|
|
if (BigEndianCPU)
|
|
{
|
|
/* (vs || vt) [127 - S .. 64 - S] */
|
|
if (s == 0)
|
|
rd = rs;
|
|
else
|
|
rd = (MOVED64 (rs, 64 - s, 0, 63, s)
|
|
| EXTRACTED64 (rt, 63, 64 - s));
|
|
}
|
|
else
|
|
{
|
|
/* (vs || vt) [63 + S .. S] */
|
|
if (s == 0)
|
|
rd = rt;
|
|
else
|
|
rd = (MOVED64 (rs, s, 0, 63, 64 - s)
|
|
| EXTRACTED64 (rt, 63, s));
|
|
}
|
|
StoreFPR (vd, fmt_long, rd);
|
|
}
|
|
|
|
010010,00,3.IMM,5.VT,5.VS,5.VD,0110,X,0::::ALNI.fmt
|
|
"alni.%s<FMT#X> v<VD>, v<VS>, v<VT>, <IMM>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
ByteAlign (SD_, VD, IMM, VS, VT);
|
|
}
|
|
|
|
|
|
|
|
// Vector align, Variable Alignment
|
|
|
|
010010,5.RS,5.VT,5.VS,5.VD,0110,X,1::::ALNV.fmt
|
|
"alnv.%s<FMT#X> v<VD>, v<VS>, v<VT>, r<RS>"
|
|
*mdmx:
|
|
{
|
|
ByteAlign (SD_, VD, GPR[RS], VS, VT);
|
|
}
|
|
|
|
|
|
|
|
// Vector And.
|
|
|
|
010010,5.SEL,5.VT,5.VS,5.VD,001100::::AND.fmt
|
|
"and.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
(value_vr (SD_, scale, VS, i)
|
|
& select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Vector Compare Equal.
|
|
|
|
|
|
010010,5.SEL,5.VT,5.VS,00000,000001::::C.EQ.fmt
|
|
"c.EQ.%s<SEL> v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_cc (SD_, i,
|
|
(value_vr (SD_, scale, VS, i)
|
|
== select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Vector Compare Less Than or Equal.
|
|
|
|
010010,5.SEL,5.VT,5.VS,00000,000101::::C.LE.fmt
|
|
"c.le.%s<SEL> v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_cc (SD_, i,
|
|
(value_vr (SD_, scale, VS, i)
|
|
<= select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Vector Compare Less Than.
|
|
|
|
010010,5.SEL,5.VT,5.VS,00000,000100::::C.LT.fmt
|
|
"c.lt.%s<SEL> v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_cc (SD_, i,
|
|
(value_vr (SD_, scale, VS, i)
|
|
< select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Vector Maximum.
|
|
|
|
:function:::signed:Max:int scale, signed l, signed r
|
|
{
|
|
if (l < r)
|
|
return r;
|
|
else
|
|
return l;
|
|
}
|
|
|
|
010010,5.SEL,5.VT,5.VS,5.VD,000111::::MAX.fmt
|
|
"max.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
Max (SD_, scale,
|
|
value_vr (SD_, scale, VS, i),
|
|
select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Vector Minimum.
|
|
|
|
:function:::signed:Min:int scale, signed l, signed r
|
|
{
|
|
if (l < r)
|
|
return l;
|
|
else
|
|
return r;
|
|
}
|
|
|
|
010010,5.SEL,5.VT,5.VS,5.VD,000110::::MIN.fmt
|
|
"min.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
Min (SD_, scale,
|
|
value_vr (SD_, scale, VS, i),
|
|
select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Vector Sign.
|
|
|
|
:function:::signed:Sign:int scale, signed l, signed r
|
|
{
|
|
if (l >= 0)
|
|
return r;
|
|
else if (r >= 0)
|
|
return -r;
|
|
else
|
|
{
|
|
/* watch for overflow of MIN_INT */
|
|
switch (scale)
|
|
{
|
|
case 0:
|
|
if ((r & 0xff) == 0x80)
|
|
return 0x7ff;
|
|
else
|
|
return -r;
|
|
case 1:
|
|
if ((r & 0xffff) == 0x8000)
|
|
return 0x7ffff;
|
|
else
|
|
return -r;
|
|
default:
|
|
abort ();
|
|
}
|
|
return -r;
|
|
}
|
|
}
|
|
|
|
010010,5.SEL,5.VT,5.VS,5.VD,000110::::MSGN.fmt
|
|
"msgn.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
if ((SEL & 1) != 1)
|
|
/* only QH allowed */
|
|
semantic_illegal (sd, cia);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
Sign (SD_, scale,
|
|
value_vr (SD_, scale, VS, i),
|
|
select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Vector Multiply.
|
|
|
|
010010,5.SEL,5.VT,5.VS,5.VD,110000::::MUL.fmt
|
|
"mul.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
Clamp (SD_, scale,
|
|
(value_vr (SD_, scale, VS, i)
|
|
* select_vr (SD_, SEL, VT, i))));
|
|
}
|
|
|
|
|
|
|
|
// Accumulate Vector Multiply
|
|
|
|
010010,5.SEL,5.VT,5.VS,00000,110011::::MULA.fmt
|
|
"mula.%s<SEL> v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_acc (SD_, scale, i,
|
|
(value_acc (SD_, scale, i)
|
|
+ ((signed64) value_vr (SD_, scale, VS, i)
|
|
* (signed64) select_vr (SD_, SEL, VT, i))));
|
|
}
|
|
|
|
|
|
|
|
// Add Vector Multiply to Accumulator.
|
|
|
|
010010,5.SEL,5.VT,5.VS,10000,110011::::MULL.fmt
|
|
"mull.%s<SEL> v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_acc (SD_, scale, i,
|
|
((signed64) value_vr (SD_, scale, VS, i)
|
|
* (signed64) select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Subtract Vector Multiply from Accumulator
|
|
|
|
010010,5.SEL,5.VT,5.VS,00000,110010::::MULS.fmt
|
|
"muls.%s<SEL> v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_acc (SD_, scale, i,
|
|
(value_acc (SD_, scale, i)
|
|
- ((signed64) value_vr (SD_, scale, VS, i)
|
|
* (signed64) select_vr (SD_, SEL, VT, i))));
|
|
}
|
|
|
|
|
|
|
|
// Load Negative Vector Multiply
|
|
|
|
010010,5.SEL,5.VT,5.VS,10000,110010::::MULSL.fmt
|
|
"mulsl.%s<SEL> v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_acc (SD_, scale, i,
|
|
- ((signed64) value_vr (SD_, scale, VS, i)
|
|
* (signed64) select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Vector Nor.
|
|
|
|
010010,5.SEL,5.VT,5.VS,5.VD,001111::::NOR.fmt
|
|
"nor.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
~(value_vr (SD_, scale, VS, i)
|
|
| select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Vector Or.
|
|
|
|
010010,5.SEL,5.VT,5.VS,5.VD,001110::::OR.fmt
|
|
"or.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
(value_vr (SD_, scale, VS, i)
|
|
| select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Select Vector Elements - False
|
|
|
|
010010,5.SEL,5.VT,5.VS,5.VD,000010::::PICKF.fmt
|
|
"pickf.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
(value_cc (SD_, i) == 0
|
|
? value_vr (SD_, scale, VS, i)
|
|
: select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Select Vector Elements - True
|
|
|
|
010010,5.SEL,5.VT,5.VS,5.VD,000011::::PICKT.fmt
|
|
"pickt.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
(value_cc (SD_, i) != 0
|
|
? value_vr (SD_, scale, VS, i)
|
|
: select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Scale, Round and Clamp Accumulator
|
|
|
|
:%s::::RND:int rnd
|
|
{
|
|
switch (rnd)
|
|
{
|
|
case 0:
|
|
return "zu";
|
|
case 1:
|
|
return "nau";
|
|
case 2:
|
|
return "neu";
|
|
case 4:
|
|
return "rzs";
|
|
case 5:
|
|
return "nas";
|
|
case 6:
|
|
return "nes";
|
|
default:
|
|
return "(invalid)";
|
|
}
|
|
}
|
|
|
|
:function:::signed:ScaleRoundClamp:int scale, int rnd, signed val, signed shift
|
|
{
|
|
int halfway = (1 << (shift - 1));
|
|
/* must be positive */
|
|
if (shift < 0)
|
|
return 0;
|
|
/* too much shift? */
|
|
switch (scale)
|
|
{
|
|
case 0:
|
|
if (shift >= 24)
|
|
return 0;
|
|
break;
|
|
case 1:
|
|
if (shift >= 48)
|
|
return 0;
|
|
break;
|
|
default:
|
|
abort ();
|
|
}
|
|
/* round */
|
|
switch (rnd & 3)
|
|
{
|
|
case 0: /* round towards zero */
|
|
break;
|
|
case 1: /* nearest, halfaway rounds away from zero */
|
|
if (val >= 0)
|
|
val += halfway;
|
|
else
|
|
val -= halfway;
|
|
break;
|
|
case 2: /* nearest, halfway rounds to even! */
|
|
if (val >= 0)
|
|
{
|
|
if (val & (halfway << 1))
|
|
val += halfway;
|
|
else
|
|
val += (halfway - 1);
|
|
}
|
|
else
|
|
{
|
|
if (val & (halfway << 1))
|
|
val -= halfway;
|
|
else
|
|
val -= (halfway - 1);
|
|
}
|
|
default:
|
|
abort ();
|
|
}
|
|
/* shift */
|
|
val >>= shift;
|
|
/* clamp */
|
|
switch (rnd & 4)
|
|
{
|
|
case 0:
|
|
/* unsigned clamp */
|
|
if (val < 0)
|
|
val = 0;
|
|
else
|
|
switch (scale)
|
|
{
|
|
case 0:
|
|
if (val > 0xff)
|
|
val = 0xff;
|
|
break;
|
|
case 1:
|
|
if (val > 0xffff)
|
|
val = 0xffff;
|
|
break;
|
|
}
|
|
break;
|
|
case 8:
|
|
/* normal signed clamp */
|
|
val = Clamp (_SD, scale, val);
|
|
break;
|
|
}
|
|
return val;
|
|
}
|
|
|
|
010010,5.SEL,5.VT,00000,5.VD,100,3.RND::::Rx.fmt
|
|
"r%s<RND>.%s<SEL> v<VD>, v<VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
ScaleRoundClamp (SD_, scale, RND,
|
|
value_acc (SD_, scale, i),
|
|
select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Vector Read Accumulator Low.
|
|
|
|
010010,0000,1.SEL,00000,00000,5.VD,111111::::RACL.fmt
|
|
"racl.%s<SEL> v<VD>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
EXTRACTED (value_acc (SD_, scale, i),
|
|
(8 << scale) - 1,
|
|
0));
|
|
}
|
|
|
|
|
|
|
|
// Vector Read Accumulator Middle.
|
|
|
|
010010,0100,1.SEL,00000,00000,5.VD,111111::::RACM.fmt
|
|
"racm.%s<SEL> v<VD>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
EXTRACTED (value_acc (SD_, scale, i),
|
|
(16 << scale) - 1,
|
|
(8 << scale) - 0));
|
|
}
|
|
|
|
|
|
|
|
// Vector Read Accumulator High.
|
|
|
|
010010,1000,1.SEL,00000,00000,5.VD,111111::::RACH.fmt
|
|
"rach.%s<SEL> v<VD>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
EXTRACTED (value_acc (SD_, scale, i),
|
|
(24 << scale) - 1,
|
|
(16 << scale) - 0));
|
|
}
|
|
|
|
|
|
|
|
// Vector Element Shuffle.
|
|
|
|
010010,0000,0,5.VT,5.VS,5.VD,011111::::SHFL.UPUH.fmt
|
|
"shfl.upuh.%s<SEL> v<VD>, v<VS>, <VT>"
|
|
*mdmx:
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
store_vr (SD_, 1, VD, i,
|
|
value_vr (SD_, 0, VS, i + 4) & 0xff);
|
|
}
|
|
}
|
|
|
|
010010,0001,0,5.VT,5.VS,5.VD,011111::::SHFL.UPUL.fmt
|
|
"shfl.upul.%s<SEL> v<VD>, v<VS>, <VT>"
|
|
*mdmx:
|
|
{
|
|
int i;
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
store_vr (SD_, 1, VD, i,
|
|
value_vr (SD_, 0, VS, i) & 0xff);
|
|
}
|
|
}
|
|
|
|
010010,0000,0,5.VT,5.VS,5.VD,011111::::SHFL.UPSH.fmt
|
|
"shfl.upsh.%s<SEL> v<VD>, v<VS>, <VT>"
|
|
*mdmx:
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
store_vr (SD_, 1, VD, i,
|
|
value_vr (SD_, 0, VS, i + 4));
|
|
}
|
|
}
|
|
|
|
010010,0001,0,5.VT,5.VS,5.VD,011111::::SHFL.UPSL.fmt
|
|
"shfl.upsl.%s<SEL> v<VD>, v<VS>, <VT>"
|
|
*mdmx:
|
|
{
|
|
int i;
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
store_vr (SD_, 1, VD, i,
|
|
value_vr (SD_, 0, VS, i));
|
|
}
|
|
}
|
|
|
|
010010,0100,1.SEL,5.VT,5.VS,5.VD,011111::::SHFL.PACH.fmt
|
|
"shfl.pach.%s<SEL> v<VD>, v<VS>, <VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (4 >> scale); i++)
|
|
{
|
|
store_vr (SD_, scale, VD, i,
|
|
value_vr (SD_, scale, VT, i * 2 + 1));
|
|
store_vr (SD_, scale, VD, 1 + (4 >> scale),
|
|
value_vr (SD_, scale, VS, i * 2 + 1));
|
|
}
|
|
}
|
|
|
|
010010,0101,1.SEL,5.VT,5.VS,5.VD,011111::::SHFL.PACL.fmt
|
|
"shfl.pacl.%s<SEL> v<VD>, v<VS>, <VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (4 >> scale); i++)
|
|
{
|
|
store_vr (SD_, scale, VD, i,
|
|
value_vr (SD_, scale, VT, i * 2));
|
|
store_vr (SD_, scale, VD, 1 + (4 >> scale),
|
|
value_vr (SD_, scale, VS, i * 2));
|
|
}
|
|
}
|
|
|
|
010010,0110,1.SEL,5.VT,5.VS,5.VD,011111::::SHFL.MIXH.fmt
|
|
"shfl.mixh.%s<SEL> v<VD>, v<VS>, <VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (4 >> scale); i++)
|
|
{
|
|
store_vr (SD_, scale, VD, i * 2,
|
|
value_vr (SD_, scale, VT, i + (4 >> scale)));
|
|
store_vr (SD_, scale, VD, i * 2 + 1,
|
|
value_vr (SD_, scale, VS, i + (4 >> scale)));
|
|
}
|
|
}
|
|
|
|
010010,0111,1.SEL,5.VT,5.VS,5.VD,011111::::SHFL.MIXL.fmt
|
|
"shfl.mixl.%s<SEL> v<VD>, v<VS>, <VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (4 >> scale); i++)
|
|
{
|
|
store_vr (SD_, scale, VD, i * 2,
|
|
value_vr (SD_, scale, VT, i));
|
|
store_vr (SD_, scale, VD, i * 2 + 1,
|
|
value_vr (SD_, scale, VS, i));
|
|
}
|
|
}
|
|
|
|
010010,100,01,5.VT,5.VS,5.VD,011111::::SHFL.BFLA.fmt
|
|
"shfl.bfla.qh v<VD>, v<VS>, <VT>"
|
|
*mdmx:
|
|
{
|
|
store_vr (SD_, 1, VD, 0,
|
|
value_vr (SD_, 1, VT, 1));
|
|
store_vr (SD_, 1, VD, 1,
|
|
value_vr (SD_, 1, VS, 0));
|
|
store_vr (SD_, 1, VD, 2,
|
|
value_vr (SD_, 1, VT, 3));
|
|
store_vr (SD_, 1, VD, 3,
|
|
value_vr (SD_, 1, VS, 2));
|
|
}
|
|
|
|
010010,101,01,5.VT,5.VS,5.VD,011111::::SHFL.BFLB.fmt
|
|
"shfl.bflb.qh v<VD>, v<VS>, <VT>"
|
|
*mdmx:
|
|
{
|
|
store_vr (SD_, 1, VD, 0,
|
|
value_vr (SD_, 1, VT, 3));
|
|
store_vr (SD_, 1, VD, 1,
|
|
value_vr (SD_, 1, VS, 2));
|
|
store_vr (SD_, 1, VD, 2,
|
|
value_vr (SD_, 1, VT, 1));
|
|
store_vr (SD_, 1, VD, 3,
|
|
value_vr (SD_, 1, VS, 0));
|
|
}
|
|
|
|
010010,101,01,5.VT,5.VS,5.VD,011111::::SHFL.REPA.fmt
|
|
"shfl.repa.qh v<VD>, v<VS>, <VT>"
|
|
*mdmx:
|
|
{
|
|
store_vr (SD_, 1, VD, 0,
|
|
value_vr (SD_, 1, VT, 2));
|
|
store_vr (SD_, 1, VD, 1,
|
|
value_vr (SD_, 1, VT, 3));
|
|
store_vr (SD_, 1, VD, 2,
|
|
value_vr (SD_, 1, VS, 2));
|
|
store_vr (SD_, 1, VD, 3,
|
|
value_vr (SD_, 1, VS, 3));
|
|
}
|
|
|
|
010010,101,01,5.VT,5.VS,5.VD,011111::::SHFL.REPB.fmt
|
|
"shfl.repb.qh v<VD>, v<VS>, <VT>"
|
|
*mdmx:
|
|
{
|
|
store_vr (SD_, 1, VD, 0,
|
|
value_vr (SD_, 1, VT, 0));
|
|
store_vr (SD_, 1, VD, 1,
|
|
value_vr (SD_, 1, VT, 1));
|
|
store_vr (SD_, 1, VD, 2,
|
|
value_vr (SD_, 1, VS, 0));
|
|
store_vr (SD_, 1, VD, 3,
|
|
value_vr (SD_, 1, VS, 1));
|
|
}
|
|
|
|
|
|
|
|
// Vector Shift Left Logical
|
|
|
|
010010,5.SEL,5.VT,5.VS,5.VD,010000::::SLL.fmt
|
|
"sll.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
int mask = (4 << scale) - 1;
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
(value_vr (SD_, scale, VS, i)
|
|
<< (select_vr (SD_, SEL, VT, i) & mask)));
|
|
}
|
|
|
|
|
|
|
|
// Vector Shift Right Arithmetic
|
|
|
|
010010,5.SEL,5.VT,5.VS,5.VD,010011::::SRA.fmt
|
|
"sra.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
{
|
|
int i;
|
|
int mask = (4 << scale) - 1;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
(value_vr (SD_, scale, VS, i)
|
|
>> (select_vr (SD_, SEL, VT, i) & mask)));
|
|
}
|
|
|
|
|
|
|
|
// Vector Shift Right Logical.
|
|
|
|
010010,5.SEL,5.VT,5.VS,5.VD,010010::::SRL.fmt
|
|
"srl.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
int mask = (4 << scale) - 1;
|
|
int zeros = (1 << (8 << scale)) - 1;
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
((value_vr (SD_, scale, VS, i) & zeros)
|
|
>> (select_vr (SD_, SEL, VT, i) & mask)));
|
|
}
|
|
|
|
|
|
|
|
// Vector Subtract.
|
|
|
|
010010,5.SEL,5.VT,5.VS,5.VD,001010::::SUB.fmt
|
|
"sub.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
(value_vr (SD_, scale, VS, i)
|
|
- select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Accumulate Vector Difference
|
|
|
|
010010,5.SEL,5.VT,5.VS,0,0000,110110::::SUBA.fmt
|
|
"suba.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_acc (SD_, scale, VD, i,
|
|
(value_acc (SD, scale, i)
|
|
+ (signed64) value_vr (SD_, scale, VS, i)
|
|
- (signed64) select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Load Vector Difference
|
|
|
|
010010,5.SEL,5.VT,5.VS,1,0000,110110::::SUBL.fmt
|
|
"subl.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_acc (SD_, scale, VD, i,
|
|
((signed64) value_vr (SD_, scale, VS, i)
|
|
- (signed64) select_vr (SD_, SEL, VT, i)));
|
|
}
|
|
|
|
|
|
|
|
// Write Accumulator High.
|
|
|
|
010010,1000,1.SEL,00000,5.VS,00000,111110::::WACH.fmt
|
|
"wach.%s<SEL> v<VS>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_acc (SD_, scale, i,
|
|
(((signed64) value_vr (SD_, scale, VS, i) << (16 << scale))
|
|
| MASKED (value_acc (SD_, scale, i), (16 << scale) - 1, 0)));
|
|
}
|
|
|
|
|
|
|
|
// Vector Write Accumulator Low.
|
|
|
|
010010,0000,1.SEL,5.VT,5.VS,00000,111110::::WACL.fmt
|
|
"wacl.%s<SEL> v<VS>, <VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_acc (SD_, scale, i,
|
|
(((signed64) value_vr (SD_, scale, VS, i) << (16 << scale))
|
|
| MASKED (value_vr (SD_, scale, VT, i),
|
|
(16 << scale) - 1, 0)));
|
|
}
|
|
|
|
|
|
|
|
// Vector Xor.
|
|
|
|
010010,5.SEL,5.VT,5.VS,5.VD,001101::::XOR.fmt
|
|
"xor.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
|
|
*mdmx:
|
|
// start-sanitize-vr5400
|
|
*vr5400:
|
|
// end-sanitize-vr5400
|
|
{
|
|
int i;
|
|
int scale = get_scale (SD_, SEL);
|
|
for (i = 0; i < (8 >> scale); i++)
|
|
store_vr (SD_, scale, VD, i,
|
|
(value_vr (SD_, scale, VS, i)
|
|
^ select_vr (SD_, SEL, VT, i)));
|
|
}
|