mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
-add function to get relevant opcode information for the disassembly
-put it to use to clean up code
This commit is contained in:
parent
0ef12098df
commit
32f1ca91fd
5 changed files with 188 additions and 39 deletions
|
@ -23,6 +23,7 @@
|
|||
#include "MIPSAnalyst.h"
|
||||
#include "MIPSCodeUtils.h"
|
||||
#include "../Debugger/SymbolMap.h"
|
||||
#include "../Debugger/DebugInterface.h"
|
||||
|
||||
using namespace MIPSCodeUtils;
|
||||
using namespace std;
|
||||
|
@ -530,4 +531,132 @@ namespace MIPSAnalyst
|
|||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
void opInfoSetJump(MipsOpcodeInfo& inf, bool link, u32 target, int reg = -1)
|
||||
{
|
||||
inf.isBranch = true;
|
||||
inf.isLinkedBranch = link;
|
||||
inf.branchTarget = target;
|
||||
|
||||
if (reg != -1)
|
||||
{
|
||||
inf.isBranchToRegister = true;
|
||||
inf.branchRegisterNum = reg;
|
||||
}
|
||||
}
|
||||
|
||||
inline void opInfoSetBranch(MipsOpcodeInfo& inf, u32 target, bool conditionMet)
|
||||
{
|
||||
inf.isBranch = true;
|
||||
inf.isConditionalBranch = true;
|
||||
inf.branchConditionMet = conditionMet;
|
||||
inf.branchTarget = target;
|
||||
}
|
||||
|
||||
inline void opInfoSetDataAccess(MipsOpcodeInfo& inf, int dataSize)
|
||||
{
|
||||
inf.isDataAccess = true;
|
||||
inf.dataSize = dataSize;
|
||||
|
||||
s16 imm16 = inf.encodedOpcode & 0xFFFF;
|
||||
inf.dataAddress = inf.cpu->GetRegValue(0,MIPS_GET_RS(inf.encodedOpcode)) + imm16;
|
||||
}
|
||||
|
||||
MipsOpcodeInfo GetOpcodeInfo(DebugInterface* cpu, u32 address)
|
||||
{
|
||||
MipsOpcodeInfo info;
|
||||
memset(&info,0,sizeof(info));
|
||||
|
||||
info.cpu = cpu;
|
||||
info.opcodeAddress = address;
|
||||
info.encodedOpcode = Memory::Read_Instruction(address);
|
||||
u32 op = info.encodedOpcode;
|
||||
|
||||
// read everything that could be used
|
||||
u32 rt = cpu->GetRegValue(0,MIPS_GET_RT(op));
|
||||
u32 rd = cpu->GetRegValue(0,MIPS_GET_RD(op));
|
||||
u32 rs = cpu->GetRegValue(0,MIPS_GET_RS(op));
|
||||
int rsNum = MIPS_GET_RS(op);
|
||||
int rtNum = MIPS_GET_RT(op);
|
||||
u32 jumpTarget = GetJumpTarget(address);
|
||||
u32 branchTarget = GetBranchTarget(address);
|
||||
|
||||
switch (MIPS_GET_OP(op))
|
||||
{
|
||||
case 0: // special
|
||||
switch (MIPS_GET_FUNC(op))
|
||||
{
|
||||
case 8: // jr
|
||||
opInfoSetJump(info,false,rs,rsNum);
|
||||
break;
|
||||
case 9: // jalr
|
||||
opInfoSetJump(info,true,rs,rsNum);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1: // regimm
|
||||
switch (rtNum)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
case 2: // j
|
||||
opInfoSetJump(info,false,jumpTarget);
|
||||
break;
|
||||
case 3: // jal
|
||||
opInfoSetJump(info,true,jumpTarget);
|
||||
break;
|
||||
case 4: // beq
|
||||
opInfoSetBranch(info,branchTarget,rt == rs);
|
||||
if (rtNum == rsNum) // pretend to be unconditional when it de facto is
|
||||
{
|
||||
info.isConditionalBranch = false;
|
||||
}
|
||||
break;
|
||||
case 20: // beql
|
||||
opInfoSetBranch(info,branchTarget,rt == rs);
|
||||
info.isLikelyBranch = true;
|
||||
case 5: // bne
|
||||
opInfoSetBranch(info,branchTarget,rt != rs);
|
||||
break;
|
||||
case 21: // bnel
|
||||
opInfoSetBranch(info,branchTarget,rt != rs);
|
||||
info.isLikelyBranch = true;
|
||||
case 6: // blez
|
||||
opInfoSetBranch(info,branchTarget,((s32)rs) <= 0);
|
||||
break;
|
||||
case 22: // blezl
|
||||
opInfoSetBranch(info,branchTarget,((s32)rs) <= 0);
|
||||
info.isLikelyBranch = true;
|
||||
case 7: // bgtz
|
||||
opInfoSetBranch(info,branchTarget,((s32)rs) > 0);
|
||||
break;
|
||||
case 23: // bgtzl
|
||||
opInfoSetBranch(info,branchTarget,((s32)rs) > 0);
|
||||
info.isLikelyBranch = true;
|
||||
break;
|
||||
|
||||
case 32: // lb
|
||||
case 36: // lb
|
||||
case 40: // sb
|
||||
opInfoSetDataAccess(info,1);
|
||||
break;
|
||||
case 33: // lh
|
||||
case 37: // lh
|
||||
case 41: // sh
|
||||
opInfoSetDataAccess(info,2);
|
||||
break;
|
||||
case 34: // lwl
|
||||
case 35: // lw
|
||||
case 38: // lwr
|
||||
case 42: // swl
|
||||
case 43: // sw
|
||||
case 46: // swr
|
||||
opInfoSetDataAccess(info,4);
|
||||
break;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include "../../Globals.h"
|
||||
|
||||
class DebugInterface;
|
||||
|
||||
namespace MIPSAnalyst
|
||||
{
|
||||
void Analyze(u32 address);
|
||||
|
@ -63,5 +65,29 @@ namespace MIPSAnalyst
|
|||
bool IsSyscall(u32 op);
|
||||
|
||||
void Shutdown();
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DebugInterface* cpu;
|
||||
u32 opcodeAddress;
|
||||
u32 encodedOpcode;
|
||||
|
||||
// branches
|
||||
u32 branchTarget;
|
||||
bool isBranch;
|
||||
bool isLinkedBranch;
|
||||
bool isLikelyBranch;
|
||||
bool isConditionalBranch;
|
||||
bool branchConditionMet;
|
||||
bool isBranchToRegister;
|
||||
int branchRegisterNum;
|
||||
|
||||
// data access
|
||||
bool isDataAccess;
|
||||
int dataSize;
|
||||
u32 dataAddress;
|
||||
} MipsOpcodeInfo;
|
||||
|
||||
MipsOpcodeInfo GetOpcodeInfo(DebugInterface* cpu, u32 address);
|
||||
|
||||
} // namespace MIPSAnalyst
|
||||
|
|
|
@ -36,6 +36,10 @@
|
|||
#define MIPS_MAKE_SYSCALL(module, function) GetSyscallOp(module, GetNibByName(module, function))
|
||||
#define MIPS_MAKE_BREAK() (13) // ! :)
|
||||
|
||||
#define MIPS_GET_OP(op) ((op>>26) & 0x3F)
|
||||
#define MIPS_GET_FUNC(op) (op & 0x3F)
|
||||
#define MIPS_GET_SA(op) (op>>6 & 0x1F)
|
||||
|
||||
#define MIPS_GET_RS(op) ((op>>21) & 0x1F)
|
||||
#define MIPS_GET_RT(op) ((op>>16) & 0x1F)
|
||||
#define MIPS_GET_RD(op) ((op>>11) & 0x1F)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "Windows/InputBox.h"
|
||||
|
||||
#include "Core/MIPS/MIPSAsm.h"
|
||||
#include "Core/MIPS/MIPSAnalyst.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Windows/Debugger/CtrlDisAsmView.h"
|
||||
#include "Windows/Debugger/Debugger_MemoryDlg.h"
|
||||
|
@ -343,6 +344,7 @@ void CtrlDisAsmView::onPaint(WPARAM wParam, LPARAM lParam)
|
|||
for (int i = 0; i < visibleRows+2; i++)
|
||||
{
|
||||
unsigned int address=windowStart + i*instructionSize;
|
||||
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(debugger,address);
|
||||
|
||||
int rowY1 = rowHeight*i;
|
||||
int rowY2 = rowHeight*(i+1);
|
||||
|
@ -403,6 +405,12 @@ void CtrlDisAsmView::onPaint(WPARAM wParam, LPARAM lParam)
|
|||
const char *dizz = debugger->disasm(address, instructionSize);
|
||||
parseDisasm(dizz,opcode,arguments);
|
||||
|
||||
// display whether the condition of a branch is met
|
||||
if (info.isConditionalBranch && address == debugger->getPC())
|
||||
{
|
||||
strcat(arguments,info.branchConditionMet ? " ; true" : " ; false");
|
||||
}
|
||||
|
||||
int length = (int) strlen(arguments);
|
||||
if (length != 0) TextOut(hdc,pixelPositions.argumentsStart,rowY1+2,arguments,length);
|
||||
|
||||
|
@ -410,7 +418,7 @@ void CtrlDisAsmView::onPaint(WPARAM wParam, LPARAM lParam)
|
|||
TextOut(hdc,pixelPositions.opcodeStart,rowY1+2,opcode,(int)strlen(opcode));
|
||||
SelectObject(hdc,font);
|
||||
|
||||
if (branchTarget != -1 && strcmp(opcode,"jal") != 0 && opcode[1] != 0) //unconditional 'b/j' branch
|
||||
if (info.isConditionalBranch)
|
||||
{
|
||||
branches[numBranches].src=rowY1 + rowHeight/2;
|
||||
branches[numBranches].srcAddr=address/instructionSize;
|
||||
|
@ -491,18 +499,12 @@ void CtrlDisAsmView::onVScroll(WPARAM wParam, LPARAM lParam)
|
|||
|
||||
void CtrlDisAsmView::followBranch()
|
||||
{
|
||||
char opcode[64],arguments[256];
|
||||
const char *dizz = debugger->disasm(curAddress, instructionSize);
|
||||
parseDisasm(dizz,opcode,arguments);
|
||||
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(debugger,curAddress);
|
||||
|
||||
if (branchTarget != -1)
|
||||
if (info.isBranch)
|
||||
{
|
||||
jumpStack.push_back(curAddress);
|
||||
gotoAddr(branchTarget);
|
||||
} else if (branchRegister != -1)
|
||||
{
|
||||
jumpStack.push_back(curAddress);
|
||||
gotoAddr(debugger->GetRegValue(0,branchRegister));
|
||||
gotoAddr(info.branchTarget);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "Core/CPU.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/MIPS/MIPSAnalyst.h"
|
||||
|
||||
#include "base/stringutil.h"
|
||||
|
||||
|
@ -287,42 +288,29 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam)
|
|||
// If the current PC is on a breakpoint, the user doesn't want to do nothing.
|
||||
CBreakPoints::SetSkipFirst(currentMIPS->pc);
|
||||
|
||||
const char* dis = cpu->disasm(cpu->GetPC(),4);
|
||||
const char* pos = strstr(dis,"->$");
|
||||
const char* reg = strstr(dis,"->");
|
||||
|
||||
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(cpu,cpu->GetPC());
|
||||
ptr->setDontRedraw(true);
|
||||
u32 breakpointAddress = cpu->GetPC()+cpu->getInstructionSize(0);
|
||||
if (memcmp(dis,"jal\t",4) == 0 || memcmp(dis,"jalr\t",5) == 0)
|
||||
if (info.isBranch)
|
||||
{
|
||||
// it's a function call with a delay slot - skip that too
|
||||
breakpointAddress += cpu->getInstructionSize(0);
|
||||
} else if (memcmp(dis,"j\t",2) == 0 || memcmp(dis,"b\t",2) == 0)
|
||||
{
|
||||
// in case of absolute branches, set the breakpoint at the branch target
|
||||
sscanf(pos+3,"%08x",&breakpointAddress);
|
||||
} else if (memcmp(dis,"jr\t",3) == 0)
|
||||
{
|
||||
// the same for jumps to registers
|
||||
int regNum = -1;
|
||||
for (int i = 0; i < 32; i++)
|
||||
if (info.isConditionalBranch == false)
|
||||
{
|
||||
if (strcasecmp(reg+2,cpu->GetRegName(0,i)) == 0)
|
||||
if (info.isLinkedBranch) // jal, jalr
|
||||
{
|
||||
regNum = i;
|
||||
break;
|
||||
// it's a function call with a delay slot - skip that too
|
||||
breakpointAddress += cpu->getInstructionSize(0);
|
||||
} else { // j, ...
|
||||
// in case of absolute branches, set the breakpoint at the branch target
|
||||
breakpointAddress = info.branchTarget;
|
||||
}
|
||||
}
|
||||
if (regNum == -1) break;
|
||||
breakpointAddress = cpu->GetRegValue(0,regNum);
|
||||
} else if (pos != NULL)
|
||||
{
|
||||
// get branch target
|
||||
sscanf(pos+3,"%08x",&breakpointAddress);
|
||||
CBreakPoints::AddBreakPoint(breakpointAddress,true);
|
||||
} else { // beq, ...
|
||||
// set breakpoint at branch target
|
||||
breakpointAddress = info.branchTarget;
|
||||
CBreakPoints::AddBreakPoint(breakpointAddress,true);
|
||||
|
||||
// also add a breakpoint after the delay slot
|
||||
breakpointAddress = cpu->GetPC()+2*cpu->getInstructionSize(0);
|
||||
// and after the delay slot
|
||||
breakpointAddress = cpu->GetPC()+2*cpu->getInstructionSize(0);
|
||||
}
|
||||
}
|
||||
|
||||
SetDebugMode(false);
|
||||
|
|
Loading…
Add table
Reference in a new issue