215 lines
8.1 KiB
C#
215 lines
8.1 KiB
C#
using Mesen.GUI.Debugger.Controls;
|
|
using Mesen.GUI.Debugger.Integration;
|
|
using Mesen.GUI.Debugger.Labels;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using static Mesen.GUI.Debugger.Integration.DbgImporter;
|
|
|
|
namespace Mesen.GUI.Debugger.Code
|
|
{
|
|
public class CpuDisassemblyManager : IDisassemblyManager
|
|
{
|
|
protected ICodeDataProvider _provider;
|
|
private DbgImporter _symbolProvider;
|
|
|
|
public ICodeDataProvider Provider { get { return this._provider; } }
|
|
|
|
public virtual CpuType CpuType { get { return CpuType.Cpu; } }
|
|
public virtual SnesMemoryType RelativeMemoryType { get { return SnesMemoryType.CpuMemory; } }
|
|
public virtual int AddressSize { get { return 6; } }
|
|
public virtual int ByteCodeSize { get { return 4; } }
|
|
public virtual bool AllowSourceView { get { return true; } }
|
|
|
|
public virtual void RefreshCode(DbgImporter symbolProvider, DbgImporter.FileInfo file)
|
|
{
|
|
_symbolProvider = symbolProvider;
|
|
if(file == null) {
|
|
this._provider = new CodeDataProvider(CpuType.Cpu);
|
|
} else {
|
|
this._provider = new DbgCodeDataProvider(CpuType.Cpu, symbolProvider, file);
|
|
}
|
|
}
|
|
|
|
protected virtual int GetFullAddress(int address, int length)
|
|
{
|
|
CpuState state = DebugApi.GetState().Cpu;
|
|
if(length == 4) {
|
|
//Append current DB register to 2-byte addresses
|
|
return (state.DBR << 16) | address;
|
|
} else if(length == 2) {
|
|
//Add direct register to 1-byte addresses
|
|
return (state.D + address);
|
|
}
|
|
|
|
return address;
|
|
}
|
|
|
|
public LocationInfo GetLocationInfo(string word, int lineIndex)
|
|
{
|
|
LocationInfo location = new LocationInfo();
|
|
|
|
int arraySeparatorIndex = word.IndexOf("+");
|
|
if(arraySeparatorIndex >= 0) {
|
|
int index;
|
|
if(int.TryParse(word.Substring(arraySeparatorIndex + 1), out index)) {
|
|
location.ArrayIndex = index;
|
|
}
|
|
word = word.Substring(0, arraySeparatorIndex);
|
|
}
|
|
|
|
if(_provider is DbgCodeDataProvider && _symbolProvider != null) {
|
|
int rangeStart, rangeEnd;
|
|
GetSymbolByteRange(lineIndex, out rangeStart, out rangeEnd);
|
|
location.Symbol = _symbolProvider.GetSymbol(word, rangeStart, rangeEnd);
|
|
}
|
|
|
|
location.Label = LabelManager.GetLabel(word);
|
|
|
|
int address;
|
|
if(location.Label != null) {
|
|
address = location.Label.GetRelativeAddress().Address;
|
|
if(address >= 0) {
|
|
location.Address = location.Label.GetRelativeAddress().Address + (location.ArrayIndex ?? 0);
|
|
} else {
|
|
location.Address = -1;
|
|
}
|
|
} else if(word.StartsWith("$")) {
|
|
word = word.Replace("$", "");
|
|
if(Int32.TryParse(word, System.Globalization.NumberStyles.HexNumber, null, out address)) {
|
|
location.Address = GetFullAddress(address, word.Length);
|
|
}
|
|
} else if(Int32.TryParse(word, out address)) {
|
|
location.Address = (int)address;
|
|
} else {
|
|
location.Address = -1;
|
|
}
|
|
|
|
if(location.Label == null && location.Address >= 0) {
|
|
AddressInfo relAddress = new AddressInfo() { Address = location.Address, Type = RelativeMemoryType };
|
|
CodeLabel label = LabelManager.GetLabel(relAddress);
|
|
if(label != null && !string.IsNullOrWhiteSpace(label.Label)) {
|
|
//ignore comment-only labels
|
|
location.Label = label;
|
|
}
|
|
}
|
|
|
|
if(location.Label != null && location.Address >= 0) {
|
|
AddressInfo absAddress = location.Label.GetAbsoluteAddress();
|
|
AddressInfo absIndexedAddress = DebugApi.GetAbsoluteAddress(new AddressInfo() { Address = location.Address, Type = RelativeMemoryType });
|
|
if(absIndexedAddress.Address > absAddress.Address) {
|
|
location.ArrayIndex = absIndexedAddress.Address - absAddress.Address;
|
|
}
|
|
}
|
|
|
|
return location;
|
|
}
|
|
|
|
public Dictionary<string, string> GetTooltipData(string word, int lineIndex)
|
|
{
|
|
if(_provider.GetCodeLineData(lineIndex).Flags.HasFlag(LineFlags.ShowAsData)) {
|
|
//Disable tooltips for .db statements
|
|
return null;
|
|
}
|
|
|
|
LocationInfo location = GetLocationInfo(word, lineIndex);
|
|
|
|
if(location.Symbol != null) {
|
|
AddressInfo? symbolAddress = _symbolProvider.GetSymbolAddressInfo(location.Symbol);
|
|
|
|
if(symbolAddress != null && symbolAddress.Value.Address >= 0) {
|
|
int relativeAddress = DebugApi.GetRelativeAddress(symbolAddress.Value).Address;
|
|
byte byteValue = relativeAddress >= 0 ? DebugApi.GetMemoryValue(this.RelativeMemoryType, (UInt32)relativeAddress) : (byte)0;
|
|
UInt16 wordValue = relativeAddress >= 0 ? (UInt16)(byteValue | (DebugApi.GetMemoryValue(this.RelativeMemoryType, (UInt32)relativeAddress + 1) << 8)) : (UInt16)0;
|
|
|
|
var values = new Dictionary<string, string>() {
|
|
{ "Symbol", location.Symbol.Name + (location.ArrayIndex != null ? $"+{location.ArrayIndex.Value}" : "") }
|
|
};
|
|
|
|
if(relativeAddress >= 0) {
|
|
values["CPU Address"] = "$" + relativeAddress.ToString("X4");
|
|
} else {
|
|
values["CPU Address"] = "<out of scope>";
|
|
}
|
|
|
|
if(symbolAddress.Value.Type == SnesMemoryType.PrgRom) {
|
|
values["PRG Offset"] = "$" + (symbolAddress.Value.Address + (location.ArrayIndex ?? 0)).ToString("X4");
|
|
}
|
|
|
|
values["Value"] = (relativeAddress >= 0 ? $"${byteValue.ToString("X2")} (byte){Environment.NewLine}${wordValue.ToString("X4")} (word)" : "n/a");
|
|
return values;
|
|
} else {
|
|
return new Dictionary<string, string>() {
|
|
{ "Symbol", location.Symbol.Name },
|
|
{ "Constant", location.Symbol.Address.HasValue ? ("$" + location.Symbol.Address.Value.ToString("X2")) : "<unknown>" }
|
|
};
|
|
}
|
|
} else if(location.Label != null) {
|
|
AddressInfo absAddress = location.Label.GetAbsoluteAddress();
|
|
int relativeAddress;
|
|
if(location.Address >= 0) {
|
|
relativeAddress = location.Address;
|
|
AddressInfo absIndexedAddress = DebugApi.GetAbsoluteAddress(new AddressInfo() { Address = location.Address, Type = RelativeMemoryType });
|
|
if(absIndexedAddress.Address > absAddress.Address) {
|
|
location.ArrayIndex = absIndexedAddress.Address - absAddress.Address;
|
|
}
|
|
} else if(absAddress.Type == SnesMemoryType.Register) {
|
|
relativeAddress = absAddress.Address;
|
|
} else {
|
|
relativeAddress = location.Label.GetRelativeAddress().Address + (location.ArrayIndex ?? 0);
|
|
}
|
|
|
|
byte byteValue = relativeAddress >= 0 ? DebugApi.GetMemoryValue(this.RelativeMemoryType, (UInt32)relativeAddress) : (byte)0;
|
|
UInt16 wordValue = relativeAddress >= 0 ? (UInt16)(byteValue | (DebugApi.GetMemoryValue(this.RelativeMemoryType, (UInt32)relativeAddress + 1) << 8)) : (UInt16)0;
|
|
|
|
var values = new Dictionary<string, string>() {
|
|
{ "Label", location.Label.Label + (location.ArrayIndex != null ? $"+{location.ArrayIndex.Value}" : "") },
|
|
{ "Address", (relativeAddress >= 0 ? "$" + relativeAddress.ToString("X4") : "n/a") },
|
|
{ "Value", (relativeAddress >= 0 ? $"${byteValue.ToString("X2")} (byte){Environment.NewLine}${wordValue.ToString("X4")} (word)" : "n/a") },
|
|
};
|
|
|
|
if(!string.IsNullOrWhiteSpace(location.Label.Comment)) {
|
|
values["Comment"] = location.Label.Comment;
|
|
}
|
|
return values;
|
|
} else if(location.Address >= 0) {
|
|
byte byteValue = DebugApi.GetMemoryValue(this.RelativeMemoryType, (uint)location.Address);
|
|
UInt16 wordValue = (UInt16)(byteValue | (DebugApi.GetMemoryValue(this.RelativeMemoryType, (uint)location.Address + 1) << 8));
|
|
return new Dictionary<string, string>() {
|
|
{ "Address", "$" + location.Address.ToString("X4") },
|
|
{ "Value", $"${byteValue.ToString("X2")} (byte){Environment.NewLine}${wordValue.ToString("X4")} (word)" }
|
|
};
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private void GetSymbolByteRange(int lineIndex, out int rangeStart, out int rangeEnd)
|
|
{
|
|
int lineCount = _provider.GetLineCount();
|
|
while(lineIndex < lineCount - 2 && _provider.GetCodeLineData(lineIndex).AbsoluteAddress < 0) {
|
|
//Find the address of the next line with an address
|
|
lineIndex++;
|
|
}
|
|
|
|
rangeStart = _provider.GetCodeLineData(lineIndex).AbsoluteAddress;
|
|
if(rangeStart >= 0) {
|
|
while(lineIndex < lineCount - 2 && _provider.GetCodeLineData(lineIndex + 1).AbsoluteAddress < 0) {
|
|
//Find the next line with an address
|
|
lineIndex++;
|
|
}
|
|
|
|
rangeEnd = _provider.GetCodeLineData(lineIndex + 1).AbsoluteAddress - 1;
|
|
|
|
if(rangeStart < rangeEnd && (rangeEnd - rangeStart) < 500) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
rangeStart = 0;
|
|
rangeEnd = Int32.MaxValue;
|
|
}
|
|
}
|
|
}
|