mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-09-11 15:13:37 +02:00
ARM64 emitter work, dispatcher work, etc. More work needed.
This commit is contained in:
@@ -1328,6 +1328,22 @@ void ARM64XEmitter::MVN(ARM64Reg Rd, ARM64Reg Rm)
|
||||
{
|
||||
ORN(Rd, Is64Bit(Rd) ? SP : WSP, Rm, ArithOption(Rm, ST_LSL, 0));
|
||||
}
|
||||
void ARM64XEmitter::LSL(ARM64Reg Rd, ARM64Reg Rm, int shift)
|
||||
{
|
||||
ORR(Rd, Is64Bit(Rd) ? SP : WSP, Rm, ArithOption(Rm, ST_LSL, shift));
|
||||
}
|
||||
void ARM64XEmitter::LSR(ARM64Reg Rd, ARM64Reg Rm, int shift)
|
||||
{
|
||||
ORR(Rd, Is64Bit(Rd) ? SP : WSP, Rm, ArithOption(Rm, ST_LSR, shift));
|
||||
}
|
||||
void ARM64XEmitter::ASR(ARM64Reg Rd, ARM64Reg Rm, int shift)
|
||||
{
|
||||
ORR(Rd, Is64Bit(Rd) ? SP : WSP, Rm, ArithOption(Rm, ST_ASR, shift));
|
||||
}
|
||||
void ARM64XEmitter::ROR(ARM64Reg Rd, ARM64Reg Rm, int shift)
|
||||
{
|
||||
ORR(Rd, Is64Bit(Rd) ? SP : WSP, Rm, ArithOption(Rm, ST_ROR, shift));
|
||||
}
|
||||
|
||||
// Logical (immediate)
|
||||
void ARM64XEmitter::AND(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms)
|
||||
@@ -3023,6 +3039,7 @@ void ARM64XEmitter::ANDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch)
|
||||
if (IsImmLogical(imm, Is64Bit(Rn) ? 64 : 32, &n, &imm_s, &imm_r)) {
|
||||
AND(Rd, Rn, imm_r, imm_s);
|
||||
} else {
|
||||
_assert_msg_(JIT, scratch != INVALID_REG, "ANDSI2R - failed to construct immediate value from %08x, need scratch", (u32)imm)
|
||||
MOVI2R(scratch, imm);
|
||||
AND(Rd, Rn, scratch);
|
||||
}
|
||||
@@ -3033,6 +3050,7 @@ void ARM64XEmitter::ORI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) {
|
||||
if (IsImmLogical(imm, Is64Bit(Rn) ? 64 : 32, &n, &imm_s, &imm_r)) {
|
||||
ORR(Rd, Rn, imm_r, imm_s);
|
||||
} else {
|
||||
_assert_msg_(JIT, scratch != INVALID_REG, "ORI2R - failed to construct immediate value from %08x, need scratch", (u32)imm)
|
||||
MOVI2R(scratch, imm);
|
||||
ORR(Rd, Rn, scratch);
|
||||
}
|
||||
@@ -3043,6 +3061,7 @@ void ARM64XEmitter::ANDSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch)
|
||||
if (IsImmLogical(imm, Is64Bit(Rn) ? 64 : 32, &n, &imm_s, &imm_r)) {
|
||||
ANDS(Rd, Rn, imm_r, imm_s);
|
||||
} else {
|
||||
_assert_msg_(JIT, scratch != INVALID_REG, "ANDSI2R - failed to construct immediate value from %08x, need scratch", (u32)imm)
|
||||
MOVI2R(scratch, imm);
|
||||
ANDS(Rd, Rn, scratch);
|
||||
}
|
||||
|
||||
+14
-5
@@ -511,8 +511,13 @@ public:
|
||||
void ANDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { ANDS(Rd, Rn, Rm, ArithOption(Rd, 0)); }
|
||||
void BICS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { BICS(Rd, Rn, Rm, ArithOption(Rd, 0)); }
|
||||
|
||||
// Convenience wrappers around ORR. These match the official convenience syntax.
|
||||
void MOV(ARM64Reg Rd, ARM64Reg Rm);
|
||||
void MVN(ARM64Reg Rd, ARM64Reg Rm);
|
||||
void LSR(ARM64Reg Rd, ARM64Reg Rm, int shift);
|
||||
void LSL(ARM64Reg Rd, ARM64Reg Rm, int shift);
|
||||
void ASR(ARM64Reg Rd, ARM64Reg Rm, int shift);
|
||||
void ROR(ARM64Reg Rd, ARM64Reg Rm, int shift);
|
||||
|
||||
// Logical (immediate)
|
||||
void AND(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms);
|
||||
@@ -621,12 +626,16 @@ public:
|
||||
|
||||
// Wrapper around MOVZ+MOVK
|
||||
void MOVI2R(ARM64Reg Rd, u64 imm, bool optimize = true);
|
||||
template <class P>
|
||||
void MOVP2R(ARM64Reg Rd, P *ptr) {
|
||||
MOVI2R(Rd, (uintptr_t)ptr);
|
||||
}
|
||||
|
||||
// Wrapper around AND x, y, imm etc
|
||||
void ANDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch);
|
||||
void ANDSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch);
|
||||
void TSTI2R(ARM64Reg Rn, u64 imm, ARM64Reg scratch) { ANDSI2R(Is64Bit(Rn) ? SP : WSP, Rn, imm, scratch); }
|
||||
void ORI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch);
|
||||
// Wrapper around AND x, y, imm etc. If you are sure the imm will work, no need to pass a scratch register.
|
||||
void ANDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG);
|
||||
void ANDSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG);
|
||||
void TSTI2R(ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG) { ANDSI2R(Is64Bit(Rn) ? SP : WSP, Rn, imm, scratch); }
|
||||
void ORI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG);
|
||||
|
||||
// ABI related
|
||||
void ABI_PushRegisters(BitSet32 registers);
|
||||
|
||||
+146
-13
@@ -35,7 +35,23 @@ static const bool enableDebug = false;
|
||||
|
||||
//static bool enableStatistics = false; //unused?
|
||||
|
||||
//The standard ARM calling convention allocates the 16 ARM registers as:
|
||||
|
||||
// ARM64 calling conventions
|
||||
// Standard: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
|
||||
// Apple: https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html
|
||||
|
||||
// Summary:
|
||||
// ===========
|
||||
// SP ("x31") is not a GPR so irrelevant.
|
||||
// x0-x7: 8 parameter/result registers
|
||||
// x8: "Indirect result location register" (points to struct return values? I think we can map this)
|
||||
// x9-x15: 7 temporary registers (no need to save)
|
||||
// x16: temporary register/procedure call scratch register 1
|
||||
// x17: temporary register/procedure call scratch register 2
|
||||
// x18: unavailable (reserved for use by the OS or linker or whatever - iOS, for example, uses it)
|
||||
// x19-x28: 10 callee-saved registers
|
||||
// x29: the frame pointer register
|
||||
// x30: link register for procedure calls
|
||||
|
||||
// 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).
|
||||
@@ -44,13 +60,19 @@ static const bool enableDebug = false;
|
||||
// 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.
|
||||
|
||||
// Mappable registers:
|
||||
// R2, R3, R4, R5, R6, R8, R11
|
||||
// So: Scratch registers: x16, x17
|
||||
// Mappable registers in priority order:
|
||||
// x19, x20, x21, x22, x23, x24, x25, x27, x28, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x0, x1,
|
||||
// That's a whole lot of registers so we might be able to statically allocate a bunch of common MIPS registers.
|
||||
// We should put statically allocated registers in the 7 callee-save regs that are left over after the system regs (x19-x25), so we don't have to bother with
|
||||
// saving them when we call out of the JIT. We will perform regular dynamic register allocation in the rest (x0-x15)
|
||||
|
||||
// STATIC ALLOCATION ARM64 (these are all callee-save registers):
|
||||
// x26 : JIT base reg
|
||||
// x27 : MIPS state
|
||||
// x28 : Memory base pointer.
|
||||
// x29 : Down counter
|
||||
|
||||
// STATIC ALLOCATION ARM:
|
||||
// R10 : MIPS state
|
||||
// R11 : Memory base pointer.
|
||||
// R7 : Down counter
|
||||
extern volatile CoreState coreState;
|
||||
|
||||
void ShowPC(u32 sp) {
|
||||
@@ -71,12 +93,123 @@ namespace MIPSComp {
|
||||
|
||||
using namespace Arm64JitConstants;
|
||||
|
||||
void Arm64Jit::GenerateFixedCode()
|
||||
{
|
||||
// Uncomment if you want to see the output...
|
||||
// INFO_LOG(JIT, "THE DISASM ========================");
|
||||
// DisassembleArm(enterCode, GetCodePtr() - enterCode);
|
||||
// INFO_LOG(JIT, "END OF THE DISASM ========================");
|
||||
void Arm64Jit::GenerateFixedCode() {
|
||||
enterCode = AlignCode16();
|
||||
|
||||
const u32 ALL_CALLEE_SAVED = 0x7FF80000;
|
||||
BitSet32 regs_to_save(ALL_CALLEE_SAVED);
|
||||
enterCode = GetCodePtr();
|
||||
|
||||
ABI_PushRegisters(regs_to_save);
|
||||
|
||||
|
||||
// Fixed registers, these are always kept when in Jit context.
|
||||
// R8 is used to hold flags during delay slots. Not always needed.
|
||||
// R13 cannot be used as it's the stack pointer.
|
||||
// TODO: Consider statically allocating:
|
||||
// * r2-r4
|
||||
// Really starting to run low on registers already though...
|
||||
|
||||
// R11, R10, R9
|
||||
MOVP2R(MEMBASEREG, Memory::base);
|
||||
MOVP2R(CTXREG, mips_);
|
||||
MOVP2R(JITBASEREG, GetBasePtr());
|
||||
|
||||
// TODO: Preserve ASIMD registers
|
||||
|
||||
RestoreDowncount();
|
||||
MovFromPC(SCRATCH1);
|
||||
outerLoopPCInR0 = GetCodePtr();
|
||||
MovToPC(SCRATCH1);
|
||||
outerLoop = GetCodePtr();
|
||||
SaveDowncount();
|
||||
RestoreRoundingMode(true);
|
||||
QuickCallFunction(SCRATCH1_64, &CoreTiming::Advance);
|
||||
ApplyRoundingMode(true);
|
||||
RestoreDowncount();
|
||||
FixupBranch skipToRealDispatch = B(); //skip the sync and compare first time
|
||||
|
||||
dispatcherCheckCoreState = GetCodePtr();
|
||||
|
||||
// The result of slice decrementation should be in flags if somebody jumped here
|
||||
// IMPORTANT - We jump on negative, not carry!!!
|
||||
FixupBranch bailCoreState = B(CC_MI);
|
||||
|
||||
MOVP2R(SCRATCH1_64, &coreState);
|
||||
LDR(INDEX_UNSIGNED, SCRATCH1, SCRATCH1_64, 0);
|
||||
CMP(SCRATCH1, 0);
|
||||
FixupBranch badCoreState = B(CC_NEQ);
|
||||
FixupBranch skipToRealDispatch2 = B(); //skip the sync and compare first time
|
||||
|
||||
dispatcherPCInSCRATCH1 = GetCodePtr();
|
||||
// TODO: Do we always need to write PC to RAM here?
|
||||
MovToPC(SCRATCH1);
|
||||
|
||||
// At this point : flags = EQ. Fine for the next check, no need to jump over it.
|
||||
dispatcher = GetCodePtr();
|
||||
|
||||
// The result of slice decrementation should be in flags if somebody jumped here
|
||||
// IMPORTANT - We jump on negative, not carry!!!
|
||||
FixupBranch bail = B(CC_MI);
|
||||
|
||||
SetJumpTarget(skipToRealDispatch);
|
||||
SetJumpTarget(skipToRealDispatch2);
|
||||
|
||||
dispatcherNoCheck = GetCodePtr();
|
||||
|
||||
// Debug
|
||||
if (enableDebug) {
|
||||
// MOV(SCRATCH1, R13);
|
||||
// QuickCallFunction(R1, (void *)&ShowPC);
|
||||
}
|
||||
|
||||
LDR(INDEX_UNSIGNED, SCRATCH1, CTXREG, offsetof(MIPSState, pc));
|
||||
LDR(SCRATCH1, MEMBASEREG, SCRATCH1_64);
|
||||
ANDI2R(SCRATCH2, SCRATCH1, 0xFF000000); // rotation is to the right, in 2-bit increments.
|
||||
ANDI2R(SCRATCH1, SCRATCH1, 0x00FFFFFF); // TODO: Replace this and the next op by a bit field extract
|
||||
LSR(SCRATCH2, SCRATCH2, 24);
|
||||
CMP(SCRATCH2, MIPS_EMUHACK_OPCODE);
|
||||
FixupBranch skipJump = B(CC_NEQ);
|
||||
// IDEA - we have 26 bits, why not just use offsets from base of code?
|
||||
// Another idea: Shift the bloc number left by two in the op, this would let us do
|
||||
// LDR(R0, R9, R0); here, replacing the next instructions.
|
||||
#ifdef IOS
|
||||
// On iOS, R9 (JITBASEREG) is volatile. We have to reload it.
|
||||
MOVI2R(JITBASEREG, (u32)GetBasePtr());
|
||||
#endif
|
||||
ADD(SCRATCH1_64, SCRATCH1_64, JITBASEREG);
|
||||
BR(SCRATCH1_64);
|
||||
SetJumpTarget(skipJump);
|
||||
// No block found, let's jit
|
||||
SaveDowncount();
|
||||
RestoreRoundingMode(true);
|
||||
QuickCallFunction(SCRATCH1_64, (void *)&MIPSComp::JitAt);
|
||||
ApplyRoundingMode(true);
|
||||
RestoreDowncount();
|
||||
|
||||
B(dispatcherNoCheck); // no point in special casing this
|
||||
|
||||
SetJumpTarget(bail);
|
||||
SetJumpTarget(bailCoreState);
|
||||
|
||||
MOVP2R(SCRATCH1_64, &coreState);
|
||||
LDR(INDEX_UNSIGNED, SCRATCH1, SCRATCH1_64, 0);
|
||||
CMP(SCRATCH1, 0);
|
||||
B(CC_EQ, outerLoop);
|
||||
|
||||
SetJumpTarget(badCoreState);
|
||||
breakpointBailout = GetCodePtr();
|
||||
|
||||
// TODO: Restore ASIMD registers
|
||||
|
||||
SaveDowncount();
|
||||
RestoreRoundingMode(true);
|
||||
|
||||
ABI_PopRegisters(regs_to_save);
|
||||
|
||||
INFO_LOG(JIT, "THE DISASM ========================");
|
||||
DisassembleArm64(enterCode, GetCodePtr() - enterCode);
|
||||
INFO_LOG(JIT, "END OF THE DISASM ========================");
|
||||
|
||||
// Don't forget to zap the instruction cache!
|
||||
FlushIcache();
|
||||
|
||||
@@ -244,8 +244,8 @@ void Arm64Jit::BranchRSZeroComp(MIPSOpcode op, CCFlags cc, bool andLink, bool li
|
||||
// Take the branch
|
||||
if (andLink)
|
||||
{
|
||||
gpr.SetRegImm(SCRATCHREG1, js.compilerPC + 8);
|
||||
STR(INDEX_UNSIGNED, SCRATCHREG1, CTXREG, MIPS_REG_RA * 4);
|
||||
gpr.SetRegImm(SCRATCH1, js.compilerPC + 8);
|
||||
STR(INDEX_UNSIGNED, SCRATCH1, CTXREG, MIPS_REG_RA * 4);
|
||||
}
|
||||
|
||||
WriteExit(targetAddr, js.nextExit++);
|
||||
|
||||
@@ -104,20 +104,20 @@ void Arm64Jit::FlushAll()
|
||||
void Arm64Jit::FlushPrefixV()
|
||||
{
|
||||
if ((js.prefixSFlag & JitState::PREFIX_DIRTY) != 0) {
|
||||
gpr.SetRegImm(SCRATCHREG1, js.prefixS);
|
||||
STR(INDEX_UNSIGNED, SCRATCHREG1, CTXREG, offsetof(MIPSState, vfpuCtrl[VFPU_CTRL_SPREFIX]));
|
||||
gpr.SetRegImm(SCRATCH1, js.prefixS);
|
||||
STR(INDEX_UNSIGNED, SCRATCH1, CTXREG, offsetof(MIPSState, vfpuCtrl[VFPU_CTRL_SPREFIX]));
|
||||
js.prefixSFlag = (JitState::PrefixState) (js.prefixSFlag & ~JitState::PREFIX_DIRTY);
|
||||
}
|
||||
|
||||
if ((js.prefixTFlag & JitState::PREFIX_DIRTY) != 0) {
|
||||
gpr.SetRegImm(SCRATCHREG1, js.prefixT);
|
||||
STR(INDEX_UNSIGNED, SCRATCHREG1, CTXREG, offsetof(MIPSState, vfpuCtrl[VFPU_CTRL_TPREFIX]));
|
||||
gpr.SetRegImm(SCRATCH1, js.prefixT);
|
||||
STR(INDEX_UNSIGNED, SCRATCH1, CTXREG, offsetof(MIPSState, vfpuCtrl[VFPU_CTRL_TPREFIX]));
|
||||
js.prefixTFlag = (JitState::PrefixState) (js.prefixTFlag & ~JitState::PREFIX_DIRTY);
|
||||
}
|
||||
|
||||
if ((js.prefixDFlag & JitState::PREFIX_DIRTY) != 0) {
|
||||
gpr.SetRegImm(SCRATCHREG1, js.prefixD);
|
||||
STR(INDEX_UNSIGNED, SCRATCHREG1, CTXREG, offsetof(MIPSState, vfpuCtrl[VFPU_CTRL_DPREFIX]));
|
||||
gpr.SetRegImm(SCRATCH1, js.prefixD);
|
||||
STR(INDEX_UNSIGNED, SCRATCH1, CTXREG, offsetof(MIPSState, vfpuCtrl[VFPU_CTRL_DPREFIX]));
|
||||
js.prefixDFlag = (JitState::PrefixState) (js.prefixDFlag & ~JitState::PREFIX_DIRTY);
|
||||
}
|
||||
}
|
||||
@@ -442,7 +442,7 @@ void Arm64Jit::WriteExit(u32 destination, int exit_num)
|
||||
b->linkStatus[exit_num] = true;
|
||||
} else {
|
||||
gpr.SetRegImm(X0, destination);
|
||||
B((const void *)dispatcherPCInR0);
|
||||
B((const void *)dispatcherPCInSCRATCH1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -280,7 +280,7 @@ public:
|
||||
const u8 *outerLoop;
|
||||
const u8 *outerLoopPCInR0;
|
||||
const u8 *dispatcherCheckCoreState;
|
||||
const u8 *dispatcherPCInR0;
|
||||
const u8 *dispatcherPCInSCRATCH1;
|
||||
const u8 *dispatcher;
|
||||
const u8 *dispatcherNoCheck;
|
||||
|
||||
|
||||
@@ -328,8 +328,8 @@ void Arm64RegCache::FlushR(MIPSGPReg r) {
|
||||
case ML_IMM:
|
||||
// IMM is always "dirty".
|
||||
if (r != MIPS_REG_ZERO) {
|
||||
SetRegImm(SCRATCHREG1, mr[r].imm);
|
||||
emit_->STR(INDEX_UNSIGNED, SCRATCHREG1, CTXREG, GetMipsRegOffset(r));
|
||||
SetRegImm(SCRATCH1, mr[r].imm);
|
||||
emit_->STR(INDEX_UNSIGNED, SCRATCH1, CTXREG, GetMipsRegOffset(r));
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -24,12 +24,14 @@
|
||||
namespace Arm64JitConstants {
|
||||
|
||||
// Bogus mappings, TODO ARM64
|
||||
const Arm64Gen::ARM64Reg JITBASEREG = Arm64Gen::W0;
|
||||
const Arm64Gen::ARM64Reg CTXREG = Arm64Gen::X1;
|
||||
const Arm64Gen::ARM64Reg MEMBASEREG = Arm64Gen::X2;
|
||||
const Arm64Gen::ARM64Reg SCRATCHREG1 = Arm64Gen::W3;
|
||||
const Arm64Gen::ARM64Reg SCRATCHREG2 = Arm64Gen::W4;
|
||||
const Arm64Gen::ARM64Reg DOWNCOUNTREG = Arm64Gen::W5;
|
||||
const Arm64Gen::ARM64Reg JITBASEREG = Arm64Gen::X26;
|
||||
const Arm64Gen::ARM64Reg CTXREG = Arm64Gen::X27;
|
||||
const Arm64Gen::ARM64Reg MEMBASEREG = Arm64Gen::X28;
|
||||
const Arm64Gen::ARM64Reg DOWNCOUNTREG = Arm64Gen::W29; // no need to use the full register width
|
||||
const Arm64Gen::ARM64Reg SCRATCH1_64 = Arm64Gen::X16;
|
||||
const Arm64Gen::ARM64Reg SCRATCH2_64 = Arm64Gen::X17;
|
||||
const Arm64Gen::ARM64Reg SCRATCH1 = Arm64Gen::W16;
|
||||
const Arm64Gen::ARM64Reg SCRATCH2 = Arm64Gen::W17;
|
||||
|
||||
enum {
|
||||
TOTAL_MAPPABLE_MIPSREGS = 36,
|
||||
|
||||
@@ -631,6 +631,9 @@ void JitCompareScreen::UpdateDisasm() {
|
||||
}
|
||||
|
||||
UI::EventReturn JitCompareScreen::OnAddressChange(UI::EventParams &e) {
|
||||
if (!MIPSComp::jit) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
|
||||
u32 addr;
|
||||
if (blockAddr_->GetText().size() > 8)
|
||||
@@ -666,6 +669,10 @@ UI::EventReturn JitCompareScreen::OnNextBlock(UI::EventParams &e) {
|
||||
}
|
||||
|
||||
UI::EventReturn JitCompareScreen::OnBlockAddress(UI::EventParams &e) {
|
||||
if (!MIPSComp::jit) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
|
||||
if (Memory::IsValidAddress(e.a)) {
|
||||
currentBlock_ = blockCache->GetBlockNumberFromStartAddress(e.a);
|
||||
@@ -677,6 +684,10 @@ UI::EventReturn JitCompareScreen::OnBlockAddress(UI::EventParams &e) {
|
||||
}
|
||||
|
||||
UI::EventReturn JitCompareScreen::OnRandomBlock(UI::EventParams &e) {
|
||||
if (!MIPSComp::jit) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
|
||||
int numBlocks = blockCache->GetNumBlocks();
|
||||
if (numBlocks > 0) {
|
||||
@@ -687,6 +698,9 @@ UI::EventReturn JitCompareScreen::OnRandomBlock(UI::EventParams &e) {
|
||||
}
|
||||
|
||||
UI::EventReturn JitCompareScreen::OnRandomVFPUBlock(UI::EventParams &e) {
|
||||
if (!MIPSComp::jit) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
|
||||
int numBlocks = blockCache->GetNumBlocks();
|
||||
if (numBlocks > 0) {
|
||||
@@ -714,6 +728,9 @@ UI::EventReturn JitCompareScreen::OnRandomVFPUBlock(UI::EventParams &e) {
|
||||
|
||||
|
||||
UI::EventReturn JitCompareScreen::OnCurrentBlock(UI::EventParams &e) {
|
||||
if (!MIPSComp::jit) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
|
||||
std::vector<int> blockNum;
|
||||
blockCache->GetBlockNumbersFromAddress(currentMIPS->pc, &blockNum);
|
||||
|
||||
@@ -439,6 +439,12 @@ void LogoScreen::render() {
|
||||
|
||||
#ifdef _WIN32
|
||||
dc.DrawText(screenManager()->getThin3DContext()->GetInfoString(T3DInfo::APINAME), bounds.centerX(), bounds.y2() - 100, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER);
|
||||
#elif defined(ANDROID)
|
||||
#ifdef ARM64
|
||||
dc.SetFontScale(2.0f, 2.0f);
|
||||
dc.DrawText("EXPERIMENTAL ARM64 BUILD", bounds.centerX(), bounds.y2() - 100, colorAlpha(0xFF3030FF, alphaText), ALIGN_CENTER);
|
||||
dc.SetFontScale(1.0f, 1.0f);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
dc.End();
|
||||
|
||||
Reference in New Issue
Block a user