mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-26 23:10:38 +00:00
Add very simple jit viewer screen to dev menu. Add untested emitter for cvt.f32.f16 & c:o.
This commit is contained in:
parent
aaeb3f3fda
commit
b661ae6c41
@ -1265,4 +1265,37 @@ void ARMXEmitter::VCVT(ARMReg Dest, ARMReg Source, int flags)
|
||||
}
|
||||
}
|
||||
|
||||
// UNTESTED
|
||||
|
||||
// See page A8-878 in ARMv7-A Architecture Reference Manual
|
||||
|
||||
// Dest is a Q register, Src is a D register.
|
||||
void ARMXEmitter::VCVTF32F16(ARMReg Dest, ARMReg Src) {
|
||||
_assert_msg_(JIT, cpu_info.bVFPv4, "Can't use half-float conversions when you don't support VFPv4");
|
||||
if (Dest < Q0 || Dest > Q15 || Src < D0 || Src > D15) {
|
||||
_assert_msg_(JIT, cpu_info.bNEON, "Bad inputs to VCVTF32F16");
|
||||
// Invalid!
|
||||
}
|
||||
|
||||
Dest = SubBase(Dest);
|
||||
Src = SubBase(Src);
|
||||
|
||||
int op = 1;
|
||||
Write32((0xF3B6 << 16) | ((Dest & 0x10) << 18) | ((Dest & 0xF) << 12) | 0x600 | (op << 8) | ((Src & 0x10) << 1) | (Src & 0xF));
|
||||
}
|
||||
|
||||
// UNTESTED
|
||||
// Dest is a D register, Src is a Q register.
|
||||
void ARMXEmitter::VCVTF16F32(ARMReg Dest, ARMReg Src) {
|
||||
_assert_msg_(JIT, cpu_info.bVFPv4, "Can't use half-float conversions when you don't support VFPv4");
|
||||
if (Dest < D0 || Dest > D15 || Src < Q0 || Src > Q15) {
|
||||
_assert_msg_(JIT, cpu_info.bNEON, "Bad inputs to VCVTF32F16");
|
||||
// Invalid!
|
||||
}
|
||||
Dest = SubBase(Dest);
|
||||
Src = SubBase(Src);
|
||||
int op = 0;
|
||||
Write32((0xF3B6 << 16) | ((Dest & 0x10) << 18) | ((Dest & 0xF) << 12) | 0x600 | (op << 8) | ((Src & 0x10) << 1) | (Src & 0xF));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -572,6 +572,10 @@ public:
|
||||
void VMOV(ARMReg Dest, ARMReg Src);
|
||||
void VCVT(ARMReg Dest, ARMReg Src, int flags);
|
||||
|
||||
// NEON, need to check for this (supported if VFP4 is supported)
|
||||
void VCVTF32F16(ARMReg Dest, ARMReg Src);
|
||||
void VCVTF16F32(ARMReg Dest, ARMReg Src);
|
||||
|
||||
void VMRS_APSR();
|
||||
void VMRS(ARMReg Rt);
|
||||
void VMSR(ARMReg Rt);
|
||||
|
@ -115,6 +115,8 @@ public:
|
||||
void InvalidateICache(u32 address, const u32 length);
|
||||
void DestroyBlock(int block_num, bool invalidate);
|
||||
|
||||
int GetNumBlocks() const { return num_blocks; }
|
||||
|
||||
private:
|
||||
void LinkBlockExits(int i);
|
||||
void LinkBlock(int i);
|
||||
|
@ -266,8 +266,8 @@ void Jit::Compile(u32 em_address)
|
||||
blocks.FinalizeBlock(block_num, jo.enableBlocklink);
|
||||
|
||||
// Drat. The VFPU hit an uneaten prefix at the end of a block.
|
||||
if (js.startDefaultPrefix && js.MayHavePrefix())
|
||||
{
|
||||
if (js.startDefaultPrefix && js.MayHavePrefix()) {
|
||||
WARN_LOG(JIT, "Uneaten prefix at end of block: %08x", js.compilerPC - 4);
|
||||
js.startDefaultPrefix = false;
|
||||
// Our assumptions are all wrong so it's clean-slate time.
|
||||
ClearCache();
|
||||
|
@ -26,13 +26,16 @@
|
||||
#include "UI/GameSettingsScreen.h"
|
||||
#include "Common/LogManager.h"
|
||||
#include "Core/Config.h"
|
||||
|
||||
#include "Core/MIPS/MIPSTables.h"
|
||||
#include "Core/MIPS/JitCommon/JitCommon.h"
|
||||
#include "ext/disarm.h"
|
||||
|
||||
void DevMenu::CreatePopupContents(UI::ViewGroup *parent) {
|
||||
using namespace UI;
|
||||
|
||||
parent->Add(new Choice("Log Channels"))->OnClick.Handle(this, &DevMenu::OnLogConfig);
|
||||
parent->Add(new Choice("Developer Tools"))->OnClick.Handle(this, &DevMenu::OnDeveloperTools);
|
||||
parent->Add(new Choice("Jit Compare"))->OnClick.Handle(this, &DevMenu::OnJitCompare);
|
||||
}
|
||||
|
||||
UI::EventReturn DevMenu::OnLogConfig(UI::EventParams &e) {
|
||||
@ -45,6 +48,11 @@ UI::EventReturn DevMenu::OnDeveloperTools(UI::EventParams &e) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn DevMenu::OnJitCompare(UI::EventParams &e) {
|
||||
screenManager()->push(new JitCompareScreen());
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
void DevMenu::dialogFinished(const Screen *dialog, DialogResult result) {
|
||||
// Close when a subscreen got closed.
|
||||
// TODO: a bug in screenmanager causes this not to work here.
|
||||
@ -149,3 +157,117 @@ void SystemInfoScreen::CreateViews() {
|
||||
scroll->Add(new TextView(exts[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Three panes: Block chooser, MIPS view, ARM/x86 view
|
||||
void JitCompareScreen::CreateViews() {
|
||||
I18NCategory *d = GetI18NCategory("Dialog");
|
||||
|
||||
using namespace UI;
|
||||
|
||||
root_ = new LinearLayout(ORIENT_HORIZONTAL);
|
||||
|
||||
ScrollView *leftColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));
|
||||
LinearLayout *leftColumn = leftColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));
|
||||
|
||||
ScrollView *midColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(2.0f)));
|
||||
LinearLayout *midColumn = midColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));
|
||||
leftDisasm_ = midColumn->Add(new LinearLayout(ORIENT_VERTICAL));
|
||||
leftDisasm_->SetSpacing(0.0f);
|
||||
|
||||
ScrollView *rightColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(2.0f)));
|
||||
LinearLayout *rightColumn = rightColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));
|
||||
rightDisasm_ = rightColumn->Add(new LinearLayout(ORIENT_VERTICAL));
|
||||
rightDisasm_->SetSpacing(0.0f);
|
||||
|
||||
leftColumn->Add(new Choice("Current"))->OnClick.Handle(this, &JitCompareScreen::OnCurrentBlock);
|
||||
leftColumn->Add(new Choice("Random"))->OnClick.Handle(this, &JitCompareScreen::OnRandomBlock);
|
||||
leftColumn->Add(new Choice(d->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
|
||||
}
|
||||
|
||||
std::vector<std::string> DisassembleArm2(const u8 *data, int size) {
|
||||
std::vector<std::string> lines;
|
||||
|
||||
char temp[256];
|
||||
for (int i = 0; i < size; i += 4) {
|
||||
const u32 *codePtr = (const u32 *)(data + i);
|
||||
u32 inst = codePtr[0];
|
||||
u32 next = (i < size - 4) ? codePtr[1] : 0;
|
||||
// MAGIC SPECIAL CASE for MOVW/MOVT readability!
|
||||
if ((inst & 0x0FF00000) == 0x03000000 && (next & 0x0FF00000) == 0x03400000) {
|
||||
u32 low = ((inst & 0x000F0000) >> 4) | (inst & 0x0FFF);
|
||||
u32 hi = ((next & 0x000F0000) >> 4) | (next & 0x0FFF);
|
||||
int reg0 = (inst & 0x0000F000) >> 12;
|
||||
int reg1 = (next & 0x0000F000) >> 12;
|
||||
if (reg0 == reg1) {
|
||||
sprintf(temp, "MOV32 %s, %04x%04x", ArmRegName(reg0), hi, low);
|
||||
// sprintf(temp, "%08x MOV32? %s, %04x%04x", (u32)inst, ArmRegName(reg0), hi, low);
|
||||
lines.push_back(temp);
|
||||
i += 4;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ArmDis((u32)codePtr, inst, temp, false);
|
||||
std::string buf = temp;
|
||||
lines.push_back(buf);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
void JitCompareScreen::UpdateDisasm() {
|
||||
leftDisasm_->Clear();
|
||||
rightDisasm_->Clear();
|
||||
|
||||
using namespace UI;
|
||||
|
||||
if (currentBlock_ == -1) {
|
||||
leftDisasm_->Add(new TextView("No block"));
|
||||
rightDisasm_->Add(new TextView("No block"));
|
||||
return;
|
||||
}
|
||||
|
||||
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
|
||||
JitBlock *block = blockCache->GetBlock(currentBlock_);
|
||||
|
||||
// Alright. First generate the MIPS disassembly.
|
||||
|
||||
for (u32 addr = block->originalAddress; addr <= block->originalAddress + block->originalSize * 4; addr += 4) {
|
||||
char temp[256];
|
||||
MIPSDisAsm(Memory::Read_Instruction(addr), addr, temp, true);
|
||||
std::string mipsDis = temp;
|
||||
leftDisasm_->Add(new TextView(mipsDis));
|
||||
}
|
||||
|
||||
#if defined(ARM)
|
||||
std::vector<std::string> targetDis = DisassembleArm2(block->normalEntry, block->codeSize);
|
||||
for (size_t i = 0; i < targetDis.size(); i++) {
|
||||
rightDisasm_->Add(new TextView(targetDis[i]));
|
||||
}
|
||||
#else
|
||||
rightDisasm_->Add(new TextView("No x86 disassembler available"));
|
||||
#endif
|
||||
}
|
||||
|
||||
UI::EventReturn JitCompareScreen::OnRandomBlock(UI::EventParams &e) {
|
||||
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
|
||||
int numBlocks = blockCache->GetNumBlocks();
|
||||
if (numBlocks > 0) {
|
||||
currentBlock_ = rand() % numBlocks;
|
||||
}
|
||||
UpdateDisasm();
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn JitCompareScreen::OnCurrentBlock(UI::EventParams &e) {
|
||||
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
|
||||
std::vector<int> blockNum;
|
||||
blockCache->GetBlockNumbersFromAddress(currentMIPS->pc, &blockNum);
|
||||
if (blockNum.size() > 0) {
|
||||
currentBlock_ = blockNum[0];
|
||||
} else {
|
||||
currentBlock_ = -1;
|
||||
}
|
||||
UpdateDisasm();
|
||||
return UI::EVENT_DONE;
|
||||
}
|
@ -37,6 +37,7 @@ public:
|
||||
|
||||
protected:
|
||||
UI::EventReturn OnLogConfig(UI::EventParams &e);
|
||||
UI::EventReturn OnJitCompare(UI::EventParams &e);
|
||||
UI::EventReturn OnDeveloperTools(UI::EventParams &e);
|
||||
};
|
||||
|
||||
@ -53,4 +54,20 @@ class SystemInfoScreen : public UIDialogScreenWithBackground {
|
||||
public:
|
||||
SystemInfoScreen() {}
|
||||
virtual void CreateViews();
|
||||
};
|
||||
|
||||
class JitCompareScreen : public UIDialogScreenWithBackground {
|
||||
public:
|
||||
JitCompareScreen() : currentBlock_(-1) {}
|
||||
virtual void CreateViews();
|
||||
|
||||
private:
|
||||
void UpdateDisasm();
|
||||
UI::EventReturn OnRandomBlock(UI::EventParams &e);
|
||||
UI::EventReturn OnCurrentBlock(UI::EventParams &e);
|
||||
|
||||
int currentBlock_;
|
||||
|
||||
UI::LinearLayout *leftDisasm_;
|
||||
UI::LinearLayout *rightDisasm_;
|
||||
};
|
@ -1023,10 +1023,15 @@ static sDisOptions options = {
|
||||
const char *ArmRegName(int r) {
|
||||
return reg_names[r];
|
||||
}
|
||||
void ArmDis(unsigned int addr, unsigned int w, char *output) {
|
||||
|
||||
void ArmDis(unsigned int addr, unsigned int w, char *output, bool includeWord) {
|
||||
pInstruction instr = instr_disassemble(w, addr, &options);
|
||||
char temp[256];
|
||||
sprintf(output, "%08x\t%s", w, instr->text);
|
||||
if (includeWord) {
|
||||
sprintf(output, "%08x\t%s", w, instr->text);
|
||||
} else {
|
||||
sprintf(output, "%s", instr->text);
|
||||
}
|
||||
if (instr->undefined || instr->badbits || instr->oddbits) {
|
||||
if (instr->undefined) sprintf(output, " [undefined instr %08x]", w);
|
||||
if (instr->badbits) sprintf(output, " [illegal bits %08x]", w);
|
||||
|
@ -31,4 +31,4 @@
|
||||
// program with this function.
|
||||
|
||||
const char *ArmRegName(int r);
|
||||
void ArmDis(unsigned int addr, unsigned int w, char *output);
|
||||
void ArmDis(unsigned int addr, unsigned int w, char *output, bool includeWord = true);
|
||||
|
Loading…
Reference in New Issue
Block a user