2012-11-01 15:19:01 +00:00
|
|
|
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
2012-11-04 22:01:49 +00:00
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official git repository and contact information can be found at
|
|
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2013-12-30 09:49:05 +00:00
|
|
|
#include <string>
|
2013-12-30 09:17:11 +00:00
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include "Common/CommonTypes.h"
|
2013-08-24 21:43:49 +00:00
|
|
|
#include "Core/MIPS/MIPS.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-07-30 08:14:56 +00:00
|
|
|
class DebugInterface;
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
namespace MIPSAnalyst
|
|
|
|
{
|
2013-08-24 22:35:31 +00:00
|
|
|
const int MIPS_NUM_GPRS = 32;
|
|
|
|
|
2013-08-24 20:41:03 +00:00
|
|
|
struct RegisterAnalysisResults {
|
2012-11-01 15:19:01 +00:00
|
|
|
bool used;
|
|
|
|
int firstRead;
|
|
|
|
int lastRead;
|
|
|
|
int firstWrite;
|
|
|
|
int lastWrite;
|
|
|
|
int firstReadAsAddr;
|
|
|
|
int lastReadAsAddr;
|
|
|
|
|
|
|
|
int readCount;
|
|
|
|
int writeCount;
|
|
|
|
int readAsAddrCount;
|
|
|
|
|
2013-08-24 22:35:31 +00:00
|
|
|
int TotalReadCount() const { return readCount + readAsAddrCount; }
|
|
|
|
int FirstRead() const { return firstReadAsAddr < firstRead ? firstReadAsAddr : firstRead; }
|
|
|
|
int LastRead() const { return lastReadAsAddr > lastRead ? lastReadAsAddr : lastRead; }
|
2013-08-24 20:41:03 +00:00
|
|
|
|
|
|
|
void MarkRead(u32 addr) {
|
|
|
|
if (firstRead == -1)
|
|
|
|
firstRead = addr;
|
|
|
|
lastRead = addr;
|
|
|
|
readCount++;
|
|
|
|
used = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MarkReadAsAddr(u32 addr) {
|
|
|
|
if (firstReadAsAddr == -1)
|
|
|
|
firstReadAsAddr = addr;
|
|
|
|
lastReadAsAddr = addr;
|
|
|
|
readAsAddrCount++;
|
|
|
|
used = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MarkWrite(u32 addr) {
|
|
|
|
if (firstWrite == -1)
|
|
|
|
firstWrite = addr;
|
|
|
|
lastWrite = addr;
|
|
|
|
writeCount++;
|
|
|
|
used = true;
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
};
|
|
|
|
|
2013-08-24 22:35:31 +00:00
|
|
|
struct AnalysisResults {
|
|
|
|
RegisterAnalysisResults r[MIPS_NUM_GPRS];
|
2012-11-01 15:19:01 +00:00
|
|
|
};
|
|
|
|
|
2013-08-24 22:35:31 +00:00
|
|
|
AnalysisResults Analyze(u32 address);
|
|
|
|
|
2014-10-12 21:23:59 +00:00
|
|
|
// This tells us if the reg is used within intrs of addr (also includes likely delay slots.)
|
|
|
|
bool IsRegisterUsed(MIPSGPReg reg, u32 addr, int instrs);
|
2014-12-08 05:09:08 +00:00
|
|
|
// This tells us if the reg is clobbered within intrs of addr (e.g. it is surely not used.)
|
|
|
|
bool IsRegisterClobbered(MIPSGPReg reg, u32 addr, int instrs);
|
2013-11-30 19:57:44 +00:00
|
|
|
|
|
|
|
struct AnalyzedFunction {
|
|
|
|
u32 start;
|
|
|
|
u32 end;
|
|
|
|
u64 hash;
|
|
|
|
u32 size;
|
|
|
|
bool isStraightLeaf;
|
|
|
|
bool hasHash;
|
|
|
|
bool usesVFPU;
|
2014-02-15 06:13:09 +00:00
|
|
|
bool foundInSymbolMap;
|
2013-11-30 19:57:44 +00:00
|
|
|
char name[64];
|
|
|
|
};
|
|
|
|
|
2013-12-17 22:40:27 +00:00
|
|
|
struct ReplacementTableEntry;
|
|
|
|
|
2013-11-30 19:57:44 +00:00
|
|
|
void Reset();
|
2013-08-24 22:35:31 +00:00
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
bool IsRegisterUsed(u32 reg, u32 addr);
|
2013-11-30 19:57:44 +00:00
|
|
|
// This will not only create a database of "AnalyzedFunction" structs, it also
|
|
|
|
// will insert all the functions it finds into the symbol map, if insertSymbols is true.
|
2013-12-17 22:40:27 +00:00
|
|
|
|
|
|
|
// If we have loaded symbols from the elf, we'll register functions as they are touched
|
|
|
|
// so that we don't just dump them all in the cache.
|
2013-12-20 14:37:37 +00:00
|
|
|
void RegisterFunction(u32 startAddr, u32 size, const char *name);
|
2013-11-30 19:57:44 +00:00
|
|
|
void ScanForFunctions(u32 startAddr, u32 endAddr, bool insertSymbols);
|
|
|
|
void ForgetFunctions(u32 startAddr, u32 endAddr);
|
2012-11-01 15:19:01 +00:00
|
|
|
void CompileLeafs();
|
2013-12-17 22:40:27 +00:00
|
|
|
|
2014-12-05 18:12:49 +00:00
|
|
|
void SetHashMapFilename(const std::string& filename = "");
|
2014-06-07 07:13:45 +00:00
|
|
|
void LoadBuiltinHashMap();
|
2014-12-05 18:12:49 +00:00
|
|
|
void LoadHashMap(const std::string& filename);
|
2013-11-30 19:57:44 +00:00
|
|
|
void StoreHashMap(std::string filename = "");
|
2013-12-17 22:40:27 +00:00
|
|
|
|
2014-05-30 16:46:13 +00:00
|
|
|
const char *LookupHash(u64 hash, u32 funcSize);
|
2014-04-12 22:48:30 +00:00
|
|
|
void ReplaceFunctions();
|
2013-11-30 19:57:44 +00:00
|
|
|
|
|
|
|
void UpdateHashMap();
|
|
|
|
void ApplyHashMap();
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-08-25 02:31:12 +00:00
|
|
|
std::vector<MIPSGPReg> GetInputRegs(MIPSOpcode op);
|
|
|
|
std::vector<MIPSGPReg> GetOutputRegs(MIPSOpcode op);
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-08-25 02:31:12 +00:00
|
|
|
MIPSGPReg GetOutGPReg(MIPSOpcode op);
|
|
|
|
bool ReadsFromGPReg(MIPSOpcode op, MIPSGPReg reg);
|
|
|
|
bool IsDelaySlotNiceReg(MIPSOpcode branchOp, MIPSOpcode op, MIPSGPReg reg1, MIPSGPReg reg2 = MIPS_REG_ZERO);
|
2013-08-24 21:43:49 +00:00
|
|
|
bool IsDelaySlotNiceVFPU(MIPSOpcode branchOp, MIPSOpcode op);
|
|
|
|
bool IsDelaySlotNiceFPU(MIPSOpcode branchOp, MIPSOpcode op);
|
|
|
|
bool IsSyscall(MIPSOpcode op);
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2014-06-19 07:48:33 +00:00
|
|
|
bool OpWouldChangeMemory(u32 pc, u32 addr, u32 size);
|
2014-01-26 19:52:37 +00:00
|
|
|
|
2013-05-26 23:29:21 +00:00
|
|
|
void Shutdown();
|
2013-07-30 08:14:56 +00:00
|
|
|
|
2013-11-30 19:57:44 +00:00
|
|
|
typedef struct {
|
2013-07-30 08:14:56 +00:00
|
|
|
DebugInterface* cpu;
|
|
|
|
u32 opcodeAddress;
|
2013-08-24 21:43:49 +00:00
|
|
|
MIPSOpcode encodedOpcode;
|
2013-07-30 09:29:30 +00:00
|
|
|
|
|
|
|
// shared between branches and conditional moves
|
|
|
|
bool isConditional;
|
|
|
|
bool conditionMet;
|
2013-07-30 08:14:56 +00:00
|
|
|
|
|
|
|
// branches
|
|
|
|
u32 branchTarget;
|
|
|
|
bool isBranch;
|
|
|
|
bool isLinkedBranch;
|
|
|
|
bool isLikelyBranch;
|
|
|
|
bool isBranchToRegister;
|
|
|
|
int branchRegisterNum;
|
|
|
|
|
|
|
|
// data access
|
|
|
|
bool isDataAccess;
|
|
|
|
int dataSize;
|
|
|
|
u32 dataAddress;
|
2013-11-05 20:20:21 +00:00
|
|
|
|
|
|
|
bool hasRelevantAddress;
|
2014-10-09 19:38:25 +00:00
|
|
|
u32 relevantAddress;
|
2013-07-30 08:14:56 +00:00
|
|
|
} MipsOpcodeInfo;
|
|
|
|
|
|
|
|
MipsOpcodeInfo GetOpcodeInfo(DebugInterface* cpu, u32 address);
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
} // namespace MIPSAnalyst
|