2012-11-01 16:19:01 +01:00
|
|
|
// Copyright (c) 2012- PPSSPP 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
|
2012-11-04 23:58:25 +01:00
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
2012-11-01 16:19:01 +01:00
|
|
|
|
|
|
|
|
// 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 git repository and contact information can be found at
|
|
|
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
|
|
2013-01-07 22:33:09 +01:00
|
|
|
#include "ArmEmitter.h"
|
|
|
|
|
#include "ArmABI.h"
|
2012-11-01 16:19:01 +01:00
|
|
|
|
2012-11-05 23:09:49 +10:00
|
|
|
#include "../../MemMap.h"
|
2012-11-01 16:19:01 +01:00
|
|
|
|
|
|
|
|
#include "../MIPS.h"
|
|
|
|
|
#include "../../CoreTiming.h"
|
|
|
|
|
#include "MemoryUtil.h"
|
|
|
|
|
|
2013-01-07 22:33:09 +01:00
|
|
|
#include "ArmJit.h"
|
2012-11-01 16:19:01 +01:00
|
|
|
#include "../JitCommon/JitCommon.h"
|
|
|
|
|
#include "../../Core.h"
|
2013-01-07 22:33:09 +01:00
|
|
|
#include "ArmAsm.h"
|
2012-11-01 16:19:01 +01:00
|
|
|
|
|
|
|
|
using namespace ArmGen;
|
|
|
|
|
|
|
|
|
|
//static int temp32; // unused?
|
|
|
|
|
|
|
|
|
|
//TODO - make an option
|
|
|
|
|
//#if _DEBUG
|
|
|
|
|
static bool enableDebug = false;
|
|
|
|
|
//#else
|
|
|
|
|
// bool enableDebug = false;
|
|
|
|
|
//#endif
|
|
|
|
|
|
|
|
|
|
//static bool enableStatistics = false; //unused?
|
|
|
|
|
|
|
|
|
|
//The standard ARM calling convention allocates the 16 ARM registers as:
|
|
|
|
|
|
|
|
|
|
// r15 is the program counter.
|
|
|
|
|
// r14 is the link register. (The BL instruction, used in a subroutine call, stores the return address in this register).
|
|
|
|
|
// r13 is the stack pointer. (The Push/Pop instructions in "Thumb" operating mode use this register only).
|
|
|
|
|
// r12 is the Intra-Procedure-call scratch register.
|
|
|
|
|
// r4 to r11: used to hold local variables.
|
|
|
|
|
// r0 to r3: used to hold argument values passed to a subroutine, and also hold results returned from a subroutine.
|
|
|
|
|
|
|
|
|
|
// R2, R3, R4, R5, R6, R7, R8, R10, R11 // omitting R9?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// STATIC ALLOCATION ARM:
|
|
|
|
|
// R11 : Memory base pointer.
|
2013-01-08 00:26:42 +01:00
|
|
|
// R10 : MIPS state
|
|
|
|
|
// R9 :
|
2012-11-01 16:19:01 +01:00
|
|
|
extern volatile CoreState coreState;
|
|
|
|
|
|
|
|
|
|
void Jit()
|
|
|
|
|
{
|
2013-01-08 13:49:52 +01:00
|
|
|
INFO_LOG(HLE, "Compiling at %08x", currentMIPS->pc);
|
2012-11-01 16:19:01 +01:00
|
|
|
MIPSComp::jit->Compile(currentMIPS->pc);
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-08 00:26:42 +01:00
|
|
|
void ImHere() {
|
|
|
|
|
static int i = 0;
|
|
|
|
|
i++;
|
|
|
|
|
INFO_LOG(HLE, "I'm too here %i", i);
|
|
|
|
|
}
|
2013-01-08 13:49:52 +01:00
|
|
|
void ImHere2(u32 hej, u32 hej2) {
|
2013-01-08 00:26:42 +01:00
|
|
|
static int i = 0;
|
|
|
|
|
i++;
|
2013-01-08 13:49:52 +01:00
|
|
|
INFO_LOG(HLE, "I'm here2 %i %08x %08x", i, hej, hej2);
|
2013-01-08 00:26:42 +01:00
|
|
|
}
|
2012-11-01 16:19:01 +01:00
|
|
|
// PLAN: no more block numbers - crazy opcodes just contain offset within
|
|
|
|
|
// dynarec buffer
|
|
|
|
|
// At this offset - 4, there is an int specifying the block number.
|
|
|
|
|
|
2013-01-08 00:26:42 +01:00
|
|
|
void ArmAsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit)
|
2012-11-01 16:19:01 +01:00
|
|
|
{
|
|
|
|
|
enterCode = AlignCode16();
|
|
|
|
|
|
2013-01-08 13:49:52 +01:00
|
|
|
INFO_LOG(HLE, "Base: %08x", (u32)Memory::base);
|
|
|
|
|
|
2012-11-01 16:19:01 +01:00
|
|
|
SetCC(CC_AL);
|
2013-01-07 22:33:09 +01:00
|
|
|
|
2013-01-08 00:26:42 +01:00
|
|
|
PUSH(8, R5, R6, R7, R8, R9, R10, R11, _LR);
|
|
|
|
|
|
2013-01-07 22:33:09 +01:00
|
|
|
// Fixed registers, these are always kept when in Jit context.
|
|
|
|
|
// R13 cannot be used as it's the stack pointer.
|
|
|
|
|
ARMABI_MOVI2R(R11, (u32)Memory::base);
|
2013-01-08 00:26:42 +01:00
|
|
|
ARMABI_MOVI2R(R10, (u32)mips);
|
|
|
|
|
ARMABI_MOVI2R(R9, (u32)jit->GetBlockCache()->GetCodePointers());
|
|
|
|
|
|
|
|
|
|
// PROVEN: We Get Here
|
|
|
|
|
ARMABI_CallFunction((void *)&ImHere);
|
2012-11-01 16:19:01 +01:00
|
|
|
|
|
|
|
|
outerLoop = GetCodePtr();
|
2013-01-08 00:26:42 +01:00
|
|
|
ARMABI_CallFunction((void *)&CoreTiming::Advance);
|
2012-11-01 16:19:01 +01:00
|
|
|
FixupBranch skipToRealDispatch = B(); //skip the sync and compare first time
|
2013-01-07 22:33:09 +01:00
|
|
|
|
|
|
|
|
dispatcherCheckCoreState = GetCodePtr();
|
|
|
|
|
|
2013-01-08 00:26:42 +01:00
|
|
|
// TODO: critical
|
|
|
|
|
ARMABI_MOVI2R(R0, (u32)&coreState);
|
|
|
|
|
LDR(R0, R0);
|
|
|
|
|
CMP(R0, 0);
|
|
|
|
|
FixupBranch badCoreState = B_CC(CC_NEQ);
|
|
|
|
|
|
|
|
|
|
// At this point : flags = EQ. Fine for the next check, no need to jump over it.
|
2013-01-07 22:33:09 +01:00
|
|
|
|
2012-11-01 16:19:01 +01:00
|
|
|
dispatcher = GetCodePtr();
|
|
|
|
|
// The result of slice decrementation should be in flags if somebody jumped here
|
|
|
|
|
// IMPORTANT - We jump on negative, not carry!!!
|
2013-01-08 00:26:42 +01:00
|
|
|
FixupBranch bail = B_CC(CC_LT);
|
|
|
|
|
|
2012-11-01 16:19:01 +01:00
|
|
|
SetJumpTarget(skipToRealDispatch);
|
|
|
|
|
|
|
|
|
|
dispatcherNoCheck = GetCodePtr();
|
|
|
|
|
|
2013-01-08 00:26:42 +01:00
|
|
|
// Debug
|
|
|
|
|
|
|
|
|
|
ARMABI_MOVI2R(R0, (u32)&mips->pc);
|
|
|
|
|
LDR(R0, R0);
|
|
|
|
|
|
|
|
|
|
ARMABI_MOVI2R(R1, Memory::MEMVIEW32_MASK); // can be done with single MOVN instruction
|
2012-11-01 16:19:01 +01:00
|
|
|
AND(R0, R0, R1);
|
2013-01-08 13:49:52 +01:00
|
|
|
ADD(R0, R0, R11); // TODO: Optimize (can merge with next instr)
|
|
|
|
|
LDR(R0, R0);
|
2013-01-08 00:26:42 +01:00
|
|
|
AND(R1, R0, Operand2(0xFC, 4)); // rotation is to the right, in 2-bit increments.
|
|
|
|
|
BIC(R0, R0, Operand2(0xFC, 4));
|
|
|
|
|
CMP(R1, Operand2(MIPS_EMUHACK_OPCODE >> 24, 4));
|
2012-11-23 19:41:35 +01:00
|
|
|
FixupBranch notfound = B_CC(CC_NEQ);
|
2012-11-01 16:19:01 +01:00
|
|
|
// IDEA - we have 24 bits, why not just use offsets from base of code?
|
|
|
|
|
if (enableDebug)
|
|
|
|
|
{
|
2012-11-23 19:41:35 +01:00
|
|
|
//ADD(32, M(&mips->debugCount), Imm8(1));
|
2012-11-01 16:19:01 +01:00
|
|
|
}
|
2012-11-23 19:41:35 +01:00
|
|
|
// grab from list and jump to it
|
2013-01-08 13:49:52 +01:00
|
|
|
ADD(R0, R9, Operand2(2, ST_LSL, R0));
|
2012-11-23 19:41:35 +01:00
|
|
|
LDR(R0, R0);
|
2012-11-02 11:58:56 +01:00
|
|
|
B(R0);
|
2013-01-08 00:26:42 +01:00
|
|
|
|
2012-11-01 16:19:01 +01:00
|
|
|
SetJumpTarget(notfound);
|
|
|
|
|
|
2013-01-08 00:26:42 +01:00
|
|
|
//Ok, no block, let's jit
|
2012-11-23 19:41:35 +01:00
|
|
|
ARMABI_CallFunction((void *)&Jit);
|
2013-01-08 00:26:42 +01:00
|
|
|
|
2012-11-23 19:41:35 +01:00
|
|
|
B(dispatcherNoCheck); // no point in special casing this
|
2012-11-01 16:19:01 +01:00
|
|
|
|
|
|
|
|
SetJumpTarget(bail);
|
|
|
|
|
|
2013-01-08 00:26:42 +01:00
|
|
|
// TODO: critical
|
|
|
|
|
ARMABI_MOVI2R(R0, (u32)&coreState);
|
|
|
|
|
LDR(R0, R0);
|
|
|
|
|
CMP(R0, 0);
|
|
|
|
|
B_CC(CC_EQ, outerLoop);
|
2012-11-01 16:19:01 +01:00
|
|
|
|
2013-01-08 00:26:42 +01:00
|
|
|
SetJumpTarget(badCoreState);
|
2012-11-01 16:19:01 +01:00
|
|
|
|
2013-01-08 00:26:42 +01:00
|
|
|
ARMABI_CallFunction((void *)&ImHere);
|
2012-11-01 16:19:01 +01:00
|
|
|
|
2013-01-08 00:26:42 +01:00
|
|
|
//Landing pad for drec space
|
|
|
|
|
|
|
|
|
|
POP(8, R5, R6, R7, R8, R9, R10, R11, _PC); // Returns
|
2013-01-07 22:33:09 +01:00
|
|
|
}
|