From 5878f28fcad2cb36078645867130fc80abcfc298 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 2 Nov 2012 11:58:56 +0100 Subject: [PATCH] Merge Ryan's latest ARM emitter work from Dolphin --- Common/ArmABI.cpp | 89 ++++++---- Common/ArmEmitter.cpp | 319 ++++++++++++++++++++++------------ Common/ArmEmitter.h | 290 ++++++++++++++++++------------- Common/Common.vcxproj | 6 + Common/Common.vcxproj.filters | 1 + Common/Thunk.h | 9 +- Common/ThunkArm.cpp | 55 ++++++ Core/MIPS/ARM/Asm.cpp | 4 +- Core/MIPS/ARM/CompALU.cpp | 8 +- android/jni/Android.mk | 2 + 10 files changed, 512 insertions(+), 271 deletions(-) create mode 100644 Common/ThunkArm.cpp diff --git a/Common/ArmABI.cpp b/Common/ArmABI.cpp index c72e8348f3..6792edb977 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 4cd923b1fc..219595471b 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 02dd5aa5ee..c3eb8d6510 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 58cd2ac38a..85d3a82b1e 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 a5d92010af..14140af678 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 ac40babe4c..68bbfa82f0 100644 --- a/Common/Thunk.h +++ b/Common/Thunk.h @@ -21,7 +21,11 @@ #include #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 thunks; diff --git a/Common/ThunkArm.cpp b/Common/ThunkArm.cpp new file mode 100644 index 0000000000..98cee1683d --- /dev/null +++ b/Common/ThunkArm.cpp @@ -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 + +#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) +{ +} diff --git a/Core/MIPS/ARM/Asm.cpp b/Core/MIPS/ARM/Asm.cpp index 438728f519..61106d6ee2 100644 --- a/Core/MIPS/ARM/Asm.cpp +++ b/Core/MIPS/ARM/Asm.cpp @@ -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(); diff --git a/Core/MIPS/ARM/CompALU.cpp b/Core/MIPS/ARM/CompALU.cpp index 08b88a1699..e15bab92f0 100644 --- a/Core/MIPS/ARM/CompALU.cpp +++ b/Core/MIPS/ARM/CompALU.cpp @@ -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; diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 003a19c78f..f94cdb3161 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -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 \