2016-12-01 19:38:48 -05:00
using System ;
using System.Collections.Generic ;
using System.ComponentModel ;
using System.Drawing ;
using System.Data ;
using System.Linq ;
using System.Text ;
using System.Threading.Tasks ;
using System.Windows.Forms ;
2016-12-11 14:25:29 -05:00
using Mesen.GUI.Controls ;
2018-03-30 18:38:14 -04:00
using Mesen.GUI.Forms ;
2018-03-30 19:14:08 -04:00
using Mesen.GUI.Config ;
2016-12-01 19:38:48 -05:00
namespace Mesen.GUI.Debugger.Controls
{
2016-12-11 14:25:29 -05:00
public partial class ctrlMemoryAccessCounters : BaseControl
2016-12-01 19:38:48 -05:00
{
private MemoryCountData [ ] _data ;
private AddressType _memoryType = AddressType . InternalRam ;
private SortType _sortType = SortType . Address ;
public ctrlMemoryAccessCounters ( )
{
InitializeComponent ( ) ;
2016-12-18 12:43:20 -05:00
2017-10-06 18:26:02 -04:00
this . toolTip . SetToolTip ( chkHighlightUninitRead , "The uninitialized memory reads highlight will only be accurate if the debugger was active when the game was loaded (or if the game has been power cycled since)" ) ;
2018-06-09 17:54:34 -04:00
}
2016-12-01 19:38:48 -05:00
2018-06-09 17:54:34 -04:00
protected override void OnLoad ( EventArgs e )
{
base . OnLoad ( e ) ;
if ( ! IsDesignMode ) {
2018-03-30 18:57:07 -04:00
InitMemoryTypeDropdown ( ) ;
2016-12-01 19:38:48 -05:00
cboSort . SelectedIndex = 0 ;
2018-06-09 17:54:34 -04:00
InitShortcuts ( ) ;
2016-12-01 19:38:48 -05:00
}
}
2018-06-09 17:54:34 -04:00
private void InitShortcuts ( )
2018-03-30 19:14:08 -04:00
{
mnuCopy . InitShortcut ( this , nameof ( DebuggerShortcutsConfig . Copy ) ) ;
mnuSelectAll . InitShortcut ( this , nameof ( DebuggerShortcutsConfig . SelectAll ) ) ;
}
2018-03-30 18:57:07 -04:00
public void InitMemoryTypeDropdown ( )
{
cboMemoryType . SelectedIndexChanged - = cboMemoryType_SelectedIndexChanged ;
AddressType originalValue = cboMemoryType . GetEnumValue < AddressType > ( ) ;
cboMemoryType . BeginUpdate ( ) ;
cboMemoryType . Items . Clear ( ) ;
cboMemoryType . Items . Add ( ResourceHelper . GetEnumText ( AddressType . InternalRam ) ) ;
if ( InteropEmu . DebugGetMemorySize ( DebugMemoryType . PrgRom ) > 0 ) {
cboMemoryType . Items . Add ( ResourceHelper . GetEnumText ( AddressType . PrgRom ) ) ;
}
if ( InteropEmu . DebugGetMemorySize ( DebugMemoryType . WorkRam ) > 0 ) {
cboMemoryType . Items . Add ( ResourceHelper . GetEnumText ( AddressType . WorkRam ) ) ;
}
if ( InteropEmu . DebugGetMemorySize ( DebugMemoryType . SaveRam ) > 0 ) {
cboMemoryType . Items . Add ( ResourceHelper . GetEnumText ( AddressType . SaveRam ) ) ;
}
cboMemoryType . SelectedIndex = 0 ;
cboMemoryType . SetEnumValue ( originalValue ) ;
cboMemoryType . SelectedIndexChanged + = cboMemoryType_SelectedIndexChanged ;
cboMemoryType . EndUpdate ( ) ;
UpdateMemoryType ( ) ;
}
2018-03-03 16:26:24 -05:00
public Font BaseFont { get { return ctrlScrollableTextbox . BaseFont ; } set { ctrlScrollableTextbox . BaseFont = value ; } }
public int TextZoom { get { return ctrlScrollableTextbox . TextZoom ; } set { ctrlScrollableTextbox . TextZoom = value ; } }
2018-03-03 10:41:59 -05:00
2016-12-01 19:38:48 -05:00
public void RefreshData ( )
{
int [ ] readCounts = InteropEmu . DebugGetMemoryAccessCounts ( _memoryType , MemoryOperationType . Read , false ) ;
int [ ] writeCounts = InteropEmu . DebugGetMemoryAccessCounts ( _memoryType , MemoryOperationType . Write , false ) ;
int [ ] execCounts = InteropEmu . DebugGetMemoryAccessCounts ( _memoryType , MemoryOperationType . Exec , false ) ;
int [ ] uninitReads = InteropEmu . DebugGetMemoryAccessCounts ( _memoryType , MemoryOperationType . Read , true ) ;
2018-03-30 18:38:14 -04:00
List < int > addresses = new List < int > ( readCounts . Length ) ;
List < string > content = new List < string > ( readCounts . Length ) ;
2016-12-01 19:38:48 -05:00
if ( _data = = null | | _data . Length ! = readCounts . Length ) {
_data = new MemoryCountData [ readCounts . Length ] ;
for ( int i = 0 ; i < readCounts . Length ; i + + ) {
_data [ i ] = new MemoryCountData ( ) ;
}
}
for ( int i = 0 ; i < readCounts . Length ; i + + ) {
_data [ i ] . Address = i ;
_data [ i ] . ReadCount = readCounts [ i ] ;
_data [ i ] . WriteCount = writeCounts [ i ] ;
_data [ i ] . ExecCount = execCounts [ i ] ;
_data [ i ] . UninitRead = uninitReads [ i ] > 0 ;
}
MemoryCountData [ ] data = new MemoryCountData [ readCounts . Length ] ;
Array . Copy ( _data , data , readCounts . Length ) ;
switch ( _sortType ) {
case SortType . Address : break ;
case SortType . Read : Array . Sort ( data . Select ( ( e ) = > - e . ReadCount ) . ToArray < int > ( ) , data ) ; break ;
case SortType . Write : Array . Sort ( data . Select ( ( e ) = > - e . WriteCount ) . ToArray < int > ( ) , data ) ; break ;
case SortType . Exec : Array . Sort ( data . Select ( ( e ) = > - e . ExecCount ) . ToArray < int > ( ) , data ) ; break ;
case SortType . UninitRead : Array . Sort ( data . Select ( ( e ) = > e . UninitRead ? - e . ReadCount : ( Int32 . MaxValue - e . ReadCount ) ) . ToArray < int > ( ) , data ) ; break ;
}
2018-03-30 18:38:14 -04:00
bool hideUnusedAddresses = chkHideUnusedAddresses . Checked ;
2016-12-01 19:38:48 -05:00
for ( int i = 0 ; i < readCounts . Length ; i + + ) {
2018-03-30 18:38:14 -04:00
if ( ! hideUnusedAddresses | | ! data [ i ] . Empty ) {
addresses . Add ( data [ i ] . Address ) ;
content . Add ( data [ i ] . Content ) ;
}
2016-12-01 19:38:48 -05:00
}
2017-03-09 23:50:20 -05:00
if ( chkHighlightUninitRead . Checked ) {
ctrlScrollableTextbox . StyleProvider = new LineStyleProvider ( new HashSet < int > ( data . Where ( ( e ) = > e . UninitRead ) . Select ( ( e ) = > e . Address ) ) ) ;
} else {
ctrlScrollableTextbox . StyleProvider = null ;
}
2018-03-30 19:14:08 -04:00
ctrlScrollableTextbox . Header = " " + "Read" . PadRight ( 12 ) + "Write" . PadRight ( 12 ) + "Execute" ;
2018-03-30 18:38:14 -04:00
ctrlScrollableTextbox . LineNumbers = addresses . ToArray ( ) ;
ctrlScrollableTextbox . TextLines = content . ToArray ( ) ;
2017-03-09 23:50:20 -05:00
}
2016-12-01 19:38:48 -05:00
2017-03-09 23:50:20 -05:00
private class LineStyleProvider : ctrlTextbox . ILineStyleProvider
{
HashSet < int > _addresses = new HashSet < int > ( ) ;
public LineStyleProvider ( HashSet < int > addresses )
{
_addresses = addresses ;
}
2018-03-18 19:57:56 -04:00
public string GetLineComment ( int lineIndex )
{
return null ;
}
2018-01-03 18:48:16 -05:00
public LineProperties GetLineStyle ( int cpuAddress , int lineIndex )
2017-03-09 23:50:20 -05:00
{
if ( _addresses . Contains ( cpuAddress ) ) {
2018-01-03 18:48:16 -05:00
return new LineProperties ( ) { TextBgColor = Color . LightCoral } ;
2016-12-01 19:38:48 -05:00
}
2017-03-09 23:50:20 -05:00
return null ;
2016-12-01 19:38:48 -05:00
}
}
private void cboMemoryType_SelectedIndexChanged ( object sender , EventArgs e )
2018-03-30 18:57:07 -04:00
{
UpdateMemoryType ( ) ;
}
private void UpdateMemoryType ( )
2016-12-01 19:38:48 -05:00
{
2018-03-30 18:38:14 -04:00
_memoryType = cboMemoryType . GetEnumValue < AddressType > ( ) ;
2016-12-01 19:38:48 -05:00
RefreshData ( ) ;
}
private void cboSort_SelectedIndexChanged ( object sender , EventArgs e )
{
_sortType = ( SortType ) cboSort . SelectedIndex ;
RefreshData ( ) ;
}
2018-03-30 18:38:14 -04:00
private void chkOption_CheckedChanged ( object sender , EventArgs e )
2016-12-01 19:38:48 -05:00
{
RefreshData ( ) ;
}
private void btnReset_Click ( object sender , EventArgs e )
{
InteropEmu . DebugResetMemoryAccessCounts ( ) ;
RefreshData ( ) ;
}
private enum SortType
{
Address = 0 ,
Read = 1 ,
Write = 2 ,
Exec = 3 ,
UninitRead = 4 ,
}
private class MemoryCountData
{
private bool _needRecalc = true ;
private int _readCount = 0 ;
private int _writeCount = 0 ;
private int _execCount = 0 ;
private string _content = string . Empty ;
public int Address { get ; set ; }
public int ReadCount
{
get { return _readCount ; }
set
{
if ( this . _readCount ! = value ) {
this . _readCount = value ;
this . _needRecalc = true ;
} ;
}
}
public int WriteCount
{
get { return _writeCount ; }
set
{
if ( this . _writeCount ! = value ) {
this . _writeCount = value ;
this . _needRecalc = true ;
} ;
}
}
public int ExecCount
{
get { return _execCount ; }
set
{
if ( this . _execCount ! = value ) {
this . _execCount = value ;
this . _needRecalc = true ;
} ;
}
}
2018-03-30 18:38:14 -04:00
public bool Empty { get { return ReadCount = = 0 & & WriteCount = = 0 & & ExecCount = = 0 ; } }
2016-12-01 19:38:48 -05:00
public string Content
{
get
{
if ( this . _needRecalc ) {
2018-03-30 19:14:08 -04:00
_content = " " + ( _readCount = = 0 ? "0" : _readCount . ToString ( ) ) . PadRight ( 12 ) +
2016-12-01 19:38:48 -05:00
( _writeCount = = 0 ? "0" : _writeCount . ToString ( ) ) . PadRight ( 12 ) +
( _execCount = = 0 ? "0" : _execCount . ToString ( ) ) ;
_needRecalc = false ;
}
return _content ;
}
}
public bool UninitRead { get ; set ; }
}
2018-03-30 19:14:08 -04:00
private void mnuCopy_Click ( object sender , EventArgs e )
{
ctrlScrollableTextbox . CopySelection ( true , false , false ) ;
}
private void mnuSelectAll_Click ( object sender , EventArgs e )
{
ctrlScrollableTextbox . SelectAll ( ) ;
}
2016-12-01 19:38:48 -05:00
}
}