diff --git a/Common/ArmABI.cpp b/Common/ArmABI.cpp
index c72e8348f..6792edb97 100644
--- a/Common/ArmABI.cpp
+++ b/Common/ArmABI.cpp
@@ -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?
-
- }
}
diff --git a/Common/ArmEmitter.cpp b/Common/ArmEmitter.cpp
index 4cd923b1f..219595471 100644
--- a/Common/ArmEmitter.cpp
+++ b/Common/ArmEmitter.cpp
@@ -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;
diff --git a/Common/ArmEmitter.h b/Common/ArmEmitter.h
index 02dd5aa5e..c3eb8d651 100644
--- a/Common/ArmEmitter.h
+++ b/Common/ArmEmitter.h
@@ -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);
diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
index 58cd2ac38..85d3a82b1 100644
--- a/Common/Common.vcxproj
+++ b/Common/Common.vcxproj
@@ -233,6 +233,12 @@
+
+ true
+ true
+ true
+ true
+
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
index a5d92010a..14140af67 100644
--- a/Common/Common.vcxproj.filters
+++ b/Common/Common.vcxproj.filters
@@ -75,5 +75,6 @@
+
\ No newline at end of file
diff --git a/Common/Thunk.h b/Common/Thunk.h
index ac40babe4..68bbfa82f 100644
--- a/Common/Thunk.h
+++ b/Common/Thunk.h
@@ -21,7 +21,11 @@
#include