16 changed files with 52 additions and 666 deletions
-
18src/common/CMakeLists.txt
-
2src/common/common_funcs.h
-
2src/common/cpu_detect.cpp
-
19src/common/cpu_detect_generic.cpp
-
465src/common/fake_emitter.h
-
2src/common/platform.h
-
6src/common/x64/abi.cpp
-
4src/common/x64/abi.h
-
16src/common/x64/emitter.cpp
-
8src/common/x64/emitter.h
-
10src/video_core/CMakeLists.txt
-
9src/video_core/shader/shader.cpp
-
36src/video_core/shader/shader_jit.cpp
-
91src/video_core/shader/shader_jit_fake.cpp
-
20src/video_core/shader/shader_jit_x64.cpp
-
10src/video_core/shader/shader_jit_x64.h
@ -1,19 +0,0 @@ |
|||
// Copyright 2014 Dolphin Emulator Project
|
|||
// Licensed under GPLv2+
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include "cpu_detect.h"
|
|||
#include "hash.h"
|
|||
|
|||
namespace Common { |
|||
|
|||
CPUInfo cpu_info; |
|||
|
|||
CPUInfo::CPUInfo() { |
|||
} |
|||
|
|||
std::string CPUInfo::Summarize() { |
|||
return "Generic"; |
|||
} |
|||
|
|||
} // namespace Common
|
|||
@ -1,465 +0,0 @@ |
|||
// 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!!! |
|||
|
|||
#pragma once |
|||
|
|||
#include <vector> |
|||
#include <stdint.h> |
|||
|
|||
#include "assert.h" |
|||
#include "common_types.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(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(shift < 32, "Invalid Operand2: LSL %u", shift); |
|||
break; |
|||
case ST_LSR: |
|||
ASSERT_MSG(shift <= 32, "Invalid Operand2: LSR %u", shift); |
|||
if (!shift) |
|||
type = ST_LSL; |
|||
if (shift == 32) |
|||
shift = 0; |
|||
break; |
|||
case ST_ASR: |
|||
ASSERT_MSG(shift < 32, "Invalid Operand2: ASR %u", shift); |
|||
if (!shift) |
|||
type = ST_LSL; |
|||
if (shift == 32) |
|||
shift = 0; |
|||
break; |
|||
case ST_ROR: |
|||
ASSERT_MSG(shift < 32, "Invalid Operand2: ROR %u", shift); |
|||
if (!shift) |
|||
type = ST_LSL; |
|||
break; |
|||
case ST_RRX: |
|||
ASSERT_MSG(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(false, "GetData with Invalid Type"); |
|||
return 0; |
|||
} |
|||
} |
|||
u32 IMMSR() // IMM shifted register |
|||
{ |
|||
ASSERT_MSG(Type == TYPE_IMMSREG, "IMMSR must be imm shifted register"); |
|||
return ((IndexOrShift & 0x1f) << 7 | (Shift << 5) | Value); |
|||
} |
|||
u32 RSR() // Register shifted register |
|||
{ |
|||
ASSERT_MSG(Type == TYPE_RSR, "RSR must be RSR Of Course"); |
|||
return (IndexOrShift << 8) | (Shift << 5) | 0x10 | Value; |
|||
} |
|||
u32 Rm() |
|||
{ |
|||
ASSERT_MSG(Type == TYPE_REG, "Rm must be with Reg"); |
|||
return Value; |
|||
} |
|||
|
|||
u32 Imm5() |
|||
{ |
|||
ASSERT_MSG((Type == TYPE_IMM), "Imm5 not IMM value"); |
|||
return ((Value & 0x0000001F) << 7); |
|||
} |
|||
u32 Imm8() |
|||
{ |
|||
ASSERT_MSG((Type == TYPE_IMM), "Imm8Rot not IMM value"); |
|||
return Value & 0xFF; |
|||
} |
|||
u32 Imm8Rot() // IMM8 with Rotation |
|||
{ |
|||
ASSERT_MSG((Type == TYPE_IMM), "Imm8Rot not IMM value"); |
|||
ASSERT_MSG((Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation); |
|||
return (1 << 25) | (Rotation << 7) | (Value & 0x000000FF); |
|||
} |
|||
u32 Imm12() |
|||
{ |
|||
ASSERT_MSG((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((Type == TYPE_IMM), "Imm12Mod not IMM"); |
|||
return ((Rotation & 0xF) << 8) | (Value & 0xFF); |
|||
} |
|||
u32 Imm16() |
|||
{ |
|||
ASSERT_MSG((Type == TYPE_IMM), "Imm16 not IMM"); |
|||
return ( (Value & 0xF000) << 4) | (Value & 0x0FFF); |
|||
} |
|||
u32 Imm16Low() |
|||
{ |
|||
return Imm16(); |
|||
} |
|||
u32 Imm16High() // Returns high 16bits |
|||
{ |
|||
ASSERT_MSG((Type == TYPE_IMM), "Imm16 not IMM"); |
|||
return ( ((Value >> 16) & 0xF000) << 4) | ((Value >> 16) & 0x0FFF); |
|||
} |
|||
u32 Imm24() |
|||
{ |
|||
ASSERT_MSG((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 |
|||
}; |
|||
|
|||
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 |
|||
@ -1,36 +0,0 @@ |
|||
// Copyright 2015 Citra Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include "video_core/pica.h"
|
|||
|
|||
#include "shader.h"
|
|||
#include "shader_jit.h"
|
|||
|
|||
namespace Pica { |
|||
|
|||
namespace Shader { |
|||
|
|||
JitShader::JitShader() : jitted(nullptr) { |
|||
} |
|||
|
|||
void JitShader::DoJit(JitCompiler& jit) { |
|||
jitted = jit.Compile(); |
|||
} |
|||
|
|||
void JitShader::Run(UnitState& state) { |
|||
if (jitted) |
|||
jitted(&state); |
|||
} |
|||
|
|||
JitCompiler::JitCompiler() { |
|||
AllocCodeSpace(1024 * 1024 * 4); |
|||
} |
|||
|
|||
void JitCompiler::Clear() { |
|||
ClearCodeSpace(); |
|||
} |
|||
|
|||
} // namespace Shader
|
|||
|
|||
} // namespace Pica
|
|||
@ -1,91 +0,0 @@ |
|||
// Copyright 2015 Citra Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include "common/fake_emitter.h"
|
|||
|
|||
#include "video_core/shader/shader.h"
|
|||
#include "video_core/shader/shader_jit.h"
|
|||
|
|||
namespace Pica { |
|||
|
|||
namespace Shader { |
|||
|
|||
using namespace FakeGen; |
|||
|
|||
void Jit::Comp_ADD(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_DP3(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_DP4(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_MUL(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_FLR(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_MAX(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_MIN(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_MOVA(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_MOV(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_SLTI(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_RCP(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_RSQ(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_NOP(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_END(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_CALL(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_CALLC(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_CALLU(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_CMP(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_MAD(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_IF(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_LOOP(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_JMP(Instruction instr) { |
|||
} |
|||
|
|||
void Jit::Comp_NextInstr(unsigned* offset) { |
|||
} |
|||
|
|||
CompiledShader Jit::Compile() { |
|||
return nullptr; |
|||
} |
|||
|
|||
} // namespace Shader
|
|||
|
|||
} // namespace Pica
|
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue