Debugger: Assembler improvements

This commit is contained in:
Souryo 2017-03-09 20:42:53 -05:00
parent 09347d85b7
commit 03105846ff
14 changed files with 350 additions and 71 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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()

View File

@ -14,7 +14,6 @@ public:
static bool IsUnofficialCode[256];
private:
string _byteCode;
uint8_t *_opPointer = nullptr;
bool _isSubEntryPoint = false;
bool _isSubExitPoint = false;

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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>

View File

@ -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);

View File

@ -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); }
};