mirror of
https://github.com/libretro/Mesen.git
synced 2024-11-30 20:40:54 +00:00
Debugger: Assembler improvements
This commit is contained in:
parent
09347d85b7
commit
03105846ff
@ -88,7 +88,7 @@ AssemblerSpecialCodes Assembler::GetLineData(std::smatch match, LineData &lineDa
|
||||
|
||||
bool foundSpace = false;
|
||||
for(char c : match.str(5)) {
|
||||
if(c != ' ') {
|
||||
if(c != ' ' && c != '\t') {
|
||||
if(foundSpace) {
|
||||
//can't have spaces in operands (except at the very end)
|
||||
return AssemblerSpecialCodes::InvalidSpaces;
|
||||
|
@ -758,3 +758,18 @@ void Debugger::SaveRomToDisk(string filename)
|
||||
{
|
||||
_mapper->SaveRomToDisk(filename);
|
||||
}
|
||||
|
||||
int32_t Debugger::FindSubEntryPoint(uint16_t relativeAddress)
|
||||
{
|
||||
AddressTypeInfo info;
|
||||
int32_t address = relativeAddress;
|
||||
do {
|
||||
GetAbsoluteAddressAndType(address, &info);
|
||||
if(info.Address < 0 || info.Type != AddressType::PrgRom || !_codeDataLogger->IsCode(info.Address) || _codeDataLogger->IsSubEntryPoint(info.Address)) {
|
||||
break;
|
||||
}
|
||||
address--;
|
||||
} while(address >= 0);
|
||||
|
||||
return address + 1;
|
||||
}
|
@ -180,4 +180,6 @@ public:
|
||||
void GetFreezeState(uint16_t startAddress, uint16_t length, bool* freezeState);
|
||||
|
||||
void SaveRomToDisk(string filename);
|
||||
|
||||
int32_t FindSubEntryPoint(uint16_t relativeAddress);
|
||||
};
|
@ -234,20 +234,17 @@ int32_t DisassemblyInfo::GetEffectiveAddress(State& cpuState, MemoryManager* mem
|
||||
|
||||
string DisassemblyInfo::GetByteCode()
|
||||
{
|
||||
if(_byteCode.empty()) {
|
||||
//Raw byte code
|
||||
string byteCodeOutput;
|
||||
byteCodeOutput.reserve(10);
|
||||
for(uint32_t i = 0; i < _opSize; i++) {
|
||||
if(!byteCodeOutput.empty()) {
|
||||
byteCodeOutput += " ";
|
||||
}
|
||||
byteCodeOutput += "$" + HexUtilities::ToHex((uint8_t)*(_opPointer + i));
|
||||
//Raw byte code
|
||||
string byteCode;
|
||||
byteCode.reserve(12);
|
||||
for(uint32_t i = 0; i < _opSize; i++) {
|
||||
if(!byteCode.empty()) {
|
||||
byteCode += " ";
|
||||
}
|
||||
_byteCode = byteCodeOutput;
|
||||
byteCode += "$" + HexUtilities::ToHex((uint8_t)*(_opPointer + i));
|
||||
}
|
||||
|
||||
return _byteCode;
|
||||
return byteCode;
|
||||
}
|
||||
|
||||
uint32_t DisassemblyInfo::GetSize()
|
||||
|
@ -14,7 +14,6 @@ public:
|
||||
static bool IsUnofficialCode[256];
|
||||
|
||||
private:
|
||||
string _byteCode;
|
||||
uint8_t *_opPointer = nullptr;
|
||||
bool _isSubEntryPoint = false;
|
||||
bool _isSubExitPoint = false;
|
||||
|
@ -68,6 +68,7 @@
|
||||
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.picCloseOccurrenceList = new System.Windows.Forms.PictureBox();
|
||||
this.lblSearchResult = new System.Windows.Forms.Label();
|
||||
this.mnuEditSelectedCode = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.contextMenuCode.SuspendLayout();
|
||||
this.contextMenuMargin.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
|
||||
@ -82,6 +83,7 @@
|
||||
// contextMenuCode
|
||||
//
|
||||
this.contextMenuCode.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.mnuEditSelectedCode,
|
||||
this.mnuEditSubroutine,
|
||||
this.toolStripMenuItem7,
|
||||
this.mnuShowNextStatement,
|
||||
@ -100,7 +102,7 @@
|
||||
this.mnuNavigateBackward,
|
||||
this.mnuNavigateForward});
|
||||
this.contextMenuCode.Name = "contextMenuWatch";
|
||||
this.contextMenuCode.Size = new System.Drawing.Size(259, 320);
|
||||
this.contextMenuCode.Size = new System.Drawing.Size(259, 342);
|
||||
this.contextMenuCode.Closed += new System.Windows.Forms.ToolStripDropDownClosedEventHandler(this.contextMenuCode_Closed);
|
||||
this.contextMenuCode.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuCode_Opening);
|
||||
//
|
||||
@ -446,6 +448,14 @@
|
||||
this.lblSearchResult.TabIndex = 11;
|
||||
this.lblSearchResult.Text = "Search results for: ";
|
||||
//
|
||||
// mnuEditSelectedCode
|
||||
//
|
||||
this.mnuEditSelectedCode.Image = global::Mesen.GUI.Properties.Resources.Edit;
|
||||
this.mnuEditSelectedCode.Name = "mnuEditSelectedCode";
|
||||
this.mnuEditSelectedCode.Size = new System.Drawing.Size(258, 22);
|
||||
this.mnuEditSelectedCode.Text = "Edit selected code";
|
||||
this.mnuEditSelectedCode.Click += new System.EventHandler(this.mnuEditSelectedCode_Click);
|
||||
//
|
||||
// ctrlDebuggerCode
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
@ -509,5 +519,6 @@
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem5;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem7;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuEditSubroutine;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuEditSelectedCode;
|
||||
}
|
||||
}
|
||||
|
@ -166,31 +166,45 @@ namespace Mesen.GUI.Debugger
|
||||
this.ctrlCodeViewer.EndUpdate();
|
||||
}
|
||||
|
||||
Dictionary<int, Tuple<string, string>> _codeContent = new Dictionary<int, Tuple<string, string>>();
|
||||
Dictionary<int, string> _codeContent = new Dictionary<int, string>();
|
||||
Dictionary<int, int> _codeByteContentLength = new Dictionary<int, int>();
|
||||
public List<string> GetCode(out int byteLength, int startAddress, int endAddress = -1)
|
||||
public List<string> GetCode(out int byteLength, ref int startAddress, int endAddress = -1)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
byteLength = 0;
|
||||
|
||||
//TODO: Handle multi-line comments
|
||||
//TODO: Find start of function
|
||||
//TODO: Display labels in code window
|
||||
//TODO: Status bar to show cursor's current line
|
||||
//TODO: Bind "Start Address" field
|
||||
//TODO: Byte code cache doesn't update
|
||||
if(endAddress == -1) {
|
||||
//When no end address is specified, find the start of the function based on startAddress
|
||||
int address = InteropEmu.DebugFindSubEntryPoint((UInt16)startAddress);
|
||||
if(address != -1) {
|
||||
startAddress = address;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Invalidate disassembly info cache / CDL file (not needed?)
|
||||
//TODO: Support .data syntax in assembler
|
||||
for(int i = startAddress; (i < endAddress || endAddress == -1) && endAddress < 65536; ) {
|
||||
Tuple<string, string> codeRow;
|
||||
if(_codeContent.TryGetValue(i, out codeRow)) {
|
||||
string code = codeRow.Item1;
|
||||
string comment = codeRow.Item2;
|
||||
for(int i = startAddress; (i <= endAddress || endAddress == -1) && endAddress < 65536; ) {
|
||||
if(_codeContent.TryGetValue(i, out string code)) {
|
||||
if(code.StartsWith("--") || code.StartsWith("__") || code.StartsWith("[[")) {
|
||||
//Stop adding code when we find a new section (new function, data blocks, etc.)
|
||||
break;
|
||||
}
|
||||
|
||||
result.Add(code + (comment ?? ""));
|
||||
AddressTypeInfo info = new AddressTypeInfo();
|
||||
InteropEmu.DebugGetAbsoluteAddressAndType((UInt32)i, ref info);
|
||||
CodeLabel codeLabel = info.Address >= 0 ? LabelManager.GetLabel((UInt32)info.Address, AddressType.PrgRom) : null;
|
||||
string comment = codeLabel?.Comment;
|
||||
string label = codeLabel?.Label;
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(comment) && comment.Contains("\n")) {
|
||||
result.AddRange(comment.Replace("\r", "").Split('\n').Select(cmt => ";" + cmt));
|
||||
comment = null;
|
||||
}
|
||||
if(!string.IsNullOrWhiteSpace(label)) {
|
||||
result.Add(label + ":");
|
||||
}
|
||||
result.Add(" " + code + (!string.IsNullOrWhiteSpace(comment) ? (" ;" + comment) : ""));
|
||||
|
||||
int length = _codeByteContentLength[i];
|
||||
byteLength += length;
|
||||
i += length;
|
||||
@ -213,7 +227,7 @@ namespace Mesen.GUI.Debugger
|
||||
List<string> lineNumberNotes = new List<string>();
|
||||
List<string> codeNotes = new List<string>();
|
||||
List<string> codeLines = new List<string>();
|
||||
_codeContent = new Dictionary<int, Tuple<string, string>>();
|
||||
_codeContent = new Dictionary<int, string>();
|
||||
_codeByteContentLength = new Dictionary<int, int>();
|
||||
_unexecutedAddresses = new HashSet<int>();
|
||||
_speculativeCodeAddreses = new HashSet<int>();
|
||||
@ -239,8 +253,7 @@ namespace Mesen.GUI.Debugger
|
||||
codeLines.Add(lineParts[4]);
|
||||
_codeByteContentLength[relativeAddress] = lineParts[3].Count(c => c == ' ') + 1;
|
||||
|
||||
string[] codeRow = lineParts[4].Split('\x2');
|
||||
_codeContent[relativeAddress] = new Tuple<string, string>(codeRow[0].Trim(), codeRow.Length > 2 ? " " + codeRow[2].Replace(Environment.NewLine, " | ") : null);
|
||||
_codeContent[relativeAddress] = lineParts[4].Split('\x2')[0].Trim();
|
||||
}
|
||||
|
||||
previousIndex = index;
|
||||
@ -738,10 +751,21 @@ namespace Mesen.GUI.Debugger
|
||||
int currentLine = this.GetCurrentLine();
|
||||
if(currentLine != -1 && InteropEmu.DebugIsExecutionStopped()) {
|
||||
int byteLength;
|
||||
List<string> code = this.GetCode(out byteLength, currentLine);
|
||||
List<string> code = this.GetCode(out byteLength, ref currentLine);
|
||||
this.OnEditCode?.Invoke(new AssemblerEventArgs() { Code = string.Join(Environment.NewLine, code), StartAddress = (UInt16)currentLine, BlockLength = (UInt16)byteLength });
|
||||
}
|
||||
}
|
||||
|
||||
private void mnuEditSelectedCode_Click(object sender, EventArgs e)
|
||||
{
|
||||
int startAddress = this.GetCurrentLine();
|
||||
int endAddress = this.ctrlCodeViewer.LastSelectedLine;
|
||||
if(startAddress != -1 && InteropEmu.DebugIsExecutionStopped()) {
|
||||
int byteLength;
|
||||
List<string> code = this.GetCode(out byteLength, ref startAddress, endAddress);
|
||||
this.OnEditCode?.Invoke(new AssemblerEventArgs() { Code = string.Join(Environment.NewLine, code), StartAddress = (UInt16)startAddress, BlockLength = (UInt16)byteLength });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class WatchEventArgs : EventArgs
|
||||
|
@ -160,6 +160,11 @@ namespace Mesen.GUI.Debugger
|
||||
get { return this.ctrlTextbox.CurrentLine; }
|
||||
}
|
||||
|
||||
public int LastSelectedLine
|
||||
{
|
||||
get { return this.ctrlTextbox.LastSelectedLine; }
|
||||
}
|
||||
|
||||
public int CodeMargin
|
||||
{
|
||||
get { return this.ctrlTextbox.CodeMargin; }
|
||||
@ -175,32 +180,57 @@ namespace Mesen.GUI.Debugger
|
||||
{
|
||||
if(!this.cboSearch.Focused) {
|
||||
switch(keyData) {
|
||||
case Keys.Right | Keys.Shift:
|
||||
case Keys.Down | Keys.Shift:
|
||||
this.ctrlTextbox.MoveSelectionDown();
|
||||
return true;
|
||||
|
||||
case Keys.Down:
|
||||
case Keys.Right:
|
||||
this.ctrlTextbox.CursorPosition++;
|
||||
this.ctrlTextbox.SelectionStart++;
|
||||
this.ctrlTextbox.SelectionLength = 0;
|
||||
return true;
|
||||
|
||||
case Keys.Up | Keys.Shift:
|
||||
case Keys.Left | Keys.Shift:
|
||||
this.ctrlTextbox.MoveSelectionUp();
|
||||
return true;
|
||||
|
||||
case Keys.Up:
|
||||
case Keys.Left:
|
||||
this.ctrlTextbox.CursorPosition--;
|
||||
this.ctrlTextbox.SelectionStart--;
|
||||
this.ctrlTextbox.SelectionLength = 0;
|
||||
return true;
|
||||
|
||||
case Keys.Home:
|
||||
this.ctrlTextbox.CursorPosition = 0;
|
||||
this.ctrlTextbox.SelectionStart = 0;
|
||||
this.ctrlTextbox.SelectionLength = 0;
|
||||
return true;
|
||||
|
||||
case Keys.End:
|
||||
this.ctrlTextbox.CursorPosition = this.ctrlTextbox.LineCount - 1;
|
||||
this.ctrlTextbox.SelectionStart = this.ctrlTextbox.LineCount - 1;
|
||||
this.ctrlTextbox.SelectionLength = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
switch(keyData) {
|
||||
case Keys.PageUp | Keys.Shift:
|
||||
this.ctrlTextbox.MoveSelectionUp(20);
|
||||
return true;
|
||||
|
||||
case Keys.PageUp:
|
||||
this.ctrlTextbox.CursorPosition-=20;
|
||||
this.ctrlTextbox.SelectionStart-=20;
|
||||
this.ctrlTextbox.SelectionLength = 0;
|
||||
return true;
|
||||
|
||||
case Keys.PageDown | Keys.Shift:
|
||||
this.ctrlTextbox.MoveSelectionDown(20);
|
||||
return true;
|
||||
|
||||
case Keys.PageDown:
|
||||
this.ctrlTextbox.CursorPosition+=20;
|
||||
this.ctrlTextbox.SelectionStart+=20;
|
||||
this.ctrlTextbox.SelectionLength = 0;
|
||||
return true;
|
||||
|
||||
case Keys.Control | Keys.F:
|
||||
@ -385,7 +415,7 @@ namespace Mesen.GUI.Debugger
|
||||
GoToAddress address = new GoToAddress();
|
||||
|
||||
int currentAddr = this.CurrentLine;
|
||||
int lineIndex = this.ctrlTextbox.CursorPosition;
|
||||
int lineIndex = this.ctrlTextbox.SelectionStart;
|
||||
while(currentAddr < 0) {
|
||||
lineIndex++;
|
||||
currentAddr = this.ctrlTextbox.GetLineNumber(lineIndex);
|
||||
|
@ -59,7 +59,8 @@ namespace Mesen.GUI.Debugger
|
||||
private bool _showSingleLineLineNumberNotes = false;
|
||||
private bool _showContentNotes = false;
|
||||
private bool _showSingleLineContentNotes = true;
|
||||
private int _cursorPosition = 0;
|
||||
private int _selectionStart = 0;
|
||||
private int _selectionLength = 0;
|
||||
private int _scrollPosition = 0;
|
||||
private int _horizontalScrollPosition = 0;
|
||||
private string _searchString = null;
|
||||
@ -278,8 +279,8 @@ namespace Mesen.GUI.Debugger
|
||||
this._searchString = searchString.ToLowerInvariant();
|
||||
int searchOffset = (searchBackwards ? -1 : 1);
|
||||
if(isNewSearch) {
|
||||
startPosition = this.CursorPosition;
|
||||
endPosition = this.CursorPosition - searchOffset;
|
||||
startPosition = this.SelectionStart;
|
||||
endPosition = this.SelectionStart - searchOffset;
|
||||
if(endPosition < 0) {
|
||||
endPosition = _contents.Length - 1;
|
||||
} else if(endPosition >= _contents.Length) {
|
||||
@ -287,8 +288,8 @@ namespace Mesen.GUI.Debugger
|
||||
}
|
||||
|
||||
} else {
|
||||
startPosition = this.CursorPosition + searchOffset;
|
||||
endPosition = this.CursorPosition;
|
||||
startPosition = this.SelectionStart + searchOffset;
|
||||
endPosition = this.SelectionStart;
|
||||
if(startPosition < 0) {
|
||||
startPosition = _contents.Length - 1;
|
||||
} else if(startPosition >= _contents.Length) {
|
||||
@ -311,7 +312,7 @@ namespace Mesen.GUI.Debugger
|
||||
}
|
||||
}
|
||||
this.Invalidate();
|
||||
return _contents[_cursorPosition].ToLowerInvariant().Contains(this._searchString);
|
||||
return _contents[_selectionStart].ToLowerInvariant().Contains(this._searchString);
|
||||
}
|
||||
}
|
||||
|
||||
@ -378,7 +379,7 @@ namespace Mesen.GUI.Debugger
|
||||
|
||||
public void ScrollToLineIndex(int lineIndex, eHistoryType historyType = eHistoryType.Always)
|
||||
{
|
||||
if(this.CursorPosition != lineIndex) {
|
||||
if(this.SelectionStart != lineIndex) {
|
||||
bool scrolled = false;
|
||||
if(lineIndex < this.ScrollPosition || lineIndex > this.GetLastVisibleLineIndex()) {
|
||||
//Line isn't currently visible, scroll it to the middle of the viewport
|
||||
@ -387,11 +388,12 @@ namespace Mesen.GUI.Debugger
|
||||
}
|
||||
|
||||
if(historyType == eHistoryType.Always || scrolled && historyType == eHistoryType.OnScroll) {
|
||||
_history.AddHistory(this.CursorPosition);
|
||||
_history.AddHistory(this.SelectionStart);
|
||||
}
|
||||
this.CursorPosition = lineIndex;
|
||||
this.SelectionStart = lineIndex;
|
||||
this.SelectionLength = 0;
|
||||
if(historyType == eHistoryType.Always || scrolled && historyType == eHistoryType.OnScroll) {
|
||||
_history.AddHistory(this.CursorPosition);
|
||||
_history.AddHistory(this.SelectionStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -511,24 +513,110 @@ namespace Mesen.GUI.Debugger
|
||||
|
||||
[Browsable(false)]
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public int CursorPosition
|
||||
public int SelectionStart
|
||||
{
|
||||
get { return Math.Min(this._contents.Length - 1, Math.Max(0, _cursorPosition)); }
|
||||
get { return Math.Min(this._contents.Length - 1, Math.Max(0, _selectionStart)); }
|
||||
set
|
||||
{
|
||||
_cursorPosition = Math.Max(0, Math.Min(this._contents.Length - 1, Math.Max(0, value)));
|
||||
if(_cursorPosition < this.ScrollPosition) {
|
||||
this.ScrollPosition = _cursorPosition;
|
||||
} else if(_cursorPosition > this.GetLastVisibleLineIndex()) {
|
||||
this.ScrollPosition = _cursorPosition - this.GetNumberVisibleLines() + 1;
|
||||
{
|
||||
int selectionStart = Math.Max(0, Math.Min(this._contents.Length - 1, Math.Max(0, value)));
|
||||
|
||||
_selectionStart = selectionStart;
|
||||
|
||||
if(this.SelectionLength == 0) {
|
||||
this.SelectedLine = this.SelectionStart;
|
||||
}
|
||||
|
||||
this.Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
[Browsable(false)]
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public int SelectionLength
|
||||
{
|
||||
get { return (this.SelectionStart + _selectionLength) > this._contents.Length - 1 ? this._contents.Length - this.SelectionStart - 1 : _selectionLength; }
|
||||
set
|
||||
{
|
||||
_selectionLength = value;
|
||||
|
||||
if(this.SelectionStart + _selectionLength > this._contents.Length - 1) {
|
||||
_selectionLength = this._contents.Length - this.SelectionStart - 1;
|
||||
}
|
||||
|
||||
if(value == 0) {
|
||||
this.SelectedLine = this.SelectionStart;
|
||||
}
|
||||
|
||||
this.Invalidate();
|
||||
}
|
||||
}
|
||||
[Browsable(false)]
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
private int SelectedLine
|
||||
{
|
||||
get { return this._selectedLine; }
|
||||
set
|
||||
{
|
||||
this._selectedLine = value;
|
||||
if(_selectedLine < this.ScrollPosition) {
|
||||
this.ScrollPosition = _selectedLine;
|
||||
} else if(_selectedLine > this.GetLastVisibleLineIndex()) {
|
||||
this.ScrollPosition = _selectedLine - this.GetNumberVisibleLines() + 1;
|
||||
}
|
||||
this.Invalidate();
|
||||
}
|
||||
}
|
||||
private int _selectedLine = 0;
|
||||
|
||||
public void MoveSelectionDown(int lines = 1)
|
||||
{
|
||||
while(lines > 0) {
|
||||
bool singleLineSelection = this.SelectionLength == 0;
|
||||
|
||||
if(singleLineSelection) {
|
||||
this.SelectedLine = this.SelectionStart + 1;
|
||||
this.SelectionLength++;
|
||||
} else if(this.SelectionStart + this.SelectionLength == this.SelectedLine) {
|
||||
this.SelectedLine++;
|
||||
this.SelectionLength++;
|
||||
} else {
|
||||
this.SelectionStart++;
|
||||
this.SelectedLine++;
|
||||
this.SelectionLength--;
|
||||
}
|
||||
lines--;
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveSelectionUp(int lines = 1)
|
||||
{
|
||||
while(lines > 0) {
|
||||
bool singleLineSelection = this.SelectionLength == 0;
|
||||
|
||||
if(singleLineSelection) {
|
||||
this.SelectionStart--;
|
||||
this.SelectedLine = this.SelectionStart;
|
||||
this.SelectionLength++;
|
||||
} else if(this.SelectionStart == this.SelectedLine) {
|
||||
this.SelectionStart--;
|
||||
this.SelectedLine--;
|
||||
this.SelectionLength++;
|
||||
} else {
|
||||
this.SelectedLine--;
|
||||
this.SelectionLength--;
|
||||
}
|
||||
lines--;
|
||||
}
|
||||
}
|
||||
|
||||
public int CurrentLine
|
||||
{
|
||||
get { return _lineNumbers.Length > _cursorPosition ? _lineNumbers[_cursorPosition] : 0; }
|
||||
get { return _lineNumbers.Length > _selectionStart ? _lineNumbers[_selectionStart] : 0; }
|
||||
}
|
||||
|
||||
public int LastSelectedLine
|
||||
{
|
||||
get { return _lineNumbers.Length > _selectionStart + this.SelectionLength ? _lineNumbers[_selectionStart + this.SelectionLength] : 0; }
|
||||
}
|
||||
|
||||
[Browsable(false)]
|
||||
@ -615,8 +703,26 @@ namespace Mesen.GUI.Debugger
|
||||
} else if(e.Button == MouseButtons.XButton2) {
|
||||
this.NavigateForward();
|
||||
} else {
|
||||
int clickedLine = this.GetLineAtPosition(e.Y);
|
||||
this.CursorPosition = this.ScrollPosition + clickedLine;
|
||||
int clickedLine = this.ScrollPosition + this.GetLineAtPosition(e.Y);
|
||||
|
||||
if(e.Button == MouseButtons.Right) {
|
||||
if(clickedLine >= this.SelectionStart && clickedLine <= this.SelectionStart + this.SelectionLength) {
|
||||
//Right-clicking on selection should not change it
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(Control.ModifierKeys.HasFlag(Keys.Shift)) {
|
||||
if(clickedLine > this.SelectedLine) {
|
||||
MoveSelectionDown(clickedLine - this.SelectedLine);
|
||||
} else {
|
||||
MoveSelectionUp(this.SelectedLine - clickedLine);
|
||||
}
|
||||
} else {
|
||||
this.SelectedLine = clickedLine;
|
||||
this.SelectionStart = clickedLine;
|
||||
this.SelectionLength = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -640,9 +746,15 @@ namespace Mesen.GUI.Debugger
|
||||
float codeStringLength = g.MeasureString(codeString, this.Font).Width;
|
||||
float addressStringLength = g.MeasureString(addressString, this.Font).Width;
|
||||
|
||||
if(currentLine == this.CursorPosition) {
|
||||
if(currentLine >= this.SelectionStart && currentLine <= this.SelectionStart + this.SelectionLength) {
|
||||
//Highlight current line
|
||||
g.FillRectangle(Brushes.AliceBlue, marginLeft, positionY, Math.Max(_maxLineWidth, this.ClientRectangle.Width), lineHeight);
|
||||
using(Brush brush = new SolidBrush(Color.FromArgb(230, 238, 255))) {
|
||||
int offset = currentLine - 1 == this.SelectedLine ? 1 : 0;
|
||||
g.FillRectangle(brush, marginLeft, positionY + offset, Math.Max(_maxLineWidth, this.ClientRectangle.Width), lineHeight - offset);
|
||||
}
|
||||
if(currentLine == this.SelectedLine) {
|
||||
g.DrawRectangle(Pens.Blue, marginLeft + 1, positionY+1, Math.Max(_maxLineWidth, this.ClientRectangle.Width - marginLeft) - 1, lineHeight);
|
||||
}
|
||||
}
|
||||
|
||||
//Adjust background color highlights based on number of spaces in front of content
|
||||
|
75
GUI.NET/Debugger/frmAssembler.Designer.cs
generated
75
GUI.NET/Debugger/frmAssembler.Designer.cs
generated
@ -45,6 +45,10 @@
|
||||
this.lblNoChanges = new System.Windows.Forms.Label();
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.txtCode = new System.Windows.Forms.RichTextBox();
|
||||
this.statCode = new System.Windows.Forms.StatusStrip();
|
||||
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.lblLineNumber = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.picStartAddressWarning = new System.Windows.Forms.PictureBox();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.grpSettings.SuspendLayout();
|
||||
this.tableLayoutPanel2.SuspendLayout();
|
||||
@ -53,6 +57,8 @@
|
||||
((System.ComponentModel.ISupportInitialize)(this.picSizeWarning)).BeginInit();
|
||||
this.flowLayoutPanel3.SuspendLayout();
|
||||
this.panel1.SuspendLayout();
|
||||
this.statCode.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picStartAddressWarning)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btnOk
|
||||
@ -92,7 +98,7 @@
|
||||
this.tableLayoutPanel1.RowCount = 2;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 141F));
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(999, 534);
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(999, 555);
|
||||
this.tableLayoutPanel1.TabIndex = 2;
|
||||
//
|
||||
// ctrlHexBox
|
||||
@ -107,7 +113,7 @@
|
||||
this.ctrlHexBox.Name = "ctrlHexBox";
|
||||
this.ctrlHexBox.ReadOnly = true;
|
||||
this.ctrlHexBox.ShadowSelectionColor = System.Drawing.Color.FromArgb(((int)(((byte)(100)))), ((int)(((byte)(60)))), ((int)(((byte)(188)))), ((int)(((byte)(255)))));
|
||||
this.ctrlHexBox.Size = new System.Drawing.Size(444, 387);
|
||||
this.ctrlHexBox.Size = new System.Drawing.Size(444, 408);
|
||||
this.ctrlHexBox.TabIndex = 1;
|
||||
this.ctrlHexBox.UseFixedBytesPerLine = true;
|
||||
this.ctrlHexBox.VScrollBarVisible = true;
|
||||
@ -115,7 +121,7 @@
|
||||
// lstErrors
|
||||
//
|
||||
this.lstErrors.FormattingEnabled = true;
|
||||
this.lstErrors.Location = new System.Drawing.Point(3, 396);
|
||||
this.lstErrors.Location = new System.Drawing.Point(3, 417);
|
||||
this.lstErrors.Name = "lstErrors";
|
||||
this.lstErrors.Size = new System.Drawing.Size(543, 134);
|
||||
this.lstErrors.TabIndex = 2;
|
||||
@ -124,7 +130,7 @@
|
||||
//
|
||||
this.grpSettings.Controls.Add(this.tableLayoutPanel2);
|
||||
this.grpSettings.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.grpSettings.Location = new System.Drawing.Point(552, 396);
|
||||
this.grpSettings.Location = new System.Drawing.Point(552, 417);
|
||||
this.grpSettings.Name = "grpSettings";
|
||||
this.grpSettings.Size = new System.Drawing.Size(444, 135);
|
||||
this.grpSettings.TabIndex = 3;
|
||||
@ -152,6 +158,7 @@
|
||||
//
|
||||
this.flowLayoutPanel1.Controls.Add(this.label1);
|
||||
this.flowLayoutPanel1.Controls.Add(this.txtStartAddress);
|
||||
this.flowLayoutPanel1.Controls.Add(this.picStartAddressWarning);
|
||||
this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(0);
|
||||
@ -175,9 +182,11 @@
|
||||
this.txtStartAddress.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.txtStartAddress.Location = new System.Drawing.Point(84, 3);
|
||||
this.txtStartAddress.Margin = new System.Windows.Forms.Padding(0, 3, 3, 3);
|
||||
this.txtStartAddress.MaxLength = 4;
|
||||
this.txtStartAddress.Name = "txtStartAddress";
|
||||
this.txtStartAddress.Size = new System.Drawing.Size(65, 20);
|
||||
this.txtStartAddress.Size = new System.Drawing.Size(48, 20);
|
||||
this.txtStartAddress.TabIndex = 1;
|
||||
this.txtStartAddress.TextChanged += new System.EventHandler(this.txtStartAddress_TextChanged);
|
||||
//
|
||||
// flowLayoutPanel2
|
||||
//
|
||||
@ -251,34 +260,76 @@
|
||||
//
|
||||
this.panel1.BackColor = System.Drawing.SystemColors.ControlDark;
|
||||
this.panel1.Controls.Add(this.txtCode);
|
||||
this.panel1.Controls.Add(this.statCode);
|
||||
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.panel1.Location = new System.Drawing.Point(3, 3);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Padding = new System.Windows.Forms.Padding(1);
|
||||
this.panel1.Size = new System.Drawing.Size(543, 387);
|
||||
this.panel1.Size = new System.Drawing.Size(543, 408);
|
||||
this.panel1.TabIndex = 4;
|
||||
//
|
||||
// txtCode
|
||||
//
|
||||
this.txtCode.AcceptsTab = true;
|
||||
this.txtCode.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.txtCode.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.txtCode.DetectUrls = false;
|
||||
this.txtCode.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.txtCode.Location = new System.Drawing.Point(1, 1);
|
||||
this.txtCode.Name = "txtCode";
|
||||
this.txtCode.Size = new System.Drawing.Size(541, 385);
|
||||
this.txtCode.TabIndex = 4;
|
||||
this.txtCode.Text = "";
|
||||
this.txtCode.WordWrap = false;
|
||||
this.txtCode.SelectionChanged += new System.EventHandler(this.txtCode_SelectionChanged);
|
||||
this.txtCode.TextChanged += new System.EventHandler(this.txtCode_TextChanged);
|
||||
this.txtCode.KeyDown += new System.Windows.Forms.KeyEventHandler(this.txtCode_KeyDown);
|
||||
//
|
||||
// statCode
|
||||
//
|
||||
this.statCode.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.toolStripStatusLabel1,
|
||||
this.lblLineNumber});
|
||||
this.statCode.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.Flow;
|
||||
this.statCode.Location = new System.Drawing.Point(1, 387);
|
||||
this.statCode.Name = "statCode";
|
||||
this.statCode.RenderMode = System.Windows.Forms.ToolStripRenderMode.Professional;
|
||||
this.statCode.Size = new System.Drawing.Size(541, 20);
|
||||
this.statCode.SizingGrip = false;
|
||||
this.statCode.TabIndex = 5;
|
||||
//
|
||||
// toolStripStatusLabel1
|
||||
//
|
||||
this.toolStripStatusLabel1.BackColor = System.Drawing.SystemColors.Control;
|
||||
this.toolStripStatusLabel1.Name = "toolStripStatusLabel1";
|
||||
this.toolStripStatusLabel1.Size = new System.Drawing.Size(32, 15);
|
||||
this.toolStripStatusLabel1.Text = "Line:";
|
||||
//
|
||||
// lblLineNumber
|
||||
//
|
||||
this.lblLineNumber.BackColor = System.Drawing.SystemColors.Control;
|
||||
this.lblLineNumber.Name = "lblLineNumber";
|
||||
this.lblLineNumber.Size = new System.Drawing.Size(13, 15);
|
||||
this.lblLineNumber.Text = "1";
|
||||
//
|
||||
// picStartAddressWarning
|
||||
//
|
||||
this.picStartAddressWarning.Image = global::Mesen.GUI.Properties.Resources.Warning;
|
||||
this.picStartAddressWarning.Location = new System.Drawing.Point(138, 5);
|
||||
this.picStartAddressWarning.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3);
|
||||
this.picStartAddressWarning.Name = "picStartAddressWarning";
|
||||
this.picStartAddressWarning.Size = new System.Drawing.Size(18, 18);
|
||||
this.picStartAddressWarning.TabIndex = 11;
|
||||
this.picStartAddressWarning.TabStop = false;
|
||||
this.picStartAddressWarning.Visible = false;
|
||||
//
|
||||
// frmAssembler
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.btnCancel;
|
||||
this.ClientSize = new System.Drawing.Size(999, 534);
|
||||
this.ClientSize = new System.Drawing.Size(999, 555);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Name = "frmAssembler";
|
||||
this.Text = "Assembler";
|
||||
@ -293,6 +344,10 @@
|
||||
this.flowLayoutPanel3.ResumeLayout(false);
|
||||
this.flowLayoutPanel3.PerformLayout();
|
||||
this.panel1.ResumeLayout(false);
|
||||
this.panel1.PerformLayout();
|
||||
this.statCode.ResumeLayout(false);
|
||||
this.statCode.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picStartAddressWarning)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
@ -316,5 +371,9 @@
|
||||
private System.Windows.Forms.RichTextBox txtCode;
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.Label lblNoChanges;
|
||||
private System.Windows.Forms.StatusStrip statCode;
|
||||
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1;
|
||||
private System.Windows.Forms.ToolStripStatusLabel lblLineNumber;
|
||||
private System.Windows.Forms.PictureBox picStartAddressWarning;
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ namespace Mesen.GUI.Debugger
|
||||
private bool _hasParsingErrors = false;
|
||||
private bool _containedRtiRts = false;
|
||||
private bool _isEditMode = false;
|
||||
private bool _startAddressValid = true;
|
||||
|
||||
public frmAssembler(string code = "", UInt16 startAddress = 0, UInt16 blockLength = 0)
|
||||
{
|
||||
@ -52,6 +53,7 @@ namespace Mesen.GUI.Debugger
|
||||
txtCode.Select(0, 0);
|
||||
|
||||
toolTip.SetToolTip(picSizeWarning, "Warning: The new code exceeds the original code's length." + Environment.NewLine + "Applying this modification will overwrite other portions of the code and potentially cause problems.");
|
||||
toolTip.SetToolTip(picStartAddressWarning, "Warning: Start address is invalid. Must be a valid hexadecimal string.");
|
||||
|
||||
UpdateWindow();
|
||||
}
|
||||
@ -137,10 +139,13 @@ namespace Mesen.GUI.Debugger
|
||||
|
||||
bool isIdentical = IsIdentical;
|
||||
lblNoChanges.Visible = isIdentical;
|
||||
btnOk.Enabled = !isIdentical;
|
||||
btnOk.Enabled = !isIdentical && _startAddressValid;
|
||||
} else {
|
||||
lblNoChanges.Visible = false;
|
||||
lblByteUsage.Text = ctrlHexBox.ByteProvider.Length.ToString();
|
||||
}
|
||||
|
||||
picStartAddressWarning.Visible = !_startAddressValid;
|
||||
}
|
||||
|
||||
private void txtCode_TextChanged(object sender, EventArgs e)
|
||||
@ -156,6 +161,22 @@ namespace Mesen.GUI.Debugger
|
||||
}
|
||||
}
|
||||
|
||||
private void txtCode_SelectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
lblLineNumber.Text = (txtCode.GetLineFromCharIndex(txtCode.GetFirstCharIndexOfCurrentLine()) + 1).ToString();
|
||||
}
|
||||
|
||||
private void txtStartAddress_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
try {
|
||||
_startAddress = UInt16.Parse(txtStartAddress.Text, System.Globalization.NumberStyles.HexNumber);
|
||||
_startAddressValid = true;
|
||||
} catch {
|
||||
_startAddressValid = false;
|
||||
}
|
||||
UpdateWindow();
|
||||
}
|
||||
|
||||
private void btnOk_Click(object sender, EventArgs e)
|
||||
{
|
||||
List<string> warningMessages = new List<string>();
|
||||
@ -168,6 +189,9 @@ namespace Mesen.GUI.Debugger
|
||||
if(NeedRtiRtsWarning) {
|
||||
warningMessages.Add("Warning: The code originally contained an RTI/RTS instruction and it no longer does - this will probably cause problems.");
|
||||
}
|
||||
if(!_startAddressValid) {
|
||||
warningMessages.Add("Warning: Start address is invalid. Must be a valid hexadecimal string.");
|
||||
}
|
||||
|
||||
if(warningMessages.Count == 0 || MessageBox.Show(string.Join(Environment.NewLine+Environment.NewLine, warningMessages.ToArray()) + Environment.NewLine + Environment.NewLine + "OK?", "Warning", MessageBoxButtons.OKCancel) == DialogResult.OK) {
|
||||
byte lastByte = ctrlHexBox.ByteProvider.ReadByte(ctrlHexBox.ByteProvider.Length - 1);
|
||||
|
@ -120,4 +120,7 @@
|
||||
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="statCode.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>107, 17</value>
|
||||
</metadata>
|
||||
</root>
|
@ -183,6 +183,7 @@ namespace Mesen.GUI
|
||||
[DllImport(DLLPath)] public static extern void DebugRun();
|
||||
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool DebugIsExecutionStopped();
|
||||
[DllImport(DLLPath)] public static extern Int32 DebugGetRelativeAddress(UInt32 absoluteAddr, AddressType type);
|
||||
[DllImport(DLLPath)] public static extern Int32 DebugFindSubEntryPoint(UInt16 relativeAddr);
|
||||
[DllImport(DLLPath)] public static extern Int32 DebugGetAbsoluteAddress(UInt32 relativeAddr);
|
||||
[DllImport(DLLPath)] public static extern Int32 DebugGetMemorySize(DebugMemoryType type);
|
||||
[DllImport(DLLPath)] public static extern Byte DebugGetMemoryValue(DebugMemoryType type, UInt32 address);
|
||||
|
@ -97,4 +97,6 @@ extern "C"
|
||||
DllExport uint32_t __stdcall DebugAssembleCode(char* code, uint16_t startAddress, int16_t* assembledOutput) { return GetDebugger()->GetAssembler()->AssembleCode(code, startAddress, assembledOutput); }
|
||||
|
||||
DllExport void __stdcall DebugSaveRomToDisk(char* filename) { GetDebugger()->SaveRomToDisk(filename); }
|
||||
|
||||
DllExport int32_t __stdcall DebugFindSubEntryPoint(uint16_t relativeAddress) { return GetDebugger()->FindSubEntryPoint(relativeAddress); }
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user