mirror of
https://github.com/SourMesen/Mesen.git
synced 2025-04-02 10:52:48 -04:00
Debugger: Several performance improvements
This commit is contained in:
parent
fcb28fd5a6
commit
930b4f2641
19 changed files with 537 additions and 310 deletions
|
@ -576,9 +576,10 @@ void Debugger::GenerateCodeOutput()
|
|||
}
|
||||
}
|
||||
|
||||
const char* Debugger::GetCode()
|
||||
const char* Debugger::GetCode(uint32_t &length)
|
||||
{
|
||||
GenerateCodeOutput();
|
||||
length = (uint32_t)_disassemblerOutput.size();
|
||||
return _disassemblerOutput.c_str();
|
||||
}
|
||||
|
||||
|
@ -650,12 +651,20 @@ void Debugger::GetCallstack(int32_t* callstackAbsolute, int32_t* callstackRelati
|
|||
callstackRelative[_callstackRelative.size()] = -2;
|
||||
}
|
||||
|
||||
void Debugger::GetFunctionEntryPoints(int32_t* entryPoints)
|
||||
int32_t Debugger::GetFunctionEntryPointCount()
|
||||
{
|
||||
return (uint32_t)_functionEntryPoints.size();
|
||||
}
|
||||
|
||||
void Debugger::GetFunctionEntryPoints(int32_t* entryPoints, int32_t maxCount)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
for(auto itt = _functionEntryPoints.begin(); itt != _functionEntryPoints.end(); itt++) {
|
||||
entryPoints[i] = *itt;
|
||||
i++;
|
||||
if(i == maxCount - 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
entryPoints[i] = -1;
|
||||
}
|
||||
|
@ -765,11 +774,14 @@ int32_t Debugger::FindSubEntryPoint(uint16_t relativeAddress)
|
|||
int32_t address = relativeAddress;
|
||||
do {
|
||||
GetAbsoluteAddressAndType(address, &info);
|
||||
if(info.Address < 0 || info.Type != AddressType::PrgRom || !_codeDataLogger->IsCode(info.Address) || _codeDataLogger->IsSubEntryPoint(info.Address)) {
|
||||
if(info.Address < 0 || info.Type != AddressType::PrgRom || _codeDataLogger->IsData(info.Address)) {
|
||||
break;
|
||||
}
|
||||
address--;
|
||||
if(_codeDataLogger->IsSubEntryPoint(info.Address)) {
|
||||
break;
|
||||
}
|
||||
} while(address >= 0);
|
||||
|
||||
return address + 1;
|
||||
return address > relativeAddress ? relativeAddress : (address + 1);
|
||||
}
|
|
@ -119,7 +119,9 @@ public:
|
|||
|
||||
shared_ptr<LabelManager> GetLabelManager();
|
||||
|
||||
void GetFunctionEntryPoints(int32_t* entryPoints);
|
||||
void GetFunctionEntryPoints(int32_t* entryPoints, int32_t maxCount);
|
||||
int32_t GetFunctionEntryPointCount();
|
||||
|
||||
void GetCallstack(int32_t* callstackAbsolute, int32_t* callstackRelative);
|
||||
|
||||
void GetState(DebugState *state, bool includeMapperInfo = true);
|
||||
|
@ -145,7 +147,7 @@ public:
|
|||
bool IsExecutionStopped();
|
||||
|
||||
void GenerateCodeOutput();
|
||||
const char* GetCode();
|
||||
const char* GetCode(uint32_t &length);
|
||||
|
||||
int32_t GetRelativeAddress(uint32_t addr, AddressType type);
|
||||
int32_t GetAbsoluteAddress(uint32_t addr);
|
||||
|
|
|
@ -253,48 +253,130 @@ vector<string> Disassembler::SplitComment(string input)
|
|||
return result;
|
||||
}
|
||||
|
||||
string Disassembler::GetLine(string code, string comment, int32_t cpuAddress, int32_t absoluteAddress, string byteCode, string addressing, bool speculativeCode)
|
||||
static const char* hexTable[256] = {
|
||||
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
|
||||
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
|
||||
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
|
||||
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
|
||||
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
|
||||
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
|
||||
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
|
||||
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
|
||||
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
|
||||
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
|
||||
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
|
||||
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
|
||||
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
|
||||
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
|
||||
"E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
|
||||
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
|
||||
};
|
||||
|
||||
static string emptyString;
|
||||
void Disassembler::GetLine(string &out, string code, string comment, int32_t cpuAddress, int32_t absoluteAddress)
|
||||
{
|
||||
string out;
|
||||
out.reserve(40);
|
||||
if(cpuAddress >= 0) {
|
||||
if(speculativeCode) {
|
||||
out += "2\x1";
|
||||
} else {
|
||||
out += (_debugger->IsMarkedAsCode(cpuAddress) || absoluteAddress == -1) ? "1\x1" : "0\x1";
|
||||
}
|
||||
out += HexUtilities::ToHex((uint16_t)cpuAddress);
|
||||
} else {
|
||||
out += "1\x1";
|
||||
}
|
||||
out += "\x1";
|
||||
if(absoluteAddress >= 0) {
|
||||
out += HexUtilities::ToHex((uint32_t)absoluteAddress);
|
||||
}
|
||||
out += "\x1" + byteCode + "\x1" + code + "\x2" + addressing + "\x2";
|
||||
if(!comment.empty()) {
|
||||
out += ";" + comment;
|
||||
}
|
||||
out += "\n";
|
||||
return out;
|
||||
GetCodeLine(out, code, comment, cpuAddress, absoluteAddress, emptyString, emptyString, false, false);
|
||||
}
|
||||
|
||||
string Disassembler::GetSubHeader(DisassemblyInfo *info, string &label, uint16_t relativeAddr, uint16_t resetVector, uint16_t nmiVector, uint16_t irqVector)
|
||||
void Disassembler::GetCodeLine(string &out, string &code, string &comment, int32_t cpuAddress, int32_t absoluteAddress, string &byteCode, string &addressing, bool speculativeCode, bool isIndented)
|
||||
{
|
||||
char buffer[1000];
|
||||
int pos = 0;
|
||||
char* ptrBuf = buffer;
|
||||
int* ptrPos = &pos;
|
||||
|
||||
auto writeChar = [=](char c) -> void {
|
||||
if(*ptrPos < 999) {
|
||||
ptrBuf[(*ptrPos)++] = c;
|
||||
}
|
||||
};
|
||||
|
||||
auto writeHex = [=](const char* hex) -> void {
|
||||
if(*ptrPos < 950) {
|
||||
ptrBuf[(*ptrPos)++] = hex[0];
|
||||
ptrBuf[(*ptrPos)++] = hex[1];
|
||||
}
|
||||
};
|
||||
|
||||
auto writeStr = [=](string &str) -> void {
|
||||
uint32_t len = (uint32_t)str.size();
|
||||
if(*ptrPos + len < 950) {
|
||||
memcpy(ptrBuf + (*ptrPos), str.c_str(), len);
|
||||
(*ptrPos) += len;
|
||||
} else {
|
||||
len = 950 - *ptrPos;
|
||||
memcpy(ptrBuf + (*ptrPos), str.c_str(), len);
|
||||
(*ptrPos) += len;
|
||||
}
|
||||
};
|
||||
|
||||
//Fields:
|
||||
//Flags | CpuAddress | AbsAddr | ByteCode | Code | Addressing | Comment
|
||||
if(cpuAddress >= 0) {
|
||||
if(speculativeCode) {
|
||||
writeChar(isIndented ? '6' : '2');
|
||||
writeChar('\x1');
|
||||
} else {
|
||||
writeChar((_debugger->IsMarkedAsCode(cpuAddress) || absoluteAddress == -1) ? (isIndented ? '5' : '1') : (isIndented ? '4' : '0'));
|
||||
writeChar('\x1');
|
||||
}
|
||||
writeHex(hexTable[(cpuAddress >> 8) & 0xFF]);
|
||||
writeHex(hexTable[cpuAddress & 0xFF]);
|
||||
writeChar('\x1');
|
||||
} else {
|
||||
writeChar('1');
|
||||
writeChar('\x1');
|
||||
writeChar('\x1');
|
||||
}
|
||||
|
||||
if(absoluteAddress >= 0) {
|
||||
if(absoluteAddress > 0xFFFFFF) {
|
||||
writeHex(hexTable[(absoluteAddress >> 24) & 0xFF]);
|
||||
}
|
||||
if(absoluteAddress > 0xFFFF) {
|
||||
writeHex(hexTable[(absoluteAddress >> 16) & 0xFF]);
|
||||
}
|
||||
writeHex(hexTable[(absoluteAddress >> 8) & 0xFF]);
|
||||
writeHex(hexTable[absoluteAddress & 0xFF]);
|
||||
}
|
||||
|
||||
writeChar('\x1');
|
||||
writeStr(byteCode);
|
||||
writeChar('\x1');
|
||||
writeStr(code);
|
||||
writeChar('\x1');
|
||||
writeStr(addressing);
|
||||
writeChar('\x1');
|
||||
if(!comment.empty()) {
|
||||
writeChar(';');
|
||||
writeStr(comment);
|
||||
}
|
||||
writeChar('\x1');
|
||||
ptrBuf[(*ptrPos)++] = 0;
|
||||
|
||||
out.append(buffer, pos - 1);
|
||||
}
|
||||
|
||||
void Disassembler::GetSubHeader(string &out, DisassemblyInfo *info, string &label, uint16_t relativeAddr, uint16_t resetVector, uint16_t nmiVector, uint16_t irqVector)
|
||||
{
|
||||
if(info->IsSubEntryPoint()) {
|
||||
if(label.empty()) {
|
||||
return GetLine() + GetLine("__sub start__");
|
||||
GetLine(out);
|
||||
GetLine(out, "__sub start__");
|
||||
} else {
|
||||
return GetLine() + GetLine("__" + label + "()__");
|
||||
GetLine(out);
|
||||
GetLine(out, "__" + label + "()__");
|
||||
}
|
||||
} else if(relativeAddr == resetVector) {
|
||||
return GetLine() + GetLine("--reset--");
|
||||
GetLine(out);
|
||||
GetLine(out, "--reset--");
|
||||
} else if(relativeAddr == irqVector) {
|
||||
return GetLine() + GetLine("--irq--");
|
||||
GetLine(out);
|
||||
GetLine(out, "--irq--");
|
||||
} else if(relativeAddr == nmiVector) {
|
||||
return GetLine() + GetLine("--nmi--");
|
||||
GetLine(out);
|
||||
GetLine(out, "--nmi--");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memoryAddr, PrgMemoryType memoryType, bool showEffectiveAddresses, bool showOnlyDiassembledCode, State& cpuState, shared_ptr<MemoryManager> memoryManager, shared_ptr<LabelManager> labelManager)
|
||||
|
@ -330,51 +412,67 @@ string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memo
|
|||
uint32_t byteCount = 0;
|
||||
bool skippingCode = false;
|
||||
shared_ptr<CodeDataLogger> cdl = _debugger->GetCodeDataLogger();
|
||||
string label;
|
||||
string commentString;
|
||||
string commentLines;
|
||||
shared_ptr<DisassemblyInfo> infoRef;
|
||||
DisassemblyInfo* info;
|
||||
bool speculativeCode;
|
||||
string spaces = " ";
|
||||
string effAddress;
|
||||
string code;
|
||||
string byteCode;
|
||||
while(addr <= endAddr) {
|
||||
string label = labelManager->GetLabel(memoryAddr, false);
|
||||
string commentString = labelManager->GetComment(memoryAddr);
|
||||
string labelLine = label.empty() ? "" : GetLine(label + ":");
|
||||
string commentLines = "";
|
||||
bool speculativeCode = false;
|
||||
labelManager->GetLabelAndComment(memoryAddr, label, commentString);
|
||||
commentLines.clear();
|
||||
speculativeCode = false;
|
||||
|
||||
if(commentString.find_first_of('\n') != string::npos) {
|
||||
for(string &str : SplitComment(commentString)) {
|
||||
commentLines += GetLine("", str);
|
||||
GetLine(commentLines, "", str);
|
||||
}
|
||||
commentString = "";
|
||||
commentString.clear();
|
||||
}
|
||||
|
||||
shared_ptr<DisassemblyInfo> info = (*cache)[addr&mask];
|
||||
infoRef = (*cache)[addr&mask];
|
||||
|
||||
info = infoRef.get();
|
||||
if(!info && source == _prgRom) {
|
||||
if(_debugger->CheckFlag(DebuggerFlags::DisassembleEverything) || _debugger->CheckFlag(DebuggerFlags::DisassembleEverythingButData) && !cdl->IsData(addr)) {
|
||||
speculativeCode = true;
|
||||
info = shared_ptr<DisassemblyInfo>(new DisassemblyInfo(source + addr, false));
|
||||
info = new DisassemblyInfo(source + addr, false);
|
||||
}
|
||||
}
|
||||
|
||||
if(info && addr + info->GetSize() <= endAddr) {
|
||||
if(byteCount > 0) {
|
||||
output += GetLine(dbBuffer, "", dbRelativeAddr, dbAbsoluteAddr);
|
||||
GetLine(output, dbBuffer, "", dbRelativeAddr, dbAbsoluteAddr);
|
||||
byteCount = 0;
|
||||
}
|
||||
|
||||
if(skippingCode) {
|
||||
output += GetLine(unknownBlockHeader, "", (uint16_t)(memoryAddr - 1), addr - 1);
|
||||
GetLine(output, unknownBlockHeader, "", (uint16_t)(memoryAddr - 1), addr - 1);
|
||||
skippingCode = false;
|
||||
}
|
||||
|
||||
output += GetSubHeader(info.get(), label, memoryAddr, resetVector, nmiVector, irqVector);
|
||||
GetSubHeader(output, info, label, memoryAddr, resetVector, nmiVector, irqVector);
|
||||
output += commentLines;
|
||||
output += labelLine;
|
||||
|
||||
char* effectiveAddress = info->GetEffectiveAddressString(cpuState, memoryManager.get(), labelManager.get());
|
||||
if(!effectiveAddress) {
|
||||
effectiveAddress = "";
|
||||
if(!label.empty()) {
|
||||
GetLine(output, label + ":");
|
||||
}
|
||||
output += GetLine(" " + string(info->ToString(memoryAddr, memoryManager.get(), labelManager.get())), commentString, memoryAddr, source != _internalRam ? addr : -1, info->GetByteCode(), effectiveAddress, speculativeCode);
|
||||
|
||||
byteCode.clear();
|
||||
code.clear();
|
||||
effAddress.clear();
|
||||
info->GetEffectiveAddressString(effAddress, cpuState, memoryManager.get(), labelManager.get());
|
||||
info->ToString(code, memoryAddr, memoryManager.get(), labelManager.get());
|
||||
info->GetByteCode(byteCode);
|
||||
|
||||
GetCodeLine(output, code, commentString, memoryAddr, source != _internalRam ? addr : -1, byteCode, effAddress, speculativeCode, true);
|
||||
|
||||
if(info->IsSubExitPoint()) {
|
||||
output += GetLine("__sub end__") + GetLine();
|
||||
GetLine(output, "__sub end__");
|
||||
GetLine(output);
|
||||
}
|
||||
|
||||
if(speculativeCode) {
|
||||
|
@ -394,20 +492,20 @@ string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memo
|
|||
}
|
||||
} else {
|
||||
if((!label.empty() || !commentString.empty()) && skippingCode) {
|
||||
output += GetLine(unknownBlockHeader, "", (uint16_t)(memoryAddr - 1), addr - 1);
|
||||
GetLine(output, unknownBlockHeader, "", (uint16_t)(memoryAddr - 1), addr - 1);
|
||||
skippingCode = false;
|
||||
}
|
||||
|
||||
if(!skippingCode && showOnlyDiassembledCode) {
|
||||
if(label.empty()) {
|
||||
output += GetLine("__unknown block__", "", memoryAddr, addr);
|
||||
GetLine(output, "__unknown block__", "", memoryAddr, addr);
|
||||
if(!commentString.empty()) {
|
||||
output += GetLine("", commentString);
|
||||
GetLine(output, "", commentString);
|
||||
}
|
||||
} else {
|
||||
output += GetLine("__" + label + "__", "", memoryAddr, addr);
|
||||
GetLine(output, "__" + label + "__", "", memoryAddr, addr);
|
||||
if(!commentString.empty()) {
|
||||
output += GetLine("", commentString);
|
||||
GetLine(output, "", commentString);
|
||||
}
|
||||
output += commentLines;
|
||||
}
|
||||
|
@ -416,14 +514,16 @@ string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memo
|
|||
|
||||
if(!showOnlyDiassembledCode) {
|
||||
if(byteCount >= 8 || ((!label.empty() || !commentString.empty()) && byteCount > 0)) {
|
||||
output += GetLine(dbBuffer, "", dbRelativeAddr, dbAbsoluteAddr);
|
||||
GetLine(output, dbBuffer, "", dbRelativeAddr, dbAbsoluteAddr);
|
||||
byteCount = 0;
|
||||
}
|
||||
|
||||
if(byteCount == 0) {
|
||||
dbBuffer = ".db";
|
||||
output += commentLines;
|
||||
output += labelLine;
|
||||
if(!label.empty()) {
|
||||
GetLine(output, label + ":");
|
||||
}
|
||||
|
||||
dbRelativeAddr = memoryAddr;
|
||||
dbAbsoluteAddr = addr;
|
||||
|
@ -432,7 +532,7 @@ string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memo
|
|||
dbBuffer += " $" + HexUtilities::ToHex(source[addr&mask]);
|
||||
|
||||
if(!label.empty() || !commentString.empty()) {
|
||||
output += GetLine(dbBuffer, commentString, dbRelativeAddr, dbAbsoluteAddr);
|
||||
GetLine(output, dbBuffer, commentString, dbRelativeAddr, dbAbsoluteAddr);
|
||||
byteCount = 0;
|
||||
} else {
|
||||
byteCount++;
|
||||
|
@ -441,14 +541,18 @@ string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memo
|
|||
addr++;
|
||||
memoryAddr++;
|
||||
}
|
||||
|
||||
if(speculativeCode) {
|
||||
delete info;
|
||||
}
|
||||
}
|
||||
|
||||
if(byteCount > 0) {
|
||||
output += GetLine(dbBuffer, "", dbRelativeAddr, dbAbsoluteAddr);
|
||||
GetLine(output, dbBuffer, "", dbRelativeAddr, dbAbsoluteAddr);
|
||||
}
|
||||
|
||||
if(skippingCode) {
|
||||
output += GetLine("----", "", (uint16_t)(memoryAddr - 1), addr - 1);
|
||||
GetLine(output, "----", "", (uint16_t)(memoryAddr - 1), addr - 1);
|
||||
}
|
||||
|
||||
return output;
|
||||
|
|
|
@ -23,8 +23,9 @@ private:
|
|||
bool IsJump(uint8_t opCode);
|
||||
bool IsUnconditionalJump(uint8_t opCode);
|
||||
vector<string> SplitComment(string input);
|
||||
string GetLine(string code = "", string comment = "", int32_t cpuAddress = -1, int32_t absoluteAddress = -1, string byteCode = "", string addressing = "", bool speculativeCode = false);
|
||||
string GetSubHeader(DisassemblyInfo *info, string &label, uint16_t relativeAddr, uint16_t resetVector, uint16_t nmiVector, uint16_t irqVector);
|
||||
void GetLine(string &out, string code = "", string comment = string(), int32_t cpuAddress = -1, int32_t absoluteAddress = -1);
|
||||
void GetCodeLine(string &out, string &code, string &comment, int32_t cpuAddress, int32_t absoluteAddress, string &byteCode, string &addressing, bool speculativeCode, bool isCode);
|
||||
void GetSubHeader(string &out, DisassemblyInfo *info, string &label, uint16_t relativeAddr, uint16_t resetVector, uint16_t nmiVector, uint16_t irqVector);
|
||||
|
||||
public:
|
||||
Disassembler(uint8_t* internalRam, uint8_t* prgRom, uint32_t prgSize, uint8_t* prgRam, uint32_t prgRamSize, Debugger* debugger);
|
||||
|
|
|
@ -28,19 +28,16 @@ static const char* hexTable[256] = {
|
|||
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
|
||||
};
|
||||
|
||||
char* DisassemblyInfo::ToString(uint32_t memoryAddr, MemoryManager* memoryManager, LabelManager* labelManager)
|
||||
{
|
||||
uint16_t length;
|
||||
return ToString(memoryAddr, memoryManager, labelManager, length);
|
||||
}
|
||||
|
||||
char* DisassemblyInfo::ToString(uint32_t memoryAddr, MemoryManager* memoryManager, LabelManager* labelManager, uint16_t &length)
|
||||
void DisassemblyInfo::ToString(string &out, uint32_t memoryAddr, MemoryManager* memoryManager, LabelManager* labelManager)
|
||||
{
|
||||
char buffer[500];
|
||||
uint8_t opCode = *_opPointer;
|
||||
length = (uint16_t)DisassemblyInfo::OPName[opCode].size();
|
||||
memcpy(_toStringBuffer, DisassemblyInfo::OPName[opCode].c_str(), length);
|
||||
uint16_t length = (uint16_t)DisassemblyInfo::OPName[opCode].size();
|
||||
|
||||
memcpy(buffer, DisassemblyInfo::OPName[opCode].c_str(), length);
|
||||
|
||||
uint16_t* ptrPos = &length;
|
||||
char* ptrBuf = buffer;
|
||||
|
||||
uint16_t opAddr = GetOpAddr(memoryAddr);
|
||||
|
||||
|
@ -59,19 +56,19 @@ char* DisassemblyInfo::ToString(uint32_t memoryAddr, MemoryManager* memoryManage
|
|||
}
|
||||
|
||||
auto writeChar = [=](char c) -> void {
|
||||
_toStringBuffer[(*ptrPos)++] = c;
|
||||
ptrBuf[(*ptrPos)++] = c;
|
||||
};
|
||||
|
||||
auto copyOperand = [=]() -> void {
|
||||
if(labelManager && _opMode != AddrMode::Imm) {
|
||||
string label = labelManager->GetLabel(opAddr, true);
|
||||
if(!label.empty()) {
|
||||
memcpy(_toStringBuffer + (*ptrPos), label.c_str(), label.size());
|
||||
memcpy(ptrBuf + (*ptrPos), label.c_str(), label.size());
|
||||
(*ptrPos) += (uint16_t)label.size();
|
||||
return;
|
||||
}
|
||||
}
|
||||
memcpy(_toStringBuffer + (*ptrPos), opBuffer, operandLength);
|
||||
memcpy(ptrBuf + (*ptrPos), opBuffer, operandLength);
|
||||
(*ptrPos) += operandLength;
|
||||
};
|
||||
|
||||
|
@ -79,13 +76,13 @@ char* DisassemblyInfo::ToString(uint32_t memoryAddr, MemoryManager* memoryManage
|
|||
case AddrMode::Acc: writeChar('A'); break;
|
||||
case AddrMode::Imm: writeChar('#'); copyOperand(); break;
|
||||
case AddrMode::Ind: writeChar('('); copyOperand(); writeChar(')'); break;
|
||||
case AddrMode::IndX: writeChar('('); copyOperand(); memcpy(_toStringBuffer + length, ",X)", 3); length += 3; break;
|
||||
case AddrMode::IndX: writeChar('('); copyOperand(); memcpy(ptrBuf + length, ",X)", 3); length += 3; break;
|
||||
|
||||
case AddrMode::IndY:
|
||||
case AddrMode::IndYW:
|
||||
writeChar('(');
|
||||
copyOperand();
|
||||
memcpy(_toStringBuffer + length, "),Y", 3);
|
||||
memcpy(ptrBuf + length, "),Y", 3);
|
||||
length += 3;
|
||||
break;
|
||||
|
||||
|
@ -99,7 +96,7 @@ char* DisassemblyInfo::ToString(uint32_t memoryAddr, MemoryManager* memoryManage
|
|||
case AddrMode::AbsXW:
|
||||
case AddrMode::ZeroX:
|
||||
copyOperand();
|
||||
memcpy(_toStringBuffer + length, ",X", 2);
|
||||
memcpy(ptrBuf + length, ",X", 2);
|
||||
length += 2;
|
||||
break;
|
||||
|
||||
|
@ -107,14 +104,14 @@ char* DisassemblyInfo::ToString(uint32_t memoryAddr, MemoryManager* memoryManage
|
|||
case AddrMode::AbsYW:
|
||||
case AddrMode::ZeroY:
|
||||
copyOperand();
|
||||
memcpy(_toStringBuffer + length, ",Y", 2);
|
||||
memcpy(ptrBuf + length, ",Y", 2);
|
||||
length += 2;
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
_toStringBuffer[length] = 0;
|
||||
return _toStringBuffer;
|
||||
ptrBuf[length] = 0;
|
||||
out.append(ptrBuf, length);
|
||||
}
|
||||
|
||||
uint16_t DisassemblyInfo::GetOpAddr(uint16_t memoryAddr)
|
||||
|
@ -149,49 +146,45 @@ void DisassemblyInfo::SetSubEntryPoint()
|
|||
_isSubEntryPoint = true;
|
||||
}
|
||||
|
||||
char* DisassemblyInfo::GetEffectiveAddressString(State& cpuState, MemoryManager* memoryManager, LabelManager* labelManager)
|
||||
{
|
||||
uint16_t length;
|
||||
return GetEffectiveAddressString(cpuState, memoryManager, labelManager, length);
|
||||
}
|
||||
|
||||
char* DisassemblyInfo::GetEffectiveAddressString(State& cpuState, MemoryManager* memoryManager, LabelManager* labelManager, uint16_t& length)
|
||||
void DisassemblyInfo::GetEffectiveAddressString(string &out, State& cpuState, MemoryManager* memoryManager, LabelManager* labelManager)
|
||||
{
|
||||
if(_opMode <= AddrMode::Abs) {
|
||||
length = 0;
|
||||
return nullptr;
|
||||
return;
|
||||
} else {
|
||||
int32_t effectiveAddress = GetEffectiveAddress(cpuState, memoryManager);
|
||||
char buffer[500];
|
||||
|
||||
_effectiveAddressBuffer[0] = ' ';
|
||||
_effectiveAddressBuffer[1] = '@';
|
||||
_effectiveAddressBuffer[2] = ' ';
|
||||
int length = 0;
|
||||
buffer[0] = ' ';
|
||||
buffer[1] = '@';
|
||||
buffer[2] = ' ';
|
||||
|
||||
if(labelManager) {
|
||||
string label = labelManager->GetLabel(effectiveAddress, true);
|
||||
if(!label.empty()) {
|
||||
memcpy(_effectiveAddressBuffer + 3, label.c_str(), label.size());
|
||||
memcpy(buffer + 3, label.c_str(), label.size());
|
||||
length = (uint16_t)label.size() + 3;
|
||||
_effectiveAddressBuffer[length] = 0;
|
||||
buffer[length] = 0;
|
||||
|
||||
return _effectiveAddressBuffer;
|
||||
out.append(buffer, length);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_effectiveAddressBuffer[3] = '$';
|
||||
buffer[3] = '$';
|
||||
|
||||
if(_opMode == AddrMode::ZeroX || _opMode == AddrMode::ZeroY) {
|
||||
memcpy(_effectiveAddressBuffer + 4, hexTable[effectiveAddress], 2);
|
||||
_effectiveAddressBuffer[6] = 0;
|
||||
memcpy(buffer + 4, hexTable[effectiveAddress], 2);
|
||||
buffer[6] = 0;
|
||||
length = 6;
|
||||
} else {
|
||||
memcpy(_effectiveAddressBuffer + 4, hexTable[effectiveAddress >> 8], 2);
|
||||
memcpy(_effectiveAddressBuffer + 6, hexTable[effectiveAddress & 0xFF], 2);
|
||||
_effectiveAddressBuffer[8] = 0;
|
||||
memcpy(buffer + 4, hexTable[effectiveAddress >> 8], 2);
|
||||
memcpy(buffer + 6, hexTable[effectiveAddress & 0xFF], 2);
|
||||
buffer[8] = 0;
|
||||
length = 8;
|
||||
}
|
||||
|
||||
return _effectiveAddressBuffer;
|
||||
|
||||
out.append(buffer, length);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,19 +225,24 @@ int32_t DisassemblyInfo::GetEffectiveAddress(State& cpuState, MemoryManager* mem
|
|||
return -1;
|
||||
}
|
||||
|
||||
string DisassemblyInfo::GetByteCode()
|
||||
void DisassemblyInfo::GetByteCode(string &out)
|
||||
{
|
||||
//Raw byte code
|
||||
string byteCode;
|
||||
byteCode.reserve(12);
|
||||
char byteCode[12];
|
||||
int pos = 1;
|
||||
byteCode[0] = '$';
|
||||
for(uint32_t i = 0; i < _opSize; i++) {
|
||||
if(!byteCode.empty()) {
|
||||
byteCode += " ";
|
||||
if(i != 0) {
|
||||
byteCode[pos++] = ' ';
|
||||
byteCode[pos++] = '$';
|
||||
}
|
||||
byteCode += "$" + HexUtilities::ToHex((uint8_t)*(_opPointer + i));
|
||||
|
||||
byteCode[pos++] = hexTable[(uint8_t)*(_opPointer + i)][0];
|
||||
byteCode[pos++] = hexTable[(uint8_t)*(_opPointer + i)][1];
|
||||
}
|
||||
|
||||
return byteCode;
|
||||
byteCode[pos] = 0;
|
||||
out.append(byteCode, pos);
|
||||
}
|
||||
|
||||
uint32_t DisassemblyInfo::GetSize()
|
||||
|
|
|
@ -19,10 +19,7 @@ private:
|
|||
bool _isSubExitPoint = false;
|
||||
uint32_t _opSize = 0;
|
||||
AddrMode _opMode;
|
||||
|
||||
char _toStringBuffer[1000];
|
||||
char _effectiveAddressBuffer[1000];
|
||||
|
||||
|
||||
public:
|
||||
DisassemblyInfo(uint8_t* opPointer, bool isSubEntryPoint);
|
||||
|
||||
|
@ -30,12 +27,9 @@ public:
|
|||
|
||||
int32_t GetEffectiveAddress(State& cpuState, MemoryManager* memoryManager);
|
||||
|
||||
char* GetEffectiveAddressString(State& cpuState, MemoryManager* memoryManager, LabelManager* labelManager);
|
||||
char* GetEffectiveAddressString(State& cpuState, MemoryManager* memoryManager, LabelManager* labelManager, uint16_t &length);
|
||||
|
||||
char* ToString(uint32_t memoryAddr, MemoryManager* memoryManager, LabelManager* labelManager);
|
||||
char* ToString(uint32_t memoryAddr, MemoryManager* memoryManager, LabelManager* labelManager, uint16_t &length);
|
||||
string GetByteCode();
|
||||
void GetEffectiveAddressString(string &out, State& cpuState, MemoryManager* memoryManager, LabelManager* labelManager);
|
||||
void ToString(string &out, uint32_t memoryAddr, MemoryManager* memoryManager, LabelManager* labelManager);
|
||||
void GetByteCode(string &out);
|
||||
uint32_t GetSize();
|
||||
uint16_t GetOpAddr(uint16_t memoryAddr);
|
||||
|
||||
|
|
|
@ -98,6 +98,27 @@ string LabelManager::GetComment(uint16_t relativeAddr)
|
|||
return "";
|
||||
}
|
||||
|
||||
void LabelManager::GetLabelAndComment(uint16_t relativeAddr, string &label, string &comment)
|
||||
{
|
||||
int32_t labelAddr = GetLabelAddress(relativeAddr, false);
|
||||
|
||||
if(labelAddr >= 0) {
|
||||
auto result = _codeLabels.find(labelAddr);
|
||||
if(result != _codeLabels.end()) {
|
||||
label = result->second;
|
||||
} else {
|
||||
label.clear();
|
||||
}
|
||||
|
||||
auto commentResult = _codeComments.find(labelAddr);
|
||||
if(commentResult != _codeComments.end()) {
|
||||
comment = commentResult->second;
|
||||
} else {
|
||||
comment.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t LabelManager::GetLabelRelativeAddress(string label)
|
||||
{
|
||||
auto result = _codeLabelReverseLookup.find(label);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
using std::unordered_map;
|
||||
|
||||
class BaseMapper;
|
||||
|
@ -9,9 +10,9 @@ enum class AddressType;
|
|||
class LabelManager
|
||||
{
|
||||
private:
|
||||
unordered_map<uint32_t, string> _codeLabels;
|
||||
unordered_map<uint32_t, string, std::function<size_t(const uint32_t &addr)>> _codeLabels = unordered_map<uint32_t, string, std::function<size_t(const uint32_t &addr)>>(10000, [](const uint32_t & addr) { return addr; });
|
||||
unordered_map<uint32_t, string, std::function<size_t(const uint32_t &addr)>> _codeComments = unordered_map<uint32_t, string, std::function<size_t(const uint32_t &addr)>>(10000, [](const uint32_t & addr) { return addr; });
|
||||
unordered_map<string, uint32_t> _codeLabelReverseLookup;
|
||||
unordered_map<uint32_t, string> _codeComments;
|
||||
|
||||
shared_ptr<BaseMapper> _mapper;
|
||||
|
||||
|
@ -26,4 +27,5 @@ public:
|
|||
|
||||
string GetLabel(uint16_t relativeAddr, bool checkRegisters);
|
||||
string GetComment(uint16_t relativeAddr);
|
||||
void GetLabelAndComment(uint16_t relativeAddr, string &label, string &comment);
|
||||
};
|
||||
|
|
|
@ -84,7 +84,9 @@ void TraceLogger::GetTraceRow(string &output, State &cpuState, PPUDebugState &pp
|
|||
output += HexUtilities::ToHex(cpuState.DebugPC) + " ";
|
||||
|
||||
if(_options.ShowByteCode) {
|
||||
output += disassemblyInfo->GetByteCode() + std::string(13 - disassemblyInfo->GetByteCode().size(), ' ');
|
||||
string byteCode;
|
||||
disassemblyInfo->GetByteCode(byteCode);
|
||||
output += byteCode + std::string(13 - byteCode.size(), ' ');
|
||||
}
|
||||
|
||||
int indentLevel = 0;
|
||||
|
@ -93,17 +95,12 @@ void TraceLogger::GetTraceRow(string &output, State &cpuState, PPUDebugState &pp
|
|||
output += std::string(indentLevel, ' ');
|
||||
}
|
||||
|
||||
uint16_t disassemblyLength = 0;
|
||||
uint16_t effectiveAddressLength = 0;
|
||||
string code;
|
||||
LabelManager* labelManager = _options.UseLabels ? _labelManager.get() : nullptr;
|
||||
char* disassembly = disassemblyInfo->ToString(cpuState.DebugPC, _memoryManager.get(), labelManager, disassemblyLength);
|
||||
char* effectiveAddress = (_options.ShowEffectiveAddresses ? disassemblyInfo->GetEffectiveAddressString(cpuState, _memoryManager.get(), labelManager, effectiveAddressLength) : nullptr);
|
||||
|
||||
output += disassembly;
|
||||
if(effectiveAddress) {
|
||||
output += effectiveAddress;
|
||||
}
|
||||
output += std::string(32 - disassemblyLength - effectiveAddressLength, ' ');
|
||||
disassemblyInfo->ToString(code, cpuState.DebugPC, _memoryManager.get(), labelManager);
|
||||
disassemblyInfo->GetEffectiveAddressString(code, cpuState, _memoryManager.get(), labelManager);
|
||||
code += std::string(32 - code.size(), ' ');
|
||||
output += code;
|
||||
|
||||
if(_options.ShowRegisters) {
|
||||
output += " A:" + HexUtilities::ToHex(cpuState.A) +
|
||||
|
|
|
@ -97,10 +97,14 @@ namespace Mesen.GUI.Debugger
|
|||
|
||||
private void UpdateStack(UInt16 stackPointer)
|
||||
{
|
||||
lstStack.BeginUpdate();
|
||||
lstStack.Items.Clear();
|
||||
for(UInt32 i = (UInt32)0x100 + stackPointer; i < 0x200; i++) {
|
||||
lstStack.Items.Add("$" + InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, i).ToString("X2"));
|
||||
ListViewItem[] itemsToAdd = new ListViewItem[256 - stackPointer];
|
||||
for(UInt32 i = (UInt32)0x100 + stackPointer; i < 0x200; i++) {
|
||||
itemsToAdd[i-stackPointer-0x100] = new ListViewItem("$" + InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, i).ToString("X2"));
|
||||
}
|
||||
lstStack.Items.AddRange(itemsToAdd);
|
||||
lstStack.EndUpdate();
|
||||
}
|
||||
|
||||
public void UpdateStatus(ref DebugState state)
|
||||
|
|
|
@ -21,10 +21,23 @@ namespace Mesen.GUI.Debugger
|
|||
public event AssemblerEventHandler OnEditCode;
|
||||
public event AddressEventHandler OnSetNextStatement;
|
||||
private DebugViewInfo _config;
|
||||
|
||||
List<int> _lineNumbers = new List<int>(10000);
|
||||
List<string> _lineNumberNotes = new List<string>(10000);
|
||||
List<string> _codeNotes = new List<string>(10000);
|
||||
List<string> _codeLines = new List<string>(10000);
|
||||
private HashSet<int> _unexecutedAddresses = new HashSet<int>();
|
||||
private HashSet<int> _speculativeCodeAddreses = new HashSet<int>();
|
||||
Dictionary<int, string> _codeContent = new Dictionary<int, string>(10000);
|
||||
Dictionary<int, string> _codeComments = new Dictionary<int, string>(10000);
|
||||
Dictionary<int, string> _codeByteCode = new Dictionary<int, string>(10000);
|
||||
List<string> _addressing = new List<string>(10000);
|
||||
List<string> _comments = new List<string>(10000);
|
||||
List<int> _lineIndentations = new List<int>(10000);
|
||||
|
||||
private Color _unexecutedColor = Color.FromArgb(183, 229, 190);
|
||||
private Color _speculativeColor = Color.FromArgb(240, 220, 220);
|
||||
private UInt32? _currentActiveAddress { get; set; } = null;
|
||||
|
||||
private frmCodeTooltip _codeTooltip = null;
|
||||
|
||||
|
@ -124,7 +137,6 @@ namespace Mesen.GUI.Debugger
|
|||
}
|
||||
}
|
||||
|
||||
private UInt32? _currentActiveAddress = null;
|
||||
public void SelectActiveAddress(UInt32 address)
|
||||
{
|
||||
this.SetActiveAddress(address);
|
||||
|
@ -144,30 +156,10 @@ namespace Mesen.GUI.Debugger
|
|||
public void UpdateLineColors()
|
||||
{
|
||||
this.ctrlCodeViewer.BeginUpdate();
|
||||
|
||||
this.ctrlCodeViewer.ClearLineStyles();
|
||||
|
||||
if(_currentActiveAddress.HasValue) {
|
||||
this.ctrlCodeViewer.SetLineColor((int)_currentActiveAddress, Color.Black, Color.Yellow, null, LineSymbol.Arrow);
|
||||
}
|
||||
|
||||
if(ConfigManager.Config.DebugInfo.HighlightUnexecutedCode) {
|
||||
foreach(int relativeAddress in _unexecutedAddresses) {
|
||||
this.ctrlCodeViewer.SetLineColor(relativeAddress, null, _unexecutedColor);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(int relativeAddress in _speculativeCodeAddreses) {
|
||||
this.ctrlCodeViewer.SetLineColor(relativeAddress, null, _speculativeColor);
|
||||
}
|
||||
|
||||
this.HighlightBreakpoints();
|
||||
|
||||
this.ctrlCodeViewer.StyleProvider = new LineStyleProvider(this);
|
||||
this.ctrlCodeViewer.EndUpdate();
|
||||
}
|
||||
|
||||
Dictionary<int, string> _codeContent = new Dictionary<int, string>();
|
||||
Dictionary<int, int> _codeByteContentLength = new Dictionary<int, int>();
|
||||
public List<string> GetCode(out int byteLength, ref int startAddress, int endAddress = -1)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
|
@ -184,7 +176,10 @@ namespace Mesen.GUI.Debugger
|
|||
//TODO: Invalidate disassembly info cache / CDL file (not needed?)
|
||||
//TODO: Support .data syntax in assembler
|
||||
for(int i = startAddress; (i <= endAddress || endAddress == -1) && endAddress < 65536; ) {
|
||||
if(_codeContent.TryGetValue(i, out string code)) {
|
||||
string code;
|
||||
if(_codeContent.TryGetValue(i, out code)) {
|
||||
code = code.Split('\x2')[0].Trim();
|
||||
|
||||
if(code.StartsWith("--") || code.StartsWith("__") || code.StartsWith("[[")) {
|
||||
//Stop adding code when we find a new section (new function, data blocks, etc.)
|
||||
break;
|
||||
|
@ -196,6 +191,16 @@ namespace Mesen.GUI.Debugger
|
|||
string comment = codeLabel?.Comment;
|
||||
string label = codeLabel?.Label;
|
||||
|
||||
if(code == "STP*" || code == "NOP*") {
|
||||
//Transform unofficial opcodes that can't be reassembled properly into .byte statements
|
||||
if(comment != null) {
|
||||
comment.Insert(1, code + " - ");
|
||||
} else {
|
||||
comment = code;
|
||||
}
|
||||
code = ".byte " + string.Join(",", _codeByteCode[i].Split(' ').Select((hexByte) => "$" + hexByte));
|
||||
}
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(comment) && comment.Contains("\n")) {
|
||||
result.AddRange(comment.Replace("\r", "").Split('\n').Select(cmt => ";" + cmt));
|
||||
comment = null;
|
||||
|
@ -205,7 +210,7 @@ namespace Mesen.GUI.Debugger
|
|||
}
|
||||
result.Add(" " + code + (!string.IsNullOrWhiteSpace(comment) ? (" ;" + comment) : ""));
|
||||
|
||||
int length = _codeByteContentLength[i];
|
||||
int length = _codeByteCode[i].Count(c => c == ' ') + 1;
|
||||
byteLength += length;
|
||||
i += length;
|
||||
|
||||
|
@ -223,46 +228,84 @@ namespace Mesen.GUI.Debugger
|
|||
public bool UpdateCode(bool forceUpdate = false)
|
||||
{
|
||||
if(_codeChanged || forceUpdate) {
|
||||
List<int> lineNumbers = new List<int>();
|
||||
List<string> lineNumberNotes = new List<string>();
|
||||
List<string> codeNotes = new List<string>();
|
||||
List<string> codeLines = new List<string>();
|
||||
_codeContent = new Dictionary<int, string>();
|
||||
_codeByteContentLength = new Dictionary<int, int>();
|
||||
_unexecutedAddresses = new HashSet<int>();
|
||||
_speculativeCodeAddreses = new HashSet<int>();
|
||||
|
||||
int index = -1;
|
||||
int previousIndex = -1;
|
||||
while((index = _code.IndexOf('\n', index + 1)) >= 0) {
|
||||
string line = _code.Substring(previousIndex + 1, index - previousIndex - 1);
|
||||
string[] lineParts = line.Split('\x1');
|
||||
_codeContent.Clear();
|
||||
_codeComments.Clear();
|
||||
_codeByteCode.Clear();
|
||||
_unexecutedAddresses.Clear();
|
||||
_speculativeCodeAddreses.Clear();
|
||||
|
||||
if(lineParts.Length >= 5) {
|
||||
int relativeAddress = ParseHexAddress(lineParts[1]);
|
||||
string[] token = new string[7];
|
||||
int tokenIndex = 0;
|
||||
int startPos = 0;
|
||||
int endPos = 0;
|
||||
|
||||
if(lineParts[0] == "0" && lineParts[4].StartsWith(" ")) {
|
||||
_unexecutedAddresses.Add(relativeAddress);
|
||||
} else if(lineParts[0] == "2" && lineParts[4].StartsWith(" ")) {
|
||||
_speculativeCodeAddreses.Add(relativeAddress);
|
||||
}
|
||||
Action readToken = () => {
|
||||
endPos = _code.IndexOf('\x1', endPos) + 1;
|
||||
token[tokenIndex++] = _code.Substring(startPos, endPos - startPos - 1);
|
||||
startPos = endPos;
|
||||
};
|
||||
|
||||
Action readLine = () => {
|
||||
tokenIndex = 0;
|
||||
readToken(); readToken(); readToken(); readToken(); readToken(); readToken(); readToken();
|
||||
};
|
||||
|
||||
lineNumbers.Add(relativeAddress);
|
||||
lineNumberNotes.Add(string.IsNullOrWhiteSpace(lineParts[2]) ? "" : lineParts[2].TrimStart('0').PadLeft(4, '0'));
|
||||
codeNotes.Add(lineParts[3]);
|
||||
codeLines.Add(lineParts[4]);
|
||||
_codeByteContentLength[relativeAddress] = lineParts[3].Count(c => c == ' ') + 1;
|
||||
Func<bool> processLine = () => {
|
||||
readLine();
|
||||
|
||||
_codeContent[relativeAddress] = lineParts[4].Split('\x2')[0].Trim();
|
||||
int relativeAddress = ParseHexAddress(token[1]);
|
||||
|
||||
//Flags:
|
||||
//1: Executed code
|
||||
//2: Speculative Code
|
||||
//4: Indented line
|
||||
if(token[0] == "4") {
|
||||
_unexecutedAddresses.Add(relativeAddress);
|
||||
_lineIndentations.Add(20);
|
||||
} else if(token[0] == "6") {
|
||||
_speculativeCodeAddreses.Add(relativeAddress);
|
||||
_lineIndentations.Add(20);
|
||||
} else if(token[0] == "5") {
|
||||
_lineIndentations.Add(20);
|
||||
} else {
|
||||
_lineIndentations.Add(0);
|
||||
}
|
||||
|
||||
previousIndex = index;
|
||||
}
|
||||
_lineNumbers.Add(relativeAddress);
|
||||
_lineNumberNotes.Add(string.IsNullOrWhiteSpace(token[2]) ? "" : (token[2].Length > 5 ? token[2].TrimStart('0').PadLeft(4, '0') : token[2]));
|
||||
_codeNotes.Add(token[3]);
|
||||
_codeLines.Add(token[4]);
|
||||
|
||||
ctrlCodeViewer.TextLines = codeLines.ToArray();
|
||||
ctrlCodeViewer.LineNumbers = lineNumbers.ToArray();
|
||||
ctrlCodeViewer.TextLineNotes = codeNotes.ToArray();
|
||||
ctrlCodeViewer.LineNumberNotes = lineNumberNotes.ToArray();
|
||||
_addressing.Add(token[5]);
|
||||
_comments.Add(token[6]);
|
||||
|
||||
//Used by assembler
|
||||
_codeByteCode[relativeAddress] = token[3];
|
||||
_codeContent[relativeAddress] = token[4];
|
||||
_codeComments[relativeAddress] = token[6];
|
||||
|
||||
return endPos < _code.Length;
|
||||
};
|
||||
|
||||
while(processLine());
|
||||
|
||||
ctrlCodeViewer.LineIndentations = _lineIndentations.ToArray();
|
||||
ctrlCodeViewer.Addressing = _addressing.ToArray();
|
||||
ctrlCodeViewer.Comments = _comments.ToArray();
|
||||
|
||||
ctrlCodeViewer.TextLines = _codeLines.ToArray();
|
||||
ctrlCodeViewer.LineNumbers = _lineNumbers.ToArray();
|
||||
ctrlCodeViewer.TextLineNotes = _codeNotes.ToArray();
|
||||
ctrlCodeViewer.LineNumberNotes = _lineNumberNotes.ToArray();
|
||||
|
||||
//These are all temporary and can be cleared right away
|
||||
_lineNumbers.Clear();
|
||||
_lineNumberNotes.Clear();
|
||||
_codeNotes.Clear();
|
||||
_codeLines.Clear();
|
||||
_addressing.Clear();
|
||||
_comments.Clear();
|
||||
_lineIndentations.Clear();
|
||||
|
||||
_codeChanged = false;
|
||||
UpdateLineColors();
|
||||
|
@ -281,37 +324,6 @@ namespace Mesen.GUI.Debugger
|
|||
}
|
||||
}
|
||||
|
||||
private void HighlightBreakpoints()
|
||||
{
|
||||
foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) {
|
||||
Color? fgColor = Color.White;
|
||||
Color? bgColor = null;
|
||||
Color? outlineColor = Color.FromArgb(140, 40, 40);
|
||||
LineSymbol symbol;
|
||||
if(breakpoint.Enabled) {
|
||||
bgColor = Color.FromArgb(140, 40, 40);
|
||||
symbol = LineSymbol.Circle;
|
||||
} else {
|
||||
fgColor = Color.Black;
|
||||
symbol = LineSymbol.CircleOutline;
|
||||
}
|
||||
|
||||
if(breakpoint.Address == (UInt32)(_currentActiveAddress.HasValue ? (int)_currentActiveAddress.Value : -1)) {
|
||||
fgColor = Color.Black;
|
||||
bgColor = Color.Yellow;
|
||||
symbol |= LineSymbol.Arrow;
|
||||
} else if(_unexecutedAddresses.Contains((Int32)breakpoint.Address)) {
|
||||
fgColor = Color.Black;
|
||||
bgColor = _unexecutedColor;
|
||||
} else if(_speculativeCodeAddreses.Contains((Int32)breakpoint.Address)) {
|
||||
fgColor = Color.Black;
|
||||
bgColor = _speculativeColor;
|
||||
}
|
||||
|
||||
ctrlCodeViewer.SetLineColor((int)breakpoint.Address, fgColor, bgColor, outlineColor, symbol);
|
||||
}
|
||||
}
|
||||
|
||||
#region Events
|
||||
private Point _previousLocation;
|
||||
private bool _preventCloseTooltip = false;
|
||||
|
@ -766,6 +778,58 @@ namespace Mesen.GUI.Debugger
|
|||
this.OnEditCode?.Invoke(new AssemblerEventArgs() { Code = string.Join(Environment.NewLine, code), StartAddress = (UInt16)startAddress, BlockLength = (UInt16)byteLength });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class LineStyleProvider : ctrlTextbox.ILineStyleProvider
|
||||
{
|
||||
ctrlDebuggerCode _code;
|
||||
public LineStyleProvider(ctrlDebuggerCode code)
|
||||
{
|
||||
_code = code;
|
||||
}
|
||||
|
||||
public LineProperties GetLineStyle(int cpuAddress)
|
||||
{
|
||||
foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) {
|
||||
if(!breakpoint.IsAbsoluteAddress && breakpoint.Address == cpuAddress) {
|
||||
Color? fgColor = Color.White;
|
||||
Color? bgColor = null;
|
||||
Color? outlineColor = Color.FromArgb(140, 40, 40);
|
||||
LineSymbol symbol;
|
||||
if(breakpoint.Enabled) {
|
||||
bgColor = Color.FromArgb(140, 40, 40);
|
||||
symbol = LineSymbol.Circle;
|
||||
} else {
|
||||
fgColor = Color.Black;
|
||||
symbol = LineSymbol.CircleOutline;
|
||||
}
|
||||
|
||||
if(breakpoint.Address == (UInt32)(_code._currentActiveAddress.HasValue ? (int)_code._currentActiveAddress.Value : -1)) {
|
||||
fgColor = Color.Black;
|
||||
bgColor = Color.Yellow;
|
||||
symbol |= LineSymbol.Arrow;
|
||||
} else if(_code._unexecutedAddresses.Contains((Int32)breakpoint.Address)) {
|
||||
fgColor = Color.Black;
|
||||
bgColor = _code._unexecutedColor;
|
||||
} else if(_code._speculativeCodeAddreses.Contains((Int32)breakpoint.Address)) {
|
||||
fgColor = Color.Black;
|
||||
bgColor = _code._speculativeColor;
|
||||
}
|
||||
|
||||
return new LineProperties() { FgColor = fgColor, BgColor = bgColor, OutlineColor = outlineColor, Symbol = symbol };
|
||||
}
|
||||
}
|
||||
|
||||
if(_code._currentActiveAddress.HasValue && cpuAddress == _code._currentActiveAddress) {
|
||||
return new LineProperties() { FgColor = Color.Black, BgColor = Color.Yellow, OutlineColor = null, Symbol = LineSymbol.Arrow };
|
||||
} else if(ConfigManager.Config.DebugInfo.HighlightUnexecutedCode && _code._unexecutedAddresses.Contains(cpuAddress)) {
|
||||
return new LineProperties() { FgColor = null, BgColor = _code._unexecutedColor, OutlineColor = null, Symbol = LineSymbol.None };
|
||||
} else if(_code._speculativeCodeAddreses.Contains(cpuAddress)) {
|
||||
return new LineProperties() { FgColor = null, BgColor = _code._speculativeColor, OutlineColor = null, Symbol = LineSymbol.None };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class WatchEventArgs : EventArgs
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
Int32[] entryPoints = InteropEmu.DebugGetFunctionEntryPoints();
|
||||
bool updating = false;
|
||||
|
||||
for(int i = 0; entryPoints[i] >= 0; i++) {
|
||||
for(int i = 0; entryPoints[i] >= 0 && i < entryPoints.Length; i++) {
|
||||
Int32 entryPoint = entryPoints[i];
|
||||
ListViewItem item;
|
||||
if(!_functions.TryGetValue(entryPoint, out item)) {
|
||||
|
|
|
@ -32,8 +32,6 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
|
||||
public void RefreshData()
|
||||
{
|
||||
ctrlScrollableTextbox.ClearLineStyles();
|
||||
|
||||
int[] readCounts = InteropEmu.DebugGetMemoryAccessCounts(_memoryType, MemoryOperationType.Read, false);
|
||||
int[] writeCounts = InteropEmu.DebugGetMemoryAccessCounts(_memoryType, MemoryOperationType.Write, false);
|
||||
int[] execCounts = InteropEmu.DebugGetMemoryAccessCounts(_memoryType, MemoryOperationType.Exec, false);
|
||||
|
@ -74,16 +72,31 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
content[i] = data[i].Content;
|
||||
}
|
||||
|
||||
if(chkHighlightUninitRead.Checked) {
|
||||
ctrlScrollableTextbox.StyleProvider = new LineStyleProvider(new HashSet<int>(data.Where((e) => e.UninitRead).Select((e) => e.Address)));
|
||||
} else {
|
||||
ctrlScrollableTextbox.StyleProvider = null;
|
||||
}
|
||||
ctrlScrollableTextbox.Header = "Read".PadRight(12) + "Write".PadRight(12) + "Execute".PadRight(12);
|
||||
ctrlScrollableTextbox.LineNumbers = addresses;
|
||||
ctrlScrollableTextbox.TextLines = content;
|
||||
}
|
||||
|
||||
if(chkHighlightUninitRead.Checked) {
|
||||
ctrlScrollableTextbox.BeginUpdate();
|
||||
foreach(int address in data.Where((e) => e.UninitRead).Select((e) => e.Address)) {
|
||||
ctrlScrollableTextbox.SetLineColor(address, null, Color.LightCoral);
|
||||
private class LineStyleProvider : ctrlTextbox.ILineStyleProvider
|
||||
{
|
||||
HashSet<int> _addresses = new HashSet<int>();
|
||||
|
||||
public LineStyleProvider(HashSet<int> addresses)
|
||||
{
|
||||
_addresses = addresses;
|
||||
}
|
||||
|
||||
public LineProperties GetLineStyle(int cpuAddress)
|
||||
{
|
||||
if(_addresses.Contains(cpuAddress)) {
|
||||
return new LineProperties() { BgColor = Color.LightCoral };
|
||||
}
|
||||
ctrlScrollableTextbox.EndUpdate();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -105,11 +105,6 @@ namespace Mesen.GUI.Debugger
|
|||
this.hScrollBar.Maximum = newMax;
|
||||
}
|
||||
|
||||
public void ClearLineStyles()
|
||||
{
|
||||
this.ctrlTextbox.ClearLineStyles();
|
||||
}
|
||||
|
||||
public void BeginUpdate()
|
||||
{
|
||||
this.ctrlTextbox.BeginUpdate();
|
||||
|
@ -120,10 +115,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlTextbox.EndUpdate();
|
||||
}
|
||||
|
||||
public void SetLineColor(int lineNumber, Color? fgColor = null, Color? bgColor = null, Color? outlineColor = null, LineSymbol symbol = LineSymbol.None)
|
||||
{
|
||||
this.ctrlTextbox.SetLineColor(lineNumber, fgColor, bgColor, outlineColor, symbol);
|
||||
}
|
||||
public ctrlTextbox.ILineStyleProvider StyleProvider { set { this.ctrlTextbox.StyleProvider = value; } }
|
||||
|
||||
public int GetLineIndex(int lineNumber)
|
||||
{
|
||||
|
@ -267,6 +259,10 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlTextbox.HorizontalScrollPosition = this.hScrollBar.Value;
|
||||
}
|
||||
|
||||
public string[] Addressing { set { this.ctrlTextbox.Addressing = value; } }
|
||||
public string[] Comments { set { this.ctrlTextbox.Comments = value; } }
|
||||
public int[] LineIndentations{ set { this.ctrlTextbox.LineIndentations = value; } }
|
||||
|
||||
public string[] TextLines
|
||||
{
|
||||
set
|
||||
|
|
|
@ -79,6 +79,10 @@ namespace Mesen.GUI.Debugger
|
|||
this.DoubleBuffered = true;
|
||||
}
|
||||
|
||||
public string[] Comments;
|
||||
public string[] Addressing;
|
||||
public int[] LineIndentations;
|
||||
|
||||
public string[] TextLines
|
||||
{
|
||||
set
|
||||
|
@ -86,18 +90,17 @@ namespace Mesen.GUI.Debugger
|
|||
int maxLength = 0;
|
||||
|
||||
_maxLineWidthIndex = 0;
|
||||
|
||||
_contents = new string[value.Length];
|
||||
_lineMargins = new int[value.Length];
|
||||
|
||||
_contents = value;
|
||||
for(int i = 0, len = value.Length; i < len; i++) {
|
||||
_contents[i] = value[i].TrimStart();
|
||||
|
||||
string stringToMeasure = GetFullWidthString(_contents[i]);
|
||||
if(stringToMeasure.Length > maxLength) {
|
||||
maxLength = stringToMeasure.Length;
|
||||
int length = _contents[i].Length + (Addressing != null ? Addressing[i].Length : 0);
|
||||
if(Comments?[i].Length > 0) {
|
||||
length = Math.Max(length, length > 0 ? CommentSpacingCharCount : 0) + Comments[i].Length;
|
||||
}
|
||||
if(length > maxLength) {
|
||||
maxLength = length;
|
||||
_maxLineWidthIndex = i;
|
||||
}
|
||||
_lineMargins[i] = (value[i].Length - _contents[i].Length) * 10;
|
||||
}
|
||||
|
||||
UpdateHorizontalScrollWidth();
|
||||
|
@ -243,9 +246,8 @@ namespace Mesen.GUI.Debugger
|
|||
}
|
||||
|
||||
for(int i = 0, len = _contents.Length; i < len; i++) {
|
||||
if(Regex.IsMatch(_contents[i], regex, matchCase ? RegexOptions.None : RegexOptions.IgnoreCase)) {
|
||||
string line = _contents[i].Replace("\x2", "\t").Trim();
|
||||
|
||||
string line = _contents[i] + Addressing?[i] + (Comments != null ? ("\t" + Comments[i]) : null);
|
||||
if(Regex.IsMatch(line, regex, matchCase ? RegexOptions.None : RegexOptions.IgnoreCase)) {
|
||||
if(line.StartsWith("__") && line.EndsWith("__") || line.StartsWith("[[") && line.EndsWith("]]")) {
|
||||
line = "Block: " + line.Substring(2, line.Length - 4);
|
||||
}
|
||||
|
@ -335,22 +337,20 @@ namespace Mesen.GUI.Debugger
|
|||
this.Invalidate();
|
||||
}
|
||||
|
||||
public void SetLineColor(int lineNumber, Color? fgColor = null, Color? bgColor = null, Color? outlineColor = null, LineSymbol symbol = LineSymbol.None)
|
||||
public interface ILineStyleProvider
|
||||
{
|
||||
if(lineNumber != -1) {
|
||||
if(_lineNumberIndex.ContainsKey(lineNumber)) {
|
||||
LineProperties properties = new LineProperties() {
|
||||
BgColor = bgColor,
|
||||
FgColor = fgColor,
|
||||
OutlineColor = outlineColor,
|
||||
Symbol = symbol
|
||||
};
|
||||
LineProperties GetLineStyle(int cpuAddress);
|
||||
}
|
||||
|
||||
_lineProperties[_lineNumberIndex[lineNumber]] = properties;
|
||||
if(!_updating) {
|
||||
this.Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public ILineStyleProvider StyleProvider { get; set; }
|
||||
|
||||
public LineProperties GetLineStyle(int lineNumber)
|
||||
{
|
||||
if(StyleProvider != null && _lineNumbers[lineNumber] >= 0) {
|
||||
return StyleProvider.GetLineStyle(_lineNumbers[lineNumber]);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,7 +419,7 @@ namespace Mesen.GUI.Debugger
|
|||
private int GetMargin(Graphics g, bool getExtendedMargin)
|
||||
{
|
||||
int marginWidth = getExtendedMargin && this.ShowContentNotes && this.ShowSingleContentLineNotes ? _marginWidth + _extendedMarginWidth : _marginWidth;
|
||||
return this.ShowLineNumbers ? (int)(g.MeasureString("".PadLeft(marginWidth, 'W'), this.Font).Width) : 0;
|
||||
return (this.ShowLineNumbers ? (int)(g.MeasureString("".PadLeft(marginWidth, 'W'), this.Font).Width) : 0) - 1;
|
||||
}
|
||||
|
||||
public int GetLineIndexAtPosition(int yPos)
|
||||
|
@ -430,14 +430,12 @@ namespace Mesen.GUI.Debugger
|
|||
return lineIndex;
|
||||
}
|
||||
|
||||
private string GetFullWidthString(string lineContent)
|
||||
private string GetFullWidthString(int lineIndex)
|
||||
{
|
||||
string text = lineContent.Replace("\x2", "");
|
||||
int commentIndex = text.IndexOf(";");
|
||||
if(commentIndex > 0 && commentIndex < CommentSpacingCharCount) {
|
||||
text = text.Insert(commentIndex, "".PadLeft(CommentSpacingCharCount - commentIndex));
|
||||
string text = _contents[lineIndex] + Addressing?[lineIndex];
|
||||
if(Comments?[lineIndex].Length > 0) {
|
||||
return text.PadRight(text.Length > 0 ? CommentSpacingCharCount : 0) + Comments[lineIndex];
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
@ -453,9 +451,9 @@ namespace Mesen.GUI.Debugger
|
|||
}
|
||||
|
||||
if(positionX >= 0 && lineIndex < _contents.Length) {
|
||||
string text = this.GetFullWidthString(_contents[lineIndex]);
|
||||
string text = this.GetFullWidthString(lineIndex);
|
||||
//Adjust background color highlights based on number of spaces in front of content
|
||||
positionX -= _lineMargins[lineIndex];
|
||||
positionX -= (LineIndentations != null ? LineIndentations[lineIndex] : 0);
|
||||
|
||||
int previousWidth = 0;
|
||||
for(int i = 0, len = text.Length; i < len; i++) {
|
||||
|
@ -476,7 +474,7 @@ namespace Mesen.GUI.Debugger
|
|||
int charIndex;
|
||||
int lineIndex;
|
||||
if(this.GetCharIndex(position, out charIndex, out lineIndex)) {
|
||||
string text = (useCompareText && _compareContents != null) ? _compareContents[lineIndex] : this.GetFullWidthString(_contents[lineIndex]);
|
||||
string text = (useCompareText && _compareContents != null) ? _compareContents[lineIndex] : this.GetFullWidthString(lineIndex);
|
||||
List<char> wordDelimiters = new List<char>(new char[] { ' ', ',', '|', ';', '(', ')', '.', '-', ':' });
|
||||
if(wordDelimiters.Contains(text[charIndex])) {
|
||||
return string.Empty;
|
||||
|
@ -656,7 +654,7 @@ namespace Mesen.GUI.Debugger
|
|||
{
|
||||
if(_contents.Length > _maxLineWidthIndex) {
|
||||
using(Graphics g = this.CreateGraphics()) {
|
||||
_maxLineWidth = _lineMargins[_maxLineWidthIndex] + g.MeasureString(GetFullWidthString(_contents[_maxLineWidthIndex]), this.Font).Width;
|
||||
_maxLineWidth = (LineIndentations != null ? LineIndentations[_maxLineWidthIndex] : 0) + g.MeasureString(GetFullWidthString(_maxLineWidthIndex), this.Font).Width;
|
||||
HorizontalScrollWidth = (int)(Math.Max(0, HorizontalScrollFactor + _maxLineWidth - (this.Width - GetMargin(g, true))) / HorizontalScrollFactor);
|
||||
}
|
||||
}
|
||||
|
@ -738,10 +736,9 @@ namespace Mesen.GUI.Debugger
|
|||
|
||||
private void DrawLine(Graphics g, int currentLine, int marginLeft, int positionY, int lineHeight)
|
||||
{
|
||||
string[] lineContent = _contents[currentLine].Split('\x2');
|
||||
string codeString = lineContent[0].TrimStart();
|
||||
string addressString = lineContent.Length > 1 ? lineContent[1] : "";
|
||||
string commentString = lineContent.Length > 2 ? lineContent[2] : "";
|
||||
string codeString = _contents[currentLine];
|
||||
string addressString = this.Addressing?[currentLine];
|
||||
string commentString = this.Comments?[currentLine];
|
||||
|
||||
float codeStringLength = g.MeasureString(codeString, this.Font).Width;
|
||||
float addressStringLength = g.MeasureString(addressString, this.Font).Width;
|
||||
|
@ -758,12 +755,12 @@ namespace Mesen.GUI.Debugger
|
|||
}
|
||||
|
||||
//Adjust background color highlights based on number of spaces in front of content
|
||||
marginLeft += _lineMargins[currentLine];
|
||||
marginLeft += (LineIndentations != null ? LineIndentations[currentLine] : 0);
|
||||
|
||||
Color textColor = Color.Black;
|
||||
if(_lineProperties.ContainsKey(currentLine)) {
|
||||
LineProperties lineProperties = GetLineStyle(currentLine);
|
||||
if(lineProperties != null) {
|
||||
//Process background, foreground, outline color and line symbol
|
||||
LineProperties lineProperties = _lineProperties[currentLine];
|
||||
textColor = lineProperties.FgColor ?? Color.Black;
|
||||
|
||||
if(lineProperties.BgColor.HasValue) {
|
||||
|
@ -963,10 +960,11 @@ namespace Mesen.GUI.Debugger
|
|||
}
|
||||
|
||||
//Adjust background color highlights based on number of spaces in front of content
|
||||
marginLeft += _lineMargins[currentLine];
|
||||
marginLeft += (LineIndentations != null ? LineIndentations[currentLine] : 0);
|
||||
|
||||
if(_lineProperties.ContainsKey(currentLine)) {
|
||||
this.DrawLineSymbols(g, positionY, _lineProperties[currentLine], lineHeight);
|
||||
LineProperties lineProperties = GetLineStyle(currentLine);
|
||||
if(lineProperties != null) {
|
||||
this.DrawLineSymbols(g, positionY, lineProperties, lineHeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace Mesen.GUI.Debugger
|
|||
(sameLabel == null || sameLabel == _originalLabel)
|
||||
&& (sameAddress == null || sameAddress == _originalLabel)
|
||||
&& (_originalLabel != null || txtLabel.Text.Length > 0 || txtComment.Text.Length > 0)
|
||||
&& !txtComment.Text.Contains('\x1') && !txtComment.Text.Contains('\x2')
|
||||
&& !txtComment.Text.Contains('\x1')
|
||||
&& (txtLabel.Text.Length == 0 || Regex.IsMatch(txtLabel.Text, "^[@_a-zA-Z]+[@_a-zA-Z0-9]*$"));
|
||||
}
|
||||
|
||||
|
|
|
@ -544,6 +544,8 @@ namespace Mesen.GUI.Forms
|
|||
InteropEmu.SetFlag(EmulationFlags.InBackground, !hasFocus);
|
||||
}
|
||||
|
||||
Image _pauseButton = Mesen.GUI.Properties.Resources.Pause;
|
||||
Image _playButton = Mesen.GUI.Properties.Resources.Play;
|
||||
private void UpdateMenus()
|
||||
{
|
||||
try {
|
||||
|
@ -570,7 +572,7 @@ namespace Mesen.GUI.Forms
|
|||
mnuPause.Enabled &= !InteropEmu.DebugIsDebuggerRunning();
|
||||
|
||||
mnuPause.Text = InteropEmu.IsPaused() ? ResourceHelper.GetMessage("Resume") : ResourceHelper.GetMessage("Pause");
|
||||
mnuPause.Image = InteropEmu.IsPaused() ? Mesen.GUI.Properties.Resources.Play : Mesen.GUI.Properties.Resources.Pause;
|
||||
mnuPause.Image = InteropEmu.IsPaused() ? _playButton : _pauseButton;
|
||||
|
||||
bool netPlay = InteropEmu.IsServerRunning() || isNetPlayClient;
|
||||
|
||||
|
|
|
@ -211,8 +211,12 @@ namespace Mesen.GUI
|
|||
|
||||
[DllImport(DLLPath)] public static extern void DebugSaveRomToDisk([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filename);
|
||||
|
||||
[DllImport(DLLPath, EntryPoint = "DebugGetCode")] private static extern IntPtr DebugGetCodeWrapper();
|
||||
public static string DebugGetCode() { return PtrToStringUtf8(InteropEmu.DebugGetCodeWrapper()); }
|
||||
[DllImport(DLLPath, EntryPoint = "DebugGetCode")] private static extern IntPtr DebugGetCodeWrapper(out UInt32 length);
|
||||
public static string DebugGetCode()
|
||||
{
|
||||
UInt32 length;
|
||||
return PtrToStringUtf8(InteropEmu.DebugGetCodeWrapper(out length), length);
|
||||
}
|
||||
|
||||
[DllImport(DLLPath, EntryPoint="DebugAssembleCode")] private static extern UInt32 DebugAssembleCodeWrapper([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string code, UInt16 startAddress, IntPtr assembledCodeBuffer);
|
||||
public static Int16[] DebugAssembleCode(string code, UInt16 startAddress)
|
||||
|
@ -436,16 +440,16 @@ namespace Mesen.GUI
|
|||
hRelative.Free();
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport(DLLPath, EntryPoint = "DebugGetFunctionEntryPoints")]
|
||||
private static extern void DebugGetFunctionEntryPointsWrapper(IntPtr callstackAbsolute);
|
||||
[DllImport(DLLPath)] private static extern Int32 DebugGetFunctionEntryPointCount();
|
||||
[DllImport(DLLPath, EntryPoint = "DebugGetFunctionEntryPoints")] private static extern void DebugGetFunctionEntryPointsWrapper(IntPtr callstackAbsolute, Int32 maxCount);
|
||||
public static Int32[] DebugGetFunctionEntryPoints()
|
||||
{
|
||||
Int32[] entryPoints = new Int32[32768];
|
||||
int maxCount = DebugGetFunctionEntryPointCount();
|
||||
Int32[] entryPoints = new Int32[maxCount+1];
|
||||
|
||||
GCHandle hEntryPoints = GCHandle.Alloc(entryPoints, GCHandleType.Pinned);
|
||||
try {
|
||||
InteropEmu.DebugGetFunctionEntryPointsWrapper(hEntryPoints.AddrOfPinnedObject());
|
||||
InteropEmu.DebugGetFunctionEntryPointsWrapper(hEntryPoints.AddrOfPinnedObject(), maxCount+1);
|
||||
} finally {
|
||||
hEntryPoints.Free();
|
||||
}
|
||||
|
@ -521,24 +525,38 @@ namespace Mesen.GUI
|
|||
return new List<string>(PtrToStringUtf8(InteropEmu.GetAudioDevicesWrapper()).Split(new string[1] { "||" }, StringSplitOptions.RemoveEmptyEntries ));
|
||||
}
|
||||
|
||||
private static string PtrToStringUtf8(IntPtr ptr)
|
||||
private static byte[] _codeByteArray = new byte[0];
|
||||
private static string PtrToStringUtf8(IntPtr ptr, UInt32 length = 0)
|
||||
{
|
||||
if(ptr == IntPtr.Zero) {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
int len = 0;
|
||||
while(System.Runtime.InteropServices.Marshal.ReadByte(ptr, len) != 0) {
|
||||
len++;
|
||||
if(length == 0) {
|
||||
while(System.Runtime.InteropServices.Marshal.ReadByte(ptr, len) != 0) {
|
||||
len++;
|
||||
}
|
||||
} else {
|
||||
len = (int)length;
|
||||
}
|
||||
|
||||
if(len == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
byte[] array = new byte[len];
|
||||
System.Runtime.InteropServices.Marshal.Copy(ptr, array, 0, len);
|
||||
return System.Text.Encoding.UTF8.GetString(array);
|
||||
if(length == 0) {
|
||||
byte[] array = new byte[len];
|
||||
System.Runtime.InteropServices.Marshal.Copy(ptr, array, 0, len);
|
||||
return System.Text.Encoding.UTF8.GetString(array);
|
||||
} else {
|
||||
//For the code window, reuse the same buffer to reduce allocations
|
||||
if(_codeByteArray.Length < len) {
|
||||
Array.Resize(ref _codeByteArray, len);
|
||||
}
|
||||
System.Runtime.InteropServices.Marshal.Copy(ptr, _codeByteArray, 0, len);
|
||||
return System.Text.Encoding.UTF8.GetString(_codeByteArray, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ConsoleNotificationType
|
||||
|
|
|
@ -46,7 +46,7 @@ extern "C"
|
|||
DllExport void __stdcall DebugStepOver() { GetDebugger()->StepOver(); }
|
||||
DllExport void __stdcall DebugStepOut() { GetDebugger()->StepOut(); }
|
||||
DllExport void __stdcall DebugPpuStep(uint32_t count) { GetDebugger()->PpuStep(count); }
|
||||
DllExport const char* __stdcall DebugGetCode() { return GetDebugger()->GetCode(); }
|
||||
DllExport const char* __stdcall DebugGetCode(uint32_t &length) { return GetDebugger()->GetCode(length); }
|
||||
|
||||
DllExport void __stdcall DebugSetPpuViewerScanlineCycle(int32_t scanline, int32_t cycle) { return GetDebugger()->SetPpuViewerScanlineCycle(scanline, cycle); }
|
||||
|
||||
|
@ -60,7 +60,8 @@ extern "C"
|
|||
DllExport void __stdcall DebugGetPalette(uint32_t *frameBuffer) { GetDebugger()->GetMemoryDumper()->GetPalette(frameBuffer); }
|
||||
|
||||
DllExport void __stdcall DebugGetCallstack(int32_t *callstackAbsolute, int32_t *callstackRelative) { GetDebugger()->GetCallstack(callstackAbsolute, callstackRelative); }
|
||||
DllExport void __stdcall DebugGetFunctionEntryPoints(int32_t *entryPoints) { GetDebugger()->GetFunctionEntryPoints(entryPoints); }
|
||||
DllExport int32_t __stdcall DebugGetFunctionEntryPointCount() { return GetDebugger()->GetFunctionEntryPointCount(); }
|
||||
DllExport void __stdcall DebugGetFunctionEntryPoints(int32_t *entryPoints, int32_t maxCount) { GetDebugger()->GetFunctionEntryPoints(entryPoints, maxCount); }
|
||||
|
||||
DllExport int32_t __stdcall DebugGetRelativeAddress(uint32_t addr, AddressType type) { return GetDebugger()->GetRelativeAddress(addr, type); }
|
||||
DllExport int32_t __stdcall DebugGetAbsoluteAddress(uint32_t addr) { return GetDebugger()->GetAbsoluteAddress(addr); }
|
||||
|
|
Loading…
Add table
Reference in a new issue