mirror of
https://github.com/SourMesen/Mesen.git
synced 2025-04-02 10:52:48 -04:00
Debugger: Allow disassembly of cartridge work ram & cpu ram + Added tracing for NMI, IRQ and DMAs
This commit is contained in:
parent
9084d48a01
commit
f1d8bde090
11 changed files with 241 additions and 136 deletions
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
};
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
};
|
Loading…
Add table
Reference in a new issue