mirror of
https://github.com/libretro/ppsspp.git
synced 2024-11-27 18:30:56 +00:00
ppc emitter
This commit is contained in:
parent
c24c5c88d9
commit
cc0a8d1321
0
Common/ppcAbi.cpp
Normal file
0
Common/ppcAbi.cpp
Normal file
426
Common/ppcEmitter.cpp
Normal file
426
Common/ppcEmitter.cpp
Normal file
@ -0,0 +1,426 @@
|
||||
#include <xtl.h>
|
||||
#include "ppcEmitter.h"
|
||||
|
||||
namespace PpcGen {
|
||||
|
||||
// Arithmetics ops
|
||||
void PPCXEmitter::ADD (PPCReg Rd, PPCReg Ra, PPCReg Rb) {
|
||||
u32 instr = (0x7C000214 | (Rd << 21) | (Ra << 16) | (Rb << 11));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::ADDI (PPCReg Rd, PPCReg Ra, unsigned short imm) {
|
||||
u32 instr = (0x38000000 | (Rd << 21) | (Ra << 16) | ((imm) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::ADDIS (PPCReg Rd, PPCReg Ra, unsigned short imm) {
|
||||
u32 instr = (0x3C000000 | (Rd << 21) | (Ra << 16) | ((imm) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::AND (PPCReg Rs, PPCReg Ra, PPCReg Rb) {
|
||||
u32 instr = (0x7C000038 | (Ra << 21) | (Rs << 16) | (Rb << 11));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::ANDI (PPCReg Rd, PPCReg Ra, unsigned short imm) {
|
||||
u32 instr = (0x70000000 | (Rd << 21) | (Ra << 16) | ((imm) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::ANDIS (PPCReg Rd, PPCReg Ra, unsigned short imm) {
|
||||
u32 instr = (0x74000000 | (Rd << 21) | (Ra << 16) | ((imm) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
// Memory load/store operations
|
||||
void PPCXEmitter::LI(PPCReg dest, unsigned short imm) {
|
||||
u32 instr = (0x38000000 | (dest << 21) | ((imm) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::LIS(PPCReg dest, unsigned short imm) {
|
||||
u32 instr = (0x3C000000 | (dest << 21) | ((imm) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::LBZ (PPCReg dest, PPCReg src, int offset) {
|
||||
u32 instr = (0x88000000 | (dest << 21) | (src << 16) | ((offset) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::LHZ (PPCReg dest, PPCReg src, int offset) {
|
||||
u32 instr = (0xA0000000 | (dest << 21) | (src << 16) | ((offset) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::LHBRX (PPCReg dest, PPCReg src, PPCReg offset) {
|
||||
u32 instr = (0x7C00062C | (dest << 21) | (src << 16) | (offset << 11));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::LWZ (PPCReg dest, PPCReg src, int offset) {
|
||||
u32 instr = (0x80000000 | (dest << 21) | (src << 16) | ((offset) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::LWBRX (PPCReg dest, PPCReg src, PPCReg offset) {
|
||||
u32 instr = (0x7C00042C | (dest << 21) | (src << 16) | (offset << 11));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::STB (PPCReg dest, PPCReg src, int offset) {
|
||||
u32 instr = (0x98000000 | (dest << 21) | (src << 16) | ((offset) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::STH (PPCReg dest, PPCReg src, int offset) {
|
||||
u32 instr = (0xB0000000 | (dest << 21) | (src << 16) | ((offset) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::STHBRX (PPCReg dest, PPCReg src, PPCReg offset) {
|
||||
u32 instr = (0x7C00072C | (dest << 21) | (src << 16) | (offset << 11));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::STW (PPCReg dest, PPCReg src, int offset) {
|
||||
u32 instr = (0x90000000 | (dest << 21) | (src << 16) | ((offset) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::STWU (PPCReg dest, PPCReg src, int offset) {
|
||||
u32 instr = (0x94000000 | (dest << 21) | (src << 16) | ((offset) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::STWBRX (PPCReg dest, PPCReg src, PPCReg offset) {
|
||||
u32 instr = (0x7C00052C | (dest << 21) | (src << 16) | (offset << 11));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
// use lwz ... can't find good opcode :s
|
||||
void PPCXEmitter::LD (PPCReg dest, PPCReg src, int offset) {
|
||||
u32 instr = ((58 << 26) | (dest << 21) | (src << 16) | ((offset) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
// use stw ... can't find good opcode :s
|
||||
void PPCXEmitter::STD (PPCReg dest, PPCReg src, int offset) {
|
||||
u32 instr = ((62 << 26) | (dest << 21) | (src << 16) | ((offset) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
// Branch operations
|
||||
void PPCXEmitter::B (const void *fnptr) {
|
||||
s32 func = (s32)fnptr - s32(code);
|
||||
u32 instr = (0x48000000 | ((s32)((func) & 0x3fffffc)));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::BL(const void *fnptr) {
|
||||
s32 func = (s32)fnptr - s32(code);
|
||||
u32 instr = (0x48000001 | ((s32)((func) & 0x3fffffc)));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::BA (const void *fnptr) {
|
||||
s32 func = (s32)fnptr - s32(code);
|
||||
u32 instr = (0x48000002 | ((s32)((func) & 0x3fffffc)));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::BLA (const void *fnptr) {
|
||||
s32 func = (s32)fnptr - s32(code);
|
||||
u32 instr = (0x48000003 | ((s32)((func) & 0x3fffffc)));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::BEQ (const void *fnptr) {
|
||||
s32 func = (s32)fnptr - s32(code);
|
||||
u32 instr = (0x41820000 | ( func & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
|
||||
void PPCXEmitter::BGT(const void *fnptr) {
|
||||
s32 func = (s32)fnptr - s32(code);
|
||||
u32 instr = (0x41810000 | (((s16)(((func)+1))) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::BLT (const void *fnptr) {
|
||||
s32 func = (s32)fnptr - s32(code);
|
||||
u32 instr = (0x41800000 | (((s16)(((func)+1))) & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
void PPCXEmitter::BEQ (PPCReg r) {
|
||||
//s32 func = (s32)(fnptr);
|
||||
//u32 instr = (0x48000003 | ((s32)((func) & 0x3fffffc)));
|
||||
//Write32(instr);
|
||||
DebugBreak();
|
||||
}
|
||||
|
||||
void PPCXEmitter::BCTRL() {
|
||||
Write32(0x4E800421);
|
||||
}
|
||||
|
||||
void PPCXEmitter::BCTR() {
|
||||
Write32(0x4E800420);
|
||||
}
|
||||
|
||||
// Link Register
|
||||
void PPCXEmitter::MFLR(PPCReg r) {
|
||||
Write32(0x7C0802A6 | r << 21);
|
||||
}
|
||||
|
||||
void PPCXEmitter::MTLR(PPCReg r) {
|
||||
Write32(0x7C0803A6 | r << 21);
|
||||
}
|
||||
|
||||
void PPCXEmitter::MTCTR(PPCReg r) {
|
||||
Write32(0x7C0903A6 | r << 21);
|
||||
}
|
||||
|
||||
void PPCXEmitter::BLR() {
|
||||
Write32(0x4E800020);
|
||||
}
|
||||
|
||||
void PPCXEmitter::BGTLR() {
|
||||
Write32(0x4D810020);
|
||||
}
|
||||
|
||||
// Fixup
|
||||
FixupBranch PPCXEmitter::B()
|
||||
{
|
||||
FixupBranch branch;
|
||||
branch.type = _B;
|
||||
branch.ptr = code;
|
||||
branch.condition = condition;
|
||||
//We'll write NOP here for now.
|
||||
Write32(0x60000000);
|
||||
return branch;
|
||||
}
|
||||
|
||||
FixupBranch PPCXEmitter::BL()
|
||||
{
|
||||
FixupBranch branch;
|
||||
branch.type = _BL;
|
||||
branch.ptr = code;
|
||||
branch.condition = condition;
|
||||
//We'll write NOP here for now.
|
||||
Write32(0x60000000);
|
||||
return branch;
|
||||
}
|
||||
|
||||
|
||||
FixupBranch PPCXEmitter::BNE() {
|
||||
FixupBranch branch;
|
||||
branch.type = _BNE;
|
||||
branch.ptr = code;
|
||||
branch.condition = condition;
|
||||
//We'll write NOP here for now.
|
||||
Write32(0x60000000);
|
||||
return branch;
|
||||
}
|
||||
|
||||
FixupBranch PPCXEmitter::BLT() {
|
||||
FixupBranch branch;
|
||||
branch.type = _BLT;
|
||||
branch.ptr = code;
|
||||
branch.condition = condition;
|
||||
//We'll write NOP here for now.
|
||||
Write32(0x60000000);
|
||||
return branch;
|
||||
}
|
||||
|
||||
FixupBranch PPCXEmitter::B_Cond(FixupBranchType type) {
|
||||
FixupBranch branch;
|
||||
branch.type = type;
|
||||
branch.ptr = code;
|
||||
branch.condition = condition;
|
||||
//We'll write NOP here for now.
|
||||
Write32(0x60000000);
|
||||
return branch;
|
||||
}
|
||||
|
||||
void PPCXEmitter::SetJumpTarget(FixupBranch const &branch)
|
||||
{
|
||||
s32 distance = s32(code) - (s32)branch.ptr;
|
||||
_assert_msg_(DYNA_REC, distance > -33554432
|
||||
&& distance <= 33554432,
|
||||
"SetJumpTarget out of range (%p calls %p)", code,
|
||||
branch.ptr);
|
||||
|
||||
switch(branch.type) {
|
||||
case _B:
|
||||
*(u32*)branch.ptr = (0x48000000 | ((s32)((distance) & 0x3fffffc)));
|
||||
break;
|
||||
case _BL:
|
||||
*(u32*)branch.ptr = (0x48000001 | ((s32)((distance) & 0x3fffffc)));
|
||||
break;
|
||||
case _BEQ:
|
||||
*(u32*)branch.ptr = (0x41820000 | ((s16)(((distance)+1)) & 0xfffc));
|
||||
break;
|
||||
case _BNE:
|
||||
*(u32*)branch.ptr = (0x40820000 | ((s16)(((distance)+1)) & 0xfffc));
|
||||
break;
|
||||
case _BLT:
|
||||
*(u32*)branch.ptr = (0x41800000 | ((s16)(((distance)+1)) & 0xfffc));
|
||||
break;
|
||||
case _BLE:
|
||||
*(u32*)branch.ptr = (0x40810000 | ((s16)(((distance)+1)) & 0xfffc));
|
||||
break;
|
||||
case _BGT:
|
||||
*(u32*)branch.ptr = (0x41810000 | ((s16)(((distance)+1)) & 0xfffc));
|
||||
break;
|
||||
case _BGE:
|
||||
*(u32*)branch.ptr = (0x40800000 | ((s16)(((distance)+1)) & 0xfffc));
|
||||
break;
|
||||
default:
|
||||
// Error !!!
|
||||
_assert_msg_(DYNA_REC, 0, "SetJumpTarget unknow branch type: %d", branch.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Compare
|
||||
void PPCXEmitter::CMPLWI(PPCReg dest, unsigned short imm) {
|
||||
Write32((0x28000000 | (dest << 16) | ((imm) & 0xffff)));
|
||||
}
|
||||
|
||||
void PPCXEmitter::CMPLI(PPCReg dest, unsigned short imm) {
|
||||
Write32((0x2C000000 | (dest << 16) | ((imm) & 0xffff)));
|
||||
}
|
||||
|
||||
void PPCXEmitter::CMP(PPCReg a, PPCReg b) {
|
||||
Write32((31 << 26) | (a << 16) | (b << 11));
|
||||
}
|
||||
|
||||
// Others operation
|
||||
void PPCXEmitter::ORI(PPCReg src, PPCReg dest, unsigned short imm) {
|
||||
if (!((imm == 0) && ((src^dest) == 0))) {
|
||||
u32 instr = (0x60000000 | (src << 21) | (dest << 16) | (imm & 0xffff));
|
||||
Write32(instr);
|
||||
}
|
||||
}
|
||||
|
||||
void PPCXEmitter::OR(PPCReg Rd, PPCReg Ra, PPCReg Rb) {
|
||||
u32 instr = (0x7C000378 | (Ra << 21) | (Rd << 16) | (Rb << 11));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
|
||||
void PPCXEmitter::SUBF(PPCReg Rd, PPCReg Ra, PPCReg Rb) {
|
||||
u32 instr = (0x7C000050 | (Rd << 21) | (Ra << 16) | (Rb << 11));
|
||||
Write32(instr);
|
||||
}
|
||||
|
||||
// Quick Call
|
||||
// dest = LIS(imm) + ORI(+imm)
|
||||
void PPCXEmitter::MOVI2R(PPCReg dest, unsigned int imm) {
|
||||
/*
|
||||
if (imm == (unsigned short)imm) {
|
||||
// 16bit
|
||||
LI(dest, imm & 0xFFFF);
|
||||
ANDIS(dest, dest, 0);
|
||||
} else
|
||||
*/
|
||||
{
|
||||
// HI 16bit
|
||||
LIS(dest, imm>>16);
|
||||
if ((imm & 0xFFFF) != 0) {
|
||||
// LO 16bit
|
||||
ORI(dest, dest, imm & 0xFFFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PPCXEmitter::QuickCallFunction(void *func) {
|
||||
/*
|
||||
// Must check if we need to use bctrl or simple branch
|
||||
u32 func_addr = (u32) func;
|
||||
u32 code_addr = (u32) code;
|
||||
if (func_addr - code_addr > 0x1fffffc) {
|
||||
// Load func address
|
||||
MOVI2R(R0, func_addr);
|
||||
// Set it to link register
|
||||
MTCTR(R0);
|
||||
// Branch
|
||||
BCTRL();
|
||||
} else {
|
||||
// Direct branch
|
||||
BL(func);
|
||||
}
|
||||
*/
|
||||
u32 func_addr = (u32) func;
|
||||
// Load func address
|
||||
MOVI2R(R0, func_addr);
|
||||
// Set it to link register
|
||||
MTCTR(R0);
|
||||
// Branch
|
||||
BCTRL();
|
||||
}
|
||||
|
||||
// Others ...
|
||||
|
||||
void PPCXEmitter::SetCodePtr(u8 *ptr)
|
||||
{
|
||||
code = ptr;
|
||||
startcode = code;
|
||||
lastCacheFlushEnd = ptr;
|
||||
}
|
||||
|
||||
const u8 *PPCXEmitter::GetCodePtr() const
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
u8 *PPCXEmitter::GetWritableCodePtr()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
void PPCXEmitter::ReserveCodeSpace(u32 bytes)
|
||||
{
|
||||
/*
|
||||
for (u32 i = 0; i < bytes/4; i++)
|
||||
Write32(0xE1200070); //bkpt 0
|
||||
*/
|
||||
for (u32 i = 0; i < bytes/4; i++)
|
||||
Write32(0x60000000); //nop
|
||||
}
|
||||
|
||||
const u8 *PPCXEmitter::AlignCode16()
|
||||
{
|
||||
ReserveCodeSpace((-(s32)code) & 15);
|
||||
return code;
|
||||
}
|
||||
|
||||
const u8 *PPCXEmitter::AlignCodePage()
|
||||
{
|
||||
ReserveCodeSpace((-(s32)code) & 4095);
|
||||
return code;
|
||||
}
|
||||
|
||||
void PPCXEmitter::FlushIcache()
|
||||
{
|
||||
FlushIcacheSection(lastCacheFlushEnd, code);
|
||||
lastCacheFlushEnd = code;
|
||||
}
|
||||
|
||||
void PPCXEmitter::FlushIcacheSection(u8 *start, u8 *end)
|
||||
{
|
||||
u8 * addr = start;
|
||||
while(addr < end) {
|
||||
__asm dcbst r0, addr
|
||||
__asm icbi r0, addr
|
||||
addr += 4;
|
||||
}
|
||||
__emit(0x7c0004ac);//sync
|
||||
__emit(0x4C00012C);//isync
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
358
Common/ppcEmitter.h
Normal file
358
Common/ppcEmitter.h
Normal file
@ -0,0 +1,358 @@
|
||||
// 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!!!
|
||||
|
||||
|
||||
// http://www.csd.uwo.ca/~mburrel/stuff/ppc-asm.html
|
||||
// http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.aixassem/doc/alangref/linkage_convent.htm
|
||||
// http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.aixassem/doc/alangref/instruction_set.htm
|
||||
|
||||
#ifndef _DOLPHIN_PPC_CODEGEN_
|
||||
#define _DOLPHIN_PPC_CODEGEN_
|
||||
|
||||
#include "Common.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include <vector>
|
||||
|
||||
#undef _IP
|
||||
#undef R0
|
||||
#undef _SP
|
||||
#undef _LR
|
||||
#undef _PC
|
||||
#undef CALL
|
||||
|
||||
namespace PpcGen
|
||||
{
|
||||
enum PPCReg
|
||||
{
|
||||
// GPRs (32)
|
||||
// Behaves as zero does in some instructions
|
||||
R0 = 0,
|
||||
// Stack pointer (SP)
|
||||
R1,
|
||||
// Reserved
|
||||
R2,
|
||||
// Used to pass integer function parameters and return values
|
||||
R3, R4,
|
||||
// Used to pass integer function parameters
|
||||
R5, R6, R7, R8, R9, R10,
|
||||
// General purpose
|
||||
R11,
|
||||
// Scratch
|
||||
R12,
|
||||
// Unused by the compiler reserved
|
||||
R13,
|
||||
// General purpose
|
||||
R14, R15, R16, R17, R18, R19,
|
||||
R20, R21, R22, R23, R24, R25,
|
||||
R26, R27, R28, R29, R30, R31,
|
||||
|
||||
// CRs (7)
|
||||
CR0 = 0,
|
||||
|
||||
// FPRs (32)
|
||||
// Scratch
|
||||
FPR0,
|
||||
// Used to pass double word function parameters and return values
|
||||
FPR1, FPR2, FPR3, FPR4,
|
||||
FPR5, FPR6, FPR7, FPR8,
|
||||
FPR9, FPR10, FPR11, FPR12,
|
||||
FPR13,
|
||||
// General purpose
|
||||
FPR14, FPR15, FPR16, FPR17,
|
||||
FPR18, FPR19, FPR20, FPR21,
|
||||
FPR22, FPR23, FPR24, FPR25,
|
||||
FPR26, FPR27, FPR28, FPR29,
|
||||
FPR30, FPR31,
|
||||
|
||||
|
||||
// Vmx (128)
|
||||
VR0,
|
||||
// Used to pass vector function parameters and return values
|
||||
VR1, VR2, VR3, VR4,
|
||||
VR5, VR6, VR7, VR8,
|
||||
VR9, VR10, VR11, VR12,
|
||||
VR13, // ...
|
||||
|
||||
// Others regs
|
||||
LR, CTR, XER, FPSCR,
|
||||
|
||||
// End
|
||||
|
||||
INVALID_REG = 0xFFFFFFFF
|
||||
};
|
||||
enum IntegerSize
|
||||
{
|
||||
I_I8 = 0,
|
||||
I_I16,
|
||||
I_I32,
|
||||
I_I64
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
NUMGPRs = 31,
|
||||
};
|
||||
|
||||
typedef const u8* JumpTarget;
|
||||
|
||||
|
||||
enum FixupBranchType {
|
||||
_B,
|
||||
_BEQ,
|
||||
_BNE,
|
||||
_BLT,
|
||||
_BLE,
|
||||
_BGT,
|
||||
_BGE,
|
||||
// Link register
|
||||
_BL
|
||||
};
|
||||
|
||||
struct FixupBranch
|
||||
{
|
||||
u8 *ptr;
|
||||
u32 condition; // Remembers our codition at the time
|
||||
FixupBranchType type; //0 = B 1 = BL
|
||||
};
|
||||
|
||||
class PPCXEmitter
|
||||
{
|
||||
private:
|
||||
u8 *code, *startcode;
|
||||
u8 *lastCacheFlushEnd;
|
||||
u32 condition;
|
||||
|
||||
protected:
|
||||
// Weite opcode
|
||||
inline void Write32(u32 value) {*(u32*)code = value; code+=4;}
|
||||
|
||||
public:
|
||||
PPCXEmitter() : code(0), startcode(0), lastCacheFlushEnd(0) {
|
||||
}
|
||||
PPCXEmitter(u8 *code_ptr) {
|
||||
code = code_ptr;
|
||||
lastCacheFlushEnd = code_ptr;
|
||||
startcode = code_ptr;
|
||||
}
|
||||
virtual ~PPCXEmitter() {}
|
||||
|
||||
void SetCodePtr(u8 *ptr);
|
||||
void ReserveCodeSpace(u32 bytes);
|
||||
const u8 *AlignCode16();
|
||||
const u8 *AlignCodePage();
|
||||
const u8 *GetCodePtr() const;
|
||||
void FlushIcache();
|
||||
void FlushIcacheSection(u8 *start, u8 *end);
|
||||
u8 *GetWritableCodePtr();
|
||||
|
||||
|
||||
// Special purpose instructions
|
||||
|
||||
// Debug Breakpoint
|
||||
void BKPT(u16 arg);
|
||||
|
||||
// Hint instruction
|
||||
void YIELD();
|
||||
|
||||
// Do nothing
|
||||
void NOP(int count = 1); //nop padding - TODO: fast nop slides, for amd and intel (check their manuals)
|
||||
|
||||
// FixupBranch ops
|
||||
FixupBranch B();
|
||||
FixupBranch BL();
|
||||
FixupBranch BNE();
|
||||
FixupBranch BLT();
|
||||
|
||||
FixupBranch B_Cond(FixupBranchType type);
|
||||
|
||||
void SetJumpTarget(FixupBranch const &branch);
|
||||
|
||||
// Branch ops
|
||||
void B (const void *fnptr);
|
||||
void BL(const void *fnptr);
|
||||
void BA (const void *fnptr);
|
||||
void BLA(const void *fnptr);
|
||||
void BEQ(const void *fnptr);
|
||||
void BLT(const void *fnptr);
|
||||
void BGT(const void *fnptr);
|
||||
void BEQ (PPCReg r);
|
||||
|
||||
void BCTRL ();
|
||||
void BCTR();
|
||||
|
||||
// Link Register
|
||||
void MFLR(PPCReg r);
|
||||
void MTLR(PPCReg r);
|
||||
void MTCTR(PPCReg r);
|
||||
void BLR();
|
||||
void BGTLR();
|
||||
|
||||
|
||||
// Logical Ops
|
||||
void AND (PPCReg Rs, PPCReg Ra, PPCReg Rb);
|
||||
void ANDI (PPCReg Rs, PPCReg Ra, unsigned short imm);
|
||||
void ANDIS(PPCReg Rs, PPCReg Ra, unsigned short imm);
|
||||
void NAND (PPCReg Rs, PPCReg Ra, PPCReg Rb);
|
||||
void OR (PPCReg Rs, PPCReg Ra, PPCReg Rb);
|
||||
void ORC (PPCReg Rs, PPCReg Ra, PPCReg Rb);
|
||||
void NOR (PPCReg Rs, PPCReg Ra, PPCReg Rb);
|
||||
void XOR (PPCReg Rs, PPCReg Ra, PPCReg Rb);
|
||||
void NEG (PPCReg Rs, PPCReg Ra, PPCReg Rb);
|
||||
|
||||
// Arithmetics ops
|
||||
void ADD (PPCReg Rd, PPCReg Ra, PPCReg Rb);
|
||||
void ADDI (PPCReg Rd, PPCReg Ra, unsigned short imm);
|
||||
void ADDIS (PPCReg Rd, PPCReg Ra, unsigned short imm);
|
||||
void ADDC (PPCReg Rd, PPCReg Ra, PPCReg Rb);
|
||||
void SUBF (PPCReg Rd, PPCReg Ra, PPCReg Rb);
|
||||
void SUBFC (PPCReg Rd, PPCReg Ra, PPCReg Rb);
|
||||
|
||||
// Floating ops
|
||||
void DIVW(PPCReg dest, PPCReg dividend, PPCReg divisor);
|
||||
void DIVWU(PPCReg dest, PPCReg dividend, PPCReg divisor);
|
||||
void MULLW(PPCReg dest, PPCReg src, PPCReg op2);
|
||||
void MULHW (PPCReg dest, PPCReg src, PPCReg op2);
|
||||
void MULHWS(PPCReg dest, PPCReg src, PPCReg op2);
|
||||
|
||||
void ORI (PPCReg src, PPCReg dest, unsigned short imm);
|
||||
|
||||
// Memory load/store operations
|
||||
void LI (PPCReg dest, unsigned short imm);
|
||||
void LIS (PPCReg dest, unsigned short imm);
|
||||
// dest = LIS(imm) + ORI(+imm)
|
||||
void MOVI2R (PPCReg dest, unsigned int imm);
|
||||
|
||||
// 8bit
|
||||
void LBZ (PPCReg dest, PPCReg src, int offset = 0);
|
||||
// 16bit
|
||||
void LHZ (PPCReg dest, PPCReg src, int offset = 0);
|
||||
void LHBRX (PPCReg dest, PPCReg src, PPCReg offset);
|
||||
// 32 bit
|
||||
void LWZ (PPCReg dest, PPCReg src, int offset = 0);
|
||||
void LWBRX (PPCReg dest, PPCReg src, PPCReg offset);
|
||||
// 64 bit
|
||||
void LD (PPCReg dest, PPCReg src, int offset = 0);
|
||||
|
||||
// 8 bit
|
||||
void STB (PPCReg dest, PPCReg src, int offset = 0);
|
||||
// 16 bit
|
||||
void STH (PPCReg dest, PPCReg src, int offset = 0);
|
||||
void STHBRX (PPCReg dest, PPCReg src, PPCReg offset);
|
||||
// 32 bit
|
||||
void STW (PPCReg dest, PPCReg src, int offset = 0);
|
||||
void STWU (PPCReg dest, PPCReg src, int offset = 0);
|
||||
void STWBRX (PPCReg dest, PPCReg src, PPCReg offset);
|
||||
// 64 bit
|
||||
void STD (PPCReg dest, PPCReg src, int offset = 0);
|
||||
|
||||
// Compare
|
||||
void CMPLWI (PPCReg dest, unsigned short imm);
|
||||
void CMPLI (PPCReg dest, unsigned short imm);
|
||||
void CMP (PPCReg a, PPCReg b);
|
||||
|
||||
// Debug !
|
||||
void Break() {
|
||||
Write32(0x0FE00016);
|
||||
}
|
||||
|
||||
void MR (PPCReg to, PPCReg from) {
|
||||
OR(to, from, from);
|
||||
}
|
||||
|
||||
void QuickCallFunction(void *func);
|
||||
protected:
|
||||
|
||||
}; // class PPCXEmitter
|
||||
|
||||
|
||||
// Everything that needs to generate X86 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 PPCXCodeBlock : public PPCXEmitter
|
||||
{
|
||||
protected:
|
||||
u8 *region;
|
||||
size_t region_size;
|
||||
|
||||
public:
|
||||
PPCXCodeBlock() : region(NULL), region_size(0) {}
|
||||
virtual ~PPCXCodeBlock() { if (region) FreeCodeSpace(); }
|
||||
|
||||
// Call this before you generate any code.
|
||||
void AllocCodeSpace(int size)
|
||||
{
|
||||
region_size = size;
|
||||
region = (u8*)AllocateExecutableMemory(region_size);
|
||||
SetCodePtr(region);
|
||||
}
|
||||
|
||||
// Always clear code space with breakpoints, so that if someone accidentally executes
|
||||
// uninitialized, it just breaks into the debugger.
|
||||
void ClearCodeSpace()
|
||||
{
|
||||
// x86/64: 0xCC = breakpoint
|
||||
memset(region, 0xCC, region_size);
|
||||
ResetCodePtr();
|
||||
}
|
||||
|
||||
// Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
|
||||
void FreeCodeSpace()
|
||||
{
|
||||
region = NULL;
|
||||
region_size = 0;
|
||||
}
|
||||
|
||||
bool IsInSpace(u8 *ptr)
|
||||
{
|
||||
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()
|
||||
{
|
||||
//WriteProtectMemory(region, region_size, true);
|
||||
}
|
||||
void UnWriteProtect()
|
||||
{
|
||||
//UnWriteProtectMemory(region, region_size, false);
|
||||
}
|
||||
|
||||
void ResetCodePtr()
|
||||
{
|
||||
SetCodePtr(region);
|
||||
}
|
||||
|
||||
size_t GetSpaceLeft() const
|
||||
{
|
||||
return region_size - (GetCodePtr() - region);
|
||||
}
|
||||
|
||||
u8 *GetBasePtr() {
|
||||
return region;
|
||||
}
|
||||
|
||||
size_t GetOffset(u8 *ptr) {
|
||||
return ptr - region;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // _DOLPHIN_INTEL_CODEGEN_
|
Loading…
Reference in New Issue
Block a user