Add very simple jit viewer screen to dev menu. Add untested emitter for cvt.f32.f16 & c:o.

This commit is contained in:
Henrik Rydgard 2013-09-29 13:39:25 +02:00
parent aaeb3f3fda
commit b661ae6c41
8 changed files with 189 additions and 6 deletions

View File

@ -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));
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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;
}

View File

@ -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_;
};

View File

@ -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);

View File

@ -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);