/* Single instruction disassembler for the Visium.
Copyright (C) 2002-2024 Free Software Foundation, Inc.
This file is part of the GNU opcodes library.
This library 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, or (at your option)
any later version.
It 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. */
case 6:
/* Illegal opcode (was EUT). */
goto illegal_opcode;
break;
case 7:
/* RFI - Return from Interrupt. */
if (ins != RFI)
goto illegal_opcode;
(*info->fprintf_func) (info->stream, "rfi");
break;
case 8:
/* Illegal opcode. */
goto illegal_opcode;
break;
case 9:
/* Illegal opcode. */
goto illegal_opcode;
break;
case 10:
/* Illegal opcode. */
goto illegal_opcode;
break;
case 11:
/* Illegal opcode. */
goto illegal_opcode;
break;
case 12:
/* Illegal opcode. */
goto illegal_opcode;
break;
case 13:
goto illegal_opcode;
break;
case 14:
goto illegal_opcode;
break;
case 15:
if (ins & EAM_SELECT_MASK)
{
/* Extension arithmetic module write */
int fp_ins = (ins >> 27) & 0xf;
if (size != 4)
goto illegal_opcode;
if (ins & FP_SELECT_MASK)
{
/* Which floating point instructions don't need a fsrcB
register. */
const int no_fsrcb[16] = { 1, 0, 0, 0, 0, 1, 1, 1,
1, 1, 0, 0, 1, 0, 0, 0
};
if (no_fsrcb[fp_ins] && source_b)
goto illegal_opcode;
/* Check that none of the floating register register numbers
is higher than 15. (If this is fload, then srcA is a
general register. */
if (ins & ((1 << 14) | (1 << 8)) || (fp_ins && ins & (1 << 20)))
goto illegal_opcode;
switch (fp_ins)
{
case 0:
(*info->fprintf_func) (info->stream, "fload f%d,r%d",
indx, source_a);
break;
case 1:
(*info->fprintf_func) (info->stream, "fadd f%d,f%d,f%d",
indx, source_a, source_b);
break;
case 2:
(*info->fprintf_func) (info->stream, "fsub f%d,f%d,f%d",
indx, source_a, source_b);
break;
case 3:
(*info->fprintf_func) (info->stream, "fmult f%d,f%d,f%d",
indx, source_a, source_b);
break;
case 4:
(*info->fprintf_func) (info->stream, "fdiv f%d,f%d,f%d",
indx, source_a, source_b);
break;
case 5:
(*info->fprintf_func) (info->stream, "fsqrt f%d,f%d",
indx, source_a);
break;
case 6:
(*info->fprintf_func) (info->stream, "fneg f%d,f%d",
indx, source_a);
break;
case 7:
(*info->fprintf_func) (info->stream, "fabs f%d,f%d",
indx, source_a);
break;
case 8:
(*info->fprintf_func) (info->stream, "ftoi f%d,f%d",
indx, source_a);
break;
case 9:
(*info->fprintf_func) (info->stream, "itof f%d,f%d",
indx, source_a);
break;
case 12:
(*info->fprintf_func) (info->stream, "fmove f%d,f%d",
indx, source_a);
break;
default:
(*info->fprintf_func) (info->stream,
"fpinst %d,f%d,f%d,f%d", fp_ins,
indx, source_a, source_b);
break;
}
}
else
{
/* Which EAM operations do not need a srcB register. */
const int no_srcb[32] =
{ 0, 0, 1, 1, 0, 1, 1, 1,
0, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
if (no_srcb[indx] && source_b)
goto illegal_opcode;
/* Disassemble storage register class instructions. */
static int
disassem_class3 (disassemble_info *info, unsigned int ins)
{
int opcode = (ins >> 21) & 0xf;
int source_b = (ins >> 4) & 0x1f;
int source_a = (ins >> 16) & 0x1f;
int size = ins & 0x7;
int dest = (ins >> 10) & 0x1f;
/* Those instructions that don't have a srcB register. */
const int no_srcb[16] =
{ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0 };
/* These are instructions which can take an immediate srcB value. */
const int srcb_immed[16] =
{ 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 };
/* User opcodes should not provide a non-zero srcB register
when none is required. Only a BRA or floating point
instruction should have a non-zero condition code field.
Only a WRITE or EAMWRITE (opcode 15) should select an EAM
or floating point operation. Note that FP_SELECT_MASK is
the same bit (bit 3) as the interrupt bit which
distinguishes SYS1 from BRA and SYS2 from RFLAG. */
if ((no_srcb[opcode] && source_b)
|| (!srcb_immed[opcode] && ins & CLASS3_SOURCEB_IMMED)
|| (opcode != 12 && opcode != 15 && ins & CC_MASK)
|| (opcode != 15 && ins & (EAM_SELECT_MASK | FP_SELECT_MASK)))
goto illegal_opcode;
/* We do return this info. */
info->insn_info_valid = 1;
/* Assume non branch insn. */
info->insn_type = dis_nonbranch;
/* Assume no delay. */
info->branch_delay_insns = 0;
/* Assume no target known. */
info->target = 0;
/* Get 32-bit instruction word. */
FETCH_DATA (info, buffer + 4);
ins = (unsigned) buffer[0] << 24;
ins |= buffer[1] << 16;
ins |= buffer[2] << 8;
ins |= buffer[3];
ans = 0;
p1 = buffer[0] ^ buffer[1] ^ buffer[2] ^ buffer[3];
p2 = 0;
for (i = 0; i < 8; i++)
{
p2 += p1 & 1;
p1 >>= 1;
}
/* Decode the instruction. */
if (p2 & 1)
ans = -1;
else
{
switch ((ins >> 25) & 0x3)
{
case 0:
ans = disassem_class0 (info, ins);
break;
case 1:
ans = disassem_class1 (info, ins);
break;
case 2:
ans = disassem_class2 (info, ins);
break;
case 3:
ans = disassem_class3 (info, ins);
break;
}
}
if (ans != 0)
(*info->fprintf_func) (info->stream, "err");
/* Return number of bytes consumed (always 4 for the Visium). */
return 4;
}