mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
Label list, call stack
This commit is contained in:
parent
ba2c574f9e
commit
329021c63c
26 changed files with 753 additions and 135 deletions
|
@ -582,7 +582,7 @@ shared_ptr<ScriptManager> Debugger::GetScriptManager()
|
||||||
shared_ptr<CallstackManager> Debugger::GetCallstackManager(CpuType cpuType)
|
shared_ptr<CallstackManager> Debugger::GetCallstackManager(CpuType cpuType)
|
||||||
{
|
{
|
||||||
if(_debuggers[(int)cpuType].Debugger) {
|
if(_debuggers[(int)cpuType].Debugger) {
|
||||||
_debuggers[(int)cpuType].Debugger->GetCallstackManager();
|
return _debuggers[(int)cpuType].Debugger->GetCallstackManager();
|
||||||
}
|
}
|
||||||
throw std::runtime_error("GetCallstackManager() - Unsupported CPU type");
|
throw std::runtime_error("GetCallstackManager() - Unsupported CPU type");
|
||||||
}
|
}
|
||||||
|
@ -600,7 +600,7 @@ Emulator* Debugger::GetEmulator()
|
||||||
shared_ptr<IAssembler> Debugger::GetAssembler(CpuType cpuType)
|
shared_ptr<IAssembler> Debugger::GetAssembler(CpuType cpuType)
|
||||||
{
|
{
|
||||||
if(_debuggers[(int)cpuType].Debugger) {
|
if(_debuggers[(int)cpuType].Debugger) {
|
||||||
_debuggers[(int)cpuType].Debugger->GetAssembler();
|
return _debuggers[(int)cpuType].Debugger->GetAssembler();
|
||||||
}
|
}
|
||||||
throw std::runtime_error("GetAssembler() - Unsupported CPU type");
|
throw std::runtime_error("GetAssembler() - Unsupported CPU type");
|
||||||
}
|
}
|
||||||
|
|
|
@ -293,13 +293,22 @@ CodeLineData Disassembler::GetLineData(DisassemblyResult& row, CpuType type, Sne
|
||||||
switch(row.Address.Type) {
|
switch(row.Address.Type) {
|
||||||
default: break;
|
default: break;
|
||||||
case SnesMemoryType::GbPrgRom:
|
case SnesMemoryType::GbPrgRom:
|
||||||
case SnesMemoryType::PrgRom: data.Flags |= (uint8_t)LineFlags::PrgRom; break;
|
case SnesMemoryType::PrgRom:
|
||||||
|
case SnesMemoryType::NesPrgRom:
|
||||||
|
data.Flags |= (uint8_t)LineFlags::PrgRom;
|
||||||
|
break;
|
||||||
|
|
||||||
case SnesMemoryType::GbWorkRam:
|
case SnesMemoryType::GbWorkRam:
|
||||||
case SnesMemoryType::WorkRam: data.Flags |= (uint8_t)LineFlags::WorkRam; break;
|
case SnesMemoryType::WorkRam:
|
||||||
|
case SnesMemoryType::NesWorkRam:
|
||||||
|
data.Flags |= (uint8_t)LineFlags::WorkRam;
|
||||||
|
break;
|
||||||
|
|
||||||
case SnesMemoryType::GbCartRam:
|
case SnesMemoryType::GbCartRam:
|
||||||
case SnesMemoryType::SaveRam: data.Flags |= (uint8_t)LineFlags::SaveRam; break;
|
case SnesMemoryType::SaveRam:
|
||||||
|
case SnesMemoryType::NesSaveRam:
|
||||||
|
data.Flags |= (uint8_t)LineFlags::SaveRam;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isBlockStartEnd = (data.Flags & (LineFlags::BlockStart | LineFlags::BlockEnd)) != 0;
|
bool isBlockStartEnd = (data.Flags & (LineFlags::BlockStart | LineFlags::BlockEnd)) != 0;
|
||||||
|
@ -511,8 +520,8 @@ uint32_t Disassembler::GetDisassemblyOutput(CpuType type, uint32_t address, Code
|
||||||
SnesMemoryType memType = DebugUtilities::GetCpuMemoryType(type);
|
SnesMemoryType memType = DebugUtilities::GetCpuMemoryType(type);
|
||||||
uint32_t maxBank = (_memoryDumper->GetMemorySize(memType) - 1) >> 16;
|
uint32_t maxBank = (_memoryDumper->GetMemorySize(memType) - 1) >> 16;
|
||||||
|
|
||||||
uint32_t row;
|
int32_t row;
|
||||||
for(row = 0; row < rowCount; row++){
|
for(row = 0; row < (int32_t)rowCount; row++){
|
||||||
if(row + i >= rows.size()) {
|
if(row + i >= rows.size()) {
|
||||||
if(bank < maxBank) {
|
if(bank < maxBank) {
|
||||||
bank++;
|
bank++;
|
||||||
|
|
|
@ -44,51 +44,12 @@ void LabelManager::SetLabel(uint32_t address, SnesMemoryType memType, string lab
|
||||||
|
|
||||||
int64_t LabelManager::GetLabelKey(uint32_t absoluteAddr, SnesMemoryType memType)
|
int64_t LabelManager::GetLabelKey(uint32_t absoluteAddr, SnesMemoryType memType)
|
||||||
{
|
{
|
||||||
switch(memType) {
|
return absoluteAddr | ((uint64_t)memType << 32);
|
||||||
case SnesMemoryType::PrgRom: return absoluteAddr | ((uint64_t)1 << 32);
|
|
||||||
case SnesMemoryType::WorkRam: return absoluteAddr | ((uint64_t)2 << 32);
|
|
||||||
case SnesMemoryType::SaveRam: return absoluteAddr | ((uint64_t)3 << 32);
|
|
||||||
case SnesMemoryType::Register: return absoluteAddr | ((uint64_t)4 << 32);
|
|
||||||
case SnesMemoryType::SpcRam: return absoluteAddr | ((uint64_t)5 << 32);
|
|
||||||
case SnesMemoryType::SpcRom: return absoluteAddr | ((uint64_t)6 << 32);
|
|
||||||
case SnesMemoryType::Sa1InternalRam: return absoluteAddr | ((uint64_t)7 << 32);
|
|
||||||
case SnesMemoryType::GsuWorkRam: return absoluteAddr | ((uint64_t)8 << 32);
|
|
||||||
case SnesMemoryType::BsxPsRam: return absoluteAddr | ((uint64_t)9 << 32);
|
|
||||||
case SnesMemoryType::BsxMemoryPack: return absoluteAddr | ((uint64_t)10 << 32);
|
|
||||||
case SnesMemoryType::DspProgramRom: return absoluteAddr | ((uint64_t)11 << 32);
|
|
||||||
case SnesMemoryType::GbPrgRom: return absoluteAddr | ((uint64_t)12 << 32);
|
|
||||||
case SnesMemoryType::GbWorkRam: return absoluteAddr | ((uint64_t)13 << 32);
|
|
||||||
case SnesMemoryType::GbCartRam: return absoluteAddr | ((uint64_t)14 << 32);
|
|
||||||
case SnesMemoryType::GbHighRam: return absoluteAddr | ((uint64_t)15 << 32);
|
|
||||||
case SnesMemoryType::GbBootRom: return absoluteAddr | ((uint64_t)16 << 32);
|
|
||||||
case SnesMemoryType::GameboyMemory: return absoluteAddr | ((uint64_t)17 << 32);
|
|
||||||
default: return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SnesMemoryType LabelManager::GetKeyMemoryType(uint64_t key)
|
SnesMemoryType LabelManager::GetKeyMemoryType(uint64_t key)
|
||||||
{
|
{
|
||||||
switch(key & ~(uint64_t)0xFFFFFFFF) {
|
return (SnesMemoryType)(key >> 32);
|
||||||
case ((uint64_t)1 << 32): return SnesMemoryType::PrgRom; break;
|
|
||||||
case ((uint64_t)2 << 32): return SnesMemoryType::WorkRam; break;
|
|
||||||
case ((uint64_t)3 << 32): return SnesMemoryType::SaveRam; break;
|
|
||||||
case ((uint64_t)4 << 32): return SnesMemoryType::Register; break;
|
|
||||||
case ((uint64_t)5 << 32): return SnesMemoryType::SpcRam; break;
|
|
||||||
case ((uint64_t)6 << 32): return SnesMemoryType::SpcRom; break;
|
|
||||||
case ((uint64_t)7 << 32): return SnesMemoryType::Sa1InternalRam; break;
|
|
||||||
case ((uint64_t)8 << 32): return SnesMemoryType::GsuWorkRam; break;
|
|
||||||
case ((uint64_t)9 << 32): return SnesMemoryType::BsxPsRam; break;
|
|
||||||
case ((uint64_t)10 << 32): return SnesMemoryType::BsxMemoryPack; break;
|
|
||||||
case ((uint64_t)11 << 32): return SnesMemoryType::DspProgramRom; break;
|
|
||||||
case ((uint64_t)12 << 32): return SnesMemoryType::GbPrgRom; break;
|
|
||||||
case ((uint64_t)13 << 32): return SnesMemoryType::GbWorkRam; break;
|
|
||||||
case ((uint64_t)14 << 32): return SnesMemoryType::GbCartRam; break;
|
|
||||||
case ((uint64_t)15 << 32): return SnesMemoryType::GbHighRam; break;
|
|
||||||
case ((uint64_t)16 << 32): return SnesMemoryType::GbBootRom; break;
|
|
||||||
case ((uint64_t)17 << 32): return SnesMemoryType::GameboyMemory; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw std::runtime_error("Invalid label key");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string LabelManager::GetLabel(AddressInfo address)
|
string LabelManager::GetLabel(AddressInfo address)
|
||||||
|
|
|
@ -73,6 +73,7 @@ uint32_t MemoryDumper::GetMemorySize(SnesMemoryType type)
|
||||||
case SnesMemoryType::Cx4Memory: return 0x1000000;
|
case SnesMemoryType::Cx4Memory: return 0x1000000;
|
||||||
case SnesMemoryType::GameboyMemory: return 0x10000;
|
case SnesMemoryType::GameboyMemory: return 0x10000;
|
||||||
case SnesMemoryType::NesMemory: return 0x10000;
|
case SnesMemoryType::NesMemory: return 0x10000;
|
||||||
|
case SnesMemoryType::Register: return 0x10000;
|
||||||
default: return _emu->GetMemory(type).Size;
|
default: return _emu->GetMemory(type).Size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
41
NewUI/Debugger/DebugUtilities.cs
Normal file
41
NewUI/Debugger/DebugUtilities.cs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
using Mesen.Interop;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Mesen.Debugger
|
||||||
|
{
|
||||||
|
public static class DebugUtilities
|
||||||
|
{
|
||||||
|
public static uint GetProgramCounter(CpuType cpuType)
|
||||||
|
{
|
||||||
|
switch(cpuType) {
|
||||||
|
case CpuType.Cpu:
|
||||||
|
case CpuType.Sa1: {
|
||||||
|
CpuState state = DebugApi.GetState<CpuState>(cpuType);
|
||||||
|
return (uint)(state.K << 16) | state.PC;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CpuType.Spc: {
|
||||||
|
SpcState state = DebugApi.GetState<SpcState>(cpuType);
|
||||||
|
return (uint)state.PC;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CpuType.Gameboy: {
|
||||||
|
GbCpuState state = DebugApi.GetState<GbCpuState>(cpuType);
|
||||||
|
return (uint)state.PC;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CpuType.Nes: {
|
||||||
|
NesCpuState state = DebugApi.GetState<NesCpuState>(cpuType);
|
||||||
|
return (uint)state.PC;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: throw new Exception("Invalid cpu type");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -64,7 +64,7 @@ namespace Mesen.Debugger
|
||||||
new SplitterDockable(),
|
new SplitterDockable(),
|
||||||
new ToolDock {
|
new ToolDock {
|
||||||
Proportion = 0.33,
|
Proportion = 0.33,
|
||||||
VisibleDockables = CreateList<IDockable>(new DummyTool() { Id = "Labels", Title = "Labels" })
|
VisibleDockables = CreateList<IDockable>(_context.LabelList)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ namespace Mesen.Debugger
|
||||||
new SplitterDockable(),
|
new SplitterDockable(),
|
||||||
new ToolDock {
|
new ToolDock {
|
||||||
Proportion = 0.33,
|
Proportion = 0.33,
|
||||||
VisibleDockables = CreateList<IDockable>(new DummyTool() { Id = "CallStack", Title = "Call Stack" })
|
VisibleDockables = CreateList<IDockable>(_context.CallStack)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Mesen.Interop;
|
using Mesen.Debugger.Labels;
|
||||||
|
using Mesen.Interop;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -33,7 +34,7 @@ namespace Mesen.Debugger
|
||||||
{
|
{
|
||||||
if(EffectiveAddress >= 0) {
|
if(EffectiveAddress >= 0) {
|
||||||
AddressInfo relAddress = new AddressInfo() { Address = EffectiveAddress, Type = _cpuType.ToMemoryType() };
|
AddressInfo relAddress = new AddressInfo() { Address = EffectiveAddress, Type = _cpuType.ToMemoryType() };
|
||||||
/*CodeLabel label = LabelManager.GetLabel(relAddress);
|
CodeLabel? label = LabelManager.GetLabel(relAddress);
|
||||||
if(label != null) {
|
if(label != null) {
|
||||||
if(label.Length > 1) {
|
if(label.Length > 1) {
|
||||||
int gap = DebugApi.GetAbsoluteAddress(relAddress).Address - label.GetAbsoluteAddress().Address;
|
int gap = DebugApi.GetAbsoluteAddress(relAddress).Address - label.GetAbsoluteAddress().Address;
|
||||||
|
@ -42,9 +43,9 @@ namespace Mesen.Debugger
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "[" + label.Label + "]";
|
return "[" + label.Label + "]";
|
||||||
} else {*/
|
} else {
|
||||||
return "[$" + EffectiveAddress.ToString(format) + "]";
|
return "[$" + EffectiveAddress.ToString(format) + "]";
|
||||||
//}
|
}
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
using Mesen.Interop;
|
using Mesen.Interop;
|
||||||
|
using ReactiveUI;
|
||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Mesen.Debugger.Labels
|
namespace Mesen.Debugger.Labels
|
||||||
{
|
{
|
||||||
public class CodeLabel
|
public class CodeLabel : ReactiveObject
|
||||||
{
|
{
|
||||||
public UInt32 Address;
|
[Reactive] public UInt32 Address { get; set; }
|
||||||
public SnesMemoryType MemoryType;
|
[Reactive] public SnesMemoryType MemoryType { get; set; }
|
||||||
public string Label = "";
|
[Reactive] public string Label { get; set; } = "";
|
||||||
public string Comment = "";
|
[Reactive] public string Comment { get; set; } = "";
|
||||||
public CodeLabelFlags Flags;
|
[Reactive] public CodeLabelFlags Flags { get; set; }
|
||||||
public UInt32 Length = 1;
|
[Reactive] public UInt32 Length { get; set; } = 1;
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
@ -49,10 +51,10 @@ namespace Mesen.Debugger.Labels
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static char[] _separatar = new char[1] { ':' };
|
private static char[] _separator = new char[1] { ':' };
|
||||||
public static CodeLabel? FromString(string data)
|
public static CodeLabel? FromString(string data)
|
||||||
{
|
{
|
||||||
string[] rowData = data.Split(_separatar, 4);
|
string[] rowData = data.Split(_separator, 4);
|
||||||
if(rowData.Length < 3) {
|
if(rowData.Length < 3) {
|
||||||
//Invalid row
|
//Invalid row
|
||||||
return null;
|
return null;
|
||||||
|
@ -151,5 +153,15 @@ namespace Mesen.Debugger.Labels
|
||||||
{
|
{
|
||||||
return (CodeLabel)this.MemberwiseClone();
|
return (CodeLabel)this.MemberwiseClone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CopyFrom(CodeLabel copy)
|
||||||
|
{
|
||||||
|
Address = copy.Address;
|
||||||
|
MemoryType = copy.MemoryType;
|
||||||
|
Label = copy.Label;
|
||||||
|
Comment = copy.Comment;
|
||||||
|
Flags = copy.Flags;
|
||||||
|
Length = copy.Length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,26 +77,7 @@ namespace Mesen.Debugger.Labels
|
||||||
|
|
||||||
private static UInt64 GetKey(UInt32 address, SnesMemoryType memType)
|
private static UInt64 GetKey(UInt32 address, SnesMemoryType memType)
|
||||||
{
|
{
|
||||||
switch(memType) {
|
return address | ((UInt64)memType << 32);
|
||||||
case SnesMemoryType.PrgRom: return address | ((ulong)1 << 32);
|
|
||||||
case SnesMemoryType.WorkRam: return address | ((ulong)2 << 32);
|
|
||||||
case SnesMemoryType.SaveRam: return address | ((ulong)3 << 32);
|
|
||||||
case SnesMemoryType.Register: return address | ((ulong)4 << 32);
|
|
||||||
case SnesMemoryType.SpcRam: return address | ((ulong)5 << 32);
|
|
||||||
case SnesMemoryType.SpcRom: return address | ((ulong)6 << 32);
|
|
||||||
case SnesMemoryType.Sa1InternalRam: return address | ((ulong)7 << 32);
|
|
||||||
case SnesMemoryType.GsuWorkRam: return address | ((ulong)8 << 32);
|
|
||||||
case SnesMemoryType.BsxPsRam: return address | ((ulong)9 << 32);
|
|
||||||
case SnesMemoryType.BsxMemoryPack: return address | ((ulong)10 << 32);
|
|
||||||
case SnesMemoryType.DspProgramRom: return address | ((ulong)11 << 32);
|
|
||||||
case SnesMemoryType.GbPrgRom: return address | ((ulong)12 << 32);
|
|
||||||
case SnesMemoryType.GbWorkRam: return address | ((ulong)13 << 32);
|
|
||||||
case SnesMemoryType.GbCartRam: return address | ((ulong)14 << 32);
|
|
||||||
case SnesMemoryType.GbHighRam: return address | ((ulong)15 << 32);
|
|
||||||
case SnesMemoryType.GbBootRom: return address | ((ulong)16 << 32);
|
|
||||||
case SnesMemoryType.GameboyMemory: return address | ((ulong)17 << 32);
|
|
||||||
}
|
|
||||||
throw new Exception("Invalid type");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetLabel(uint address, SnesMemoryType memType, string label, string comment)
|
private static void SetLabel(uint address, SnesMemoryType memType, string label, string comment)
|
||||||
|
@ -234,6 +215,7 @@ namespace Mesen.Debugger.Labels
|
||||||
|
|
||||||
public static void SetDefaultLabels()
|
public static void SetDefaultLabels()
|
||||||
{
|
{
|
||||||
|
SetSnesDefaultLabels();
|
||||||
//TODO
|
//TODO
|
||||||
/*CoprocessorType coproc = EmuApi.GetRomInfo().CoprocessorType;
|
/*CoprocessorType coproc = EmuApi.GetRomInfo().CoprocessorType;
|
||||||
if(coproc == CoprocessorType.SGB) {
|
if(coproc == CoprocessorType.SGB) {
|
||||||
|
|
86
NewUI/Debugger/ViewModels/CallStackViewModel.cs
Normal file
86
NewUI/Debugger/ViewModels/CallStackViewModel.cs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
using Dock.Model.ReactiveUI.Controls;
|
||||||
|
using Mesen.Debugger.Labels;
|
||||||
|
using Mesen.Interop;
|
||||||
|
using Mesen.ViewModels;
|
||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace Mesen.Debugger.ViewModels
|
||||||
|
{
|
||||||
|
public class CallStackViewModel : Tool
|
||||||
|
{
|
||||||
|
private CpuType _cpuType;
|
||||||
|
|
||||||
|
[Reactive] public List<StackInfo> StackFrames { get; private set; } = new List<StackInfo>();
|
||||||
|
|
||||||
|
//For designer
|
||||||
|
public CallStackViewModel() : this(CpuType.Cpu) { }
|
||||||
|
|
||||||
|
public CallStackViewModel(CpuType cpuType)
|
||||||
|
{
|
||||||
|
_cpuType = cpuType;
|
||||||
|
Id = "CallStack";
|
||||||
|
Title = "Call Stack";
|
||||||
|
UpdateCallStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateCallStack()
|
||||||
|
{
|
||||||
|
StackFrames = GetStackInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<StackInfo> GetStackInfo()
|
||||||
|
{
|
||||||
|
StackFrameInfo[] stackFrames = DebugApi.GetCallstack(_cpuType);
|
||||||
|
|
||||||
|
int relDestinationAddr = -1;
|
||||||
|
|
||||||
|
List<StackInfo> stack = new List<StackInfo>();
|
||||||
|
for(int i = 0, len = stackFrames.Length; i < len; i++) {
|
||||||
|
int relSubEntryAddr = i == 0 ? -1 : (int)stackFrames[i - 1].Target;
|
||||||
|
|
||||||
|
stack.Insert(0, new StackInfo() {
|
||||||
|
SubName = this.GetFunctionName(relSubEntryAddr, i == 0 ? StackFrameFlags.None : stackFrames[i - 1].Flags),
|
||||||
|
Address = stackFrames[i].Source,
|
||||||
|
});
|
||||||
|
|
||||||
|
relDestinationAddr = (int)stackFrames[i].Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add current location
|
||||||
|
stack.Insert(0, new StackInfo() {
|
||||||
|
SubName = this.GetFunctionName(relDestinationAddr, stackFrames.Length == 0 ? StackFrameFlags.None : stackFrames[^1].Flags),
|
||||||
|
Address = DebugUtilities.GetProgramCounter(_cpuType),
|
||||||
|
});
|
||||||
|
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFunctionName(int relSubEntryAddr, StackFrameFlags flags)
|
||||||
|
{
|
||||||
|
if(relSubEntryAddr < 0) {
|
||||||
|
return "[bottom of stack]";
|
||||||
|
}
|
||||||
|
|
||||||
|
string format = "X" + _cpuType.GetAddressSize();
|
||||||
|
CodeLabel? label = relSubEntryAddr >= 0 ? LabelManager.GetLabel(new AddressInfo() { Address = relSubEntryAddr, Type = _cpuType.ToMemoryType() }) : null;
|
||||||
|
if(label != null) {
|
||||||
|
return label.Label + " ($" + relSubEntryAddr.ToString(format) + ")";
|
||||||
|
} else if(flags == StackFrameFlags.Nmi) {
|
||||||
|
return "[nmi] $" + relSubEntryAddr.ToString(format);
|
||||||
|
} else if(flags == StackFrameFlags.Irq) {
|
||||||
|
return "[irq] $" + relSubEntryAddr.ToString(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "$" + relSubEntryAddr.ToString(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StackInfo
|
||||||
|
{
|
||||||
|
public string SubName { get; set; }
|
||||||
|
public UInt32 Address { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
using Dock.Model.Core;
|
using Dock.Model.Core;
|
||||||
using Dock.Model.ReactiveUI.Controls;
|
using Dock.Model.ReactiveUI.Controls;
|
||||||
using Mesen.Debugger.Disassembly;
|
using Mesen.Debugger.Disassembly;
|
||||||
|
using Mesen.Debugger.Labels;
|
||||||
using Mesen.Interop;
|
using Mesen.Interop;
|
||||||
using Mesen.ViewModels;
|
using Mesen.ViewModels;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
@ -15,6 +16,8 @@ namespace Mesen.Debugger.ViewModels
|
||||||
{
|
{
|
||||||
[Reactive] public DisassemblyViewerViewModel Disassembly { get; private set; }
|
[Reactive] public DisassemblyViewerViewModel Disassembly { get; private set; }
|
||||||
[Reactive] public BreakpointListViewModel BreakpointList { get; private set; }
|
[Reactive] public BreakpointListViewModel BreakpointList { get; private set; }
|
||||||
|
[Reactive] public LabelListViewModel LabelList { get; private set; }
|
||||||
|
[Reactive] public CallStackViewModel CallStack { get; private set; }
|
||||||
|
|
||||||
[Reactive] public DebuggerDockFactory DockFactory { get; private set; }
|
[Reactive] public DebuggerDockFactory DockFactory { get; private set; }
|
||||||
[Reactive] public IRootDock DockLayout { get; private set; }
|
[Reactive] public IRootDock DockLayout { get; private set; }
|
||||||
|
@ -34,12 +37,7 @@ namespace Mesen.Debugger.ViewModels
|
||||||
Disassembly = new DisassemblyViewerViewModel();
|
Disassembly = new DisassemblyViewerViewModel();
|
||||||
BreakpointList = new BreakpointListViewModel();
|
BreakpointList = new BreakpointListViewModel();
|
||||||
|
|
||||||
var factory = new DebuggerDockFactory(this);
|
DockFactory = new DebuggerDockFactory(this);
|
||||||
var layout = factory.CreateLayout();
|
|
||||||
factory.InitLayout(layout);
|
|
||||||
|
|
||||||
DockFactory = factory;
|
|
||||||
DockLayout = layout;
|
|
||||||
|
|
||||||
RomInfo romInfo = EmuApi.GetRomInfo();
|
RomInfo romInfo = EmuApi.GetRomInfo();
|
||||||
|
|
||||||
|
@ -64,6 +62,14 @@ namespace Mesen.Debugger.ViewModels
|
||||||
ConfigApi.SetDebuggerFlag(DebuggerFlags.GbDebuggerEnabled, true);
|
ConfigApi.SetDebuggerFlag(DebuggerFlags.GbDebuggerEnabled, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LabelManager.SetDefaultLabels();
|
||||||
|
LabelList = new LabelListViewModel(CpuType);
|
||||||
|
|
||||||
|
CallStack = new CallStackViewModel(CpuType);
|
||||||
|
|
||||||
|
DockLayout = DockFactory.CreateLayout();
|
||||||
|
DockFactory.InitLayout(DockLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void UpdateDisassembly()
|
internal void UpdateDisassembly()
|
||||||
|
|
66
NewUI/Debugger/ViewModels/LabelEditViewModel.cs
Normal file
66
NewUI/Debugger/ViewModels/LabelEditViewModel.cs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
using Dock.Model.ReactiveUI.Controls;
|
||||||
|
using Mesen.Debugger.Labels;
|
||||||
|
using Mesen.Interop;
|
||||||
|
using Mesen.ViewModels;
|
||||||
|
using ReactiveUI;
|
||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
|
||||||
|
namespace Mesen.Debugger.ViewModels
|
||||||
|
{
|
||||||
|
public class LabelEditViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
[Reactive] public CodeLabel Label { get; set; }
|
||||||
|
[ObservableAsProperty] public bool OkEnabled { get; }
|
||||||
|
[ObservableAsProperty] public string MaxAddress { get; }
|
||||||
|
|
||||||
|
//For designer
|
||||||
|
public LabelEditViewModel() : this(new CodeLabel()) { }
|
||||||
|
|
||||||
|
public LabelEditViewModel(CodeLabel label, CodeLabel? originalLabel = null)
|
||||||
|
{
|
||||||
|
Label = label;
|
||||||
|
|
||||||
|
this.WhenAnyValue(x => x.Label.MemoryType, (memoryType) => {
|
||||||
|
int maxAddress = DebugApi.GetMemorySize(memoryType) - 1;
|
||||||
|
if(maxAddress <= 0) {
|
||||||
|
return "(unavailable)";
|
||||||
|
} else {
|
||||||
|
return "(Max: $" + maxAddress.ToString("X4") + ")";
|
||||||
|
}
|
||||||
|
}).ToPropertyEx(this, x => x.MaxAddress);
|
||||||
|
|
||||||
|
this.WhenAnyValue(x => x.Label.Label, x => x.Label.Comment, x => x.Label.Length, x => x.Label.MemoryType, x => x.Label.Address, (label, comment, length, memoryType, address) => {
|
||||||
|
CodeLabel? sameLabel = LabelManager.GetLabel(label);
|
||||||
|
int maxAddress = DebugApi.GetMemorySize(memoryType) - 1;
|
||||||
|
|
||||||
|
for(UInt32 i = 0; i < length; i++) {
|
||||||
|
CodeLabel? sameAddress = LabelManager.GetLabel(address + i, memoryType);
|
||||||
|
if(sameAddress != null) {
|
||||||
|
if(originalLabel == null) {
|
||||||
|
//A label already exists and we're not editing an existing label, so we can't add it
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if(sameAddress.Label != originalLabel.Label && !sameAddress.Label.StartsWith(originalLabel.Label + "+")) {
|
||||||
|
//A label already exists, we're trying to edit an existing label, but the existing label
|
||||||
|
//and the label we're editing aren't the same label. Can't override an existing label with a different one.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
length >= 1 && length <= 65536 &&
|
||||||
|
address + (length - 1) <= maxAddress &&
|
||||||
|
(sameLabel == null || sameLabel == originalLabel)
|
||||||
|
&& (label.Length > 0 || comment.Length > 0)
|
||||||
|
&& !comment.Contains('\x1')
|
||||||
|
&& (label.Length == 0 || LabelManager.LabelRegex.IsMatch(label));
|
||||||
|
}).ToPropertyEx(this, x => x.OkEnabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
NewUI/Debugger/ViewModels/LabelListViewModel.cs
Normal file
34
NewUI/Debugger/ViewModels/LabelListViewModel.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
using Dock.Model.ReactiveUI.Controls;
|
||||||
|
using Mesen.Debugger.Labels;
|
||||||
|
using Mesen.Interop;
|
||||||
|
using Mesen.ViewModels;
|
||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace Mesen.Debugger.ViewModels
|
||||||
|
{
|
||||||
|
public class LabelListViewModel : Tool
|
||||||
|
{
|
||||||
|
private CpuType _cpuType;
|
||||||
|
|
||||||
|
[Reactive] public List<CodeLabel> Labels { get; private set; } = new List<CodeLabel>();
|
||||||
|
|
||||||
|
//For designer
|
||||||
|
public LabelListViewModel() : this(CpuType.Cpu) { }
|
||||||
|
|
||||||
|
public LabelListViewModel(CpuType cpuType)
|
||||||
|
{
|
||||||
|
_cpuType = cpuType;
|
||||||
|
Id = "Labels";
|
||||||
|
Title = "Labels";
|
||||||
|
UpdateLabelList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateLabelList()
|
||||||
|
{
|
||||||
|
Labels = LabelManager.GetLabels(_cpuType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,40 +13,6 @@
|
||||||
<vm:BreakpointListViewModel />
|
<vm:BreakpointListViewModel />
|
||||||
</Design.DataContext>
|
</Design.DataContext>
|
||||||
|
|
||||||
<UserControl.Styles>
|
|
||||||
<Style Selector="DataGridColumnHeader">
|
|
||||||
<Setter Property="MinHeight" Value="18" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="DataGridColumnHeader Grid">
|
|
||||||
<Setter Property="Margin" Value="-8 0 0 0" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="DataGridColumnHeader Grid ContentPresenter">
|
|
||||||
<Setter Property="Margin" Value="0 0 -30 0" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="DataGridColumnHeader Path">
|
|
||||||
<Setter Property="Width" Value="0" />
|
|
||||||
<Setter Property="MinWidth" Value="0" />
|
|
||||||
<Setter Property="IsVisible" Value="False" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="DataGridRow">
|
|
||||||
<Setter Property="Height" Value="18" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="DataGridCell">
|
|
||||||
<Setter Property="FontSize" Value="10.5" />
|
|
||||||
<Setter Property="Height" Value="14" />
|
|
||||||
<Setter Property="Padding" Value="0" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="DataGridCell /template/ ContentPresenter > TextBlock">
|
|
||||||
<Setter Property="Margin" Value="0" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="DataGridCell CheckBox">
|
|
||||||
<Setter Property="MinWidth" Value="0" />
|
|
||||||
<Setter Property="Padding" Value="0" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="DataGridCell Grid#FocusVisual">
|
|
||||||
<Setter Property="Opacity" Value="0" />
|
|
||||||
</Style>
|
|
||||||
</UserControl.Styles>
|
|
||||||
<Border BorderThickness="1" BorderBrush="LightGray">
|
<Border BorderThickness="1" BorderBrush="LightGray">
|
||||||
<DataGrid
|
<DataGrid
|
||||||
Items="{Binding Breakpoints}"
|
Items="{Binding Breakpoints}"
|
||||||
|
|
40
NewUI/Debugger/Views/CallStackView.axaml
Normal file
40
NewUI/Debugger/Views/CallStackView.axaml
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<UserControl
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:vm="using:Mesen.Debugger.ViewModels"
|
||||||
|
xmlns:dbg="using:Mesen.Debugger"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="110"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
x:DataType="vm:CallStackViewModel"
|
||||||
|
x:Class="Mesen.Debugger.Views.CallStackView"
|
||||||
|
>
|
||||||
|
<Design.DataContext>
|
||||||
|
<vm:CallStackViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
|
||||||
|
<UserControl.Resources>
|
||||||
|
<dbg:HexConverter x:Key="Hex" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
|
||||||
|
<Border BorderThickness="1" BorderBrush="LightGray">
|
||||||
|
<DataGrid
|
||||||
|
Name="DataGrid"
|
||||||
|
Items="{CompiledBinding StackFrames}"
|
||||||
|
CanUserSortColumns="True"
|
||||||
|
CanUserResizeColumns="True"
|
||||||
|
CanUserReorderColumns="True"
|
||||||
|
SelectionMode="Extended"
|
||||||
|
FontFamily="Microsoft Sans Serif"
|
||||||
|
GridLinesVisibility="All"
|
||||||
|
IsReadOnly="True"
|
||||||
|
>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Function (Entry Address)" Binding="{Binding SubName}" Width="1*" CanUserResize="True" />
|
||||||
|
<DataGridTextColumn Header="PC Address" Binding="{Binding Address, Converter={StaticResource Hex}, ConverterParameter='X4'}}" Width="1*" CanUserResize="True" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</Border>
|
||||||
|
</UserControl>
|
27
NewUI/Debugger/Views/CallStackView.axaml.cs
Normal file
27
NewUI/Debugger/Views/CallStackView.axaml.cs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Mesen.ViewModels;
|
||||||
|
using Mesen.Debugger;
|
||||||
|
using Mesen.Debugger.ViewModels;
|
||||||
|
using Mesen.Debugger.Labels;
|
||||||
|
using Mesen.Debugger.Windows;
|
||||||
|
using Mesen.Utilities;
|
||||||
|
using Avalonia.Input;
|
||||||
|
|
||||||
|
namespace Mesen.Debugger.Views
|
||||||
|
{
|
||||||
|
public class CallStackView : UserControl
|
||||||
|
{
|
||||||
|
public CallStackView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
66
NewUI/Debugger/Views/LabelListView.axaml
Normal file
66
NewUI/Debugger/Views/LabelListView.axaml
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<UserControl
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:vm="using:Mesen.Debugger.ViewModels"
|
||||||
|
xmlns:dbg="using:Mesen.Debugger"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="110"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
x:DataType="vm:LabelListViewModel"
|
||||||
|
x:Class="Mesen.Debugger.Views.LabelListView"
|
||||||
|
>
|
||||||
|
<Design.DataContext>
|
||||||
|
<vm:LabelListViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
|
||||||
|
<UserControl.Resources>
|
||||||
|
<dbg:HexConverter x:Key="Hex" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
|
||||||
|
<Border BorderThickness="1" BorderBrush="LightGray">
|
||||||
|
<DataGrid
|
||||||
|
Name="DataGrid"
|
||||||
|
Items="{CompiledBinding Labels}"
|
||||||
|
CanUserSortColumns="True"
|
||||||
|
CanUserResizeColumns="True"
|
||||||
|
CanUserReorderColumns="True"
|
||||||
|
SelectionMode="Extended"
|
||||||
|
FontFamily="Microsoft Sans Serif"
|
||||||
|
GridLinesVisibility="All"
|
||||||
|
DoubleTapped="OnGridDoubleClick"
|
||||||
|
Tapped="OnGridClick"
|
||||||
|
CellPointerPressed="OnCellPointerPressed"
|
||||||
|
IsReadOnly="True"
|
||||||
|
>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Label" Binding="{Binding Label}" Width="1*" CanUserResize="True" />
|
||||||
|
<DataGridTextColumn Header="CPU Addr" Width="1*" CanUserResize="True" />
|
||||||
|
<DataGridTextColumn Header="ROM Addr" Binding="{Binding Address, Converter={StaticResource Hex}, ConverterParameter='X4'}}" Width="1*" CanUserResize="True" />
|
||||||
|
<DataGridTextColumn Header="Comment" Binding="{Binding Comment}" Width="1*" CanUserResize="True" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
|
||||||
|
<DataGrid.ContextMenu>
|
||||||
|
<ContextMenu PlacementMode="Pointer">
|
||||||
|
<MenuItem Header="Add" Click="mnuAddLabel_Click">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<Image Source="/Assets/Add.png" />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem Header="Edit" Click="mnuEditLabel_Click">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<Image Source="/Assets/EditLabel.png" />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
<Separator />
|
||||||
|
<MenuItem Header="Delete" Click="mnuDeleteLabel_Click">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<Image Source="/Assets/Close.png" />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
</ContextMenu>
|
||||||
|
</DataGrid.ContextMenu>
|
||||||
|
</DataGrid>
|
||||||
|
</Border>
|
||||||
|
</UserControl>
|
94
NewUI/Debugger/Views/LabelListView.axaml.cs
Normal file
94
NewUI/Debugger/Views/LabelListView.axaml.cs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Mesen.ViewModels;
|
||||||
|
using Mesen.Debugger;
|
||||||
|
using Mesen.Debugger.ViewModels;
|
||||||
|
using Mesen.Debugger.Labels;
|
||||||
|
using Mesen.Debugger.Windows;
|
||||||
|
using Mesen.Utilities;
|
||||||
|
using Avalonia.Input;
|
||||||
|
|
||||||
|
namespace Mesen.Debugger.Views
|
||||||
|
{
|
||||||
|
public class LabelListView : UserControl
|
||||||
|
{
|
||||||
|
public LabelListView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCellPointerPressed(object sender, DataGridCellPointerPressedEventArgs e)
|
||||||
|
{
|
||||||
|
DataGrid grid = this.FindControl<DataGrid>("DataGrid");
|
||||||
|
grid.SelectedIndex = e.Row.GetIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGridClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void mnuAddLabel_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
CodeLabel newLabel = new CodeLabel();
|
||||||
|
LabelEditWindow wnd = new LabelEditWindow() {
|
||||||
|
DataContext = new LabelEditViewModel(newLabel)
|
||||||
|
};
|
||||||
|
|
||||||
|
bool result = await wnd.ShowCenteredDialog<bool>(this);
|
||||||
|
if(result) {
|
||||||
|
LabelManager.SetLabel(newLabel, true);
|
||||||
|
((LabelListViewModel)DataContext!).UpdateLabelList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mnuEditLabel_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
DataGrid grid = this.FindControl<DataGrid>("DataGrid");
|
||||||
|
CodeLabel ? label = grid.SelectedItem as CodeLabel;
|
||||||
|
if(label != null && grid != null) {
|
||||||
|
EditLabel(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mnuDeleteLabel_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
DataGrid grid = this.FindControl<DataGrid>("DataGrid");
|
||||||
|
CodeLabel? label = grid.SelectedItem as CodeLabel;
|
||||||
|
if(label != null && grid != null) {
|
||||||
|
LabelManager.DeleteLabel(label, true);
|
||||||
|
((LabelListViewModel)DataContext!).UpdateLabelList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGridDoubleClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
DataGrid grid = (DataGrid)sender;
|
||||||
|
CodeLabel? label = grid.SelectedItem as CodeLabel;
|
||||||
|
if(label != null && grid != null) {
|
||||||
|
EditLabel(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void EditLabel(CodeLabel label)
|
||||||
|
{
|
||||||
|
CodeLabel copy = label.Clone();
|
||||||
|
LabelEditWindow wnd = new LabelEditWindow() {
|
||||||
|
DataContext = new LabelEditViewModel(copy, label)
|
||||||
|
};
|
||||||
|
|
||||||
|
bool result = await wnd.ShowCenteredDialog<bool>(this);
|
||||||
|
if(result) {
|
||||||
|
label.CopyFrom(copy);
|
||||||
|
LabelManager.SetLabel(label, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,7 @@
|
||||||
<Style Selector="TextBox.h1">
|
<Style Selector="TextBox.h1">
|
||||||
<Setter Property="FontFamily" Value="Consolas" />
|
<Setter Property="FontFamily" Value="Consolas" />
|
||||||
<Setter Property="FontSize" Value="12" />
|
<Setter Property="FontSize" Value="12" />
|
||||||
|
<Setter Property="MinWidth" Value="0" />
|
||||||
</Style>
|
</Style>
|
||||||
</UserControl.Styles>
|
</UserControl.Styles>
|
||||||
|
|
||||||
|
@ -39,6 +40,8 @@
|
||||||
<TextBlock>Y:</TextBlock>
|
<TextBlock>Y:</TextBlock>
|
||||||
<TextBox Classes="h1" Text="{CompiledBinding RegY, Converter={StaticResource Hex}}" />
|
<TextBox Classes="h1" Text="{CompiledBinding RegY, Converter={StaticResource Hex}}" />
|
||||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
||||||
|
<TextBlock>K:</TextBlock>
|
||||||
|
<TextBox Classes="h1" Text="{CompiledBinding RegK, Converter={StaticResource Hex}}" />
|
||||||
<TextBlock>PC:</TextBlock>
|
<TextBlock>PC:</TextBlock>
|
||||||
<TextBox Classes="h1" Text="{CompiledBinding RegPC, Converter={StaticResource Hex}}" />
|
<TextBox Classes="h1" Text="{CompiledBinding RegPC, Converter={StaticResource Hex}}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -46,20 +49,20 @@
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<TextBlock>D:</TextBlock>
|
<TextBlock>D:</TextBlock>
|
||||||
<TextBox Classes="h1" Text="{Binding RegD}" />
|
<TextBox Classes="h1" Text="{Binding RegD, Converter={StaticResource Hex}}" />
|
||||||
<TextBlock>DB:</TextBlock>
|
<TextBlock>DB:</TextBlock>
|
||||||
<TextBox Classes="h1" Text="{Binding RegDBR}" />
|
<TextBox Classes="h1" Text="{Binding RegDBR, Converter={StaticResource Hex}}" />
|
||||||
|
|
||||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
||||||
<TextBlock>S:</TextBlock>
|
<TextBlock>S:</TextBlock>
|
||||||
<TextBox Classes="h1" Text="{Binding RegSP}" />
|
<TextBox Classes="h1" Text="{Binding RegSP, Converter={StaticResource Hex}}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<TextBlock />
|
<TextBlock />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<DockPanel Margin="0 2 0 0">
|
<DockPanel Margin="0 2 0 0">
|
||||||
<StackPanel DockPanel.Dock="Left" Orientation="Horizontal" VerticalAlignment="Top">
|
<StackPanel DockPanel.Dock="Left" Orientation="Horizontal" VerticalAlignment="Top">
|
||||||
<TextBlock>P:</TextBlock>
|
<TextBlock>P:</TextBlock>
|
||||||
<TextBox Classes="h1" Text="{Binding RegPS}" />
|
<TextBox Classes="h1" Text="{Binding RegPS, Converter={StaticResource Hex}}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<TextBox
|
<TextBox
|
||||||
|
|
|
@ -9,6 +9,7 @@ using Mesen.Debugger.Disassembly;
|
||||||
using Mesen.Interop;
|
using Mesen.Interop;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using Mesen.Debugger.Labels;
|
||||||
|
|
||||||
namespace Mesen.Debugger.Windows
|
namespace Mesen.Debugger.Windows
|
||||||
{
|
{
|
||||||
|
@ -66,6 +67,7 @@ namespace Mesen.Debugger.Windows
|
||||||
if(e.NotificationType == ConsoleNotificationType.CodeBreak) {
|
if(e.NotificationType == ConsoleNotificationType.CodeBreak) {
|
||||||
_model.UpdateCpuState();
|
_model.UpdateCpuState();
|
||||||
_model.UpdateDisassembly();
|
_model.UpdateDisassembly();
|
||||||
|
_model.CallStack.UpdateCallStack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
80
NewUI/Debugger/Windows/LabelEditWindow.axaml
Normal file
80
NewUI/Debugger/Windows/LabelEditWindow.axaml
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
<Window
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:m="clr-namespace:Mesen"
|
||||||
|
xmlns:vm="using:Mesen.Debugger.ViewModels"
|
||||||
|
xmlns:sys="using:System"
|
||||||
|
xmlns:v="using:Mesen.Views"
|
||||||
|
xmlns:dbg="using:Mesen.Debugger"
|
||||||
|
xmlns:c="using:Mesen.Controls"
|
||||||
|
xmlns:i="using:Mesen.Interop"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:dvm="using:Mesen.Debugger.ViewModels"
|
||||||
|
xmlns:dc="using:Mesen.Debugger.Controls"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="230"
|
||||||
|
x:Class="Mesen.Debugger.Windows.LabelEditWindow"
|
||||||
|
x:DataType="vm:LabelEditViewModel"
|
||||||
|
Icon="/Assets/EditLabel.png"
|
||||||
|
Width="300" Height="230"
|
||||||
|
Title="Edit label..."
|
||||||
|
>
|
||||||
|
<Design.DataContext>
|
||||||
|
<vm:LabelEditViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
|
||||||
|
<Window.Resources>
|
||||||
|
<dbg:HexConverter x:Key="Hex" />
|
||||||
|
</Window.Resources>
|
||||||
|
|
||||||
|
<DockPanel>
|
||||||
|
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
|
<Button Width="70" HorizontalContentAlignment="Center" Click="Ok_OnClick" Content="OK" IsEnabled="{CompiledBinding OkEnabled}" />
|
||||||
|
<Button Width="70" HorizontalContentAlignment="Center" IsCancel="True" Click="Cancel_OnClick" Content="Cancel" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Grid
|
||||||
|
DockPanel.Dock="Right"
|
||||||
|
ColumnDefinitions="Auto,*"
|
||||||
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto"
|
||||||
|
Margin="5 0 5 0"
|
||||||
|
>
|
||||||
|
<TextBlock Grid.Column="0" Grid.Row="0" Text="Memory type:" />
|
||||||
|
<c:EnumComboBox
|
||||||
|
Grid.Column="1" Grid.Row="0"
|
||||||
|
EnumType="{x:Type i:SnesMemoryType}"
|
||||||
|
SelectedItem="{CompiledBinding Label.MemoryType}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="0" Grid.Row="1" Text="Address:" />
|
||||||
|
<StackPanel Grid.Column="1" Grid.Row="1" Orientation="Horizontal">
|
||||||
|
<TextBlock Margin="0 0 3 0">$</TextBlock>
|
||||||
|
<TextBox Text="{CompiledBinding Label.Address, Converter={StaticResource Hex}, ConverterParameter='X'}" Width="50" />
|
||||||
|
<TextBlock Margin="3 0 0 0" Text="{CompiledBinding MaxAddress}" Foreground="Gray" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="0" Grid.Row="2" Text="Label:" />
|
||||||
|
<TextBox
|
||||||
|
Grid.Column="1" Grid.Row="2"
|
||||||
|
Text="{CompiledBinding Label.Label}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="0" Grid.Row="3" Text="Comment:" />
|
||||||
|
<TextBox
|
||||||
|
Grid.Column="1" Grid.Row="3"
|
||||||
|
AcceptsReturn="True"
|
||||||
|
Height="100"
|
||||||
|
VerticalContentAlignment="Top"
|
||||||
|
Text="{CompiledBinding Label.Comment}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="0" Grid.Row="4" Text="Length:" />
|
||||||
|
<NumericUpDown
|
||||||
|
Grid.Column="1" Grid.Row="4"
|
||||||
|
Value="{CompiledBinding Label.Length}"
|
||||||
|
Minimum="1"
|
||||||
|
Maximum="65536"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</DockPanel>
|
||||||
|
</Window>
|
33
NewUI/Debugger/Windows/LabelEditWindow.axaml.cs
Normal file
33
NewUI/Debugger/Windows/LabelEditWindow.axaml.cs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
|
namespace Mesen.Debugger.Windows
|
||||||
|
{
|
||||||
|
public class LabelEditWindow : Window
|
||||||
|
{
|
||||||
|
public LabelEditWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
#if DEBUG
|
||||||
|
this.AttachDevTools();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Ok_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Close(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Close(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -721,7 +721,7 @@ namespace Mesen.Interop
|
||||||
Zero = 0x80
|
Zero = 0x80
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct GbCpuState
|
public struct GbCpuState : BaseState
|
||||||
{
|
{
|
||||||
public UInt16 PC;
|
public UInt16 PC;
|
||||||
public UInt16 SP;
|
public UInt16 SP;
|
||||||
|
|
|
@ -179,6 +179,12 @@
|
||||||
<Compile Update="Controls\OptionSection.axaml.cs">
|
<Compile Update="Controls\OptionSection.axaml.cs">
|
||||||
<DependentUpon>OptionSection.axaml</DependentUpon>
|
<DependentUpon>OptionSection.axaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Update="Debugger\Views\CallStackView.axaml.cs">
|
||||||
|
<DependentUpon>CallStackView.axaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Debugger\Views\LabelListView.axaml.cs">
|
||||||
|
<DependentUpon>LabelListView.axaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Update="Debugger\Views\DebuggerDock\StatusToolView.axaml.cs">
|
<Compile Update="Debugger\Views\DebuggerDock\StatusToolView.axaml.cs">
|
||||||
<DependentUpon>StatusToolView.axaml</DependentUpon>
|
<DependentUpon>StatusToolView.axaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -191,6 +197,9 @@
|
||||||
<Compile Update="Debugger\Views\SnesPpuView.axaml.cs">
|
<Compile Update="Debugger\Views\SnesPpuView.axaml.cs">
|
||||||
<DependentUpon>SnesPpuView.axaml</DependentUpon>
|
<DependentUpon>SnesPpuView.axaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Update="Debugger\Windows\LabelEditWindow.axaml.cs">
|
||||||
|
<DependentUpon>LabelEditWindow.axaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Update="Debugger\Windows\TileViewerWindow.axaml.cs">
|
<Compile Update="Debugger\Windows\TileViewerWindow.axaml.cs">
|
||||||
<DependentUpon>TileViewerWindow.axaml</DependentUpon>
|
<DependentUpon>TileViewerWindow.axaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
|
@ -344,6 +344,55 @@
|
||||||
<Setter Property="CornerRadius" Value="0" />
|
<Setter Property="CornerRadius" Value="0" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ContextMenu">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<ControlTemplate>
|
||||||
|
<Border Background="{TemplateBinding Background}"
|
||||||
|
BorderBrush="{TemplateBinding BorderBrush}"
|
||||||
|
BorderThickness="{TemplateBinding BorderThickness}"
|
||||||
|
Padding="0"
|
||||||
|
MaxWidth="{TemplateBinding MaxWidth}"
|
||||||
|
MinHeight="{TemplateBinding MinHeight}"
|
||||||
|
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||||
|
CornerRadius="{DynamicResource OverlayCornerRadius}">
|
||||||
|
<Panel>
|
||||||
|
<Rectangle
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Width="24">
|
||||||
|
<Rectangle.Fill>
|
||||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="24,0">
|
||||||
|
<GradientStop Color="#fcfcfc" Offset="0.0" />
|
||||||
|
<GradientStop Color="#f1f1f1" Offset="1.0" />
|
||||||
|
</LinearGradientBrush>
|
||||||
|
</Rectangle.Fill>
|
||||||
|
</Rectangle>
|
||||||
|
|
||||||
|
<ScrollViewer Classes="menuscroller">
|
||||||
|
<ItemsPresenter Name="PART_ItemsPresenter"
|
||||||
|
Items="{TemplateBinding Items}"
|
||||||
|
ItemsPanel="{TemplateBinding ItemsPanel}"
|
||||||
|
ItemTemplate="{TemplateBinding ItemTemplate}"
|
||||||
|
Margin="{DynamicResource MenuFlyoutScrollerMargin}"
|
||||||
|
KeyboardNavigation.TabNavigation="Continue"
|
||||||
|
Grid.IsSharedSizeScope="True" />
|
||||||
|
</ScrollViewer>
|
||||||
|
</Panel>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ContextMenu > MenuItem">
|
||||||
|
<Setter Property="Height" Value="20" />
|
||||||
|
<Setter Property="Padding" Value="2 0" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ContextMenu > MenuItem:selected /template/ Border">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource MesenMenuBackgroundHighlight}" />
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource MesenMenuBorderHighlight}" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
<Style Selector="Button">
|
<Style Selector="Button">
|
||||||
<Setter Property="Height" Value="21" />
|
<Setter Property="Height" Value="21" />
|
||||||
<Setter Property="Margin" Value="1" />
|
<Setter Property="Margin" Value="1" />
|
||||||
|
@ -491,6 +540,44 @@
|
||||||
<Setter Property="VerticalAlignment" Value="Center" />
|
<Setter Property="VerticalAlignment" Value="Center" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ScrollBar">
|
||||||
|
<Setter Property="AllowAutoHide" Value="False" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- Data grid -->
|
||||||
|
<Style Selector="DataGridColumnHeader">
|
||||||
|
<Setter Property="MinHeight" Value="18" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="DataGridColumnHeader Grid">
|
||||||
|
<Setter Property="Margin" Value="-8 0 0 0" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="DataGridColumnHeader Grid ContentPresenter">
|
||||||
|
<Setter Property="Margin" Value="0 0 -30 0" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="DataGridColumnHeader Path">
|
||||||
|
<Setter Property="Width" Value="0" />
|
||||||
|
<Setter Property="MinWidth" Value="0" />
|
||||||
|
<Setter Property="IsVisible" Value="False" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="DataGridRow">
|
||||||
|
<Setter Property="Height" Value="18" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="DataGridCell">
|
||||||
|
<Setter Property="FontSize" Value="10.5" />
|
||||||
|
<Setter Property="Height" Value="14" />
|
||||||
|
<Setter Property="Padding" Value="0" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="DataGridCell /template/ ContentPresenter > TextBlock">
|
||||||
|
<Setter Property="Margin" Value="0" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="DataGridCell CheckBox">
|
||||||
|
<Setter Property="MinWidth" Value="0" />
|
||||||
|
<Setter Property="Padding" Value="0" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="DataGridCell Grid#FocusVisual">
|
||||||
|
<Setter Property="Opacity" Value="0" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
<!-- Disable overlapped scrollbar in scrollviewer -->
|
<!-- Disable overlapped scrollbar in scrollviewer -->
|
||||||
<Style Selector="ScrollViewer">
|
<Style Selector="ScrollViewer">
|
||||||
<Setter Property="Background"
|
<Setter Property="Background"
|
||||||
|
|
|
@ -10,24 +10,36 @@ namespace Mesen.Utilities
|
||||||
{
|
{
|
||||||
static class WindowExtensions
|
static class WindowExtensions
|
||||||
{
|
{
|
||||||
private static void CenterWindow(Window child, Window parent)
|
private static void CenterWindow(Window child, Control parent)
|
||||||
{
|
{
|
||||||
child.WindowStartupLocation = WindowStartupLocation.Manual;
|
child.WindowStartupLocation = WindowStartupLocation.Manual;
|
||||||
Size wndCenter = (parent.ClientSize / 2);
|
Size wndCenter = new Size(parent.Bounds.Width / 2, parent.Bounds.Height / 2);
|
||||||
PixelPoint screenCenter = new PixelPoint(parent.Position.X + (int)wndCenter.Width, parent.Position.Y + (int)wndCenter.Height);
|
PixelPoint controlPosition =parent.PointToScreen(new Point(0, 0));
|
||||||
|
PixelPoint screenCenter = new PixelPoint(controlPosition.X + (int)wndCenter.Width, controlPosition.Y + (int)wndCenter.Height);
|
||||||
child.Position = new PixelPoint(screenCenter.X - (int)child.Width / 2, screenCenter.Y - (int)child.Height / 2);
|
child.Position = new PixelPoint(screenCenter.X - (int)child.Width / 2, screenCenter.Y - (int)child.Height / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ShowCentered(this Window child, Window parent)
|
public static void ShowCentered(this Window child, Control parent)
|
||||||
{
|
{
|
||||||
CenterWindow(child, parent);
|
CenterWindow(child, parent);
|
||||||
child.Show();
|
child.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task ShowCenteredDialog(this Window child, Window parent)
|
public static Task ShowCenteredDialog(this Window child, Control parent)
|
||||||
|
{
|
||||||
|
return ShowCenteredDialog<object>(child, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Task<TResult> ShowCenteredDialog<TResult>(this Window child, Control parent)
|
||||||
{
|
{
|
||||||
CenterWindow(child, parent);
|
CenterWindow(child, parent);
|
||||||
return child.ShowDialog(parent);
|
|
||||||
|
IControl parentWnd = parent;
|
||||||
|
while(!(parentWnd is Window) && parentWnd != null) {
|
||||||
|
parentWnd = parentWnd.Parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return child.ShowDialog<TResult>(parentWnd as Window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue