Merge Ryan's latest ARM emitter work from Dolphin

This commit is contained in:
Henrik Rydgard 2012-11-02 11:58:56 +01:00
parent 16f5a874a3
commit 5878f28fca
10 changed files with 512 additions and 271 deletions

View File

@ -20,13 +20,32 @@
#include "ArmABI.h"
using namespace ArmGen;
// Shared code between Win32 and Unix32
// If passing arguments, don't use this.
void ARMXEmitter::ARMABI_CallFunction(void *func)
{
ARMABI_MOVIMM32(R8, (u32)func);
PUSH(1, _LR);
BLX(R8);
POP(1, _LR);
ARMABI_MOVI2R(R14, Mem(func));
PUSH(5, R0, R1, R2, R3, _LR);
BL(R14);
POP(5, R0, R1, R2, R3, _LR);
}
void ARMXEmitter::ARMABI_CallFunctionC(void *func, u32 Arg)
{
ARMABI_MOVI2R(R14, Mem(func));
PUSH(5, R0, R1, R2, R3, _LR);
ARMABI_MOVI2R(R0, Arg);
BL(R14);
POP(5, R0, R1, R2, R3, _LR);
}
void ARMXEmitter::ARMABI_CallFunctionCC(void *func, u32 Arg1, u32 Arg2)
{
ARMABI_MOVI2R(R14, Mem(func));
PUSH(5, R0, R1, R2, R3, _LR);
ARMABI_MOVI2R(R0, Arg1);
ARMABI_MOVI2R(R1, Arg2);
BL(R14);
POP(5, R0, R1, R2, R3, _LR);
}
void ARMXEmitter::ARMABI_PushAllCalleeSavedRegsAndAdjustStack() {
// Note: 4 * 4 = 16 bytes, so alignment is preserved.
@ -34,29 +53,44 @@ void ARMXEmitter::ARMABI_PushAllCalleeSavedRegsAndAdjustStack() {
}
void ARMXEmitter::ARMABI_PopAllCalleeSavedRegsAndAdjustStack() {
POP(4, R3, R4, R5, R6);
POP(4, R0, R1, R2, R3);
}
void ARMXEmitter::ARMABI_MOVIMM32(ARMReg reg, u32 val)
void ARMXEmitter::ARMABI_MOVI2R(ARMReg reg, Operand2 val)
{
// TODO: We can do this in less instructions if we check for if it is
// smaller than a 32bit variable. Like if it is a 8bit or 14bit(?)
// variable it should be able to be moved to just a single MOV instruction
// but for now, we are just taking the long route out and using the MOVW
// and MOVT
Operand2 Val(val);
MOVW(reg, Val);
MOVT(reg, Val, true);
return;
// TODO: There are more fancy ways to save calls if we check if
// The imm can be rotated or shifted a certain way.
// Masks tend to be able to be moved in to a reg with one call
MOVW(reg, val);
if(val.Value & 0xFFFF0000)
MOVT(reg, val, true);
}
// Moves IMM to memory location
void ARMXEmitter::ARMABI_MOVIMM32(Operand2 op, u32 val)
void ARMXEmitter::ARMABI_MOVI2M(Operand2 op, Operand2 val)
{
// This moves imm to a memory location
Operand2 Val(val);
MOVW(R10, Val); MOVT(R10, Val, true);
MOVW(R11, op); MOVT(R11, op, true);
STR(R11, R10); // R10 is what we want to store
MOVW(R14, val); MOVT(R14, val, true);
MOVW(R12, op); MOVT(R12, op, true);
STR(R12, R14); // R10 is what we want to store
}
const char *conditions[] = {"EQ", "NEQ", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "AL" };
static void ShowCondition(u32 cond)
{
printf("Condition: %s[%d]\n", conditions[cond], cond);
}
void ARMXEmitter::ARMABI_ShowConditions()
{
const u8 *ptr = GetCodePtr();
FixupBranch cc[15];
for(u32 a = 0; a < 15; ++a)
cc[a] = B_CC((CCFlags)a);
for(u32 a = 0; a < 15; ++a)
{
SetJumpTarget(cc[a]);
ARMABI_CallFunctionC((void*)&ShowCondition, a);
if(a != 14)
B(ptr + ((a + 1) * 4));
}
}
// NZCVQ is stored in the lower five bits of the Flags variable
// GE values are in the lower four bits of the GEval variable
@ -67,12 +101,11 @@ void ARMXEmitter::UpdateAPSR(bool NZCVQ, u8 Flags, bool GE, u8 GEval)
{
// Can't update GE with the other ones with a immediate
// Got to use a scratch register
u32 IMM = (Flags << 27) | ((GEval & 0xF) << 16);
ARMABI_MOVIMM32(R8, IMM);
_MSR(true, true, R8);
u32 Imm = (Flags << 27) | ((GEval & 0xF) << 16);
ARMABI_MOVI2R(R14, IMM(Imm));
_MSR(true, true, R14);
}
else
{
if(NZCVQ)
{
Operand2 value(Flags << 1, 3);
@ -83,8 +116,4 @@ void ARMXEmitter::UpdateAPSR(bool NZCVQ, u8 Flags, bool GE, u8 GEval)
Operand2 value(GEval << 2, 9);
_MSR(false, true, value);
}
else
; // Okay?
}
}

View File

@ -76,6 +76,11 @@ void ARMXEmitter::NOP(int count)
}
}
void ARMXEmitter::SETEND(bool BE)
{
//SETEND is non-conditional
Write32( 0xF1010000 | (BE << 9));
}
void ARMXEmitter::BKPT(u16 arg)
{
Write32(condition | 0x01200070 | (arg << 4 & 0x000FFF00) | (arg & 0x0000000F));
@ -85,10 +90,6 @@ void ARMXEmitter::YIELD()
Write32(condition | 0x0320F001);
}
void ARMXEmitter::B (Operand2 op2)
{
Write32(condition | (10 << 24) | op2.Imm24());
}
FixupBranch ARMXEmitter::B()
{
FixupBranch branch;
@ -109,6 +110,65 @@ FixupBranch ARMXEmitter::BL()
Write32(condition | 0x01A00000);
return branch;
}
FixupBranch ARMXEmitter::B_CC(CCFlags Cond)
{
FixupBranch branch;
branch.type = 0; // Zero for B
branch.ptr = code;
branch.condition = Cond << 28;
//We'll write NOP here for now.
Write32(condition | 0x01A00000);
return branch;
}
void ARMXEmitter::B_CC(CCFlags Cond, const void *fnptr)
{
s32 distance = (s32)fnptr - (s32(code) + 8);
_assert_msg_(DYNA_REC, distance > -33554432
&& distance <= 33554432,
"B_CC out of range (%p calls %p)", code, fnptr);
Write32((Cond << 28) | 0x0A000000 | ((distance >> 2) & 0x00FFFFFF));
}
FixupBranch ARMXEmitter::BL_CC(CCFlags Cond)
{
FixupBranch branch;
branch.type = 1; // Zero for B
branch.ptr = code;
branch.condition = Cond << 28;
//We'll write NOP here for now.
Write32(condition | 0x01A00000);
return branch;
}
void ARMXEmitter::SetJumpTarget(FixupBranch const &branch)
{
s32 distance = (s32(code) - 8) - (s32)branch.ptr;
_assert_msg_(DYNA_REC, distance > -33554432
&& distance <= 33554432,
"SetJumpTarget out of range (%p calls %p)", code,
branch.ptr);
if(branch.type == 0) // B
*(u32*)branch.ptr = (u32)(branch.condition | (10 << 24) | ((distance >> 2) &
0x00FFFFFF));
else // BL
*(u32*)branch.ptr = (u32)(branch.condition | 0x0B000000 | ((distance >> 2)
& 0x00FFFFFF));
}
void ARMXEmitter::B (const void *fnptr)
{
s32 distance = (s32)fnptr - (s32(code) + 8);
_assert_msg_(DYNA_REC, distance > -33554432
&& distance <= 33554432,
"B out of range (%p calls %p)", code, fnptr);
Write32(condition | 0x0A000000 | ((distance >> 2) & 0x00FFFFFF));
}
void ARMXEmitter::B(ARMReg src)
{
Write32(condition | (18 << 20) | (0xFFF << 8) | (1 << 4) | src);
}
void ARMXEmitter::BL(const void *fnptr)
{
s32 distance = (s32)fnptr - (s32(code) + 8);
@ -117,31 +177,10 @@ void ARMXEmitter::BL(const void *fnptr)
"BL out of range (%p calls %p)", code, fnptr);
Write32(condition | 0x0B000000 | ((distance >> 2) & 0x00FFFFFF));
}
void ARMXEmitter::BLX(ARMReg src)
void ARMXEmitter::BL(ARMReg src)
{
Write32(condition | 0x12FFF30 | src);
}
void ARMXEmitter::BX(ARMReg src)
{
Write32(condition | (18 << 20) | (0xFFF << 8) | (1 << 4) | src);
}
void ARMXEmitter::SetJumpTarget(FixupBranch const &branch)
{
s32 distance = (s32(code) + 4) - (s32)branch.ptr;
_assert_msg_(DYNA_REC, distance > -33554432
&& distance <= 33554432,
"SetJumpTarget out of range (%p calls %p)", code,
branch.ptr);
printf("Jumping to %08x\n", distance);
if(branch.type == 0) // B
*(u32*)branch.ptr = (u32)(branch.condition | (10 << 24) | (distance &
0x00FFFFFF));
else // BL
*(u32*)branch.ptr = (u32)(branch.condition | 0x0B000000 | ((distance >> 2)
& 0x00FFFFFF));
}
void ARMXEmitter::PUSH(const int num, ...)
{
u16 RegList = 0;
@ -173,78 +212,135 @@ void ARMXEmitter::POP(const int num, ...)
Write32(condition | (2237 << 16) | RegList);
}
void ARMXEmitter::WriteDataOp(u32 op, ARMReg dest, ARMReg src, Operand2 op2)
void ARMXEmitter::WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, Operand2 op2)
{
Write32(condition | (op << 20) | (src << 16) | (dest << 12) | op2.Imm12Mod());
Write32(condition | (13 << 21) | (SetFlags << 20) | (dest << 12) | op2.Imm5() | (op << 4) | src);
}
void ARMXEmitter::WriteDataOp(u32 op, ARMReg dest, ARMReg src, ARMReg op2)
void ARMXEmitter::WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, ARMReg op2)
{
Write32(condition | (op << 20) | (src << 16) | (dest << 12) | op2);
}
void ARMXEmitter::WriteDataOp(u32 op, ARMReg dest, ARMReg src)
{
Write32(condition | (op << 20) | (dest << 12) | src);
Write32(condition | (13 << 21) | (SetFlags << 20) | (dest << 12) | (op2 << 8) | (op << 4) | src);
}
// IMM, REG, IMMSREG, RSR
// -1 for invalid if the instruction doesn't support that
const s32 InstOps[][4] = {{16, 0, 0, 0}, // AND(s)
{17, 1, 1, 1}, // EOR(s)
{18, 2, 2, 2}, // SUB(s)
{19, 3, 3, 3}, // RSB(s)
{20, 4, 4, 4}, // ADD(s)
{21, 5, 5, 5}, // ADC(s)
{22, 6, 6, 6}, // SBC(s)
{23, 7, 7, 7}, // RSC(s)
{24, 8, 8, 8}, // TST
{25, 9, 9, 9}, // TEQ
{26, 10, 10, 10}, // CMP
{27, 11, 11, 11}, // CMN
{28, 12, 12, 12}, // ORR(s)
{29, 13, 13, 13}, // MOV(s)
{30, 14, 14, 14}, // BIC(s)
{31, 15, 15, 15}, // MVN(s)
{24, -1, -1, -1}, // MOVW
{26, -1, -1, -1}, // MOVT
};
const char *InstNames[] = { "AND",
"EOR",
"SUB",
"RSB",
"ADD",
"ADC",
"SBC",
"RSC",
"TST",
"TEQ",
"CMP",
"CMN",
"ORR",
"MOV",
"BIC",
"MVN"
};
void ARMXEmitter::AND (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(0, Rd, Rn, Rm); }
void ARMXEmitter::ANDS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(0, Rd, Rn, Rm, true); }
void ARMXEmitter::EOR (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(1, Rd, Rn, Rm); }
void ARMXEmitter::EORS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(1, Rd, Rn, Rm, true); }
void ARMXEmitter::SUB (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(2, Rd, Rn, Rm); }
void ARMXEmitter::SUBS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(2, Rd, Rn, Rm, true); }
void ARMXEmitter::RSB (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(3, Rd, Rn, Rm); }
void ARMXEmitter::RSBS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(3, Rd, Rn, Rm, true); }
void ARMXEmitter::ADD (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(4, Rd, Rn, Rm); }
void ARMXEmitter::ADDS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(4, Rd, Rn, Rm, true); }
void ARMXEmitter::ADC (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(5, Rd, Rn, Rm); }
void ARMXEmitter::ADCS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(5, Rd, Rn, Rm, true); }
void ARMXEmitter::SBC (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(6, Rd, Rn, Rm); }
void ARMXEmitter::SBCS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(6, Rd, Rn, Rm, true); }
void ARMXEmitter::RSC (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(7, Rd, Rn, Rm); }
void ARMXEmitter::RSCS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(7, Rd, Rn, Rm, true); }
void ARMXEmitter::TST ( ARMReg Rn, Operand2 Rm) { WriteInstruction(8, R0, Rn, Rm, true); }
void ARMXEmitter::TEQ ( ARMReg Rn, Operand2 Rm) { WriteInstruction(9, R0, Rn, Rm, true); }
void ARMXEmitter::CMP ( ARMReg Rn, Operand2 Rm) { WriteInstruction(10, R0, Rn, Rm, true); }
void ARMXEmitter::CMN ( ARMReg Rn, Operand2 Rm) { WriteInstruction(11, R0, Rn, Rm, true); }
void ARMXEmitter::ORR (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(12, Rd, Rn, Rm); }
void ARMXEmitter::ORRS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(12, Rd, Rn, Rm, true); }
void ARMXEmitter::MOV (ARMReg Rd, Operand2 Rm) { WriteInstruction(13, Rd, R0, Rm); }
void ARMXEmitter::MOVS(ARMReg Rd, Operand2 Rm) { WriteInstruction(13, Rd, R0, Rm, true); }
void ARMXEmitter::BIC (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(14, Rd, Rn, Rm); }
void ARMXEmitter::BICS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(14, Rd, Rn, Rm, true); }
void ARMXEmitter::MVN (ARMReg Rd, Operand2 Rm) { WriteInstruction(15, Rd, R0, Rm); }
void ARMXEmitter::MVNS(ARMReg Rd, Operand2 Rm) { WriteInstruction(15, Rd, R0, Rm, true); }
void ARMXEmitter::MOVW(ARMReg Rd, Operand2 Rm) { WriteInstruction(16, Rd, R0, Rm); }
void ARMXEmitter::MOVT(ARMReg Rd, Operand2 Rm, bool TopBits) { WriteInstruction(17, Rd, R0, TopBits ? Rm.Value >> 16 : Rm); }
void ARMXEmitter::WriteInstruction (u32 Op, ARMReg Rd, ARMReg Rn, Operand2 Rm, bool SetFlags) // This can get renamed later
{
u32 op = InstOps[Op][Rm.GetType()]; // Type always decided by last operand
u32 Data = Rm.GetData();
if (Rm.GetType() == TYPE_IMM)
{
switch (Op)
{
// MOV cases that support IMM16
case 16:
case 17:
Data = Rm.Imm16();
break;
default:
break;
}
}
if (op == -1)
_assert_msg_(DYNA_REC, false, "%s not yet support %d", InstNames[Op], Rm.GetType());
Write32(condition | (op << 21) | (SetFlags ? (1 << 20) : 0) | Rn << 16 | Rd << 12 | Data);
}
// Data Operations
void ARMXEmitter::AND (ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(32, dest, src, op2);}
void ARMXEmitter::ANDS(ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(33, dest, src, op2);}
void ARMXEmitter::AND (ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp( 0, dest, src, op2);}
void ARMXEmitter::ANDS(ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp( 1, dest, src, op2);}
void ARMXEmitter::EOR (ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(34, dest, src, op2);}
void ARMXEmitter::EORS(ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(35, dest, src, op2);}
void ARMXEmitter::EOR (ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp( 2, dest, src, op2);}
void ARMXEmitter::EORS(ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp( 3, dest, src, op2);}
void ARMXEmitter::SUB (ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(36, dest, src, op2);}
void ARMXEmitter::SUBS(ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(37, dest, src, op2);}
void ARMXEmitter::SUB (ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp( 4, dest, src, op2);}
void ARMXEmitter::SUBS(ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp( 5, dest, src, op2);}
void ARMXEmitter::RSB (ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(38, dest, src, op2);}
void ARMXEmitter::RSBS(ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(39, dest, src, op2);}
void ARMXEmitter::RSB (ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp( 6, dest, src, op2);}
void ARMXEmitter::RSBS(ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp( 7, dest, src, op2);}
void ARMXEmitter::ADD (ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(40, dest, src, op2);}
void ARMXEmitter::ADDS(ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(41, dest, src, op2);}
void ARMXEmitter::ADD (ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp( 8, dest, src, op2);}
void ARMXEmitter::ADDS(ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp( 9, dest, src, op2);}
void ARMXEmitter::ADC (ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(42, dest, src, op2);}
void ARMXEmitter::ADCS(ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(43, dest, src, op2);}
void ARMXEmitter::ADC (ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp(10, dest, src, op2);}
void ARMXEmitter::ADCS(ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp(11, dest, src, op2);}
void ARMXEmitter::SBC (ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(44, dest, src, op2);}
void ARMXEmitter::SBCS(ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(45, dest, src, op2);}
void ARMXEmitter::SBC (ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp(12, dest, src, op2);}
void ARMXEmitter::SBCS(ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp(13, dest, src, op2);}
void ARMXEmitter::RSC (ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(46, dest, src, op2);}
void ARMXEmitter::RSCS(ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(47, dest, src, op2);}
void ARMXEmitter::RSC (ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp(14, dest, src, op2);}
void ARMXEmitter::RSCS(ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp(15, dest, src, op2);}
void ARMXEmitter::TST ( ARMReg src, Operand2 op2) { WriteDataOp(49, R0 , src, op2);}
void ARMXEmitter::TST ( ARMReg src, ARMReg op2) { WriteDataOp(17, R0 , src, op2);}
void ARMXEmitter::TEQ ( ARMReg src, Operand2 op2) { WriteDataOp(51, R0 , src, op2);}
void ARMXEmitter::TEQ ( ARMReg src, ARMReg op2) { WriteDataOp(19, R0 , src, op2);}
void ARMXEmitter::CMP ( ARMReg src, Operand2 op2) { WriteDataOp(53, R0 , src, op2);}
void ARMXEmitter::CMP ( ARMReg src, ARMReg op2) { WriteDataOp(21, R0 , src, op2);}
void ARMXEmitter::CMN ( ARMReg src, Operand2 op2) { WriteDataOp(55, R0 , src, op2);}
void ARMXEmitter::CMN ( ARMReg src, ARMReg op2) { WriteDataOp(23, R0 , src, op2);}
void ARMXEmitter::ORR (ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(56, dest, src, op2);}
void ARMXEmitter::ORRS(ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(57, dest, src, op2);}
void ARMXEmitter::ORR (ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp(24, dest, src, op2);}
void ARMXEmitter::ORRS(ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp(25, dest, src, op2);}
void ARMXEmitter::MOV (ARMReg dest, Operand2 op2) { WriteDataOp(58, dest, R0 , op2);}
void ARMXEmitter::MOVS(ARMReg dest, Operand2 op2) { WriteDataOp(59, dest, R0 , op2);}
void ARMXEmitter::MOV (ARMReg dest, ARMReg src ) { WriteDataOp(26, dest, R0 , src);}
void ARMXEmitter::MOVS(ARMReg dest, ARMReg src ) { WriteDataOp(27, dest, R0 , src);}
void ARMXEmitter::BIC (ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(60, dest, src, op2);}
void ARMXEmitter::BICS(ARMReg dest, ARMReg src, Operand2 op2) { WriteDataOp(61, dest, src, op2);}
void ARMXEmitter::BIC (ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp(28, dest, src, op2);}
void ARMXEmitter::BICS(ARMReg dest, ARMReg src, ARMReg op2) { WriteDataOp(29, dest, src, op2);}
void ARMXEmitter::MVN (ARMReg dest, Operand2 op2) { WriteDataOp(62, dest, R0 , op2);}
void ARMXEmitter::MVNS(ARMReg dest, Operand2 op2) { WriteDataOp(63, dest, R0 , op2);}
void ARMXEmitter::MVN (ARMReg dest, ARMReg op2) { WriteDataOp(30, dest, R0 , op2);}
void ARMXEmitter::MVNS(ARMReg dest, ARMReg op2) { WriteDataOp(31, dest, R0 , op2);}
void ARMXEmitter::LSL (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(0, false, dest, src, op2);}
void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(0, true, dest, src, op2);}
void ARMXEmitter::LSL (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, false, dest, src, op2);}
void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, true, dest, src, op2);}
void ARMXEmitter::MUL (ARMReg dest, ARMReg src, ARMReg op2)
{
Write32(condition | (dest << 16) | (src << 8) | (9 << 4) | op2);
}
void ARMXEmitter::MULS(ARMReg dest, ARMReg src, ARMReg op2)
{
Write32(condition | (1 << 20) | (dest << 16) | (src << 8) | (9 << 4) | op2);
}
void ARMXEmitter::SXTB (ARMReg dest, ARMReg op2)
{
Write32(condition | (0x6AF << 16) | (dest << 12) | (7 << 4) | op2);
}
void ARMXEmitter::SXTH (ARMReg dest, ARMReg op2, u8 rotation)
{
SXTAH(dest, (ARMReg)15, op2, rotation);
}
void ARMXEmitter::SXTAH(ARMReg dest, ARMReg src, ARMReg op2, u8 rotation)
{
// bits ten and 11 are the rotation amount, see 8.8.232 for more
// information
Write32(condition | (0x6B << 20) | (src << 16) | (dest << 12) | (rotation << 10) | (7 << 4) | op2);
}
void ARMXEmitter::REV (ARMReg dest, ARMReg src )
{
Write32(condition | (107 << 20) | (15 << 16) | (dest << 12) | (243 << 4) | src);
@ -262,30 +358,37 @@ void ARMXEmitter::MRS (ARMReg dest)
{
Write32(condition | (16 << 20) | (15 << 16) | (dest << 12));
}
// Memory Load/Store operations
void ARMXEmitter::WriteMoveOp(u32 op, ARMReg dest, Operand2 op2, bool TopBits)
{
Write32(condition | (op << 20) | (dest << 12) | (TopBits ? op2.Imm16High() : op2.Imm16Low()));
}
void ARMXEmitter::MOVT(ARMReg dest, Operand2 op2, bool TopBits)
{
WriteMoveOp( 52, dest, op2, TopBits);
}
void ARMXEmitter::MOVW(ARMReg dest, Operand2 op2) { WriteMoveOp( 48, dest, op2);}
void ARMXEmitter::WriteStoreOp(u32 op, ARMReg dest, ARMReg src, Operand2 op2)
{
Write32(condition | (op << 20) | (dest << 16) | (src << 12) | op2.Imm12());
if (op2.GetData() == 0) // Don't index
Write32(condition | (op << 20) | (dest << 16) | (src << 12) | op2.Imm12());
else
Write32(condition | (op << 20) | (3 << 23) | (dest << 16) | (src << 12) | op2.Imm12());
}
void ARMXEmitter::STR (ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x40, dest, src, op);}
void ARMXEmitter::STRB(ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x44, dest, src, op);}
void ARMXEmitter::STR (ARMReg dest, ARMReg base, ARMReg offset, bool Index,
bool Add)
void ARMXEmitter::STR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add)
{
Write32(condition | (0x60 << 20) | (Index << 24) | (Add << 23) | (base << 12) | (dest << 16) | offset);
Write32(condition | (0x60 << 20) | (Index << 24) | (Add << 23) | (dest << 16) | (base << 12) | offset);
}
void ARMXEmitter::LDR (ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x41, dest, src, op);}
void ARMXEmitter::LDRB(ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x45, dest, src, op);}
void ARMXEmitter::LDREX(ARMReg dest, ARMReg base)
{
Write32(condition | (25 << 20) | (base << 16) | (dest << 12) | 0xF9F);
}
void ARMXEmitter::STREX(ARMReg dest, ARMReg base, ARMReg op)
{
_assert_msg_(DYNA_REC, (dest != base && dest != op), "STREX dest can't be other two registers");
Write32(condition | (24 << 20) | (base << 16) | (dest << 12) | (0xF9 << 4) | op);
}
void ARMXEmitter::DMB ()
{
Write32(0xF57FF05E);
}
void ARMXEmitter::LDR (ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x41, src, dest, op);}
void ARMXEmitter::LDRB(ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x45, src, dest, op);}
void ARMXEmitter::LDR (ARMReg dest, ARMReg base, ARMReg offset, bool Index,
bool Add)
{
@ -297,7 +400,6 @@ void ARMXEmitter::WriteRegStoreOp(u32 op, ARMReg dest, bool WriteBack, u16 RegLi
}
void ARMXEmitter::STMFD(ARMReg dest, bool WriteBack, const int Regnum, ...)
{
_assert_msg_(DYNA_REC, Regnum > 1, "Doesn't support only one register");
u16 RegList = 0;
u8 Reg;
int i;
@ -313,7 +415,6 @@ void ARMXEmitter::STMFD(ARMReg dest, bool WriteBack, const int Regnum, ...)
}
void ARMXEmitter::LDMFD(ARMReg dest, bool WriteBack, const int Regnum, ...)
{
_assert_msg_(DYNA_REC, Regnum > 1, "Doesn't support only one register");
u16 RegList = 0;
u8 Reg;
int i;

View File

@ -23,10 +23,6 @@
#include "Common.h"
#include "MemoryUtil.h"
#ifndef _M_ARM32
#error Compile this on ARM.
#endif
namespace ArmGen
{
@ -62,9 +58,9 @@ enum CCFlags
{
CC_EQ = 0, // Equal
CC_NEQ, // Not equal
CC_CS, // Carry Set
CC_CS, // Carry Set
CC_CC, // Carry Clear
CC_MI, // Minus
CC_MI, // Minus (Negative)
CC_PL, // Plus
CC_VS, // Overflow
CC_VC, // No Overflow
@ -75,9 +71,8 @@ enum CCFlags
CC_GT, // Signed greater than
CC_LE, // Signed less than or equal
CC_AL, // Always (unconditional) 14
CC_HS = CC_CS, // Higher or same
CC_LO = CC_CC, // Unsigned Lower
CC_HS = 2, // Alias of CC_CS
CC_LO = 3, // Alias of CC_CC
};
const u32 NO_COND = 0xE0000000;
@ -101,32 +96,45 @@ class ARMXEmitter;
enum OpType
{
TYPE_IMM = 0,
TYPE_MEM,
TYPE_REG
TYPE_REG,
TYPE_IMMSREG,
TYPE_RSR,
TYPE_MEM
};
class Operand2
{
private:
OpType Type;
// IMM types
friend class ARMXEmitter;
protected:
u32 Value;
private:
OpType Type;
// IMM types
u8 Rotation; // Only for u8 values
// Memory types
bool Away;
// Register types
ARMReg Base;
ARMReg IndexOrShift;
u8 IndexOrShift;
ShiftType Shift;
public:
Operand2() {}
Operand2(u32 imm, OpType type = TYPE_IMM, bool away = false )
OpType GetType()
{
return Type;
}
Operand2() {}
Operand2(u32 imm, OpType type = TYPE_IMM)
{
Type = type;
Value = imm;
Away = away;
Rotation = 0;
}
Operand2(ARMReg Reg)
{
Type = TYPE_REG;
Value = Reg;
Rotation = 0;
}
Operand2(u8 imm, u8 rotation)
{
@ -134,26 +142,93 @@ public:
Value = imm;
Rotation = rotation;
}
Operand2(ARMReg base, ShiftType type, ARMReg shift)
Operand2(ARMReg base, ShiftType type, ARMReg shift) // RSR
{
Type = TYPE_REG;
Type = TYPE_RSR;
_assert_msg_(DYNA_REC, type != RRX, "Invalid Operand2: RRX does not take a register shift amount");
IndexOrShift = shift;
Shift = type;
Base = base;
Value = base;
}
Operand2(ARMReg base)
Operand2(u8 shift, ShiftType type, ARMReg base)// For IMM shifted register
{
_assert_msg_(DYNA_REC, false, "Can't have just register operand...yet");
if(shift == 32) shift = 0;
switch (type)
{
case LSL:
_assert_msg_(DYNA_REC, shift < 32, "Invalid Operand2: LSL %u", shift);
break;
case LSR:
_assert_msg_(DYNA_REC, shift <= 32, "Invalid Operand2: LSR %u", shift);
if (!shift)
type = LSL;
if (shift == 32)
shift = 0;
break;
case ASR:
_assert_msg_(DYNA_REC, shift < 32, "Invalid Operand2: LSR %u", shift);
if (!shift)
type = LSL;
if (shift == 32)
shift = 0;
break;
case ROR:
_assert_msg_(DYNA_REC, shift < 32, "Invalid Operand2: ROR %u", shift);
if (!shift)
type = LSL;
break;
case RRX:
_assert_msg_(DYNA_REC, shift == 0, "Invalid Operand2: RRX does not take an immediate shift amount");
type = ROR;
break;
}
IndexOrShift = shift;
Shift = type;
Value = base;
Type = TYPE_IMMSREG;
}
const 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_(DYNA_REC, false, "GetData with Invalid Type");
break;
}
}
const u32 IMMSR() // IMM shifted register
{
_assert_msg_(DYNA_REC, Type = TYPE_IMMSREG, "IMMSR must be imm shifted register");
return ((IndexOrShift & 0x1f) << 7 | (Shift << 5) | Value);
}
const u32 RSR() // Register shifted register
{
_assert_msg_(DYNA_REC, !(Type == TYPE_IMM), "RSR can't be IMM");
return (IndexOrShift << 8) | (Shift << 5) | 0x10 | Base;
_assert_msg_(DYNA_REC, Type == TYPE_RSR, "RSR must be RSR Of Course");
return (IndexOrShift << 8) | (Shift << 5) | 0x10 | Value;
}
const u32 Rm()
{
_assert_msg_(DYNA_REC, Type == TYPE_REG, "Rm must be with Reg");
return Value;
}
const u32 Imm5()
{
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm5 not IMM value");
return ((Value & 0x0000001F) << 7);
}
const u32 Imm8Rot() // IMM8 with Rotation
{
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8Rot not IMM value;");
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8Rot not IMM value");
_assert_msg_(DYNA_REC, (Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation);
return (1 << 25) | (Rotation << 7) | (Value & 0x000000FF);
}
@ -169,12 +244,7 @@ public:
// bottom eight being a IMM. This is for instructions that need to
// expand a 8bit IMM to a 32bit value and gives you some rotation as
// well.
// 0000 = no rotation
// 0001 = Rotate right 2 bits
// 0010 = Rotate right 4 bits
// 0011 = Rotate right 6 bits
// 0100 = Rotate right 8 bits (So the IMM is in the top 8 bits of the IMM32)
// See A5.2.4 in the Arm reference manual for more.
// Each rotation rotates to the right by 2 bits
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm12Mod not IMM");
return ((Rotation & 0xF) << 8) | (Value & 0xFF);
}
@ -182,7 +252,6 @@ public:
{
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm16 not IMM");
return ( (Value & 0xF000) << 4) | (Value & 0x0FFF);
}
const u32 Imm16Low()
{
@ -192,49 +261,18 @@ public:
{
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm16 not IMM");
return ( ((Value >> 16) & 0xF000) << 4) | ((Value >> 16) & 0x0FFF);
}
const u32 Imm24()
{
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm16 not IMM");
return (Value & 0x0FFFFFFF);
}
/*Operand2(ARMReg base, ShiftType type = LSL, u8 shift = 0)
{
switch (type)
{
case LSL:
_assert_msg_(DYNA_REC, shift >= 32, "Invalid Operand2: LSL %u", shift);
break;
case LSR:
_assert_msg_(DYNA_REC, shift > 32, "Invalid Operand2: LSR %u", shift);
if (!shift)
type = LSL;
if (shift == 32)
shift = 0;
break;
case ASR:
_assert_msg_(DYNA_REC, shift > 32, "Invalid Operand2: LSR %u", shift);
if (!shift)
type = LSL;
if (shift == 32)
shift = 0;
break;
case ROR:
_assert_msg_(DYNA_REC, shift >= 32, "Invalid Operand2: ROR %u", shift);
if (!shift)
type = LSL;
break;
case RRX:
_assert_msg_(DYNA_REC, shift != 0, "Invalid Operand2: RRX does not take an immediate shift amount");
type = ROR;
break;
}
encoding = (shift << 7) | (type << 5) | base;
} */
};
inline Operand2 Mem(void *ptr) { return Operand2((u32)ptr, true); }
inline Operand2 R(ARMReg Reg) { return Operand2(Reg, TYPE_REG); }
inline Operand2 IMM(u32 Imm) { return Operand2(Imm, TYPE_IMM); }
inline Operand2 Mem(void *ptr) { return Operand2((u32)ptr, TYPE_IMM); }
//usage: int a[]; ARRAY_OFFSET(a,10)
#define ARRAY_OFFSET(array,index) ((u32)((u64)&(array)[index]-(u64)&(array)[0]))
//usage: struct {int e;} s; STRUCT_OFFSET(s,e)
@ -256,13 +294,13 @@ private:
u8 *code, *startcode;
u32 condition;
void WriteDataOp(u32 op, ARMReg dest, ARMReg src, Operand2 op2);
void WriteDataOp(u32 op, ARMReg dest, ARMReg src, ARMReg op2);
void WriteDataOp(u32 op, ARMReg dest, ARMReg src);
void WriteMoveOp(u32 op, ARMReg dest, Operand2 op2, bool TopBits = false);
void WriteStoreOp(u32 op, ARMReg dest, ARMReg src, Operand2 op2);
void WriteRegStoreOp(u32 op, ARMReg dest, bool WriteBack, u16 RegList);
void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, ARMReg op2);
void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, Operand2 op2);
// New Ops
void WriteInstruction(u32 op, ARMReg Rd, ARMReg Rn, Operand2 Rm, bool SetFlags = false);
protected:
inline void Write32(u32 value) {*(u32*)code = value; code+=4;}
@ -282,6 +320,10 @@ public:
void SetCC(CCFlags cond = CC_AL);
// Special purpose instructions
// Dynamic Endian Switching
void SETEND(bool BE);
// Debug Breakpoint
void BKPT(u16 arg);
@ -295,76 +337,65 @@ public:
#undef CALL
#endif
void B (Operand2 op2);
// Branching
FixupBranch B();
void BL(const void *ptr);
FixupBranch B_CC(CCFlags Cond);
void B_CC(CCFlags Cond, const void *fnptr);
FixupBranch BL();
void BLX(ARMReg src);
void BX (ARMReg src);
FixupBranch BL_CC(CCFlags Cond);
void SetJumpTarget(FixupBranch const &branch);
void B (const void *fnptr);
void B (ARMReg src);
void BL(const void *fnptr);
void BL(ARMReg src);
void PUSH(const int num, ...);
void POP(const int num, ...);
// Data operations
void AND (ARMReg dest, ARMReg src, Operand2 op2);
void ANDS(ARMReg dest, ARMReg src, Operand2 op2);
void AND (ARMReg dest, ARMReg src, ARMReg op2);
void ANDS(ARMReg dest, ARMReg src, ARMReg op2);
// New Data Ops
void AND (ARMReg Rd, ARMReg Rn, Operand2 Rm);
void ANDS(ARMReg Rd, ARMReg Rn, Operand2 Rm);
void EOR (ARMReg dest, ARMReg src, Operand2 op2);
void EORS(ARMReg dest, ARMReg src, Operand2 op2);
void EOR (ARMReg dest, ARMReg src, ARMReg op2);
void EORS(ARMReg dest, ARMReg src, ARMReg op2);
void SUB (ARMReg dest, ARMReg src, Operand2 op2);
void SUBS(ARMReg dest, ARMReg src, Operand2 op2);
void SUB (ARMReg dest, ARMReg src, ARMReg op2);
void SUBS(ARMReg dest, ARMReg src, ARMReg op2);
void RSB (ARMReg dest, ARMReg src, Operand2 op2);
void RSBS(ARMReg dest, ARMReg src, Operand2 op2);
void RSB (ARMReg dest, ARMReg src, ARMReg op2);
void RSBS(ARMReg dest, ARMReg src, ARMReg op2);
void ADD (ARMReg dest, ARMReg src, Operand2 op2);
void ADDS(ARMReg dest, ARMReg src, Operand2 op2);
void ADD (ARMReg dest, ARMReg src, ARMReg op2);
void ADDS(ARMReg dest, ARMReg src, ARMReg op2);
void ADC (ARMReg dest, ARMReg src, Operand2 op2);
void ADCS(ARMReg dest, ARMReg src, Operand2 op2);
void ADC (ARMReg dest, ARMReg src, ARMReg op2);
void ADCS(ARMReg dest, ARMReg src, ARMReg op2);
void LSL (ARMReg dest, ARMReg src, Operand2 op2);
void LSL (ARMReg dest, ARMReg src, ARMReg op2);
void LSLS(ARMReg dest, ARMReg src, Operand2 op2);
void LSLS(ARMReg dest, ARMReg src, ARMReg op2);
void SBC (ARMReg dest, ARMReg src, Operand2 op2);
void SBCS(ARMReg dest, ARMReg src, Operand2 op2);
void SBC (ARMReg dest, ARMReg src, ARMReg op2);
void SBCS(ARMReg dest, ARMReg src, ARMReg op2);
void REV (ARMReg dest, ARMReg src );
void RSC (ARMReg dest, ARMReg src, Operand2 op2);
void RSCS(ARMReg dest, ARMReg src, Operand2 op2);
void RSC (ARMReg dest, ARMReg src, ARMReg op2);
void RSCS(ARMReg dest, ARMReg src, ARMReg op2);
void TST ( ARMReg src, Operand2 op2);
void TST ( ARMReg src, ARMReg op2);
void TEQ ( ARMReg src, Operand2 op2);
void TEQ ( ARMReg src, ARMReg op2);
void CMP ( ARMReg src, Operand2 op2);
void CMP ( ARMReg src, ARMReg op2);
void CMN ( ARMReg src, Operand2 op2);
void CMN ( ARMReg src, ARMReg op2);
void ORR (ARMReg dest, ARMReg src, Operand2 op2);
void ORRS(ARMReg dest, ARMReg src, Operand2 op2);
void ORR (ARMReg dest, ARMReg src, ARMReg op2);
void ORRS(ARMReg dest, ARMReg src, ARMReg op2);
void MOV (ARMReg dest, Operand2 op2);
void MOVS(ARMReg dest, Operand2 op2);
void MOV (ARMReg dest, ARMReg src );
void MOVS(ARMReg dest, ARMReg src );
void BIC (ARMReg dest, ARMReg src, Operand2 op2);
void BICS(ARMReg dest, ARMReg src, Operand2 op2);
void BIC (ARMReg dest, ARMReg src, ARMReg op2);
void BICS(ARMReg dest, ARMReg src, ARMReg op2);
void MVN (ARMReg dest, Operand2 op2);
void MVNS(ARMReg dest, Operand2 op2);
void MVN (ARMReg dest, ARMReg op2);
void MVNS(ARMReg dest, ARMReg op2);
void MOVW(ARMReg dest, Operand2 op2);
void MOVT(ARMReg dest, Operand2 op2, bool TopBits = false);
void MUL (ARMReg dest, ARMReg src, ARMReg op2);
void MULS(ARMReg dest, ARMReg src, ARMReg op2);
void SXTB(ARMReg dest, ARMReg op2);
void SXTH(ARMReg dest, ARMReg op2, u8 rotation = 0);
void SXTAH(ARMReg dest, ARMReg src, ARMReg op2, u8 rotation = 0);
// Using just MSR here messes with our defines on the PPC side of stuff
// Just need to put an underscore here, bit annoying.
void _MSR (bool nzcvq, bool g, Operand2 op2);
@ -372,26 +403,35 @@ public:
void MRS (ARMReg dest);
// Memory load/store operations
void MOVT(ARMReg dest, Operand2 op2, bool TopBits = false);
void MOVW(ARMReg dest, Operand2 op2);
void LDR (ARMReg dest, ARMReg src, Operand2 op2);
void LDR (ARMReg dest, ARMReg base, ARMReg offset = R0, bool Index = false, bool Add = false);
void LDRB(ARMReg dest, ARMReg src, Operand2 op2);
void STR (ARMReg dest, ARMReg src, Operand2 op2);
void STR (ARMReg dest, ARMReg base, ARMReg offset = R0, bool Index = false, bool Add = false);
void LDR (ARMReg dest, ARMReg src, Operand2 op2 = 0);
// Offset adds to the base register in LDR
void LDR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add);
void LDRB(ARMReg dest, ARMReg src, Operand2 op2 = 0);
void STR (ARMReg dest, ARMReg src, Operand2 op2 = 0);
// Offset adds on to the destination register in STR
void STR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add);
void STRB(ARMReg dest, ARMReg src, Operand2 op2);
void STRB(ARMReg dest, ARMReg src, Operand2 op2 = 0);
void STMFD(ARMReg dest, bool WriteBack, const int Regnum, ...);
void LDMFD(ARMReg dest, bool WriteBack, const int Regnum, ...);
// Exclusive Access operations
void LDREX(ARMReg dest, ARMReg base);
// dest contains the result if the instruction managed to store the value
void STREX(ARMReg dest, ARMReg base, ARMReg op);
void DMB ();
// Utility functions
// The difference between this and CALL is that this aligns the stack
// where appropriate.
void ARMABI_CallFunction(void *func);
void ARMABI_CallFunction(void *func);
void ARMABI_CallFunctionC(void *func, u32 Arg0);
void ARMABI_CallFunctionCC(void *func, u32 Arg1, u32 Arg2);
void ARMABI_PushAllCalleeSavedRegsAndAdjustStack();
void ARMABI_PopAllCalleeSavedRegsAndAdjustStack();
void ARMABI_MOVIMM32(ARMReg reg, u32 val);
void ARMABI_MOVIMM32(Operand2 op, u32 val);
void ARMABI_MOVI2R(ARMReg reg, Operand2 val);
void ARMABI_MOVI2M(Operand2 op, Operand2 val);
void ARMABI_ShowConditions();
void UpdateAPSR(bool NZCVQ, u8 Flags, bool GE, u8 GEval);

View File

@ -233,6 +233,12 @@
<ClCompile Include="StringUtil.cpp" />
<ClCompile Include="Thread.cpp" />
<ClCompile Include="Thunk.cpp" />
<ClCompile Include="ThunkArm.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Timer.cpp" />
<ClCompile Include="Version.cpp" />
<ClCompile Include="x64Analyzer.cpp" />

View File

@ -75,5 +75,6 @@
<ClCompile Include="ArmABI.cpp" />
<ClCompile Include="x86Disasm.cpp" />
<ClCompile Include="Action.cpp" />
<ClCompile Include="ThunkArm.cpp" />
</ItemGroup>
</Project>

View File

@ -21,7 +21,11 @@
#include <map>
#include "Common.h"
#ifdef ANDROID
#include "ArmEmitter.h"
#else
#include "x64Emitter.h"
#endif
// This simple class creates a wrapper around a C/C++ function that saves all fp state
// before entering it, and restores it upon exit. This is required to be able to selectively
@ -34,8 +38,11 @@
// we don't want to pollute the stack, so we store away regs somewhere global.
// NOT THREAD SAFE. This may only be used from the CPU thread.
// Any other thread using this stuff will be FATAL.
#ifdef ANDROID
class ThunkManager : public ArmGen::ARMXCodeBlock
#else
class ThunkManager : public Gen::XCodeBlock
#endif
{
std::map<void *, const u8 *> thunks;

55
Common/ThunkArm.cpp Normal file
View File

@ -0,0 +1,55 @@
// 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/
#include <map>
#include "Common.h"
#include "MemoryUtil.h"
#include "Thunk.h"
#define THUNK_ARENA_SIZE 1024*1024*1
namespace
{
static u8 GC_ALIGNED32(saved_fp_state[16 * 4 * 4]);
static u8 GC_ALIGNED32(saved_gpr_state[16 * 8]);
static u16 saved_mxcsr;
} // namespace
using namespace ArmGen;
void ThunkManager::Init()
{
}
void ThunkManager::Reset()
{
thunks.clear();
ResetCodePtr();
}
void ThunkManager::Shutdown()
{
Reset();
FreeCodeSpace();
}
void *ThunkManager::ProtectFunction(void *function, int num_params)
{
}

View File

@ -121,7 +121,7 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit)
}
//grab from list and jump to it
// ADD(R0, R10, LSL(R0, 2));
BX(R0);
B(R0);
SetJumpTarget(notfound);
//BL(&Jit);
@ -146,7 +146,7 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit)
//Landing pad for drec space
//ARMABI_PopAllCalleeSavedRegsAndAdjustStack();
BX(_LR);
B(_LR);
breakpointBailout = GetCodePtr();

View File

@ -187,18 +187,18 @@ namespace MIPSComp
case 42: //R(rd) = (int)R(rs) < (int)R(rt); break; //slt
CMP(gpr.RX(rs), gpr.RX(rt));
SetCC(CC_LT);
ARMABI_MOVIMM32(gpr.RX(rd), 1);
ARMABI_MOVI2R(gpr.RX(rd), 1);
SetCC(CC_GE);
ARMABI_MOVIMM32(gpr.RX(rd), 0);
ARMABI_MOVI2R(gpr.RX(rd), 0);
SetCC(CC_AL);
break;
case 43: //R(rd) = R(rs) < R(rt); break; //sltu
CMP(gpr.RX(rs), gpr.RX(rt));
SetCC(CC_LO);
ARMABI_MOVIMM32(gpr.RX(rd), 1);
ARMABI_MOVI2R(gpr.RX(rd), 1);
SetCC(CC_HS);
ARMABI_MOVIMM32(gpr.RX(rd), 0);
ARMABI_MOVI2R(gpr.RX(rd), 0);
SetCC(CC_AL);
break;

View File

@ -49,6 +49,7 @@ LOCAL_SRC_FILES := \
ui_atlas.cpp \
$(SRC)/native/android/app-android.cpp \
$(SRC)/Globals.cpp \
$(SRC)/Common/ArmABI.cpp \
$(SRC)/Common/ArmEmitter.cpp \
$(SRC)/Common/LogManager.cpp \
$(SRC)/Common/MemArena.cpp \
@ -58,6 +59,7 @@ LOCAL_SRC_FILES := \
$(SRC)/Common/FileUtil.cpp \
$(SRC)/Common/StringUtil.cpp \
$(SRC)/Common/Timer.cpp \
$(SRC)/Common/ThunkARM.cpp \
$(SRC)/Common/Misc.cpp \
$(SRC)/GPU/Math3D.cpp \
$(SRC)/GPU/GpuState.cpp \