Debugger: Allow disassembly of cartridge work ram & cpu ram + Added tracing for NMI, IRQ and DMAs

This commit is contained in:
Souryo 2016-02-13 22:19:42 -05:00
parent 9084d48a01
commit f1d8bde090
11 changed files with 241 additions and 136 deletions

View file

@ -549,15 +549,25 @@ void BaseMapper::NotifyVRAMAddressChange(uint16_t addr)
}
//Debugger Helper Functions
uint8_t* BaseMapper::GetPrgRom()
{
return _prgRom;
}
uint8_t* BaseMapper::GetWorkRam()
{
return _workRam;
}
void BaseMapper::GetPrgCopy(uint8_t **buffer)
{
*buffer = new uint8_t[_prgSize];
memcpy(*buffer, _prgRom, _prgSize);
}
uint32_t BaseMapper::GetPrgSize()
uint32_t BaseMapper::GetPrgSize(bool getWorkRamSize)
{
return _prgSize;
return getWorkRamSize ? GetWorkRamSize() : _prgSize;
}
void BaseMapper::GetChrRomCopy(uint8_t **buffer)
@ -586,6 +596,15 @@ int32_t BaseMapper::ToAbsoluteAddress(uint16_t addr)
return -1;
}
int32_t BaseMapper::ToAbsoluteRamAddress(uint16_t addr)
{
uint8_t *prgRamAddr = _prgPages[addr >> 8] + (addr & 0xFF);
if(prgRamAddr >= _workRam && prgRamAddr < _workRam + GetWorkRamSize()) {
return (uint32_t)(prgRamAddr - _workRam);
}
return -1;
}
int32_t BaseMapper::ToAbsoluteChrAddress(uint16_t addr)
{
uint8_t *chrAddr = _chrPages[addr >> 8] + (addr & 0xFF);
@ -608,18 +627,4 @@ int32_t BaseMapper::FromAbsoluteAddress(uint32_t addr)
//Address is currently not mapped
return -1;
}
vector<int32_t> BaseMapper::GetPRGRanges()
{
vector<int32_t> memoryRanges;
for(uint32_t i = 0x8000; i <= 0xFFFF; i += 0x100) {
int32_t pageStart = ToAbsoluteAddress((uint16_t)i);
int32_t pageEnd = ToAbsoluteAddress((uint16_t)i + 0xFF);
memoryRanges.push_back(pageStart);
memoryRanges.push_back(pageEnd);
}
return memoryRanges;
}

View file

@ -168,13 +168,15 @@ public:
void WriteVRAM(uint16_t addr, uint8_t value);
//Debugger Helper Functions
uint8_t* GetPrgRom();
uint8_t* GetWorkRam();
void GetPrgCopy(uint8_t **buffer);
uint32_t GetPrgSize();
uint32_t GetPrgSize(bool getWorkRamSize = false);
void GetChrRomCopy(uint8_t **buffer);
uint32_t GetChrSize(bool getRamSize = false);
void GetChrRamCopy(uint8_t **buffer);
int32_t ToAbsoluteAddress(uint16_t addr);
int32_t ToAbsoluteRamAddress(uint16_t addr);
int32_t ToAbsoluteChrAddress(uint16_t addr);
int32_t FromAbsoluteAddress(uint32_t addr);
vector<int32_t> GetPRGRanges();
};

View file

@ -3,6 +3,7 @@
#include "PPU.h"
#include "APU.h"
#include "DeltaModulationChannel.h"
#include "TraceLogger.h"
CPU* CPU::Instance = nullptr;
@ -106,6 +107,7 @@ void CPU::IncCycleCount()
//Update the DMC buffer when the stall period is completed
_dmcDmaRunning = false;
DeltaModulationChannel::SetReadBuffer();
TraceLogger::LogStatic("DMC DMA End");
}
}
@ -126,6 +128,7 @@ void CPU::IncCycleCount()
void CPU::RunDMATransfer(uint8_t* spriteRAM, uint8_t offsetValue)
{
TraceLogger::LogStatic("Sprite DMA Start");
Instance->_spriteDmaTransfer = true;
//"The CPU is suspended during the transfer, which will take 513 or 514 cycles after the $4014 write tick."
@ -149,12 +152,15 @@ void CPU::RunDMATransfer(uint8_t* spriteRAM, uint8_t offsetValue)
}
Instance->_spriteDmaTransfer = false;
TraceLogger::LogStatic("Sprite DMA End");
}
void CPU::StartDmcTransfer()
{
//"DMC DMA adds 4 cycles normally, 2 if it lands on the $4014 write or during OAM DMA"
//3 cycles if it lands on the last write cycle of any instruction
TraceLogger::LogStatic("DMC DMA Start");
Instance->_dmcDmaRunning = true;
if(Instance->_spriteDmaTransfer) {
if(Instance->_spriteDmaCounter == 2) {

View file

@ -4,6 +4,7 @@
#include "MemoryManager.h"
#include "PPU.h"
#include "Snapshotable.h"
#include "TraceLogger.h"
namespace PSFlags
{
@ -643,11 +644,15 @@ private:
SetFlags(PSFlags::Interrupt);
SetPC(MemoryReadWord(CPU::NMIVector));
TraceLogger::LogStatic("NMI");
} else {
Push((uint8_t)flags);
SetFlags(PSFlags::Interrupt);
SetPC(MemoryReadWord(CPU::IRQVector));
TraceLogger::LogStatic("IRQ");
}
//Since we just set the flag to prevent interrupts, do not run one right away after this (fixes nmi_and_brk & nmi_and_irq tests)
@ -665,10 +670,14 @@ private:
SetPC(MemoryReadWord(CPU::NMIVector));
_state.NMIFlag = false;
TraceLogger::LogStatic("NMI");
} else {
Push((uint8_t)PS());
SetFlags(PSFlags::Interrupt);
SetPC(MemoryReadWord(CPU::IRQVector));
TraceLogger::LogStatic("IRQ");
}
}

View file

@ -22,9 +22,7 @@ Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<
_memoryManager = memoryManager;
_mapper = mapper;
uint8_t *prgBuffer;
mapper->GetPrgCopy(&prgBuffer);
_disassembler.reset(new Disassembler(memoryManager->GetInternalRAM(), prgBuffer, mapper->GetPrgSize()));
_disassembler.reset(new Disassembler(memoryManager->GetInternalRAM(), mapper->GetPrgRom(), mapper->GetPrgSize(), mapper->GetWorkRam(), mapper->GetPrgSize(true)));
_codeDataLogger.reset(new CodeDataLogger(mapper->GetPrgSize(), mapper->GetChrSize()));
_stepOut = false;
@ -67,7 +65,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, 0xFFFF) - 1;
i = _disassembler->BuildCache(i, -1, 0xFFFF, false) - 1;
}
}
return true;
@ -241,27 +239,38 @@ void Debugger::PrivateProcessRamOperation(MemoryOperationType type, uint16_t &ad
//Check if a breakpoint has been hit and freeze execution if one has
bool breakDone = false;
int32_t absoluteAddr = _mapper->ToAbsoluteAddress(addr);
int32_t absoluteRamAddr = _mapper->ToAbsoluteRamAddress(addr);
if(absoluteAddr >= 0) {
if(type == MemoryOperationType::ExecOpCode) {
_codeDataLogger->SetFlag(absoluteAddr, CdlPrgFlags::Code);
_disassembler->BuildCache(absoluteAddr, addr);
_lastInstruction = _memoryManager->DebugRead(addr);
if(_traceLogger) {
DebugState state;
GetState(&state);
_traceLogger->Log(state, _disassembler->GetDisassemblyInfo(absoluteAddr));
}
UpdateCallstack(addr);
ProcessStepConditions(addr);
breakDone = SleepUntilResume();
} else if(type == MemoryOperationType::ExecOperand) {
if(type == MemoryOperationType::ExecOperand) {
_codeDataLogger->SetFlag(absoluteAddr, CdlPrgFlags::Code);
} else {
_codeDataLogger->SetFlag(absoluteAddr, CdlPrgFlags::Data);
}
} else if(addr < 0x2000 || absoluteRamAddr >= 0) {
if(type == MemoryOperationType::Write) {
_disassembler->InvalidateCache(addr, absoluteRamAddr);
}
}
if(type == MemoryOperationType::ExecOpCode) {
if(absoluteAddr >= 0) {
_codeDataLogger->SetFlag(absoluteAddr, CdlPrgFlags::Code);
}
bool isSubEntryPoint = _lastInstruction == 0x20; //Previous instruction was a JSR
_disassembler->BuildCache(absoluteAddr, absoluteRamAddr, addr, isSubEntryPoint);
_lastInstruction = _memoryManager->DebugRead(addr);
UpdateCallstack(addr);
ProcessStepConditions(addr);
if(_traceLogger) {
DebugState state;
GetState(&state);
_traceLogger->Log(state, _disassembler->GetDisassemblyInfo(absoluteAddr, absoluteRamAddr, addr));
}
breakDone = SleepUntilResume();
}
if(!breakDone && _hasBreakpoint) {
@ -393,26 +402,36 @@ bool Debugger::IsCodeChanged()
string Debugger::GenerateOutput()
{
std::ostringstream output;
vector<int32_t> memoryRanges = _mapper->GetPRGRanges();
//RAM code viewer doesn't work well yet
//output << _disassembler->GetRAMCode();
//Get code in internal RAM
output << _disassembler->GetCode(0x0000, 0x1FFF, 0x0000, PrgMemoryType::PrgRom);
output << "2000:::--END OF INTERNAL RAM--\n";
uint16_t memoryAddr = 0x8000;
for(size_t i = 0, size = memoryRanges.size(); i < size; i += 2) {
int32_t startRange = memoryRanges[i];
for(uint32_t i = 0x4100; i < 0x10000; i += 0x100) {
//Merge all sequential ranges into 1 chunk
if(startRange != -1) {
for(size_t j = i+1; j < size - 1; j+=2) {
if(memoryRanges[j] + 1 == memoryRanges[j + 1]) {
i+=2;
} else {
break;
}
int32_t romAddr = _mapper->ToAbsoluteAddress(i);
int32_t ramAddr = _mapper->ToAbsoluteRamAddress(i);
uint32_t startMemoryAddr = i;
int32_t startAddr, endAddr;
if(romAddr >= 0) {
startAddr = romAddr;
endAddr = startAddr + 0xFF;
while(romAddr + 0x100 == _mapper->ToAbsoluteAddress(i + 0x100) && i < 0x10000) {
endAddr += 0x100;
romAddr += 0x100;
i+=0x100;
}
output << _disassembler->GetCode(startRange, memoryRanges[i+1], memoryAddr);
} else {
memoryAddr += 0x100;
output << _disassembler->GetCode(startAddr, endAddr, startMemoryAddr, PrgMemoryType::PrgRom);
} else if(ramAddr >= 0) {
startAddr = ramAddr;
endAddr = startAddr + 0xFF;
while(ramAddr + 0x100 == _mapper->ToAbsoluteRamAddress(i + 0x100) && i < 0x10000) {
endAddr += 0x100;
ramAddr += 0x100;
i += 0x100;
}
output << _disassembler->GetCode(startAddr, endAddr, startMemoryAddr, PrgMemoryType::WorkRam);
}
}

View file

@ -1,38 +1,42 @@
#include "stdafx.h"
#include "Disassembler.h"
#include "DisassemblyInfo.h"
#include "BaseMapper.h"
Disassembler::Disassembler(uint8_t* internalRAM, uint8_t* prgROM, uint32_t prgSize)
Disassembler::Disassembler(uint8_t* internalRam, uint8_t* prgRom, uint32_t prgSize, uint8_t* prgRam, uint32_t prgRamSize)
{
_internalRAM = internalRAM;
_prgROM = prgROM;
_internalRam = internalRam;
_prgRom = prgRom;
_prgRam = prgRam;
_prgSize = prgSize;
for(uint32_t i = 0; i < prgSize; i++) {
_disassembleCache.push_back(shared_ptr<DisassemblyInfo>(nullptr));
}
for(uint32_t i = 0; i < 0x2000; i++) {
for(uint32_t i = 0; i < prgRamSize; i++) {
_disassembleRamCache.push_back(shared_ptr<DisassemblyInfo>(nullptr));
}
for(uint32_t i = 0; i < 0x800; i++) {
_disassembleMemoryCache.push_back(shared_ptr<DisassemblyInfo>(nullptr));
}
string opName[256] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
"BRK", "ORA", "", "", "NOP", "ORA", "ASL", "", "PHP", "ORA", "ASL", "", "NOP", "ORA", "ASL", "", //0
"BPL", "ORA", "", "", "NOP", "ORA", "ASL", "", "CLC", "ORA", "", "", "NOP", "ORA", "ASL", "", //1
"JSR", "AND", "", "", "BIT", "AND", "ROL", "", "PLP", "AND", "ROL", "", "BIT", "AND", "ROL", "", //2
"BMI", "AND", "", "", "NOP", "AND", "ROL", "", "SEC", "AND", "", "", "NOP", "AND", "ROL", "", //3
"RTI", "EOR", "", "", "NOP", "EOR", "LSR", "", "PHA", "EOR", "LSR", "", "JMP", "EOR", "LSR", "", //4
"BVC", "EOR", "", "", "NOP", "EOR", "LSR", "", "CLI", "EOR", "", "", "NOP", "EOR", "LSR", "", //5
"RTS", "ADC", "", "", "NOP", "ADC", "ROR", "", "PLA", "ADC", "ROR", "", "JMP", "ADC", "ROR", "", //6
"BVS", "ADC", "", "", "NOP", "ADC", "ROR", "", "SEI", "ADC", "", "", "NOP", "ADC", "ROR", "", //7
"NOP", "STA", "NOP", "", "STY", "STA", "STX", "", "DEY", "NOP", "TXA", "", "STY", "STA", "STX", "", //8
"BCC", "STA", "", "", "STY", "STA", "STX", "", "TYA", "STA", "TXS", "", "", "STA", "", "", //9
"LDY", "LDA", "LDX", "", "LDY", "LDA", "LDX", "", "TAY", "LDA", "TAX", "", "LDY", "LDA", "LDX", "", //A
"BCS", "LDA", "", "", "LDY", "LDA", "LDX", "", "CLV", "LDA", "TSX", "", "LDY", "LDA", "LDX", "", //B
"CPY", "CPA", "NOP", "", "CPY", "CPA", "DEC", "", "INY", "CPA", "DEX", "", "CPY", "CPA", "DEC", "", //C
"BNE", "CPA", "", "", "NOP", "CPA", "DEC", "", "CLD", "CPA", "", "", "NOP", "CPA", "DEC", "", //D
"CPX", "SBC", "NOP", "", "CPX", "SBC", "INC", "", "INX", "SBC", "NOP", "", "CPX", "SBC", "INC", "", //E
"BEQ", "SBC", "", "", "NOP", "SBC", "INC", "", "SED", "SBC", "", "", "NOP", "SBC", "INC", "" //F
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
"BRK", "ORA", "", "SLO*", "NOP", "ORA", "ASL", "SLO*", "PHP", "ORA", "ASL", "AAC*", "NOP", "ORA", "ASL", "SLO*", //0
"BPL", "ORA", "", "SLO*", "NOP", "ORA", "ASL", "SLO*", "CLC", "ORA", "NOP*", "SLO*", "NOP", "ORA", "ASL", "SLO*", //1
"JSR", "AND", "", "RLA*", "BIT", "AND", "ROL", "RLA*", "PLP", "AND", "ROL", "AAC*", "BIT", "AND", "ROL", "RLA*", //2
"BMI", "AND", "", "RLA*", "NOP", "AND", "ROL", "RLA*", "SEC", "AND", "NOP*", "RLA*", "NOP", "AND", "ROL", "RLA*", //3
"RTI", "EOR", "", "SRE*", "NOP", "EOR", "LSR", "SRE*", "PHA", "EOR", "LSR", "ASR*", "JMP", "EOR", "LSR", "SRE*", //4
"BVC", "EOR", "", "SRE*", "NOP", "EOR", "LSR", "SRE*", "CLI", "EOR", "NOP*", "SRE*", "NOP", "EOR", "LSR", "SRE*", //5
"RTS", "ADC", "", "RRA*", "NOP", "ADC", "ROR", "RRA*", "PLA", "ADC", "ROR", "ARR*", "JMP", "ADC", "ROR", "RRA*", //6
"BVS", "ADC", "", "RRA*", "NOP", "ADC", "ROR", "RRA*", "SEI", "ADC", "NOP*", "RRA*", "NOP", "ADC", "ROR", "RRA*", //7
"NOP", "STA", "NOP", "SAX*", "STY", "STA", "STX", "SAX*", "DEY", "NOP", "TXA", "", "STY", "STA", "STX", "SAX*", //8
"BCC", "STA", "", "AXA*", "STY", "STA", "STX", "SAX*", "TYA", "STA", "TXS", "TAS*", "SYA*", "STA", "SXA", "AXA*", //9
"LDY", "LDA", "LDX", "LAX*", "LDY", "LDA", "LDX", "LAX*", "TAY", "LDA", "TAX", "ATX*", "LDY", "LDA", "LDX", "LAX*", //A
"BCS", "LDA", "", "LAX*", "LDY", "LDA", "LDX", "LAX*", "CLV", "LDA", "TSX", "LAS*", "LDY", "LDA", "LDX", "LAX*", //B
"CPY", "CPA", "NOP", "DCP*", "CPY", "CPA", "DEC", "DCP*", "INY", "CPA", "DEX", "AXS*", "CPY", "CPA", "DEC", "DCP*", //C
"BNE", "CPA", "", "DCP*", "NOP", "CPA", "DEC", "DCP*", "CLD", "CPA", "NOP*", "DCP*", "NOP", "CPA", "DEC", "DCP*", //D
"CPX", "SBC", "NOP", "ISB*", "CPX", "SBC", "INC", "ISB*", "INX", "SBC", "NOP", "SBC*", "CPX", "SBC", "INC", "ISB*", //E
"BEQ", "SBC", "", "ISB*", "NOP", "SBC", "INC", "ISB*", "SED", "SBC", "NOP*", "ISB*", "NOP", "SBC", "INC", "ISB*" //F
};
AddrMode opMode[256] = {
@ -87,28 +91,34 @@ Disassembler::Disassembler(uint8_t* internalRAM, uint8_t* prgROM, uint32_t prgSi
Disassembler::~Disassembler()
{
if(_prgROM) {
delete[] _prgROM;
}
}
uint32_t Disassembler::BuildCache(uint32_t absoluteAddr, uint16_t memoryAddr)
uint32_t Disassembler::BuildCache(int32_t absoluteAddr, int32_t absoluteRamAddr, uint16_t memoryAddr, bool isSubEntryPoint)
{
if(memoryAddr < 0x2000) {
memoryAddr = memoryAddr & 0x7FF;
if(!_disassembleMemoryCache[memoryAddr]) {
shared_ptr<DisassemblyInfo> disInfo(new DisassemblyInfo(&_internalRAM[memoryAddr]));
shared_ptr<DisassemblyInfo> disInfo(new DisassemblyInfo(&_internalRam[memoryAddr], isSubEntryPoint));
_disassembleMemoryCache[memoryAddr] = disInfo;
memoryAddr += disInfo->GetSize();
} else if(isSubEntryPoint) {
_disassembleMemoryCache[memoryAddr]->SetSubEntryPoint();
}
return memoryAddr;
} else {
if(!_disassembleCache[absoluteAddr]) {
while(absoluteAddr < _prgSize && !_disassembleCache[absoluteAddr]) {
shared_ptr<DisassemblyInfo> disInfo(new DisassemblyInfo(&_prgROM[absoluteAddr]));
_disassembleCache[absoluteAddr] = disInfo;
vector<shared_ptr<DisassemblyInfo>> &cache = absoluteRamAddr >= 0 ? _disassembleRamCache : _disassembleCache;
uint8_t *source = absoluteRamAddr >= 0 ? _prgRam : _prgRom;
if(absoluteRamAddr >= 0) {
absoluteAddr = absoluteRamAddr;
}
uint8_t opCode = _prgROM[absoluteAddr];
if(!cache[absoluteAddr]) {
while(absoluteAddr < (int32_t)_prgSize && !cache[absoluteAddr]) {
shared_ptr<DisassemblyInfo> disInfo(new DisassemblyInfo(&source[absoluteAddr], isSubEntryPoint));
isSubEntryPoint = false;
cache[absoluteAddr] = disInfo;
uint8_t opCode = source[absoluteAddr];
absoluteAddr += disInfo->GetSize();
if(opCode == 0x10 || opCode == 0x20 || opCode == 0x30 || opCode == 0x40 || opCode == 0x50 || opCode == 0x60 || opCode == 0x70 || opCode == 0x90 || opCode == 0xB0 || opCode == 0xD0 || opCode == 0xF0 || opCode == 0x4C || opCode == 0x6C) {
//Hit a jump/return instruction, can't assume that what follows is actual code, stop disassembling
@ -116,56 +126,66 @@ uint32_t Disassembler::BuildCache(uint32_t absoluteAddr, uint16_t memoryAddr)
}
}
} else {
absoluteAddr += _disassembleCache[absoluteAddr]->GetSize();
if(isSubEntryPoint) {
cache[absoluteAddr]->SetSubEntryPoint();
}
absoluteAddr += cache[absoluteAddr]->GetSize();
}
return absoluteAddr;
}
}
string Disassembler::GetRAMCode()
void Disassembler::InvalidateCache(uint16_t memoryAddr, int32_t absoluteRamAddr)
{
std::ostringstream output;
uint32_t addr = 0x0000;
uint32_t byteCount = 0;
while(addr < 0x2000) {
shared_ptr<DisassemblyInfo> info;
if(info = _disassembleMemoryCache[addr&0x7FF]) {
if(byteCount > 0) {
output << "\n";
byteCount = 0;
}
output << std::hex << std::uppercase << addr << ":" << info->ToString(addr) << "\n";
addr += info->GetSize();
} else {
if(byteCount >= 8) {
output << "\n";
byteCount = 0;
}
if(byteCount == 0) {
output << std::hex << std::uppercase << addr << ":" << ".db";
}
output << std::hex << " $" << std::setfill('0') << std::setw(2) << (short)_internalRAM[addr];
byteCount++;
addr++;
}
uint32_t addr;
vector<shared_ptr<DisassemblyInfo>> *cache;
if(memoryAddr < 0x2000) {
addr = memoryAddr & 0x7FF;
cache = &_disassembleMemoryCache;
} else {
addr = absoluteRamAddr;
cache = &_disassembleRamCache;
}
if(addr >= 0) {
for(int i = 1; i <= 2; i++) {
int offsetAddr = (int)addr - i;
if(offsetAddr >= 0) {
if((*cache)[offsetAddr] != nullptr) {
if((*cache)[offsetAddr]->GetSize() >= (uint32_t)i + 1) {
//Invalidate any instruction that overlapped this address
(*cache)[offsetAddr] = nullptr;
}
}
}
}
(*cache)[addr] = nullptr;
}
output << "\n1FFF:--END OF INTERNAL RAM--\n";
return output.str();
}
string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t &memoryAddr)
string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memoryAddr, PrgMemoryType memoryType)
{
std::ostringstream output;
vector<shared_ptr<DisassemblyInfo>> *cache;
uint8_t *source;
uint32_t mask = 0xFFFFFFFF;
if(memoryAddr < 0x2000) {
cache = &_disassembleMemoryCache;
source = _internalRam;
mask = 0x7FF;
} else if(memoryType == PrgMemoryType::WorkRam) {
cache = &_disassembleRamCache;
source = _prgRam;
} else {
cache = &_disassembleCache;
source = _prgRom;
}
uint32_t addr = startAddr;
uint32_t byteCount = 0;
while(addr <= endAddr) {
shared_ptr<DisassemblyInfo> info;
if(info = _disassembleCache[addr]) {
if(info = (*cache)[addr&mask]) {
if(byteCount > 0) {
output << "\n";
byteCount = 0;
@ -181,7 +201,7 @@ string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t &mem
if(byteCount == 0) {
output << std::hex << std::uppercase << memoryAddr << ":" << addr << "::" << ".db";
}
output << std::hex << " $" << std::setfill('0') << std::setw(2) << (short)_prgROM[addr];
output << std::hex << " $" << std::setfill('0') << std::setw(2) << (short)source[addr];
byteCount++;
addr++;
@ -193,7 +213,15 @@ string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t &mem
return output.str();
}
shared_ptr<DisassemblyInfo> Disassembler::GetDisassemblyInfo(uint32_t address)
shared_ptr<DisassemblyInfo> Disassembler::GetDisassemblyInfo(int32_t absoluteAddress, int32_t absoluteRamAddress, uint16_t memoryAddress)
{
return _disassembleCache[address];
if(memoryAddress < 0x2000) {
return _disassembleMemoryCache[memoryAddress & 0x7FF];
} else if(absoluteAddress >= 0) {
return _disassembleCache[absoluteAddress];
} else if(absoluteRamAddress >= 0) {
return _disassembleRamCache[absoluteRamAddress];
}
return nullptr;
}

View file

@ -1,6 +1,6 @@
#pragma once
#include "stdafx.h"
#include "CPU.h"
#include "BaseMapper.h"
class DisassemblyInfo;
@ -8,18 +8,21 @@ class Disassembler
{
private:
vector<shared_ptr<DisassemblyInfo>> _disassembleCache;
vector<shared_ptr<DisassemblyInfo>> _disassembleRamCache;
vector<shared_ptr<DisassemblyInfo>> _disassembleMemoryCache;
uint8_t* _internalRAM;
uint8_t* _prgROM;
uint8_t* _internalRam;
uint8_t* _prgRom;
uint8_t* _prgRam;
uint32_t _prgSize;
public:
Disassembler(uint8_t* internalRAM, uint8_t* prgROM, uint32_t prgSize);
Disassembler(uint8_t* internalRam, uint8_t* prgRom, uint32_t prgSize, uint8_t* prgRam, uint32_t prgRamSize);
~Disassembler();
uint32_t BuildCache(uint32_t absoluteAddr, uint16_t memoryAddr);
string GetRAMCode();
string GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t &memoryAddr);
uint32_t BuildCache(int32_t absoluteAddr, int32_t absoluteRamAddr, uint16_t memoryAddr, bool isSubEntryPoint);
void InvalidateCache(uint16_t memoryAddr, int32_t absoluteRamAddr);
shared_ptr<DisassemblyInfo> GetDisassemblyInfo(uint32_t address);
string GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memoryAddr, PrgMemoryType memoryType);
shared_ptr<DisassemblyInfo> GetDisassemblyInfo(int32_t absoluteAddress, int32_t absoluteRamAddress, uint16_t memoryAddress);
};

View file

@ -31,7 +31,7 @@ void DisassemblyInfo::Initialize(uint32_t memoryAddr)
output << DisassemblyInfo::OPName[opCode];
if(opCode == 0x40 || opCode == 0x60) {
//Make end of function/interrupt routines more obvious
output << " ---------------------------";
output << " ---->";
}
if(DisassemblyInfo::OPName[opCode].empty()) {
@ -103,15 +103,28 @@ void DisassemblyInfo::Initialize(uint32_t memoryAddr)
break;
}
if(_isSubEntryPoint) {
output << " <----";
}
_disassembly = output.str();
}
DisassemblyInfo::DisassemblyInfo(uint8_t* opPointer)
DisassemblyInfo::DisassemblyInfo(uint8_t* opPointer, bool isSubEntryPoint)
{
_opPointer = opPointer;
_isSubEntryPoint = isSubEntryPoint;
Initialize();
}
void DisassemblyInfo::SetSubEntryPoint()
{
if(!_isSubEntryPoint) {
_isSubEntryPoint = true;
Initialize();
}
}
string DisassemblyInfo::ToString(uint32_t memoryAddr)
{

View file

@ -12,6 +12,7 @@ public:
private:
string _disassembly;
uint8_t *_opPointer = nullptr;
bool _isSubEntryPoint = false;
uint32_t _opSize = 0;
AddrMode _opMode;
uint32_t _lastAddr = 0;
@ -20,8 +21,9 @@ private:
void Initialize(uint32_t memoryAddr = 0);
public:
DisassemblyInfo(uint8_t* opPointer);
DisassemblyInfo(uint8_t* opPointer, bool isSubEntryPoint);
void SetSubEntryPoint();
string ToString(uint32_t memoryAddr);
uint32_t GetSize();
};

View file

@ -3,10 +3,13 @@
#include "DisassemblyInfo.h"
#include "DebugState.h"
TraceLogger *TraceLogger::_instance = nullptr;
TraceLogger::TraceLogger(string outputFilepath, TraceLoggerOptions options)
{
_outputFile.open(outputFilepath, ios::out | ios::binary);
_options = options;
_instance = this;
}
TraceLogger::~TraceLogger()
@ -14,6 +17,17 @@ TraceLogger::~TraceLogger()
if(_outputFile) {
_outputFile.close();
}
if(_instance == this) {
_instance = nullptr;
}
}
void TraceLogger::LogStatic(string log)
{
if(_instance) {
_instance->_outputFile << "--- " << log << " ---" << std::endl;
}
}
void TraceLogger::Log(DebugState &state, shared_ptr<DisassemblyInfo> disassemblyInfo)

View file

@ -1,7 +1,8 @@
#pragma once
#include "stdafx.h"
#include "DebugState.h"
#include "DisassemblyInfo.h"
class DisassemblyInfo;
struct DebugState;
struct TraceLoggerOptions
{
@ -11,6 +12,7 @@ struct TraceLoggerOptions
class TraceLogger
{
private:
static TraceLogger *_instance;
TraceLoggerOptions _options;
string _outputFilepath;
ofstream _outputFile;
@ -20,4 +22,6 @@ public:
~TraceLogger();
void Log(DebugState &state, shared_ptr<DisassemblyInfo> disassemblyInfo);
static void LogStatic(string log);
};