mupen64plus-oldsvn/z64/rsp_opinfo.cpp

557 lines
14 KiB
C++

/*
* z64
*
* This program is free software; you can redistribute it and/
* or modify it under the terms of the GNU General Public Li-
* cence as published by the Free Software Foundation; either
* version 2 of the Licence, or any later version.
*
* This program is distributed in the hope that it will be use-
* ful, but WITHOUT ANY WARRANTY; without even the implied war-
* ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public Licence for more details.
*
* You should have received a copy of the GNU General Public
* Licence along with this program; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
* USA.
*
**/
#include "rsp_opinfo.h"
static const int vector_elements_2[16][8] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // none
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // ???
{ 0, 0, 2, 2, 4, 4, 6, 6 }, // 0q
{ 1, 1, 3, 3, 5, 5, 7, 7 }, // 1q
{ 0, 0, 0, 0, 4, 4, 4, 4 }, // 0h
{ 1, 1, 1, 1, 5, 5, 5, 5 }, // 1h
{ 2, 2, 2, 2, 6, 6, 6, 6 }, // 2h
{ 3, 3, 3, 3, 7, 7, 7, 7 }, // 3h
{ 0, 0, 0, 0, 0, 0, 0, 0 }, // 0
{ 1, 1, 1, 1, 1, 1, 1, 1 }, // 1
{ 2, 2, 2, 2, 2, 2, 2, 2 }, // 2
{ 3, 3, 3, 3, 3, 3, 3, 3 }, // 3
{ 4, 4, 4, 4, 4, 4, 4, 4 }, // 4
{ 5, 5, 5, 5, 5, 5, 5, 5 }, // 5
{ 6, 6, 6, 6, 6, 6, 6, 6 }, // 6
{ 7, 7, 7, 7, 7, 7, 7, 7 }, // 7
};
void rsp_get_opinfo(UINT32 op, rsp_opinfo_t * info)
{
int op2;
int i;
info->op = op;
switch (op>>26) {
case 0: /* SPECIAL */
op2 = RSP_SPECIAL_OFFS + (op&0x3f);
break;
case 0x12: /* COP2 */
if (((op>>21)&0x1f) >= 0x10)
op2 = RSP_COP2_2_OFFS + (op & 0x3f);
else
op2 = RSP_COP2_1_OFFS + ((op >> 21) & 0x1f);
break;
case 0x32: /* LWC2 */
op2 = RSP_LWC2_OFFS + ((op>>11)&0x1f);
break;
case 0x3a: /* SWC2 */
op2 = RSP_SWC2_OFFS + ((op>>11)&0x1f);
break;
default:
op2 = RSP_BASIC_OFFS + (op>>26);
if (op2 == RSP_REGIMM) {
switch (RTREG)
{
case 0x00: /* BLTZ */
op2 = RSP_BLTZ;
break;
case 0x01: /* BGEZ */
op2 = RSP_BGEZ;
break;
case 0x11: /* BGEZAL */
op2 = RSP_BGEZAL;
break;
}
}
}
info->op2 = op2;
memset(&info->used, 0, sizeof(info->used));
memset(&info->set, 0, sizeof(info->set));
info->used.accu = info->used.flag = 0;
info->set.accu = info->set.flag = 0;
info->flags = 0;
int dest = (op >> 16) & 0x1f;
int base = (op >> 21) & 0x1f;
int index = (op >> 7) & 0xf;
int offset = (op & 0x7f);
if (offset & 0x40)
offset |= 0xffffffc0;
switch(op2) {
case RSP_SPECIAL:
case RSP_BLTZ:
info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_COND | RSP_OPINFO_USEPC;
break;
case RSP_BGEZ:
info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_COND | RSP_OPINFO_USEPC;
break;
case RSP_BGEZAL:
info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_COND | RSP_OPINFO_LINK | RSP_OPINFO_USEPC;
break;
case RSP_J:
info->flags = RSP_OPINFO_JUMP;
break;
case RSP_JAL:
info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_LINK | RSP_OPINFO_USEPC;
break;
case RSP_BEQ:
case RSP_BNE:
case RSP_BLEZ:
case RSP_BGTZ:
info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_COND | RSP_OPINFO_USEPC;
break;
case RSP_ADDI:
case RSP_ADDIU:
case RSP_SLTI:
case RSP_SLTIU:
case RSP_ANDI:
case RSP_ORI:
case RSP_XORI:
case RSP_LUI:
case RSP_COP0:
case RSP_LB:
case RSP_LH:
case RSP_LW:
case RSP_LBU:
case RSP_LHU:
case RSP_SB:
case RSP_SH:
case RSP_SW:
break;
case RSP_SLL:
case RSP_SRL:
case RSP_SRA:
case RSP_SLLV:
case RSP_SRLV:
case RSP_SRAV:
break;
case RSP_JR:
info->flags = RSP_OPINFO_JUMP;
break;
case RSP_JALR:
info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_LINK | RSP_OPINFO_USEPC;
break;
case RSP_BREAK:
info->flags = RSP_OPINFO_BREAK;
break;
case RSP_ADD:
case RSP_ADDU:
case RSP_SUB:
case RSP_SUBU:
case RSP_AND:
case RSP_OR:
case RSP_XOR:
case RSP_NOR:
case RSP_SLT:
case RSP_SLTU:
break;
case RSP_MFC2:
{
int el = op >> 7;
RSP_SET_VEC_I(info->used, VS1REG, ((el+0)&0xf)>>1);
RSP_SET_VEC_I(info->used, VS1REG, ((el+1)&0xf)>>1);
break;
}
case RSP_CFC2:
RSP_SET_FLAG_I(info->used, RDREG & 3);
break;
case RSP_MTC2:
{
int el = op >> 7;
RSP_SET_VEC_I(info->set, VS1REG, ((el+0)&0xf)>>1);
RSP_SET_VEC_I(info->set, VS1REG, ((el+1)&0xf)>>1);
break;
}
case RSP_CTC2:
RSP_SET_FLAG_I(info->set, RDREG & 3);
break;
case RSP_LBV:
RSP_SET_VEC_I(info->set, dest, index>>1);
break;
case RSP_LSV:
for (i=index; i<index+2; i++)
RSP_SET_VEC_I(info->set, dest, (i>>1)&7);
break;
case RSP_LLV:
for (i=index; i<index+4; i++)
RSP_SET_VEC_I(info->set, dest, (i>>1)&7);
break;
case RSP_LDV:
for (i=index; i<index+8; i++)
RSP_SET_VEC_I(info->set, dest, (i>>1)&7);
break;
case RSP_LQV:
case RSP_LRV:
// WARNING WARNING WARNING
// we assume this instruction always used to load the full vector
// i.e. the address is always 16 bytes aligned
// for (i=0; i<8; i++)
// RSP_SET_VEC_I(info->set, dest, i);
break;
case RSP_LPV:
case RSP_LUV:
case RSP_LHV:
case RSP_LWV:
for (i=0; i<8; i++)
RSP_SET_VEC_I(info->set, dest, i);
break;
case RSP_LFV:
for (i=(index>>1); i<(index>>1)+4; i++)
RSP_SET_VEC_I(info->set, dest, i);
break;
case RSP_LTV:
{
// 31 25 20 15 10 6 0
// --------------------------------------------------
// | 110010 | BBBBB | TTTTT | 01011 | IIII | Offset |
// --------------------------------------------------
//
// Loads one element to maximum of 8 vectors, while incrementing element index
// FIXME: has a small problem with odd indices
int element;
int vs = dest;
int ve = dest + 8;
if (ve > 32)
ve = 32;
element = 7 - (index >> 1);
if (index & 1) fatalerror("RSP: LTV: index = %d\n", index);
for (i=vs; i < ve; i++)
{
element = ((8 - (index >> 1) + (i-vs)) << 1);
RSP_SET_VEC_I(info->set, i, (element & 0xf)>>1);
RSP_SET_VEC_I(info->set, i, ((element+1) & 0xf)>>1);
}
break;
}
case RSP_SBV:
RSP_SET_VEC_I(info->used, dest, index>>1);
break;
case RSP_SSV:
for (i=index; i<index+2; i++)
RSP_SET_VEC_I(info->used, dest, (i>>1)&7);
break;
case RSP_SLV:
for (i=index; i<index+4; i++)
RSP_SET_VEC_I(info->used, dest, (i>>1)&7);
break;
case RSP_SDV:
for (i=index; i<index+8; i++)
RSP_SET_VEC_I(info->used, dest, (i>>1)&7);
break;
case RSP_SQV:
case RSP_SRV:
// WARNING WARNING WARNING
// we assume this instruction always used to store the full vector
// i.e. the address is always 16 bytes aligned
for (i=0; i<8; i++)
RSP_SET_VEC_I(info->used, dest, i);
break;
case RSP_SPV:
case RSP_SUV:
case RSP_SHV:
case RSP_SWV:
for (i=0; i<8; i++)
RSP_SET_VEC_I(info->used, dest, i);
break;
case RSP_SFV:
for (i=(index>>1); i<(index>>1)+4; i++)
RSP_SET_VEC_I(info->used, dest, i);
break;
case RSP_STV:
{
// 31 25 20 15 10 6 0
// --------------------------------------------------
// | 111010 | BBBBB | TTTTT | 01011 | IIII | Offset |
// --------------------------------------------------
//
// Stores one element from maximum of 8 vectors, while incrementing element index
int element, eaoffset;
int vs = dest;
int ve = dest + 8;
if (ve > 32)
ve = 32;
element = 8 - (index >> 1);
if (index & 0x1) fatalerror("RSP: STV: index = %d at %08X\n", index, rsp.ppc);
for (i=vs; i < ve; i++)
{
RSP_SET_VEC_I(info->used, i, element & 0x7);
element++;
}
break;
}
case RSP_VMULF:
case RSP_VMULU:
case RSP_VMUDL:
case RSP_VMUDM:
case RSP_VMUDN:
case RSP_VMUDH:
{
for (i=0; i < 8; i++)
{
int sel = VEC_EL_2(EL, i);
RSP_SET_VEC_I(info->used, VS1REG, i);
RSP_SET_VEC_I(info->used, VS2REG, sel);
RSP_SET_VEC_I(info->set, VDREG, i);
RSP_SET_ACCU_I(info->set, i, 14);
}
break;
}
case RSP_VMACF:
case RSP_VMACU:
case RSP_VMADL:
case RSP_VMADM:
case RSP_VMADN:
case RSP_VMADH:
{
for (i=0; i < 8; i++)
{
int sel = VEC_EL_2(EL, i);
RSP_SET_VEC_I(info->used, VS1REG, i);
RSP_SET_VEC_I(info->used, VS2REG, sel);
RSP_SET_VEC_I(info->set, VDREG, i);
RSP_SET_ACCU_I(info->used, i, 14);
RSP_SET_ACCU_I(info->set, i, 14);
}
break;
}
case RSP_VADD:
case RSP_VSUB:
{
for (i=0; i < 8; i++)
{
int sel = VEC_EL_2(EL, i);
RSP_SET_VEC_I(info->used, VS1REG, i);
RSP_SET_VEC_I(info->used, VS2REG, sel);
RSP_SET_VEC_I(info->set, VDREG, i);
RSP_SET_ACCU_I(info->set, i, 2);
}
RSP_SET_FLAG_I(info->used, 0);
RSP_SET_FLAG_I(info->set, 0);
break;
}
case RSP_VABS:
{
for (i=0; i < 8; i++)
{
int sel = VEC_EL_2(EL, i);
RSP_SET_VEC_I(info->used, VS1REG, i);
RSP_SET_VEC_I(info->used, VS2REG, sel);
RSP_SET_VEC_I(info->set, VDREG, i);
RSP_SET_ACCU_I(info->set, i, 2);
}
break;
}
case RSP_VADDC:
case RSP_VSUBC:
{
for (i=0; i < 8; i++)
{
int sel = VEC_EL_2(EL, i);
RSP_SET_VEC_I(info->used, VS1REG, i);
RSP_SET_VEC_I(info->used, VS2REG, sel);
RSP_SET_VEC_I(info->set, VDREG, i);
RSP_SET_ACCU_I(info->set, i, 2);
}
RSP_SET_FLAG_I(info->set, 0);
break;
}
case RSP_VSAW:
switch (EL)
{
case 0x08: // VSAWH
{
for (i=0; i < 8; i++)
{
RSP_SET_VEC_I(info->set, VDREG, i);
RSP_SET_ACCU_I(info->used, i, 8);
}
break;
}
case 0x09: // VSAWM
{
for (i=0; i < 8; i++)
{
RSP_SET_VEC_I(info->set, VDREG, i);
RSP_SET_ACCU_I(info->used, i, 4);
}
break;
}
case 0x0a: // VSAWL
{
for (i=0; i < 8; i++)
{
RSP_SET_VEC_I(info->set, VDREG, i);
RSP_SET_ACCU_I(info->used, i, 2);
}
break;
}
default: fatalerror("RSP: VSAW: el = %d\n", EL);
}
break;
case RSP_VLT:
{
for (i=0; i < 8; i++)
{
int sel = VEC_EL_2(EL, i);
RSP_SET_VEC_I(info->used, VS1REG, i);
RSP_SET_VEC_I(info->used, VS2REG, sel);
RSP_SET_VEC_I(info->set, VDREG, i);
RSP_SET_ACCU_I(info->set, i, 2);
}
RSP_SET_FLAG_I(info->set, 0);
RSP_SET_FLAG_I(info->set, 1);
break;
}
case RSP_VEQ:
case RSP_VNE:
case RSP_VGE:
{
for (i=0; i < 8; i++)
{
int sel = VEC_EL_2(EL, i);
RSP_SET_VEC_I(info->used, VS1REG, i);
RSP_SET_VEC_I(info->used, VS2REG, sel);
RSP_SET_VEC_I(info->set, VDREG, i);
RSP_SET_ACCU_I(info->set, i, 2);
}
RSP_SET_FLAG_I(info->used, 0);
RSP_SET_FLAG_I(info->set, 0);
RSP_SET_FLAG_I(info->set, 1);
break;
}
case RSP_VCL:
{
for (i=0; i < 8; i++)
{
int sel = VEC_EL_2(EL, i);
RSP_SET_VEC_I(info->used, VS1REG, i);
RSP_SET_VEC_I(info->used, VS2REG, sel);
RSP_SET_VEC_I(info->set, VDREG, i);
RSP_SET_ACCU_I(info->set, i, 2);
}
RSP_SET_FLAG_I(info->used, 0);
RSP_SET_FLAG_I(info->used, 1);
RSP_SET_FLAG_I(info->set, 0);
RSP_SET_FLAG_I(info->set, 1);
RSP_SET_FLAG_I(info->set, 2);
break;
}
case RSP_VCH:
case RSP_VCR:
{
for (i=0; i < 8; i++)
{
int sel = VEC_EL_2(EL, i);
RSP_SET_VEC_I(info->used, VS1REG, i);
RSP_SET_VEC_I(info->used, VS2REG, sel);
RSP_SET_VEC_I(info->set, VDREG, i);
RSP_SET_ACCU_I(info->set, i, 2);
}
RSP_SET_FLAG_I(info->set, 0);
RSP_SET_FLAG_I(info->set, 1);
RSP_SET_FLAG_I(info->set, 2);
break;
}
case RSP_VMRG:
{
for (i=0; i < 8; i++)
{
int sel = VEC_EL_2(EL, i);
RSP_SET_VEC_I(info->used, VS1REG, i);
RSP_SET_VEC_I(info->used, VS2REG, sel);
RSP_SET_VEC_I(info->set, VDREG, i);
RSP_SET_ACCU_I(info->set, i, 2);
}
RSP_SET_FLAG_I(info->used, 1);
break;
}
case RSP_VAND:
case RSP_VNAND:
case RSP_VOR:
case RSP_VNOR:
case RSP_VXOR:
case RSP_VNXOR:
{
for (i=0; i < 8; i++)
{
int sel = VEC_EL_2(EL, i);
RSP_SET_VEC_I(info->used, VS1REG, i);
RSP_SET_VEC_I(info->used, VS2REG, sel);
RSP_SET_VEC_I(info->set, VDREG, i);
RSP_SET_ACCU_I(info->set, i, 2);
}
break;
}
case RSP_VRCP:
case RSP_VRCPL:
case RSP_VRCPH:
case RSP_VRSQL:
case RSP_VRSQH:
{
int del = (VS1REG & 7);
int sel = VEC_EL_2(EL, del);
RSP_SET_VEC_I(info->used, VS2REG, sel);
for (i=0; i < 8; i++)
{
int element = VEC_EL_2(EL, i);
RSP_SET_VEC_I(info->used, VS2REG, element);
RSP_SET_ACCU_I(info->set, i, 2);
}
RSP_SET_VEC_I(info->set, VDREG, del);
break;
}
case RSP_VMOV:
{
int element = VS1REG & 7;
RSP_SET_VEC_I(info->used, VS2REG, VEC_EL_2(EL, 7-element));
RSP_SET_VEC_I(info->set, VDREG, element);
break;
}
default:
{
// char string[200];
// rsp_dasm_one(string, 0x800, op);
// if (strcmp(string, "???")) {
// printf("%s\n", string);
// printf("unimplemented opcode\n");
// }
break;
}
}
}