1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Drawing; 5 using System.Data; 6 using System.Linq; 7 using System.Text; 8 using System.Threading.Tasks; 9 using System.Windows.Forms; 10 using Mesen.GUI.Debugger.Controls; 11 using Mesen.GUI.Config; 12 using Mesen.GUI.Controls; 13 using System.Text.RegularExpressions; 14 15 namespace Mesen.GUI.Debugger 16 { 17 public partial class ctrlDebuggerCode : BaseScrollableTextboxUserControl, ICodeViewer 18 { AssemblerEventHandler(AssemblerEventArgs args)19 public delegate void AssemblerEventHandler(AssemblerEventArgs args); 20 public event AssemblerEventHandler OnEditCode; 21 22 private UInt32? _currentActiveAddress { get; set; } = null; 23 24 private DebugViewInfo _config; 25 private CodeTooltipManager _tooltipManager = null; 26 private CodeViewerActions _codeViewerActions; 27 ctrlDebuggerCode()28 public ctrlDebuggerCode() 29 { 30 InitializeComponent(); 31 _tooltipManager = new CodeTooltipManager(this, this.ctrlCodeViewer); 32 } 33 OnLoad(EventArgs e)34 protected override void OnLoad(EventArgs e) 35 { 36 base.OnLoad(e); 37 if(!IsDesignMode) { 38 _codeViewerActions = new CodeViewerActions(this, false); 39 40 ctrlFindOccurrences.Viewer = this; 41 splitContainer.Panel2Collapsed = true; 42 43 this.SymbolProvider = DebugWorkspaceManager.SymbolProvider; 44 DebugWorkspaceManager.SymbolProviderChanged += UpdateSymbolProvider; 45 } 46 } 47 UpdateSymbolProvider(Ld65DbgImporter symbolProvider)48 private void UpdateSymbolProvider(Ld65DbgImporter symbolProvider) 49 { 50 this.SymbolProvider = symbolProvider; 51 } 52 SetConfig(DebugViewInfo config, bool disableActions = false)53 public void SetConfig(DebugViewInfo config, bool disableActions = false) 54 { 55 _config = config; 56 if(!disableActions) { 57 _codeViewerActions.InitMenu(config); 58 } 59 60 if(this.ctrlCodeViewer.TextZoom != config.TextZoom) { 61 this.ctrlCodeViewer.TextZoom = config.TextZoom; 62 } 63 } 64 SetMessage(TextboxMessageInfo message)65 public void SetMessage(TextboxMessageInfo message) 66 { 67 this.ctrlCodeViewer.SetMessage(message); 68 } 69 70 protected override ctrlScrollableTextbox ScrollableTextbox 71 { 72 get { return this.ctrlCodeViewer; } 73 } 74 75 private Ld65DbgImporter _symbolProvider; 76 public Ld65DbgImporter SymbolProvider 77 { 78 get { return _symbolProvider; } 79 set { _symbolProvider = value; } 80 } 81 82 private CodeInfo _code = new CodeInfo(""); 83 84 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 85 public CodeInfo Code 86 { 87 get { return _code; } 88 set 89 { 90 _code = value; 91 _tooltipManager.Code = value; 92 UpdateCode(); 93 } 94 } 95 96 public bool ShowMemoryValues 97 { 98 get { return this.ctrlCodeViewer.ShowMemoryValues; } 99 set { this.ctrlCodeViewer.ShowMemoryValues = value; } 100 } 101 102 public ctrlScrollableTextbox CodeViewer { get { return this.ctrlCodeViewer; } } 103 public CodeViewerActions CodeViewerActions { get { return _codeViewerActions; } } 104 public uint? ActiveAddress { get { return _currentActiveAddress; } } 105 SelectActiveAddress(UInt32 address)106 public void SelectActiveAddress(UInt32 address) 107 { 108 this.SetActiveAddress(address); 109 this.ctrlCodeViewer.ScrollToLineNumber((int)address, eHistoryType.OnScroll); 110 } 111 SetActiveAddress(UInt32 address)112 public void SetActiveAddress(UInt32 address) 113 { 114 _currentActiveAddress = address; 115 } 116 ClearActiveAddress()117 public void ClearActiveAddress() 118 { 119 _currentActiveAddress = null; 120 } 121 UpdateLineColors()122 public void UpdateLineColors() 123 { 124 this.ctrlCodeViewer.StyleProvider = new LineStyleProvider(this); 125 if(this.ctrlCodeViewer.ShowScrollbars) { 126 this.ctrlCodeViewer.ScrollbarColorProvider = new ScrollbarColorProvider(this); 127 } 128 } 129 ScrollToAddress(AddressTypeInfo addressInfo, bool scrollToTop = false)130 public void ScrollToAddress(AddressTypeInfo addressInfo, bool scrollToTop = false) 131 { 132 int relativeAddress = InteropEmu.DebugGetRelativeAddress((uint)addressInfo.Address, addressInfo.Type); 133 if(relativeAddress >= 0) { 134 this.ctrlCodeViewer.ScrollToLineNumber(relativeAddress, eHistoryType.Always , scrollToTop); 135 } 136 } 137 GetCode(out int byteLength, ref int startAddress, int endAddress = -1)138 public List<string> GetCode(out int byteLength, ref int startAddress, int endAddress = -1) 139 { 140 _code.InitAssemblerValues(); 141 142 List<string> result = new List<string>(); 143 byteLength = 0; 144 145 if(endAddress == -1) { 146 //When no end address is specified, find the start of the function based on startAddress 147 int address = InteropEmu.DebugFindSubEntryPoint((UInt16)startAddress); 148 if(address != -1) { 149 startAddress = address; 150 } 151 } 152 153 for(int i = startAddress; (i <= endAddress || endAddress == -1) && endAddress < 65536; ) { 154 string code; 155 if(_code.CodeContent.TryGetValue(i, out code)) { 156 code = code.Split('\x2')[0].Trim(); 157 158 if(code.StartsWith("--") || code.StartsWith("__")) { 159 //Stop adding code when we find a new section (new function, data blocks, etc.) 160 break; 161 } 162 163 AddressTypeInfo info = new AddressTypeInfo(); 164 InteropEmu.DebugGetAbsoluteAddressAndType((UInt32)i, info); 165 CodeLabel codeLabel = info.Address >= 0 ? LabelManager.GetLabel((UInt32)info.Address, AddressType.PrgRom) : null; 166 string comment = codeLabel?.Comment; 167 string label = codeLabel?.Label; 168 169 bool addPadding = true; 170 if(code.StartsWith("STP*") || code.StartsWith("NOP*")) { 171 //Transform unofficial opcodes that can't be reassembled properly into .byte statements 172 if(comment != null) { 173 comment.Insert(0, code + " - "); 174 } else { 175 comment = code; 176 } 177 code = ".byte " + string.Join(",", _code.CodeByteCode[i].Split(' ')); 178 addPadding = false; 179 } 180 181 if(!string.IsNullOrWhiteSpace(comment) && comment.Contains("\n")) { 182 result.AddRange(comment.Replace("\r", "").Split('\n').Select(cmt => ";" + cmt)); 183 comment = null; 184 } 185 if(!string.IsNullOrWhiteSpace(label)) { 186 result.Add(label + ":"); 187 } 188 result.Add((addPadding ? " " : "") + code + (!string.IsNullOrWhiteSpace(comment) ? (" ;" + comment) : "")); 189 190 int length = _code.CodeByteCode[i].Count(c => c == ' ') + 1; 191 byteLength += length; 192 i += length; 193 194 if(endAddress == -1 && (string.Compare(code, "RTI", true) == 0 || string.Compare(code, "RTS", true) == 0)) { 195 break; 196 } 197 } else { 198 break; 199 } 200 } 201 202 result.Add(""); 203 return result; 204 } 205 UpdateCode()206 private void UpdateCode() 207 { 208 int centerLineIndex = ctrlCodeViewer.GetLineIndexAtPosition(0) + ctrlCodeViewer.GetNumberVisibleLines() / 2; 209 int centerLineAddress; 210 int scrollOffset = -1; 211 do { 212 //Save the address at the center of the debug view 213 centerLineAddress = ctrlCodeViewer.GetLineNumber(centerLineIndex); 214 centerLineIndex--; 215 scrollOffset++; 216 } while(centerLineAddress < 0 && centerLineIndex > 0); 217 218 219 ctrlCodeViewer.LineIndentations = _code.LineIndentations; 220 ctrlCodeViewer.Addressing = _code.Addressing; 221 ctrlCodeViewer.Comments = _code.Comments; 222 223 ctrlCodeViewer.LineNumbers = _code.LineNumbers; 224 ctrlCodeViewer.TextLineNotes = _code.CodeNotes; 225 ctrlCodeViewer.LineNumberNotes = _code.LineNumberNotes; 226 ctrlCodeViewer.TextLines = _code.CodeLines; 227 228 if(centerLineAddress >= 0) { 229 //Scroll to the same address as before, to prevent the code view from changing due to setting or banking changes, etc. 230 int lineIndex = ctrlCodeViewer.GetLineIndex(centerLineAddress) + scrollOffset; 231 ctrlCodeViewer.ScrollToLineIndex(lineIndex, eHistoryType.None, false, true); 232 } 233 } 234 GetCurrentLineBreakpoint()235 private Breakpoint GetCurrentLineBreakpoint() 236 { 237 AddressTypeInfo addressInfo = GetAddressInfo(ctrlCodeViewer.SelectedLine); 238 if(addressInfo.Address >= 0) { 239 int relativeAddress = InteropEmu.DebugGetRelativeAddress((uint)addressInfo.Address, addressInfo.Type); 240 return BreakpointManager.GetMatchingBreakpoint(relativeAddress, addressInfo); 241 } 242 return null; 243 } 244 ctrlCodeViewer_MouseMove(object sender, MouseEventArgs e)245 private void ctrlCodeViewer_MouseMove(object sender, MouseEventArgs e) 246 { 247 if(e.Location.X < this.ctrlCodeViewer.CodeMargin / 4) { 248 if(this.ctrlCodeViewer.ContextMenuStrip != contextMenuMargin) { 249 this.ctrlCodeViewer.ContextMenuStrip = contextMenuMargin; 250 ThemeHelper.FixMonoColors(contextMenuMargin); 251 } 252 } else { 253 if(this.ctrlCodeViewer.ContextMenuStrip != _codeViewerActions.contextMenu) { 254 this.ctrlCodeViewer.ContextMenuStrip = _codeViewerActions.contextMenu; 255 ThemeHelper.FixMonoColors(this.ctrlCodeViewer.ContextMenuStrip); 256 } 257 } 258 } 259 ProcessCmdKey(ref Message msg, Keys keyData)260 protected override bool ProcessCmdKey(ref Message msg, Keys keyData) 261 { 262 _codeViewerActions.UpdateContextMenuItemVisibility(_codeViewerActions.contextMenu.Items); 263 return base.ProcessCmdKey(ref msg, keyData); 264 } 265 ctrlCodeViewer_MouseUp(object sender, MouseEventArgs e)266 private void ctrlCodeViewer_MouseUp(object sender, MouseEventArgs e) 267 { 268 _codeViewerActions.ProcessMouseUp(e.Location, e.Button); 269 } 270 ctrlCodeViewer_MouseDown(object sender, MouseEventArgs e)271 private void ctrlCodeViewer_MouseDown(object sender, MouseEventArgs e) 272 { 273 if(e.Button == MouseButtons.Left && e.Location.X < this.ctrlCodeViewer.CodeMargin / 4) { 274 _codeViewerActions.ToggleBreakpoint(false); 275 } 276 } 277 GetAddressInfo(int lineNumber)278 public AddressTypeInfo GetAddressInfo(int lineNumber) 279 { 280 AddressTypeInfo info = new AddressTypeInfo(); 281 SetAddressInfo(info, lineNumber); 282 return info; 283 } 284 SetAddressInfo(AddressTypeInfo info, int lineNumber)285 private void SetAddressInfo(AddressTypeInfo info, int lineNumber) 286 { 287 if(lineNumber < this._code.AbsoluteLineNumbers.Length) { 288 info.Address = this._code.AbsoluteLineNumbers[lineNumber]; 289 switch(this._code.LineMemoryType[lineNumber]) { 290 case 'P': info.Type = AddressType.PrgRom; break; 291 case 'W': info.Type = AddressType.WorkRam; break; 292 case 'S': info.Type = AddressType.SaveRam; break; 293 case 'N': info.Type = AddressType.InternalRam; break; 294 } 295 } 296 } 297 ctrlCodeViewer_MouseDoubleClick(object sender, MouseEventArgs e)298 private void ctrlCodeViewer_MouseDoubleClick(object sender, MouseEventArgs e) 299 { 300 if(e.Location.X > this.ctrlCodeViewer.CodeMargin / 2 && e.Location.X < this.ctrlCodeViewer.CodeMargin) { 301 AddressTypeInfo info = GetAddressInfo(ctrlCodeViewer.GetLineIndexAtPosition(e.Y)); 302 if(info.Address >= 0) { 303 ctrlLabelList.EditLabel((UInt32)info.Address, info.Type); 304 } 305 } else{ 306 _codeViewerActions.ProcessMouseDoubleClick(e.Location); 307 } 308 } 309 contextMenuMargin_Opening(object sender, CancelEventArgs e)310 private void contextMenuMargin_Opening(object sender, CancelEventArgs e) 311 { 312 Breakpoint bp = GetCurrentLineBreakpoint(); 313 if(bp == null) { 314 e.Cancel = true; 315 } else { 316 mnuDisableBreakpoint.Text = bp.Enabled ? "Disable breakpoint" : "Enable breakpoint"; 317 } 318 } 319 mnuRemoveBreakpoint_Click(object sender, EventArgs e)320 private void mnuRemoveBreakpoint_Click(object sender, EventArgs e) 321 { 322 BreakpointManager.RemoveBreakpoint(GetCurrentLineBreakpoint()); 323 } 324 mnuEditBreakpoint_Click(object sender, EventArgs e)325 private void mnuEditBreakpoint_Click(object sender, EventArgs e) 326 { 327 BreakpointManager.EditBreakpoint(GetCurrentLineBreakpoint()); 328 } 329 mnuDisableBreakpoint_Click(object sender, EventArgs e)330 private void mnuDisableBreakpoint_Click(object sender, EventArgs e) 331 { 332 Breakpoint bp = GetCurrentLineBreakpoint(); 333 bp.SetEnabled(!bp.Enabled); 334 } 335 ctrlCodeViewer_TextZoomChanged(object sender, EventArgs e)336 private void ctrlCodeViewer_TextZoomChanged(object sender, EventArgs e) 337 { 338 _config.TextZoom = this.ctrlCodeViewer.TextZoom; 339 ConfigManager.ApplyChanges(); 340 } 341 EditSubroutine()342 public void EditSubroutine() 343 { 344 int currentLine = this.GetCurrentLine(); 345 if(currentLine != -1 && InteropEmu.DebugIsExecutionStopped()) { 346 int byteLength; 347 List<string> code = this.GetCode(out byteLength, ref currentLine); 348 this.OnEditCode?.Invoke(new AssemblerEventArgs() { Code = string.Join(Environment.NewLine, code), StartAddress = (UInt16)currentLine, BlockLength = (UInt16)byteLength }); 349 } 350 } 351 EditSelectedCode()352 public void EditSelectedCode() 353 { 354 int startAddress = this.GetCurrentLine(); 355 int endAddress = this.ctrlCodeViewer.LastSelectedLine; 356 if(startAddress != -1 && InteropEmu.DebugIsExecutionStopped()) { 357 int byteLength; 358 List<string> code = this.GetCode(out byteLength, ref startAddress, endAddress); 359 this.OnEditCode?.Invoke(new AssemblerEventArgs() { Code = string.Join(Environment.NewLine, code), StartAddress = (UInt16)startAddress, BlockLength = (UInt16)byteLength }); 360 } 361 } 362 EditSourceFile()363 public void EditSourceFile() 364 { 365 //TODO: Not supported yet 366 } 367 FindAllOccurrences(Ld65DbgImporter.SymbolInfo symbol)368 public void FindAllOccurrences(Ld65DbgImporter.SymbolInfo symbol) 369 { 370 FindAllOccurrences(symbol.Name, true, true); 371 } 372 FindAllOccurrences(string text, bool matchWholeWord, bool matchCase)373 public void FindAllOccurrences(string text, bool matchWholeWord, bool matchCase) 374 { 375 List<FindAllOccurrenceResult> results = new List<FindAllOccurrenceResult>(); 376 377 string regexPattern; 378 if(matchWholeWord) { 379 regexPattern = $"([^0-9a-zA-Z_#@]+|^){Regex.Escape(text)}([^0-9a-zA-Z_#@]+|$)"; 380 } else { 381 regexPattern = Regex.Escape(text); 382 } 383 384 Regex regex = new Regex(regexPattern, matchCase ? RegexOptions.None : RegexOptions.IgnoreCase); 385 386 for(int i = 0, len = ctrlCodeViewer.LineCount; i < len; i++) { 387 string line = ctrlCodeViewer.GetLineContent(i); 388 if(regex.IsMatch(line)) { 389 if(line.StartsWith("__") && line.EndsWith("__")) { 390 line = "Function: " + line.Substring(2, line.Length - 4); 391 } 392 if(line.StartsWith("--") && line.EndsWith("--")) { 393 continue; 394 } 395 396 int j = i; 397 while(j < ctrlCodeViewer.LineCount && ctrlCodeViewer.GetLineNumber(j) < 0) { 398 j++; 399 } 400 401 int cpuAddress = ctrlCodeViewer.GetLineNumber(j); 402 results.Add(new FindAllOccurrenceResult() { 403 MatchedLine = line, 404 Location = "$" + cpuAddress.ToString("X4"), 405 Destination = new GoToDestination() { 406 CpuAddress = cpuAddress 407 } 408 }); 409 } 410 } 411 412 ctrlFindOccurrences.FindAllOccurrences(text, results); 413 this.splitContainer.Panel2Collapsed = false; 414 } 415 ctrlFindOccurrences_OnSearchResultsClosed(object sender, EventArgs e)416 private void ctrlFindOccurrences_OnSearchResultsClosed(object sender, EventArgs e) 417 { 418 this.splitContainer.Panel2Collapsed = true; 419 } 420 421 public class LineStyleProvider : ctrlTextbox.ILineStyleProvider 422 { 423 private ctrlDebuggerCode _code; 424 LineStyleProvider(ctrlDebuggerCode code)425 public LineStyleProvider(ctrlDebuggerCode code) 426 { 427 _code = code; 428 } 429 GetLineComment(int lineNumber)430 public string GetLineComment(int lineNumber) 431 { 432 if(_code.SymbolProvider != null && _code._config?.ShowSourceAsComments == true) { 433 AddressTypeInfo addressInfo = _code.GetAddressInfo(lineNumber); 434 if(addressInfo.Type == AddressType.PrgRom) { 435 return _code.SymbolProvider.GetSourceCodeLine(addressInfo.Address); 436 } 437 } 438 return null; 439 } 440 ConfigureActiveStatement(LineProperties props)441 public static void ConfigureActiveStatement(LineProperties props) 442 { 443 props.FgColor = Color.Black; 444 props.TextBgColor = ConfigManager.Config.DebugInfo.CodeActiveStatementColor; 445 props.Symbol |= LineSymbol.Arrow; 446 447 if(ConfigManager.Config.DebugInfo.ShowInstructionProgression) { 448 InstructionProgress state = new InstructionProgress(); 449 InteropEmu.DebugGetInstructionProgress(ref state); 450 451 LineProgress progress = new LineProgress(); 452 progress.Current = (int)state.OpCycle; 453 progress.Maxixum = frmOpCodeTooltip.OpCycles[state.OpCode]; 454 switch(state.OpMemoryOperationType) { 455 case InteropMemoryOperationType.DmcRead: progress.Color = Color.FromArgb(255, 160, 221); progress.Text = "DMC"; break; 456 case InteropMemoryOperationType.DummyRead: progress.Color = Color.FromArgb(184, 160, 255); progress.Text = "DR"; break; 457 case InteropMemoryOperationType.DummyWrite: progress.Color = Color.FromArgb(255, 245, 137); progress.Text = "DW"; break; 458 case InteropMemoryOperationType.Read: progress.Color = Color.FromArgb(150, 176, 255); progress.Text = "R"; break; 459 case InteropMemoryOperationType.Write: progress.Color = Color.FromArgb(255, 171, 150); progress.Text = "W"; break; 460 default: progress.Color = Color.FromArgb(143, 255, 173); progress.Text = "X"; break; 461 } 462 props.Progress = progress; 463 } 464 } 465 GetLineStyle(int cpuAddress, int lineNumber)466 public LineProperties GetLineStyle(int cpuAddress, int lineNumber) 467 { 468 DebugInfo info = ConfigManager.Config.DebugInfo; 469 LineProperties props = new LineProperties(); 470 AddressTypeInfo addressInfo = _code.GetAddressInfo(lineNumber); 471 GetBreakpointLineProperties(props, cpuAddress, addressInfo); 472 473 bool isActiveStatement = _code._currentActiveAddress.HasValue && _code.ctrlCodeViewer.GetLineIndex((int)_code._currentActiveAddress.Value) == lineNumber; 474 if(isActiveStatement) { 475 ConfigureActiveStatement(props); 476 } else if(_code._code.UnexecutedAddresses.Contains(lineNumber)) { 477 props.LineBgColor = info.CodeUnexecutedCodeColor; 478 } else if(_code._code.SpeculativeCodeAddreses.Contains(lineNumber)) { 479 props.LineBgColor = info.CodeUnidentifiedDataColor; 480 } else if(_code._code.VerifiedDataAddresses.Contains(lineNumber)) { 481 props.LineBgColor = info.CodeVerifiedDataColor; 482 } 483 484 switch(_code._code.LineMemoryType[lineNumber]) { 485 case 'P': props.AddressColor = Color.Gray; break; 486 case 'W': props.AddressColor = Color.DarkBlue; break; 487 case 'S': props.AddressColor = Color.DarkRed; break; 488 case 'N': props.AddressColor = Color.DarkGreen; break; 489 } 490 491 return props; 492 } 493 GetBreakpointLineProperties(LineProperties props, int cpuAddress, AddressTypeInfo addressInfo)494 public static void GetBreakpointLineProperties(LineProperties props, int cpuAddress, AddressTypeInfo addressInfo) 495 { 496 DebugInfo info = ConfigManager.Config.DebugInfo; 497 foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) { 498 if(breakpoint.Matches(cpuAddress, addressInfo)) { 499 Color fgColor = Color.White; 500 Color? bgColor = null; 501 Color bpColor = breakpoint.BreakOnExec ? info.CodeExecBreakpointColor : (breakpoint.BreakOnWrite ? info.CodeWriteBreakpointColor : info.CodeReadBreakpointColor); 502 Color outlineColor = bpColor; 503 LineSymbol symbol; 504 if(breakpoint.Enabled) { 505 bgColor = bpColor; 506 symbol = LineSymbol.Circle; 507 } else { 508 fgColor = Color.Black; 509 symbol = LineSymbol.CircleOutline; 510 } 511 512 if(breakpoint.MarkEvent) { 513 symbol |= LineSymbol.Mark; 514 } 515 516 if(!string.IsNullOrWhiteSpace(breakpoint.Condition)) { 517 symbol |= LineSymbol.Plus; 518 } 519 520 props.FgColor = fgColor; 521 props.TextBgColor = bgColor; 522 props.OutlineColor = outlineColor; 523 props.Symbol = symbol; 524 return; 525 } 526 } 527 } 528 } 529 530 class ScrollbarColorProvider : IScrollbarColorProvider 531 { 532 private Color _nesRamColor = Color.FromArgb(213, 255, 213); 533 private Dictionary<int, Color> _breakpointColors = new Dictionary<int, Color>(); 534 535 private ctrlDebuggerCode _code; ScrollbarColorProvider(ctrlDebuggerCode code)536 public ScrollbarColorProvider(ctrlDebuggerCode code) 537 { 538 _code = code; 539 DebugInfo info = ConfigManager.Config.DebugInfo; 540 int len = _code._code.AbsoluteLineNumbers.Length; 541 542 AddressTypeInfo addressInfo = new AddressTypeInfo(); 543 544 Breakpoint[] breakpoints = BreakpointManager.Breakpoints.ToArray(); 545 for(int i = 0; i < len; i++) { 546 _code.SetAddressInfo(addressInfo, i); 547 for(int j = 0; j < breakpoints.Length; j++) { 548 if(breakpoints[j].Matches(_code._code.LineNumbers[i], addressInfo)) { 549 Color bpColor = breakpoints[j].BreakOnExec ? info.CodeExecBreakpointColor : (breakpoints[j].BreakOnWrite ? info.CodeWriteBreakpointColor : info.CodeReadBreakpointColor); 550 _breakpointColors[i] = bpColor; 551 break; 552 } 553 } 554 } 555 } 556 GetBackgroundColor(float position)557 public Color GetBackgroundColor(float position) 558 { 559 DebugInfo info = ConfigManager.Config.DebugInfo; 560 int lineIndex = (int)((_code._code.LineMemoryType.Length - 1) * position); 561 562 if(lineIndex < _code._code.LineMemoryType.Length) { 563 switch(_code._code.LineMemoryType[lineIndex]) { 564 case 'N': return _nesRamColor; 565 case 'P': 566 if(_code._code.UnexecutedAddresses.Contains(lineIndex)) { 567 return info.CodeUnexecutedCodeColor; 568 } else if(_code._code.VerifiedDataAddresses.Contains(lineIndex)) { 569 return info.CodeVerifiedDataColor; 570 } else if(_code._code.SpeculativeCodeAddreses.Contains(lineIndex)) { 571 return info.CodeUnidentifiedDataColor; 572 } 573 return Color.White; 574 575 case 'W': return Color.Lavender; 576 case 'S': return Color.MistyRose; 577 } 578 } 579 return Color.Transparent; 580 } 581 GetPreview(int lineIndex)582 public frmCodePreviewTooltip GetPreview(int lineIndex) 583 { 584 if(lineIndex < _code._code.LineNumbers.Length) { 585 while(lineIndex > 0 && _code._code.LineNumbers[lineIndex] < 0) { 586 lineIndex--; 587 } 588 return new frmCodePreviewTooltip(_code.FindForm(), lineIndex, _code._code); 589 } else { 590 return null; 591 } 592 } 593 GetActiveLine()594 public int GetActiveLine() 595 { 596 if(_code._currentActiveAddress.HasValue) { 597 return _code.ctrlCodeViewer.GetLineIndex((int)_code._currentActiveAddress.Value); 598 } else { 599 return -1; 600 } 601 } 602 GetSelectedLine()603 public int GetSelectedLine() 604 { 605 return _code.ctrlCodeViewer.SelectedLine; 606 } 607 GetMarkerColor(float position, int linesPerPixel)608 public Color GetMarkerColor(float position, int linesPerPixel) 609 { 610 int lineIndex = (int)((_code._code.LineMemoryType.Length - 1) * position); 611 612 Color bpColor; 613 for(int i = 0; i < linesPerPixel; i++) { 614 if(_breakpointColors.TryGetValue(lineIndex + i, out bpColor)) { 615 return bpColor; 616 } 617 } 618 return Color.Transparent; 619 } 620 } 621 } 622 623 public class AssemblerEventArgs : EventArgs 624 { 625 public string Code { get; set; } 626 public UInt16 StartAddress { get; set; } 627 public UInt16 BlockLength { get; set; } 628 } 629 } 630