Debugger: Performance improvements, code refactoring & code display changes/fixes

This commit is contained in:
Souryo 2016-11-26 10:42:59 -05:00
parent 9da501bbd5
commit 80bd7d0b3e
9 changed files with 211 additions and 126 deletions

View file

@ -470,13 +470,14 @@ bool Debugger::IsCodeChanged()
string Debugger::GenerateOutput()
{
State cpuState = _cpu->GetState();
std::ostringstream output;
string output;
output.reserve(10000);
bool showEffectiveAddresses = CheckFlag(DebuggerFlags::ShowEffectiveAddresses);
bool showOnlyDiassembledCode = CheckFlag(DebuggerFlags::ShowOnlyDisassembledCode);
//Get code in internal RAM
output << _disassembler->GetCode(0x0000, 0x1FFF, 0x0000, PrgMemoryType::PrgRom, showEffectiveAddresses, showOnlyDiassembledCode, cpuState, _memoryManager, _labelManager);
output << "2000\x1\x1\x1--End of internal RAM--\n";
output = _disassembler->GetCode(0x0000, 0x1FFF, 0x0000, PrgMemoryType::PrgRom, showEffectiveAddresses, showOnlyDiassembledCode, cpuState, _memoryManager, _labelManager);
for(uint32_t i = 0x2000; i < 0x10000; i += 0x100) {
//Merge all sequential ranges into 1 chunk
@ -497,11 +498,11 @@ string Debugger::GenerateOutput()
addr += 0x100;
i+=0x100;
}
output << _disassembler->GetCode(startAddr, endAddr, startMemoryAddr, memoryType, showEffectiveAddresses, showOnlyDiassembledCode, cpuState, _memoryManager, _labelManager);
output += _disassembler->GetCode(startAddr, endAddr, startMemoryAddr, memoryType, showEffectiveAddresses, showOnlyDiassembledCode, cpuState, _memoryManager, _labelManager);
}
}
return output.str();
return output;
}
string* Debugger::GetCode()

View file

@ -5,6 +5,7 @@
#include "MemoryManager.h"
#include "CPU.h"
#include "LabelManager.h"
#include "../Utilities/HexUtilities.h"
Disassembler::Disassembler(uint8_t* internalRam, uint8_t* prgRom, uint32_t prgSize, uint8_t* prgRam, uint32_t prgRamSize)
{
@ -187,9 +188,47 @@ vector<string> Disassembler::SplitComment(string input)
return result;
}
string Disassembler::GetLine(string code, string comment, int32_t cpuAddress, int32_t absoluteAddress, string byteCode, string addressing)
{
string out;
out.reserve(50);
if(cpuAddress >= 0) {
out += HexUtilities::ToHex((uint16_t)cpuAddress);
}
out += "\x1";
if(absoluteAddress >= 0) {
out += HexUtilities::ToHex((uint32_t)absoluteAddress);
}
out += "\x1" + byteCode + "\x1" + code + "\x2" + addressing + "\x2" + (comment.empty() ? "" : (";" + comment)) + "\n";
return out;
}
string Disassembler::GetSubHeader(DisassemblyInfo *info, string &label, uint16_t relativeAddr, uint16_t resetVector, uint16_t nmiVector, uint16_t irqVector)
{
if(info->IsSubEntryPoint()) {
if(label.empty()) {
return GetLine() + GetLine("__sub start__");
} else {
return GetLine() + GetLine("__" + label + "()__");
}
} else if(relativeAddr == resetVector) {
return GetLine() + GetLine("--reset--");
} else if(relativeAddr == irqVector) {
return GetLine() + GetLine("--irq--");
} else if(relativeAddr == nmiVector) {
return GetLine() + GetLine("--nmi--");
}
return "";
}
string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memoryAddr, PrgMemoryType memoryType, bool showEffectiveAddresses, bool showOnlyDiassembledCode, State& cpuState, shared_ptr<MemoryManager> memoryManager, shared_ptr<LabelManager> labelManager)
{
std::ostringstream output;
string output;
output.reserve(10000000);
int32_t dbRelativeAddr;
int32_t dbAbsoluteAddr;
string dbBuffer;
uint16_t resetVector = memoryManager->DebugReadWord(CPU::ResetVector);
uint16_t nmiVector = memoryManager->DebugReadWord(CPU::NMIVector);
@ -210,116 +249,90 @@ string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memo
source = _prgRom;
}
string unknownBlockHeader = showOnlyDiassembledCode ? "----" : "__unknown block__";
uint32_t addr = startAddr;
uint32_t byteCount = 0;
bool skippingCode = false;
while(addr <= endAddr) {
string label = labelManager->GetLabel(memoryAddr, false);
string commentString = labelManager->GetComment(memoryAddr);
string labelString = label.empty() ? "" : ("\x1\x1\x1" + label + ":\n");
bool multilineComment = commentString.find_first_of('\n') != string::npos;
string singleLineComment = "";
string multiLineComment = "";
if(multilineComment) {
string labelLine = label.empty() ? "" : GetLine(label + ":");
string commentLines = "";
if(commentString.find_first_of('\n') != string::npos) {
for(string &str : SplitComment(commentString)) {
multiLineComment += "\x1\x1\x1\x2\x2;" + str + "\n";
commentLines += GetLine("", str);
}
} else if(!commentString.empty()) {
singleLineComment = "\x2;" + commentString;
commentString = "";
}
shared_ptr<DisassemblyInfo> info = (*cache)[addr&mask];
if(info) {
if(byteCount > 0) {
output << "\n";
output += GetLine(dbBuffer, "", dbRelativeAddr, dbAbsoluteAddr);
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";
}
output += GetLine(unknownBlockHeader, "", (uint16_t)(memoryAddr - 1), addr - 1);
skippingCode = false;
}
output += GetSubHeader(info.get(), label, memoryAddr, resetVector, nmiVector, irqVector);
output += commentLines;
output += labelLine;
string effectiveAddress = showEffectiveAddresses ? info->GetEffectiveAddressString(cpuState, memoryManager, labelManager) : "";
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, labelManager) << "\x2" << effectiveAddress;
output << singleLineComment;
output << "\n";
output += GetLine(" " + info->ToString(memoryAddr, memoryManager, labelManager), commentString, memoryAddr, addr, info->GetByteCode(), effectiveAddress);
if(info->IsSubExitPoint()) {
output << "\x1\x1\x1__sub end__\n\x1\x1\x1\n";
output += GetLine("__sub end__") + GetLine();
}
addr += info->GetSize();
memoryAddr += info->GetSize();
} else {
if(!label.empty() && skippingCode) {
output << std::hex << std::uppercase << (memoryAddr - 1) << "\x1" << (addr - 1) << "\x1\x1";
if(showOnlyDiassembledCode) {
output << "----\n";
} else {
output << "__unknown block__\n";
}
if((!label.empty() || !commentString.empty()) && skippingCode) {
output += GetLine(unknownBlockHeader, "", (uint16_t)(memoryAddr - 1), addr - 1);
skippingCode = false;
}
if(!skippingCode) {
output << std::hex << std::uppercase << memoryAddr << "\x1" << addr << "\x1\x1";
if(showOnlyDiassembledCode) {
if(label.empty()) {
output << "__unknown block__\n";
} else {
output << "__" << label << "__\n";
if(!singleLineComment.empty()) {
output << "\x1\x1\x1\x2" << singleLineComment << "\n";
} else {
output << multiLineComment;
}
if(!skippingCode && showOnlyDiassembledCode) {
if(label.empty()) {
output += GetLine("__unknown block__", "", memoryAddr, addr);
if(!commentString.empty()) {
output += GetLine("", commentString);
}
} else {
output << "--unknown block--\n";
output += GetLine("__" + label + "__", "", memoryAddr, addr);
if(!commentString.empty()) {
output += GetLine("", commentString);
}
output += commentLines;
}
skippingCode = true;
}
if(!showOnlyDiassembledCode) {
if(byteCount >= 8 || !label.empty() || !commentString.empty()) {
output << "\n";
output += GetLine(dbBuffer, "", dbRelativeAddr, dbAbsoluteAddr);
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;
}
if(byteCount == 0) {
dbBuffer = ".db";
output += commentLines;
output += labelLine;
dbRelativeAddr = memoryAddr;
dbAbsoluteAddr = addr;
}
dbBuffer += " $" + HexUtilities::ToHex(source[addr&mask]);
if(!label.empty() || !commentString.empty()) {
output += GetLine(dbBuffer, commentString, dbRelativeAddr, dbAbsoluteAddr);
}
output << std::hex << " $" << std::setfill('0') << std::setw(2) << (short)source[addr&mask];
byteCount++;
}
@ -329,21 +342,14 @@ string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memo
}
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";
if(showOnlyDiassembledCode && byteCount > 0) {
output += GetLine(dbBuffer, "", dbRelativeAddr, dbAbsoluteAddr);
}
return output.str();
output += GetLine("----", "", (uint16_t)(memoryAddr - 1), addr - 1);
}
return output;
}
shared_ptr<DisassemblyInfo> Disassembler::GetDisassemblyInfo(int32_t absoluteAddress, int32_t absoluteRamAddress, uint16_t memoryAddress)

View file

@ -20,6 +20,8 @@ private:
bool IsUnconditionalJump(uint8_t opCode);
vector<string> SplitComment(string input);
string GetLine(string code = "", string comment = "", int32_t cpuAddress = -1, int32_t absoluteAddress = -1, string byteCode = "", string addressing = "");
string GetSubHeader(DisassemblyInfo *info, string &label, uint16_t relativeAddr, uint16_t resetVector, uint16_t nmiVector, uint16_t irqVector);
public:
Disassembler(uint8_t* internalRam, uint8_t* prgRom, uint32_t prgSize, uint8_t* prgRam, uint32_t prgRamSize);

View file

@ -2,6 +2,7 @@
#include "DisassemblyInfo.h"
#include "CPU.h"
#include "LabelManager.h"
#include "../Utilities/HexUtilities.h"
string DisassemblyInfo::OPName[256];
AddrMode DisassemblyInfo::OPMode[256];
@ -9,20 +10,26 @@ uint32_t DisassemblyInfo::OPSize[256];
string DisassemblyInfo::ToString(uint32_t memoryAddr, shared_ptr<MemoryManager> memoryManager, shared_ptr<LabelManager> labelManager)
{
std::ostringstream output;
string out;
out.reserve(50);
uint8_t opCode = *_opPointer;
output << DisassemblyInfo::OPName[opCode];
if(DisassemblyInfo::OPName[opCode].empty()) {
output << "invalid opcode";
out = "invalid opcode";
} else {
out = DisassemblyInfo::OPName[opCode];
}
std::ostringstream addrString;
if(_opSize == 2) {
_opAddr = *(_opPointer + 1);
} else if(_opSize == 3) {
_opAddr = *(_opPointer + 1) | (*(_opPointer + 2) << 8);
}
if(_opMode == AddrMode::Rel) {
_opAddr = (int8_t)_opAddr + memoryAddr + 2;
}
string operandValue;
if(labelManager && _opMode != AddrMode::Imm) {
@ -30,50 +37,48 @@ string DisassemblyInfo::ToString(uint32_t memoryAddr, shared_ptr<MemoryManager>
}
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();
if(_opSize == 2) {
operandValue += "$" + HexUtilities::ToHex((uint8_t)_opAddr);
} else {
operandValue += "$" + HexUtilities::ToHex((uint16_t)_opAddr);
}
}
output << " ";
out += " ";
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::Acc: out += "A"; break;
case AddrMode::Imm: out += "#" + operandValue; break;
case AddrMode::Ind: out += "(" + operandValue + ")"; break;
case AddrMode::IndX: out += "(" + operandValue + ",X)"; break;
case AddrMode::IndY:
case AddrMode::IndYW:
output << "(" << operandValue << "),Y";
out += "(" + operandValue + "),Y";
break;
case AddrMode::Abs:
case AddrMode::Rel:
case AddrMode::Zero:
output << operandValue;
out += operandValue;
break;
case AddrMode::AbsX:
case AddrMode::AbsXW:
case AddrMode::ZeroX:
output << operandValue << ",X";
out += operandValue + ",X";
break;
case AddrMode::AbsY:
case AddrMode::AbsYW:
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);
out += operandValue + ",Y";
break;
default: break;
}
return output.str();
return out;
}
DisassemblyInfo::DisassemblyInfo(uint8_t* opPointer, bool isSubEntryPoint)
@ -86,21 +91,20 @@ DisassemblyInfo::DisassemblyInfo(uint8_t* opPointer, bool isSubEntryPoint)
_opMode = DisassemblyInfo::OPMode[opCode];
_isSubExitPoint = opCode == 0x40 || opCode == 0x60;
//Raw byte code
std::stringstream byteCodeOutput;
string byteCodeOutput;
byteCodeOutput.reserve(10);
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);
byteCodeOutput += "$" + HexUtilities::ToHex((uint16_t)*(_opPointer + i));
} else {
byteCodeOutput << " ";
byteCodeOutput += " ";
}
if(i != 2) {
byteCodeOutput << " ";
byteCodeOutput += " ";
}
}
_byteCode = byteCodeOutput.str();
_byteCode = byteCodeOutput;
}
void DisassemblyInfo::SetSubEntryPoint()
@ -122,15 +126,15 @@ string DisassemblyInfo::GetEffectiveAddressString(State& cpuState, shared_ptr<Me
}
}
std::stringstream ss;
ss << std::uppercase << std::setfill('0') << " @ $";
string output;
output = " @ $";
if(_opMode == AddrMode::ZeroX || _opMode == AddrMode::ZeroY) {
ss << std::setw(2) << std::hex << (uint16_t)effectiveAddress;
output += HexUtilities::ToHex((uint8_t)effectiveAddress);
} else {
ss << std::setw(4) << std::hex << (uint16_t)effectiveAddress;
output += HexUtilities::ToHex((uint16_t)effectiveAddress);
}
return ss.str();
return output;
}
}

View file

@ -4,6 +4,7 @@
#include "Console.h"
#include "Debugger.h"
#include "LabelManager.h"
#include "../Utilities/HexUtilities.h"
std::unordered_map<string, std::vector<int>, StringHasher> ExpressionEvaluator::_outputCache;
SimpleLock ExpressionEvaluator::_cacheLock;
@ -164,11 +165,7 @@ string ExpressionEvaluator::GetNextToken(string expression, size_t &pos)
}
if(isHex) {
unsigned int x;
std::stringstream ss;
ss << std::hex << output;
ss >> x;
output = std::to_string(x);
output = std::to_string(HexUtilities::FromHex(output));
}
return output;

View file

@ -0,0 +1,52 @@
#include "stdafx.h"
#include "HexUtilities.h"
const vector<string> HexUtilities::_hexCache = { {
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
"E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
} };
int HexUtilities::FromHex(string hex)
{
int value = 0;
for(size_t i = 0, len = hex.size(); i < len; i++) {
value <<= 4;
if(hex[i] >= '0' && hex[i] <= '9') {
value |= hex[i] - '0';
} else if(hex[i] >= 'A' && hex[i] <= 'F') {
value |= hex[i] - 'A' + 10;
} else if(hex[i] >= 'a' && hex[i] <= 'f') {
value |= hex[i] - 'a' + 10;
}
}
return value;
}
string HexUtilities::ToHex(uint8_t value)
{
return _hexCache[value];
}
string HexUtilities::ToHex(uint16_t value)
{
return _hexCache[value >> 8] + _hexCache[value & 0xFF];
}
string HexUtilities::ToHex(uint32_t value)
{
return _hexCache[value >> 24] + _hexCache[(value >> 16) & 0xFF] + _hexCache[(value >> 8) & 0xFF] + _hexCache[value & 0xFF];
}

15
Utilities/HexUtilities.h Normal file
View file

@ -0,0 +1,15 @@
#pragma once
#include "stdafx.h"
class HexUtilities
{
private:
const static vector<string> _hexCache;
public:
static string ToHex(uint8_t addr);
static string ToHex(uint16_t addr);
static string ToHex(uint32_t addr);
static int FromHex(string hex);
};

View file

@ -325,6 +325,7 @@
<ClInclude Include="blip_buf.h" />
<ClInclude Include="CRC32.h" />
<ClInclude Include="FolderUtilities.h" />
<ClInclude Include="HexUtilities.h" />
<ClInclude Include="HQX\common.h" />
<ClInclude Include="HQX\hqx.h" />
<ClInclude Include="IpsPatcher.h" />
@ -359,6 +360,7 @@
<ClCompile Include="blip_buf.cpp" />
<ClCompile Include="CRC32.cpp" />
<ClCompile Include="FolderUtilities.cpp" />
<ClCompile Include="HexUtilities.cpp" />
<ClCompile Include="HQX\hq2x.cpp" />
<ClCompile Include="HQX\hq3x.cpp" />
<ClCompile Include="HQX\hq4x.cpp" />

View file

@ -119,6 +119,9 @@
<ClInclude Include="PlatformUtilities.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="HexUtilities.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -214,5 +217,8 @@
<ClCompile Include="PlatformUtilities.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="HexUtilities.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>