mirror of
https://github.com/libretro/ppsspp.git
synced 2025-02-26 11:45:26 +00:00
mips: Add smarter delay slot handling to emitter.
This commit is contained in:
parent
0d2c7846f5
commit
e2e97a8f4e
@ -15,6 +15,11 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
// Symbian can't build this due to an old gcc/lib combination, and doesn't need to.
|
||||
// Kind programmer, if you want to translate this to a proper feature-detection
|
||||
// define, please feel free to.
|
||||
#ifndef __SYMBIAN32__
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
#include <assert.h>
|
||||
@ -80,98 +85,107 @@ void MIPSEmitter::BREAK(u32 code) {
|
||||
Write32Fields(26, 0x00, 6, code & 0xfffff, 0, 0x0d);
|
||||
}
|
||||
|
||||
FixupBranch MIPSEmitter::J() {
|
||||
FixupBranch MIPSEmitter::J(std::function<void ()> delaySlot) {
|
||||
// 000010 iiiiiiiiiiiiiiiiiiiiiiiiii (fix up)
|
||||
FixupBranch b = MakeFixupBranch(BRANCH_26);
|
||||
Write32Fields(26, 0x02);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
return b;
|
||||
}
|
||||
|
||||
void MIPSEmitter::J(const void *func) {
|
||||
SetJumpTarget(J(), func);
|
||||
void MIPSEmitter::J(const void *func, std::function<void ()> delaySlot) {
|
||||
SetJumpTarget(J(delaySlot), func);
|
||||
}
|
||||
|
||||
FixupBranch MIPSEmitter::JAL() {
|
||||
FixupBranch MIPSEmitter::JAL(std::function<void ()> delaySlot) {
|
||||
// 000011 iiiiiiiiiiiiiiiiiiiiiiiiii (fix up)
|
||||
FixupBranch b = MakeFixupBranch(BRANCH_26);
|
||||
Write32Fields(26, 0x03);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
return b;
|
||||
}
|
||||
|
||||
void MIPSEmitter::JAL(const void *func) {
|
||||
SetJumpTarget(JAL(), func);
|
||||
void MIPSEmitter::JAL(const void *func, std::function<void ()> delaySlot) {
|
||||
SetJumpTarget(JAL(delaySlot), func);
|
||||
}
|
||||
|
||||
void MIPSEmitter::JR(MIPSReg rs) {
|
||||
void MIPSEmitter::JR(MIPSReg rs, std::function<void ()> delaySlot) {
|
||||
// 000000 sssss xxxxxxxxxx hint- 001000 (hint must be 0.)
|
||||
_dbg_assert_msg_(JIT, rs < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 21, rs, 0, 0x08);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
}
|
||||
|
||||
void MIPSEmitter::JALR(MIPSReg rd, MIPSReg rs) {
|
||||
void MIPSEmitter::JALR(MIPSReg rd, MIPSReg rs, std::function<void ()> delaySlot) {
|
||||
// 000000 sssss xxxxx ddddd hint- 001001 (hint must be 0.)
|
||||
_dbg_assert_msg_(JIT, rs < F_BASE, "Bad emitter arguments");
|
||||
Write32Fields(26, 0x00, 21, rs, 11, rd, 0, 0x09);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
}
|
||||
|
||||
FixupBranch MIPSEmitter::BLTZ(MIPSReg rs) {
|
||||
FixupBranch MIPSEmitter::BLTZ(MIPSReg rs, std::function<void ()> delaySlot) {
|
||||
// 000001 sssss xxxxx iiiiiiiiiiiiiii (fix up)
|
||||
_dbg_assert_msg_(JIT, rs < F_BASE, "Bad emitter arguments");
|
||||
FixupBranch b = MakeFixupBranch(BRANCH_16);
|
||||
Write32Fields(26, 0x01, 21, rs);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
return b;
|
||||
}
|
||||
|
||||
void MIPSEmitter::BLTZ(MIPSReg rs, const void *func) {
|
||||
SetJumpTarget(BLTZ(rs), func);
|
||||
void MIPSEmitter::BLTZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot) {
|
||||
SetJumpTarget(BLTZ(rs, delaySlot), func);
|
||||
}
|
||||
|
||||
FixupBranch MIPSEmitter::BEQ(MIPSReg rs, MIPSReg rt) {
|
||||
FixupBranch MIPSEmitter::BEQ(MIPSReg rs, MIPSReg rt, std::function<void ()> delaySlot) {
|
||||
// 000100 sssss ttttt iiiiiiiiiiiiiii (fix up)
|
||||
_dbg_assert_msg_(JIT, rs < F_BASE && rt < F_BASE, "Bad emitter arguments");
|
||||
FixupBranch b = MakeFixupBranch(BRANCH_16);
|
||||
Write32Fields(26, 0x04, 21, rs, 16, rt);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
return b;
|
||||
}
|
||||
|
||||
void MIPSEmitter::BEQ(MIPSReg rs, MIPSReg rt, const void *func) {
|
||||
SetJumpTarget(BEQ(rs, rt), func);
|
||||
void MIPSEmitter::BEQ(MIPSReg rs, MIPSReg rt, const void *func, std::function<void ()> delaySlot) {
|
||||
SetJumpTarget(BEQ(rs, rt, delaySlot), func);
|
||||
}
|
||||
|
||||
FixupBranch MIPSEmitter::BNE(MIPSReg rs, MIPSReg rt) {
|
||||
FixupBranch MIPSEmitter::BNE(MIPSReg rs, MIPSReg rt, std::function<void ()> delaySlot) {
|
||||
// 000101 sssss ttttt iiiiiiiiiiiiiii (fix up)
|
||||
_dbg_assert_msg_(JIT, rs < F_BASE && rt < F_BASE, "Bad emitter arguments");
|
||||
FixupBranch b = MakeFixupBranch(BRANCH_16);
|
||||
Write32Fields(26, 0x05, 21, rs, 16, rt);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
return b;
|
||||
}
|
||||
|
||||
void MIPSEmitter::BNE(MIPSReg rs, MIPSReg rt, const void *func) {
|
||||
SetJumpTarget(BNE(rs, rt), func);
|
||||
void MIPSEmitter::BNE(MIPSReg rs, MIPSReg rt, const void *func, std::function<void ()> delaySlot) {
|
||||
SetJumpTarget(BNE(rs, rt, delaySlot), func);
|
||||
}
|
||||
|
||||
FixupBranch MIPSEmitter::BLEZ(MIPSReg rs) {
|
||||
FixupBranch MIPSEmitter::BLEZ(MIPSReg rs, std::function<void ()> delaySlot) {
|
||||
// 000110 sssss xxxxx iiiiiiiiiiiiiii (fix up)
|
||||
_dbg_assert_msg_(JIT, rs < F_BASE, "Bad emitter arguments");
|
||||
FixupBranch b = MakeFixupBranch(BRANCH_16);
|
||||
Write32Fields(26, 0x06, 21, rs);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
return b;
|
||||
}
|
||||
|
||||
void MIPSEmitter::BLEZ(MIPSReg rs, const void *func) {
|
||||
SetJumpTarget(BLEZ(rs), func);
|
||||
void MIPSEmitter::BLEZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot) {
|
||||
SetJumpTarget(BLEZ(rs, delaySlot), func);
|
||||
}
|
||||
|
||||
FixupBranch MIPSEmitter::BGTZ(MIPSReg rs) {
|
||||
FixupBranch MIPSEmitter::BGTZ(MIPSReg rs, std::function<void ()> delaySlot) {
|
||||
// 000111 sssss xxxxx iiiiiiiiiiiiiii (fix up)
|
||||
_dbg_assert_msg_(JIT, rs < F_BASE, "Bad emitter arguments");
|
||||
FixupBranch b = MakeFixupBranch(BRANCH_16);
|
||||
Write32Fields(26, 0x07, 21, rs);
|
||||
ApplyDelaySlot(delaySlot);
|
||||
return b;
|
||||
}
|
||||
|
||||
void MIPSEmitter::BGTZ(MIPSReg rs, const void *func) {
|
||||
SetJumpTarget(BGTZ(rs), func);
|
||||
void MIPSEmitter::BGTZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot) {
|
||||
SetJumpTarget(BGTZ(rs, delaySlot), func);
|
||||
}
|
||||
|
||||
void MIPSEmitter::SetJumpTarget(const FixupBranch &branch) {
|
||||
@ -221,6 +235,15 @@ bool MIPSEmitter::JInRange(const void *src, const void *dst) {
|
||||
return (srcp - (srcp & 0x0fffffff)) == (dstp - (dstp & 0x0fffffff));
|
||||
}
|
||||
|
||||
void MIPSEmitter::ApplyDelaySlot(std::function<void ()> delaySlot) {
|
||||
if (delaySlot) {
|
||||
delaySlot();
|
||||
} else {
|
||||
// We just insert a NOP if there's no delay slot provided. Safer.
|
||||
NOP();
|
||||
}
|
||||
}
|
||||
|
||||
void MIPSEmitter::QuickCallFunction(MIPSReg scratchreg, const void *func) {
|
||||
_dbg_assert_msg_(JIT, scratchreg < F_BASE, "Bad emitter arguments");
|
||||
if (JInRange(func)) {
|
||||
@ -470,3 +493,5 @@ void MIPSCodeBlock::UnWriteProtect() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -18,7 +18,12 @@
|
||||
// WARNING - THIS LIBRARY IS NOT THREAD SAFE!!! (cargo culted but probably true)
|
||||
|
||||
#pragma once
|
||||
// Symbian can't build this due to an old gcc/lib combination, and doesn't need to.
|
||||
// Kind programmer, if you want to translate this to a proper feature-detection
|
||||
// define, please feel free to.
|
||||
#ifndef __SYMBIAN32__
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
@ -95,47 +100,62 @@ public:
|
||||
SLL(R_ZERO, R_ZERO, 0);
|
||||
}
|
||||
|
||||
FixupBranch J();
|
||||
void J(const void *func);
|
||||
FixupBranch JAL();
|
||||
void JAL(const void *func);
|
||||
void JR(MIPSReg rs);
|
||||
void JRRA() {
|
||||
JR(R_RA);
|
||||
// Note for all branches and jumps:
|
||||
// MIPS has DELAY SLOTS. This emitter makes it so if you forget that, you'll be safe.
|
||||
// If you want to run something inside a delay slot, emit the instruction inside a closure.
|
||||
//
|
||||
// Example: Translates to:
|
||||
// J(&myFunc); J(&myFunc);
|
||||
// ADDU(V0, V0, V1); NOP();
|
||||
// ADDU(V0, V0, V1);
|
||||
//
|
||||
// J(&myFunc, [&] { J(&myFunc);
|
||||
// ADDU(V0, V0, V1); ADDU(V0, V0, V1);
|
||||
// });
|
||||
//
|
||||
// This applies to all J*() and B*() functions (except BREAK(), which is not a branch func.)
|
||||
|
||||
FixupBranch J(std::function<void ()> delaySlot = nullptr);
|
||||
void J(const void *func, std::function<void ()> delaySlot = nullptr);
|
||||
FixupBranch JAL(std::function<void ()> delaySlot = nullptr);
|
||||
void JAL(const void *func, std::function<void ()> delaySlot = nullptr);
|
||||
void JR(MIPSReg rs, std::function<void ()> delaySlot = nullptr);
|
||||
void JRRA(std::function<void ()> delaySlot = nullptr) {
|
||||
JR(R_RA, delaySlot);
|
||||
}
|
||||
void JALR(MIPSReg rd, MIPSReg rs);
|
||||
void JALR(MIPSReg rs) {
|
||||
JALR(R_RA, rs);
|
||||
void JALR(MIPSReg rd, MIPSReg rs, std::function<void ()> delaySlot = nullptr);
|
||||
void JALR(MIPSReg rs, std::function<void ()> delaySlot = nullptr) {
|
||||
JALR(R_RA, rs, delaySlot);
|
||||
}
|
||||
|
||||
inline FixupBranch B() {
|
||||
return BEQ(R_ZERO, R_ZERO);
|
||||
inline FixupBranch B(std::function<void ()> delaySlot = nullptr) {
|
||||
return BEQ(R_ZERO, R_ZERO, delaySlot);
|
||||
}
|
||||
inline void B(const void *func) {
|
||||
return BEQ(R_ZERO, R_ZERO, func);
|
||||
inline void B(const void *func, std::function<void ()> delaySlot = nullptr) {
|
||||
return BEQ(R_ZERO, R_ZERO, func, delaySlot);
|
||||
}
|
||||
FixupBranch BLTZ(MIPSReg rs);
|
||||
void BLTZ(MIPSReg rs, const void *func);
|
||||
FixupBranch BEQ(MIPSReg rs, MIPSReg rt);
|
||||
void BEQ(MIPSReg rs, MIPSReg rt, const void *func);
|
||||
FixupBranch BNE(MIPSReg rs, MIPSReg rt);
|
||||
void BNE(MIPSReg rs, MIPSReg rt, const void *func);
|
||||
inline FixupBranch BEQZ(MIPSReg rs) {
|
||||
return BEQ(rs, R_ZERO);
|
||||
FixupBranch BLTZ(MIPSReg rs, std::function<void ()> delaySlot = nullptr);
|
||||
void BLTZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot = nullptr);
|
||||
FixupBranch BEQ(MIPSReg rs, MIPSReg rt, std::function<void ()> delaySlot = nullptr);
|
||||
void BEQ(MIPSReg rs, MIPSReg rt, const void *func, std::function<void ()> delaySlot = nullptr);
|
||||
FixupBranch BNE(MIPSReg rs, MIPSReg rt, std::function<void ()> delaySlot = nullptr);
|
||||
void BNE(MIPSReg rs, MIPSReg rt, const void *func, std::function<void ()> delaySlot = nullptr);
|
||||
inline FixupBranch BEQZ(MIPSReg rs, std::function<void ()> delaySlot = nullptr) {
|
||||
return BEQ(rs, R_ZERO, delaySlot);
|
||||
}
|
||||
inline void BEQZ(MIPSReg rs, const void *func) {
|
||||
return BEQ(rs, R_ZERO, func);
|
||||
inline void BEQZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot = nullptr) {
|
||||
return BEQ(rs, R_ZERO, func, delaySlot);
|
||||
}
|
||||
inline FixupBranch BNEZ(MIPSReg rs) {
|
||||
return BNE(rs, R_ZERO);
|
||||
inline FixupBranch BNEZ(MIPSReg rs, std::function<void ()> delaySlot = nullptr) {
|
||||
return BNE(rs, R_ZERO, delaySlot);
|
||||
}
|
||||
inline void BNEZ(MIPSReg rs, const void *func) {
|
||||
return BNE(rs, R_ZERO, func);
|
||||
inline void BNEZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot = nullptr) {
|
||||
return BNE(rs, R_ZERO, func, delaySlot);
|
||||
}
|
||||
FixupBranch BLEZ(MIPSReg rs);
|
||||
void BLEZ(MIPSReg rs, const void *func);
|
||||
FixupBranch BGTZ(MIPSReg rs);
|
||||
void BGTZ(MIPSReg rs, const void *func);
|
||||
FixupBranch BLEZ(MIPSReg rs, std::function<void ()> delaySlot = nullptr);
|
||||
void BLEZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot = nullptr);
|
||||
FixupBranch BGTZ(MIPSReg rs, std::function<void ()> delaySlot = nullptr);
|
||||
void BGTZ(MIPSReg rs, const void *func, std::function<void ()> delaySlot = nullptr);
|
||||
|
||||
void SetJumpTarget(const FixupBranch &branch);
|
||||
bool BInRange(const void *func);
|
||||
@ -230,6 +250,7 @@ protected:
|
||||
static bool BInRange(const void *src, const void *dst);
|
||||
static bool JInRange(const void *src, const void *dst);
|
||||
FixupBranch MakeFixupBranch(FixupBranchType type);
|
||||
void ApplyDelaySlot(std::function<void ()> delaySlot);
|
||||
|
||||
private:
|
||||
union {
|
||||
@ -293,3 +314,5 @@ protected:
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user