2019-02-12 22:13:09 -05:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include "Debugger.h"
|
2019-02-27 20:33:56 -05:00
|
|
|
#include "DebugTypes.h"
|
2019-02-15 21:33:13 -05:00
|
|
|
#include "Console.h"
|
2019-02-12 22:13:09 -05:00
|
|
|
#include "Cpu.h"
|
2019-02-13 13:32:21 -05:00
|
|
|
#include "Ppu.h"
|
2019-04-06 17:38:14 -04:00
|
|
|
#include "Spc.h"
|
2019-02-27 19:49:26 -05:00
|
|
|
#include "BaseCartridge.h"
|
|
|
|
#include "MemoryManager.h"
|
2019-03-07 20:12:32 -05:00
|
|
|
#include "SoundMixer.h"
|
2019-02-16 08:10:08 -05:00
|
|
|
#include "NotificationManager.h"
|
2019-02-12 22:13:09 -05:00
|
|
|
#include "CpuTypes.h"
|
|
|
|
#include "DisassemblyInfo.h"
|
|
|
|
#include "TraceLogger.h"
|
2019-02-15 21:33:13 -05:00
|
|
|
#include "MemoryDumper.h"
|
2019-03-28 17:47:43 -04:00
|
|
|
#include "MemoryAccessCounter.h"
|
2019-02-27 19:49:26 -05:00
|
|
|
#include "CodeDataLogger.h"
|
|
|
|
#include "Disassembler.h"
|
2019-03-01 20:27:49 -05:00
|
|
|
#include "BreakpointManager.h"
|
2019-03-03 16:34:23 -05:00
|
|
|
#include "PpuTools.h"
|
2019-03-07 20:12:32 -05:00
|
|
|
#include "EventManager.h"
|
|
|
|
#include "EventType.h"
|
2019-03-24 12:05:51 -04:00
|
|
|
#include "CallstackManager.h"
|
2019-02-27 20:33:56 -05:00
|
|
|
#include "ExpressionEvaluator.h"
|
2019-02-12 22:13:09 -05:00
|
|
|
#include "../Utilities/HexUtilities.h"
|
2019-02-27 19:49:26 -05:00
|
|
|
#include "../Utilities/FolderUtilities.h"
|
2019-02-12 22:13:09 -05:00
|
|
|
|
2019-02-15 21:33:13 -05:00
|
|
|
Debugger::Debugger(shared_ptr<Console> console)
|
2019-02-12 22:13:09 -05:00
|
|
|
{
|
2019-02-16 08:10:08 -05:00
|
|
|
_console = console;
|
2019-02-15 21:33:13 -05:00
|
|
|
_cpu = console->GetCpu();
|
|
|
|
_ppu = console->GetPpu();
|
2019-04-06 17:38:14 -04:00
|
|
|
_spc = console->GetSpc();
|
2019-02-15 21:33:13 -05:00
|
|
|
_memoryManager = console->GetMemoryManager();
|
|
|
|
|
2019-04-07 14:38:22 -04:00
|
|
|
_watchExpEval[(int)CpuType::Cpu].reset(new ExpressionEvaluator(this, CpuType::Cpu));
|
|
|
|
_watchExpEval[(int)CpuType::Spc].reset(new ExpressionEvaluator(this, CpuType::Spc));
|
|
|
|
|
2019-03-28 17:47:43 -04:00
|
|
|
_codeDataLogger.reset(new CodeDataLogger(console->GetCartridge()->DebugGetPrgRomSize(), _memoryManager.get()));
|
2019-02-27 19:49:26 -05:00
|
|
|
_disassembler.reset(new Disassembler(console, _codeDataLogger));
|
2019-03-07 20:12:32 -05:00
|
|
|
_traceLogger.reset(new TraceLogger(this, _console));
|
2019-03-22 21:38:31 -04:00
|
|
|
_memoryDumper.reset(new MemoryDumper(_ppu, console->GetSpc(), _memoryManager, console->GetCartridge()));
|
2019-04-07 14:38:22 -04:00
|
|
|
_memoryAccessCounter.reset(new MemoryAccessCounter(this, _spc.get(), _memoryManager.get()));
|
2019-03-01 20:27:49 -05:00
|
|
|
_breakpointManager.reset(new BreakpointManager(this));
|
2019-03-03 16:34:23 -05:00
|
|
|
_ppuTools.reset(new PpuTools(_console.get(), _ppu.get()));
|
2019-03-07 20:12:32 -05:00
|
|
|
_eventManager.reset(new EventManager(this, _cpu.get(), _ppu.get()));
|
2019-03-24 12:05:51 -04:00
|
|
|
_callstackManager.reset(new CallstackManager(this));
|
2019-04-07 12:25:14 -04:00
|
|
|
_spcCallstackManager.reset(new CallstackManager(this));
|
2019-03-07 20:12:32 -05:00
|
|
|
|
2019-03-23 15:39:21 -04:00
|
|
|
_cpuStepCount = -1;
|
2019-04-07 12:25:14 -04:00
|
|
|
_spcStepCount = -1;
|
2019-03-28 17:47:43 -04:00
|
|
|
_ppuStepCount = -1;
|
2019-04-07 12:25:14 -04:00
|
|
|
_cpuBreakAddress = -1;
|
|
|
|
_spcBreakAddress = -1;
|
2019-03-30 22:58:57 -04:00
|
|
|
_breakScanline = -1;
|
2019-04-07 12:25:14 -04:00
|
|
|
|
2019-03-07 20:12:32 -05:00
|
|
|
_executionStopped = false;
|
|
|
|
_breakRequestCount = 0;
|
2019-02-27 19:49:26 -05:00
|
|
|
|
2019-03-12 12:28:41 -04:00
|
|
|
string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_console->GetCartridge()->GetRomInfo().RomFile.GetFileName(), false) + ".cdl");
|
2019-02-27 19:49:26 -05:00
|
|
|
_codeDataLogger->LoadCdlFile(cdlFile);
|
|
|
|
|
|
|
|
//TODO: Thread safety
|
|
|
|
uint32_t prgRomSize = console->GetCartridge()->DebugGetPrgRomSize();
|
|
|
|
AddressInfo addrInfo;
|
|
|
|
addrInfo.Type = SnesMemoryType::PrgRom;
|
|
|
|
for(uint32_t i = 0; i < prgRomSize; i++) {
|
|
|
|
if(_codeDataLogger->IsCode(i)) {
|
|
|
|
addrInfo.Address = (int32_t)i;
|
2019-04-06 17:38:14 -04:00
|
|
|
i += _disassembler->BuildCache(addrInfo, _codeDataLogger->GetCpuFlags(i), CpuType::Cpu) - 1;
|
2019-02-27 19:49:26 -05:00
|
|
|
}
|
|
|
|
}
|
2019-02-12 22:13:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
Debugger::~Debugger()
|
2019-03-16 12:20:18 -04:00
|
|
|
{
|
|
|
|
Release();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::Release()
|
2019-02-12 22:13:09 -05:00
|
|
|
{
|
2019-03-12 12:28:41 -04:00
|
|
|
string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_console->GetCartridge()->GetRomInfo().RomFile.GetFileName(), false) + ".cdl");
|
2019-02-27 19:49:26 -05:00
|
|
|
_codeDataLogger->SaveCdlFile(cdlFile);
|
2019-03-16 12:20:18 -04:00
|
|
|
|
|
|
|
while(_executionStopped) {
|
|
|
|
Run();
|
|
|
|
}
|
2019-02-12 22:13:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type)
|
|
|
|
{
|
2019-02-27 19:49:26 -05:00
|
|
|
AddressInfo addressInfo = _memoryManager->GetAbsoluteAddress(addr);
|
2019-03-01 20:27:49 -05:00
|
|
|
MemoryOperationInfo operation = { addr, value, type };
|
2019-02-27 19:49:26 -05:00
|
|
|
CpuState state = _cpu->GetState();
|
|
|
|
|
2019-02-12 22:13:09 -05:00
|
|
|
if(type == MemoryOperationType::ExecOpCode) {
|
2019-02-27 19:49:26 -05:00
|
|
|
if(addressInfo.Address >= 0) {
|
|
|
|
if(addressInfo.Type == SnesMemoryType::PrgRom) {
|
|
|
|
uint8_t flags = CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8));
|
|
|
|
if(_prevOpCode == 0x20 || _prevOpCode == 0x5C || _prevOpCode == 0xDC || _prevOpCode == 0xFC) {
|
|
|
|
flags |= CdlFlags::SubEntryPoint;
|
|
|
|
}
|
|
|
|
_codeDataLogger->SetFlags(addressInfo.Address, flags);
|
|
|
|
}
|
2019-04-06 17:38:14 -04:00
|
|
|
_disassembler->BuildCache(addressInfo, state.PS, CpuType::Cpu);
|
2019-02-27 19:49:26 -05:00
|
|
|
}
|
|
|
|
|
2019-02-13 13:32:21 -05:00
|
|
|
DebugState debugState;
|
2019-03-01 20:27:49 -05:00
|
|
|
GetState(debugState);
|
2019-02-12 22:13:09 -05:00
|
|
|
|
2019-02-27 19:49:26 -05:00
|
|
|
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo);
|
|
|
|
_traceLogger->Log(debugState, disInfo);
|
|
|
|
|
2019-03-24 12:05:51 -04:00
|
|
|
uint32_t pc = (state.K << 16) | state.PC;
|
|
|
|
if(_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC) {
|
|
|
|
//JSR, JSL
|
2019-04-06 17:38:14 -04:00
|
|
|
uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, state.PS, CpuType::Cpu);
|
2019-03-24 12:05:51 -04:00
|
|
|
uint32_t returnPc = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + opSize) & 0xFFFF);
|
|
|
|
_callstackManager->Push(_prevProgramCounter, pc, returnPc, StackFrameFlags::None);
|
|
|
|
} else if(_prevOpCode == 0x60 || _prevOpCode == 0x6B || _prevOpCode == 0x40) {
|
|
|
|
//RTS, RTL, RTI
|
|
|
|
_callstackManager->Pop(pc);
|
|
|
|
}
|
|
|
|
|
2019-03-24 16:42:52 -04:00
|
|
|
ProcessStepConditions(_prevOpCode, pc);
|
|
|
|
|
2019-02-27 19:49:26 -05:00
|
|
|
_prevOpCode = value;
|
2019-03-24 12:05:51 -04:00
|
|
|
_prevProgramCounter = pc;
|
2019-02-27 19:49:26 -05:00
|
|
|
|
2019-02-12 22:13:09 -05:00
|
|
|
if(_cpuStepCount > 0) {
|
|
|
|
_cpuStepCount--;
|
2019-03-01 20:27:49 -05:00
|
|
|
}
|
2019-04-12 17:49:58 -04:00
|
|
|
|
2019-03-03 16:34:23 -05:00
|
|
|
/*if(value == 0x00 || value == 0xDB || value == 0x42) {
|
|
|
|
//Break on BRK/STP/WDM
|
2019-03-01 20:27:49 -05:00
|
|
|
_cpuStepCount = 0;
|
2019-03-03 16:34:23 -05:00
|
|
|
}*/
|
2019-02-27 19:49:26 -05:00
|
|
|
} else if(type == MemoryOperationType::ExecOperand) {
|
|
|
|
if(addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) {
|
|
|
|
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) {
|
|
|
|
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)));
|
|
|
|
}
|
2019-02-12 22:13:09 -05:00
|
|
|
}
|
2019-03-01 20:27:49 -05:00
|
|
|
|
2019-03-28 17:47:43 -04:00
|
|
|
_memoryAccessCounter->ProcessMemoryAccess(addressInfo, type, _memoryManager->GetMasterClock());
|
|
|
|
|
2019-03-07 20:12:32 -05:00
|
|
|
if(_memoryManager->IsRegister(addr)) {
|
|
|
|
_eventManager->AddEvent(DebugEventType::Register, operation);
|
|
|
|
}
|
|
|
|
|
2019-03-01 20:27:49 -05:00
|
|
|
ProcessBreakConditions(operation, addressInfo);
|
2019-02-12 22:13:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::ProcessCpuWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
|
|
|
|
{
|
2019-02-27 19:49:26 -05:00
|
|
|
AddressInfo addressInfo = _memoryManager->GetAbsoluteAddress(addr);
|
2019-03-01 20:27:49 -05:00
|
|
|
MemoryOperationInfo operation = { addr, value, type };
|
2019-02-27 19:49:26 -05:00
|
|
|
if(addressInfo.Address >= 0 && (addressInfo.Type == SnesMemoryType::WorkRam || addressInfo.Type == SnesMemoryType::SaveRam)) {
|
|
|
|
_disassembler->InvalidateCache(addressInfo);
|
2019-02-12 22:13:09 -05:00
|
|
|
}
|
2019-03-01 20:27:49 -05:00
|
|
|
|
2019-03-07 20:12:32 -05:00
|
|
|
if(_memoryManager->IsRegister(addr)) {
|
|
|
|
_eventManager->AddEvent(DebugEventType::Register, operation);
|
|
|
|
}
|
|
|
|
|
2019-03-28 17:47:43 -04:00
|
|
|
_memoryAccessCounter->ProcessMemoryAccess(addressInfo, type, _memoryManager->GetMasterClock());
|
|
|
|
|
2019-03-01 20:27:49 -05:00
|
|
|
ProcessBreakConditions(operation, addressInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::ProcessWorkRamRead(uint32_t addr, uint8_t value)
|
|
|
|
{
|
|
|
|
AddressInfo addressInfo(addr, SnesMemoryType::WorkRam);
|
|
|
|
//TODO Make this more flexible/accurate
|
|
|
|
MemoryOperationInfo operation(0x7E0000 | addr, value, MemoryOperationType::Read);
|
|
|
|
ProcessBreakConditions(operation, addressInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::ProcessWorkRamWrite(uint32_t addr, uint8_t value)
|
|
|
|
{
|
|
|
|
AddressInfo addressInfo(addr, SnesMemoryType::WorkRam);
|
|
|
|
//TODO Make this more flexible/accurate
|
|
|
|
MemoryOperationInfo operation(0x7E0000 | addr, value, MemoryOperationType::Write);
|
|
|
|
ProcessBreakConditions(operation, addressInfo);
|
|
|
|
}
|
|
|
|
|
2019-03-28 17:47:43 -04:00
|
|
|
void Debugger::ProcessSpcRead(uint16_t addr, uint8_t value, MemoryOperationType type)
|
|
|
|
{
|
2019-04-07 14:38:22 -04:00
|
|
|
if(type == MemoryOperationType::DummyRead) {
|
|
|
|
//Ignore all dummy reads for now
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-04-06 17:38:14 -04:00
|
|
|
AddressInfo addressInfo = _spc->GetAbsoluteAddress(addr);
|
2019-03-28 17:47:43 -04:00
|
|
|
MemoryOperationInfo operation(addr, value, type);
|
2019-04-06 17:38:14 -04:00
|
|
|
|
|
|
|
if(type == MemoryOperationType::ExecOpCode) {
|
|
|
|
_disassembler->BuildCache(addressInfo, 0, CpuType::Spc);
|
|
|
|
|
|
|
|
DebugState debugState;
|
|
|
|
GetState(debugState);
|
|
|
|
|
|
|
|
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo);
|
|
|
|
_traceLogger->Log(debugState, disInfo);
|
2019-04-07 12:25:14 -04:00
|
|
|
|
|
|
|
if(_spcPrevOpCode == 0x3F || _spcPrevOpCode == 0x0F) {
|
|
|
|
//JSR, BRK
|
|
|
|
uint8_t opSize = DisassemblyInfo::GetOpSize(_spcPrevOpCode, 0, CpuType::Spc);
|
|
|
|
uint16_t returnPc = _spcPrevProgramCounter + opSize;
|
|
|
|
_spcCallstackManager->Push(_spcPrevProgramCounter, debugState.Spc.PC, returnPc, StackFrameFlags::None);
|
|
|
|
} else if(_spcPrevOpCode == 0x6F || _spcPrevOpCode == 0x7F) {
|
|
|
|
//RTS, RTI
|
|
|
|
_spcCallstackManager->Pop(debugState.Spc.PC);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(_spcBreakAddress == (int32_t)debugState.Spc.PC && (_spcPrevOpCode == 0x6F || _spcPrevOpCode == 0x7F)) {
|
|
|
|
//RTS/RTI found, if we're on the expected return address, break immediately (for step over/step out)
|
|
|
|
_cpuStepCount = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_spcPrevOpCode = value;
|
|
|
|
_spcPrevProgramCounter = debugState.Spc.PC;
|
|
|
|
|
|
|
|
if(_spcStepCount > 0) {
|
|
|
|
_spcStepCount--;
|
|
|
|
if(_spcStepCount == 0) {
|
|
|
|
_spcStepCount = -1;
|
|
|
|
_cpuStepCount = 0;
|
|
|
|
}
|
|
|
|
}
|
2019-04-06 17:38:14 -04:00
|
|
|
}
|
|
|
|
|
2019-03-28 17:47:43 -04:00
|
|
|
ProcessBreakConditions(operation, addressInfo);
|
|
|
|
|
|
|
|
_memoryAccessCounter->ProcessMemoryAccess(addressInfo, type, _memoryManager->GetMasterClock());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::ProcessSpcWrite(uint16_t addr, uint8_t value, MemoryOperationType type)
|
|
|
|
{
|
2019-04-06 17:38:14 -04:00
|
|
|
AddressInfo addressInfo(addr, SnesMemoryType::SpcRam); //Writes never affect the SPC ROM
|
2019-03-28 17:47:43 -04:00
|
|
|
MemoryOperationInfo operation(addr, value, type);
|
|
|
|
ProcessBreakConditions(operation, addressInfo);
|
|
|
|
|
|
|
|
_memoryAccessCounter->ProcessMemoryAccess(addressInfo, type, _memoryManager->GetMasterClock());
|
|
|
|
}
|
|
|
|
|
2019-03-01 20:27:49 -05:00
|
|
|
void Debugger::ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType)
|
|
|
|
{
|
|
|
|
AddressInfo addressInfo(addr, memoryType);
|
|
|
|
MemoryOperationInfo operation(addr, value, MemoryOperationType::Read);
|
|
|
|
ProcessBreakConditions(operation, addressInfo);
|
2019-03-28 17:47:43 -04:00
|
|
|
|
|
|
|
_memoryAccessCounter->ProcessMemoryAccess(addressInfo, MemoryOperationType::Read, _memoryManager->GetMasterClock());
|
2019-03-01 20:27:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType)
|
|
|
|
{
|
|
|
|
AddressInfo addressInfo(addr, memoryType);
|
|
|
|
MemoryOperationInfo operation(addr, value, MemoryOperationType::Write);
|
|
|
|
ProcessBreakConditions(operation, addressInfo);
|
2019-03-28 17:47:43 -04:00
|
|
|
|
|
|
|
_memoryAccessCounter->ProcessMemoryAccess(addressInfo, MemoryOperationType::Write, _memoryManager->GetMasterClock());
|
2019-03-01 20:27:49 -05:00
|
|
|
}
|
|
|
|
|
2019-03-03 16:34:23 -05:00
|
|
|
void Debugger::ProcessPpuCycle()
|
|
|
|
{
|
|
|
|
uint16_t scanline = _ppu->GetState().Scanline;
|
|
|
|
uint16_t cycle = _ppu->GetState().Cycle;
|
|
|
|
_ppuTools->UpdateViewers(scanline, cycle);
|
2019-03-24 16:42:52 -04:00
|
|
|
|
|
|
|
if(_ppuStepCount > 0) {
|
|
|
|
_ppuStepCount--;
|
|
|
|
if(_ppuStepCount == 0) {
|
|
|
|
_cpuStepCount = 0;
|
|
|
|
SleepUntilResume();
|
|
|
|
}
|
|
|
|
}
|
2019-03-30 22:58:57 -04:00
|
|
|
|
|
|
|
if(cycle == 0 && scanline == _breakScanline) {
|
|
|
|
_cpuStepCount = 0;
|
|
|
|
_breakScanline = -1;
|
|
|
|
SleepUntilResume();
|
|
|
|
}
|
2019-03-24 16:42:52 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::SleepUntilResume()
|
|
|
|
{
|
|
|
|
_console->GetSoundMixer()->StopAudio();
|
2019-04-07 12:25:14 -04:00
|
|
|
_disassembler->Disassemble(CpuType::Cpu);
|
|
|
|
_disassembler->Disassemble(CpuType::Spc);
|
2019-03-24 16:42:52 -04:00
|
|
|
|
|
|
|
_executionStopped = true;
|
2019-03-31 20:02:52 -04:00
|
|
|
|
|
|
|
if(_cpuStepCount == 0) {
|
|
|
|
//Only trigger code break event if the pause was caused by user action
|
|
|
|
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak);
|
|
|
|
}
|
|
|
|
|
2019-03-24 16:42:52 -04:00
|
|
|
while(_cpuStepCount == 0 || _breakRequestCount) {
|
|
|
|
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(10));
|
|
|
|
}
|
2019-03-31 20:02:52 -04:00
|
|
|
|
2019-03-24 16:42:52 -04:00
|
|
|
_executionStopped = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::ProcessStepConditions(uint8_t opCode, uint32_t currentPc)
|
|
|
|
{
|
2019-04-07 12:25:14 -04:00
|
|
|
if(_cpuBreakAddress == (int32_t)currentPc && (opCode == 0x60 || opCode == 0x40 || opCode == 0x6B || opCode == 0x44 || opCode == 0x54)) {
|
2019-03-24 16:42:52 -04:00
|
|
|
//RTS/RTL/RTI found, if we're on the expected return address, break immediately (for step over/step out)
|
|
|
|
_cpuStepCount = 0;
|
|
|
|
}
|
2019-03-03 16:34:23 -05:00
|
|
|
}
|
|
|
|
|
2019-03-01 20:27:49 -05:00
|
|
|
void Debugger::ProcessBreakConditions(MemoryOperationInfo &operation, AddressInfo &addressInfo)
|
|
|
|
{
|
|
|
|
if(_breakpointManager->CheckBreakpoint(operation, addressInfo)) {
|
|
|
|
_cpuStepCount = 0;
|
|
|
|
}
|
|
|
|
|
2019-03-07 20:12:32 -05:00
|
|
|
if(_cpuStepCount == 0 || _breakRequestCount) {
|
2019-03-24 16:42:52 -04:00
|
|
|
SleepUntilResume();
|
2019-03-07 20:12:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-24 16:42:52 -04:00
|
|
|
void Debugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi)
|
2019-03-24 12:05:51 -04:00
|
|
|
{
|
2019-03-24 16:42:52 -04:00
|
|
|
_callstackManager->Push(_prevProgramCounter, currentPc, originalPc, forNmi ? StackFrameFlags::Nmi : StackFrameFlags::Irq);
|
2019-03-24 12:05:51 -04:00
|
|
|
_eventManager->AddEvent(forNmi ? DebugEventType::Nmi : DebugEventType::Irq);
|
|
|
|
}
|
|
|
|
|
2019-03-07 20:12:32 -05:00
|
|
|
void Debugger::ProcessEvent(EventType type)
|
|
|
|
{
|
|
|
|
switch(type) {
|
2019-03-31 14:50:12 -04:00
|
|
|
default: break;
|
|
|
|
|
2019-03-07 20:28:48 -05:00
|
|
|
case EventType::StartFrame:
|
|
|
|
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh);
|
|
|
|
_eventManager->ClearFrameEvents();
|
|
|
|
break;
|
2019-03-01 20:27:49 -05:00
|
|
|
}
|
2019-02-12 22:13:09 -05:00
|
|
|
}
|
|
|
|
|
2019-04-07 14:38:22 -04:00
|
|
|
int32_t Debugger::EvaluateExpression(string expression, CpuType cpuType, EvalResultType &resultType, bool useCache)
|
2019-02-27 20:33:56 -05:00
|
|
|
{
|
2019-03-01 20:27:49 -05:00
|
|
|
MemoryOperationInfo operationInfo { 0, 0, MemoryOperationType::Read };
|
2019-02-27 20:33:56 -05:00
|
|
|
DebugState state;
|
2019-03-01 20:27:49 -05:00
|
|
|
GetState(state);
|
2019-02-27 20:33:56 -05:00
|
|
|
if(useCache) {
|
2019-04-07 14:38:22 -04:00
|
|
|
return _watchExpEval[(int)cpuType]->Evaluate(expression, state, resultType, operationInfo);
|
2019-02-27 20:33:56 -05:00
|
|
|
} else {
|
2019-04-07 14:38:22 -04:00
|
|
|
ExpressionEvaluator expEval(this, cpuType);
|
2019-02-27 20:33:56 -05:00
|
|
|
return expEval.Evaluate(expression, state, resultType, operationInfo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-12 22:13:09 -05:00
|
|
|
void Debugger::Run()
|
|
|
|
{
|
|
|
|
_cpuStepCount = -1;
|
2019-04-07 12:25:14 -04:00
|
|
|
_spcStepCount = -1;
|
2019-03-24 16:42:52 -04:00
|
|
|
_ppuStepCount = -1;
|
2019-04-07 12:25:14 -04:00
|
|
|
_cpuBreakAddress = -1;
|
|
|
|
_spcBreakAddress = -1;
|
2019-03-30 22:58:57 -04:00
|
|
|
_breakScanline = -1;
|
2019-02-12 22:13:09 -05:00
|
|
|
}
|
|
|
|
|
2019-03-24 16:42:52 -04:00
|
|
|
void Debugger::Step(int32_t stepCount, StepType type)
|
2019-02-12 22:13:09 -05:00
|
|
|
{
|
2019-03-24 16:42:52 -04:00
|
|
|
switch(type) {
|
|
|
|
case StepType::CpuStep:
|
|
|
|
_cpuStepCount = stepCount;
|
2019-04-07 12:25:14 -04:00
|
|
|
_cpuBreakAddress = -1;
|
|
|
|
_spcBreakAddress = -1;
|
|
|
|
_spcStepCount = -1;
|
2019-03-24 16:42:52 -04:00
|
|
|
_ppuStepCount = -1;
|
2019-03-30 22:58:57 -04:00
|
|
|
_breakScanline = -1;
|
2019-03-24 16:42:52 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case StepType::CpuStepOut:
|
2019-04-07 12:25:14 -04:00
|
|
|
_cpuBreakAddress = _callstackManager->GetReturnAddress();
|
2019-03-24 16:42:52 -04:00
|
|
|
_cpuStepCount = -1;
|
2019-04-07 12:25:14 -04:00
|
|
|
_spcStepCount = -1;
|
2019-03-24 16:42:52 -04:00
|
|
|
_ppuStepCount = -1;
|
2019-04-07 12:25:14 -04:00
|
|
|
_spcBreakAddress = -1;
|
2019-03-30 22:58:57 -04:00
|
|
|
_breakScanline = -1;
|
2019-03-24 16:42:52 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case StepType::CpuStepOver:
|
|
|
|
if(_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC || _prevOpCode == 0x00 || _prevOpCode == 0x02 || _prevOpCode == 0x44 || _prevOpCode == 0x54) {
|
|
|
|
//JSR, JSL, BRK, COP, MVP, MVN
|
2019-04-07 12:25:14 -04:00
|
|
|
_cpuBreakAddress = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Cpu)) & 0xFFFF);
|
2019-03-24 16:42:52 -04:00
|
|
|
_cpuStepCount = -1;
|
2019-04-07 12:25:14 -04:00
|
|
|
_spcStepCount = -1;
|
2019-03-24 16:42:52 -04:00
|
|
|
_ppuStepCount = -1;
|
2019-04-07 12:25:14 -04:00
|
|
|
_spcBreakAddress = -1;
|
2019-03-30 22:58:57 -04:00
|
|
|
_breakScanline = -1;
|
2019-03-24 16:42:52 -04:00
|
|
|
} else {
|
|
|
|
//For any other instruction, step over is the same as step into
|
|
|
|
_cpuStepCount = 1;
|
2019-04-07 12:25:14 -04:00
|
|
|
_spcStepCount = -1;
|
|
|
|
_cpuBreakAddress = -1;
|
|
|
|
_spcBreakAddress = -1;
|
|
|
|
_ppuStepCount = -1;
|
|
|
|
_breakScanline = -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case StepType::SpcStep:
|
|
|
|
_spcStepCount = stepCount;
|
|
|
|
_cpuStepCount = -1;
|
|
|
|
_cpuBreakAddress = -1;
|
|
|
|
_spcBreakAddress = -1;
|
|
|
|
_ppuStepCount = -1;
|
|
|
|
_breakScanline = -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case StepType::SpcStepOut:
|
|
|
|
_spcBreakAddress = _spcCallstackManager->GetReturnAddress();
|
|
|
|
_spcStepCount = -1;
|
|
|
|
_cpuBreakAddress = -1;
|
|
|
|
_cpuStepCount = -1;
|
|
|
|
_ppuStepCount = -1;
|
|
|
|
_breakScanline = -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case StepType::SpcStepOver:
|
|
|
|
if(_spcPrevOpCode == 0x3F || _spcPrevOpCode == 0x0F) {
|
|
|
|
//JSR, BRK
|
|
|
|
_spcBreakAddress = _spcPrevProgramCounter + DisassemblyInfo::GetOpSize(_spcPrevOpCode, 0, CpuType::Spc);
|
|
|
|
_cpuStepCount = -1;
|
|
|
|
_spcStepCount = -1;
|
|
|
|
_ppuStepCount = -1;
|
|
|
|
_cpuBreakAddress = -1;
|
|
|
|
_breakScanline = -1;
|
|
|
|
} else {
|
|
|
|
//For any other instruction, step over is the same as step into
|
|
|
|
_spcStepCount = 1;
|
|
|
|
_cpuStepCount = -1;
|
|
|
|
_cpuBreakAddress = -1;
|
|
|
|
_spcBreakAddress = -1;
|
2019-03-24 16:42:52 -04:00
|
|
|
_ppuStepCount = -1;
|
2019-03-30 22:58:57 -04:00
|
|
|
_breakScanline = -1;
|
2019-03-24 16:42:52 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case StepType::PpuStep:
|
|
|
|
_ppuStepCount = stepCount;
|
|
|
|
_cpuStepCount = -1;
|
2019-04-07 12:25:14 -04:00
|
|
|
_spcStepCount = -1;
|
|
|
|
_cpuBreakAddress = -1;
|
|
|
|
_spcBreakAddress = -1;
|
2019-03-30 22:58:57 -04:00
|
|
|
_breakScanline = -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case StepType::SpecificScanline:
|
|
|
|
_breakScanline = stepCount;
|
|
|
|
_ppuStepCount = -1;
|
|
|
|
_cpuStepCount = -1;
|
2019-04-07 12:25:14 -04:00
|
|
|
_spcStepCount = -1;
|
|
|
|
_cpuBreakAddress = -1;
|
|
|
|
_spcBreakAddress = -1;
|
2019-03-24 16:42:52 -04:00
|
|
|
break;
|
|
|
|
}
|
2019-02-12 22:13:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Debugger::IsExecutionStopped()
|
|
|
|
{
|
2019-03-07 20:12:32 -05:00
|
|
|
return _executionStopped;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::BreakRequest(bool release)
|
|
|
|
{
|
|
|
|
if(release) {
|
|
|
|
_breakRequestCount--;
|
|
|
|
} else {
|
|
|
|
_breakRequestCount++;
|
|
|
|
}
|
2019-02-12 22:13:09 -05:00
|
|
|
}
|
|
|
|
|
2019-03-01 20:27:49 -05:00
|
|
|
void Debugger::GetState(DebugState &state)
|
2019-02-13 13:32:21 -05:00
|
|
|
{
|
2019-03-28 17:47:43 -04:00
|
|
|
state.MasterClock = _memoryManager->GetMasterClock();
|
2019-03-01 20:27:49 -05:00
|
|
|
state.Cpu = _cpu->GetState();
|
|
|
|
state.Ppu = _ppu->GetState();
|
2019-04-06 17:38:14 -04:00
|
|
|
state.Spc = _spc->GetState();
|
2019-02-13 13:32:21 -05:00
|
|
|
}
|
|
|
|
|
2019-02-12 22:13:09 -05:00
|
|
|
shared_ptr<TraceLogger> Debugger::GetTraceLogger()
|
|
|
|
{
|
|
|
|
return _traceLogger;
|
2019-02-15 21:33:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
shared_ptr<MemoryDumper> Debugger::GetMemoryDumper()
|
|
|
|
{
|
|
|
|
return _memoryDumper;
|
|
|
|
}
|
2019-02-27 19:49:26 -05:00
|
|
|
|
2019-03-28 17:47:43 -04:00
|
|
|
shared_ptr<MemoryAccessCounter> Debugger::GetMemoryAccessCounter()
|
|
|
|
{
|
|
|
|
return _memoryAccessCounter;
|
|
|
|
}
|
|
|
|
|
|
|
|
shared_ptr<CodeDataLogger> Debugger::GetCodeDataLogger()
|
|
|
|
{
|
|
|
|
return _codeDataLogger;
|
|
|
|
}
|
|
|
|
|
2019-02-27 19:49:26 -05:00
|
|
|
shared_ptr<Disassembler> Debugger::GetDisassembler()
|
|
|
|
{
|
|
|
|
return _disassembler;
|
|
|
|
}
|
2019-03-01 20:27:49 -05:00
|
|
|
|
|
|
|
shared_ptr<BreakpointManager> Debugger::GetBreakpointManager()
|
|
|
|
{
|
|
|
|
return _breakpointManager;
|
|
|
|
}
|
2019-03-03 16:34:23 -05:00
|
|
|
|
|
|
|
shared_ptr<PpuTools> Debugger::GetPpuTools()
|
|
|
|
{
|
|
|
|
return _ppuTools;
|
|
|
|
}
|
2019-03-07 20:12:32 -05:00
|
|
|
|
|
|
|
shared_ptr<EventManager> Debugger::GetEventManager()
|
|
|
|
{
|
|
|
|
return _eventManager;
|
|
|
|
}
|
|
|
|
|
2019-04-07 12:25:14 -04:00
|
|
|
shared_ptr<CallstackManager> Debugger::GetCallstackManager(CpuType cpuType)
|
2019-03-24 12:05:51 -04:00
|
|
|
{
|
2019-04-07 12:25:14 -04:00
|
|
|
return cpuType == CpuType::Cpu ? _callstackManager : _spcCallstackManager;
|
2019-03-24 12:05:51 -04:00
|
|
|
}
|
|
|
|
|
2019-03-07 20:12:32 -05:00
|
|
|
shared_ptr<Console> Debugger::GetConsole()
|
|
|
|
{
|
|
|
|
return _console;
|
|
|
|
}
|