mirror of
https://github.com/libretro/ppsspp.git
synced 2024-11-27 10:20:49 +00:00
Merge Ryan's latest ARM emitter work from Dolphin
This commit is contained in:
parent
16f5a874a3
commit
5878f28fca
@ -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?
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
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;
|
||||
|
@ -23,10 +23,6 @@
|
||||
#include "Common.h"
|
||||
#include "MemoryUtil.h"
|
||||
|
||||
#ifndef _M_ARM32
|
||||
#error Compile this on ARM.
|
||||
#endif
|
||||
|
||||
namespace ArmGen
|
||||
{
|
||||
|
||||
@ -64,7 +60,7 @@ enum CCFlags
|
||||
CC_NEQ, // Not equal
|
||||
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:
|
||||
OpType GetType()
|
||||
{
|
||||
return Type;
|
||||
}
|
||||
Operand2() {}
|
||||
Operand2(u32 imm, OpType type = TYPE_IMM, bool away = false )
|
||||
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_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);
|
||||
|
||||
|
@ -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" />
|
||||
|
@ -75,5 +75,6 @@
|
||||
<ClCompile Include="ArmABI.cpp" />
|
||||
<ClCompile Include="x86Disasm.cpp" />
|
||||
<ClCompile Include="Action.cpp" />
|
||||
<ClCompile Include="ThunkArm.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -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
55
Common/ThunkArm.cpp
Normal 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)
|
||||
{
|
||||
}
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user