Introduce a Fake JIT for generic builds.

This commit is contained in:
Sacha 2014-11-13 00:09:51 +10:00
parent cbef4fae26
commit a0086f6412
9 changed files with 998 additions and 15 deletions

475
Common/FakeEmitter.h Normal file
View File

@ -0,0 +1,475 @@
// Copyright (C) 2003 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// WARNING - THIS LIBRARY IS NOT THREAD SAFE!!!
#ifndef _DOLPHIN_FAKE_CODEGEN_
#define _DOLPHIN_FAKE_CODEGEN_
#include <vector>
#include <stdint.h>
#include "Common.h"
#include "MsgHandler.h"
// TODO: Check if Pandora still needs signal.h/kill here. Symbian doesn't.
// VCVT flags
#define TO_FLOAT 0
#define TO_INT 1 << 0
#define IS_SIGNED 1 << 1
#define ROUND_TO_ZERO 1 << 2
namespace FakeGen
{
enum FakeReg
{
// GPRs
R0 = 0, R1, R2, R3, R4, R5,
R6, R7, R8, R9, R10, R11,
// SPRs
// R13 - R15 are SP, LR, and PC.
// Almost always referred to by name instead of register number
R12 = 12, R13 = 13, R14 = 14, R15 = 15,
R_IP = 12, R_SP = 13, R_LR = 14, R_PC = 15,
// VFP single precision registers
S0, S1, S2, S3, S4, S5, S6,
S7, S8, S9, S10, S11, S12, S13,
S14, S15, S16, S17, S18, S19, S20,
S21, S22, S23, S24, S25, S26, S27,
S28, S29, S30, S31,
// VFP Double Precision registers
D0, D1, D2, D3, D4, D5, D6, D7,
D8, D9, D10, D11, D12, D13, D14, D15,
D16, D17, D18, D19, D20, D21, D22, D23,
D24, D25, D26, D27, D28, D29, D30, D31,
// ASIMD Quad-Word registers
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7,
Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15,
// for NEON VLD/VST instructions
REG_UPDATE = R13,
INVALID_REG = 0xFFFFFFFF
};
enum CCFlags
{
CC_EQ = 0, // Equal
CC_NEQ, // Not equal
CC_CS, // Carry Set
CC_CC, // Carry Clear
CC_MI, // Minus (Negative)
CC_PL, // Plus
CC_VS, // Overflow
CC_VC, // No Overflow
CC_HI, // Unsigned higher
CC_LS, // Unsigned lower or same
CC_GE, // Signed greater than or equal
CC_LT, // Signed less than
CC_GT, // Signed greater than
CC_LE, // Signed less than or equal
CC_AL, // Always (unconditional) 14
CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same
CC_LO = CC_CC, // Alias of CC_CC Unsigned lower
};
const u32 NO_COND = 0xE0000000;
enum ShiftType
{
ST_LSL = 0,
ST_ASL = 0,
ST_LSR = 1,
ST_ASR = 2,
ST_ROR = 3,
ST_RRX = 4
};
enum IntegerSize
{
I_I8 = 0,
I_I16,
I_I32,
I_I64
};
enum
{
NUMGPRs = 13,
};
class FakeXEmitter;
enum OpType
{
TYPE_IMM = 0,
TYPE_REG,
TYPE_IMMSREG,
TYPE_RSR,
TYPE_MEM
};
// This is no longer a proper operand2 class. Need to split up.
class Operand2
{
friend class FakeXEmitter;
protected:
u32 Value;
private:
OpType Type;
// IMM types
u8 Rotation; // Only for u8 values
// Register types
u8 IndexOrShift;
ShiftType Shift;
public:
OpType GetType()
{
return Type;
}
Operand2() {}
Operand2(u32 imm, OpType type = TYPE_IMM)
{
Type = type;
Value = imm;
Rotation = 0;
}
Operand2(FakeReg Reg)
{
Type = TYPE_REG;
Value = Reg;
Rotation = 0;
}
Operand2(u8 imm, u8 rotation)
{
Type = TYPE_IMM;
Value = imm;
Rotation = rotation;
}
Operand2(FakeReg base, ShiftType type, FakeReg shift) // RSR
{
Type = TYPE_RSR;
_assert_msg_(JIT, type != ST_RRX, "Invalid Operand2: RRX does not take a register shift amount");
IndexOrShift = shift;
Shift = type;
Value = base;
}
Operand2(FakeReg base, ShiftType type, u8 shift)// For IMM shifted register
{
if(shift == 32) shift = 0;
switch (type)
{
case ST_LSL:
_assert_msg_(JIT, shift < 32, "Invalid Operand2: LSL %u", shift);
break;
case ST_LSR:
_assert_msg_(JIT, shift <= 32, "Invalid Operand2: LSR %u", shift);
if (!shift)
type = ST_LSL;
if (shift == 32)
shift = 0;
break;
case ST_ASR:
_assert_msg_(JIT, shift < 32, "Invalid Operand2: ASR %u", shift);
if (!shift)
type = ST_LSL;
if (shift == 32)
shift = 0;
break;
case ST_ROR:
_assert_msg_(JIT, shift < 32, "Invalid Operand2: ROR %u", shift);
if (!shift)
type = ST_LSL;
break;
case ST_RRX:
_assert_msg_(JIT, shift == 0, "Invalid Operand2: RRX does not take an immediate shift amount");
type = ST_ROR;
break;
}
IndexOrShift = shift;
Shift = type;
Value = base;
Type = TYPE_IMMSREG;
}
u32 GetData()
{
switch(Type)
{
case TYPE_IMM:
return Imm12Mod(); // This'll need to be changed later
case TYPE_REG:
return Rm();
case TYPE_IMMSREG:
return IMMSR();
case TYPE_RSR:
return RSR();
default:
_assert_msg_(JIT, false, "GetData with Invalid Type");
return 0;
}
}
u32 IMMSR() // IMM shifted register
{
_assert_msg_(JIT, Type == TYPE_IMMSREG, "IMMSR must be imm shifted register");
return ((IndexOrShift & 0x1f) << 7 | (Shift << 5) | Value);
}
u32 RSR() // Register shifted register
{
_assert_msg_(JIT, Type == TYPE_RSR, "RSR must be RSR Of Course");
return (IndexOrShift << 8) | (Shift << 5) | 0x10 | Value;
}
u32 Rm()
{
_assert_msg_(JIT, Type == TYPE_REG, "Rm must be with Reg");
return Value;
}
u32 Imm5()
{
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm5 not IMM value");
return ((Value & 0x0000001F) << 7);
}
u32 Imm8()
{
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm8Rot not IMM value");
return Value & 0xFF;
}
u32 Imm8Rot() // IMM8 with Rotation
{
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm8Rot not IMM value");
_assert_msg_(JIT, (Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation);
return (1 << 25) | (Rotation << 7) | (Value & 0x000000FF);
}
u32 Imm12()
{
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm12 not IMM");
return (Value & 0x00000FFF);
}
u32 Imm12Mod()
{
// This is an IMM12 with the top four bits being rotation and the
// bottom eight being an IMM. This is for instructions that need to
// expand a 8bit IMM to a 32bit value and gives you some rotation as
// well.
// Each rotation rotates to the right by 2 bits
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm12Mod not IMM");
return ((Rotation & 0xF) << 8) | (Value & 0xFF);
}
u32 Imm16()
{
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm16 not IMM");
return ( (Value & 0xF000) << 4) | (Value & 0x0FFF);
}
u32 Imm16Low()
{
return Imm16();
}
u32 Imm16High() // Returns high 16bits
{
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm16 not IMM");
return ( ((Value >> 16) & 0xF000) << 4) | ((Value >> 16) & 0x0FFF);
}
u32 Imm24()
{
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm16 not IMM");
return (Value & 0x0FFFFFFF);
}
};
// Use these when you don't know if an imm can be represented as an operand2.
// This lets you generate both an optimal and a fallback solution by checking
// the return value, which will be false if these fail to find a Operand2 that
// represents your 32-bit imm value.
bool TryMakeOperand2(u32 imm, Operand2 &op2);
bool TryMakeOperand2_AllowInverse(u32 imm, Operand2 &op2, bool *inverse);
bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated);
// Use this only when you know imm can be made into an Operand2.
Operand2 AssumeMakeOperand2(u32 imm);
inline Operand2 R(FakeReg Reg) { return Operand2(Reg, TYPE_REG); }
inline Operand2 IMM(u32 Imm) { return Operand2(Imm, TYPE_IMM); }
inline Operand2 Mem(void *ptr) { return Operand2((u32)(uintptr_t)ptr, TYPE_IMM); }
//usage: struct {int e;} s; STRUCT_OFFSET(s,e)
#define STRUCT_OFF(str,elem) ((u32)((u32)&(str).elem-(u32)&(str)))
struct FixupBranch
{
u8 *ptr;
u32 condition; // Remembers our codition at the time
int type; //0 = B 1 = BL
};
struct LiteralPool
{
intptr_t loc;
u8* ldr_address;
u32 val;
};
typedef const u8* JumpTarget;
// XXX: Stop polluting the global namespace
const u32 I_8 = (1 << 0);
const u32 I_16 = (1 << 1);
const u32 I_32 = (1 << 2);
const u32 I_64 = (1 << 3);
const u32 I_SIGNED = (1 << 4);
const u32 I_UNSIGNED = (1 << 5);
const u32 F_32 = (1 << 6);
const u32 I_POLYNOMIAL = (1 << 7); // Only used in VMUL/VMULL
u32 EncodeVd(FakeReg Vd);
u32 EncodeVn(FakeReg Vn);
u32 EncodeVm(FakeReg Vm);
u32 encodedSize(u32 value);
// Subtracts the base from the register to give us the real one
FakeReg SubBase(FakeReg Reg);
// See A.7.1 in the Fakev7-A
// VMUL F32 scalars can only be up to D15[0], D15[1] - higher scalars cannot be individually addressed
FakeReg DScalar(FakeReg dreg, int subScalar);
FakeReg QScalar(FakeReg qreg, int subScalar);
enum NEONAlignment {
ALIGN_NONE = 0,
ALIGN_64 = 1,
ALIGN_128 = 2,
ALIGN_256 = 3
};
class NEONXEmitter;
class FakeXEmitter
{
friend struct OpArg; // for Write8 etc
private:
u8 *code, *startcode;
u8 *lastCacheFlushEnd;
u32 condition;
protected:
inline void Write32(u32 value) {*(u32*)code = value; code+=4;}
public:
FakeXEmitter() : code(0), startcode(0), lastCacheFlushEnd(0) {
condition = CC_AL << 28;
}
FakeXEmitter(u8 *code_ptr) {
code = code_ptr;
lastCacheFlushEnd = code_ptr;
startcode = code_ptr;
condition = CC_AL << 28;
}
virtual ~FakeXEmitter() {}
void SetCodePtr(u8 *ptr) {}
void ReserveCodeSpace(u32 bytes) {}
const u8 *AlignCode16() { return nullptr; }
const u8 *AlignCodePage() { return nullptr; }
const u8 *GetCodePtr() const { return nullptr; }
void FlushIcache() {}
void FlushIcacheSection(u8 *start, u8 *end) {}
u8 *GetWritableCodePtr() { return nullptr; }
CCFlags GetCC() { return CCFlags(condition >> 28); }
void SetCC(CCFlags cond = CC_AL) {}
// Special purpose instructions
// Do nothing
void NOP(int count = 1) {} //nop padding - TODO: fast nop slides, for amd and intel (check their manuals)
#ifdef CALL
#undef CALL
#endif
void QuickCallFunction(FakeReg scratchreg, const void *func);
template <typename T> void QuickCallFunction(FakeReg scratchreg, T func) {
QuickCallFunction(scratchreg, (const void *)func);
}
}; // class FakeXEmitter
// Everything that needs to generate machine code should inherit from this.
// You get memory management for free, plus, you can use all the MOV etc functions without
// having to prefix them with gen-> or something similar.
class FakeXCodeBlock : public FakeXEmitter
{
protected:
u8 *region;
size_t region_size;
public:
FakeXCodeBlock() : region(NULL), region_size(0) {}
virtual ~FakeXCodeBlock() { if (region) FreeCodeSpace(); }
// Call this before you generate any code.
void AllocCodeSpace(int size) { }
// Always clear code space with breakpoints, so that if someone accidentally executes
// uninitialized, it just breaks into the debugger.
void ClearCodeSpace() { }
// Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
void FreeCodeSpace() { }
bool IsInSpace(const u8 *ptr) const
{
return ptr >= region && ptr < region + region_size;
}
// Cannot currently be undone. Will write protect the entire code region.
// Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
void WriteProtect() { }
void UnWriteProtect() { }
void ResetCodePtr()
{
SetCodePtr(region);
}
size_t GetSpaceLeft() const
{
return region_size - (GetCodePtr() - region);
}
u8 *GetBasePtr() {
return region;
}
size_t GetOffset(const u8 *ptr) const {
return ptr - region;
}
};
} // namespace
#endif // _DOLPHIN_FAKE_CODEGEN_

View File

@ -44,20 +44,15 @@
#include "Core/MIPS/JitCommon/JitCommon.h"
#if defined(ARM)
#include "Common/ArmEmitter.h"
#include "Core/MIPS/ARM/ArmAsm.h"
using namespace ArmGen;
#elif defined(_M_IX86) || defined(_M_X64)
#include "Common/x64Emitter.h"
#include "Common/x64Analyzer.h"
#include "Core/MIPS/x86/Asm.h"
using namespace Gen;
#elif defined(PPC)
#include "Common/ppcEmitter.h"
#include "Core/MIPS/MIPS.h"
using namespace PpcGen;
#else
#error "Unsupported arch!"
#warning "Unsupported arch!"
#include "Core/MIPS/MIPS.h"
#endif
// #include "JitBase.h"

View File

@ -50,7 +50,11 @@ namespace PpcGen { class PPCXEmitter; }
using namespace PpcGen;
typedef PpcGen::PPCXCodeBlock CodeBlock;
#else
#error "Unsupported arch!"
#warning "Unsupported arch!"
#include "Common/FakeEmitter.h"
namespace FakeGen { class FakeXEmitter; }
using namespace FakeGen;
typedef FakeGen::FakeXCodeBlock CodeBlock;
#endif
#if defined(ARM)

View File

@ -32,8 +32,10 @@ struct JitBlock;
#include "../PPC/PpcJit.h"
#elif defined(ARM)
#include "../ARM/ArmJit.h"
#else
#elif defined(_M_IX86) || defined(_M_X64)
#include "../x86/Jit.h"
#else
#include "../fake/FakeJit.h"
#endif
// Unlike on the PPC, opcode 0 is not unused and thus we have to choose another fake

View File

@ -32,12 +32,14 @@
#include "Core/System.h"
#include "Core/HLE/sceDisplay.h"
#if defined(ARM)
#include "ARM/ArmJit.h"
#elif defined(PPC)
#if defined(PPC)
#include "PPC/PpcJit.h"
#else
#elif defined(ARM)
#include "ARM/ArmJit.h"
#elif defined(_M_IX86) || defined(_M_X64)
#include "x86/Jit.h"
#else
#include "fake/FakeJit.h"
#endif
#include "Core/MIPS/JitCommon/JitCommon.h"
#include "Core/CoreTiming.h"

243
Core/MIPS/fake/FakeJit.cpp Normal file
View File

@ -0,0 +1,243 @@
// Copyright (c) 2012- PPSSPP Project.
// 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, version 2.0 or later versions.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "base/logging.h"
#include "Common/ChunkFile.h"
#include "Core/Reporting.h"
#include "Core/Config.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/Debugger/SymbolMap.h"
#include "Core/MemMap.h"
#include "Core/MIPS/MIPS.h"
#include "Core/MIPS/MIPSCodeUtils.h"
#include "Core/MIPS/MIPSInt.h"
#include "Core/MIPS/MIPSTables.h"
#include "Core/HLE/ReplaceTables.h"
#include "FakeJit.h"
#include "CPUDetect.h"
void DisassembleFake(const u8 *data, int size) {
}
namespace MIPSComp
{
FakeJitOptions::FakeJitOptions() {
enableBlocklink = true;
downcountInRegister = true;
useBackJump = false;
useForwardJump = false;
cachePointers = true;
immBranches = false;
continueBranches = false;
continueJumps = false;
continueMaxInstructions = 300;
}
Jit::Jit(MIPSState *mips) : blocks(mips, this), mips_(mips)
{
logBlocks = 0;
dontLogBlocks = 0;
blocks.Init();
}
void Jit::DoState(PointerWrap &p)
{
auto s = p.Section("Jit", 1, 2);
if (!s)
return;
p.Do(js.startDefaultPrefix);
if (s >= 2) {
p.Do(js.hasSetRounding);
js.lastSetRounding = 0;
} else {
js.hasSetRounding = 1;
}
}
// This is here so the savestate matches between jit and non-jit.
void Jit::DoDummyState(PointerWrap &p)
{
auto s = p.Section("Jit", 1, 2);
if (!s)
return;
bool dummy = false;
p.Do(dummy);
if (s >= 2) {
dummy = true;
p.Do(dummy);
}
}
void Jit::FlushAll()
{
FlushPrefixV();
}
void Jit::FlushPrefixV()
{
}
void Jit::ClearCache()
{
blocks.Clear();
ClearCodeSpace();
GenerateFixedCode();
}
void Jit::InvalidateCache()
{
blocks.Clear();
}
void Jit::InvalidateCacheAt(u32 em_address, int length)
{
blocks.InvalidateICache(em_address, length);
}
void Jit::EatInstruction(MIPSOpcode op) {
}
void Jit::CompileDelaySlot(int flags)
{
}
void Jit::Compile(u32 em_address) {
}
void Jit::RunLoopUntil(u64 globalticks)
{
((void (*)())enterCode)();
}
const u8 *Jit::DoJit(u32 em_address, JitBlock *b)
{
return b->normalEntry;
}
void Jit::AddContinuedBlock(u32 dest)
{
}
bool Jit::DescribeCodePtr(const u8 *ptr, std::string &name)
{
// TODO: Not used by anything yet.
return false;
}
void Jit::Comp_RunBlock(MIPSOpcode op)
{
// This shouldn't be necessary, the dispatcher should catch us before we get here.
ERROR_LOG(JIT, "Comp_RunBlock should never be reached!");
}
bool Jit::ReplaceJalTo(u32 dest) {
return true;
}
void Jit::Comp_ReplacementFunc(MIPSOpcode op)
{
}
void Jit::Comp_Generic(MIPSOpcode op)
{
FlushAll();
MIPSInterpretFunc func = MIPSGetInterpretFunc(op);
if (func)
{
SaveDowncount();
QuickCallFunction(R1, (void *)func);
RestoreDowncount();
}
const MIPSInfo info = MIPSGetInfo(op);
if ((info & IS_VFPU) != 0 && (info & VFPU_NO_PREFIX) == 0)
{
// If it does eat them, it'll happen in MIPSCompileOp().
if ((info & OUT_EAT_PREFIX) == 0)
js.PrefixUnknown();
}
}
void Jit::MovFromPC(FakeReg r) {
}
void Jit::MovToPC(FakeReg r) {
}
void Jit::SaveDowncount() {
}
void Jit::RestoreDowncount() {
}
void Jit::WriteDownCount(int offset) {
}
// Abuses R2
void Jit::WriteDownCountR(FakeReg reg) {
}
void Jit::RestoreRoundingMode(bool force) {
}
void Jit::ApplyRoundingMode(bool force) {
}
void Jit::UpdateRoundingMode() {
}
void Jit::WriteExit(u32 destination, int exit_num)
{
}
void Jit::WriteExitDestInR(FakeReg Reg)
{
}
void Jit::WriteSyscallExit()
{
}
void Jit::Comp_DoNothing(MIPSOpcode op) { }
#define _RS ((op>>21) & 0x1F)
#define _RT ((op>>16) & 0x1F)
#define _RD ((op>>11) & 0x1F)
#define _FS ((op>>11) & 0x1F)
#define _FT ((op>>16) & 0x1F)
#define _FD ((op>>6) & 0x1F)
#define _POS ((op>>6) & 0x1F)
#define _SIZE ((op>>11) & 0x1F)
//memory regions:
//
// 08-0A
// 48-4A
// 04-05
// 44-45
// mov eax, addrreg
// shr eax, 28
// mov eax, [table+eax]
// mov dreg, [eax+offreg]
}

258
Core/MIPS/fake/FakeJit.h Normal file
View File

@ -0,0 +1,258 @@
// Copyright (c) 2012- PPSSPP Project.
// 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, version 2.0 or later versions.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include "Core/MIPS/JitCommon/JitState.h"
#include "Core/MIPS/JitCommon/JitBlockCache.h"
#include "../MIPSVFPUUtils.h"
#ifndef offsetof
#include "stddef.h"
#endif
namespace MIPSComp
{
struct FakeJitOptions
{
FakeJitOptions();
bool useNEONVFPU;
bool enableBlocklink;
bool downcountInRegister;
bool useBackJump;
bool useForwardJump;
bool cachePointers;
bool immBranches;
bool continueBranches;
bool continueJumps;
int continueMaxInstructions;
};
class Jit : public FakeGen::FakeXCodeBlock
{
public:
Jit(MIPSState *mips);
void DoState(PointerWrap &p);
static void DoDummyState(PointerWrap &p);
// Compiled ops should ignore delay slots
// the compiler will take care of them by itself
// OR NOT
void Comp_Generic(MIPSOpcode op);
void RunLoopUntil(u64 globalticks);
void Compile(u32 em_address); // Compiles a block at current MIPS PC
const u8 *DoJit(u32 em_address, JitBlock *b);
bool DescribeCodePtr(const u8 *ptr, std::string &name);
void CompileDelaySlot(int flags);
void EatInstruction(MIPSOpcode op);
void AddContinuedBlock(u32 dest);
void Comp_RunBlock(MIPSOpcode op);
void Comp_ReplacementFunc(MIPSOpcode op);
// Ops
void Comp_ITypeMem(MIPSOpcode op);
void Comp_Cache(MIPSOpcode op);
void Comp_RelBranch(MIPSOpcode op);
void Comp_RelBranchRI(MIPSOpcode op);
void Comp_FPUBranch(MIPSOpcode op);
void Comp_FPULS(MIPSOpcode op);
void Comp_FPUComp(MIPSOpcode op);
void Comp_Jump(MIPSOpcode op);
void Comp_JumpReg(MIPSOpcode op);
void Comp_Syscall(MIPSOpcode op);
void Comp_Break(MIPSOpcode op);
void Comp_IType(MIPSOpcode op);
void Comp_RType2(MIPSOpcode op);
void Comp_RType3(MIPSOpcode op);
void Comp_ShiftType(MIPSOpcode op);
void Comp_Allegrex(MIPSOpcode op);
void Comp_Allegrex2(MIPSOpcode op);
void Comp_VBranch(MIPSOpcode op);
void Comp_MulDivType(MIPSOpcode op);
void Comp_Special3(MIPSOpcode op);
void Comp_FPU3op(MIPSOpcode op);
void Comp_FPU2op(MIPSOpcode op);
void Comp_mxc1(MIPSOpcode op);
void Comp_DoNothing(MIPSOpcode op);
void Comp_SV(MIPSOpcode op);
void Comp_SVQ(MIPSOpcode op);
void Comp_VPFX(MIPSOpcode op);
void Comp_VVectorInit(MIPSOpcode op);
void Comp_VMatrixInit(MIPSOpcode op);
void Comp_VDot(MIPSOpcode op);
void Comp_VecDo3(MIPSOpcode op);
void Comp_VV2Op(MIPSOpcode op);
void Comp_Mftv(MIPSOpcode op);
void Comp_Vmfvc(MIPSOpcode op);
void Comp_Vmtvc(MIPSOpcode op);
void Comp_Vmmov(MIPSOpcode op);
void Comp_VScl(MIPSOpcode op);
void Comp_Vmmul(MIPSOpcode op);
void Comp_Vmscl(MIPSOpcode op);
void Comp_Vtfm(MIPSOpcode op);
void Comp_VHdp(MIPSOpcode op);
void Comp_VCrs(MIPSOpcode op);
void Comp_VDet(MIPSOpcode op);
void Comp_Vi2x(MIPSOpcode op);
void Comp_Vx2i(MIPSOpcode op);
void Comp_Vf2i(MIPSOpcode op);
void Comp_Vi2f(MIPSOpcode op);
void Comp_Vh2f(MIPSOpcode op);
void Comp_Vcst(MIPSOpcode op);
void Comp_Vhoriz(MIPSOpcode op);
void Comp_VRot(MIPSOpcode op);
void Comp_VIdt(MIPSOpcode op);
void Comp_Vcmp(MIPSOpcode op);
void Comp_Vcmov(MIPSOpcode op);
void Comp_Viim(MIPSOpcode op);
void Comp_Vfim(MIPSOpcode op);
void Comp_VCrossQuat(MIPSOpcode op);
void Comp_Vsgn(MIPSOpcode op);
void Comp_Vocp(MIPSOpcode op);
// Non-NEON: VPFX
// NEON implementations of the VFPU ops.
void CompNEON_SV(MIPSOpcode op);
void CompNEON_SVQ(MIPSOpcode op);
void CompNEON_VVectorInit(MIPSOpcode op);
void CompNEON_VMatrixInit(MIPSOpcode op);
void CompNEON_VDot(MIPSOpcode op);
void CompNEON_VecDo3(MIPSOpcode op);
void CompNEON_VV2Op(MIPSOpcode op);
void CompNEON_Mftv(MIPSOpcode op);
void CompNEON_Vmfvc(MIPSOpcode op);
void CompNEON_Vmtvc(MIPSOpcode op);
void CompNEON_Vmmov(MIPSOpcode op);
void CompNEON_VScl(MIPSOpcode op);
void CompNEON_Vmmul(MIPSOpcode op);
void CompNEON_Vmscl(MIPSOpcode op);
void CompNEON_Vtfm(MIPSOpcode op);
void CompNEON_VHdp(MIPSOpcode op);
void CompNEON_VCrs(MIPSOpcode op);
void CompNEON_VDet(MIPSOpcode op);
void CompNEON_Vi2x(MIPSOpcode op);
void CompNEON_Vx2i(MIPSOpcode op);
void CompNEON_Vf2i(MIPSOpcode op);
void CompNEON_Vi2f(MIPSOpcode op);
void CompNEON_Vh2f(MIPSOpcode op);
void CompNEON_Vcst(MIPSOpcode op);
void CompNEON_Vhoriz(MIPSOpcode op);
void CompNEON_VRot(MIPSOpcode op);
void CompNEON_VIdt(MIPSOpcode op);
void CompNEON_Vcmp(MIPSOpcode op);
void CompNEON_Vcmov(MIPSOpcode op);
void CompNEON_Viim(MIPSOpcode op);
void CompNEON_Vfim(MIPSOpcode op);
void CompNEON_VCrossQuat(MIPSOpcode op);
void CompNEON_Vsgn(MIPSOpcode op);
void CompNEON_Vocp(MIPSOpcode op);
int Replace_fabsf();
JitBlockCache *GetBlockCache() { return &blocks; }
void ClearCache();
void InvalidateCache();
void InvalidateCacheAt(u32 em_address, int length = 4);
void EatPrefix() { js.EatPrefix(); }
private:
void GenerateFixedCode();
void FlushAll();
void FlushPrefixV();
void WriteDownCount(int offset = 0);
void WriteDownCountR(FakeReg reg);
void RestoreRoundingMode(bool force = false);
void ApplyRoundingMode(bool force = false);
void UpdateRoundingMode();
void MovFromPC(FakeReg r);
void MovToPC(FakeReg r);
bool ReplaceJalTo(u32 dest);
void SaveDowncount();
void RestoreDowncount();
void WriteExit(u32 destination, int exit_num);
void WriteExitDestInR(FakeReg Reg);
void WriteSyscallExit();
// Utility compilation functions
void BranchFPFlag(MIPSOpcode op, FakeGen::CCFlags cc, bool likely);
void BranchVFPUFlag(MIPSOpcode op, FakeGen::CCFlags cc, bool likely);
void BranchRSZeroComp(MIPSOpcode op, FakeGen::CCFlags cc, bool andLink, bool likely);
void BranchRSRTComp(MIPSOpcode op, FakeGen::CCFlags cc, bool likely);
// Utilities to reduce duplicated code
void CompImmLogic(MIPSGPReg rs, MIPSGPReg rt, u32 uimm, void (FakeXEmitter::*arith)(FakeReg dst, FakeReg src, Operand2 op2), bool (FakeXEmitter::*tryArithI2R)(FakeReg dst, FakeReg src, u32 val), u32 (*eval)(u32 a, u32 b));
void CompType3(MIPSGPReg rd, MIPSGPReg rs, MIPSGPReg rt, void (FakeXEmitter::*arithOp2)(FakeReg dst, FakeReg rm, Operand2 rn), bool (FakeXEmitter::*tryArithI2R)(FakeReg dst, FakeReg rm, u32 val), u32 (*eval)(u32 a, u32 b), bool symmetric = false);
void CompShiftImm(MIPSOpcode op, FakeGen::ShiftType shiftType, int sa);
void CompShiftVar(MIPSOpcode op, FakeGen::ShiftType shiftType);
// Utils
void SetR0ToEffectiveAddress(MIPSGPReg rs, s16 offset);
void SetCCAndR0ForSafeAddress(MIPSGPReg rs, s16 offset, FakeReg tempReg, bool reverse = false);
void Comp_ITypeMemLR(MIPSOpcode op, bool load);
JitBlockCache blocks;
FakeJitOptions jo;
JitState js;
// FakeRegCache gpr;
// FakeRegCacheFPU fpr;
MIPSState *mips_;
int dontLogBlocks;
int logBlocks;
public:
// Code pointers
const u8 *enterCode;
const u8 *outerLoop;
const u8 *outerLoopPCInR0;
const u8 *dispatcherCheckCoreState;
const u8 *dispatcherPCInR0;
const u8 *dispatcher;
const u8 *dispatcherNoCheck;
const u8 *breakpointBailout;
};
typedef void (Jit::*MIPSCompileFunc)(MIPSOpcode opcode);
typedef int (Jit::*MIPSReplaceFunc)();
} // namespace MIPSComp

View File

@ -13,9 +13,13 @@ arm {
$$P/ext/disarm.cpp
HEADERS += $$P/Core/MIPS/ARM/*.h
}
else {
else:i86 {
SOURCES += $$P/Core/MIPS/x86/*.cpp
HEADERS += $$P/Core/MIPS/x86/*.h
}
else {
SOURCES += $$P/Core/MIPS/fake/*.cpp
HEADERS += $$P/Core/MIPS/fake/*.h
}
SOURCES += $$P/Core/*.cpp \ # Core

View File

@ -57,7 +57,7 @@ SOURCES += $$P/GPU/GeDisasm.cpp \ # GPU
armv7: SOURCES += $$P/GPU/Common/TextureDecoderNEON.cpp
arm: SOURCES += $$P/GPU/Common/VertexDecoderArm.cpp
else: SOURCES += $$P/GPU/Common/VertexDecoderX86.cpp
i86: SOURCES += $$P/GPU/Common/VertexDecoderX86.cpp
HEADERS += $$P/GPU/GLES/*.h \
$$P/GPU/Software/*.h \