Debugger: Ability to add labels/symbols & comments to code (work in progress)
This commit is contained in:
parent
1215b3e813
commit
4ffebdb4e0
28 changed files with 1231 additions and 270 deletions
|
@ -55,11 +55,12 @@ struct State
|
|||
|
||||
class CPU : public Snapshotable
|
||||
{
|
||||
private:
|
||||
public:
|
||||
static const uint16_t NMIVector = 0xFFFA;
|
||||
static const uint16_t ResetVector = 0xFFFC;
|
||||
static const uint16_t IRQVector = 0xFFFE;
|
||||
|
||||
private:
|
||||
static CPU* Instance;
|
||||
|
||||
typedef void(CPU::*Func)();
|
||||
|
|
|
@ -97,7 +97,7 @@ bool Debugger::LoadCdlFile(string cdlFilepath)
|
|||
if(_codeDataLogger->LoadCdlFile(cdlFilepath)) {
|
||||
for(int i = 0, len = _mapper->GetPrgSize(); i < len; i++) {
|
||||
if(_codeDataLogger->IsCode(i)) {
|
||||
i = _disassembler->BuildCache(i, -1, 0xFFFF, false) - 1;
|
||||
i = _disassembler->BuildCache(i, -1, 0xFFFF, _codeDataLogger->IsSubEntryPoint(i)) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,6 +127,19 @@ CdlRatios Debugger::GetCdlRatios()
|
|||
return _codeDataLogger->GetRatios();
|
||||
}
|
||||
|
||||
void Debugger::SetLabel(uint32_t address, string label, string comment)
|
||||
{
|
||||
_codeLabels.erase(address);
|
||||
if(!label.empty()) {
|
||||
_codeLabels.emplace(address, label);
|
||||
}
|
||||
|
||||
_codeComments.erase(address);
|
||||
if(!comment.empty()) {
|
||||
_codeComments.emplace(address, comment);
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::SetBreakpoints(Breakpoint breakpoints[], uint32_t length)
|
||||
{
|
||||
_bpUpdateLock.AcquireSafe();
|
||||
|
@ -449,10 +462,11 @@ string Debugger::GenerateOutput()
|
|||
State cpuState = _cpu->GetState();
|
||||
std::ostringstream output;
|
||||
bool showEffectiveAddresses = CheckFlag(DebuggerFlags::ShowEffectiveAddresses);
|
||||
bool showOnlyDiassembledCode = CheckFlag(DebuggerFlags::ShowOnlyDisassembledCode);
|
||||
|
||||
//Get code in internal RAM
|
||||
output << _disassembler->GetCode(0x0000, 0x1FFF, 0x0000, PrgMemoryType::PrgRom, showEffectiveAddresses, cpuState, _memoryManager);
|
||||
output << "2000:::--END OF INTERNAL RAM--\n";
|
||||
output << _disassembler->GetCode(0x0000, 0x1FFF, 0x0000, PrgMemoryType::PrgRom, showEffectiveAddresses, showOnlyDiassembledCode, cpuState, _memoryManager, _codeLabels, _codeComments);
|
||||
output << "2000\x1\x1\x1--End of internal RAM--\n";
|
||||
|
||||
for(uint32_t i = 0x2000; i < 0x10000; i += 0x100) {
|
||||
//Merge all sequential ranges into 1 chunk
|
||||
|
@ -469,7 +483,7 @@ string Debugger::GenerateOutput()
|
|||
romAddr += 0x100;
|
||||
i+=0x100;
|
||||
}
|
||||
output << _disassembler->GetCode(startAddr, endAddr, startMemoryAddr, PrgMemoryType::PrgRom, showEffectiveAddresses, cpuState, _memoryManager);
|
||||
output << _disassembler->GetCode(startAddr, endAddr, startMemoryAddr, PrgMemoryType::PrgRom, showEffectiveAddresses, showOnlyDiassembledCode, cpuState, _memoryManager, _codeLabels, _codeComments);
|
||||
} else if(ramAddr >= 0) {
|
||||
startAddr = ramAddr;
|
||||
endAddr = startAddr + 0xFF;
|
||||
|
@ -478,7 +492,7 @@ string Debugger::GenerateOutput()
|
|||
ramAddr += 0x100;
|
||||
i += 0x100;
|
||||
}
|
||||
output << _disassembler->GetCode(startAddr, endAddr, startMemoryAddr, PrgMemoryType::WorkRam, showEffectiveAddresses, cpuState, _memoryManager);
|
||||
output << _disassembler->GetCode(startAddr, endAddr, startMemoryAddr, PrgMemoryType::WorkRam, showEffectiveAddresses, showOnlyDiassembledCode, cpuState, _memoryManager, _codeLabels, _codeComments);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
using std::atomic;
|
||||
using std::deque;
|
||||
using std::unordered_set;
|
||||
using std::unordered_map;
|
||||
|
||||
#include "DebugState.h"
|
||||
#include "Breakpoint.h"
|
||||
|
@ -25,6 +27,7 @@ enum class DebuggerFlags
|
|||
{
|
||||
PpuPartialDraw = 1,
|
||||
ShowEffectiveAddresses = 2,
|
||||
ShowOnlyDisassembledCode = 4
|
||||
};
|
||||
|
||||
class Debugger
|
||||
|
@ -54,6 +57,9 @@ private:
|
|||
vector<Breakpoint> _breakpoints[BreakpointTypeCount];
|
||||
bool _hasBreakpoint[BreakpointTypeCount];
|
||||
|
||||
unordered_map<uint32_t, string> _codeLabels;
|
||||
unordered_map<uint32_t, string> _codeComments;
|
||||
|
||||
deque<uint32_t> _callstackAbsolute;
|
||||
deque<uint32_t> _callstackRelative;
|
||||
|
||||
|
@ -99,6 +105,7 @@ public:
|
|||
bool CheckFlag(DebuggerFlags flag);
|
||||
|
||||
void SetBreakpoints(Breakpoint breakpoints[], uint32_t length);
|
||||
void SetLabel(uint32_t address, string label, string comment);
|
||||
|
||||
void GetFunctionEntryPoints(int32_t* entryPoints);
|
||||
void GetCallstack(int32_t* callstackAbsolute, int32_t* callstackRelative);
|
||||
|
|
|
@ -174,9 +174,25 @@ void Disassembler::InvalidateCache(uint16_t memoryAddr, int32_t absoluteRamAddr)
|
|||
}
|
||||
}
|
||||
|
||||
string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memoryAddr, PrgMemoryType memoryType, bool showEffectiveAddresses, State& cpuState, shared_ptr<MemoryManager> memoryManager)
|
||||
vector<string> Disassembler::SplitComment(string input)
|
||||
{
|
||||
vector<string> result;
|
||||
size_t index;
|
||||
while((index = input.find('\n')) != string::npos) {
|
||||
result.push_back(input.substr(0, index));
|
||||
input = input.substr(index + 1, input.size() - index - 1);
|
||||
}
|
||||
result.push_back(input);
|
||||
return result;
|
||||
}
|
||||
|
||||
string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memoryAddr, PrgMemoryType memoryType, bool showEffectiveAddresses, bool showOnlyDiassembledCode, State& cpuState, shared_ptr<MemoryManager> memoryManager, unordered_map<uint32_t, string> &codeLabels, unordered_map<uint32_t, string> &codeComments) {
|
||||
std::ostringstream output;
|
||||
|
||||
uint16_t resetVector = memoryManager->DebugReadWord(CPU::ResetVector);
|
||||
uint16_t nmiVector = memoryManager->DebugReadWord(CPU::NMIVector);
|
||||
uint16_t irqVector = memoryManager->DebugReadWord(CPU::IRQVector);
|
||||
|
||||
vector<shared_ptr<DisassemblyInfo>> *cache;
|
||||
uint8_t *source;
|
||||
uint32_t mask = 0xFFFFFFFF;
|
||||
|
@ -194,32 +210,128 @@ string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memo
|
|||
|
||||
uint32_t addr = startAddr;
|
||||
uint32_t byteCount = 0;
|
||||
bool skippingCode = false;
|
||||
while(addr <= endAddr) {
|
||||
shared_ptr<DisassemblyInfo> info;
|
||||
if(info = (*cache)[addr&mask]) {
|
||||
auto labelSearch = codeLabels.find(addr);
|
||||
auto commentSearch = codeComments.find(addr);
|
||||
string label = labelSearch != codeLabels.end() ? labelSearch->second : "";
|
||||
string labelString = label.empty() ? "" : ("\x1\x1\x1" + labelSearch->second + ":\n");
|
||||
string commentString = commentSearch != codeComments.end() ? commentSearch->second : "";
|
||||
bool multilineComment = commentString.find_first_of('\n') != string::npos;
|
||||
string singleLineComment = "";
|
||||
string multiLineComment = "";
|
||||
if(multilineComment) {
|
||||
for(string &str : SplitComment(commentString)) {
|
||||
multiLineComment += "\x1\x1\x1\x2\x2;" + str + "\n";
|
||||
}
|
||||
} else if(!commentString.empty()) {
|
||||
singleLineComment = "\x2;" + commentString;
|
||||
}
|
||||
|
||||
shared_ptr<DisassemblyInfo> info = (*cache)[addr&mask];
|
||||
if(info) {
|
||||
if(byteCount > 0) {
|
||||
output << "\n";
|
||||
byteCount = 0;
|
||||
}
|
||||
|
||||
if(skippingCode) {
|
||||
output << std::hex << std::uppercase << (memoryAddr - 1) << "\x1" << (addr - 1) << "\x1\x1";
|
||||
if(showOnlyDiassembledCode) {
|
||||
output << "----\n";
|
||||
} else {
|
||||
output << "__unknown block__\n";
|
||||
}
|
||||
skippingCode = false;
|
||||
}
|
||||
string effectiveAddress = showEffectiveAddresses ? info->GetEffectiveAddress(cpuState, memoryManager) : "";
|
||||
output << std::hex << std::uppercase << memoryAddr << ":" << addr << ":" << info->ToString(memoryAddr) << "||" << effectiveAddress << "\n";
|
||||
|
||||
string effectiveAddress = showEffectiveAddresses ? info->GetEffectiveAddressString(cpuState, memoryManager, &codeLabels) : "";
|
||||
|
||||
if(info->IsSubEntryPoint()) {
|
||||
if(label.empty()) {
|
||||
output << "\x1\x1\x1\n\x1\x1\x1--sub start--\n";
|
||||
} else {
|
||||
output << "\x1\x1\x1\n\x1\x1\x1--" + label + "()--\n";
|
||||
}
|
||||
} else if(memoryAddr == resetVector) {
|
||||
output << "\x1\x1\x1\n\x1\x1\x1--reset--\n";
|
||||
} else if(memoryAddr == irqVector) {
|
||||
output << "\x1\x1\x1\n\x1\x1\x1--irq--\n";
|
||||
} else if(memoryAddr == nmiVector) {
|
||||
output << "\x1\x1\x1\n\x1\x1\x1--nmi--\n";
|
||||
}
|
||||
|
||||
output << multiLineComment;
|
||||
output << labelString;
|
||||
output << std::hex << std::uppercase << memoryAddr << "\x1" << addr << "\x1" << info->GetByteCode() << "\x1 " << info->ToString(memoryAddr, memoryManager, &codeLabels) << "\x2" << effectiveAddress;
|
||||
output << singleLineComment;
|
||||
|
||||
output << "\n";
|
||||
|
||||
if(info->IsSubExitPoint()) {
|
||||
output << "\x1\x1\x1__sub end__\n\x1\x1\x1\n";
|
||||
}
|
||||
|
||||
addr += info->GetSize();
|
||||
memoryAddr += info->GetSize();
|
||||
} else {
|
||||
if(byteCount >= 8) {
|
||||
output << "\n";
|
||||
byteCount = 0;
|
||||
if(!skippingCode) {
|
||||
output << std::hex << std::uppercase << memoryAddr << "\x1" << addr << "\x1\x1";
|
||||
if(showOnlyDiassembledCode) {
|
||||
output << "____\n\x1\x1\x1";
|
||||
if(label.empty()) {
|
||||
output << "[[unknown block]]\n";
|
||||
} else {
|
||||
output << "[[" << label << "]]\n";
|
||||
if(!singleLineComment.empty()) {
|
||||
output << "\x1\x1\x1" << singleLineComment << "\n";
|
||||
} else {
|
||||
output << multiLineComment;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
output << "--unknown block--\n";
|
||||
}
|
||||
skippingCode = true;
|
||||
}
|
||||
if(byteCount == 0) {
|
||||
output << std::hex << std::uppercase << memoryAddr << ":" << addr << "::" << ".db";
|
||||
}
|
||||
output << std::hex << " $" << std::setfill('0') << std::setw(2) << (short)source[addr&mask];
|
||||
|
||||
byteCount++;
|
||||
if(!showOnlyDiassembledCode) {
|
||||
if(byteCount >= 8 || !label.empty() || !commentString.empty()) {
|
||||
output << "\n";
|
||||
byteCount = 0;
|
||||
}
|
||||
if(byteCount == 0) {
|
||||
output << multiLineComment;
|
||||
output << labelString;
|
||||
output << std::hex << std::uppercase << memoryAddr << "\x1" << addr << "\x1\x1" << ".db";
|
||||
output << singleLineComment;
|
||||
|
||||
if(!label.empty() || !commentString.empty()) {
|
||||
byteCount = 7;
|
||||
}
|
||||
}
|
||||
output << std::hex << " $" << std::setfill('0') << std::setw(2) << (short)source[addr&mask];
|
||||
|
||||
byteCount++;
|
||||
}
|
||||
addr++;
|
||||
memoryAddr++;
|
||||
}
|
||||
}
|
||||
|
||||
if(skippingCode) {
|
||||
if(byteCount != 0) {
|
||||
output << "\n";
|
||||
}
|
||||
|
||||
output << std::hex << std::uppercase << (memoryAddr - 1) << "\x1" << (addr - 1) << "\x1\x1";
|
||||
if(showOnlyDiassembledCode) {
|
||||
output << "----\n";
|
||||
} else {
|
||||
output << "__unknown block__\n";
|
||||
}
|
||||
}
|
||||
|
||||
output << "\n";
|
||||
|
||||
return output.str();
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "BaseMapper.h"
|
||||
#include <unordered_map>
|
||||
using std::unordered_map;
|
||||
|
||||
struct State;
|
||||
class MemoryManager;
|
||||
|
@ -18,6 +20,7 @@ private:
|
|||
uint32_t _prgSize;
|
||||
|
||||
bool IsUnconditionalJump(uint8_t opCode);
|
||||
vector<string> SplitComment(string input);
|
||||
|
||||
public:
|
||||
Disassembler(uint8_t* internalRam, uint8_t* prgRom, uint32_t prgSize, uint8_t* prgRam, uint32_t prgRamSize);
|
||||
|
@ -26,7 +29,7 @@ public:
|
|||
uint32_t BuildCache(int32_t absoluteAddr, int32_t absoluteRamAddr, uint16_t memoryAddr, bool isSubEntryPoint);
|
||||
void InvalidateCache(uint16_t memoryAddr, int32_t absoluteRamAddr);
|
||||
|
||||
string GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memoryAddr, PrgMemoryType memoryType, bool showEffectiveAddresses, State& cpuState, shared_ptr<MemoryManager> memoryManager);
|
||||
string GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memoryAddr, PrgMemoryType memoryType, bool showEffectiveAddresses, bool showOnlyDiassembledCode, State& cpuState, shared_ptr<MemoryManager> memoryManager, unordered_map<uint32_t, string> &codeLabels, unordered_map<uint32_t, string> &codeComments);
|
||||
|
||||
shared_ptr<DisassemblyInfo> GetDisassemblyInfo(int32_t absoluteAddress, int32_t absoluteRamAddress, uint16_t memoryAddress);
|
||||
};
|
||||
|
|
|
@ -6,108 +6,76 @@ string DisassemblyInfo::OPName[256];
|
|||
AddrMode DisassemblyInfo::OPMode[256];
|
||||
uint32_t DisassemblyInfo::OPSize[256];
|
||||
|
||||
void DisassemblyInfo::Initialize(uint32_t memoryAddr)
|
||||
string DisassemblyInfo::ToString(uint32_t memoryAddr, shared_ptr<MemoryManager> memoryManager, std::unordered_map<uint32_t, string> *codeLabels)
|
||||
{
|
||||
_lastAddr = memoryAddr;
|
||||
|
||||
std::ostringstream output;
|
||||
uint8_t opCode = *_opPointer;
|
||||
_opSize = DisassemblyInfo::OPSize[opCode];
|
||||
_opMode = DisassemblyInfo::OPMode[opCode];
|
||||
|
||||
//Output raw byte code
|
||||
for(uint32_t i = 0; i < 3; i++) {
|
||||
if(i < _opSize) {
|
||||
output << "$" << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << (short)*(_opPointer + i);
|
||||
} else {
|
||||
output << " ";
|
||||
}
|
||||
if(i != 2) {
|
||||
output << " ";
|
||||
}
|
||||
}
|
||||
output << ":";
|
||||
|
||||
output << DisassemblyInfo::OPName[opCode];
|
||||
if(opCode == 0x40 || opCode == 0x60) {
|
||||
//Make end of function/interrupt routines more obvious
|
||||
output << " ---->";
|
||||
}
|
||||
|
||||
if(DisassemblyInfo::OPName[opCode].empty()) {
|
||||
output << "invalid opcode";
|
||||
}
|
||||
|
||||
std::ostringstream nextByte;
|
||||
std::ostringstream nextWord;
|
||||
std::ostringstream addrString;
|
||||
if(_opSize == 2) {
|
||||
nextByte << std::uppercase << std::hex << std::setw(2) << std::setfill('0') << (short)(*(_opPointer + 1));
|
||||
_opAddr = *(_opPointer + 1);
|
||||
} else if(_opSize == 3) {
|
||||
nextWord << std::uppercase << std::hex << std::setw(4) << std::setfill('0') << (*(_opPointer + 1) | (*(_opPointer + 2) << 8));
|
||||
_opAddr = *(_opPointer + 1) | (*(_opPointer + 2) << 8);
|
||||
}
|
||||
|
||||
string operandValue;
|
||||
if(codeLabels) {
|
||||
auto result = codeLabels->find(memoryManager->ToAbsolutePrgAddress(_opAddr));
|
||||
if(result != codeLabels->end()) {
|
||||
operandValue = result->second;
|
||||
}
|
||||
}
|
||||
|
||||
if(operandValue.empty()) {
|
||||
std::stringstream ss;
|
||||
ss << "$" << std::uppercase << std::hex << std::setw(_opSize == 2 ? 2 : 4) << std::setfill('0') << (short)_opAddr;
|
||||
operandValue = ss.str();
|
||||
}
|
||||
|
||||
output << " ";
|
||||
|
||||
switch(_opMode) {
|
||||
case AddrMode::Acc: output << " A"; break;
|
||||
case AddrMode::Imm: output << "#" << operandValue; break;
|
||||
case AddrMode::Ind: output << "(" << operandValue << ")"; break;
|
||||
case AddrMode::IndX: output << "(" << operandValue << ",X)"; break;
|
||||
|
||||
case AddrMode::IndY:
|
||||
case AddrMode::IndYW:
|
||||
output << "(" << operandValue << "),Y";
|
||||
break;
|
||||
|
||||
case AddrMode::Abs:
|
||||
output << " $" << nextWord.str();
|
||||
case AddrMode::Zero:
|
||||
output << operandValue;
|
||||
break;
|
||||
|
||||
case AddrMode::AbsX:
|
||||
case AddrMode::AbsXW:
|
||||
output << " $" << nextWord.str() << ",X";
|
||||
case AddrMode::ZeroX:
|
||||
output << operandValue << ",X";
|
||||
break;
|
||||
|
||||
case AddrMode::AbsY:
|
||||
case AddrMode::AbsYW:
|
||||
output << " $" << nextWord.str() << ",Y";
|
||||
break;
|
||||
|
||||
case AddrMode::Imm:
|
||||
output << " #$" << nextByte.str();
|
||||
break;
|
||||
|
||||
case AddrMode::Ind:
|
||||
output << " ($" << nextWord.str() << ")";
|
||||
break;
|
||||
|
||||
case AddrMode::IndX:
|
||||
output << " ($" << nextByte.str() << ",X)";
|
||||
break;
|
||||
|
||||
case AddrMode::IndY:
|
||||
case AddrMode::IndYW:
|
||||
output << " ($" << nextByte.str() << "),Y";
|
||||
case AddrMode::ZeroY:
|
||||
output << operandValue << ",Y";
|
||||
break;
|
||||
|
||||
case AddrMode::Rel:
|
||||
//TODO (not correct when banks are switched around in memory)
|
||||
output << " $" << std::uppercase << std::hex << std::setw(2) << std::setfill('0') << ((int8_t)*(_opPointer + 1) + memoryAddr + 2);
|
||||
break;
|
||||
|
||||
case AddrMode::Zero:
|
||||
output << " $" << nextByte.str();
|
||||
break;
|
||||
|
||||
case AddrMode::ZeroX:
|
||||
output << " $" << nextByte.str() << ",X";
|
||||
break;
|
||||
|
||||
case AddrMode::ZeroY:
|
||||
output << " $" << nextByte.str() << ",Y";
|
||||
break;
|
||||
|
||||
case AddrMode::Acc:
|
||||
output << " A";
|
||||
break;
|
||||
|
||||
default:
|
||||
output << "$" << std::uppercase << std::hex << std::setw(2) << std::setfill('0') << ((int8_t)*(_opPointer + 1) + memoryAddr + 2);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
if(_isSubEntryPoint) {
|
||||
output << " <----";
|
||||
}
|
||||
|
||||
_disassembly = output.str();
|
||||
return output.str();
|
||||
}
|
||||
|
||||
DisassemblyInfo::DisassemblyInfo(uint8_t* opPointer, bool isSubEntryPoint)
|
||||
|
@ -115,72 +83,99 @@ DisassemblyInfo::DisassemblyInfo(uint8_t* opPointer, bool isSubEntryPoint)
|
|||
_opPointer = opPointer;
|
||||
_isSubEntryPoint = isSubEntryPoint;
|
||||
|
||||
Initialize();
|
||||
uint8_t opCode = *_opPointer;
|
||||
_opSize = DisassemblyInfo::OPSize[opCode];
|
||||
_opMode = DisassemblyInfo::OPMode[opCode];
|
||||
_isSubExitPoint = opCode == 0x40 || opCode == 0x60;
|
||||
|
||||
|
||||
//Raw byte code
|
||||
std::stringstream byteCodeOutput;
|
||||
for(uint32_t i = 0; i < 3; i++) {
|
||||
if(i < _opSize) {
|
||||
byteCodeOutput << "$" << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << (short)*(_opPointer + i);
|
||||
} else {
|
||||
byteCodeOutput << " ";
|
||||
}
|
||||
if(i != 2) {
|
||||
byteCodeOutput << " ";
|
||||
}
|
||||
}
|
||||
_byteCode = byteCodeOutput.str();
|
||||
|
||||
}
|
||||
|
||||
void DisassemblyInfo::SetSubEntryPoint()
|
||||
{
|
||||
if(!_isSubEntryPoint) {
|
||||
_isSubEntryPoint = true;
|
||||
Initialize();
|
||||
_isSubEntryPoint = true;
|
||||
}
|
||||
|
||||
string DisassemblyInfo::GetEffectiveAddressString(State& cpuState, shared_ptr<MemoryManager> memoryManager, std::unordered_map<uint32_t, string> *codeLabels)
|
||||
{
|
||||
int32_t effectiveAddress = GetEffectiveAddress(cpuState, memoryManager);
|
||||
if(effectiveAddress < 0) {
|
||||
return "";
|
||||
} else {
|
||||
bool empty = true;
|
||||
if(codeLabels) {
|
||||
auto result = codeLabels->find(memoryManager->ToAbsolutePrgAddress(effectiveAddress));
|
||||
if(result != codeLabels->end()) {
|
||||
return " @ " + result->second;
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::uppercase << std::setfill('0') << " @ $";
|
||||
if(_opMode == AddrMode::ZeroX || _opMode == AddrMode::ZeroY) {
|
||||
ss << std::setw(2) << std::hex << (uint16_t)effectiveAddress;
|
||||
} else {
|
||||
ss << std::setw(4) << std::hex << (uint16_t)effectiveAddress;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
string DisassemblyInfo::GetEffectiveAddress(State& cpuState, shared_ptr<MemoryManager> memoryManager)
|
||||
int32_t DisassemblyInfo::GetEffectiveAddress(State& cpuState, shared_ptr<MemoryManager> memoryManager)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::uppercase << std::setfill('0');
|
||||
switch(_opMode) {
|
||||
case AddrMode::ZeroX: ss << " @ $" << std::setw(2) << std::hex << (short)(uint8_t)(*(_opPointer + 1) + cpuState.X); break;
|
||||
case AddrMode::ZeroY: ss << " @ $" << std::setw(2) << std::hex << (short)(uint8_t)(*(_opPointer + 1) + cpuState.Y); break;
|
||||
case AddrMode::ZeroX: return (uint8_t)(*(_opPointer + 1) + cpuState.X); break;
|
||||
case AddrMode::ZeroY: return (uint8_t)(*(_opPointer + 1) + cpuState.Y); break;
|
||||
|
||||
case AddrMode::IndX: {
|
||||
uint8_t zeroAddr = *(_opPointer + 1) + cpuState.X;
|
||||
uint16_t addr = memoryManager->DebugRead(zeroAddr) | memoryManager->DebugRead((uint8_t)(zeroAddr + 1)) << 8;
|
||||
ss << " @ $" << std::setw(4) << std::hex << addr;
|
||||
break;
|
||||
return memoryManager->DebugRead(zeroAddr) | memoryManager->DebugRead((uint8_t)(zeroAddr + 1)) << 8;
|
||||
}
|
||||
|
||||
case AddrMode::IndY:
|
||||
case AddrMode::IndYW: {
|
||||
uint8_t zeroAddr = *(_opPointer + 1);
|
||||
uint16_t addr = memoryManager->DebugRead(zeroAddr) | memoryManager->DebugRead((uint8_t)(zeroAddr + 1)) << 8;
|
||||
addr += cpuState.Y;
|
||||
ss << " @ $" << std::setw(4) << std::hex << addr;
|
||||
break;
|
||||
return addr + cpuState.Y;
|
||||
}
|
||||
|
||||
case AddrMode::Ind: {
|
||||
uint8_t zeroAddr = *(_opPointer + 1);
|
||||
uint16_t addr = memoryManager->DebugRead(zeroAddr) | memoryManager->DebugRead((uint8_t)(zeroAddr + 1)) << 8;
|
||||
ss << " @ $" << std::setw(4) << std::hex << addr;
|
||||
break;
|
||||
return memoryManager->DebugRead(zeroAddr) | memoryManager->DebugRead((uint8_t)(zeroAddr + 1)) << 8;
|
||||
}
|
||||
|
||||
case AddrMode::AbsX:
|
||||
case AddrMode::AbsXW: {
|
||||
uint16_t addr = (*(_opPointer + 1) | (*(_opPointer + 2) << 8)) + cpuState.X;
|
||||
ss << " @ $" << std::setw(4) << std::hex << addr;
|
||||
break;
|
||||
return (*(_opPointer + 1) | (*(_opPointer + 2) << 8)) + cpuState.X;
|
||||
}
|
||||
|
||||
case AddrMode::AbsY:
|
||||
case AddrMode::AbsYW: {
|
||||
uint16_t addr = (*(_opPointer + 1) | (*(_opPointer + 2) << 8)) + cpuState.Y;
|
||||
ss << " @ $" << std::setfill('0') << std::setw(4) << std::hex << addr;
|
||||
break;
|
||||
return (*(_opPointer + 1) | (*(_opPointer + 2) << 8)) + cpuState.Y;
|
||||
}
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
return -1;
|
||||
}
|
||||
|
||||
string DisassemblyInfo::ToString(uint32_t memoryAddr)
|
||||
string DisassemblyInfo::GetByteCode()
|
||||
{
|
||||
if(memoryAddr != _lastAddr && _opMode == AddrMode::Rel) {
|
||||
Initialize(memoryAddr);
|
||||
}
|
||||
return _disassembly;
|
||||
return _byteCode;
|
||||
}
|
||||
|
||||
uint32_t DisassemblyInfo::GetSize()
|
||||
|
@ -188,3 +183,12 @@ uint32_t DisassemblyInfo::GetSize()
|
|||
return _opSize;
|
||||
}
|
||||
|
||||
bool DisassemblyInfo::IsSubEntryPoint()
|
||||
{
|
||||
return _isSubEntryPoint;
|
||||
}
|
||||
|
||||
bool DisassemblyInfo::IsSubExitPoint()
|
||||
{
|
||||
return _isSubExitPoint;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include <unordered_map>
|
||||
#include "CPU.h"
|
||||
|
||||
class DisassemblyInfo
|
||||
|
@ -10,22 +11,28 @@ public:
|
|||
static uint32_t OPSize[256];
|
||||
|
||||
private:
|
||||
string _disassembly;
|
||||
string _byteCode;
|
||||
uint8_t *_opPointer = nullptr;
|
||||
bool _isSubEntryPoint = false;
|
||||
bool _isSubExitPoint = false;
|
||||
uint32_t _opSize = 0;
|
||||
AddrMode _opMode;
|
||||
uint32_t _lastAddr = 0;
|
||||
|
||||
private:
|
||||
void Initialize(uint32_t memoryAddr = 0);
|
||||
uint16_t _opAddr;
|
||||
|
||||
public:
|
||||
DisassemblyInfo(uint8_t* opPointer, bool isSubEntryPoint);
|
||||
|
||||
void SetSubEntryPoint();
|
||||
string GetEffectiveAddress(State& cpuState, shared_ptr<MemoryManager> memoryManager);
|
||||
string ToString(uint32_t memoryAddr);
|
||||
|
||||
int32_t GetEffectiveAddress(State& cpuState, shared_ptr<MemoryManager> memoryManager);
|
||||
string GetEffectiveAddressString(State& cpuState, shared_ptr<MemoryManager> memoryManager, std::unordered_map<uint32_t, string> *codeLabels);
|
||||
|
||||
string ToString(uint32_t memoryAddr, shared_ptr<MemoryManager> memoryManager, std::unordered_map<uint32_t, string> *codeLabels = nullptr);
|
||||
string GetByteCode();
|
||||
uint32_t GetSize();
|
||||
|
||||
bool IsSubEntryPoint();
|
||||
bool IsSubExitPoint();
|
||||
};
|
||||
|
||||
|
|
|
@ -101,6 +101,11 @@ uint8_t MemoryManager::DebugRead(uint16_t addr)
|
|||
return value;
|
||||
}
|
||||
|
||||
uint16_t MemoryManager::DebugReadWord(uint16_t addr)
|
||||
{
|
||||
return DebugRead(addr) | (DebugRead(addr + 1) << 8);
|
||||
}
|
||||
|
||||
void MemoryManager::ProcessCpuClock()
|
||||
{
|
||||
_mapper->ProcessCpuClock();
|
||||
|
@ -179,6 +184,11 @@ void MemoryManager::WriteVRAM(uint16_t addr, uint8_t value)
|
|||
_mapper->WriteVRAM(addr, value);
|
||||
}
|
||||
|
||||
uint32_t MemoryManager::ToAbsolutePrgAddress(uint16_t ramAddr)
|
||||
{
|
||||
return _mapper->ToAbsoluteAddress(ramAddr);
|
||||
}
|
||||
|
||||
uint32_t MemoryManager::ToAbsoluteChrAddress(uint16_t vramAddr)
|
||||
{
|
||||
return _mapper->ToAbsoluteChrAddress(vramAddr);
|
||||
|
|
|
@ -39,6 +39,7 @@ class MemoryManager: public Snapshotable
|
|||
void RegisterIODevice(IMemoryHandler *handler);
|
||||
|
||||
uint8_t DebugRead(uint16_t addr);
|
||||
uint16_t DebugReadWord(uint16_t addr);
|
||||
uint8_t DebugReadVRAM(uint16_t addr);
|
||||
void DebugWrite(uint16_t addr, uint8_t value);
|
||||
|
||||
|
@ -53,6 +54,7 @@ class MemoryManager: public Snapshotable
|
|||
uint8_t ReadVRAM(uint16_t addr, MemoryOperationType operationType = MemoryOperationType::PpuRenderingRead);
|
||||
void WriteVRAM(uint16_t addr, uint8_t value);
|
||||
|
||||
uint32_t ToAbsolutePrgAddress(uint16_t ramAddr);
|
||||
uint32_t ToAbsoluteChrAddress(uint16_t vramAddr);
|
||||
|
||||
static uint8_t GetOpenBus(uint8_t mask = 0xFF);
|
||||
|
|
|
@ -42,11 +42,7 @@ void TraceLogger::Log(DebugState &state, shared_ptr<DisassemblyInfo> disassembly
|
|||
State &cpuState = state.CPU;
|
||||
PPUDebugState &ppuState = state.PPU;
|
||||
|
||||
string disassembly = disassemblyInfo->ToString(cpuState.DebugPC);
|
||||
auto separatorPosition = disassembly.begin() + disassembly.find_first_of(':', 0);
|
||||
string byteCode(disassembly.begin(), separatorPosition);
|
||||
byteCode.erase(std::remove(byteCode.begin(), byteCode.end(), '$'), byteCode.end());
|
||||
string assemblyCode(separatorPosition + 1, disassembly.end());
|
||||
string disassembly = disassemblyInfo->ToString(cpuState.DebugPC, _memoryManager);
|
||||
|
||||
//Roughly adjust PPU cycle & scanline to take into account the PPU already ran 3 cycles by the time we get here
|
||||
short ppuCycle = (short)ppuState.Cycle - 3;
|
||||
|
@ -66,7 +62,7 @@ void TraceLogger::Log(DebugState &state, shared_ptr<DisassemblyInfo> disassembly
|
|||
_outputFile << std::uppercase << std::hex << std::setfill('0') << std::setw(4) << std::right << (short)cpuState.DebugPC << " ";
|
||||
|
||||
if(_options.ShowByteCode) {
|
||||
_outputFile << std::setfill(' ') << std::setw(10) << std::left << byteCode;
|
||||
_outputFile << std::setfill(' ') << std::setw(10) << std::left << disassemblyInfo->GetByteCode();
|
||||
}
|
||||
|
||||
int indentLevel = 0;
|
||||
|
@ -75,7 +71,7 @@ void TraceLogger::Log(DebugState &state, shared_ptr<DisassemblyInfo> disassembly
|
|||
_outputFile << std::string(indentLevel, ' ');
|
||||
}
|
||||
|
||||
string codeString = assemblyCode + (_options.ShowEffectiveAddresses ? disassemblyInfo->GetEffectiveAddress(state.CPU, _memoryManager) : "");
|
||||
string codeString = disassembly + (_options.ShowEffectiveAddresses ? disassemblyInfo->GetEffectiveAddressString(state.CPU, _memoryManager, nullptr) : "");
|
||||
_outputFile << std::setfill(' ') << std::setw(32 - indentLevel) << std::left << codeString;
|
||||
|
||||
if(_options.ShowRegisters) {
|
||||
|
|
|
@ -12,7 +12,6 @@ namespace Mesen.GUI.Config
|
|||
{
|
||||
public class DebugViewInfo
|
||||
{
|
||||
public bool ShowOnlyDiassembledCode = true;
|
||||
public bool ShowByteCode = false;
|
||||
public bool ShowPrgAddresses = false;
|
||||
public float FontSize = 13;
|
||||
|
@ -22,6 +21,9 @@ namespace Mesen.GUI.Config
|
|||
{
|
||||
public DebugViewInfo LeftView;
|
||||
public DebugViewInfo RightView;
|
||||
|
||||
public bool ShowOnlyDisassembledCode = true;
|
||||
|
||||
public bool SplitView = false;
|
||||
public bool HexDisplay = true;
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
this.mnuShowNextStatement = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuSetNextStatement = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuShowOnlyDisassembledCode = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuShowLineNotes = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuShowCodeNotes = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
|
@ -54,7 +53,6 @@
|
|||
this.mnuShowNextStatement,
|
||||
this.mnuSetNextStatement,
|
||||
this.toolStripMenuItem1,
|
||||
this.mnuShowOnlyDisassembledCode,
|
||||
this.mnuShowLineNotes,
|
||||
this.mnuShowCodeNotes,
|
||||
this.toolStripMenuItem2,
|
||||
|
@ -87,16 +85,6 @@
|
|||
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
|
||||
this.toolStripMenuItem1.Size = new System.Drawing.Size(255, 6);
|
||||
//
|
||||
// mnuShowOnlyDisassembledCode
|
||||
//
|
||||
this.mnuShowOnlyDisassembledCode.Checked = true;
|
||||
this.mnuShowOnlyDisassembledCode.CheckOnClick = true;
|
||||
this.mnuShowOnlyDisassembledCode.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.mnuShowOnlyDisassembledCode.Name = "mnuShowOnlyDisassembledCode";
|
||||
this.mnuShowOnlyDisassembledCode.Size = new System.Drawing.Size(258, 22);
|
||||
this.mnuShowOnlyDisassembledCode.Text = "Show Only Disassembled Code";
|
||||
this.mnuShowOnlyDisassembledCode.Click += new System.EventHandler(this.mnuShowOnlyDisassembledCode_Click);
|
||||
//
|
||||
// mnuShowLineNotes
|
||||
//
|
||||
this.mnuShowLineNotes.CheckOnClick = true;
|
||||
|
@ -146,6 +134,7 @@
|
|||
this.ctrlCodeViewer.MouseUp += new System.Windows.Forms.MouseEventHandler(this.ctrlCodeViewer_MouseUp);
|
||||
this.ctrlCodeViewer.MouseMove += new System.Windows.Forms.MouseEventHandler(this.ctrlCodeViewer_MouseMove);
|
||||
this.ctrlCodeViewer.MouseDown += new System.Windows.Forms.MouseEventHandler(this.ctrlCodeViewer_MouseDown);
|
||||
this.ctrlCodeViewer.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.ctrlCodeViewer_MouseDoubleClick);
|
||||
this.ctrlCodeViewer.FontSizeChanged += new System.EventHandler(this.ctrlCodeViewer_FontSizeChanged);
|
||||
//
|
||||
// contextMenuMargin
|
||||
|
@ -199,7 +188,6 @@
|
|||
private System.Windows.Forms.ToolStripMenuItem mnuShowNextStatement;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuSetNextStatement;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuShowOnlyDisassembledCode;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuGoToLocation;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuAddToWatch;
|
||||
|
|
|
@ -27,7 +27,6 @@ namespace Mesen.GUI.Debugger
|
|||
public void SetConfig(DebugViewInfo config)
|
||||
{
|
||||
_config = config;
|
||||
this.mnuShowOnlyDisassembledCode.Checked = config.ShowOnlyDiassembledCode;
|
||||
this.mnuShowLineNotes.Checked = config.ShowPrgAddresses;
|
||||
this.mnuShowCodeNotes.Checked = config.ShowByteCode;
|
||||
this.FontSize = config.FontSize;
|
||||
|
@ -38,7 +37,6 @@ namespace Mesen.GUI.Debugger
|
|||
|
||||
private void UpdateConfig()
|
||||
{
|
||||
_config.ShowOnlyDiassembledCode = this.mnuShowOnlyDisassembledCode.Checked;
|
||||
_config.ShowPrgAddresses = this.mnuShowLineNotes.Checked;
|
||||
_config.ShowByteCode = this.mnuShowCodeNotes.Checked;
|
||||
_config.FontSize = this.FontSize;
|
||||
|
@ -102,50 +100,17 @@ namespace Mesen.GUI.Debugger
|
|||
List<string> lineNumberNotes = new List<string>();
|
||||
List<string> codeNotes = new List<string>();
|
||||
List<string> codeLines = new List<string>();
|
||||
bool diassembledCodeOnly = mnuShowOnlyDisassembledCode.Checked;
|
||||
bool skippingCode = false;
|
||||
|
||||
string[] lines = _code.Split('\n');
|
||||
for(int i = 0, len = lines.Length - 1; i < len; i++) {
|
||||
string line = lines[i];
|
||||
string[] lineParts = line.Split(':');
|
||||
if(skippingCode && (i == len - 1 || lineParts[3][0] != '.')) {
|
||||
lineNumbers.Add(-1);
|
||||
lineNumberNotes.Add("");
|
||||
codeLines.Add("[code not disassembled]");
|
||||
codeNotes.Add("");
|
||||
|
||||
int address = (int)ParseHexAddress(lineParts[0]);
|
||||
if(i != len - 1 || lineParts[3][0] != '.') {
|
||||
address--;
|
||||
} else if(i == len - 1 && lineParts[3][0] == '.' && address >= 0xFFF8) {
|
||||
address = 0xFFFF;
|
||||
}
|
||||
lineNumbers.Add(address);
|
||||
lineNumberNotes.Add(lineParts[1]);
|
||||
codeLines.Add("[code not disassembled]");
|
||||
codeNotes.Add("");
|
||||
|
||||
skippingCode = false;
|
||||
if(i == len - 1 && lineParts[3][0] == '.') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string[] lineParts = line.Split('\x1');
|
||||
|
||||
if(lineParts.Length >= 4) {
|
||||
if(diassembledCodeOnly && lineParts[3][0] == '.') {
|
||||
if(!skippingCode) {
|
||||
lineNumbers.Add((int)ParseHexAddress(lineParts[0]));
|
||||
lineNumberNotes.Add(lineParts[1]);
|
||||
codeLines.Add("[code not disassembled]");
|
||||
codeNotes.Add("");
|
||||
skippingCode = true;
|
||||
}
|
||||
} else {
|
||||
lineNumbers.Add((int)ParseHexAddress(lineParts[0]));
|
||||
lineNumberNotes.Add(lineParts[1]);
|
||||
codeLines.Add(lineParts[3]);
|
||||
codeNotes.Add(lineParts[2]);
|
||||
}
|
||||
lineNumbers.Add(ParseHexAddress(lineParts[0]));
|
||||
lineNumberNotes.Add(lineParts[1]);
|
||||
codeNotes.Add(lineParts[2]);
|
||||
codeLines.Add(lineParts[3]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,9 +125,13 @@ namespace Mesen.GUI.Debugger
|
|||
return false;
|
||||
}
|
||||
|
||||
private UInt32 ParseHexAddress(string hexAddress)
|
||||
private int ParseHexAddress(string hexAddress)
|
||||
{
|
||||
return UInt32.Parse(hexAddress, System.Globalization.NumberStyles.AllowHexSpecifier);
|
||||
if(string.IsNullOrWhiteSpace(hexAddress)) {
|
||||
return -1;
|
||||
} else {
|
||||
return (int)UInt32.Parse(hexAddress, System.Globalization.NumberStyles.AllowHexSpecifier);
|
||||
}
|
||||
}
|
||||
|
||||
public void HighlightBreakpoints()
|
||||
|
@ -211,7 +180,19 @@ namespace Mesen.GUI.Debugger
|
|||
string valueText = "$" + memoryValue.ToString("X");
|
||||
toolTip.Show(valueText, ctrlCodeViewer, e.Location.X + 5, e.Location.Y - 20, 3000);
|
||||
} else {
|
||||
toolTip.Hide(ctrlCodeViewer);
|
||||
CodeLabel label = LabelManager.GetLabel(word);
|
||||
|
||||
if(label == null) {
|
||||
toolTip.Hide(ctrlCodeViewer);
|
||||
} else {
|
||||
Byte memoryValue = InteropEmu.DebugGetMemoryValue(label.Address);
|
||||
toolTip.Show(
|
||||
"Label: " + label.Label + Environment.NewLine +
|
||||
"Address: $" + InteropEmu.DebugGetRelativeAddress(label.Address).ToString("X4") + Environment.NewLine +
|
||||
"Value: $" + memoryValue.ToString("X2") + Environment.NewLine +
|
||||
"Comment: " + (label.Comment.Contains(Environment.NewLine) ? (Environment.NewLine + label.Comment) : label.Comment)
|
||||
, ctrlCodeViewer, e.Location.X + 5, e.Location.Y - 60 - label.Comment.Split('\n').Length * 14, 3000);
|
||||
}
|
||||
}
|
||||
_previousLocation = e.Location;
|
||||
}
|
||||
|
@ -255,6 +236,26 @@ namespace Mesen.GUI.Debugger
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ctrlCodeViewer_MouseDoubleClick(object sender, MouseEventArgs e)
|
||||
{
|
||||
int address = ctrlCodeViewer.GetLineNumberAtPosition(e.Y);
|
||||
|
||||
if(address >= 0 && e.Location.X > this.ctrlCodeViewer.CodeMargin / 2 && e.Location.X < this.ctrlCodeViewer.CodeMargin) {
|
||||
UInt32 absoluteAddr = (UInt32)InteropEmu.DebugGetAbsoluteAddress((UInt32)address);
|
||||
CodeLabel existingLabel = LabelManager.GetLabel(absoluteAddr);
|
||||
CodeLabel newLabel = new CodeLabel() { Label = existingLabel?.Label, Comment = existingLabel?.Comment };
|
||||
|
||||
frmEditLabel frm = new frmEditLabel(absoluteAddr, newLabel);
|
||||
if(frm.ShowDialog() == DialogResult.OK) {
|
||||
if(string.IsNullOrWhiteSpace(newLabel.Label) && string.IsNullOrWhiteSpace(newLabel.Comment)) {
|
||||
LabelManager.DeleteLabel(absoluteAddr);
|
||||
} else {
|
||||
LabelManager.SetLabel(absoluteAddr, newLabel.Label, newLabel.Comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Context Menu
|
||||
|
||||
|
|
|
@ -53,7 +53,8 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
lstFunctions.ListViewItemSorter = null;
|
||||
lstFunctions.Items.Clear();
|
||||
for(int i = 0; entryPoints[i] >= 0; i++) {
|
||||
ListViewItem item = lstFunctions.Items.Add("");
|
||||
CodeLabel label = LabelManager.GetLabel((UInt32)entryPoints[i]);
|
||||
ListViewItem item = lstFunctions.Items.Add(label?.Label);
|
||||
|
||||
Int32 relativeAddress = InteropEmu.DebugGetRelativeAddress((UInt32)entryPoints[i]);
|
||||
if(relativeAddress >= 0) {
|
||||
|
|
113
GUI.NET/Debugger/Controls/ctrlLabelList.Designer.cs
generated
Normal file
113
GUI.NET/Debugger/Controls/ctrlLabelList.Designer.cs
generated
Normal file
|
@ -0,0 +1,113 @@
|
|||
namespace Mesen.GUI.Debugger.Controls
|
||||
{
|
||||
partial class ctrlLabelList
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if(disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.lstLabels = new System.Windows.Forms.ListView();
|
||||
this.colFunctionLabel = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.colFunctionAddress = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.colMemoryAddress = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.contextMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.mnuDelete = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.contextMenu.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// lstLabels
|
||||
//
|
||||
this.lstLabels.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.colFunctionLabel,
|
||||
this.colFunctionAddress,
|
||||
this.colMemoryAddress});
|
||||
this.lstLabels.ContextMenuStrip = this.contextMenu;
|
||||
this.lstLabels.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.lstLabels.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lstLabels.FullRowSelect = true;
|
||||
this.lstLabels.GridLines = true;
|
||||
this.lstLabels.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
|
||||
this.lstLabels.Location = new System.Drawing.Point(0, 0);
|
||||
this.lstLabels.MultiSelect = false;
|
||||
this.lstLabels.Name = "lstLabels";
|
||||
this.lstLabels.Size = new System.Drawing.Size(275, 112);
|
||||
this.lstLabels.TabIndex = 2;
|
||||
this.lstLabels.UseCompatibleStateImageBehavior = false;
|
||||
this.lstLabels.View = System.Windows.Forms.View.Details;
|
||||
this.lstLabels.DoubleClick += new System.EventHandler(this.lstLabels_DoubleClick);
|
||||
//
|
||||
// colFunctionLabel
|
||||
//
|
||||
this.colFunctionLabel.Text = "Label";
|
||||
this.colFunctionLabel.Width = 136;
|
||||
//
|
||||
// colFunctionAddress
|
||||
//
|
||||
this.colFunctionAddress.Text = "Address";
|
||||
this.colFunctionAddress.Width = 62;
|
||||
//
|
||||
// colMemoryAddress
|
||||
//
|
||||
this.colMemoryAddress.Text = "ROM Addr.";
|
||||
this.colMemoryAddress.Width = 71;
|
||||
//
|
||||
// contextMenu
|
||||
//
|
||||
this.contextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.mnuDelete});
|
||||
this.contextMenu.Name = "contextMenu";
|
||||
this.contextMenu.Size = new System.Drawing.Size(153, 48);
|
||||
this.contextMenu.Opening += new System.ComponentModel.CancelEventHandler(this.mnuActions_Opening);
|
||||
//
|
||||
// mnuDelete
|
||||
//
|
||||
this.mnuDelete.Name = "mnuDelete";
|
||||
this.mnuDelete.ShortcutKeys = System.Windows.Forms.Keys.Delete;
|
||||
this.mnuDelete.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuDelete.Text = "Delete";
|
||||
this.mnuDelete.Click += new System.EventHandler(this.mnuDelete_Click);
|
||||
//
|
||||
// ctrlLabelList
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.lstLabels);
|
||||
this.Name = "ctrlLabelList";
|
||||
this.Size = new System.Drawing.Size(275, 112);
|
||||
this.contextMenu.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.ListView lstLabels;
|
||||
private System.Windows.Forms.ColumnHeader colFunctionLabel;
|
||||
private System.Windows.Forms.ColumnHeader colFunctionAddress;
|
||||
private System.Windows.Forms.ColumnHeader colMemoryAddress;
|
||||
private System.Windows.Forms.ContextMenuStrip contextMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuDelete;
|
||||
}
|
||||
}
|
73
GUI.NET/Debugger/Controls/ctrlLabelList.cs
Normal file
73
GUI.NET/Debugger/Controls/ctrlLabelList.cs
Normal file
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Collections;
|
||||
|
||||
namespace Mesen.GUI.Debugger.Controls
|
||||
{
|
||||
public partial class ctrlLabelList : UserControl
|
||||
{
|
||||
public event EventHandler OnLabelSelected;
|
||||
public ctrlLabelList()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void UpdateLabelList()
|
||||
{
|
||||
Int32[] entryPoints = InteropEmu.DebugGetFunctionEntryPoints();
|
||||
|
||||
lstLabels.BeginUpdate();
|
||||
lstLabels.Items.Clear();
|
||||
foreach(KeyValuePair<UInt32, CodeLabel> kvp in LabelManager.GetLabels()) {
|
||||
if(kvp.Value.Label.Length > 0) {
|
||||
ListViewItem item = lstLabels.Items.Add(kvp.Value.Label);
|
||||
|
||||
Int32 relativeAddress = InteropEmu.DebugGetRelativeAddress(kvp.Value.Address);
|
||||
if(relativeAddress >= 0) {
|
||||
item.SubItems.Add("$" + relativeAddress.ToString("X4"));
|
||||
} else {
|
||||
item.SubItems.Add("[n/a]");
|
||||
item.ForeColor = Color.Gray;
|
||||
item.Font = new Font(item.Font, FontStyle.Italic);
|
||||
}
|
||||
item.SubItems.Add("$" + kvp.Value.Address.ToString("X4"));
|
||||
item.SubItems[1].Tag = kvp.Value.Address;
|
||||
|
||||
item.Tag = relativeAddress;
|
||||
}
|
||||
}
|
||||
lstLabels.Sort();
|
||||
lstLabels.EndUpdate();
|
||||
}
|
||||
|
||||
private void lstLabels_DoubleClick(object sender, EventArgs e)
|
||||
{
|
||||
if(lstLabels.SelectedItems.Count > 0) {
|
||||
Int32 relativeAddress = (Int32)lstLabels.SelectedItems[0].Tag;
|
||||
|
||||
if(relativeAddress >= 0) {
|
||||
OnLabelSelected?.Invoke(relativeAddress, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void mnuActions_Opening(object sender, CancelEventArgs e)
|
||||
{
|
||||
mnuDelete.Enabled = lstLabels.SelectedItems.Count > 0;
|
||||
}
|
||||
|
||||
private void mnuDelete_Click(object sender, EventArgs e)
|
||||
{
|
||||
foreach(ListViewItem item in lstLabels.SelectedItems) {
|
||||
LabelManager.DeleteLabel((UInt32)item.SubItems[1].Tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
123
GUI.NET/Debugger/Controls/ctrlLabelList.resx
Normal file
123
GUI.NET/Debugger/Controls/ctrlLabelList.resx
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="contextMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
|
@ -30,6 +30,12 @@ namespace Mesen.GUI.Debugger
|
|||
remove { this.ctrlTextbox.MouseDown -= value; }
|
||||
}
|
||||
|
||||
public new event MouseEventHandler MouseDoubleClick
|
||||
{
|
||||
add { this.ctrlTextbox.MouseDoubleClick += value; }
|
||||
remove { this.ctrlTextbox.MouseDoubleClick -= value; }
|
||||
}
|
||||
|
||||
public event EventHandler FontSizeChanged;
|
||||
|
||||
public ctrlScrollableTextbox()
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace Mesen.GUI.Debugger
|
|||
private string[] _contentNotes = new string[0];
|
||||
private string[] _compareContents = null;
|
||||
private int[] _lineNumbers = new int[0];
|
||||
private int[] _lineMargins = new int[0];
|
||||
private string[] _lineNumberNotes = new string[0];
|
||||
private Dictionary<int, int> _lineNumberIndex = new Dictionary<int,int>();
|
||||
private Dictionary<int, LineProperties> _lineProperties = new Dictionary<int,LineProperties>();
|
||||
|
@ -61,7 +62,13 @@ namespace Mesen.GUI.Debugger
|
|||
{
|
||||
set
|
||||
{
|
||||
_contents = value;
|
||||
_contents = new string[value.Length];
|
||||
_lineMargins = new int[value.Length];
|
||||
for(int i = 0, len = value.Length; i < len; i++) {
|
||||
_contents[i] = value[i].TrimStart();
|
||||
_lineMargins[i] = (value[i].Length - _contents[i].Length) * 10;
|
||||
}
|
||||
|
||||
_lineNumbers = new int[_contents.Length];
|
||||
_lineNumberIndex.Clear();
|
||||
for(int i = _contents.Length - 1; i >=0; i--) {
|
||||
|
@ -317,7 +324,10 @@ namespace Mesen.GUI.Debugger
|
|||
}
|
||||
|
||||
if(positionX >= 0 && lineIndex < _contents.Length) {
|
||||
string text = _contents[lineIndex];
|
||||
string text = _contents[lineIndex].Replace("\x2", "");
|
||||
//Adjust background color highlights based on number of spaces in front of content
|
||||
positionX -= _lineMargins[lineIndex];
|
||||
|
||||
int previousWidth = 0;
|
||||
for(int i = 0, len = text.Length; i < len; i++) {
|
||||
int width = (int)g.MeasureString(text.Substring(0, i+1), this.Font).Width;
|
||||
|
@ -337,7 +347,7 @@ namespace Mesen.GUI.Debugger
|
|||
int charIndex;
|
||||
int lineIndex;
|
||||
if(this.GetCharIndex(position, out charIndex, out lineIndex)) {
|
||||
string text = (useCompareText && _compareContents != null) ? _compareContents[lineIndex] : _contents[lineIndex];
|
||||
string text = ((useCompareText && _compareContents != null) ? _compareContents[lineIndex] : _contents[lineIndex]).Replace("\x2", "");
|
||||
List<char> wordDelimiters = new List<char>(new char[] { ' ', ',', '|', ';', '(', ')' });
|
||||
if(wordDelimiters.Contains(text[charIndex])) {
|
||||
return string.Empty;
|
||||
|
@ -444,8 +454,8 @@ namespace Mesen.GUI.Debugger
|
|||
|
||||
private void DrawLine(Graphics g, int currentLine, int marginLeft, int positionY)
|
||||
{
|
||||
string[] lineContent = _contents[currentLine].Split(new string[] { "||" }, StringSplitOptions.None);
|
||||
string codeString = lineContent.Length > 0 ? lineContent[0] : "";
|
||||
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] : "";
|
||||
|
||||
|
@ -454,13 +464,7 @@ namespace Mesen.GUI.Debugger
|
|||
|
||||
if(this.ShowLineNumbers) {
|
||||
//Show line number
|
||||
string lineNumber = _lineNumbers[currentLine] >= 0 ? _lineNumbers[currentLine].ToString(_showLineInHex ? "X4" : "") : "..";
|
||||
float width = g.MeasureString(lineNumber, this.Font).Width;
|
||||
g.DrawString(lineNumber, this.Font, Brushes.Gray, marginLeft - width, positionY);
|
||||
if(this.ShowLineNumberNotes) {
|
||||
width = g.MeasureString(_lineNumberNotes[currentLine], _noteFont).Width;
|
||||
g.DrawString(_lineNumberNotes[currentLine], _noteFont, Brushes.Gray, marginLeft - width, positionY+this.Font.Size+3);
|
||||
}
|
||||
this.DrawLineNumber(g, currentLine, marginLeft, positionY);
|
||||
}
|
||||
|
||||
if(currentLine == this.CursorPosition) {
|
||||
|
@ -468,6 +472,9 @@ namespace Mesen.GUI.Debugger
|
|||
g.FillRectangle(Brushes.AliceBlue, marginLeft, positionY, this.ClientRectangle.Width - marginLeft, this.LineHeight);
|
||||
}
|
||||
|
||||
//Adjust background color highlights based on number of spaces in front of content
|
||||
marginLeft += _lineMargins[currentLine];
|
||||
|
||||
Color textColor = Color.Black;
|
||||
if(_lineProperties.ContainsKey(currentLine)) {
|
||||
//Process background, foreground, outline color and line symbol
|
||||
|
@ -476,59 +483,100 @@ namespace Mesen.GUI.Debugger
|
|||
|
||||
if(lineProperties.BgColor.HasValue) {
|
||||
using(Brush bgBrush = new SolidBrush(lineProperties.BgColor.Value)) {
|
||||
g.FillRectangle(bgBrush, marginLeft + 1, positionY + 1, codeStringLength, this.LineHeight-1);
|
||||
g.FillRectangle(bgBrush, marginLeft, positionY + 1, codeStringLength, this.LineHeight-1);
|
||||
}
|
||||
}
|
||||
if(lineProperties.OutlineColor.HasValue) {
|
||||
using(Pen outlinePen = new Pen(lineProperties.OutlineColor.Value, 1)) {
|
||||
g.DrawRectangle(outlinePen, marginLeft + 1, positionY + 1, codeStringLength, this.LineHeight-1);
|
||||
g.DrawRectangle(outlinePen, marginLeft, positionY + 1, codeStringLength, this.LineHeight-1);
|
||||
}
|
||||
}
|
||||
|
||||
if(lineProperties.Symbol.HasFlag(LineSymbol.Circle)) {
|
||||
using(Brush brush = new SolidBrush(lineProperties.OutlineColor.Value)) {
|
||||
g.FillEllipse(brush, 1, positionY + 2, this.LineHeight - 3, this.LineHeight - 3);
|
||||
}
|
||||
}
|
||||
if(lineProperties.Symbol.HasFlag(LineSymbol.CircleOutline) && lineProperties.OutlineColor.HasValue) {
|
||||
using(Pen pen = new Pen(lineProperties.OutlineColor.Value, 1)) {
|
||||
g.DrawEllipse(pen, 1, positionY + 2, this.LineHeight - 3, this.LineHeight - 3);
|
||||
}
|
||||
}
|
||||
if(lineProperties.Symbol.HasFlag(LineSymbol.Arrow)) {
|
||||
int arrowY = positionY + this.LineHeight / 2 + 1;
|
||||
using(Pen pen = new Pen(Color.Black, this.LineHeight * 0.33f)) {
|
||||
//Outline
|
||||
g.DrawLine(pen, 3, arrowY, 3 + this.LineHeight * 0.25f, arrowY);
|
||||
pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
|
||||
g.DrawLine(pen, 3 + this.LineHeight * 0.25f, arrowY, 3 + this.LineHeight * 0.75f, arrowY);
|
||||
|
||||
//Fill
|
||||
pen.Width-=2f;
|
||||
pen.Color = lineProperties.BgColor.Value;
|
||||
pen.EndCap = System.Drawing.Drawing2D.LineCap.Square;
|
||||
g.DrawLine(pen, 4, arrowY, 3 + this.LineHeight * 0.25f - 1, arrowY);
|
||||
pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
|
||||
g.DrawLine(pen, 3 + this.LineHeight * 0.25f, arrowY, this.LineHeight * 0.75f + 1, arrowY);
|
||||
}
|
||||
}
|
||||
this.DrawLineSymbols(g, positionY, lineProperties);
|
||||
}
|
||||
|
||||
this.DrawLineText(g, currentLine, marginLeft, positionY, codeString, addressString, commentString, codeStringLength, addressStringLength, textColor);
|
||||
}
|
||||
|
||||
private void DrawLineNumber(Graphics g, int currentLine, int marginLeft, int positionY)
|
||||
{
|
||||
string lineNumber = _lineNumbers[currentLine] >= 0 ? _lineNumbers[currentLine].ToString(_showLineInHex ? "X4" : "") : "..";
|
||||
float width = g.MeasureString(lineNumber, this.Font).Width;
|
||||
g.DrawString(lineNumber, this.Font, Brushes.Gray, marginLeft - width, positionY);
|
||||
if(this.ShowLineNumberNotes) {
|
||||
width = g.MeasureString(_lineNumberNotes[currentLine], _noteFont).Width;
|
||||
g.DrawString(_lineNumberNotes[currentLine], _noteFont, Brushes.Gray, marginLeft - width, positionY+this.Font.Size+3);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawLineText(Graphics g, int currentLine, int marginLeft, int positionY, string codeString, string addressString, string commentString, float codeStringLength, float addressStringLength, Color textColor)
|
||||
{
|
||||
using(Brush fgBrush = new SolidBrush(textColor)) {
|
||||
g.DrawString(codeString, this.Font, fgBrush, marginLeft, positionY);
|
||||
if(codeString.StartsWith("--") && codeString.EndsWith("--")) {
|
||||
//Draw block start
|
||||
string text = codeString.Substring(2, codeString.Length - 4);
|
||||
float textLength = g.MeasureString(text, this._noteFont).Width;
|
||||
g.DrawString(text, this._noteFont, fgBrush, (marginLeft + this.Width - textLength) / 2, positionY);
|
||||
g.DrawLine(Pens.Black, marginLeft, positionY+this.LineHeight-2, marginLeft+this.Width, positionY+this.LineHeight-2);
|
||||
} else if(codeString.StartsWith("__") && codeString.EndsWith("__")) {
|
||||
//Draw block end
|
||||
string text = codeString.Substring(2, codeString.Length - 4);
|
||||
float textLength = g.MeasureString(text, this._noteFont).Width;
|
||||
g.DrawString(text, this._noteFont, fgBrush, (marginLeft + this.Width - textLength) / 2, positionY + 4);
|
||||
g.DrawLine(Pens.Black, marginLeft, positionY+2, marginLeft+this.Width, positionY+2);
|
||||
} else if(codeString.StartsWith("[[") && codeString.EndsWith("]]")) {
|
||||
//Draw small centered text
|
||||
string text = codeString.Substring(2, codeString.Length - 4);
|
||||
float textLength = g.MeasureString(text, this._noteFont).Width;
|
||||
g.DrawString(text, new Font(this._noteFont, FontStyle.Italic), fgBrush, (marginLeft + this.Width - textLength) / 2, positionY + 2);
|
||||
} else {
|
||||
//Draw line content
|
||||
g.DrawString(codeString, this.Font, fgBrush, marginLeft, positionY);
|
||||
|
||||
using(Brush addressBrush = new SolidBrush(Color.SteelBlue)) {
|
||||
g.DrawString(addressString, this.Font, addressBrush, marginLeft + codeStringLength, positionY);
|
||||
}
|
||||
using(Brush commentBrush = new SolidBrush(Color.DarkGreen)) {
|
||||
g.DrawString(commentString, this.Font, commentBrush, Math.Max(marginLeft + 220, marginLeft + codeStringLength + addressStringLength), positionY);
|
||||
}
|
||||
using(Brush addressBrush = new SolidBrush(Color.SteelBlue)) {
|
||||
g.DrawString(addressString, this.Font, addressBrush, marginLeft + codeStringLength - 4, positionY);
|
||||
}
|
||||
using(Brush commentBrush = new SolidBrush(Color.DarkGreen)) {
|
||||
g.DrawString(commentString, this.Font, commentBrush, codeString.Length == 0 && addressString.Length == 0 ? marginLeft : Math.Max(marginLeft + 220, marginLeft + codeStringLength + addressStringLength), positionY);
|
||||
}
|
||||
|
||||
if(this.ShowContentNotes) {
|
||||
g.DrawString(_contentNotes[currentLine], _noteFont, Brushes.Gray, marginLeft, positionY + this.Font.Size+3);
|
||||
if(this.ShowContentNotes) {
|
||||
g.DrawString(_contentNotes[currentLine], _noteFont, Brushes.Gray, marginLeft, positionY + this.Font.Size+3);
|
||||
}
|
||||
this.DrawHighlightedSearchString(g, codeString, marginLeft, positionY);
|
||||
this.DrawHighlightedCompareString(g, codeString, currentLine, marginLeft, positionY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawLineSymbols(Graphics g, int positionY, LineProperties lineProperties)
|
||||
{
|
||||
if(lineProperties.Symbol.HasFlag(LineSymbol.Circle)) {
|
||||
using(Brush brush = new SolidBrush(lineProperties.OutlineColor.Value)) {
|
||||
g.FillEllipse(brush, 1, positionY + 2, this.LineHeight - 3, this.LineHeight - 3);
|
||||
}
|
||||
}
|
||||
if(lineProperties.Symbol.HasFlag(LineSymbol.CircleOutline) && lineProperties.OutlineColor.HasValue) {
|
||||
using(Pen pen = new Pen(lineProperties.OutlineColor.Value, 1)) {
|
||||
g.DrawEllipse(pen, 1, positionY + 2, this.LineHeight - 3, this.LineHeight - 3);
|
||||
}
|
||||
}
|
||||
if(lineProperties.Symbol.HasFlag(LineSymbol.Arrow)) {
|
||||
int arrowY = positionY + this.LineHeight / 2 + 1;
|
||||
using(Pen pen = new Pen(Color.Black, this.LineHeight * 0.33f)) {
|
||||
//Outline
|
||||
g.DrawLine(pen, 3, arrowY, 3 + this.LineHeight * 0.25f, arrowY);
|
||||
pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
|
||||
g.DrawLine(pen, 3 + this.LineHeight * 0.25f, arrowY, 3 + this.LineHeight * 0.75f, arrowY);
|
||||
|
||||
//Fill
|
||||
pen.Width-=2f;
|
||||
pen.Color = lineProperties.BgColor.Value;
|
||||
pen.EndCap = System.Drawing.Drawing2D.LineCap.Square;
|
||||
g.DrawLine(pen, 4, arrowY, 3 + this.LineHeight * 0.25f - 1, arrowY);
|
||||
pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
|
||||
g.DrawLine(pen, 3 + this.LineHeight * 0.25f, arrowY, this.LineHeight * 0.75f + 1, arrowY);
|
||||
}
|
||||
this.DrawHighlightedSearchString(g, codeString, marginLeft, positionY);
|
||||
this.DrawHighlightedCompareString(g, codeString, currentLine, marginLeft, positionY);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
71
GUI.NET/Debugger/LabelManager.cs
Normal file
71
GUI.NET/Debugger/LabelManager.cs
Normal file
|
@ -0,0 +1,71 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Mesen.GUI.Debugger
|
||||
{
|
||||
public class CodeLabel
|
||||
{
|
||||
public UInt32 Address;
|
||||
public string Label;
|
||||
public string Comment;
|
||||
}
|
||||
|
||||
public class LabelManager
|
||||
{
|
||||
private static Dictionary<UInt32, CodeLabel> _labels = new Dictionary<uint, CodeLabel>();
|
||||
private static Dictionary<string, CodeLabel> _reverseLookup = new Dictionary<string, CodeLabel>();
|
||||
|
||||
public static event EventHandler OnLabelUpdated;
|
||||
|
||||
public static CodeLabel GetLabel(UInt32 address)
|
||||
{
|
||||
return _labels.ContainsKey(address) ? _labels[address] : null;
|
||||
}
|
||||
|
||||
public static CodeLabel GetLabel(string label)
|
||||
{
|
||||
return _reverseLookup.ContainsKey(label) ? _reverseLookup[label] : null;
|
||||
}
|
||||
|
||||
public static Dictionary<UInt32, CodeLabel> GetLabels()
|
||||
{
|
||||
return _labels;
|
||||
}
|
||||
|
||||
public static bool SetLabel(UInt32 address, string label, string comment)
|
||||
{
|
||||
if(_reverseLookup.ContainsKey(label) && _reverseLookup[label].Address != address) {
|
||||
//Label already exists
|
||||
return false;
|
||||
}
|
||||
|
||||
if(_labels.ContainsKey(address)) {
|
||||
_reverseLookup.Remove(_labels[address].Label);
|
||||
}
|
||||
|
||||
_labels[address] = new CodeLabel() { Address = address, Label = label, Comment = comment };
|
||||
if(label.Length > 0) {
|
||||
_reverseLookup[label] = _labels[address];
|
||||
}
|
||||
|
||||
InteropEmu.DebugSetLabel(address, label, comment);
|
||||
OnLabelUpdated?.Invoke(null, null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void DeleteLabel(UInt32 address)
|
||||
{
|
||||
if(_labels.ContainsKey(address)) {
|
||||
_reverseLookup.Remove(_labels[address].Label);
|
||||
}
|
||||
if(_labels.Remove(address)) {
|
||||
InteropEmu.DebugSetLabel(address, string.Empty, string.Empty);
|
||||
OnLabelUpdated?.Invoke(null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
51
GUI.NET/Debugger/frmDebugger.Designer.cs
generated
51
GUI.NET/Debugger/frmDebugger.Designer.cs
generated
|
@ -43,6 +43,7 @@
|
|||
this.ctrlDebuggerCodeSplit = new Mesen.GUI.Debugger.ctrlDebuggerCode();
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.grpLabels = new System.Windows.Forms.GroupBox();
|
||||
this.ctrlLabelList = new Mesen.GUI.Debugger.Controls.ctrlLabelList();
|
||||
this.grpFunctions = new System.Windows.Forms.GroupBox();
|
||||
this.ctrlFunctionList = new Mesen.GUI.Debugger.Controls.ctrlFunctionList();
|
||||
this.tableLayoutPanel10 = new System.Windows.Forms.TableLayoutPanel();
|
||||
|
@ -111,6 +112,7 @@
|
|||
this.lblChrAnalysisResult = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.ctrlPpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping();
|
||||
this.ctrlCpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping();
|
||||
this.mnuShowOnlyDisassembledCode = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.contextMenuCode.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
|
||||
this.splitContainer.Panel1.SuspendLayout();
|
||||
|
@ -118,6 +120,7 @@
|
|||
this.splitContainer.SuspendLayout();
|
||||
this.tlpTop.SuspendLayout();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.grpLabels.SuspendLayout();
|
||||
this.grpFunctions.SuspendLayout();
|
||||
this.tableLayoutPanel10.SuspendLayout();
|
||||
this.grpWatch.SuspendLayout();
|
||||
|
@ -250,13 +253,23 @@
|
|||
//
|
||||
// grpLabels
|
||||
//
|
||||
this.grpLabels.Controls.Add(this.ctrlLabelList);
|
||||
this.grpLabels.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.grpLabels.Location = new System.Drawing.Point(3, 196);
|
||||
this.grpLabels.Name = "grpLabels";
|
||||
this.grpLabels.Size = new System.Drawing.Size(304, 188);
|
||||
this.grpLabels.TabIndex = 6;
|
||||
this.grpLabels.TabStop = false;
|
||||
this.grpLabels.Text = "Labels and Comments";
|
||||
this.grpLabels.Text = "Labels";
|
||||
//
|
||||
// ctrlLabelList
|
||||
//
|
||||
this.ctrlLabelList.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlLabelList.Location = new System.Drawing.Point(3, 16);
|
||||
this.ctrlLabelList.Name = "ctrlLabelList";
|
||||
this.ctrlLabelList.Size = new System.Drawing.Size(298, 169);
|
||||
this.ctrlLabelList.TabIndex = 0;
|
||||
this.ctrlLabelList.OnLabelSelected += new System.EventHandler(this.ctrlLabelList_OnLabelSelected);
|
||||
//
|
||||
// grpFunctions
|
||||
//
|
||||
|
@ -393,12 +406,12 @@
|
|||
// toolStripMenuItem3
|
||||
//
|
||||
this.toolStripMenuItem3.Name = "toolStripMenuItem3";
|
||||
this.toolStripMenuItem3.Size = new System.Drawing.Size(100, 6);
|
||||
this.toolStripMenuItem3.Size = new System.Drawing.Size(149, 6);
|
||||
//
|
||||
// mnuClose
|
||||
//
|
||||
this.mnuClose.Name = "mnuClose";
|
||||
this.mnuClose.Size = new System.Drawing.Size(103, 22);
|
||||
this.mnuClose.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuClose.Text = "Close";
|
||||
this.mnuClose.Click += new System.EventHandler(this.mnuClose_Click);
|
||||
//
|
||||
|
@ -598,7 +611,8 @@
|
|||
this.mnuShowPpuMemoryMapping,
|
||||
this.toolStripMenuItem6,
|
||||
this.mnuPpuPartialDraw,
|
||||
this.mnuShowEffectiveAddresses});
|
||||
this.mnuShowEffectiveAddresses,
|
||||
this.mnuShowOnlyDisassembledCode});
|
||||
this.mnuOptions.Name = "mnuOptions";
|
||||
this.mnuOptions.Size = new System.Drawing.Size(61, 20);
|
||||
this.mnuOptions.Text = "Options";
|
||||
|
@ -607,7 +621,7 @@
|
|||
//
|
||||
this.mnuSplitView.CheckOnClick = true;
|
||||
this.mnuSplitView.Name = "mnuSplitView";
|
||||
this.mnuSplitView.Size = new System.Drawing.Size(228, 22);
|
||||
this.mnuSplitView.Size = new System.Drawing.Size(237, 22);
|
||||
this.mnuSplitView.Text = "Split View";
|
||||
this.mnuSplitView.Click += new System.EventHandler(this.mnuSplitView_Click);
|
||||
//
|
||||
|
@ -618,7 +632,7 @@
|
|||
this.mnuDecreaseFontSize,
|
||||
this.mnuResetFontSize});
|
||||
this.fontSizeToolStripMenuItem.Name = "fontSizeToolStripMenuItem";
|
||||
this.fontSizeToolStripMenuItem.Size = new System.Drawing.Size(228, 22);
|
||||
this.fontSizeToolStripMenuItem.Size = new System.Drawing.Size(237, 22);
|
||||
this.fontSizeToolStripMenuItem.Text = "Text Size";
|
||||
//
|
||||
// mnuIncreaseFontSize
|
||||
|
@ -651,13 +665,13 @@
|
|||
// toolStripMenuItem5
|
||||
//
|
||||
this.toolStripMenuItem5.Name = "toolStripMenuItem5";
|
||||
this.toolStripMenuItem5.Size = new System.Drawing.Size(225, 6);
|
||||
this.toolStripMenuItem5.Size = new System.Drawing.Size(234, 6);
|
||||
//
|
||||
// mnuShowCpuMemoryMapping
|
||||
//
|
||||
this.mnuShowCpuMemoryMapping.CheckOnClick = true;
|
||||
this.mnuShowCpuMemoryMapping.Name = "mnuShowCpuMemoryMapping";
|
||||
this.mnuShowCpuMemoryMapping.Size = new System.Drawing.Size(228, 22);
|
||||
this.mnuShowCpuMemoryMapping.Size = new System.Drawing.Size(237, 22);
|
||||
this.mnuShowCpuMemoryMapping.Text = "Show CPU Memory Mapping";
|
||||
this.mnuShowCpuMemoryMapping.CheckedChanged += new System.EventHandler(this.mnuShowCpuMemoryMapping_CheckedChanged);
|
||||
//
|
||||
|
@ -665,20 +679,20 @@
|
|||
//
|
||||
this.mnuShowPpuMemoryMapping.CheckOnClick = true;
|
||||
this.mnuShowPpuMemoryMapping.Name = "mnuShowPpuMemoryMapping";
|
||||
this.mnuShowPpuMemoryMapping.Size = new System.Drawing.Size(228, 22);
|
||||
this.mnuShowPpuMemoryMapping.Size = new System.Drawing.Size(237, 22);
|
||||
this.mnuShowPpuMemoryMapping.Text = "Show PPU Memory Mapping";
|
||||
this.mnuShowPpuMemoryMapping.CheckedChanged += new System.EventHandler(this.mnuShowPpuMemoryMapping_CheckedChanged);
|
||||
//
|
||||
// toolStripMenuItem6
|
||||
//
|
||||
this.toolStripMenuItem6.Name = "toolStripMenuItem6";
|
||||
this.toolStripMenuItem6.Size = new System.Drawing.Size(225, 6);
|
||||
this.toolStripMenuItem6.Size = new System.Drawing.Size(234, 6);
|
||||
//
|
||||
// mnuPpuPartialDraw
|
||||
//
|
||||
this.mnuPpuPartialDraw.CheckOnClick = true;
|
||||
this.mnuPpuPartialDraw.Name = "mnuPpuPartialDraw";
|
||||
this.mnuPpuPartialDraw.Size = new System.Drawing.Size(228, 22);
|
||||
this.mnuPpuPartialDraw.Size = new System.Drawing.Size(237, 22);
|
||||
this.mnuPpuPartialDraw.Text = "Draw Partial Frame";
|
||||
this.mnuPpuPartialDraw.Click += new System.EventHandler(this.mnuPpuPartialDraw_Click);
|
||||
//
|
||||
|
@ -686,9 +700,9 @@
|
|||
//
|
||||
this.mnuShowEffectiveAddresses.CheckOnClick = true;
|
||||
this.mnuShowEffectiveAddresses.Name = "mnuShowEffectiveAddresses";
|
||||
this.mnuShowEffectiveAddresses.Size = new System.Drawing.Size(228, 22);
|
||||
this.mnuShowEffectiveAddresses.Size = new System.Drawing.Size(237, 22);
|
||||
this.mnuShowEffectiveAddresses.Text = "Show Effective Addresses";
|
||||
this.mnuShowEffectiveAddresses.Click += new System.EventHandler(this.mnuShowEffectiveAddresses_Click);
|
||||
this.mnuShowEffectiveAddresses.CheckedChanged += new System.EventHandler(this.mnuShowEffectiveAddresses_CheckedChanged);
|
||||
//
|
||||
// toolsToolStripMenuItem
|
||||
//
|
||||
|
@ -852,6 +866,14 @@
|
|||
this.ctrlCpuMemoryMapping.Text = "ctrlMemoryMapping1";
|
||||
this.ctrlCpuMemoryMapping.Visible = false;
|
||||
//
|
||||
// mnuShowOnlyDisassembledCode
|
||||
//
|
||||
this.mnuShowOnlyDisassembledCode.CheckOnClick = true;
|
||||
this.mnuShowOnlyDisassembledCode.Name = "mnuShowOnlyDisassembledCode";
|
||||
this.mnuShowOnlyDisassembledCode.Size = new System.Drawing.Size(237, 22);
|
||||
this.mnuShowOnlyDisassembledCode.Text = "Show Only Disassembled Code";
|
||||
this.mnuShowOnlyDisassembledCode.CheckedChanged += new System.EventHandler(this.mnuShowOnlyDisassembledCode_CheckedChanged);
|
||||
//
|
||||
// frmDebugger
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
|
@ -875,6 +897,7 @@
|
|||
this.splitContainer.ResumeLayout(false);
|
||||
this.tlpTop.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.grpLabels.ResumeLayout(false);
|
||||
this.grpFunctions.ResumeLayout(false);
|
||||
this.tableLayoutPanel10.ResumeLayout(false);
|
||||
this.grpWatch.ResumeLayout(false);
|
||||
|
@ -971,5 +994,7 @@
|
|||
private System.Windows.Forms.GroupBox grpLabels;
|
||||
private System.Windows.Forms.GroupBox grpFunctions;
|
||||
private Controls.ctrlFunctionList ctrlFunctionList;
|
||||
private Controls.ctrlLabelList ctrlLabelList;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuShowOnlyDisassembledCode;
|
||||
}
|
||||
}
|
|
@ -35,6 +35,9 @@ namespace Mesen.GUI.Debugger
|
|||
this.mnuShowEffectiveAddresses.Checked = ConfigManager.Config.DebugInfo.ShowEffectiveAddresses;
|
||||
this.mnuShowCpuMemoryMapping.Checked = ConfigManager.Config.DebugInfo.ShowCpuMemoryMapping;
|
||||
this.mnuShowPpuMemoryMapping.Checked = ConfigManager.Config.DebugInfo.ShowPpuMemoryMapping;
|
||||
this.mnuShowOnlyDisassembledCode.Checked = ConfigManager.Config.DebugInfo.ShowOnlyDisassembledCode;
|
||||
|
||||
LabelManager.OnLabelUpdated += LabelManager_OnLabelUpdated;
|
||||
|
||||
_lastCodeWindow = ctrlDebuggerCode;
|
||||
|
||||
|
@ -94,6 +97,9 @@ namespace Mesen.GUI.Debugger
|
|||
if(mnuShowEffectiveAddresses.Checked) {
|
||||
flags |= DebuggerFlags.ShowEffectiveAddresses;
|
||||
}
|
||||
if(mnuShowOnlyDisassembledCode.Checked) {
|
||||
flags |= DebuggerFlags.ShowOnlyDisassembledCode;
|
||||
}
|
||||
InteropEmu.DebugSetFlags(flags);
|
||||
}
|
||||
|
||||
|
@ -129,13 +135,13 @@ namespace Mesen.GUI.Debugger
|
|||
return mnuSplitView.Checked;
|
||||
}
|
||||
|
||||
private void UpdateDebugger()
|
||||
private void UpdateDebugger(bool updateActiveAddress = true)
|
||||
{
|
||||
ctrlFunctionList.UpdateFunctionList();
|
||||
UpdateDebuggerFlags();
|
||||
|
||||
if(InteropEmu.DebugIsCodeChanged()) {
|
||||
string code = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(InteropEmu.DebugGetCode());
|
||||
string code = InteropEmu.DebugGetCode();
|
||||
ctrlDebuggerCode.Code = code;
|
||||
ctrlDebuggerCodeSplit.Code = code;
|
||||
}
|
||||
|
@ -149,8 +155,10 @@ namespace Mesen.GUI.Debugger
|
|||
_lastCodeWindow = ctrlDebuggerCode;
|
||||
}
|
||||
|
||||
ctrlDebuggerCode.SelectActiveAddress(state.CPU.DebugPC);
|
||||
ctrlDebuggerCodeSplit.SetActiveAddress(state.CPU.DebugPC);
|
||||
if(updateActiveAddress) {
|
||||
ctrlDebuggerCode.SelectActiveAddress(state.CPU.DebugPC);
|
||||
ctrlDebuggerCodeSplit.SetActiveAddress(state.CPU.DebugPC);
|
||||
}
|
||||
RefreshBreakpoints();
|
||||
|
||||
ctrlConsoleStatus.UpdateStatus(ref state);
|
||||
|
@ -282,7 +290,7 @@ namespace Mesen.GUI.Debugger
|
|||
ConfigManager.Config.DebugInfo.SplitView = this.mnuSplitView.Checked;
|
||||
ConfigManager.ApplyChanges();
|
||||
|
||||
UpdateDebugger();
|
||||
UpdateDebugger(false);
|
||||
}
|
||||
|
||||
private void mnuMemoryViewer_Click(object sender, EventArgs e)
|
||||
|
@ -423,11 +431,18 @@ namespace Mesen.GUI.Debugger
|
|||
ConfigManager.ApplyChanges();
|
||||
}
|
||||
|
||||
private void mnuShowEffectiveAddresses_Click(object sender, EventArgs e)
|
||||
private void mnuShowEffectiveAddresses_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
ConfigManager.Config.DebugInfo.ShowEffectiveAddresses = mnuShowEffectiveAddresses.Checked;
|
||||
ConfigManager.ApplyChanges();
|
||||
UpdateDebugger();
|
||||
UpdateDebugger(false);
|
||||
}
|
||||
|
||||
private void mnuShowOnlyDisassembledCode_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
ConfigManager.Config.DebugInfo.ShowOnlyDisassembledCode = mnuShowOnlyDisassembledCode.Checked;
|
||||
ConfigManager.ApplyChanges();
|
||||
UpdateDebugger(false);
|
||||
}
|
||||
|
||||
private void mnuShowCpuMemoryMapping_CheckedChanged(object sender, EventArgs e)
|
||||
|
@ -458,5 +473,16 @@ namespace Mesen.GUI.Debugger
|
|||
{
|
||||
_lastCodeWindow.ScrollToLineNumber((Int32)relativeAddress);
|
||||
}
|
||||
|
||||
private void LabelManager_OnLabelUpdated(object sender, EventArgs e)
|
||||
{
|
||||
UpdateDebugger(false);
|
||||
ctrlLabelList.UpdateLabelList();
|
||||
}
|
||||
|
||||
private void ctrlLabelList_OnLabelSelected(object relativeAddress, EventArgs e)
|
||||
{
|
||||
_lastCodeWindow.ScrollToLineNumber((Int32)relativeAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
125
GUI.NET/Debugger/frmEditLabel.Designer.cs
generated
Normal file
125
GUI.NET/Debugger/frmEditLabel.Designer.cs
generated
Normal file
|
@ -0,0 +1,125 @@
|
|||
namespace Mesen.GUI.Debugger
|
||||
{
|
||||
partial class frmEditLabel
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if(disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.txtComment = new System.Windows.Forms.TextBox();
|
||||
this.lblLabel = new System.Windows.Forms.Label();
|
||||
this.lblComment = new System.Windows.Forms.Label();
|
||||
this.txtLabel = new System.Windows.Forms.TextBox();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// baseConfigPanel
|
||||
//
|
||||
this.baseConfigPanel.Location = new System.Drawing.Point(0, 165);
|
||||
this.baseConfigPanel.Size = new System.Drawing.Size(352, 29);
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 2;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel1.Controls.Add(this.txtComment, 1, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.lblLabel, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.lblComment, 0, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.txtLabel, 1, 0);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 2;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(352, 165);
|
||||
this.tableLayoutPanel1.TabIndex = 2;
|
||||
//
|
||||
// txtComment
|
||||
//
|
||||
this.txtComment.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.txtComment.Location = new System.Drawing.Point(63, 29);
|
||||
this.txtComment.Multiline = true;
|
||||
this.txtComment.Name = "txtComment";
|
||||
this.txtComment.Size = new System.Drawing.Size(286, 133);
|
||||
this.txtComment.TabIndex = 3;
|
||||
//
|
||||
// lblLabel
|
||||
//
|
||||
this.lblLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblLabel.AutoSize = true;
|
||||
this.lblLabel.Location = new System.Drawing.Point(3, 6);
|
||||
this.lblLabel.Name = "lblLabel";
|
||||
this.lblLabel.Size = new System.Drawing.Size(36, 13);
|
||||
this.lblLabel.TabIndex = 0;
|
||||
this.lblLabel.Text = "Label:";
|
||||
//
|
||||
// lblComment
|
||||
//
|
||||
this.lblComment.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblComment.AutoSize = true;
|
||||
this.lblComment.Location = new System.Drawing.Point(3, 89);
|
||||
this.lblComment.Name = "lblComment";
|
||||
this.lblComment.Size = new System.Drawing.Size(54, 13);
|
||||
this.lblComment.TabIndex = 1;
|
||||
this.lblComment.Text = "Comment:";
|
||||
//
|
||||
// txtLabel
|
||||
//
|
||||
this.txtLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.txtLabel.Location = new System.Drawing.Point(63, 3);
|
||||
this.txtLabel.Name = "txtLabel";
|
||||
this.txtLabel.Size = new System.Drawing.Size(286, 20);
|
||||
this.txtLabel.TabIndex = 2;
|
||||
//
|
||||
// frmEditLabel
|
||||
//
|
||||
this.AcceptButton = null;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(352, 194);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
||||
this.Name = "frmEditLabel";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Edit Label";
|
||||
this.Controls.SetChildIndex(this.baseConfigPanel, 0);
|
||||
this.Controls.SetChildIndex(this.tableLayoutPanel1, 0);
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.TextBox txtComment;
|
||||
private System.Windows.Forms.Label lblLabel;
|
||||
private System.Windows.Forms.Label lblComment;
|
||||
private System.Windows.Forms.TextBox txtLabel;
|
||||
}
|
||||
}
|
54
GUI.NET/Debugger/frmEditLabel.cs
Normal file
54
GUI.NET/Debugger/frmEditLabel.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Mesen.GUI.Forms;
|
||||
|
||||
namespace Mesen.GUI.Debugger
|
||||
{
|
||||
public partial class frmEditLabel : BaseConfigForm
|
||||
{
|
||||
UInt32 _address;
|
||||
|
||||
public frmEditLabel(UInt32 address, CodeLabel label)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_address = address;
|
||||
this.Text = "Edit Label: $" + address.ToString("X4");
|
||||
|
||||
Entity = label;
|
||||
|
||||
AddBinding("Label", txtLabel);
|
||||
AddBinding("Comment", txtComment);
|
||||
}
|
||||
|
||||
protected override bool ValidateInput()
|
||||
{
|
||||
CodeLabel existingLabel = LabelManager.GetLabel(txtLabel.Text);
|
||||
return (existingLabel == null || existingLabel.Address == _address)
|
||||
&& !txtComment.Text.Contains('\x1') && !txtComment.Text.Contains('\x2')
|
||||
&& !txtLabel.Text.Contains('\x1') && !txtLabel.Text.Contains('\x2');
|
||||
}
|
||||
|
||||
protected override void OnFormClosed(FormClosedEventArgs e)
|
||||
{
|
||||
txtLabel.Text = txtLabel.Text.Replace("$", "");
|
||||
base.OnFormClosed(e);
|
||||
}
|
||||
|
||||
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
||||
{
|
||||
if(keyData == (Keys.Control | Keys.Enter)) {
|
||||
this.DialogResult = DialogResult.OK;
|
||||
this.Close();
|
||||
}
|
||||
return base.ProcessCmdKey(ref msg, keyData);
|
||||
}
|
||||
}
|
||||
}
|
123
GUI.NET/Debugger/frmEditLabel.resx
Normal file
123
GUI.NET/Debugger/frmEditLabel.resx
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
|
@ -278,6 +278,12 @@
|
|||
<Compile Include="Debugger\Controls\ctrlAddressList.Designer.cs">
|
||||
<DependentUpon>ctrlAddressList.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\Controls\ctrlLabelList.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\Controls\ctrlLabelList.Designer.cs">
|
||||
<DependentUpon>ctrlLabelList.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\Controls\ctrlFunctionList.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
|
@ -343,6 +349,12 @@
|
|||
<Compile Include="Debugger\Controls\ctrlWatch.Designer.cs">
|
||||
<DependentUpon>ctrlWatch.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\frmEditLabel.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\frmEditLabel.Designer.cs">
|
||||
<DependentUpon>frmEditLabel.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\frmBreakpoint.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
@ -379,6 +391,7 @@
|
|||
<Compile Include="Debugger\frmTraceLogger.Designer.cs">
|
||||
<DependentUpon>frmTraceLogger.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\LabelManager.cs" />
|
||||
<Compile Include="Forms\BaseConfigForm.Designer.cs">
|
||||
<DependentUpon>BaseConfigForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -582,6 +595,9 @@
|
|||
<EmbeddedResource Include="Debugger\Controls\ctrlAddressList.resx">
|
||||
<DependentUpon>ctrlAddressList.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\Controls\ctrlLabelList.resx">
|
||||
<DependentUpon>ctrlLabelList.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\Controls\ctrlFunctionList.resx">
|
||||
<DependentUpon>ctrlFunctionList.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
@ -612,6 +628,9 @@
|
|||
<EmbeddedResource Include="Debugger\Controls\ctrlWatch.resx">
|
||||
<DependentUpon>ctrlWatch.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\frmEditLabel.resx">
|
||||
<DependentUpon>frmEditLabel.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\frmBreakpoint.resx">
|
||||
<DependentUpon>frmBreakpoint.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
|
|
@ -166,6 +166,7 @@ namespace Mesen.GUI
|
|||
[DllImport(DLLPath)] public static extern void DebugSetFlags(DebuggerFlags flags);
|
||||
[DllImport(DLLPath)] public static extern void DebugGetState(ref DebugState state);
|
||||
[DllImport(DLLPath)] public static extern void DebugSetBreakpoints([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]InteropBreakpoint[] breakpoints, UInt32 length);
|
||||
[DllImport(DLLPath)] public static extern void DebugSetLabel(UInt32 address, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string label, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string comment);
|
||||
[DllImport(DLLPath)] public static extern void DebugStep(UInt32 count);
|
||||
[DllImport(DLLPath)] public static extern void DebugPpuStep(UInt32 count);
|
||||
[DllImport(DLLPath)] public static extern void DebugStepCycles(UInt32 count);
|
||||
|
@ -173,9 +174,9 @@ namespace Mesen.GUI
|
|||
[DllImport(DLLPath)] public static extern void DebugStepOver();
|
||||
[DllImport(DLLPath)] public static extern void DebugRun();
|
||||
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool DebugIsCodeChanged();
|
||||
[DllImport(DLLPath)] public static extern IntPtr DebugGetCode();
|
||||
[DllImport(DLLPath)] public static extern Byte DebugGetMemoryValue(UInt32 addr);
|
||||
[DllImport(DLLPath)] public static extern Int32 DebugGetRelativeAddress(UInt32 addr);
|
||||
[DllImport(DLLPath)] public static extern Int32 DebugGetRelativeAddress(UInt32 absoluteAddr);
|
||||
[DllImport(DLLPath)] public static extern Int32 DebugGetAbsoluteAddress(UInt32 relativeAddr);
|
||||
[DllImport(DLLPath)] public static extern void DebugSetNextStatement(UInt16 addr);
|
||||
[DllImport(DLLPath)] public static extern Int32 DebugEvaluateExpression([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string expression, out EvalResultType resultType);
|
||||
|
||||
|
@ -187,6 +188,9 @@ namespace Mesen.GUI
|
|||
[DllImport(DLLPath)] public static extern void DebugGetCdlRatios(ref CdlRatios ratios);
|
||||
[DllImport(DLLPath)] public static extern void DebugResetCdlLog();
|
||||
|
||||
[DllImport(DLLPath, EntryPoint = "DebugGetCode")] private static extern IntPtr DebugGetCodeWrapper();
|
||||
public static string DebugGetCode() { return PtrToStringUtf8(InteropEmu.DebugGetCodeWrapper()); }
|
||||
|
||||
[DllImport(DLLPath, EntryPoint="DebugGetMemoryState")] private static extern UInt32 DebugGetMemoryStateWrapper(DebugMemoryType type, IntPtr buffer);
|
||||
public static byte[] DebugGetMemoryState(DebugMemoryType type)
|
||||
{
|
||||
|
@ -735,7 +739,8 @@ namespace Mesen.GUI
|
|||
{
|
||||
None = 0,
|
||||
PpuPartialDraw = 1,
|
||||
ShowEffectiveAddresses = 2
|
||||
ShowEffectiveAddresses = 2,
|
||||
ShowOnlyDisassembledCode = 4,
|
||||
}
|
||||
|
||||
public struct InteropRomInfo
|
||||
|
|
|
@ -31,6 +31,7 @@ extern "C"
|
|||
DllExport void __stdcall DebugGetState(DebugState *state) { GetDebugger()->GetState(state); }
|
||||
|
||||
DllExport void __stdcall DebugSetBreakpoints(Breakpoint breakpoints[], uint32_t length) { GetDebugger()->SetBreakpoints(breakpoints, length); }
|
||||
DllExport void __stdcall DebugSetLabel(uint32_t address, char* label, char* comment) { GetDebugger()->SetLabel(address, label, comment); }
|
||||
|
||||
DllExport void __stdcall DebugRun() { GetDebugger()->Run(); }
|
||||
DllExport void __stdcall DebugStep(uint32_t count) { GetDebugger()->Step(count); }
|
||||
|
@ -55,6 +56,7 @@ extern "C"
|
|||
|
||||
DllExport uint8_t __stdcall DebugGetMemoryValue(uint32_t addr) { return GetDebugger()->GetMemoryValue(addr); }
|
||||
DllExport int32_t __stdcall DebugGetRelativeAddress(uint32_t addr) { return GetDebugger()->GetRelativeAddress(addr); }
|
||||
DllExport int32_t __stdcall DebugGetAbsoluteAddress(uint32_t addr) { return GetDebugger()->GetAbsoluteAddress(addr); }
|
||||
|
||||
DllExport bool __stdcall DebugLoadCdlFile(char* cdlFilepath) { return GetDebugger()->LoadCdlFile(cdlFilepath); }
|
||||
DllExport bool __stdcall DebugSaveCdlFile(char* cdlFilepath) { return GetDebugger()->SaveCdlFile(cdlFilepath); }
|
||||
|
|
Loading…
Add table
Reference in a new issue