/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - interpreter_special.def * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2002 Hacktarux * * * * 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 2 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ DECLARE_INSTRUCTION(NOP) { ADD_TO_PC(1); } DECLARE_INSTRUCTION(SLL) { rrd32 = (unsigned int)(rrt32) << rsa; sign_extended(rrd); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SRL) { rrd32 = (unsigned int)rrt32 >> rsa; sign_extended(rrd); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SRA) { rrd32 = (signed int)rrt32 >> rsa; sign_extended(rrd); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SLLV) { rrd32 = (unsigned int)(rrt32) << (rrs32&0x1F); sign_extended(rrd); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SRLV) { rrd32 = (unsigned int)rrt32 >> (rrs32 & 0x1F); sign_extended(rrd); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SRAV) { rrd32 = (signed int)rrt32 >> (rrs32 & 0x1F); sign_extended(rrd); ADD_TO_PC(1); } DECLARE_JUMP(JR, irs32, 1, ®[0], 0, 0) DECLARE_JUMP(JALR, irs32, 1, PC->f.r.rd, 0, 0) DECLARE_INSTRUCTION(SYSCALL) { Cause = 8 << 2; exception_general(); } DECLARE_INSTRUCTION(SYNC) { ADD_TO_PC(1); } DECLARE_INSTRUCTION(MFHI) { rrd = hi; ADD_TO_PC(1); } DECLARE_INSTRUCTION(MTHI) { hi = rrs; ADD_TO_PC(1); } DECLARE_INSTRUCTION(MFLO) { rrd = lo; ADD_TO_PC(1); } DECLARE_INSTRUCTION(MTLO) { lo = rrs; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSLLV) { rrd = rrt << (rrs32&0x3F); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSRLV) { rrd = (unsigned long long)rrt >> (rrs32 & 0x3F); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSRAV) { rrd = (long long)rrt >> (rrs32 & 0x3F); ADD_TO_PC(1); } DECLARE_INSTRUCTION(MULT) { long long int temp; temp = rrs * rrt; hi = temp >> 32; lo = temp; sign_extended(lo); ADD_TO_PC(1); } DECLARE_INSTRUCTION(MULTU) { unsigned long long int temp; temp = (unsigned int)rrs * (unsigned long long)((unsigned int)rrt); hi = (long long)temp >> 32; lo = temp; sign_extended(lo); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DIV) { if (rrt32) { lo = rrs32 / rrt32; hi = rrs32 % rrt32; sign_extended(lo); sign_extended(hi); } else DebugMessage(M64MSG_ERROR, "DIV: divide by 0"); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DIVU) { if (rrt32) { lo = (unsigned int)rrs32 / (unsigned int)rrt32; hi = (unsigned int)rrs32 % (unsigned int)rrt32; sign_extended(lo); sign_extended(hi); } else DebugMessage(M64MSG_ERROR, "DIVU: divide by 0"); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DMULT) { unsigned long long int op1, op2, op3, op4; unsigned long long int result1, result2, result3, result4; unsigned long long int temp1, temp2, temp3, temp4; int sign = 0; if (rrs < 0) { op2 = -rrs; sign = 1 - sign; } else op2 = rrs; if (rrt < 0) { op4 = -rrt; sign = 1 - sign; } else op4 = rrt; op1 = op2 & 0xFFFFFFFF; op2 = (op2 >> 32) & 0xFFFFFFFF; op3 = op4 & 0xFFFFFFFF; op4 = (op4 >> 32) & 0xFFFFFFFF; temp1 = op1 * op3; temp2 = (temp1 >> 32) + op1 * op4; temp3 = op2 * op3; temp4 = (temp3 >> 32) + op2 * op4; result1 = temp1 & 0xFFFFFFFF; result2 = temp2 + (temp3 & 0xFFFFFFFF); result3 = (result2 >> 32) + temp4; result4 = (result3 >> 32); lo = result1 | (result2 << 32); hi = (result3 & 0xFFFFFFFF) | (result4 << 32); if (sign) { hi = ~hi; if (!lo) hi++; else lo = ~lo + 1; } ADD_TO_PC(1); } DECLARE_INSTRUCTION(DMULTU) { unsigned long long int op1, op2, op3, op4; unsigned long long int result1, result2, result3, result4; unsigned long long int temp1, temp2, temp3, temp4; op1 = rrs & 0xFFFFFFFF; op2 = (rrs >> 32) & 0xFFFFFFFF; op3 = rrt & 0xFFFFFFFF; op4 = (rrt >> 32) & 0xFFFFFFFF; temp1 = op1 * op3; temp2 = (temp1 >> 32) + op1 * op4; temp3 = op2 * op3; temp4 = (temp3 >> 32) + op2 * op4; result1 = temp1 & 0xFFFFFFFF; result2 = temp2 + (temp3 & 0xFFFFFFFF); result3 = (result2 >> 32) + temp4; result4 = (result3 >> 32); lo = result1 | (result2 << 32); hi = (result3 & 0xFFFFFFFF) | (result4 << 32); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DDIV) { if (rrt) { lo = (long long int)rrs / (long long int)rrt; hi = (long long int)rrs % (long long int)rrt; } else DebugMessage(M64MSG_ERROR, "DDIV: divide by 0"); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DDIVU) { if (rrt) { lo = (unsigned long long int)rrs / (unsigned long long int)rrt; hi = (unsigned long long int)rrs % (unsigned long long int)rrt; } else DebugMessage(M64MSG_ERROR, "DDIVU: divide by 0"); ADD_TO_PC(1); } DECLARE_INSTRUCTION(ADD) { rrd32 = rrs32 + rrt32; sign_extended(rrd); ADD_TO_PC(1); } DECLARE_INSTRUCTION(ADDU) { rrd32 = rrs32 + rrt32; sign_extended(rrd); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SUB) { rrd32 = rrs32 - rrt32; sign_extended(rrd); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SUBU) { rrd32 = rrs32 - rrt32; sign_extended(rrd); ADD_TO_PC(1); } DECLARE_INSTRUCTION(AND) { rrd = rrs & rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(OR) { rrd = rrs | rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(XOR) { rrd = rrs ^ rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(NOR) { rrd = ~(rrs | rrt); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SLT) { if (rrs < rrt) rrd = 1; else rrd = 0; ADD_TO_PC(1); } DECLARE_INSTRUCTION(SLTU) { if ((unsigned long long)rrs < (unsigned long long)rrt) rrd = 1; else rrd = 0; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DADD) { rrd = rrs + rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DADDU) { rrd = rrs + rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSUB) { rrd = rrs - rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSUBU) { rrd = rrs - rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(TEQ) { if (rrs == rrt) { DebugMessage(M64MSG_ERROR, "trap exception in TEQ"); stop=1; } ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSLL) { rrd = rrt << rsa; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSRL) { rrd = (unsigned long long)rrt >> rsa; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSRA) { rrd = rrt >> rsa; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSLL32) { rrd = rrt << (32+rsa); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSRL32) { rrd = (unsigned long long int)rrt >> (32+rsa); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSRA32) { rrd = (signed long long int)rrt >> (32+rsa); ADD_TO_PC(1); }