Debugger: Added option to evaluate all breakpoints on the first cycle of an instruction
This commit is contained in:
parent
35192daeed
commit
937a90626d
16 changed files with 378 additions and 79 deletions
43
Core/CPU.cpp
43
Core/CPU.cpp
|
@ -10,6 +10,7 @@
|
|||
CPU::CPU(shared_ptr<Console> console)
|
||||
{
|
||||
_console = console;
|
||||
_memoryManager = _console->GetMemoryManager();
|
||||
|
||||
Func opTable[] = {
|
||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
|
@ -64,7 +65,7 @@ CPU::CPU(shared_ptr<Console> console)
|
|||
_dmcCounter = 0;
|
||||
_dmcDmaRunning = false;
|
||||
_cpuWrite = false;
|
||||
_writeAddr = false;
|
||||
_writeAddr = 0;
|
||||
_irqMask = 0;
|
||||
_state = {};
|
||||
_prevRunIrq = false;
|
||||
|
@ -73,7 +74,6 @@ CPU::CPU(shared_ptr<Console> console)
|
|||
|
||||
void CPU::Reset(bool softReset, NesModel model)
|
||||
{
|
||||
_memoryManager = _console->GetMemoryManager();
|
||||
_state.NMIFlag = false;
|
||||
_state.IRQFlag = 0;
|
||||
_cycleCount = -1;
|
||||
|
@ -140,15 +140,19 @@ void CPU::IRQ()
|
|||
SetPC(MemoryReadWord(CPU::NMIVector));
|
||||
_state.NMIFlag = false;
|
||||
|
||||
#ifndef DUMMYCPU
|
||||
_console->DebugAddTrace("NMI");
|
||||
_console->DebugProcessInterrupt(originalPc, _state.PC, true);
|
||||
#endif
|
||||
} else {
|
||||
Push((uint8_t)(PS() | PSFlags::Reserved));
|
||||
SetFlags(PSFlags::Interrupt);
|
||||
SetPC(MemoryReadWord(CPU::IRQVector));
|
||||
|
||||
#ifndef DUMMYCPU
|
||||
_console->DebugAddTrace("IRQ");
|
||||
_console->DebugProcessInterrupt(originalPc, _state.PC, false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,14 +166,18 @@ void CPU::BRK() {
|
|||
|
||||
SetPC(MemoryReadWord(CPU::NMIVector));
|
||||
|
||||
#ifndef DUMMYCPU
|
||||
_console->DebugAddTrace("NMI");
|
||||
#endif
|
||||
} else {
|
||||
Push((uint8_t)flags);
|
||||
SetFlags(PSFlags::Interrupt);
|
||||
|
||||
SetPC(MemoryReadWord(CPU::IRQVector));
|
||||
|
||||
#ifndef DUMMYCPU
|
||||
_console->DebugAddTrace("IRQ");
|
||||
#endif
|
||||
}
|
||||
|
||||
//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)
|
||||
|
@ -184,7 +192,17 @@ void CPU::MemoryWrite(uint16_t addr, uint8_t value, MemoryOperationType operatio
|
|||
while(_dmcDmaRunning) {
|
||||
IncCycleCount();
|
||||
}
|
||||
|
||||
#ifdef DUMMYCPU
|
||||
if(operationType == MemoryOperationType::Write || operationType == MemoryOperationType::DummyWrite) {
|
||||
_writeAddresses[_writeCounter] = addr;
|
||||
_isDummyWrite[_writeCounter] = operationType == MemoryOperationType::DummyWrite;
|
||||
_writeValue[_writeCounter] = value;
|
||||
_writeCounter++;
|
||||
}
|
||||
#else
|
||||
_memoryManager->Write(addr, value, operationType);
|
||||
#endif
|
||||
|
||||
//DMA DMC might have started after a write to $4015, stall CPU if needed
|
||||
while(_dmcDmaRunning) {
|
||||
|
@ -202,16 +220,31 @@ uint8_t CPU::MemoryRead(uint16_t addr, MemoryOperationType operationType) {
|
|||
//Reads are only performed every other cycle? This fixes "dma_2007_read" test
|
||||
//This behavior causes the $4016/7 data corruption when a DMC is running.
|
||||
//When reading $4016/7, only the last read counts (because this only occurs to low-to-high transitions, i.e once in this case)
|
||||
#ifdef DUMMYCPU
|
||||
_memoryManager->DebugRead(addr);
|
||||
#else
|
||||
_memoryManager->Read(addr);
|
||||
#endif
|
||||
}
|
||||
IncCycleCount();
|
||||
}
|
||||
|
||||
#ifdef DUMMYCPU
|
||||
if(operationType == MemoryOperationType::Read || operationType == MemoryOperationType::DummyRead) {
|
||||
_readAddresses[_readCounter] = addr;
|
||||
_isDummyRead[_readCounter] = operationType == MemoryOperationType::DummyRead;
|
||||
_readCounter++;
|
||||
}
|
||||
|
||||
return _memoryManager->DebugRead(addr);
|
||||
#else
|
||||
if(operationType == MemoryOperationType::ExecOpCode) {
|
||||
_state.DebugPC = _state.PC;
|
||||
}
|
||||
|
||||
uint8_t value = _memoryManager->Read(addr, operationType);
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t CPU::FetchOperand()
|
||||
|
@ -236,7 +269,7 @@ uint16_t CPU::FetchOperand()
|
|||
default: break;
|
||||
}
|
||||
|
||||
#ifndef LIBRETRO
|
||||
#if !defined(LIBRETRO) && !defined(DUMMYCPU)
|
||||
if(_warnOnCrash && _console->GetSettings()->CheckFlag(EmulationFlags::DeveloperMode)) {
|
||||
MessageManager::DisplayMessage("Error", "GameCrash", "Invalid OP code - CPU crashed.");
|
||||
_warnOnCrash = false;
|
||||
|
@ -270,12 +303,16 @@ void CPU::IncCycleCount()
|
|||
if(_dmcCounter == 0) {
|
||||
//Update the DMC buffer when the stall period is completed
|
||||
_dmcDmaRunning = false;
|
||||
#ifndef DUMMYCPU
|
||||
_console->GetApu()->FillDmcReadBuffer();
|
||||
_console->DebugAddTrace("DMC DMA End");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DUMMYCPU
|
||||
_console->ProcessCpuClock();
|
||||
#endif
|
||||
|
||||
if(!_spriteDmaTransfer && !_dmcDmaRunning) {
|
||||
//IRQ flags are ignored during Sprite DMA - fixes irq_and_dma
|
||||
|
|
85
Core/CPU.h
85
Core/CPU.h
|
@ -1,4 +1,9 @@
|
|||
#pragma once
|
||||
#if (defined(DUMMYCPU) && !defined(__DUMMYCPU__H)) || (!defined(DUMMYCPU) && !defined(__CPU__H))
|
||||
#ifdef DUMMYCPU
|
||||
#define __DUMMYCPU__H
|
||||
#else
|
||||
#define __CPU__H
|
||||
#endif
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Snapshotable.h"
|
||||
|
@ -7,24 +12,12 @@
|
|||
enum class NesModel;
|
||||
class Console;
|
||||
class MemoryManager;
|
||||
|
||||
namespace PSFlags
|
||||
{
|
||||
enum PSFlags : uint8_t
|
||||
{
|
||||
Carry = 0x01,
|
||||
Zero = 0x02,
|
||||
Interrupt = 0x04,
|
||||
Decimal = 0x08,
|
||||
Break = 0x10,
|
||||
Reserved = 0x20,
|
||||
Overflow = 0x40,
|
||||
Negative = 0x80
|
||||
};
|
||||
}
|
||||
class DummyCpu;
|
||||
|
||||
class CPU : public Snapshotable
|
||||
{
|
||||
friend DummyCpu;
|
||||
|
||||
public:
|
||||
static constexpr uint16_t NMIVector = 0xFFFA;
|
||||
static constexpr uint16_t ResetVector = 0xFFFC;
|
||||
|
@ -62,6 +55,17 @@ private:
|
|||
|
||||
bool _warnOnCrash = true;
|
||||
|
||||
#ifdef DUMMYCPU
|
||||
uint32_t _writeCounter = 0;
|
||||
uint16_t _writeAddresses[10];
|
||||
uint8_t _writeValue[10];
|
||||
bool _isDummyWrite[10];
|
||||
|
||||
uint32_t _readCounter = 0;
|
||||
uint16_t _readAddresses[10];
|
||||
bool _isDummyRead[10];
|
||||
#endif
|
||||
|
||||
void IncCycleCount();
|
||||
uint16_t FetchOperand();
|
||||
void IRQ();
|
||||
|
@ -818,4 +822,53 @@ public:
|
|||
state.PC = originalPc;
|
||||
state.DebugPC = originalDebugPc;
|
||||
}
|
||||
|
||||
#ifdef DUMMYCPU
|
||||
#undef CPU
|
||||
void SetDummyState(CPU *c)
|
||||
{
|
||||
#define CPU DummyCpu
|
||||
_writeCounter = 0;
|
||||
_readCounter = 0;
|
||||
|
||||
_state = c->_state;
|
||||
|
||||
_cycleCount = c->_cycleCount;
|
||||
_operand = c->_operand;
|
||||
_spriteDmaCounter = c->_spriteDmaCounter;
|
||||
_spriteDmaTransfer = c->_spriteDmaTransfer;
|
||||
_dmcCounter = c->_dmcCounter;
|
||||
_dmcDmaRunning = c->_dmcDmaRunning;
|
||||
_cpuWrite = c->_cpuWrite;
|
||||
_irqMask = c->_irqMask;
|
||||
_prevRunIrq = c->_prevRunIrq;
|
||||
_runIrq = c->_runIrq;
|
||||
_cycleCount = c->_cycleCount;
|
||||
}
|
||||
|
||||
uint32_t GetWriteCount()
|
||||
{
|
||||
return _writeCounter;
|
||||
}
|
||||
|
||||
uint32_t GetReadCount()
|
||||
{
|
||||
return _readCounter;
|
||||
}
|
||||
|
||||
void GetWriteAddrValue(uint32_t index, uint16_t &addr, uint8_t &value, bool &isDummyWrite)
|
||||
{
|
||||
addr = _writeAddresses[index];
|
||||
value = _writeValue[index];
|
||||
isDummyWrite = _isDummyWrite[index];
|
||||
}
|
||||
|
||||
void GetReadAddr(uint32_t index, uint16_t &addr, bool &isDummyRead)
|
||||
{
|
||||
addr = _readAddresses[index];
|
||||
isDummyRead = _isDummyRead[index];
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
|
@ -533,6 +533,7 @@
|
|||
<ClInclude Include="Dance2000.h" />
|
||||
<ClInclude Include="DragonFighter.h" />
|
||||
<ClInclude Include="DrawScreenBufferCommand.h" />
|
||||
<ClInclude Include="DummyCpu.h" />
|
||||
<ClInclude Include="FaridSlrom.h" />
|
||||
<ClInclude Include="FaridUnrom.h" />
|
||||
<ClInclude Include="FdsSystemActionManager.h" />
|
||||
|
|
|
@ -1471,6 +1471,9 @@
|
|||
<ClInclude Include="ConsolePauseHelper.h">
|
||||
<Filter>Misc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DummyCpu.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "CodeDataLogger.h"
|
||||
#include "NotificationManager.h"
|
||||
#include "DebugHud.h"
|
||||
#include "DummyCpu.h"
|
||||
|
||||
const int Debugger::BreakpointTypeCount;
|
||||
string Debugger::_disassemblerOutput = "";
|
||||
|
@ -42,6 +43,9 @@ Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<
|
|||
_memoryManager = memoryManager;
|
||||
_mapper = mapper;
|
||||
|
||||
_dummyCpu.reset(new DummyCpu(console));
|
||||
_breakOnFirstCycle = false;
|
||||
|
||||
_labelManager.reset(new LabelManager(_mapper));
|
||||
_assembler.reset(new Assembler(_labelManager));
|
||||
_disassembler.reset(new Disassembler(memoryManager.get(), mapper.get(), this));
|
||||
|
@ -177,6 +181,7 @@ void Debugger::SetFlags(uint32_t flags)
|
|||
{
|
||||
bool needUpdate = ((flags ^ _flags) & (int)DebuggerFlags::DisplayOpCodesInLowerCase) != 0;
|
||||
_flags = flags;
|
||||
_breakOnFirstCycle = CheckFlag(DebuggerFlags::BreakOnFirstCycle);
|
||||
if(needUpdate) {
|
||||
_disassembler->BuildOpCodeTables(CheckFlag(DebuggerFlags::DisplayOpCodesInLowerCase));
|
||||
}
|
||||
|
@ -298,11 +303,11 @@ void Debugger::SetBreakpoints(Breakpoint breakpoints[], uint32_t length)
|
|||
}
|
||||
}
|
||||
|
||||
void Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationInfo, bool allowBreak)
|
||||
bool Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationInfo, bool allowBreak, bool allowMark)
|
||||
{
|
||||
if(_runToCycle != 0) {
|
||||
//Disable all breakpoints while stepping backwards
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
AddressTypeInfo info { -1, AddressType::InternalRam };
|
||||
|
@ -347,6 +352,11 @@ void Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationI
|
|||
|
||||
for(size_t i = 0, len = breakpoints.size(); i < len; i++) {
|
||||
Breakpoint &breakpoint = breakpoints[i];
|
||||
if(!((breakpoint.IsEnabled() && allowBreak) || (breakpoint.IsMarked() && allowMark))) {
|
||||
//Skip breakpoints we don't need to process
|
||||
continue;
|
||||
}
|
||||
|
||||
if(
|
||||
type == BreakpointType::Global ||
|
||||
(!isPpuBreakpoint && breakpoint.Matches(operationInfo.Address, info, operationInfo.OperationType)) ||
|
||||
|
@ -365,20 +375,117 @@ void Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationI
|
|||
}
|
||||
}
|
||||
|
||||
if(needMark && needBreak) {
|
||||
if((needMark || !allowMark) && (needBreak || !allowBreak)) {
|
||||
//No need to process remaining breakpoints
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(needMark) {
|
||||
if(needMark && allowMark) {
|
||||
AddDebugEvent(DebugEventType::Breakpoint, operationInfo.Address, (uint8_t)operationInfo.Value, markBreakpointId);
|
||||
}
|
||||
|
||||
if(needBreak && allowBreak) {
|
||||
//Found a matching breakpoint, stop execution
|
||||
Step(1);
|
||||
SleepUntilResume(BreakSource::Breakpoint, breakpointId, type, operationInfo.Address);
|
||||
SleepUntilResume(BreakSource::Breakpoint, breakpointId, type, operationInfo.Address, operationInfo.OperationType);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::ProcessAllBreakpoints(OperationInfo &operationInfo, AddressTypeInfo &addressInfo)
|
||||
{
|
||||
if(_hasBreakpoint[BreakpointType::Execute]) {
|
||||
ProcessBreakpoints(BreakpointType::Execute, operationInfo, true, true);
|
||||
}
|
||||
|
||||
_dummyCpu->SetDummyState(_cpu.get());
|
||||
_dummyCpu->Exec();
|
||||
|
||||
DebugState &state = _debugState;
|
||||
uint32_t readCount = _dummyCpu->GetReadCount();
|
||||
if(readCount > 0) {
|
||||
uint16_t addr;
|
||||
bool isDummyRead;
|
||||
for(uint32_t i = 0; i < readCount; i++) {
|
||||
_dummyCpu->GetReadAddr(i, addr, isDummyRead);
|
||||
|
||||
OperationInfo info;
|
||||
|
||||
if(addr >= 0x2000 && addr < 0x4000 && (addr & 0x07) == 0x07) {
|
||||
//Reads to $2007 will trigger a PPU read
|
||||
if(_hasBreakpoint[BreakpointType::ReadVram]) {
|
||||
OperationInfo ppuInfo;
|
||||
ppuInfo.OperationType = MemoryOperationType::Read;
|
||||
if((state.PPU.State.VideoRamAddr & 0x3FFF) >= 0x3F00) {
|
||||
ppuInfo.Address = state.PPU.State.VideoRamAddr;
|
||||
ppuInfo.Value = _ppu->ReadPaletteRAM(ppuInfo.Address);
|
||||
} else {
|
||||
ppuInfo.Address = state.PPU.BusAddress;
|
||||
ppuInfo.Value = _mapper->DebugReadVRAM(ppuInfo.Address);
|
||||
}
|
||||
if(ProcessBreakpoints(BreakpointType::ReadVram, ppuInfo, true, false)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
info.Value = state.PPU.MemoryReadBuffer;
|
||||
} else {
|
||||
if(_enableBreakOnUninitRead && CheckFlag(DebuggerFlags::BreakOnUninitMemoryRead)) {
|
||||
//Break on uninit memory read
|
||||
if(_memoryAccessCounter->IsAddressUninitialized(addressInfo)) {
|
||||
Step(1);
|
||||
SleepUntilResume(BreakSource::BreakOnUninitMemoryRead, 0, BreakpointType::ReadRam, addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
info.Value = _memoryManager->DebugRead(addr);
|
||||
}
|
||||
|
||||
if(_hasBreakpoint[BreakpointType::ReadRam]) {
|
||||
info.Address = addr;
|
||||
info.OperationType = isDummyRead ? MemoryOperationType::DummyRead : MemoryOperationType::Read;
|
||||
if(ProcessBreakpoints(BreakpointType::ReadRam, info, true, false)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t writeCount = _dummyCpu->GetWriteCount();
|
||||
if(writeCount > 0 && (_hasBreakpoint[BreakpointType::WriteRam] || _hasBreakpoint[BreakpointType::WriteVram])) {
|
||||
uint16_t addr;
|
||||
uint8_t value;
|
||||
bool isDummyWrite;
|
||||
for(uint32_t i = 0; i < writeCount; i++) {
|
||||
_dummyCpu->GetWriteAddrValue(i, addr, value, isDummyWrite);
|
||||
|
||||
if(_hasBreakpoint[BreakpointType::WriteRam]) {
|
||||
OperationInfo info;
|
||||
info.Address = addr;
|
||||
info.Value = value;
|
||||
info.OperationType = isDummyWrite ? MemoryOperationType::DummyWrite : MemoryOperationType::Write;
|
||||
if(ProcessBreakpoints(BreakpointType::WriteRam, info, true, false)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(_hasBreakpoint[BreakpointType::WriteVram]) {
|
||||
if(addr >= 0x2000 && addr < 0x4000 && (addr & 0x07) == 0x07) {
|
||||
//Write to $2007 will trigger a PPU write
|
||||
OperationInfo ppuInfo;
|
||||
ppuInfo.Address = state.PPU.BusAddress;
|
||||
ppuInfo.Value = value;
|
||||
ppuInfo.OperationType = MemoryOperationType::Write;
|
||||
if(ProcessBreakpoints(BreakpointType::WriteVram, ppuInfo, true, false)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -592,7 +699,7 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin
|
|||
}
|
||||
} else {
|
||||
if(_memoryAccessCounter->ProcessMemoryAccess(addressInfo, type, _cpu->GetCycleCount())) {
|
||||
if(_enableBreakOnUninitRead && CheckFlag(DebuggerFlags::BreakOnUninitMemoryRead)) {
|
||||
if(!_breakOnFirstCycle && _enableBreakOnUninitRead && CheckFlag(DebuggerFlags::BreakOnUninitMemoryRead)) {
|
||||
//Break on uninit memory read
|
||||
Step(1);
|
||||
breakDone = SleepUntilResume(BreakSource::BreakOnUninitMemoryRead);
|
||||
|
@ -691,8 +798,17 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin
|
|||
case MemoryOperationType::Write: breakpointType = BreakpointType::WriteRam; break;
|
||||
}
|
||||
|
||||
if(_breakOnFirstCycle) {
|
||||
if(type == MemoryOperationType::ExecOpCode && !breakDone) {
|
||||
ProcessAllBreakpoints(operationInfo, addressInfo);
|
||||
}
|
||||
|
||||
//Process marked breakpoints
|
||||
ProcessBreakpoints(breakpointType, operationInfo, false, true);
|
||||
} else {
|
||||
if(_hasBreakpoint[breakpointType]) {
|
||||
ProcessBreakpoints(breakpointType, operationInfo, !breakDone);
|
||||
ProcessBreakpoints(breakpointType, operationInfo, !breakDone, true);
|
||||
}
|
||||
}
|
||||
|
||||
_currentReadAddr = nullptr;
|
||||
|
@ -726,7 +842,7 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::SleepUntilResume(BreakSource source, uint32_t breakpointId, BreakpointType bpType, uint16_t bpAddress)
|
||||
bool Debugger::SleepUntilResume(BreakSource source, uint32_t breakpointId, BreakpointType bpType, uint16_t bpAddress, MemoryOperationType bpMemOpType)
|
||||
{
|
||||
int32_t stepCount = _stepCount.load();
|
||||
if(stepCount > 0) {
|
||||
|
@ -753,7 +869,14 @@ bool Debugger::SleepUntilResume(BreakSource source, uint32_t breakpointId, Break
|
|||
}
|
||||
_breakSource = BreakSource::Unspecified;
|
||||
|
||||
uint64_t param = ((uint64_t)breakpointId << 32) | ((uint64_t)(bpAddress & 0xFFFF) << 16) | ((uint64_t)(bpType & 0xFF) << 8) | ((uint64_t)source & 0xFF);
|
||||
uint64_t param = (
|
||||
((uint64_t)breakpointId << 32) |
|
||||
((uint64_t)(bpAddress & 0xFFFF) << 16) |
|
||||
((uint64_t)((int)bpMemOpType & 0x0F) << 12) |
|
||||
((uint64_t)(bpType & 0x0F) << 8) |
|
||||
((uint64_t)source & 0xFF)
|
||||
);
|
||||
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak, (void*)(uint64_t)param);
|
||||
|
||||
ProcessEvent(EventType::CodeBreak);
|
||||
|
@ -784,7 +907,7 @@ void Debugger::ProcessVramReadOperation(MemoryOperationType type, uint16_t addr,
|
|||
int32_t absoluteAddr = _mapper->ToAbsoluteChrAddress(addr);
|
||||
_codeDataLogger->SetFlag(absoluteAddr, type == MemoryOperationType::Read ? CdlChrFlags::Read : CdlChrFlags::Drawn);
|
||||
|
||||
if(_hasBreakpoint[BreakpointType::ReadVram]) {
|
||||
if(!_breakOnFirstCycle && _hasBreakpoint[BreakpointType::ReadVram]) {
|
||||
OperationInfo operationInfo{ addr, value, type };
|
||||
ProcessBreakpoints(BreakpointType::ReadVram, operationInfo);
|
||||
}
|
||||
|
@ -794,7 +917,7 @@ void Debugger::ProcessVramReadOperation(MemoryOperationType type, uint16_t addr,
|
|||
|
||||
void Debugger::ProcessVramWriteOperation(uint16_t addr, uint8_t &value)
|
||||
{
|
||||
if(_hasBreakpoint[BreakpointType::WriteVram]) {
|
||||
if(!_breakOnFirstCycle && _hasBreakpoint[BreakpointType::WriteVram]) {
|
||||
OperationInfo operationInfo{ addr, value, MemoryOperationType::Write };
|
||||
ProcessBreakpoints(BreakpointType::WriteVram, operationInfo);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ class TraceLogger;
|
|||
class Breakpoint;
|
||||
class CodeDataLogger;
|
||||
class ExpressionEvaluator;
|
||||
class DummyCpu;
|
||||
struct ExpressionData;
|
||||
|
||||
enum EvalResultType : int32_t;
|
||||
|
@ -59,6 +60,9 @@ private:
|
|||
shared_ptr<MemoryManager> _memoryManager;
|
||||
shared_ptr<BaseMapper> _mapper;
|
||||
|
||||
shared_ptr<DummyCpu> _dummyCpu;
|
||||
bool _breakOnFirstCycle;
|
||||
|
||||
bool _hasScript;
|
||||
SimpleLock _scriptLock;
|
||||
int _nextScriptId;
|
||||
|
@ -138,13 +142,14 @@ private:
|
|||
vector<vector<int>> _debugEventMarkerRpn;
|
||||
|
||||
private:
|
||||
void ProcessBreakpoints(BreakpointType type, OperationInfo &operationInfo, bool allowBreak = true);
|
||||
bool ProcessBreakpoints(BreakpointType type, OperationInfo &operationInfo, bool allowBreak = true, bool allowMark = true);
|
||||
void ProcessAllBreakpoints(OperationInfo &operationInfo, AddressTypeInfo &addressInfo);
|
||||
|
||||
void AddCallstackFrame(uint16_t source, uint16_t target, StackFrameFlags flags);
|
||||
void UpdateCallstack(uint8_t currentInstruction, uint32_t addr);
|
||||
|
||||
void ProcessStepConditions(uint16_t addr);
|
||||
bool SleepUntilResume(BreakSource source, uint32_t breakpointId = 0, BreakpointType bpType = BreakpointType::Global, uint16_t bpAddress = 0);
|
||||
bool SleepUntilResume(BreakSource source, uint32_t breakpointId = 0, BreakpointType bpType = BreakpointType::Global, uint16_t bpAddress = 0, MemoryOperationType bpMemOpType = MemoryOperationType::Read);
|
||||
|
||||
void AddDebugEvent(DebugEventType type, uint16_t address = -1, uint8_t value = 0, int16_t breakpointId = -1, int8_t ppuLatch = -1);
|
||||
|
||||
|
|
|
@ -36,6 +36,8 @@ enum class DebuggerFlags
|
|||
BreakOnDecayedOamRead = 0x2000,
|
||||
BreakOnInit = 0x4000,
|
||||
BreakOnPlay = 0x8000,
|
||||
|
||||
BreakOnFirstCycle = 0x10000,
|
||||
};
|
||||
|
||||
enum class BreakSource
|
||||
|
@ -117,6 +119,8 @@ struct PPUDebugState
|
|||
uint32_t NmiScanline;
|
||||
uint32_t ScanlineCount;
|
||||
uint32_t SafeOamScanline;
|
||||
uint16_t BusAddress;
|
||||
uint8_t MemoryReadBuffer;
|
||||
};
|
||||
|
||||
struct DebugState
|
||||
|
|
10
Core/DummyCpu.h
Normal file
10
Core/DummyCpu.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#define DUMMYCPU
|
||||
#define CPU DummyCpu
|
||||
#include "CPU.h"
|
||||
#include "CPU.cpp"
|
||||
#undef CPU
|
||||
#undef DUMMYCPU
|
|
@ -42,6 +42,15 @@ vector<int32_t>& MemoryAccessCounter::GetArray(MemoryOperationType operationType
|
|||
}
|
||||
}
|
||||
|
||||
bool MemoryAccessCounter::IsAddressUninitialized(AddressTypeInfo &addressInfo)
|
||||
{
|
||||
if(addressInfo.Type == AddressType::InternalRam || addressInfo.Type == AddressType::WorkRam) {
|
||||
int index = (int)addressInfo.Type;
|
||||
return !_initWrites[index][addressInfo.Address];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MemoryAccessCounter::ProcessMemoryAccess(AddressTypeInfo &addressInfo, MemoryOperationType operation, int32_t cpuCycle)
|
||||
{
|
||||
int index = (int)addressInfo.Type;
|
||||
|
|
|
@ -28,6 +28,8 @@ public:
|
|||
bool ProcessMemoryAccess(AddressTypeInfo &addressInfo, MemoryOperationType operation, int32_t cpuCycle);
|
||||
void ResetCounts();
|
||||
|
||||
bool IsAddressUninitialized(AddressTypeInfo &addressInfo);
|
||||
|
||||
void GetAccessCounts(AddressType memoryType, MemoryOperationType operationType, uint32_t counts[], bool forUninitReads);
|
||||
void GetAccessCountsEx(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, int32_t counts[]);
|
||||
void GetAccessStamps(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, uint32_t stamps[]);
|
||||
|
|
|
@ -150,6 +150,8 @@ void PPU::GetState(PPUDebugState &state)
|
|||
state.NmiScanline = _nmiScanline;
|
||||
state.ScanlineCount = _vblankEnd + 2;
|
||||
state.SafeOamScanline = _nesModel == NesModel::NTSC ? _nmiScanline + 19 : _palSpriteEvalScanline;
|
||||
state.BusAddress = _ppuBusAddress;
|
||||
state.MemoryReadBuffer = _memoryReadBuffer;
|
||||
}
|
||||
|
||||
void PPU::SetState(PPUDebugState &state)
|
||||
|
|
15
Core/Types.h
15
Core/Types.h
|
@ -1,6 +1,21 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
namespace PSFlags
|
||||
{
|
||||
enum PSFlags : uint8_t
|
||||
{
|
||||
Carry = 0x01,
|
||||
Zero = 0x02,
|
||||
Interrupt = 0x04,
|
||||
Decimal = 0x08,
|
||||
Break = 0x10,
|
||||
Reserved = 0x20,
|
||||
Overflow = 0x40,
|
||||
Negative = 0x80
|
||||
};
|
||||
}
|
||||
|
||||
enum class AddrMode
|
||||
{
|
||||
None, Acc, Imp, Imm, Rel,
|
||||
|
|
|
@ -301,6 +301,7 @@ namespace Mesen.GUI.Config
|
|||
public bool BreakOnUninitMemoryRead = false;
|
||||
public bool BreakOnInit = true;
|
||||
public bool BreakOnPlay = false;
|
||||
public bool BreakOnFirstCycle = true;
|
||||
|
||||
public bool BringToFrontOnPause = false;
|
||||
public bool BringToFrontOnBreak = true;
|
||||
|
|
97
GUI.NET/Debugger/frmDebugger.Designer.cs
generated
97
GUI.NET/Debugger/frmDebugger.Designer.cs
generated
|
@ -140,6 +140,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.toolStripMenuItem20 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuBringToFrontOnBreak = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuBringToFrontOnPause = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuEnableSubInstructionBreakpoints = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem12 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuShowOptions = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuShowToolbar = new System.Windows.Forms.ToolStripMenuItem();
|
||||
|
@ -174,6 +175,8 @@ namespace Mesen.GUI.Debugger
|
|||
this.mnuPpuShowPreviousFrame = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem19 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuShowBreakNotifications = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuShowInstructionProgression = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem27 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuAlwaysScrollToCenter = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuRefreshWhileRunning = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem6 = new System.Windows.Forms.ToolStripSeparator();
|
||||
|
@ -211,8 +214,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlPpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping();
|
||||
this.ctrlCpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping();
|
||||
this.tsToolbar = new Mesen.GUI.Controls.ctrlMesenToolStrip();
|
||||
this.mnuShowInstructionProgression = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem27 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.toolStripMenuItem28 = new System.Windows.Forms.ToolStripSeparator();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
|
||||
this.splitContainer.Panel1.SuspendLayout();
|
||||
this.splitContainer.Panel2.SuspendLayout();
|
||||
|
@ -257,7 +259,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.splitContainer.Panel2.Controls.Add(this.tableLayoutPanel10);
|
||||
this.splitContainer.Panel2MinSize = 100;
|
||||
this.splitContainer.Size = new System.Drawing.Size(1075, 570);
|
||||
this.splitContainer.SplitterDistance = 416;
|
||||
this.splitContainer.SplitterDistance = 410;
|
||||
this.splitContainer.SplitterWidth = 7;
|
||||
this.splitContainer.TabIndex = 1;
|
||||
this.splitContainer.TabStop = false;
|
||||
|
@ -281,7 +283,7 @@ namespace Mesen.GUI.Debugger
|
|||
//
|
||||
this.ctrlSplitContainerTop.Panel2.Controls.Add(this.tlpFunctionLabelLists);
|
||||
this.ctrlSplitContainerTop.Panel2MinSize = 150;
|
||||
this.ctrlSplitContainerTop.Size = new System.Drawing.Size(1075, 416);
|
||||
this.ctrlSplitContainerTop.Size = new System.Drawing.Size(1075, 410);
|
||||
this.ctrlSplitContainerTop.SplitterDistance = 750;
|
||||
this.ctrlSplitContainerTop.SplitterWidth = 7;
|
||||
this.ctrlSplitContainerTop.TabIndex = 3;
|
||||
|
@ -302,8 +304,8 @@ namespace Mesen.GUI.Debugger
|
|||
this.tlpTop.Name = "tlpTop";
|
||||
this.tlpTop.RowCount = 1;
|
||||
this.tlpTop.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tlpTop.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 416F));
|
||||
this.tlpTop.Size = new System.Drawing.Size(750, 416);
|
||||
this.tlpTop.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 410F));
|
||||
this.tlpTop.Size = new System.Drawing.Size(750, 410);
|
||||
this.tlpTop.TabIndex = 2;
|
||||
//
|
||||
// panel1
|
||||
|
@ -314,7 +316,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.panel1.Location = new System.Drawing.Point(3, 0);
|
||||
this.panel1.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Size = new System.Drawing.Size(286, 416);
|
||||
this.panel1.Size = new System.Drawing.Size(286, 410);
|
||||
this.panel1.TabIndex = 5;
|
||||
//
|
||||
// ctrlSourceViewer
|
||||
|
@ -323,7 +325,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlSourceViewer.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlSourceViewer.Location = new System.Drawing.Point(0, 0);
|
||||
this.ctrlSourceViewer.Name = "ctrlSourceViewer";
|
||||
this.ctrlSourceViewer.Size = new System.Drawing.Size(286, 416);
|
||||
this.ctrlSourceViewer.Size = new System.Drawing.Size(286, 410);
|
||||
this.ctrlSourceViewer.SymbolProvider = null;
|
||||
this.ctrlSourceViewer.TabIndex = 7;
|
||||
this.ctrlSourceViewer.Visible = false;
|
||||
|
@ -336,7 +338,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlDebuggerCode.Location = new System.Drawing.Point(0, 0);
|
||||
this.ctrlDebuggerCode.Name = "ctrlDebuggerCode";
|
||||
this.ctrlDebuggerCode.ShowMemoryValues = false;
|
||||
this.ctrlDebuggerCode.Size = new System.Drawing.Size(286, 416);
|
||||
this.ctrlDebuggerCode.Size = new System.Drawing.Size(286, 410);
|
||||
this.ctrlDebuggerCode.SymbolProvider = null;
|
||||
this.ctrlDebuggerCode.TabIndex = 2;
|
||||
this.ctrlDebuggerCode.OnEditCode += new Mesen.GUI.Debugger.ctrlDebuggerCode.AssemblerEventHandler(this.ctrlDebuggerCode_OnEditCode);
|
||||
|
@ -350,7 +352,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.panel2.Location = new System.Drawing.Point(292, 0);
|
||||
this.panel2.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
|
||||
this.panel2.Name = "panel2";
|
||||
this.panel2.Size = new System.Drawing.Size(1, 416);
|
||||
this.panel2.Size = new System.Drawing.Size(1, 410);
|
||||
this.panel2.TabIndex = 6;
|
||||
//
|
||||
// ctrlSourceViewerSplit
|
||||
|
@ -359,7 +361,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlSourceViewerSplit.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlSourceViewerSplit.Location = new System.Drawing.Point(0, 0);
|
||||
this.ctrlSourceViewerSplit.Name = "ctrlSourceViewerSplit";
|
||||
this.ctrlSourceViewerSplit.Size = new System.Drawing.Size(1, 416);
|
||||
this.ctrlSourceViewerSplit.Size = new System.Drawing.Size(1, 410);
|
||||
this.ctrlSourceViewerSplit.SymbolProvider = null;
|
||||
this.ctrlSourceViewerSplit.TabIndex = 8;
|
||||
this.ctrlSourceViewerSplit.Visible = false;
|
||||
|
@ -372,7 +374,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlDebuggerCodeSplit.Location = new System.Drawing.Point(0, 0);
|
||||
this.ctrlDebuggerCodeSplit.Name = "ctrlDebuggerCodeSplit";
|
||||
this.ctrlDebuggerCodeSplit.ShowMemoryValues = false;
|
||||
this.ctrlDebuggerCodeSplit.Size = new System.Drawing.Size(1, 416);
|
||||
this.ctrlDebuggerCodeSplit.Size = new System.Drawing.Size(1, 410);
|
||||
this.ctrlDebuggerCodeSplit.SymbolProvider = null;
|
||||
this.ctrlDebuggerCodeSplit.TabIndex = 4;
|
||||
this.ctrlDebuggerCodeSplit.Visible = false;
|
||||
|
@ -392,7 +394,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.tableLayoutPanel1.RowCount = 2;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(458, 416);
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(458, 410);
|
||||
this.tableLayoutPanel1.TabIndex = 7;
|
||||
//
|
||||
// ctrlConsoleStatus
|
||||
|
@ -416,7 +418,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.tlpVerticalLayout.Name = "tlpVerticalLayout";
|
||||
this.tlpVerticalLayout.RowCount = 1;
|
||||
this.tlpVerticalLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tlpVerticalLayout.Size = new System.Drawing.Size(458, 16);
|
||||
this.tlpVerticalLayout.Size = new System.Drawing.Size(458, 10);
|
||||
this.tlpVerticalLayout.TabIndex = 4;
|
||||
//
|
||||
// tlpFunctionLabelLists
|
||||
|
@ -432,16 +434,16 @@ namespace Mesen.GUI.Debugger
|
|||
this.tlpFunctionLabelLists.RowCount = 2;
|
||||
this.tlpFunctionLabelLists.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tlpFunctionLabelLists.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tlpFunctionLabelLists.Size = new System.Drawing.Size(318, 416);
|
||||
this.tlpFunctionLabelLists.Size = new System.Drawing.Size(318, 410);
|
||||
this.tlpFunctionLabelLists.TabIndex = 5;
|
||||
//
|
||||
// grpLabels
|
||||
//
|
||||
this.grpLabels.Controls.Add(this.ctrlLabelList);
|
||||
this.grpLabels.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.grpLabels.Location = new System.Drawing.Point(3, 211);
|
||||
this.grpLabels.Location = new System.Drawing.Point(3, 208);
|
||||
this.grpLabels.Name = "grpLabels";
|
||||
this.grpLabels.Size = new System.Drawing.Size(312, 202);
|
||||
this.grpLabels.Size = new System.Drawing.Size(312, 199);
|
||||
this.grpLabels.TabIndex = 6;
|
||||
this.grpLabels.TabStop = false;
|
||||
this.grpLabels.Text = "Labels";
|
||||
|
@ -451,7 +453,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlLabelList.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlLabelList.Location = new System.Drawing.Point(3, 16);
|
||||
this.ctrlLabelList.Name = "ctrlLabelList";
|
||||
this.ctrlLabelList.Size = new System.Drawing.Size(306, 183);
|
||||
this.ctrlLabelList.Size = new System.Drawing.Size(306, 180);
|
||||
this.ctrlLabelList.TabIndex = 0;
|
||||
this.ctrlLabelList.OnFindOccurrence += new System.EventHandler(this.ctrlLabelList_OnFindOccurrence);
|
||||
this.ctrlLabelList.OnLabelSelected += new System.EventHandler(this.ctrlLabelList_OnLabelSelected);
|
||||
|
@ -462,7 +464,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.grpFunctions.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.grpFunctions.Location = new System.Drawing.Point(3, 3);
|
||||
this.grpFunctions.Name = "grpFunctions";
|
||||
this.grpFunctions.Size = new System.Drawing.Size(312, 202);
|
||||
this.grpFunctions.Size = new System.Drawing.Size(312, 199);
|
||||
this.grpFunctions.TabIndex = 5;
|
||||
this.grpFunctions.TabStop = false;
|
||||
this.grpFunctions.Text = "Functions";
|
||||
|
@ -472,7 +474,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlFunctionList.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlFunctionList.Location = new System.Drawing.Point(3, 16);
|
||||
this.ctrlFunctionList.Name = "ctrlFunctionList";
|
||||
this.ctrlFunctionList.Size = new System.Drawing.Size(306, 183);
|
||||
this.ctrlFunctionList.Size = new System.Drawing.Size(306, 180);
|
||||
this.ctrlFunctionList.TabIndex = 0;
|
||||
this.ctrlFunctionList.OnFindOccurrence += new System.EventHandler(this.ctrlFunctionList_OnFindOccurrence);
|
||||
this.ctrlFunctionList.OnFunctionSelected += new System.EventHandler(this.ctrlFunctionList_OnFunctionSelected);
|
||||
|
@ -503,7 +505,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel10.Size = new System.Drawing.Size(1075, 147);
|
||||
this.tableLayoutPanel10.Size = new System.Drawing.Size(1075, 153);
|
||||
this.tableLayoutPanel10.TabIndex = 0;
|
||||
//
|
||||
// grpWatch
|
||||
|
@ -512,7 +514,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.grpWatch.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.grpWatch.Location = new System.Drawing.Point(3, 3);
|
||||
this.grpWatch.Name = "grpWatch";
|
||||
this.grpWatch.Size = new System.Drawing.Size(352, 141);
|
||||
this.grpWatch.Size = new System.Drawing.Size(352, 147);
|
||||
this.grpWatch.TabIndex = 2;
|
||||
this.grpWatch.TabStop = false;
|
||||
this.grpWatch.Text = "Watch";
|
||||
|
@ -522,7 +524,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlWatch.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlWatch.Location = new System.Drawing.Point(3, 16);
|
||||
this.ctrlWatch.Name = "ctrlWatch";
|
||||
this.ctrlWatch.Size = new System.Drawing.Size(346, 122);
|
||||
this.ctrlWatch.Size = new System.Drawing.Size(346, 128);
|
||||
this.ctrlWatch.TabIndex = 0;
|
||||
//
|
||||
// grpBreakpoints
|
||||
|
@ -531,7 +533,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.grpBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.grpBreakpoints.Location = new System.Drawing.Point(361, 3);
|
||||
this.grpBreakpoints.Name = "grpBreakpoints";
|
||||
this.grpBreakpoints.Size = new System.Drawing.Size(352, 141);
|
||||
this.grpBreakpoints.Size = new System.Drawing.Size(352, 147);
|
||||
this.grpBreakpoints.TabIndex = 3;
|
||||
this.grpBreakpoints.TabStop = false;
|
||||
this.grpBreakpoints.Text = "Breakpoints";
|
||||
|
@ -541,7 +543,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlBreakpoints.Location = new System.Drawing.Point(3, 16);
|
||||
this.ctrlBreakpoints.Name = "ctrlBreakpoints";
|
||||
this.ctrlBreakpoints.Size = new System.Drawing.Size(346, 122);
|
||||
this.ctrlBreakpoints.Size = new System.Drawing.Size(346, 128);
|
||||
this.ctrlBreakpoints.TabIndex = 0;
|
||||
this.ctrlBreakpoints.BreakpointNavigation += new System.EventHandler(this.ctrlBreakpoints_BreakpointNavigation);
|
||||
//
|
||||
|
@ -551,7 +553,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.grpCallstack.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.grpCallstack.Location = new System.Drawing.Point(719, 3);
|
||||
this.grpCallstack.Name = "grpCallstack";
|
||||
this.grpCallstack.Size = new System.Drawing.Size(353, 141);
|
||||
this.grpCallstack.Size = new System.Drawing.Size(353, 147);
|
||||
this.grpCallstack.TabIndex = 4;
|
||||
this.grpCallstack.TabStop = false;
|
||||
this.grpCallstack.Text = "Call Stack";
|
||||
|
@ -561,7 +563,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlCallstack.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlCallstack.Location = new System.Drawing.Point(3, 16);
|
||||
this.ctrlCallstack.Name = "ctrlCallstack";
|
||||
this.ctrlCallstack.Size = new System.Drawing.Size(347, 122);
|
||||
this.ctrlCallstack.Size = new System.Drawing.Size(347, 128);
|
||||
this.ctrlCallstack.TabIndex = 0;
|
||||
this.ctrlCallstack.FunctionSelected += new System.EventHandler(this.ctrlCallstack_FunctionSelected);
|
||||
//
|
||||
|
@ -1181,7 +1183,9 @@ namespace Mesen.GUI.Debugger
|
|||
this.mnuBreakOnDebuggerFocus,
|
||||
this.toolStripMenuItem20,
|
||||
this.mnuBringToFrontOnBreak,
|
||||
this.mnuBringToFrontOnPause});
|
||||
this.mnuBringToFrontOnPause,
|
||||
this.toolStripMenuItem28,
|
||||
this.mnuEnableSubInstructionBreakpoints});
|
||||
this.mnuBreakOptions.Name = "mnuBreakOptions";
|
||||
this.mnuBreakOptions.Size = new System.Drawing.Size(266, 22);
|
||||
this.mnuBreakOptions.Text = "Break Options";
|
||||
|
@ -1303,6 +1307,14 @@ namespace Mesen.GUI.Debugger
|
|||
this.mnuBringToFrontOnPause.Text = "Bring debugger to front on pause";
|
||||
this.mnuBringToFrontOnPause.Click += new System.EventHandler(this.mnuBringToFrontOnPause_Click);
|
||||
//
|
||||
// mnuBreakOnFirstCycle
|
||||
//
|
||||
this.mnuEnableSubInstructionBreakpoints.CheckOnClick = true;
|
||||
this.mnuEnableSubInstructionBreakpoints.Name = "mnuEnableSubInstructionBreakpoints";
|
||||
this.mnuEnableSubInstructionBreakpoints.Size = new System.Drawing.Size(261, 22);
|
||||
this.mnuEnableSubInstructionBreakpoints.Text = "Enable sub-instruction breakpoints";
|
||||
this.mnuEnableSubInstructionBreakpoints.Click += new System.EventHandler(this.mnuBreakOnFirstCycle_Click);
|
||||
//
|
||||
// toolStripMenuItem12
|
||||
//
|
||||
this.toolStripMenuItem12.Name = "toolStripMenuItem12";
|
||||
|
@ -1572,6 +1584,19 @@ namespace Mesen.GUI.Debugger
|
|||
this.mnuShowBreakNotifications.Text = "Show break notifications";
|
||||
this.mnuShowBreakNotifications.Click += new System.EventHandler(this.mnuShowBreakNotifications_Click);
|
||||
//
|
||||
// mnuShowInstructionProgression
|
||||
//
|
||||
this.mnuShowInstructionProgression.CheckOnClick = true;
|
||||
this.mnuShowInstructionProgression.Name = "mnuShowInstructionProgression";
|
||||
this.mnuShowInstructionProgression.Size = new System.Drawing.Size(266, 22);
|
||||
this.mnuShowInstructionProgression.Text = "Show instruction progression";
|
||||
this.mnuShowInstructionProgression.Click += new System.EventHandler(this.mnuShowInstructionProgression_Click);
|
||||
//
|
||||
// toolStripMenuItem27
|
||||
//
|
||||
this.toolStripMenuItem27.Name = "toolStripMenuItem27";
|
||||
this.toolStripMenuItem27.Size = new System.Drawing.Size(263, 6);
|
||||
//
|
||||
// mnuAlwaysScrollToCenter
|
||||
//
|
||||
this.mnuAlwaysScrollToCenter.CheckOnClick = true;
|
||||
|
@ -1874,18 +1899,10 @@ namespace Mesen.GUI.Debugger
|
|||
this.tsToolbar.Text = "toolStrip1";
|
||||
this.tsToolbar.Visible = false;
|
||||
//
|
||||
// mnuShowInstructionProgression
|
||||
// toolStripMenuItem28
|
||||
//
|
||||
this.mnuShowInstructionProgression.CheckOnClick = true;
|
||||
this.mnuShowInstructionProgression.Name = "mnuShowInstructionProgression";
|
||||
this.mnuShowInstructionProgression.Size = new System.Drawing.Size(266, 22);
|
||||
this.mnuShowInstructionProgression.Text = "Show instruction progression";
|
||||
this.mnuShowInstructionProgression.Click += new System.EventHandler(this.mnuShowInstructionProgression_Click);
|
||||
//
|
||||
// toolStripMenuItem27
|
||||
//
|
||||
this.toolStripMenuItem27.Name = "toolStripMenuItem27";
|
||||
this.toolStripMenuItem27.Size = new System.Drawing.Size(263, 6);
|
||||
this.toolStripMenuItem28.Name = "toolStripMenuItem28";
|
||||
this.toolStripMenuItem28.Size = new System.Drawing.Size(258, 6);
|
||||
//
|
||||
// frmDebugger
|
||||
//
|
||||
|
@ -2120,5 +2137,7 @@ namespace Mesen.GUI.Debugger
|
|||
private System.Windows.Forms.ToolStripMenuItem mnuShowBreakNotifications;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuShowInstructionProgression;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem27;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuEnableSubInstructionBreakpoints;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem28;
|
||||
}
|
||||
}
|
|
@ -102,6 +102,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.mnuShowPpuMemoryMapping.Checked = ConfigManager.Config.DebugInfo.ShowPpuMemoryMapping;
|
||||
this.mnuAutoLoadDbgFiles.Checked = ConfigManager.Config.DebugInfo.AutoLoadDbgFiles;
|
||||
this.mnuAutoLoadCdlFiles.Checked = ConfigManager.Config.DebugInfo.AutoLoadCdlFiles;
|
||||
this.mnuEnableSubInstructionBreakpoints.Checked = !ConfigManager.Config.DebugInfo.BreakOnFirstCycle;
|
||||
this.mnuBreakOnReset.Checked = ConfigManager.Config.DebugInfo.BreakOnReset;
|
||||
this.mnuBreakOnInit.Checked = ConfigManager.Config.DebugInfo.BreakOnInit;
|
||||
this.mnuBreakOnPlay.Checked = ConfigManager.Config.DebugInfo.BreakOnPlay;
|
||||
|
@ -484,6 +485,7 @@ namespace Mesen.GUI.Debugger
|
|||
SetFlag(DebuggerFlags.BreakOnDecayedOamRead, config.BreakOnDecayedOamRead);
|
||||
SetFlag(DebuggerFlags.BreakOnInit, config.BreakOnInit);
|
||||
SetFlag(DebuggerFlags.BreakOnPlay, config.BreakOnPlay);
|
||||
SetFlag(DebuggerFlags.BreakOnFirstCycle, config.BreakOnFirstCycle);
|
||||
SetFlag(DebuggerFlags.HidePauseIcon, config.HidePauseIcon);
|
||||
InteropEmu.SetFlag(EmulationFlags.DebuggerWindowEnabled, true);
|
||||
}
|
||||
|
@ -497,7 +499,8 @@ namespace Mesen.GUI.Debugger
|
|||
message = ResourceHelper.GetEnumText(source);
|
||||
if(source == BreakSource.Breakpoint) {
|
||||
int breakpointId = (int)(param >> 32);
|
||||
BreakpointType bpType = (BreakpointType)(byte)(param >> 8);
|
||||
BreakpointType bpType = (BreakpointType)(byte)((param >> 8) & 0x0F);
|
||||
InteropMemoryOperationType memOpType = (InteropMemoryOperationType)(byte)((param >> 12) & 0x0F);
|
||||
UInt16 bpAddress = (UInt16)(param >> 16);
|
||||
|
||||
ReadOnlyCollection<Breakpoint> breakpoints = BreakpointManager.Breakpoints;
|
||||
|
@ -506,9 +509,7 @@ namespace Mesen.GUI.Debugger
|
|||
if(bpType != BreakpointType.Global) {
|
||||
string prefix = "";
|
||||
if(bpType == BreakpointType.ReadRam || bpType == BreakpointType.WriteRam) {
|
||||
InstructionProgress progress = new InstructionProgress();
|
||||
InteropEmu.DebugGetInstructionProgress(ref progress);
|
||||
if(progress.OpMemoryOperationType == InteropMemoryOperationType.DummyRead || progress.OpMemoryOperationType == InteropMemoryOperationType.DummyWrite) {
|
||||
if(memOpType == InteropMemoryOperationType.DummyRead || memOpType == InteropMemoryOperationType.DummyWrite) {
|
||||
prefix = "(Dummy) ";
|
||||
}
|
||||
}
|
||||
|
@ -523,6 +524,9 @@ namespace Mesen.GUI.Debugger
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if(source == BreakSource.BreakOnUninitMemoryRead) {
|
||||
UInt16 address = (UInt16)(param >> 16);
|
||||
message += " ($" + address.ToString("X4") + ")";
|
||||
} else if(source == BreakSource.CpuStep || source == BreakSource.PpuStep) {
|
||||
//Don't display anything when breaking due to stepping
|
||||
message = null;
|
||||
|
@ -1190,6 +1194,13 @@ namespace Mesen.GUI.Debugger
|
|||
ConfigManager.ApplyChanges();
|
||||
}
|
||||
|
||||
private void mnuBreakOnFirstCycle_Click(object sender, EventArgs e)
|
||||
{
|
||||
ConfigManager.Config.DebugInfo.BreakOnFirstCycle = !mnuEnableSubInstructionBreakpoints.Checked;
|
||||
ConfigManager.ApplyChanges();
|
||||
UpdateDebuggerFlags();
|
||||
}
|
||||
|
||||
private void mnuBreakOnReset_Click(object sender, EventArgs e)
|
||||
{
|
||||
ConfigManager.Config.DebugInfo.BreakOnReset = mnuBreakOnReset.Checked;
|
||||
|
|
|
@ -1322,6 +1322,8 @@ namespace Mesen.GUI
|
|||
public UInt32 NmiScanline;
|
||||
public UInt32 ScanlineCount;
|
||||
public UInt32 SafeOamScanline;
|
||||
public UInt16 BusAddress;
|
||||
public byte MemoryReadBuffer;
|
||||
}
|
||||
|
||||
public struct PPUState
|
||||
|
@ -1690,6 +1692,8 @@ namespace Mesen.GUI
|
|||
BreakOnDecayedOamRead = 0x2000,
|
||||
BreakOnInit = 0x4000,
|
||||
BreakOnPlay = 0x8000,
|
||||
|
||||
BreakOnFirstCycle = 0x10000,
|
||||
}
|
||||
|
||||
public struct InteropRomInfo
|
||||
|
|
Loading…
Add table
Reference in a new issue