Debugger: Added performance profiler tool
This commit is contained in:
parent
3312871006
commit
0cf94db654
26 changed files with 1310 additions and 137 deletions
|
@ -2,13 +2,19 @@
|
||||||
#include "CallstackManager.h"
|
#include "CallstackManager.h"
|
||||||
#include "Debugger.h"
|
#include "Debugger.h"
|
||||||
#include "DebugBreakHelper.h"
|
#include "DebugBreakHelper.h"
|
||||||
|
#include "Profiler.h"
|
||||||
|
|
||||||
CallstackManager::CallstackManager(Debugger* debugger)
|
CallstackManager::CallstackManager(Debugger* debugger)
|
||||||
{
|
{
|
||||||
_debugger = debugger;
|
_debugger = debugger;
|
||||||
|
_profiler.reset(new Profiler(debugger));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallstackManager::Push(uint32_t srcAddr, uint32_t destAddr, uint32_t returnAddress, StackFrameFlags flags)
|
CallstackManager::~CallstackManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallstackManager::Push(AddressInfo &src, uint32_t srcAddr, AddressInfo& dest, uint32_t destAddr, AddressInfo& ret, uint32_t returnAddress, StackFrameFlags flags)
|
||||||
{
|
{
|
||||||
if(_callstack.size() >= 511) {
|
if(_callstack.size() >= 511) {
|
||||||
//Ensure callstack stays below 512 entries - games can use various tricks that could keep making the callstack grow
|
//Ensure callstack stays below 512 entries - games can use various tricks that could keep making the callstack grow
|
||||||
|
@ -20,13 +26,15 @@ void CallstackManager::Push(uint32_t srcAddr, uint32_t destAddr, uint32_t return
|
||||||
stackFrame.Target = destAddr;
|
stackFrame.Target = destAddr;
|
||||||
|
|
||||||
stackFrame.Return = returnAddress;
|
stackFrame.Return = returnAddress;
|
||||||
|
stackFrame.AbsReturn = ret;
|
||||||
|
|
||||||
stackFrame.Flags = flags;
|
stackFrame.Flags = flags;
|
||||||
|
|
||||||
_callstack.push_back(stackFrame);
|
_callstack.push_back(stackFrame);
|
||||||
|
_profiler->StackFunction(dest, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallstackManager::Pop(uint32_t destAddress)
|
void CallstackManager::Pop(AddressInfo& dest, uint32_t destAddress)
|
||||||
{
|
{
|
||||||
if(_callstack.empty()) {
|
if(_callstack.empty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -34,6 +42,7 @@ void CallstackManager::Pop(uint32_t destAddress)
|
||||||
|
|
||||||
StackFrameInfo prevFrame = _callstack.back();
|
StackFrameInfo prevFrame = _callstack.back();
|
||||||
_callstack.pop_back();
|
_callstack.pop_back();
|
||||||
|
_profiler->UnstackFunction();
|
||||||
|
|
||||||
uint32_t returnAddr = prevFrame.Return;
|
uint32_t returnAddr = prevFrame.Return;
|
||||||
|
|
||||||
|
@ -46,6 +55,7 @@ void CallstackManager::Pop(uint32_t destAddress)
|
||||||
foundMatch = true;
|
foundMatch = true;
|
||||||
for(int j = (int)_callstack.size() - i - 1; j >= 0; j--) {
|
for(int j = (int)_callstack.size() - i - 1; j >= 0; j--) {
|
||||||
_callstack.pop_back();
|
_callstack.pop_back();
|
||||||
|
_profiler->UnstackFunction();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +63,7 @@ void CallstackManager::Pop(uint32_t destAddress)
|
||||||
|
|
||||||
if(!foundMatch) {
|
if(!foundMatch) {
|
||||||
//Couldn't find a matching frame, replace the current one
|
//Couldn't find a matching frame, replace the current one
|
||||||
Push(returnAddr, destAddress, returnAddr, StackFrameFlags::None);
|
Push(prevFrame.AbsReturn, returnAddr, dest, destAddress, prevFrame.AbsReturn, returnAddr, StackFrameFlags::None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,3 +87,8 @@ int32_t CallstackManager::GetReturnAddress()
|
||||||
}
|
}
|
||||||
return _callstack.back().Return;
|
return _callstack.back().Return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Profiler* CallstackManager::GetProfiler()
|
||||||
|
{
|
||||||
|
return _profiler.get();
|
||||||
|
}
|
||||||
|
|
|
@ -3,19 +3,23 @@
|
||||||
#include "DebugTypes.h"
|
#include "DebugTypes.h"
|
||||||
|
|
||||||
class Debugger;
|
class Debugger;
|
||||||
|
class Profiler;
|
||||||
|
|
||||||
class CallstackManager
|
class CallstackManager
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Debugger* _debugger;
|
Debugger* _debugger;
|
||||||
deque<StackFrameInfo> _callstack;
|
deque<StackFrameInfo> _callstack;
|
||||||
|
unique_ptr<Profiler> _profiler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CallstackManager(Debugger* debugger);
|
CallstackManager(Debugger* debugger);
|
||||||
|
~CallstackManager();
|
||||||
|
|
||||||
void Push(uint32_t srcAddr, uint32_t destAddr, uint32_t returnAddress, StackFrameFlags flags);
|
void Push(AddressInfo& src, uint32_t srcAddr, AddressInfo& dest, uint32_t destAddr, AddressInfo& ret, uint32_t returnAddress, StackFrameFlags flags);
|
||||||
void Pop(uint32_t destAddr);
|
void Pop(AddressInfo& dest, uint32_t destAddr);
|
||||||
|
|
||||||
void GetCallstack(StackFrameInfo* callstackArray, uint32_t &callstackSize);
|
void GetCallstack(StackFrameInfo* callstackArray, uint32_t &callstackSize);
|
||||||
int32_t GetReturnAddress();
|
int32_t GetReturnAddress();
|
||||||
|
Profiler* GetProfiler();
|
||||||
};
|
};
|
|
@ -127,6 +127,7 @@
|
||||||
<ClInclude Include="PcmReader.h" />
|
<ClInclude Include="PcmReader.h" />
|
||||||
<ClInclude Include="PlayerListMessage.h" />
|
<ClInclude Include="PlayerListMessage.h" />
|
||||||
<ClInclude Include="PpuTools.h" />
|
<ClInclude Include="PpuTools.h" />
|
||||||
|
<ClInclude Include="Profiler.h" />
|
||||||
<ClInclude Include="RecordedRomTest.h" />
|
<ClInclude Include="RecordedRomTest.h" />
|
||||||
<ClInclude Include="RegisterHandlerB.h" />
|
<ClInclude Include="RegisterHandlerB.h" />
|
||||||
<ClInclude Include="CpuTypes.h" />
|
<ClInclude Include="CpuTypes.h" />
|
||||||
|
@ -273,6 +274,7 @@
|
||||||
<ClCompile Include="PcmReader.cpp" />
|
<ClCompile Include="PcmReader.cpp" />
|
||||||
<ClCompile Include="Ppu.cpp" />
|
<ClCompile Include="Ppu.cpp" />
|
||||||
<ClCompile Include="PpuTools.cpp" />
|
<ClCompile Include="PpuTools.cpp" />
|
||||||
|
<ClCompile Include="Profiler.cpp" />
|
||||||
<ClCompile Include="RecordedRomTest.cpp" />
|
<ClCompile Include="RecordedRomTest.cpp" />
|
||||||
<ClCompile Include="RegisterHandlerB.cpp" />
|
<ClCompile Include="RegisterHandlerB.cpp" />
|
||||||
<ClCompile Include="RewindData.cpp" />
|
<ClCompile Include="RewindData.cpp" />
|
||||||
|
|
|
@ -488,6 +488,9 @@
|
||||||
<ClInclude Include="Sa1BwRamHandler.h">
|
<ClInclude Include="Sa1BwRamHandler.h">
|
||||||
<Filter>SNES\Coprocessors\SA1</Filter>
|
<Filter>SNES\Coprocessors\SA1</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Profiler.h">
|
||||||
|
<Filter>Debugger</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="stdafx.cpp" />
|
<ClCompile Include="stdafx.cpp" />
|
||||||
|
@ -773,6 +776,9 @@
|
||||||
<ClCompile Include="Msu1.cpp">
|
<ClCompile Include="Msu1.cpp">
|
||||||
<Filter>SNES\Coprocessors\MSU1</Filter>
|
<Filter>SNES\Coprocessors\MSU1</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Profiler.cpp">
|
||||||
|
<Filter>Debugger</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="SNES">
|
<Filter Include="SNES">
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "Console.h"
|
#include "Console.h"
|
||||||
#include "MemoryAccessCounter.h"
|
#include "MemoryAccessCounter.h"
|
||||||
#include "ExpressionEvaluator.h"
|
#include "ExpressionEvaluator.h"
|
||||||
|
#include "Profiler.h"
|
||||||
|
|
||||||
CpuDebugger::CpuDebugger(Debugger* debugger, CpuType cpuType)
|
CpuDebugger::CpuDebugger(Debugger* debugger, CpuType cpuType)
|
||||||
{
|
{
|
||||||
|
@ -50,6 +51,7 @@ CpuDebugger::CpuDebugger(Debugger* debugger, CpuType cpuType)
|
||||||
void CpuDebugger::Reset()
|
void CpuDebugger::Reset()
|
||||||
{
|
{
|
||||||
_enableBreakOnUninitRead = true;
|
_enableBreakOnUninitRead = true;
|
||||||
|
_callstackManager.reset(new CallstackManager(_debugger));
|
||||||
_prevOpCode = 0xFF;
|
_prevOpCode = 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,10 +90,12 @@ void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
|
||||||
//JSR, JSL
|
//JSR, JSL
|
||||||
uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, state.PS, _cpuType);
|
uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, state.PS, _cpuType);
|
||||||
uint32_t returnPc = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + opSize) & 0xFFFF);
|
uint32_t returnPc = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + opSize) & 0xFFFF);
|
||||||
_callstackManager->Push(_prevProgramCounter, pc, returnPc, StackFrameFlags::None);
|
AddressInfo srcAddress = GetMemoryMappings().GetAbsoluteAddress(_prevProgramCounter);
|
||||||
|
AddressInfo retAddress = GetMemoryMappings().GetAbsoluteAddress(returnPc);
|
||||||
|
_callstackManager->Push(srcAddress, _prevProgramCounter, addressInfo, pc, retAddress, returnPc, StackFrameFlags::None);
|
||||||
} else if(_prevOpCode == 0x60 || _prevOpCode == 0x6B || _prevOpCode == 0x40) {
|
} else if(_prevOpCode == 0x60 || _prevOpCode == 0x6B || _prevOpCode == 0x40) {
|
||||||
//RTS, RTL, RTI
|
//RTS, RTL, RTI
|
||||||
_callstackManager->Pop(pc);
|
_callstackManager->Pop(addressInfo, pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_step->BreakAddress == (int32_t)pc && (_prevOpCode == 0x60 || _prevOpCode == 0x40 || _prevOpCode == 0x6B || _prevOpCode == 0x44 || _prevOpCode == 0x54)) {
|
if(_step->BreakAddress == (int32_t)pc && (_prevOpCode == 0x60 || _prevOpCode == 0x40 || _prevOpCode == 0x6B || _prevOpCode == 0x44 || _prevOpCode == 0x54)) {
|
||||||
|
@ -205,7 +209,10 @@ void CpuDebugger::Step(int32_t stepCount, StepType type)
|
||||||
|
|
||||||
void CpuDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi)
|
void CpuDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi)
|
||||||
{
|
{
|
||||||
_callstackManager->Push(_prevProgramCounter, currentPc, originalPc, forNmi ? StackFrameFlags::Nmi : StackFrameFlags::Irq);
|
AddressInfo src = GetMemoryMappings().GetAbsoluteAddress(_prevProgramCounter);
|
||||||
|
AddressInfo ret = GetMemoryMappings().GetAbsoluteAddress(originalPc);
|
||||||
|
AddressInfo dest = GetMemoryMappings().GetAbsoluteAddress(currentPc);
|
||||||
|
_callstackManager->Push(src, _prevProgramCounter, dest, currentPc, ret, originalPc, forNmi ? StackFrameFlags::Nmi : StackFrameFlags::Irq);
|
||||||
_eventManager->AddEvent(forNmi ? DebugEventType::Nmi : DebugEventType::Irq);
|
_eventManager->AddEvent(forNmi ? DebugEventType::Nmi : DebugEventType::Irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -221,6 +221,7 @@ struct StackFrameInfo
|
||||||
uint32_t Source;
|
uint32_t Source;
|
||||||
uint32_t Target;
|
uint32_t Target;
|
||||||
uint32_t Return;
|
uint32_t Return;
|
||||||
|
AddressInfo AbsReturn;
|
||||||
StackFrameFlags Flags;
|
StackFrameFlags Flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
129
Core/Profiler.cpp
Normal file
129
Core/Profiler.cpp
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include <limits>
|
||||||
|
#include "Profiler.h"
|
||||||
|
#include "DebugBreakHelper.h"
|
||||||
|
#include "Debugger.h"
|
||||||
|
#include "Console.h"
|
||||||
|
#include "MemoryManager.h"
|
||||||
|
#include "MemoryDumper.h"
|
||||||
|
#include "DebugTypes.h"
|
||||||
|
|
||||||
|
Profiler::Profiler(Debugger* debugger)
|
||||||
|
{
|
||||||
|
_debugger = debugger;
|
||||||
|
_memoryManager = debugger->GetConsole()->GetMemoryManager().get();
|
||||||
|
InternalReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Profiler::~Profiler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Profiler::StackFunction(AddressInfo &addr, StackFrameFlags stackFlag)
|
||||||
|
{
|
||||||
|
UpdateCycles();
|
||||||
|
|
||||||
|
if(addr.Address >= 0) {
|
||||||
|
_stackFlags.push_back(stackFlag);
|
||||||
|
|
||||||
|
_cycleCountStack.push(_currentCycleCount);
|
||||||
|
|
||||||
|
_functionStack.push_back(_currentFunction);
|
||||||
|
|
||||||
|
uint32_t key = addr.Address | ((uint8_t)addr.Type << 24);
|
||||||
|
if(_functions.find(key) == _functions.end()) {
|
||||||
|
_functions[key] = ProfiledFunction();
|
||||||
|
_functions[key].Address = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProfiledFunction& func = _functions[key];
|
||||||
|
func.CallCount++;
|
||||||
|
|
||||||
|
_currentFunction = key;
|
||||||
|
_currentCycleCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Profiler::UpdateCycles()
|
||||||
|
{
|
||||||
|
uint64_t masterClock = _memoryManager->GetMasterClock();
|
||||||
|
|
||||||
|
ProfiledFunction& func = _functions[_currentFunction];
|
||||||
|
uint64_t clockGap = masterClock - _prevMasterClock;
|
||||||
|
func.ExclusiveCycles += clockGap;
|
||||||
|
func.InclusiveCycles += clockGap;
|
||||||
|
|
||||||
|
int32_t len = (int32_t)_functionStack.size();
|
||||||
|
for(int32_t i = len - 1; i >= 0; i--) {
|
||||||
|
_functions[_functionStack[i]].InclusiveCycles += clockGap;
|
||||||
|
if(_stackFlags[i] != StackFrameFlags::None) {
|
||||||
|
//Don't apply inclusive times to stack frames before an IRQ/NMI
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentCycleCount += clockGap;
|
||||||
|
_prevMasterClock = masterClock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Profiler::UnstackFunction()
|
||||||
|
{
|
||||||
|
UpdateCycles();
|
||||||
|
|
||||||
|
if(!_functionStack.empty()) {
|
||||||
|
//Return to the previous function
|
||||||
|
ProfiledFunction& func = _functions[_currentFunction];
|
||||||
|
func.MinCycles = std::min(func.MinCycles, _currentCycleCount);
|
||||||
|
func.MaxCycles = std::max(func.MaxCycles, _currentCycleCount);
|
||||||
|
|
||||||
|
_currentFunction = _functionStack.back();
|
||||||
|
_functionStack.pop_back();
|
||||||
|
|
||||||
|
StackFrameFlags stackFlag = _stackFlags.back();
|
||||||
|
_stackFlags.pop_back();
|
||||||
|
|
||||||
|
if(stackFlag == StackFrameFlags::None) {
|
||||||
|
//Prevent IRQ/NMI from adding cycles to the calling function
|
||||||
|
//Add the subroutine's cycle count to the parent function's inclusive cycle count
|
||||||
|
//_functions[_currentFunction].InclusiveCycles += _currentCycleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add the subroutine's cycle count to the current routine's cycle count
|
||||||
|
_currentCycleCount = _cycleCountStack.top() + _currentCycleCount;
|
||||||
|
_cycleCountStack.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Profiler::Reset()
|
||||||
|
{
|
||||||
|
DebugBreakHelper helper(_debugger);
|
||||||
|
InternalReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Profiler::InternalReset()
|
||||||
|
{
|
||||||
|
_prevMasterClock = _memoryManager->GetMasterClock();
|
||||||
|
_currentCycleCount = 0;
|
||||||
|
_currentFunction = Profiler::ResetFunctionIndex;
|
||||||
|
|
||||||
|
_functions.clear();
|
||||||
|
_functions[Profiler::ResetFunctionIndex] = ProfiledFunction();
|
||||||
|
_functions[Profiler::ResetFunctionIndex].Address = { Profiler::ResetFunctionIndex, SnesMemoryType::Register };
|
||||||
|
}
|
||||||
|
|
||||||
|
void Profiler::GetProfilerData(ProfiledFunction* profilerData, uint32_t& functionCount)
|
||||||
|
{
|
||||||
|
DebugBreakHelper helper(_debugger);
|
||||||
|
|
||||||
|
UpdateCycles();
|
||||||
|
|
||||||
|
functionCount = 0;
|
||||||
|
for(auto func : _functions) {
|
||||||
|
profilerData[functionCount] = func.second;
|
||||||
|
functionCount++;
|
||||||
|
|
||||||
|
if(functionCount >= 100000) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
Core/Profiler.h
Normal file
50
Core/Profiler.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#pragma once
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <stack>
|
||||||
|
#include "DebugTypes.h"
|
||||||
|
|
||||||
|
class Debugger;
|
||||||
|
class MemoryManager;
|
||||||
|
|
||||||
|
struct ProfiledFunction
|
||||||
|
{
|
||||||
|
uint64_t ExclusiveCycles = 0;
|
||||||
|
uint64_t InclusiveCycles = 0;
|
||||||
|
uint64_t CallCount = 0;
|
||||||
|
uint64_t MinCycles = UINT64_MAX;
|
||||||
|
uint64_t MaxCycles = 0;
|
||||||
|
AddressInfo Address;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Profiler
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static constexpr int32_t ResetFunctionIndex = -1;
|
||||||
|
|
||||||
|
Debugger* _debugger;
|
||||||
|
MemoryManager* _memoryManager;
|
||||||
|
|
||||||
|
unordered_map<int32_t, ProfiledFunction> _functions;
|
||||||
|
|
||||||
|
deque<int32_t> _functionStack;
|
||||||
|
deque<StackFrameFlags> _stackFlags;
|
||||||
|
std::stack<uint64_t> _cycleCountStack;
|
||||||
|
|
||||||
|
uint64_t _currentCycleCount;
|
||||||
|
uint64_t _prevMasterClock;
|
||||||
|
int32_t _currentFunction;
|
||||||
|
|
||||||
|
void InternalReset();
|
||||||
|
void UpdateCycles();
|
||||||
|
|
||||||
|
public:
|
||||||
|
Profiler(Debugger* debugger);
|
||||||
|
~Profiler();
|
||||||
|
|
||||||
|
void StackFunction(AddressInfo& addr, StackFrameFlags stackFlag);
|
||||||
|
void UnstackFunction();
|
||||||
|
|
||||||
|
void Reset();
|
||||||
|
void GetProfilerData(ProfiledFunction* profilerData, uint32_t& functionCount);
|
||||||
|
};
|
|
@ -12,6 +12,7 @@
|
||||||
#include "MemoryAccessCounter.h"
|
#include "MemoryAccessCounter.h"
|
||||||
#include "ExpressionEvaluator.h"
|
#include "ExpressionEvaluator.h"
|
||||||
#include "EmuSettings.h"
|
#include "EmuSettings.h"
|
||||||
|
#include "Profiler.h"
|
||||||
|
|
||||||
SpcDebugger::SpcDebugger(Debugger* debugger)
|
SpcDebugger::SpcDebugger(Debugger* debugger)
|
||||||
{
|
{
|
||||||
|
@ -30,6 +31,7 @@ SpcDebugger::SpcDebugger(Debugger* debugger)
|
||||||
|
|
||||||
void SpcDebugger::Reset()
|
void SpcDebugger::Reset()
|
||||||
{
|
{
|
||||||
|
_callstackManager.reset(new CallstackManager(_debugger));
|
||||||
_prevOpCode = 0xFF;
|
_prevOpCode = 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,10 +66,12 @@ void SpcDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType
|
||||||
//JSR, BRK
|
//JSR, BRK
|
||||||
uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Spc);
|
uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Spc);
|
||||||
uint16_t returnPc = _prevProgramCounter + opSize;
|
uint16_t returnPc = _prevProgramCounter + opSize;
|
||||||
_callstackManager->Push(_prevProgramCounter, spcState.PC, returnPc, StackFrameFlags::None);
|
AddressInfo src = _spc->GetAbsoluteAddress(_prevProgramCounter);
|
||||||
|
AddressInfo ret = _spc->GetAbsoluteAddress(returnPc);
|
||||||
|
_callstackManager->Push(src, _prevProgramCounter, addressInfo, spcState.PC, ret, returnPc, StackFrameFlags::None);
|
||||||
} else if(_prevOpCode == 0x6F || _prevOpCode == 0x7F) {
|
} else if(_prevOpCode == 0x6F || _prevOpCode == 0x7F) {
|
||||||
//RTS, RTI
|
//RTS, RTI
|
||||||
_callstackManager->Pop(spcState.PC);
|
_callstackManager->Pop(addressInfo, spcState.PC);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_step->BreakAddress == (int32_t)spcState.PC && (_prevOpCode == 0x6F || _prevOpCode == 0x7F)) {
|
if(_step->BreakAddress == (int32_t)spcState.PC && (_prevOpCode == 0x6F || _prevOpCode == 0x7F)) {
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "../Core/CallstackManager.h"
|
#include "../Core/CallstackManager.h"
|
||||||
#include "../Core/LabelManager.h"
|
#include "../Core/LabelManager.h"
|
||||||
#include "../Core/ScriptManager.h"
|
#include "../Core/ScriptManager.h"
|
||||||
|
#include "../Core/Profiler.h"
|
||||||
|
|
||||||
extern shared_ptr<Console> _console;
|
extern shared_ptr<Console> _console;
|
||||||
|
|
||||||
|
@ -59,6 +60,8 @@ extern "C"
|
||||||
DllExport void __stdcall SetBreakpoints(Breakpoint breakpoints[], uint32_t length) { GetDebugger()->SetBreakpoints(breakpoints, length); }
|
DllExport void __stdcall SetBreakpoints(Breakpoint breakpoints[], uint32_t length) { GetDebugger()->SetBreakpoints(breakpoints, length); }
|
||||||
DllExport int32_t __stdcall EvaluateExpression(char* expression, CpuType cpuType, EvalResultType *resultType, bool useCache) { return GetDebugger()->EvaluateExpression(expression, cpuType, *resultType, useCache); }
|
DllExport int32_t __stdcall EvaluateExpression(char* expression, CpuType cpuType, EvalResultType *resultType, bool useCache) { return GetDebugger()->EvaluateExpression(expression, cpuType, *resultType, useCache); }
|
||||||
DllExport void __stdcall GetCallstack(CpuType cpuType, StackFrameInfo *callstackArray, uint32_t &callstackSize) { GetDebugger()->GetCallstackManager(cpuType)->GetCallstack(callstackArray, callstackSize); }
|
DllExport void __stdcall GetCallstack(CpuType cpuType, StackFrameInfo *callstackArray, uint32_t &callstackSize) { GetDebugger()->GetCallstackManager(cpuType)->GetCallstack(callstackArray, callstackSize); }
|
||||||
|
DllExport void __stdcall GetProfilerData(CpuType cpuType, ProfiledFunction* profilerData, uint32_t& functionCount) { GetDebugger()->GetCallstackManager(cpuType)->GetProfiler()->GetProfilerData(profilerData, functionCount); }
|
||||||
|
DllExport void __stdcall ResetProfiler(CpuType cpuType) { GetDebugger()->GetCallstackManager(cpuType)->GetProfiler()->Reset(); }
|
||||||
|
|
||||||
DllExport void __stdcall GetState(DebugState &state) { GetDebugger()->GetState(state, false); }
|
DllExport void __stdcall GetState(DebugState &state) { GetDebugger()->GetState(state, false); }
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace Mesen.GUI.Config
|
||||||
public SpriteViewerConfig SpriteViewer = new SpriteViewerConfig();
|
public SpriteViewerConfig SpriteViewer = new SpriteViewerConfig();
|
||||||
public DbgIntegrationConfig DbgIntegration = new DbgIntegrationConfig();
|
public DbgIntegrationConfig DbgIntegration = new DbgIntegrationConfig();
|
||||||
public ScriptWindowConfig ScriptWindow = new ScriptWindowConfig();
|
public ScriptWindowConfig ScriptWindow = new ScriptWindowConfig();
|
||||||
|
public ProfilerConfig Profiler = new ProfilerConfig();
|
||||||
|
|
||||||
public DebugInfo()
|
public DebugInfo()
|
||||||
{
|
{
|
||||||
|
|
10
UI/Debugger/Config/ProfilerConfig.cs
Normal file
10
UI/Debugger/Config/ProfilerConfig.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace Mesen.GUI.Config
|
||||||
|
{
|
||||||
|
public class ProfilerConfig
|
||||||
|
{
|
||||||
|
public Size WindowSize = new Size(0, 0);
|
||||||
|
public Point WindowLocation;
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,6 +39,7 @@ namespace Mesen.GUI.Debugger
|
||||||
case DebugWindow.EventViewer: frm = new frmEventViewer(); frm.Icon = Properties.Resources.NesEventViewer; break;
|
case DebugWindow.EventViewer: frm = new frmEventViewer(); frm.Icon = Properties.Resources.NesEventViewer; break;
|
||||||
case DebugWindow.ScriptWindow: frm = new frmScript(); frm.Icon = Properties.Resources.Script; break;
|
case DebugWindow.ScriptWindow: frm = new frmScript(); frm.Icon = Properties.Resources.Script; break;
|
||||||
case DebugWindow.RegisterViewer: frm = new frmRegisterViewer(); frm.Icon = Properties.Resources.RegisterIcon; break;
|
case DebugWindow.RegisterViewer: frm = new frmRegisterViewer(); frm.Icon = Properties.Resources.RegisterIcon; break;
|
||||||
|
case DebugWindow.Profiler: frm = new frmProfiler(); frm.Icon = Properties.Resources.PerfTracker; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_openedWindows.Count == 0) {
|
if(_openedWindows.Count == 0) {
|
||||||
|
@ -120,6 +121,7 @@ namespace Mesen.GUI.Debugger
|
||||||
case DebugWindow.GsuDebugger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmDebugger) && ((frmDebugger)form).CpuType == CpuType.Gsu);
|
case DebugWindow.GsuDebugger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmDebugger) && ((frmDebugger)form).CpuType == CpuType.Gsu);
|
||||||
case DebugWindow.TraceLogger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmTraceLogger));
|
case DebugWindow.TraceLogger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmTraceLogger));
|
||||||
case DebugWindow.EventViewer: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmEventViewer));
|
case DebugWindow.EventViewer: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmEventViewer));
|
||||||
|
case DebugWindow.Profiler: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmProfiler));
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -166,6 +168,7 @@ namespace Mesen.GUI.Debugger
|
||||||
SpriteViewer,
|
SpriteViewer,
|
||||||
EventViewer,
|
EventViewer,
|
||||||
ScriptWindow,
|
ScriptWindow,
|
||||||
RegisterViewer
|
RegisterViewer,
|
||||||
|
Profiler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,10 @@ namespace Mesen.GUI.Debugger
|
||||||
_lastUpdate = _timer.ElapsedTicks;
|
_lastUpdate = _timer.ElapsedTicks;
|
||||||
_window.RefreshData();
|
_window.RefreshData();
|
||||||
((Form)_window).BeginInvoke((Action)(() => {
|
((Form)_window).BeginInvoke((Action)(() => {
|
||||||
|
if(((Form)_window).IsDisposed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_window.RefreshViewer();
|
_window.RefreshViewer();
|
||||||
|
|
||||||
//Limit FPS to 3x time it takes for a single update (rough estimate), and cap based on requested fps.
|
//Limit FPS to 3x time it takes for a single update (rough estimate), and cap based on requested fps.
|
||||||
|
|
171
UI/Debugger/Profiler/ctrlProfiler.Designer.cs
generated
Normal file
171
UI/Debugger/Profiler/ctrlProfiler.Designer.cs
generated
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
namespace Mesen.GUI.Debugger.Controls
|
||||||
|
{
|
||||||
|
partial class ctrlProfiler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if(disposing && (components != null)) {
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Component Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||||
|
this.btnReset = new System.Windows.Forms.Button();
|
||||||
|
this.lstFunctions = new Mesen.GUI.Controls.DoubleBufferedListView();
|
||||||
|
this.colFunction = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.columnHeader5 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.colExclusiveTimePercent = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.columnHeader6 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.columnHeader7 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.tableLayoutPanel1.SuspendLayout();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// tableLayoutPanel1
|
||||||
|
//
|
||||||
|
this.tableLayoutPanel1.ColumnCount = 2;
|
||||||
|
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||||
|
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||||
|
this.tableLayoutPanel1.Controls.Add(this.btnReset, 1, 2);
|
||||||
|
this.tableLayoutPanel1.Controls.Add(this.lstFunctions, 0, 1);
|
||||||
|
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||||
|
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||||
|
this.tableLayoutPanel1.RowCount = 3;
|
||||||
|
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.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||||
|
this.tableLayoutPanel1.Size = new System.Drawing.Size(673, 307);
|
||||||
|
this.tableLayoutPanel1.TabIndex = 3;
|
||||||
|
//
|
||||||
|
// btnReset
|
||||||
|
//
|
||||||
|
this.btnReset.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnReset.Location = new System.Drawing.Point(595, 281);
|
||||||
|
this.btnReset.Name = "btnReset";
|
||||||
|
this.btnReset.Size = new System.Drawing.Size(75, 23);
|
||||||
|
this.btnReset.TabIndex = 5;
|
||||||
|
this.btnReset.Text = "Reset Counts";
|
||||||
|
this.btnReset.UseVisualStyleBackColor = true;
|
||||||
|
this.btnReset.Click += new System.EventHandler(this.btnReset_Click);
|
||||||
|
//
|
||||||
|
// lstFunctions
|
||||||
|
//
|
||||||
|
this.lstFunctions.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||||
|
this.colFunction,
|
||||||
|
this.columnHeader4,
|
||||||
|
this.columnHeader3,
|
||||||
|
this.columnHeader5,
|
||||||
|
this.columnHeader2,
|
||||||
|
this.colExclusiveTimePercent,
|
||||||
|
this.columnHeader1,
|
||||||
|
this.columnHeader6,
|
||||||
|
this.columnHeader7});
|
||||||
|
this.tableLayoutPanel1.SetColumnSpan(this.lstFunctions, 2);
|
||||||
|
this.lstFunctions.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
this.lstFunctions.FullRowSelect = true;
|
||||||
|
this.lstFunctions.GridLines = true;
|
||||||
|
this.lstFunctions.HideSelection = false;
|
||||||
|
this.lstFunctions.Location = new System.Drawing.Point(0, 0);
|
||||||
|
this.lstFunctions.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.lstFunctions.Name = "lstFunctions";
|
||||||
|
this.lstFunctions.Size = new System.Drawing.Size(673, 278);
|
||||||
|
this.lstFunctions.TabIndex = 7;
|
||||||
|
this.lstFunctions.UseCompatibleStateImageBehavior = false;
|
||||||
|
this.lstFunctions.View = System.Windows.Forms.View.Details;
|
||||||
|
this.lstFunctions.VirtualMode = true;
|
||||||
|
this.lstFunctions.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.lstFunctions_ColumnClick);
|
||||||
|
this.lstFunctions.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.lstFunctions_RetrieveVirtualItem);
|
||||||
|
this.lstFunctions.DoubleClick += new System.EventHandler(this.lstFunctions_DoubleClick);
|
||||||
|
//
|
||||||
|
// colFunction
|
||||||
|
//
|
||||||
|
this.colFunction.Text = "Function (Entry Addr)";
|
||||||
|
this.colFunction.Width = 120;
|
||||||
|
//
|
||||||
|
// columnHeader4
|
||||||
|
//
|
||||||
|
this.columnHeader4.Text = "Call Count";
|
||||||
|
//
|
||||||
|
// columnHeader3
|
||||||
|
//
|
||||||
|
this.columnHeader3.Text = "Inclusive Time (Cyc)";
|
||||||
|
this.columnHeader3.Width = 79;
|
||||||
|
//
|
||||||
|
// columnHeader5
|
||||||
|
//
|
||||||
|
this.columnHeader5.Text = "Inclusive Time (%)";
|
||||||
|
this.columnHeader5.Width = 70;
|
||||||
|
//
|
||||||
|
// columnHeader2
|
||||||
|
//
|
||||||
|
this.columnHeader2.Text = "Exclusive Time (Cyc)";
|
||||||
|
this.columnHeader2.Width = 72;
|
||||||
|
//
|
||||||
|
// colExclusiveTimePercent
|
||||||
|
//
|
||||||
|
this.colExclusiveTimePercent.Text = "Exclusive Time (%)";
|
||||||
|
this.colExclusiveTimePercent.Width = 57;
|
||||||
|
//
|
||||||
|
// columnHeader1
|
||||||
|
//
|
||||||
|
this.columnHeader1.Text = "Avg. Cycles";
|
||||||
|
//
|
||||||
|
// columnHeader6
|
||||||
|
//
|
||||||
|
this.columnHeader6.Text = "Min. Cycles";
|
||||||
|
//
|
||||||
|
// columnHeader7
|
||||||
|
//
|
||||||
|
this.columnHeader7.Text = "Max. Cycles";
|
||||||
|
//
|
||||||
|
// ctrlProfiler
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.Controls.Add(this.tableLayoutPanel1);
|
||||||
|
this.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.Name = "ctrlProfiler";
|
||||||
|
this.Size = new System.Drawing.Size(673, 307);
|
||||||
|
this.tableLayoutPanel1.ResumeLayout(false);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||||
|
private System.Windows.Forms.Button btnReset;
|
||||||
|
private Mesen.GUI.Controls.DoubleBufferedListView lstFunctions;
|
||||||
|
private System.Windows.Forms.ColumnHeader colFunction;
|
||||||
|
private System.Windows.Forms.ColumnHeader columnHeader4;
|
||||||
|
private System.Windows.Forms.ColumnHeader columnHeader2;
|
||||||
|
private System.Windows.Forms.ColumnHeader columnHeader3;
|
||||||
|
private System.Windows.Forms.ColumnHeader columnHeader5;
|
||||||
|
private System.Windows.Forms.ColumnHeader colExclusiveTimePercent;
|
||||||
|
private System.Windows.Forms.ColumnHeader columnHeader1;
|
||||||
|
private System.Windows.Forms.ColumnHeader columnHeader6;
|
||||||
|
private System.Windows.Forms.ColumnHeader columnHeader7;
|
||||||
|
}
|
||||||
|
}
|
209
UI/Debugger/Profiler/ctrlProfiler.cs
Normal file
209
UI/Debugger/Profiler/ctrlProfiler.cs
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Collections;
|
||||||
|
using Mesen.GUI.Controls;
|
||||||
|
using Mesen.GUI.Debugger.Labels;
|
||||||
|
|
||||||
|
namespace Mesen.GUI.Debugger.Controls
|
||||||
|
{
|
||||||
|
public partial class ctrlProfiler : BaseControl
|
||||||
|
{
|
||||||
|
private ProfiledFunction[] _newData = new ProfiledFunction[0];
|
||||||
|
private ProfiledFunction[] _functions = new ProfiledFunction[0];
|
||||||
|
UInt64 _exclusiveTotal = 0;
|
||||||
|
private int _sortColumn = 5;
|
||||||
|
private bool _sortOrder = true;
|
||||||
|
|
||||||
|
public CpuType CpuType { get; internal set; }
|
||||||
|
|
||||||
|
public ctrlProfiler()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnLoad(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnLoad(e);
|
||||||
|
|
||||||
|
bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
|
||||||
|
if(!designMode) {
|
||||||
|
lstFunctions.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
|
||||||
|
int newWidth = Math.Max(colFunction.Width * 2, 250);
|
||||||
|
columnHeader7.Width -= (newWidth - colFunction.Width) + 30;
|
||||||
|
colFunction.Width = newWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshData()
|
||||||
|
{
|
||||||
|
_newData = DebugApi.GetProfilerData(this.CpuType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshList()
|
||||||
|
{
|
||||||
|
_functions = _newData;
|
||||||
|
_exclusiveTotal = 0;
|
||||||
|
foreach(ProfiledFunction func in _functions) {
|
||||||
|
_exclusiveTotal += func.ExclusiveCycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
lstFunctions.BeginUpdate();
|
||||||
|
|
||||||
|
int? topItemIndex = lstFunctions.TopItem?.Index;
|
||||||
|
int selectedIndex = lstFunctions.SelectedIndices.Count > 0 ? lstFunctions.SelectedIndices[0] : -1;
|
||||||
|
|
||||||
|
Array.Sort(_functions, new ListComparer(this, _sortColumn, _sortOrder));
|
||||||
|
lstFunctions.VirtualListSize = _functions.Length;
|
||||||
|
|
||||||
|
if(topItemIndex.HasValue) {
|
||||||
|
lstFunctions.TopItem = lstFunctions.Items[topItemIndex.Value];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(selectedIndex >= 0 && _functions.Length > selectedIndex) {
|
||||||
|
lstFunctions.Items[selectedIndex].Selected = true;
|
||||||
|
lstFunctions.Items[selectedIndex].Focused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
lstFunctions.EndUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnReset_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
DebugApi.ResetProfiler(this.CpuType);
|
||||||
|
lstFunctions.Items.Clear();
|
||||||
|
RefreshData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lstFunctions_ColumnClick(object sender, ColumnClickEventArgs e)
|
||||||
|
{
|
||||||
|
if(_sortColumn == e.Column) {
|
||||||
|
_sortOrder = !_sortOrder;
|
||||||
|
} else {
|
||||||
|
_sortColumn = e.Column;
|
||||||
|
_sortOrder = e.Column == 0 ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lstFunctions_DoubleClick(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if(lstFunctions.SelectedIndices.Count > 0) {
|
||||||
|
AddressInfo relativeAddress = DebugApi.GetRelativeAddress(_functions[lstFunctions.SelectedIndices[0]].Address);
|
||||||
|
if(relativeAddress.Address >= 0) {
|
||||||
|
frmDebugger debugger = DebugWindowManager.OpenDebugger(this.CpuType);
|
||||||
|
debugger.GoToAddress(relativeAddress.Address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lstFunctions_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
|
||||||
|
{
|
||||||
|
e.Item = GetListItem(_functions[e.ItemIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ListViewItem GetListItem(ProfiledFunction func)
|
||||||
|
{
|
||||||
|
ListViewItem item = new ListViewItem(GetFunctionName(func));
|
||||||
|
item.Selected = false;
|
||||||
|
item.Focused = false;
|
||||||
|
|
||||||
|
item.SubItems.Add(GetColumnContent(func, 1).ToString());
|
||||||
|
item.SubItems.Add(GetColumnContent(func, 2).ToString());
|
||||||
|
item.SubItems.Add(((double)GetColumnContent(func, 3)).ToString("0.00"));
|
||||||
|
item.SubItems.Add(GetColumnContent(func, 4).ToString());
|
||||||
|
item.SubItems.Add(((double)GetColumnContent(func, 5)).ToString("0.00"));
|
||||||
|
item.SubItems.Add(GetColumnContent(func, 6).ToString());
|
||||||
|
item.SubItems.Add((UInt64)GetColumnContent(func, 7) == UInt64.MaxValue ? "n/a" : GetColumnContent(func, 7).ToString());
|
||||||
|
item.SubItems.Add((UInt64)GetColumnContent(func, 8) == 0 ? "n/a" : GetColumnContent(func, 8).ToString());
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFunctionName(ProfiledFunction func)
|
||||||
|
{
|
||||||
|
int hexCount = this.CpuType == CpuType.Spc ? 4 : 6;
|
||||||
|
string functionName;
|
||||||
|
|
||||||
|
if(func.Address.Address == -1) {
|
||||||
|
functionName = "[Reset]";
|
||||||
|
} else {
|
||||||
|
CodeLabel label = LabelManager.GetLabel((UInt32)func.Address.Address, func.Address.Type);
|
||||||
|
|
||||||
|
switch(func.Address.Type) {
|
||||||
|
case SnesMemoryType.PrgRom: functionName = "PRG: $"; break;
|
||||||
|
case SnesMemoryType.Register: functionName = "REG: $"; break;
|
||||||
|
case SnesMemoryType.SaveRam: functionName = "SRAM: $"; break;
|
||||||
|
case SnesMemoryType.WorkRam: functionName = "WRAM: $"; break;
|
||||||
|
case SnesMemoryType.SpcRam: functionName = "SPC: $"; break;
|
||||||
|
case SnesMemoryType.SpcRom: functionName = "SPC ROM: $"; break;
|
||||||
|
case SnesMemoryType.Sa1InternalRam: functionName = "IRAM: $"; break;
|
||||||
|
default: throw new Exception("Unsupported type");
|
||||||
|
}
|
||||||
|
|
||||||
|
functionName += func.Address.Address.ToString("X" + hexCount.ToString());
|
||||||
|
if(label != null) {
|
||||||
|
functionName = label.Label + " (" + functionName + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return functionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private object GetColumnContent(ProfiledFunction func, int columnIndex)
|
||||||
|
{
|
||||||
|
switch(columnIndex) {
|
||||||
|
case 0: return GetFunctionName(func);
|
||||||
|
case 1: return func.CallCount;
|
||||||
|
case 2: return func.InclusiveCycles;
|
||||||
|
case 3: return (double)func.InclusiveCycles / _exclusiveTotal * 100;
|
||||||
|
case 4: return func.ExclusiveCycles;
|
||||||
|
case 5: return (double)func.ExclusiveCycles / _exclusiveTotal * 100;
|
||||||
|
case 6: return func.CallCount == 0 ? 0 : (func.InclusiveCycles / func.CallCount);
|
||||||
|
case 7: return func.MinCycles;
|
||||||
|
case 8: return func.MaxCycles;
|
||||||
|
}
|
||||||
|
throw new Exception("Invalid column index");
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ListComparer : IComparer<ProfiledFunction>
|
||||||
|
{
|
||||||
|
private int _columnIndex;
|
||||||
|
private bool _sortOrder;
|
||||||
|
private ctrlProfiler _profiler;
|
||||||
|
|
||||||
|
public ListComparer(ctrlProfiler profiler, int columnIndex, bool sortOrder)
|
||||||
|
{
|
||||||
|
_profiler = profiler;
|
||||||
|
_columnIndex = columnIndex;
|
||||||
|
_sortOrder = sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Compare(ProfiledFunction x, ProfiledFunction y)
|
||||||
|
{
|
||||||
|
if(_columnIndex == 0) {
|
||||||
|
if(_sortOrder) {
|
||||||
|
return String.Compare(_profiler.GetFunctionName(y), _profiler.GetFunctionName(x));
|
||||||
|
} else {
|
||||||
|
return String.Compare(_profiler.GetFunctionName(x), _profiler.GetFunctionName(y));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
IComparable columnValueY = (IComparable)_profiler.GetColumnContent(x, _columnIndex);
|
||||||
|
IComparable columnValueX = (IComparable)_profiler.GetColumnContent(y, _columnIndex);
|
||||||
|
if(_sortOrder) {
|
||||||
|
return columnValueX.CompareTo(columnValueY);
|
||||||
|
} else {
|
||||||
|
return columnValueY.CompareTo(columnValueX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
120
UI/Debugger/Profiler/ctrlProfiler.resx
Normal file
120
UI/Debugger/Profiler/ctrlProfiler.resx
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
119
UI/Debugger/Profiler/frmProfiler.Designer.cs
generated
Normal file
119
UI/Debugger/Profiler/frmProfiler.Designer.cs
generated
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
namespace Mesen.GUI.Debugger
|
||||||
|
{
|
||||||
|
partial class frmProfiler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if(disposing && (components != null)) {
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
_refreshManager?.Dispose();
|
||||||
|
_notifListener?.Dispose();
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.ctrlProfiler = new Mesen.GUI.Debugger.Controls.ctrlProfiler();
|
||||||
|
this.tabMain = new System.Windows.Forms.TabControl();
|
||||||
|
this.tpgCpu = new System.Windows.Forms.TabPage();
|
||||||
|
this.tpgSpc = new System.Windows.Forms.TabPage();
|
||||||
|
this.ctrlProfilerSpc = new Mesen.GUI.Debugger.Controls.ctrlProfiler();
|
||||||
|
this.tabMain.SuspendLayout();
|
||||||
|
this.tpgCpu.SuspendLayout();
|
||||||
|
this.tpgSpc.SuspendLayout();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// ctrlProfiler
|
||||||
|
//
|
||||||
|
this.ctrlProfiler.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
this.ctrlProfiler.Location = new System.Drawing.Point(0, 0);
|
||||||
|
this.ctrlProfiler.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.ctrlProfiler.Name = "ctrlProfiler";
|
||||||
|
this.ctrlProfiler.Size = new System.Drawing.Size(657, 359);
|
||||||
|
this.ctrlProfiler.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// tabMain
|
||||||
|
//
|
||||||
|
this.tabMain.Controls.Add(this.tpgCpu);
|
||||||
|
this.tabMain.Controls.Add(this.tpgSpc);
|
||||||
|
this.tabMain.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
this.tabMain.Location = new System.Drawing.Point(0, 0);
|
||||||
|
this.tabMain.Name = "tabMain";
|
||||||
|
this.tabMain.SelectedIndex = 0;
|
||||||
|
this.tabMain.Size = new System.Drawing.Size(665, 385);
|
||||||
|
this.tabMain.TabIndex = 2;
|
||||||
|
this.tabMain.SelectedIndexChanged += new System.EventHandler(this.tabMain_SelectedIndexChanged);
|
||||||
|
//
|
||||||
|
// tpgCpu
|
||||||
|
//
|
||||||
|
this.tpgCpu.Controls.Add(this.ctrlProfiler);
|
||||||
|
this.tpgCpu.Location = new System.Drawing.Point(4, 22);
|
||||||
|
this.tpgCpu.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.tpgCpu.Name = "tpgCpu";
|
||||||
|
this.tpgCpu.Size = new System.Drawing.Size(657, 359);
|
||||||
|
this.tpgCpu.TabIndex = 0;
|
||||||
|
this.tpgCpu.Text = "CPU";
|
||||||
|
this.tpgCpu.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// tpgSpc
|
||||||
|
//
|
||||||
|
this.tpgSpc.Controls.Add(this.ctrlProfilerSpc);
|
||||||
|
this.tpgSpc.Location = new System.Drawing.Point(4, 22);
|
||||||
|
this.tpgSpc.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.tpgSpc.Name = "tpgSpc";
|
||||||
|
this.tpgSpc.Size = new System.Drawing.Size(657, 359);
|
||||||
|
this.tpgSpc.TabIndex = 1;
|
||||||
|
this.tpgSpc.Text = "SPC";
|
||||||
|
this.tpgSpc.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// ctrlProfilerSpc
|
||||||
|
//
|
||||||
|
this.ctrlProfilerSpc.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
this.ctrlProfilerSpc.Location = new System.Drawing.Point(0, 0);
|
||||||
|
this.ctrlProfilerSpc.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.ctrlProfilerSpc.Name = "ctrlProfilerSpc";
|
||||||
|
this.ctrlProfilerSpc.Size = new System.Drawing.Size(657, 359);
|
||||||
|
this.ctrlProfilerSpc.TabIndex = 2;
|
||||||
|
//
|
||||||
|
// frmProfiler
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.ClientSize = new System.Drawing.Size(665, 385);
|
||||||
|
this.Controls.Add(this.tabMain);
|
||||||
|
this.Name = "frmProfiler";
|
||||||
|
this.Text = "Performance Profiler";
|
||||||
|
this.Controls.SetChildIndex(this.tabMain, 0);
|
||||||
|
this.tabMain.ResumeLayout(false);
|
||||||
|
this.tpgCpu.ResumeLayout(false);
|
||||||
|
this.tpgSpc.ResumeLayout(false);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private Controls.ctrlProfiler ctrlProfiler;
|
||||||
|
private System.Windows.Forms.TabControl tabMain;
|
||||||
|
private System.Windows.Forms.TabPage tpgCpu;
|
||||||
|
private System.Windows.Forms.TabPage tpgSpc;
|
||||||
|
private Controls.ctrlProfiler ctrlProfilerSpc;
|
||||||
|
}
|
||||||
|
}
|
126
UI/Debugger/Profiler/frmProfiler.cs
Normal file
126
UI/Debugger/Profiler/frmProfiler.cs
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
using Mesen.GUI.Config;
|
||||||
|
using Mesen.GUI.Debugger.Controls;
|
||||||
|
using Mesen.GUI.Forms;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace Mesen.GUI.Debugger
|
||||||
|
{
|
||||||
|
public partial class frmProfiler : BaseForm, IRefresh
|
||||||
|
{
|
||||||
|
private ctrlProfiler ctrlProfilerCoprocessor = new ctrlProfiler();
|
||||||
|
private WindowRefreshManager _refreshManager;
|
||||||
|
private NotificationListener _notifListener;
|
||||||
|
private TabPage _selectedTab;
|
||||||
|
private int _frameCount = 0;
|
||||||
|
|
||||||
|
public ctrlScanlineCycleSelect ScanlineCycleSelect => null;
|
||||||
|
|
||||||
|
public frmProfiler()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
if(!DesignMode) {
|
||||||
|
ProfilerConfig cfg = ConfigManager.Config.Debug.Profiler;
|
||||||
|
RestoreLocation(cfg.WindowLocation, cfg.WindowSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnLoad(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnLoad(e);
|
||||||
|
|
||||||
|
ctrlProfiler.CpuType = CpuType.Cpu;
|
||||||
|
ctrlProfilerSpc.CpuType = CpuType.Spc;
|
||||||
|
|
||||||
|
_selectedTab = tpgCpu;
|
||||||
|
UpdateAvailableTabs();
|
||||||
|
RefreshData();
|
||||||
|
RefreshViewer();
|
||||||
|
|
||||||
|
_refreshManager = new WindowRefreshManager(this);
|
||||||
|
_refreshManager.AutoRefresh = true;
|
||||||
|
_refreshManager.AutoRefreshSpeed = RefreshSpeed.Low;
|
||||||
|
|
||||||
|
_notifListener = new NotificationListener();
|
||||||
|
_notifListener.OnNotification += OnNotificationReceived;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnNotificationReceived(NotificationEventArgs e)
|
||||||
|
{
|
||||||
|
switch(e.NotificationType) {
|
||||||
|
case ConsoleNotificationType.GameLoaded:
|
||||||
|
_selectedTab = tpgCpu;
|
||||||
|
this.BeginInvoke((Action)(() => {
|
||||||
|
UpdateAvailableTabs();
|
||||||
|
}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshData()
|
||||||
|
{
|
||||||
|
if(_selectedTab == tpgCpu) {
|
||||||
|
ctrlProfiler.RefreshData();
|
||||||
|
} else if(_selectedTab == tpgSpc) {
|
||||||
|
ctrlProfilerSpc.RefreshData();
|
||||||
|
} else {
|
||||||
|
ctrlProfilerCoprocessor.RefreshData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshViewer()
|
||||||
|
{
|
||||||
|
if(_selectedTab == tpgCpu) {
|
||||||
|
ctrlProfiler.RefreshList();
|
||||||
|
} else if(_selectedTab == tpgSpc) {
|
||||||
|
ctrlProfilerSpc.RefreshList();
|
||||||
|
} else {
|
||||||
|
ctrlProfilerCoprocessor.RefreshList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateAvailableTabs()
|
||||||
|
{
|
||||||
|
if(tabMain.Controls.Count > 2) {
|
||||||
|
tabMain.Controls.RemoveAt(2);
|
||||||
|
}
|
||||||
|
tabMain.SelectedTab = tpgCpu;
|
||||||
|
_selectedTab = tpgCpu;
|
||||||
|
|
||||||
|
if(EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.SA1) {
|
||||||
|
TabPage coprocessorTab = new TabPage(ResourceHelper.GetEnumText(CoprocessorType.SA1));
|
||||||
|
tabMain.TabPages.Add(coprocessorTab);
|
||||||
|
|
||||||
|
coprocessorTab.Controls.Add(ctrlProfilerCoprocessor);
|
||||||
|
ctrlProfilerCoprocessor.Dock = DockStyle.Fill;
|
||||||
|
ctrlProfilerCoprocessor.CpuType = CpuType.Sa1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFormClosing(FormClosingEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnFormClosing(e);
|
||||||
|
|
||||||
|
ProfilerConfig cfg = ConfigManager.Config.Debug.Profiler;
|
||||||
|
|
||||||
|
cfg.WindowSize = this.WindowState != FormWindowState.Normal ? this.RestoreBounds.Size : this.Size;
|
||||||
|
cfg.WindowLocation = this.WindowState != FormWindowState.Normal ? this.RestoreBounds.Location : this.Location;
|
||||||
|
ConfigManager.ApplyChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tabMain_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
_selectedTab = tabMain.SelectedTab;
|
||||||
|
RefreshData();
|
||||||
|
RefreshViewer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
123
UI/Debugger/Profiler/frmProfiler.resx
Normal file
123
UI/Debugger/Profiler/frmProfiler.resx
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>17, 17</value>
|
||||||
|
</metadata>
|
||||||
|
</root>
|
|
@ -48,7 +48,7 @@ namespace Mesen.GUI.Debugger
|
||||||
GetMember(nameof(DebuggerShortcutsConfig.OpenEventViewer)),
|
GetMember(nameof(DebuggerShortcutsConfig.OpenEventViewer)),
|
||||||
GetMember(nameof(DebuggerShortcutsConfig.OpenMemoryTools)),
|
GetMember(nameof(DebuggerShortcutsConfig.OpenMemoryTools)),
|
||||||
GetMember(nameof(DebuggerShortcutsConfig.OpenRegisterViewer)),
|
GetMember(nameof(DebuggerShortcutsConfig.OpenRegisterViewer)),
|
||||||
//GetMember(nameof(DebuggerShortcutsConfig.OpenProfiler)),
|
GetMember(nameof(DebuggerShortcutsConfig.OpenProfiler)),
|
||||||
GetMember(nameof(DebuggerShortcutsConfig.OpenScriptWindow)),
|
GetMember(nameof(DebuggerShortcutsConfig.OpenScriptWindow)),
|
||||||
GetMember(nameof(DebuggerShortcutsConfig.OpenTraceLogger)),
|
GetMember(nameof(DebuggerShortcutsConfig.OpenTraceLogger)),
|
||||||
//GetMember(nameof(DebuggerShortcutsConfig.OpenWatchWindow)),
|
//GetMember(nameof(DebuggerShortcutsConfig.OpenWatchWindow)),
|
||||||
|
|
|
@ -18,6 +18,7 @@ namespace Mesen.GUI.Debugger
|
||||||
private NotificationListener _notifListener;
|
private NotificationListener _notifListener;
|
||||||
private CpuType _cpuType;
|
private CpuType _cpuType;
|
||||||
private bool _firstBreak = true;
|
private bool _firstBreak = true;
|
||||||
|
private int _destAddress = -1;
|
||||||
|
|
||||||
public CpuType CpuType { get { return _cpuType; } }
|
public CpuType CpuType { get { return _cpuType; } }
|
||||||
|
|
||||||
|
@ -331,7 +332,11 @@ namespace Mesen.GUI.Debugger
|
||||||
|
|
||||||
public void GoToAddress(int address)
|
public void GoToAddress(int address)
|
||||||
{
|
{
|
||||||
ctrlDisassemblyView.ScrollToAddress((uint)address);
|
if(_firstBreak) {
|
||||||
|
_destAddress = address;
|
||||||
|
} else {
|
||||||
|
ctrlDisassemblyView.ScrollToAddress((uint)address);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GoToAddress()
|
private void GoToAddress()
|
||||||
|
@ -468,10 +473,15 @@ namespace Mesen.GUI.Debugger
|
||||||
this.BeginInvoke((MethodInvoker)(() => {
|
this.BeginInvoke((MethodInvoker)(() => {
|
||||||
ProcessBreakEvent(evt, state, activeAddress);
|
ProcessBreakEvent(evt, state, activeAddress);
|
||||||
|
|
||||||
if(_firstBreak && !ConfigManager.Config.Debug.Debugger.BreakOnOpen) {
|
if(_firstBreak) {
|
||||||
DebugApi.ResumeExecution();
|
_firstBreak = false;
|
||||||
|
if(!ConfigManager.Config.Debug.Debugger.BreakOnOpen) {
|
||||||
|
DebugApi.ResumeExecution();
|
||||||
|
}
|
||||||
|
if(_destAddress >= 0) {
|
||||||
|
GoToAddress(_destAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_firstBreak = false;
|
|
||||||
}));
|
}));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
252
UI/Forms/frmMain.Designer.cs
generated
252
UI/Forms/frmMain.Designer.cs
generated
|
@ -117,6 +117,19 @@
|
||||||
this.mnuPlayMovie = new System.Windows.Forms.ToolStripMenuItem();
|
this.mnuPlayMovie = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.mnuRecordMovie = new System.Windows.Forms.ToolStripMenuItem();
|
this.mnuRecordMovie = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.mnuStopMovie = new System.Windows.Forms.ToolStripMenuItem();
|
this.mnuStopMovie = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
this.mnuNetPlay = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
this.mnuStartServer = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
this.mnuConnect = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
this.mnuNetPlaySelectController = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
this.mnuNetPlayPlayer1 = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
this.mnuNetPlayPlayer2 = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
this.mnuNetPlayPlayer3 = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
this.mnuNetPlayPlayer4 = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
this.mnuNetPlayPlayer5 = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
|
||||||
|
this.mnuNetPlaySpectator = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
||||||
|
this.mnuProfile = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.toolStripMenuItem25 = new System.Windows.Forms.ToolStripSeparator();
|
this.toolStripMenuItem25 = new System.Windows.Forms.ToolStripSeparator();
|
||||||
this.mnuSoundRecorder = new System.Windows.Forms.ToolStripMenuItem();
|
this.mnuSoundRecorder = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.mnuWaveRecord = new System.Windows.Forms.ToolStripMenuItem();
|
this.mnuWaveRecord = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
@ -158,19 +171,7 @@
|
||||||
this.mnuAbout = new System.Windows.Forms.ToolStripMenuItem();
|
this.mnuAbout = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.pnlRenderer = new System.Windows.Forms.Panel();
|
this.pnlRenderer = new System.Windows.Forms.Panel();
|
||||||
this.ctrlRecentGames = new Mesen.GUI.Controls.ctrlRecentGames();
|
this.ctrlRecentGames = new Mesen.GUI.Controls.ctrlRecentGames();
|
||||||
this.mnuNetPlay = new System.Windows.Forms.ToolStripMenuItem();
|
this.mnuProfiler = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.mnuStartServer = new System.Windows.Forms.ToolStripMenuItem();
|
|
||||||
this.mnuConnect = new System.Windows.Forms.ToolStripMenuItem();
|
|
||||||
this.mnuNetPlaySelectController = new System.Windows.Forms.ToolStripMenuItem();
|
|
||||||
this.mnuNetPlayPlayer1 = new System.Windows.Forms.ToolStripMenuItem();
|
|
||||||
this.mnuNetPlayPlayer2 = new System.Windows.Forms.ToolStripMenuItem();
|
|
||||||
this.mnuNetPlayPlayer3 = new System.Windows.Forms.ToolStripMenuItem();
|
|
||||||
this.mnuNetPlayPlayer4 = new System.Windows.Forms.ToolStripMenuItem();
|
|
||||||
this.mnuNetPlayPlayer5 = new System.Windows.Forms.ToolStripMenuItem();
|
|
||||||
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
|
|
||||||
this.mnuNetPlaySpectator = new System.Windows.Forms.ToolStripMenuItem();
|
|
||||||
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
|
||||||
this.mnuProfile = new System.Windows.Forms.ToolStripMenuItem();
|
|
||||||
this.mnuMain.SuspendLayout();
|
this.mnuMain.SuspendLayout();
|
||||||
this.pnlRenderer.SuspendLayout();
|
this.pnlRenderer.SuspendLayout();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
|
@ -840,7 +841,7 @@
|
||||||
//
|
//
|
||||||
this.mnuPlayMovie.Image = global::Mesen.GUI.Properties.Resources.MediaPlay;
|
this.mnuPlayMovie.Image = global::Mesen.GUI.Properties.Resources.MediaPlay;
|
||||||
this.mnuPlayMovie.Name = "mnuPlayMovie";
|
this.mnuPlayMovie.Name = "mnuPlayMovie";
|
||||||
this.mnuPlayMovie.Size = new System.Drawing.Size(152, 22);
|
this.mnuPlayMovie.Size = new System.Drawing.Size(120, 22);
|
||||||
this.mnuPlayMovie.Text = "Play...";
|
this.mnuPlayMovie.Text = "Play...";
|
||||||
this.mnuPlayMovie.Click += new System.EventHandler(this.mnuPlayMovie_Click);
|
this.mnuPlayMovie.Click += new System.EventHandler(this.mnuPlayMovie_Click);
|
||||||
//
|
//
|
||||||
|
@ -848,7 +849,7 @@
|
||||||
//
|
//
|
||||||
this.mnuRecordMovie.Image = global::Mesen.GUI.Properties.Resources.Record;
|
this.mnuRecordMovie.Image = global::Mesen.GUI.Properties.Resources.Record;
|
||||||
this.mnuRecordMovie.Name = "mnuRecordMovie";
|
this.mnuRecordMovie.Name = "mnuRecordMovie";
|
||||||
this.mnuRecordMovie.Size = new System.Drawing.Size(152, 22);
|
this.mnuRecordMovie.Size = new System.Drawing.Size(120, 22);
|
||||||
this.mnuRecordMovie.Text = "Record...";
|
this.mnuRecordMovie.Text = "Record...";
|
||||||
this.mnuRecordMovie.Click += new System.EventHandler(this.mnuRecordMovie_Click);
|
this.mnuRecordMovie.Click += new System.EventHandler(this.mnuRecordMovie_Click);
|
||||||
//
|
//
|
||||||
|
@ -856,10 +857,101 @@
|
||||||
//
|
//
|
||||||
this.mnuStopMovie.Image = global::Mesen.GUI.Properties.Resources.MediaStop;
|
this.mnuStopMovie.Image = global::Mesen.GUI.Properties.Resources.MediaStop;
|
||||||
this.mnuStopMovie.Name = "mnuStopMovie";
|
this.mnuStopMovie.Name = "mnuStopMovie";
|
||||||
this.mnuStopMovie.Size = new System.Drawing.Size(152, 22);
|
this.mnuStopMovie.Size = new System.Drawing.Size(120, 22);
|
||||||
this.mnuStopMovie.Text = "Stop";
|
this.mnuStopMovie.Text = "Stop";
|
||||||
this.mnuStopMovie.Click += new System.EventHandler(this.mnuStopMovie_Click);
|
this.mnuStopMovie.Click += new System.EventHandler(this.mnuStopMovie_Click);
|
||||||
//
|
//
|
||||||
|
// mnuNetPlay
|
||||||
|
//
|
||||||
|
this.mnuNetPlay.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||||
|
this.mnuStartServer,
|
||||||
|
this.mnuConnect,
|
||||||
|
this.mnuNetPlaySelectController,
|
||||||
|
this.toolStripSeparator2,
|
||||||
|
this.mnuProfile});
|
||||||
|
this.mnuNetPlay.Image = global::Mesen.GUI.Properties.Resources.Network;
|
||||||
|
this.mnuNetPlay.Name = "mnuNetPlay";
|
||||||
|
this.mnuNetPlay.Size = new System.Drawing.Size(182, 22);
|
||||||
|
this.mnuNetPlay.Text = "Net Play";
|
||||||
|
//
|
||||||
|
// mnuStartServer
|
||||||
|
//
|
||||||
|
this.mnuStartServer.Name = "mnuStartServer";
|
||||||
|
this.mnuStartServer.Size = new System.Drawing.Size(168, 22);
|
||||||
|
this.mnuStartServer.Text = "Start Server";
|
||||||
|
//
|
||||||
|
// mnuConnect
|
||||||
|
//
|
||||||
|
this.mnuConnect.Name = "mnuConnect";
|
||||||
|
this.mnuConnect.Size = new System.Drawing.Size(168, 22);
|
||||||
|
this.mnuConnect.Text = "Connect to Server";
|
||||||
|
//
|
||||||
|
// mnuNetPlaySelectController
|
||||||
|
//
|
||||||
|
this.mnuNetPlaySelectController.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||||
|
this.mnuNetPlayPlayer1,
|
||||||
|
this.mnuNetPlayPlayer2,
|
||||||
|
this.mnuNetPlayPlayer3,
|
||||||
|
this.mnuNetPlayPlayer4,
|
||||||
|
this.mnuNetPlayPlayer5,
|
||||||
|
this.toolStripSeparator1,
|
||||||
|
this.mnuNetPlaySpectator});
|
||||||
|
this.mnuNetPlaySelectController.Name = "mnuNetPlaySelectController";
|
||||||
|
this.mnuNetPlaySelectController.Size = new System.Drawing.Size(168, 22);
|
||||||
|
this.mnuNetPlaySelectController.Text = "Select Controller";
|
||||||
|
//
|
||||||
|
// mnuNetPlayPlayer1
|
||||||
|
//
|
||||||
|
this.mnuNetPlayPlayer1.Name = "mnuNetPlayPlayer1";
|
||||||
|
this.mnuNetPlayPlayer1.Size = new System.Drawing.Size(124, 22);
|
||||||
|
this.mnuNetPlayPlayer1.Text = "Player 1";
|
||||||
|
//
|
||||||
|
// mnuNetPlayPlayer2
|
||||||
|
//
|
||||||
|
this.mnuNetPlayPlayer2.Name = "mnuNetPlayPlayer2";
|
||||||
|
this.mnuNetPlayPlayer2.Size = new System.Drawing.Size(124, 22);
|
||||||
|
this.mnuNetPlayPlayer2.Text = "Player 2";
|
||||||
|
//
|
||||||
|
// mnuNetPlayPlayer3
|
||||||
|
//
|
||||||
|
this.mnuNetPlayPlayer3.Name = "mnuNetPlayPlayer3";
|
||||||
|
this.mnuNetPlayPlayer3.Size = new System.Drawing.Size(124, 22);
|
||||||
|
this.mnuNetPlayPlayer3.Text = "Player 3";
|
||||||
|
//
|
||||||
|
// mnuNetPlayPlayer4
|
||||||
|
//
|
||||||
|
this.mnuNetPlayPlayer4.Name = "mnuNetPlayPlayer4";
|
||||||
|
this.mnuNetPlayPlayer4.Size = new System.Drawing.Size(124, 22);
|
||||||
|
this.mnuNetPlayPlayer4.Text = "Player 4";
|
||||||
|
//
|
||||||
|
// mnuNetPlayPlayer5
|
||||||
|
//
|
||||||
|
this.mnuNetPlayPlayer5.Name = "mnuNetPlayPlayer5";
|
||||||
|
this.mnuNetPlayPlayer5.Size = new System.Drawing.Size(124, 22);
|
||||||
|
this.mnuNetPlayPlayer5.Text = "Player 5";
|
||||||
|
//
|
||||||
|
// toolStripSeparator1
|
||||||
|
//
|
||||||
|
this.toolStripSeparator1.Name = "toolStripSeparator1";
|
||||||
|
this.toolStripSeparator1.Size = new System.Drawing.Size(121, 6);
|
||||||
|
//
|
||||||
|
// mnuNetPlaySpectator
|
||||||
|
//
|
||||||
|
this.mnuNetPlaySpectator.Name = "mnuNetPlaySpectator";
|
||||||
|
this.mnuNetPlaySpectator.Size = new System.Drawing.Size(124, 22);
|
||||||
|
this.mnuNetPlaySpectator.Text = "Spectator";
|
||||||
|
//
|
||||||
|
// toolStripSeparator2
|
||||||
|
//
|
||||||
|
this.toolStripSeparator2.Name = "toolStripSeparator2";
|
||||||
|
this.toolStripSeparator2.Size = new System.Drawing.Size(165, 6);
|
||||||
|
//
|
||||||
|
// mnuProfile
|
||||||
|
//
|
||||||
|
this.mnuProfile.Name = "mnuProfile";
|
||||||
|
this.mnuProfile.Size = new System.Drawing.Size(168, 22);
|
||||||
|
this.mnuProfile.Text = "Configure Profile";
|
||||||
|
//
|
||||||
// toolStripMenuItem25
|
// toolStripMenuItem25
|
||||||
//
|
//
|
||||||
this.toolStripMenuItem25.Name = "toolStripMenuItem25";
|
this.toolStripMenuItem25.Name = "toolStripMenuItem25";
|
||||||
|
@ -990,6 +1082,7 @@
|
||||||
this.mnuDebugger,
|
this.mnuDebugger,
|
||||||
this.mnuEventViewer,
|
this.mnuEventViewer,
|
||||||
this.mnuMemoryTools,
|
this.mnuMemoryTools,
|
||||||
|
this.mnuProfiler,
|
||||||
this.mnuRegisterViewer,
|
this.mnuRegisterViewer,
|
||||||
this.mnuScriptWindow,
|
this.mnuScriptWindow,
|
||||||
this.mnuTraceLogger,
|
this.mnuTraceLogger,
|
||||||
|
@ -1012,101 +1105,101 @@
|
||||||
//
|
//
|
||||||
this.mnuDebugger.Image = global::Mesen.GUI.Properties.Resources.Debugger;
|
this.mnuDebugger.Image = global::Mesen.GUI.Properties.Resources.Debugger;
|
||||||
this.mnuDebugger.Name = "mnuDebugger";
|
this.mnuDebugger.Name = "mnuDebugger";
|
||||||
this.mnuDebugger.Size = new System.Drawing.Size(155, 22);
|
this.mnuDebugger.Size = new System.Drawing.Size(183, 22);
|
||||||
this.mnuDebugger.Text = "Debugger";
|
this.mnuDebugger.Text = "Debugger";
|
||||||
//
|
//
|
||||||
// mnuEventViewer
|
// mnuEventViewer
|
||||||
//
|
//
|
||||||
this.mnuEventViewer.Image = global::Mesen.GUI.Properties.Resources.NesEventViewer;
|
this.mnuEventViewer.Image = global::Mesen.GUI.Properties.Resources.NesEventViewer;
|
||||||
this.mnuEventViewer.Name = "mnuEventViewer";
|
this.mnuEventViewer.Name = "mnuEventViewer";
|
||||||
this.mnuEventViewer.Size = new System.Drawing.Size(155, 22);
|
this.mnuEventViewer.Size = new System.Drawing.Size(183, 22);
|
||||||
this.mnuEventViewer.Text = "Event Viewer";
|
this.mnuEventViewer.Text = "Event Viewer";
|
||||||
//
|
//
|
||||||
// mnuMemoryTools
|
// mnuMemoryTools
|
||||||
//
|
//
|
||||||
this.mnuMemoryTools.Image = global::Mesen.GUI.Properties.Resources.CheatCode;
|
this.mnuMemoryTools.Image = global::Mesen.GUI.Properties.Resources.CheatCode;
|
||||||
this.mnuMemoryTools.Name = "mnuMemoryTools";
|
this.mnuMemoryTools.Name = "mnuMemoryTools";
|
||||||
this.mnuMemoryTools.Size = new System.Drawing.Size(155, 22);
|
this.mnuMemoryTools.Size = new System.Drawing.Size(183, 22);
|
||||||
this.mnuMemoryTools.Text = "Memory Tools";
|
this.mnuMemoryTools.Text = "Memory Tools";
|
||||||
//
|
//
|
||||||
// mnuRegisterViewer
|
// mnuRegisterViewer
|
||||||
//
|
//
|
||||||
this.mnuRegisterViewer.Image = global::Mesen.GUI.Properties.Resources.RegisterIcon;
|
this.mnuRegisterViewer.Image = global::Mesen.GUI.Properties.Resources.RegisterIcon;
|
||||||
this.mnuRegisterViewer.Name = "mnuRegisterViewer";
|
this.mnuRegisterViewer.Name = "mnuRegisterViewer";
|
||||||
this.mnuRegisterViewer.Size = new System.Drawing.Size(155, 22);
|
this.mnuRegisterViewer.Size = new System.Drawing.Size(183, 22);
|
||||||
this.mnuRegisterViewer.Text = "Register Viewer";
|
this.mnuRegisterViewer.Text = "Register Viewer";
|
||||||
//
|
//
|
||||||
// mnuScriptWindow
|
// mnuScriptWindow
|
||||||
//
|
//
|
||||||
this.mnuScriptWindow.Image = global::Mesen.GUI.Properties.Resources.Script;
|
this.mnuScriptWindow.Image = global::Mesen.GUI.Properties.Resources.Script;
|
||||||
this.mnuScriptWindow.Name = "mnuScriptWindow";
|
this.mnuScriptWindow.Name = "mnuScriptWindow";
|
||||||
this.mnuScriptWindow.Size = new System.Drawing.Size(155, 22);
|
this.mnuScriptWindow.Size = new System.Drawing.Size(183, 22);
|
||||||
this.mnuScriptWindow.Text = "Script Window";
|
this.mnuScriptWindow.Text = "Script Window";
|
||||||
//
|
//
|
||||||
// mnuTraceLogger
|
// mnuTraceLogger
|
||||||
//
|
//
|
||||||
this.mnuTraceLogger.Image = global::Mesen.GUI.Properties.Resources.LogWindow;
|
this.mnuTraceLogger.Image = global::Mesen.GUI.Properties.Resources.LogWindow;
|
||||||
this.mnuTraceLogger.Name = "mnuTraceLogger";
|
this.mnuTraceLogger.Name = "mnuTraceLogger";
|
||||||
this.mnuTraceLogger.Size = new System.Drawing.Size(155, 22);
|
this.mnuTraceLogger.Size = new System.Drawing.Size(183, 22);
|
||||||
this.mnuTraceLogger.Text = "Trace Logger";
|
this.mnuTraceLogger.Text = "Trace Logger";
|
||||||
//
|
//
|
||||||
// toolStripMenuItem12
|
// toolStripMenuItem12
|
||||||
//
|
//
|
||||||
this.toolStripMenuItem12.Name = "toolStripMenuItem12";
|
this.toolStripMenuItem12.Name = "toolStripMenuItem12";
|
||||||
this.toolStripMenuItem12.Size = new System.Drawing.Size(152, 6);
|
this.toolStripMenuItem12.Size = new System.Drawing.Size(180, 6);
|
||||||
//
|
//
|
||||||
// mnuTilemapViewer
|
// mnuTilemapViewer
|
||||||
//
|
//
|
||||||
this.mnuTilemapViewer.Image = global::Mesen.GUI.Properties.Resources.VideoOptions;
|
this.mnuTilemapViewer.Image = global::Mesen.GUI.Properties.Resources.VideoOptions;
|
||||||
this.mnuTilemapViewer.Name = "mnuTilemapViewer";
|
this.mnuTilemapViewer.Name = "mnuTilemapViewer";
|
||||||
this.mnuTilemapViewer.Size = new System.Drawing.Size(155, 22);
|
this.mnuTilemapViewer.Size = new System.Drawing.Size(183, 22);
|
||||||
this.mnuTilemapViewer.Text = "Tilemap Viewer";
|
this.mnuTilemapViewer.Text = "Tilemap Viewer";
|
||||||
//
|
//
|
||||||
// mnuTileViewer
|
// mnuTileViewer
|
||||||
//
|
//
|
||||||
this.mnuTileViewer.Image = global::Mesen.GUI.Properties.Resources.VerticalLayout;
|
this.mnuTileViewer.Image = global::Mesen.GUI.Properties.Resources.VerticalLayout;
|
||||||
this.mnuTileViewer.Name = "mnuTileViewer";
|
this.mnuTileViewer.Name = "mnuTileViewer";
|
||||||
this.mnuTileViewer.Size = new System.Drawing.Size(155, 22);
|
this.mnuTileViewer.Size = new System.Drawing.Size(183, 22);
|
||||||
this.mnuTileViewer.Text = "Tile Viewer";
|
this.mnuTileViewer.Text = "Tile Viewer";
|
||||||
//
|
//
|
||||||
// mnuSpriteViewer
|
// mnuSpriteViewer
|
||||||
//
|
//
|
||||||
this.mnuSpriteViewer.Image = global::Mesen.GUI.Properties.Resources.PerfTracker;
|
this.mnuSpriteViewer.Image = global::Mesen.GUI.Properties.Resources.PerfTracker;
|
||||||
this.mnuSpriteViewer.Name = "mnuSpriteViewer";
|
this.mnuSpriteViewer.Name = "mnuSpriteViewer";
|
||||||
this.mnuSpriteViewer.Size = new System.Drawing.Size(155, 22);
|
this.mnuSpriteViewer.Size = new System.Drawing.Size(183, 22);
|
||||||
this.mnuSpriteViewer.Text = "Sprite Viewer";
|
this.mnuSpriteViewer.Text = "Sprite Viewer";
|
||||||
//
|
//
|
||||||
// mnuPaletteViewer
|
// mnuPaletteViewer
|
||||||
//
|
//
|
||||||
this.mnuPaletteViewer.Image = global::Mesen.GUI.Properties.Resources.VideoFilter;
|
this.mnuPaletteViewer.Image = global::Mesen.GUI.Properties.Resources.VideoFilter;
|
||||||
this.mnuPaletteViewer.Name = "mnuPaletteViewer";
|
this.mnuPaletteViewer.Name = "mnuPaletteViewer";
|
||||||
this.mnuPaletteViewer.Size = new System.Drawing.Size(155, 22);
|
this.mnuPaletteViewer.Size = new System.Drawing.Size(183, 22);
|
||||||
this.mnuPaletteViewer.Text = "Palette Viewer";
|
this.mnuPaletteViewer.Text = "Palette Viewer";
|
||||||
//
|
//
|
||||||
// toolStripMenuItem22
|
// toolStripMenuItem22
|
||||||
//
|
//
|
||||||
this.toolStripMenuItem22.Name = "toolStripMenuItem22";
|
this.toolStripMenuItem22.Name = "toolStripMenuItem22";
|
||||||
this.toolStripMenuItem22.Size = new System.Drawing.Size(152, 6);
|
this.toolStripMenuItem22.Size = new System.Drawing.Size(180, 6);
|
||||||
//
|
//
|
||||||
// mnuSpcDebugger
|
// mnuSpcDebugger
|
||||||
//
|
//
|
||||||
this.mnuSpcDebugger.Image = global::Mesen.GUI.Properties.Resources.SpcDebugger;
|
this.mnuSpcDebugger.Image = global::Mesen.GUI.Properties.Resources.SpcDebugger;
|
||||||
this.mnuSpcDebugger.Name = "mnuSpcDebugger";
|
this.mnuSpcDebugger.Name = "mnuSpcDebugger";
|
||||||
this.mnuSpcDebugger.Size = new System.Drawing.Size(155, 22);
|
this.mnuSpcDebugger.Size = new System.Drawing.Size(183, 22);
|
||||||
this.mnuSpcDebugger.Text = "SPC Debugger";
|
this.mnuSpcDebugger.Text = "SPC Debugger";
|
||||||
//
|
//
|
||||||
// mnuSa1Debugger
|
// mnuSa1Debugger
|
||||||
//
|
//
|
||||||
this.mnuSa1Debugger.Image = global::Mesen.GUI.Properties.Resources.Sa1Debugger;
|
this.mnuSa1Debugger.Image = global::Mesen.GUI.Properties.Resources.Sa1Debugger;
|
||||||
this.mnuSa1Debugger.Name = "mnuSa1Debugger";
|
this.mnuSa1Debugger.Name = "mnuSa1Debugger";
|
||||||
this.mnuSa1Debugger.Size = new System.Drawing.Size(155, 22);
|
this.mnuSa1Debugger.Size = new System.Drawing.Size(183, 22);
|
||||||
this.mnuSa1Debugger.Text = "SA-1 Debugger";
|
this.mnuSa1Debugger.Text = "SA-1 Debugger";
|
||||||
//
|
//
|
||||||
// mnuGsuDebugger
|
// mnuGsuDebugger
|
||||||
//
|
//
|
||||||
this.mnuGsuDebugger.Image = global::Mesen.GUI.Properties.Resources.GsuDebugger;
|
this.mnuGsuDebugger.Image = global::Mesen.GUI.Properties.Resources.GsuDebugger;
|
||||||
this.mnuGsuDebugger.Name = "mnuGsuDebugger";
|
this.mnuGsuDebugger.Name = "mnuGsuDebugger";
|
||||||
this.mnuGsuDebugger.Size = new System.Drawing.Size(155, 22);
|
this.mnuGsuDebugger.Size = new System.Drawing.Size(183, 22);
|
||||||
this.mnuGsuDebugger.Text = "GSU Debugger";
|
this.mnuGsuDebugger.Text = "GSU Debugger";
|
||||||
//
|
//
|
||||||
// mnuHelp
|
// mnuHelp
|
||||||
|
@ -1177,96 +1270,12 @@
|
||||||
this.ctrlRecentGames.TabIndex = 1;
|
this.ctrlRecentGames.TabIndex = 1;
|
||||||
this.ctrlRecentGames.Visible = false;
|
this.ctrlRecentGames.Visible = false;
|
||||||
//
|
//
|
||||||
// mnuNetPlay
|
// mnuProfiler
|
||||||
//
|
//
|
||||||
this.mnuNetPlay.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
this.mnuProfiler.Image = global::Mesen.GUI.Properties.Resources.PerfTracker;
|
||||||
this.mnuStartServer,
|
this.mnuProfiler.Name = "mnuProfiler";
|
||||||
this.mnuConnect,
|
this.mnuProfiler.Size = new System.Drawing.Size(183, 22);
|
||||||
this.mnuNetPlaySelectController,
|
this.mnuProfiler.Text = "Performance Profiler";
|
||||||
this.toolStripSeparator2,
|
|
||||||
this.mnuProfile});
|
|
||||||
this.mnuNetPlay.Image = global::Mesen.GUI.Properties.Resources.Network;
|
|
||||||
this.mnuNetPlay.Name = "mnuNetPlay";
|
|
||||||
this.mnuNetPlay.Size = new System.Drawing.Size(182, 22);
|
|
||||||
this.mnuNetPlay.Text = "Net Play";
|
|
||||||
//
|
|
||||||
// mnuStartServer
|
|
||||||
//
|
|
||||||
this.mnuStartServer.Name = "mnuStartServer";
|
|
||||||
this.mnuStartServer.Size = new System.Drawing.Size(168, 22);
|
|
||||||
this.mnuStartServer.Text = "Start Server";
|
|
||||||
//
|
|
||||||
// mnuConnect
|
|
||||||
//
|
|
||||||
this.mnuConnect.Name = "mnuConnect";
|
|
||||||
this.mnuConnect.Size = new System.Drawing.Size(168, 22);
|
|
||||||
this.mnuConnect.Text = "Connect to Server";
|
|
||||||
//
|
|
||||||
// mnuNetPlaySelectController
|
|
||||||
//
|
|
||||||
this.mnuNetPlaySelectController.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
|
||||||
this.mnuNetPlayPlayer1,
|
|
||||||
this.mnuNetPlayPlayer2,
|
|
||||||
this.mnuNetPlayPlayer3,
|
|
||||||
this.mnuNetPlayPlayer4,
|
|
||||||
this.mnuNetPlayPlayer5,
|
|
||||||
this.toolStripSeparator1,
|
|
||||||
this.mnuNetPlaySpectator});
|
|
||||||
this.mnuNetPlaySelectController.Name = "mnuNetPlaySelectController";
|
|
||||||
this.mnuNetPlaySelectController.Size = new System.Drawing.Size(168, 22);
|
|
||||||
this.mnuNetPlaySelectController.Text = "Select Controller";
|
|
||||||
//
|
|
||||||
// mnuNetPlayPlayer1
|
|
||||||
//
|
|
||||||
this.mnuNetPlayPlayer1.Name = "mnuNetPlayPlayer1";
|
|
||||||
this.mnuNetPlayPlayer1.Size = new System.Drawing.Size(152, 22);
|
|
||||||
this.mnuNetPlayPlayer1.Text = "Player 1";
|
|
||||||
//
|
|
||||||
// mnuNetPlayPlayer2
|
|
||||||
//
|
|
||||||
this.mnuNetPlayPlayer2.Name = "mnuNetPlayPlayer2";
|
|
||||||
this.mnuNetPlayPlayer2.Size = new System.Drawing.Size(152, 22);
|
|
||||||
this.mnuNetPlayPlayer2.Text = "Player 2";
|
|
||||||
//
|
|
||||||
// mnuNetPlayPlayer3
|
|
||||||
//
|
|
||||||
this.mnuNetPlayPlayer3.Name = "mnuNetPlayPlayer3";
|
|
||||||
this.mnuNetPlayPlayer3.Size = new System.Drawing.Size(152, 22);
|
|
||||||
this.mnuNetPlayPlayer3.Text = "Player 3";
|
|
||||||
//
|
|
||||||
// mnuNetPlayPlayer4
|
|
||||||
//
|
|
||||||
this.mnuNetPlayPlayer4.Name = "mnuNetPlayPlayer4";
|
|
||||||
this.mnuNetPlayPlayer4.Size = new System.Drawing.Size(152, 22);
|
|
||||||
this.mnuNetPlayPlayer4.Text = "Player 4";
|
|
||||||
//
|
|
||||||
// mnuNetPlayPlayer5
|
|
||||||
//
|
|
||||||
this.mnuNetPlayPlayer5.Name = "mnuNetPlayPlayer5";
|
|
||||||
this.mnuNetPlayPlayer5.Size = new System.Drawing.Size(152, 22);
|
|
||||||
this.mnuNetPlayPlayer5.Text = "Player 5";
|
|
||||||
//
|
|
||||||
// toolStripSeparator1
|
|
||||||
//
|
|
||||||
this.toolStripSeparator1.Name = "toolStripSeparator1";
|
|
||||||
this.toolStripSeparator1.Size = new System.Drawing.Size(149, 6);
|
|
||||||
//
|
|
||||||
// mnuNetPlaySpectator
|
|
||||||
//
|
|
||||||
this.mnuNetPlaySpectator.Name = "mnuNetPlaySpectator";
|
|
||||||
this.mnuNetPlaySpectator.Size = new System.Drawing.Size(152, 22);
|
|
||||||
this.mnuNetPlaySpectator.Text = "Spectator";
|
|
||||||
//
|
|
||||||
// toolStripSeparator2
|
|
||||||
//
|
|
||||||
this.toolStripSeparator2.Name = "toolStripSeparator2";
|
|
||||||
this.toolStripSeparator2.Size = new System.Drawing.Size(165, 6);
|
|
||||||
//
|
|
||||||
// mnuProfile
|
|
||||||
//
|
|
||||||
this.mnuProfile.Name = "mnuProfile";
|
|
||||||
this.mnuProfile.Size = new System.Drawing.Size(168, 22);
|
|
||||||
this.mnuProfile.Text = "Configure Profile";
|
|
||||||
//
|
//
|
||||||
// frmMain
|
// frmMain
|
||||||
//
|
//
|
||||||
|
@ -1437,5 +1446,6 @@
|
||||||
private System.Windows.Forms.ToolStripMenuItem mnuNetPlaySpectator;
|
private System.Windows.Forms.ToolStripMenuItem mnuNetPlaySpectator;
|
||||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
|
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
|
||||||
private System.Windows.Forms.ToolStripMenuItem mnuProfile;
|
private System.Windows.Forms.ToolStripMenuItem mnuProfile;
|
||||||
}
|
private System.Windows.Forms.ToolStripMenuItem mnuProfiler;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -288,6 +288,7 @@ namespace Mesen.GUI.Forms
|
||||||
mnuTraceLogger.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenTraceLogger));
|
mnuTraceLogger.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenTraceLogger));
|
||||||
mnuScriptWindow.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenScriptWindow));
|
mnuScriptWindow.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenScriptWindow));
|
||||||
mnuRegisterViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenRegisterViewer));
|
mnuRegisterViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenRegisterViewer));
|
||||||
|
mnuProfiler.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenProfiler));
|
||||||
|
|
||||||
mnuNoneFilter.Click += (s, e) => { _shortcuts.SetVideoFilter(VideoFilterType.None); };
|
mnuNoneFilter.Click += (s, e) => { _shortcuts.SetVideoFilter(VideoFilterType.None); };
|
||||||
mnuNtscFilter.Click += (s, e) => { _shortcuts.SetVideoFilter(VideoFilterType.NTSC); };
|
mnuNtscFilter.Click += (s, e) => { _shortcuts.SetVideoFilter(VideoFilterType.NTSC); };
|
||||||
|
@ -348,6 +349,7 @@ namespace Mesen.GUI.Forms
|
||||||
mnuEventViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.EventViewer); };
|
mnuEventViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.EventViewer); };
|
||||||
mnuScriptWindow.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.ScriptWindow); };
|
mnuScriptWindow.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.ScriptWindow); };
|
||||||
mnuRegisterViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.RegisterViewer); };
|
mnuRegisterViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.RegisterViewer); };
|
||||||
|
mnuProfiler.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.Profiler); };
|
||||||
|
|
||||||
mnuTestRun.Click += (s, e) => { RomTestHelper.RunTest(); };
|
mnuTestRun.Click += (s, e) => { RomTestHelper.RunTest(); };
|
||||||
mnuTestRecord.Click += (s, e) => { RomTestHelper.RecordTest(); };
|
mnuTestRecord.Click += (s, e) => { RomTestHelper.RecordTest(); };
|
||||||
|
@ -439,6 +441,7 @@ namespace Mesen.GUI.Forms
|
||||||
mnuPaletteViewer.Enabled = running;
|
mnuPaletteViewer.Enabled = running;
|
||||||
mnuEventViewer.Enabled = running;
|
mnuEventViewer.Enabled = running;
|
||||||
mnuRegisterViewer.Enabled = running;
|
mnuRegisterViewer.Enabled = running;
|
||||||
|
mnuProfiler.Enabled = running;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResizeRecentGames()
|
private void ResizeRecentGames()
|
||||||
|
|
|
@ -130,6 +130,19 @@ namespace Mesen.GUI
|
||||||
return callstack;
|
return callstack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[DllImport(DllPath)] public static extern void ResetProfiler(CpuType type);
|
||||||
|
[DllImport(DllPath, EntryPoint = "GetProfilerData")] private static extern void GetProfilerDataWrapper(CpuType type, [In, Out]ProfiledFunction[] profilerData, ref UInt32 functionCount);
|
||||||
|
public static ProfiledFunction[] GetProfilerData(CpuType type)
|
||||||
|
{
|
||||||
|
ProfiledFunction[] profilerData = new ProfiledFunction[100000];
|
||||||
|
UInt32 functionCount = 0;
|
||||||
|
|
||||||
|
DebugApi.GetProfilerDataWrapper(type, profilerData, ref functionCount);
|
||||||
|
Array.Resize(ref profilerData, (int)functionCount);
|
||||||
|
|
||||||
|
return profilerData;
|
||||||
|
}
|
||||||
|
|
||||||
[DllImport(DllPath, EntryPoint = "GetMemoryAccessStamps")] private static extern void GetMemoryAccessStampsWrapper(UInt32 offset, UInt32 length, SnesMemoryType type, MemoryOperationType operationType, [In,Out]UInt64[] stamps);
|
[DllImport(DllPath, EntryPoint = "GetMemoryAccessStamps")] private static extern void GetMemoryAccessStampsWrapper(UInt32 offset, UInt32 length, SnesMemoryType type, MemoryOperationType operationType, [In,Out]UInt64[] stamps);
|
||||||
public static UInt64[] GetMemoryAccessStamps(UInt32 offset, UInt32 length, SnesMemoryType type, MemoryOperationType operationType)
|
public static UInt64[] GetMemoryAccessStamps(UInt32 offset, UInt32 length, SnesMemoryType type, MemoryOperationType operationType)
|
||||||
{
|
{
|
||||||
|
@ -444,6 +457,7 @@ namespace Mesen.GUI
|
||||||
public UInt32 Source;
|
public UInt32 Source;
|
||||||
public UInt32 Target;
|
public UInt32 Target;
|
||||||
public UInt32 Return;
|
public UInt32 Return;
|
||||||
|
public AddressInfo AbsReturn;
|
||||||
public StackFrameFlags Flags;
|
public StackFrameFlags Flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -532,4 +546,14 @@ namespace Mesen.GUI
|
||||||
IndexMode8 = 0x10,
|
IndexMode8 = 0x10,
|
||||||
MemoryMode8 = 0x20,
|
MemoryMode8 = 0x20,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct ProfiledFunction
|
||||||
|
{
|
||||||
|
public UInt64 ExclusiveCycles;
|
||||||
|
public UInt64 InclusiveCycles;
|
||||||
|
public UInt64 CallCount;
|
||||||
|
public UInt64 MinCycles;
|
||||||
|
public UInt64 MaxCycles;
|
||||||
|
public AddressInfo Address;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
19
UI/UI.csproj
19
UI/UI.csproj
|
@ -272,6 +272,7 @@
|
||||||
<Compile Include="Debugger\Code\IDisassemblyManager.cs" />
|
<Compile Include="Debugger\Code\IDisassemblyManager.cs" />
|
||||||
<Compile Include="Debugger\Config\DebuggerShortcutsConfig.cs" />
|
<Compile Include="Debugger\Config\DebuggerShortcutsConfig.cs" />
|
||||||
<Compile Include="Debugger\Config\DebuggerInfo.cs" />
|
<Compile Include="Debugger\Config\DebuggerInfo.cs" />
|
||||||
|
<Compile Include="Debugger\Config\ProfilerConfig.cs" />
|
||||||
<Compile Include="Debugger\Config\ScriptWindowConfig.cs" />
|
<Compile Include="Debugger\Config\ScriptWindowConfig.cs" />
|
||||||
<Compile Include="Debugger\Config\SpriteViewerConfig.cs" />
|
<Compile Include="Debugger\Config\SpriteViewerConfig.cs" />
|
||||||
<Compile Include="Debugger\Config\RegisterViewerConfig.cs" />
|
<Compile Include="Debugger\Config\RegisterViewerConfig.cs" />
|
||||||
|
@ -379,6 +380,18 @@
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Debugger\PpuViewer\SpriteInfo.cs" />
|
<Compile Include="Debugger\PpuViewer\SpriteInfo.cs" />
|
||||||
<Compile Include="Debugger\PpuViewer\WindowRefreshManager.cs" />
|
<Compile Include="Debugger\PpuViewer\WindowRefreshManager.cs" />
|
||||||
|
<Compile Include="Debugger\Profiler\ctrlProfiler.cs">
|
||||||
|
<SubType>UserControl</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Debugger\Profiler\ctrlProfiler.Designer.cs">
|
||||||
|
<DependentUpon>ctrlProfiler.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Debugger\Profiler\frmProfiler.cs">
|
||||||
|
<SubType>Form</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Debugger\Profiler\frmProfiler.Designer.cs">
|
||||||
|
<DependentUpon>frmProfiler.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Debugger\Scripts\FastColoredTextBox\AutocompleteItem.cs" />
|
<Compile Include="Debugger\Scripts\FastColoredTextBox\AutocompleteItem.cs" />
|
||||||
<Compile Include="Debugger\Scripts\FastColoredTextBox\AutocompleteMenu.cs">
|
<Compile Include="Debugger\Scripts\FastColoredTextBox\AutocompleteMenu.cs">
|
||||||
<SubType>UserControl</SubType>
|
<SubType>UserControl</SubType>
|
||||||
|
@ -1084,6 +1097,12 @@
|
||||||
<EmbeddedResource Include="Debugger\HexBox\HexBox.resx">
|
<EmbeddedResource Include="Debugger\HexBox\HexBox.resx">
|
||||||
<DependentUpon>HexBox.cs</DependentUpon>
|
<DependentUpon>HexBox.cs</DependentUpon>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Debugger\Profiler\ctrlProfiler.resx">
|
||||||
|
<DependentUpon>ctrlProfiler.cs</DependentUpon>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Debugger\Profiler\frmProfiler.resx">
|
||||||
|
<DependentUpon>frmProfiler.cs</DependentUpon>
|
||||||
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Include="Debugger\Scripts\FastColoredTextBox\FastColoredTextBox.resx">
|
<EmbeddedResource Include="Debugger\Scripts\FastColoredTextBox\FastColoredTextBox.resx">
|
||||||
<DependentUpon>FastColoredTextBox.cs</DependentUpon>
|
<DependentUpon>FastColoredTextBox.cs</DependentUpon>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
|
Loading…
Add table
Reference in a new issue