Files
ARMSX2/pcsx2/R5900OpcodeTables.cpp
T
bmdhacks c5a6c7cb0a Record the FPU's measured timings; leave the cycle table alone
The EE's divide unit was timed on silicon to bound what its recurrence can
be -- eleven rounds of modelling its rounding had never constrained the
hypothesis space, and cycles per quotient bit constrains it hard.

DIV.S and SQRT.S each occupy the FPU for 7 cycles and RSQRT.S for 13, against
this table's 6, 6 and 8.  MUL.S is latency 4 / issue interval 1, which is the
one entry the table already has right.  Measured with COP0 Count around loops
of k copies of one instruction so the loop overhead falls out as the intercept;
four runs, three byte-identical.

The interesting part is not the numbers but the mix.  Interleaved div.s/sqrt.s
costs the sum while div.s/add.s costs the divide alone, so div and sqrt are one
shared non-pipelined unit rather than two that happen to take equally long, and
RSQRT.S at 7+7-1 is two passes through it -- which is what FPU.cpp's RSQRT_S
already assumed from values alone.  The latency does not move on any operand
class, including denormals and divide by zero, so there is no early-out.

The table is not touched.  It drives game timing, its own comment already calls
itself a hack, and nothing here measured what moving it would do to
compatibility; that is a separate change with a separate burden of proof.  The
comment exists so the console run does not have to be taken a third time.

Idea by pstef.
2026-08-02 17:03:02 -07:00

758 lines
32 KiB
C++

// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+
//all tables for R5900 are define here..
#include "R5900OpcodeTables.h"
#include "R5900.h"
// TODO(Stenzek): Move headers to common code.
#include "x86/iR5900AritImm.h"
#include "x86/iR5900Arit.h"
#include "x86/iR5900MultDiv.h"
#include "x86/iR5900Shift.h"
#include "x86/iR5900Branch.h"
#include "x86/iR5900Jump.h"
#include "x86/iR5900LoadStore.h"
#include "x86/iR5900Move.h"
#include "x86/iMMI.h"
#include "x86/iCOP0.h"
#include "x86/iFPU.h"
namespace R5900
{
namespace Opcodes
{
// Generates an entry for the given opcode name.
// Assumes the default function naming schemes for interpreter and recompiler functions.
#if defined(_M_X86) || defined(ARCH_ARM64) // ARM64 EE recompiler is supported
# define MakeOpcode( name, cycles, flags ) \
static const OPCODE name = { \
#name, \
cycles, \
flags, \
NULL, \
::R5900::Interpreter::OpcodeImpl::name, \
::R5900::Dynarec::OpcodeImpl::rec##name, \
::R5900::OpcodeDisasm::name \
}
# define MakeOpcodeM( name, cycles, flags ) \
static const OPCODE name = { \
#name, \
cycles, \
flags, \
NULL, \
::R5900::Interpreter::OpcodeImpl::MMI::name, \
::R5900::Dynarec::OpcodeImpl::MMI::rec##name, \
::R5900::OpcodeDisasm::name \
}
# define MakeOpcode0( name, cycles, flags ) \
static const OPCODE name = { \
#name, \
cycles, \
flags, \
NULL, \
::R5900::Interpreter::OpcodeImpl::COP0::name, \
::R5900::Dynarec::OpcodeImpl::COP0::rec##name, \
::R5900::OpcodeDisasm::name \
}
# define MakeOpcode1( name, cycles, flags ) \
static const OPCODE name = { \
#name, \
cycles, \
flags, \
NULL, \
::R5900::Interpreter::OpcodeImpl::COP1::name, \
::R5900::Dynarec::OpcodeImpl::COP1::rec##name, \
::R5900::OpcodeDisasm::name \
}
#else
# define MakeOpcode( name, cycles, flags ) \
static const OPCODE name = { \
#name, \
cycles, \
flags, \
NULL, \
::R5900::Interpreter::OpcodeImpl::name, \
nullptr, \
::R5900::OpcodeDisasm::name \
}
# define MakeOpcodeM( name, cycles, flags ) \
static const OPCODE name = { \
#name, \
cycles, \
flags, \
NULL, \
::R5900::Interpreter::OpcodeImpl::MMI::name, \
nullptr, \
::R5900::OpcodeDisasm::name \
}
# define MakeOpcode0( name, cycles, flags ) \
static const OPCODE name = { \
#name, \
cycles, \
flags, \
NULL, \
::R5900::Interpreter::OpcodeImpl::COP0::name, \
nullptr, \
::R5900::OpcodeDisasm::name \
}
# define MakeOpcode1( name, cycles, flags ) \
static const OPCODE name = { \
#name, \
cycles, \
flags, \
NULL, \
::R5900::Interpreter::OpcodeImpl::COP1::name, \
nullptr, \
::R5900::OpcodeDisasm::name \
}
#endif
# define MakeOpcodeClass( name ) \
static const OPCODE name = { \
#name, \
0, \
0, \
R5900::Opcodes::Class_##name, \
NULL, \
NULL, \
NULL \
}
// We're working on new hopefully better cycle ratios, but they're still a WIP.
// And yes this whole thing is an ugly hack. I'll clean it up once we have
// a better idea how exactly the cycle ratios will work best.
namespace Cycles
{
static const int Default = 9;
static const int Branch = 11;
static const int CopDefault = 7;
static const int Mult = 2*8;
static const int Div = 14*8;
static const int MMI_Mult = 3*8;
static const int MMI_Div = 22*8;
static const int MMI_Default = 14;
static const int FPU_Mult = 4*8;
static const int Store = 14;
static const int Load = 14;
}
using namespace Cycles;
MakeOpcode( Unknown, Default, 0 );
MakeOpcode( MMI_Unknown, Default, 0 );
MakeOpcode( COP0_Unknown, Default, 0 );
MakeOpcode( COP1_Unknown, Default, 0 );
// Class Subset Opcodes
// (not really opcodes, but rather entire subsets of other opcode classes)
MakeOpcodeClass( SPECIAL );
MakeOpcodeClass( REGIMM );
//MakeOpcodeClass( COP2 );
MakeOpcodeClass( MMI );
MakeOpcodeClass( MMI0 );
MakeOpcodeClass( MMI2 );
MakeOpcodeClass( MMI1 );
MakeOpcodeClass( MMI3 );
MakeOpcodeClass( COP0 );
MakeOpcodeClass( COP1 );
// Misc Junk
MakeOpcode( COP2, Default, 0 );
MakeOpcode( CACHE, Default, 0 );
MakeOpcode( PREF, Default, 0 );
MakeOpcode( SYSCALL, Default, IS_BRANCH|BRANCHTYPE_SYSCALL );
MakeOpcode( BREAK, Default, 0 );
MakeOpcode( SYNC, Default, 0 );
// Branch/Jump Opcodes
MakeOpcode( J , Default, IS_BRANCH|BRANCHTYPE_JUMP );
MakeOpcode( JAL, Default, IS_BRANCH|BRANCHTYPE_JUMP|IS_LINKED );
MakeOpcode( JR, Default, IS_BRANCH|BRANCHTYPE_REGISTER );
MakeOpcode( JALR, Default, IS_BRANCH|BRANCHTYPE_REGISTER|IS_LINKED );
MakeOpcode( BEQ, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_EQ );
MakeOpcode( BNE, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_NE );
MakeOpcode( BLEZ, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_LEZ );
MakeOpcode( BGTZ, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_GTZ );
MakeOpcode( BEQL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_EQ|IS_LIKELY );
MakeOpcode( BNEL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_NE|IS_LIKELY );
MakeOpcode( BLEZL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_LEZ|IS_LIKELY );
MakeOpcode( BGTZL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_GTZ|IS_LIKELY );
MakeOpcode( BLTZ, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_LTZ );
MakeOpcode( BGEZ, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_GEZ );
MakeOpcode( BLTZL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_LTZ|IS_LIKELY );
MakeOpcode( BGEZL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_GEZ|IS_LIKELY );
MakeOpcode( BLTZAL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_LTZ|IS_LINKED );
MakeOpcode( BGEZAL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_GEZ|IS_LINKED );
MakeOpcode( BLTZALL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_LTZ|IS_LINKED|IS_LIKELY );
MakeOpcode( BGEZALL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_GEZ|IS_LINKED|IS_LIKELY );
MakeOpcode( TGEI, Branch, 0 );
MakeOpcode( TGEIU, Branch, 0 );
MakeOpcode( TLTI, Branch, 0 );
MakeOpcode( TLTIU, Branch, 0 );
MakeOpcode( TEQI, Branch, 0 );
MakeOpcode( TNEI, Branch, 0 );
MakeOpcode( TGE, Branch, 0 );
MakeOpcode( TGEU, Branch, 0 );
MakeOpcode( TLT, Branch, 0 );
MakeOpcode( TLTU, Branch, 0 );
MakeOpcode( TEQ, Branch, 0 );
MakeOpcode( TNE, Branch, 0 );
// Arithmetic
MakeOpcode( MULT, Mult, 0 );
MakeOpcode( MULTU, Mult, 0 );
MakeOpcode( MULT1, Mult, 0 );
MakeOpcode( MULTU1, Mult, 0 );
MakeOpcode( MADD, Mult, 0 );
MakeOpcode( MADDU, Mult, 0 );
MakeOpcode( MADD1, Mult, 0 );
MakeOpcode( MADDU1, Mult, 0 );
MakeOpcode( DIV, Div, 0 );
MakeOpcode( DIVU, Div, 0 );
MakeOpcode( DIV1, Div, 0 );
MakeOpcode( DIVU1, Div, 0 );
MakeOpcode( ADDI, Default, IS_ALU|ALUTYPE_ADDI );
MakeOpcode( ADDIU, Default, IS_ALU|ALUTYPE_ADDI );
MakeOpcode( DADDI, Default, IS_ALU|ALUTYPE_ADDI|IS_64BIT );
MakeOpcode( DADDIU, Default, IS_ALU|ALUTYPE_ADDI|IS_64BIT );
MakeOpcode( DADD, Default, IS_ALU|ALUTYPE_ADD|IS_64BIT );
MakeOpcode( DADDU, Default, IS_ALU|ALUTYPE_ADD|IS_64BIT );
MakeOpcode( DSUB, Default, IS_ALU|ALUTYPE_SUB|IS_64BIT );
MakeOpcode( DSUBU, Default, IS_ALU|ALUTYPE_SUB|IS_64BIT );
MakeOpcode( ADD, Default, IS_ALU|ALUTYPE_ADD );
MakeOpcode( ADDU, Default, IS_ALU|ALUTYPE_ADD );
MakeOpcode( SUB, Default, IS_ALU|ALUTYPE_SUB );
MakeOpcode( SUBU, Default, IS_ALU|ALUTYPE_SUB );
MakeOpcode( ANDI, Default, 0 );
MakeOpcode( ORI, Default, 0 );
MakeOpcode( XORI, Default, 0 );
MakeOpcode( AND, Default, 0 );
MakeOpcode( OR, Default, 0 );
MakeOpcode( XOR, Default, 0 );
MakeOpcode( NOR, Default, 0 );
MakeOpcode( SLTI, Default, 0 );
MakeOpcode( SLTIU, Default, 0 );
MakeOpcode( SLT, Default, 0 );
MakeOpcode( SLTU, Default, 0 );
MakeOpcode( LUI, Default, 0 );
MakeOpcode( SLL, Default, 0 );
MakeOpcode( SRL, Default, 0 );
MakeOpcode( SRA, Default, 0 );
MakeOpcode( SLLV, Default, 0 );
MakeOpcode( SRLV, Default, 0 );
MakeOpcode( SRAV, Default, 0 );
MakeOpcode( MOVZ, Default, IS_ALU|ALUTYPE_CONDMOVE|CONDTYPE_EQ );
MakeOpcode( MOVN, Default, IS_ALU|ALUTYPE_CONDMOVE|CONDTYPE_NE );
MakeOpcode( DSLLV, Default, 0 );
MakeOpcode( DSRLV, Default, 0 );
MakeOpcode( DSRAV, Default, 0 );
MakeOpcode( DSLL, Default, 0 );
MakeOpcode( DSRL, Default, 0 );
MakeOpcode( DSRA, Default, 0 );
MakeOpcode( DSLL32, Default, 0 );
MakeOpcode( DSRL32, Default, 0 );
MakeOpcode( DSRA32, Default, 0 );
MakeOpcode( MFHI, Default, 0 );
MakeOpcode( MTHI, Default, 0 );
MakeOpcode( MFLO, Default, 0 );
MakeOpcode( MTLO, Default, 0 );
MakeOpcode( MFSA, Default, 0 );
MakeOpcode( MTSA, Default, 0 );
MakeOpcode( MTSAB, Default, 0 );
MakeOpcode( MTSAH, Default, 0 );
MakeOpcode( MFHI1, Default, 0 );
MakeOpcode( MTHI1, Default, 0 );
MakeOpcode( MFLO1, Default, 0 );
MakeOpcode( MTLO1, Default, 0 );
// Loads!
MakeOpcode( LDL, Load, IS_MEMORY|IS_LOAD|MEMTYPE_DWORD|IS_LEFT );
MakeOpcode( LDR, Load, IS_MEMORY|IS_LOAD|MEMTYPE_DWORD|IS_RIGHT );
MakeOpcode( LQ, Load, IS_MEMORY|IS_LOAD|MEMTYPE_QWORD );
MakeOpcode( LB, Load, IS_MEMORY|IS_LOAD|MEMTYPE_BYTE );
MakeOpcode( LH, Load, IS_MEMORY|IS_LOAD|MEMTYPE_HALF );
MakeOpcode( LWL, Load, IS_MEMORY|IS_LOAD|MEMTYPE_WORD|IS_LEFT );
MakeOpcode( LW, Load, IS_MEMORY|IS_LOAD|MEMTYPE_WORD );
MakeOpcode( LBU, Load, IS_MEMORY|IS_LOAD|MEMTYPE_BYTE );
MakeOpcode( LHU, Load, IS_MEMORY|IS_LOAD|MEMTYPE_HALF );
MakeOpcode( LWR, Load, IS_MEMORY|IS_LOAD|MEMTYPE_WORD|IS_RIGHT );
MakeOpcode( LWU, Load, IS_MEMORY|IS_LOAD|MEMTYPE_WORD );
MakeOpcode( LWC1, Load, IS_MEMORY|IS_LOAD|MEMTYPE_WORD );
MakeOpcode( LQC2, Load, IS_MEMORY|IS_LOAD|MEMTYPE_QWORD );
MakeOpcode( LD, Load, IS_MEMORY|IS_LOAD|MEMTYPE_DWORD );
// Stores!
MakeOpcode( SQ, Store, IS_MEMORY|IS_STORE|MEMTYPE_QWORD );
MakeOpcode( SB, Store, IS_MEMORY|IS_STORE|MEMTYPE_BYTE );
MakeOpcode( SH, Store, IS_MEMORY|IS_STORE|MEMTYPE_HALF );
MakeOpcode( SWL, Store, IS_MEMORY|IS_STORE|MEMTYPE_WORD|IS_LEFT );
MakeOpcode( SW, Store, IS_MEMORY|IS_STORE|MEMTYPE_WORD );
MakeOpcode( SDL, Store, IS_MEMORY|IS_STORE|MEMTYPE_DWORD|IS_LEFT );
MakeOpcode( SDR, Store, IS_MEMORY|IS_STORE|MEMTYPE_DWORD|IS_RIGHT );
MakeOpcode( SWR, Store, IS_MEMORY|IS_STORE|MEMTYPE_WORD|IS_RIGHT );
MakeOpcode( SWC1, Store, IS_MEMORY|IS_STORE|MEMTYPE_WORD );
MakeOpcode( SQC2, Store, IS_MEMORY|IS_STORE|MEMTYPE_QWORD );
MakeOpcode( SD, Store, IS_MEMORY|IS_STORE|MEMTYPE_DWORD );
// Multimedia Instructions!
MakeOpcodeM( PLZCW, MMI_Default, 0 );
MakeOpcodeM( PMFHL, MMI_Default, 0 );
MakeOpcodeM( PMTHL, MMI_Default, 0 );
MakeOpcodeM( PSLLH, MMI_Default, 0 );
MakeOpcodeM( PSRLH, MMI_Default, 0 );
MakeOpcodeM( PSRAH, MMI_Default, 0 );
MakeOpcodeM( PSLLW, MMI_Default, 0 );
MakeOpcodeM( PSRLW, MMI_Default, 0 );
MakeOpcodeM( PSRAW, MMI_Default, 0 );
MakeOpcodeM( PADDW, MMI_Default, 0 );
MakeOpcodeM( PADDH, MMI_Default, 0 );
MakeOpcodeM( PADDB, MMI_Default, 0 );
MakeOpcodeM( PADDSW, MMI_Default, 0 );
MakeOpcodeM( PADDSH, MMI_Default, 0 );
MakeOpcodeM( PADDSB, MMI_Default, 0 );
MakeOpcodeM( PADDUW, MMI_Default, 0 );
MakeOpcodeM( PADDUH, MMI_Default, 0 );
MakeOpcodeM( PADDUB, MMI_Default, 0 );
MakeOpcodeM( PSUBW, MMI_Default, 0 );
MakeOpcodeM( PSUBH, MMI_Default, 0 );
MakeOpcodeM( PSUBB, MMI_Default, 0 );
MakeOpcodeM( PSUBSW, MMI_Default, 0 );
MakeOpcodeM( PSUBSH, MMI_Default, 0 );
MakeOpcodeM( PSUBSB, MMI_Default, 0 );
MakeOpcodeM( PSUBUW, MMI_Default, 0 );
MakeOpcodeM( PSUBUH, MMI_Default, 0 );
MakeOpcodeM( PSUBUB, MMI_Default, 0 );
MakeOpcodeM( PCGTW, MMI_Default, 0 );
MakeOpcodeM( PMAXW, MMI_Default, 0 );
MakeOpcodeM( PMAXH, MMI_Default, 0 );
MakeOpcodeM( PCGTH, MMI_Default, 0 );
MakeOpcodeM( PCGTB, MMI_Default, 0 );
MakeOpcodeM( PEXTLW, MMI_Default, 0 );
MakeOpcodeM( PEXTLH, MMI_Default, 0 );
MakeOpcodeM( PEXTLB, MMI_Default, 0 );
MakeOpcodeM( PEXT5, MMI_Default, 0 );
MakeOpcodeM( PPACW, MMI_Default, 0 );
MakeOpcodeM( PPACH, MMI_Default, 0 );
MakeOpcodeM( PPACB, MMI_Default, 0 );
MakeOpcodeM( PPAC5, MMI_Default, 0 );
MakeOpcodeM( PABSW, MMI_Default, 0 );
MakeOpcodeM( PABSH, MMI_Default, 0 );
MakeOpcodeM( PCEQW, MMI_Default, 0 );
MakeOpcodeM( PMINW, MMI_Default, 0 );
MakeOpcodeM( PMINH, MMI_Default, 0 );
MakeOpcodeM( PADSBH, MMI_Default, 0 );
MakeOpcodeM( PCEQH, MMI_Default, 0 );
MakeOpcodeM( PCEQB, MMI_Default, 0 );
MakeOpcodeM( PEXTUW, MMI_Default, 0 );
MakeOpcodeM( PEXTUH, MMI_Default, 0 );
MakeOpcodeM( PEXTUB, MMI_Default, 0 );
MakeOpcodeM( PSLLVW, MMI_Default, 0 );
MakeOpcodeM( PSRLVW, MMI_Default, 0 );
MakeOpcodeM( QFSRV, MMI_Default, 0 );
MakeOpcodeM( PMADDH, MMI_Mult, 0 );
MakeOpcodeM( PHMADH, MMI_Mult, 0 );
MakeOpcodeM( PMSUBH, MMI_Mult, 0 );
MakeOpcodeM( PHMSBH, MMI_Mult, 0 );
MakeOpcodeM( PMULTH, MMI_Mult, 0 );
MakeOpcodeM( PMADDW, MMI_Mult, 0 );
MakeOpcodeM( PMSUBW, MMI_Mult, 0 );
MakeOpcodeM( PMFHI, MMI_Mult, 0 );
MakeOpcodeM( PMFLO, MMI_Mult, 0 );
MakeOpcodeM( PMULTW, MMI_Mult, 0 );
MakeOpcodeM( PMADDUW, MMI_Mult, 0 );
MakeOpcodeM( PMULTUW, MMI_Mult, 0 );
MakeOpcodeM( PDIVUW, MMI_Div, 0 );
MakeOpcodeM( PDIVW, MMI_Div, 0 );
MakeOpcodeM( PDIVBW, MMI_Div, 0 );
MakeOpcodeM( PINTH, MMI_Default, 0 );
MakeOpcodeM( PCPYLD, MMI_Default, 0 );
MakeOpcodeM( PAND, MMI_Default, 0 );
MakeOpcodeM( PXOR, MMI_Default, 0 );
MakeOpcodeM( PEXEH, MMI_Default, 0 );
MakeOpcodeM( PREVH, MMI_Default, 0 );
MakeOpcodeM( PEXEW, MMI_Default, 0 );
MakeOpcodeM( PROT3W, MMI_Default, 0 );
MakeOpcodeM( PSRAVW, MMI_Default, 0 );
MakeOpcodeM( PMTHI, MMI_Default, 0 );
MakeOpcodeM( PMTLO, MMI_Default, 0 );
MakeOpcodeM( PINTEH, MMI_Default, 0 );
MakeOpcodeM( PCPYUD, MMI_Default, 0 );
MakeOpcodeM( POR, MMI_Default, 0 );
MakeOpcodeM( PNOR, MMI_Default, 0 );
MakeOpcodeM( PEXCH, MMI_Default, 0 );
MakeOpcodeM( PCPYH, MMI_Default, 0 );
MakeOpcodeM( PEXCW, MMI_Default, 0 );
//////////////////////////////////////////////////////////
// COP0 Instructions
MakeOpcodeClass( COP0_C0 );
MakeOpcodeClass( COP0_BC0 );
MakeOpcode0( MFC0, CopDefault, 0 );
MakeOpcode0( MTC0, CopDefault, 0 );
MakeOpcode0(BC0F, Branch, IS_BRANCH | BRANCHTYPE_BC0 | CONDTYPE_EQ);
MakeOpcode0(BC0T, Branch, IS_BRANCH | BRANCHTYPE_BC0 | CONDTYPE_NE);
MakeOpcode0(BC0FL, Branch, IS_BRANCH | BRANCHTYPE_BC0 | CONDTYPE_EQ | IS_LIKELY);
MakeOpcode0(BC0TL, Branch, IS_BRANCH | BRANCHTYPE_BC0 | CONDTYPE_NE | IS_LIKELY);
MakeOpcode0( TLBR, CopDefault, 0 );
MakeOpcode0( TLBWI, CopDefault, 0 );
MakeOpcode0( TLBWR, CopDefault, 0 );
MakeOpcode0( TLBP, CopDefault, 0 );
MakeOpcode0( ERET, CopDefault, IS_BRANCH|BRANCHTYPE_ERET );
MakeOpcode0( EI, CopDefault, 0 );
MakeOpcode0( DI, CopDefault, 0 );
//////////////////////////////////////////////////////////
// COP1 Instructions!
MakeOpcodeClass( COP1_BC1 );
MakeOpcodeClass( COP1_S );
MakeOpcodeClass( COP1_W ); // contains CVT_S instruction *only*
MakeOpcode1( MFC1, CopDefault, 0 );
MakeOpcode1( CFC1, CopDefault, 0 );
MakeOpcode1( MTC1, CopDefault, 0 );
MakeOpcode1( CTC1, CopDefault, 0 );
MakeOpcode1( BC1F, Branch, IS_BRANCH|BRANCHTYPE_BC1|CONDTYPE_EQ );
MakeOpcode1( BC1T, Branch, IS_BRANCH|BRANCHTYPE_BC1|CONDTYPE_NE );
MakeOpcode1( BC1FL, Branch, IS_BRANCH|BRANCHTYPE_BC1|CONDTYPE_EQ|IS_LIKELY );
MakeOpcode1( BC1TL, Branch, IS_BRANCH|BRANCHTYPE_BC1|CONDTYPE_NE|IS_LIKELY );
MakeOpcode1( ADD_S, CopDefault, 0 );
MakeOpcode1( ADDA_S, CopDefault, 0 );
MakeOpcode1( SUB_S, CopDefault, 0 );
MakeOpcode1( SUBA_S, CopDefault, 0 );
MakeOpcode1( ABS_S, CopDefault, 0 );
MakeOpcode1( MOV_S, CopDefault, 0 );
MakeOpcode1( NEG_S, CopDefault, 0 );
MakeOpcode1( MAX_S, CopDefault, 0 );
MakeOpcode1( MIN_S, CopDefault, 0 );
// The FPU's real timings, measured on silicon rather than inferred.
// Method: COP0 Count around loops of k copies of one instruction, k in
// {1,2,4,8}, so the loop overhead falls out as the intercept and the
// per-instruction cost is the slope. Taken on an SCPH-90000 (FCR0
// 0x2E40) over four runs; three produce byte-identical tables.
//
// MUL.S latency 4, issue interval 1 (pipelined)
// DIV.S 7, and latency == issue interval
// SQRT.S 7, identical to DIV.S
// RSQRT.S 13
//
// DIV.S and SQRT.S are ONE shared, non-pipelined unit. Equal latency
// alone would not say that -- what does is the mix: interleaved
// div.s/sqrt.s costs the SUM (14 per pair), while div.s/add.s and
// div.s/mul.s cost the divide ALONE (7 per pair), because the FMAC runs
// concurrently and hides inside the divide entirely. RSQRT.S at
// 7 + 7 - 1 is two passes through that unit, which agrees with its value
// identity (rsqrt == sqrt then divide, see FPU.cpp's RSQRT_S). The
// latency is identical on every operand class tried -- exact and
// non-terminating quotients, denormals, zero, divide by zero, overflow
// to the EE maximum -- so there is no early termination anywhere.
//
// The three entries below say 6, 6 and 8. They are LEFT AS THEY ARE
// deliberately: this is a compatibility-sensitive timing table, not a
// correctness one, and nothing has measured what moving it does to
// games. The numbers above are recorded here so that the next person to
// wonder does not have to take the console run again. (FPU_Mult's 4
// does match the measured multiply latency.)
MakeOpcode1( MUL_S, FPU_Mult, 0 );
MakeOpcode1( DIV_S, 6*8, 0 );
MakeOpcode1( SQRT_S, 6*8, 0 );
MakeOpcode1( RSQRT_S, 8*8, 0 );
MakeOpcode1( MULA_S, FPU_Mult, 0 );
MakeOpcode1( MADD_S, FPU_Mult, 0 );
MakeOpcode1( MSUB_S, FPU_Mult, 0 );
MakeOpcode1( MADDA_S, FPU_Mult, 0 );
MakeOpcode1( MSUBA_S, FPU_Mult, 0 );
MakeOpcode1( C_F, CopDefault, 0 );
MakeOpcode1( C_EQ, CopDefault, 0 );
MakeOpcode1( C_LT, CopDefault, 0 );
MakeOpcode1( C_LE, CopDefault, 0 );
MakeOpcode1( CVT_S, CopDefault, 0 );
MakeOpcode1( CVT_W, CopDefault, 0 );
}
namespace OpcodeTables
{
using namespace Opcodes;
const OPCODE tbl_Standard[64] =
{
SPECIAL, REGIMM, J, JAL, BEQ, BNE, BLEZ, BGTZ,
ADDI, ADDIU, SLTI, SLTIU, ANDI, ORI, XORI, LUI,
COP0, COP1, COP2, Unknown, BEQL, BNEL, BLEZL, BGTZL,
DADDI, DADDIU, LDL, LDR, MMI, Unknown, LQ, SQ,
LB, LH, LWL, LW, LBU, LHU, LWR, LWU,
SB, SH, SWL, SW, SDL, SDR, SWR, CACHE,
Unknown, LWC1, Unknown, PREF, Unknown, Unknown, LQC2, LD,
Unknown, SWC1, Unknown, Unknown, Unknown, Unknown, SQC2, SD
};
static const OPCODE tbl_Special[64] =
{
SLL, Unknown, SRL, SRA, SLLV, Unknown, SRLV, SRAV,
JR, JALR, MOVZ, MOVN, SYSCALL, BREAK, Unknown, SYNC,
MFHI, MTHI, MFLO, MTLO, DSLLV, Unknown, DSRLV, DSRAV,
MULT, MULTU, DIV, DIVU, Unknown, Unknown, Unknown, Unknown,
ADD, ADDU, SUB, SUBU, AND, OR, XOR, NOR,
MFSA, MTSA, SLT, SLTU, DADD, DADDU, DSUB, DSUBU,
TGE, TGEU, TLT, TLTU, TEQ, Unknown, TNE, Unknown,
DSLL, Unknown, DSRL, DSRA, DSLL32, Unknown, DSRL32, DSRA32
};
static const OPCODE tbl_RegImm[32] = {
BLTZ, BGEZ, BLTZL, BGEZL, Unknown, Unknown, Unknown, Unknown,
TGEI, TGEIU, TLTI, TLTIU, TEQI, Unknown, TNEI, Unknown,
BLTZAL, BGEZAL, BLTZALL, BGEZALL, Unknown, Unknown, Unknown, Unknown,
MTSAB, MTSAH , Unknown, Unknown, Unknown, Unknown, Unknown, Unknown,
};
static const OPCODE tbl_MMI[64] =
{
MADD, MADDU, MMI_Unknown, MMI_Unknown, PLZCW, MMI_Unknown, MMI_Unknown, MMI_Unknown,
MMI0, MMI2, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown,
MFHI1, MTHI1, MFLO1, MTLO1, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown,
MULT1, MULTU1, DIV1, DIVU1, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown,
MADD1, MADDU1, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown,
MMI1, MMI3, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown,
PMFHL, PMTHL, MMI_Unknown, MMI_Unknown, PSLLH, MMI_Unknown, PSRLH, PSRAH,
MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, PSLLW, MMI_Unknown, PSRLW, PSRAW,
};
static const OPCODE tbl_MMI0[32] =
{
PADDW, PSUBW, PCGTW, PMAXW,
PADDH, PSUBH, PCGTH, PMAXH,
PADDB, PSUBB, PCGTB, MMI_Unknown,
MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown,
PADDSW, PSUBSW, PEXTLW, PPACW,
PADDSH, PSUBSH, PEXTLH, PPACH,
PADDSB, PSUBSB, PEXTLB, PPACB,
MMI_Unknown, MMI_Unknown, PEXT5, PPAC5,
};
static const OPCODE tbl_MMI1[32] =
{
MMI_Unknown, PABSW, PCEQW, PMINW,
PADSBH, PABSH, PCEQH, PMINH,
MMI_Unknown, MMI_Unknown, PCEQB, MMI_Unknown,
MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown,
PADDUW, PSUBUW, PEXTUW, MMI_Unknown,
PADDUH, PSUBUH, PEXTUH, MMI_Unknown,
PADDUB, PSUBUB, PEXTUB, QFSRV,
MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown,
};
static const OPCODE tbl_MMI2[32] =
{
PMADDW, MMI_Unknown, PSLLVW, PSRLVW,
PMSUBW, MMI_Unknown, MMI_Unknown, MMI_Unknown,
PMFHI, PMFLO, PINTH, MMI_Unknown,
PMULTW, PDIVW, PCPYLD, MMI_Unknown,
PMADDH, PHMADH, PAND, PXOR,
PMSUBH, PHMSBH, MMI_Unknown, MMI_Unknown,
MMI_Unknown, MMI_Unknown, PEXEH, PREVH,
PMULTH, PDIVBW, PEXEW, PROT3W,
};
static const OPCODE tbl_MMI3[32] =
{
PMADDUW, MMI_Unknown, MMI_Unknown, PSRAVW,
MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown,
PMTHI, PMTLO, PINTEH, MMI_Unknown,
PMULTUW, PDIVUW, PCPYUD, MMI_Unknown,
MMI_Unknown, MMI_Unknown, POR, PNOR,
MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown,
MMI_Unknown, MMI_Unknown, PEXCH, PCPYH,
MMI_Unknown, MMI_Unknown, PEXCW, MMI_Unknown,
};
static const OPCODE tbl_COP0[32] =
{
MFC0, COP0_Unknown, COP0_Unknown, COP0_Unknown, MTC0, COP0_Unknown, COP0_Unknown, COP0_Unknown,
COP0_BC0, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown,
COP0_C0, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown,
COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown,
};
static const OPCODE tbl_COP0_BC0[32] =
{
BC0F, BC0T, BC0FL, BC0TL, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown,
COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown,
COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown,
COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown,
};
static const OPCODE tbl_COP0_C0[64] =
{
COP0_Unknown, TLBR, TLBWI, COP0_Unknown, COP0_Unknown, COP0_Unknown, TLBWR, COP0_Unknown,
TLBP, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown,
COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown,
ERET, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown,
COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown,
COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown,
COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown,
EI, DI, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown
};
static const OPCODE tbl_COP1[32] =
{
MFC1, COP1_Unknown, CFC1, COP1_Unknown, MTC1, COP1_Unknown, CTC1, COP1_Unknown,
COP1_BC1, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown,
COP1_S, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_W, COP1_Unknown, COP1_Unknown, COP1_Unknown,
COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown,
};
static const OPCODE tbl_COP1_BC1[32] =
{
BC1F, BC1T, BC1FL, BC1TL, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown,
COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown,
COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown,
COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown,
};
static const OPCODE tbl_COP1_S[64] =
{
ADD_S, SUB_S, MUL_S, DIV_S, SQRT_S, ABS_S, MOV_S, NEG_S,
COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,
COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,RSQRT_S, COP1_Unknown,
ADDA_S, SUBA_S, MULA_S, COP1_Unknown,MADD_S, MSUB_S, MADDA_S, MSUBA_S,
COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,CVT_W, COP1_Unknown,COP1_Unknown,COP1_Unknown,
MAX_S, MIN_S, COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,
C_F, COP1_Unknown,C_EQ, COP1_Unknown,C_LT, COP1_Unknown,C_LE, COP1_Unknown,
COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,
};
static const OPCODE tbl_COP1_W[64] =
{
COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,
COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,
COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,
COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,
CVT_S, COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,
COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,
COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,
COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,
};
} // end namespace R5900::OpcodeTables
namespace Opcodes
{
using namespace OpcodeTables;
const OPCODE& Class_SPECIAL(u32 op) { return tbl_Special[op & 0x3F]; }
const OPCODE& Class_REGIMM(u32 op) { return tbl_RegImm[(op >> 16) & 0x1F]; }
const OPCODE& Class_MMI(u32 op) { return tbl_MMI[op & 0x3F]; }
const OPCODE& Class_MMI0(u32 op) { return tbl_MMI0[(op >> 6) & 0x1F]; }
const OPCODE& Class_MMI1(u32 op) { return tbl_MMI1[(op >> 6) & 0x1F]; }
const OPCODE& Class_MMI2(u32 op) { return tbl_MMI2[(op >> 6) & 0x1F]; }
const OPCODE& Class_MMI3(u32 op) { return tbl_MMI3[(op >> 6) & 0x1F]; }
const OPCODE& Class_COP0(u32 op) { return tbl_COP0[(op >> 21) & 0x1F]; }
const OPCODE& Class_COP0_BC0(u32 op) { return tbl_COP0_BC0[(op >> 16) & 0x03]; }
const OPCODE& Class_COP0_C0(u32 op) { return tbl_COP0_C0[op & 0x3F]; }
const OPCODE& Class_COP1(u32 op) { return tbl_COP1[(op >> 21) & 0x1F]; }
const OPCODE& Class_COP1_BC1(u32 op) { return tbl_COP1_BC1[(op >> 16) & 0x1F]; }
const OPCODE& Class_COP1_S(u32 op) { return tbl_COP1_S[op & 0x3F]; }
const OPCODE& Class_COP1_W(u32 op) { return tbl_COP1_W[op & 0x3F]; }
// These are for future use when the COP2 tables are completed.
//const OPCODE& Class_COP2() { return tbl_COP2[_Rs_]; }
//const OPCODE& Class_COP2_BC2() { return tbl_COP2_BC2[_Rt_]; }
//const OPCODE& Class_COP2_SPECIAL() { return tbl_COP2_SPECIAL[_Funct_]; }
//const OPCODE& Class_COP2_SPECIAL2() { return tbl_COP2_SPECIAL2[(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c)]; }
}
} // end namespace R5900
void (*Int_COP2PrintTable[32])() = {
COP2_Unknown, QMFC2, CFC2, COP2_Unknown, COP2_Unknown, QMTC2, CTC2, COP2_Unknown,
COP2_BC2, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown,
COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL,
COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL,
};
void (*Int_COP2BC2PrintTable[32])() = {
BC2F, BC2T, BC2FL, BC2TL, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown,
COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown,
COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown,
COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown,
};
void (*Int_COP2SPECIAL1PrintTable[64])() =
{
VADDx, VADDy, VADDz, VADDw, VSUBx, VSUBy, VSUBz, VSUBw,
VMADDx, VMADDy, VMADDz, VMADDw, VMSUBx, VMSUBy, VMSUBz, VMSUBw,
VMAXx, VMAXy, VMAXz, VMAXw, VMINIx, VMINIy, VMINIz, VMINIw,
VMULx, VMULy, VMULz, VMULw, VMULq, VMAXi, VMULi, VMINIi,
VADDq, VMADDq, VADDi, VMADDi, VSUBq, VMSUBq, VSUBi, VMSUBi,
VADD, VMADD, VMUL, VMAX, VSUB, VMSUB, VOPMSUB, VMINI,
VIADD, VISUB, VIADDI, COP2_Unknown,VIAND, VIOR, COP2_Unknown, COP2_Unknown,
VCALLMS, VCALLMSR, COP2_Unknown,COP2_Unknown,COP2_SPECIAL2,COP2_SPECIAL2,COP2_SPECIAL2,COP2_SPECIAL2,
};
void (*Int_COP2SPECIAL2PrintTable[128])() =
{
VADDAx ,VADDAy ,VADDAz ,VADDAw ,VSUBAx ,VSUBAy ,VSUBAz ,VSUBAw,
VMADDAx ,VMADDAy ,VMADDAz ,VMADDAw ,VMSUBAx ,VMSUBAy ,VMSUBAz ,VMSUBAw,
VITOF0 ,VITOF4 ,VITOF12 ,VITOF15 ,VFTOI0 ,VFTOI4 ,VFTOI12 ,VFTOI15,
VMULAx ,VMULAy ,VMULAz ,VMULAw ,VMULAq ,VABS ,VMULAi ,VCLIPw,
VADDAq ,VMADDAq ,VADDAi ,VMADDAi ,VSUBAq ,VMSUBAq ,VSUBAi ,VMSUBAi,
VADDA ,VMADDA ,VMULA ,COP2_Unknown,VSUBA ,VMSUBA ,VOPMULA ,VNOP,
VMOVE ,VMR32 ,COP2_Unknown,COP2_Unknown,VLQI ,VSQI ,VLQD ,VSQD,
VDIV ,VSQRT ,VRSQRT ,VWAITQ ,VMTIR ,VMFIR ,VILWR ,VISWR,
VRNEXT ,VRGET ,VRINIT ,VRXOR ,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,
COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,
COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,
COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,
COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,
COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,
COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,
COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,
};