2016-01-10 19:56:40 -05:00
using System ;
using System.Collections.Generic ;
using System.ComponentModel ;
using System.Data ;
using System.Drawing ;
2016-09-03 21:52:59 -04:00
using System.IO ;
2016-01-10 19:56:40 -05:00
using System.Linq ;
using System.Text ;
using System.Threading.Tasks ;
using System.Windows.Forms ;
2016-09-03 21:52:59 -04:00
using Mesen.GUI.Config ;
2017-03-04 15:18:00 -05:00
using Mesen.GUI.Controls ;
2016-01-10 19:56:40 -05:00
using Mesen.GUI.Forms ;
namespace Mesen.GUI.Debugger
{
public partial class frmTraceLogger : BaseForm
{
2017-03-04 15:18:00 -05:00
private int _lineCount ;
2016-09-03 21:52:59 -04:00
private bool _loggingEnabled = false ;
2017-03-04 15:18:00 -05:00
private string _lastFilename ;
2017-03-16 21:34:28 -04:00
private EntityBinder _entityBinder = new EntityBinder ( ) ;
2017-08-06 16:23:22 -04:00
private int _previousCycleCount ;
private string _previousTrace ;
2017-08-06 17:53:18 -04:00
private volatile bool _refreshRunning ;
2016-09-03 21:52:59 -04:00
2016-01-10 19:56:40 -05:00
public frmTraceLogger ( )
{
InitializeComponent ( ) ;
2017-03-04 15:18:00 -05:00
DebugInfo debugInfo = ConfigManager . Config . DebugInfo ;
2017-08-06 16:23:22 -04:00
if ( ! debugInfo . TraceLoggerSize . IsEmpty ) {
this . Size = debugInfo . TraceLoggerSize ;
}
2017-03-04 15:18:00 -05:00
mnuAutoRefresh . Checked = debugInfo . TraceAutoRefresh ;
_lineCount = debugInfo . TraceLineCount ;
2017-03-16 21:34:28 -04:00
_entityBinder . Entity = debugInfo . TraceLoggerOptions ;
_entityBinder . AddBinding ( "ShowByteCode" , chkShowByteCode ) ;
_entityBinder . AddBinding ( "ShowCpuCycles" , chkShowCpuCycles ) ;
_entityBinder . AddBinding ( "ShowEffectiveAddresses" , chkShowEffectiveAddresses ) ;
_entityBinder . AddBinding ( "ShowExtraInfo" , chkShowExtraInfo ) ;
_entityBinder . AddBinding ( "ShowPpuFrames" , chkShowFrameCount ) ;
_entityBinder . AddBinding ( "ShowPpuCycles" , chkShowPpuCycles ) ;
_entityBinder . AddBinding ( "ShowPpuScanline" , chkShowPpuScanline ) ;
_entityBinder . AddBinding ( "ShowRegisters" , chkShowRegisters ) ;
_entityBinder . AddBinding ( "IndentCode" , chkIndentCode ) ;
_entityBinder . AddBinding ( "UseLabels" , chkUseLabels ) ;
_entityBinder . AddBinding ( "StatusFormat" , cboStatusFlagFormat ) ;
_entityBinder . UpdateUI ( ) ;
2017-03-04 15:18:00 -05:00
UpdateMenu ( ) ;
2017-08-06 16:23:22 -04:00
txtTraceLog . FontSize = 10 ;
2017-03-04 15:18:00 -05:00
tmrUpdateLog . Start ( ) ;
2017-08-06 16:23:22 -04:00
RefreshLog ( true ) ;
2017-08-05 12:13:53 -04:00
this . toolTip . SetToolTip ( this . picExpressionWarning , "Condition contains invalid syntax or symbols." ) ;
this . toolTip . SetToolTip ( this . picHelp , "When a condition is given, instructions will only be logged by the trace logger if the condition returns a value not equal to 0 or false." + Environment . NewLine + Environment . NewLine + frmBreakpoint . GetConditionTooltip ( false ) ) ;
2016-01-10 19:56:40 -05:00
}
2016-09-03 21:52:59 -04:00
protected override void OnFormClosing ( FormClosingEventArgs e )
{
2017-08-06 17:53:18 -04:00
tmrUpdateLog . Stop ( ) ;
while ( _refreshRunning ) {
System . Threading . Thread . Sleep ( 50 ) ;
}
2016-09-03 21:52:59 -04:00
base . OnFormClosing ( e ) ;
2017-03-04 15:18:00 -05:00
DebugInfo debugInfo = ConfigManager . Config . DebugInfo ;
debugInfo . TraceAutoRefresh = mnuAutoRefresh . Checked ;
debugInfo . TraceLineCount = _lineCount ;
debugInfo . TraceIndentCode = chkIndentCode . Checked ;
2017-08-06 16:23:22 -04:00
debugInfo . TraceLoggerSize = this . WindowState = = FormWindowState . Maximized ? this . RestoreBounds . Size : this . Size ;
2017-03-16 21:34:28 -04:00
_entityBinder . Entity = debugInfo . TraceLoggerOptions ;
_entityBinder . UpdateObject ( ) ;
debugInfo . TraceLoggerOptions = ( TraceLoggerOptions ) _entityBinder . Entity ;
2017-03-04 15:18:00 -05:00
ConfigManager . ApplyChanges ( ) ;
2016-09-03 21:52:59 -04:00
if ( _loggingEnabled ) {
InteropEmu . DebugStopTraceLogger ( ) ;
}
}
2017-03-04 15:18:00 -05:00
private void SetOptions ( )
2016-01-10 19:56:40 -05:00
{
2017-03-16 21:34:28 -04:00
_entityBinder . Entity = ConfigManager . Config . DebugInfo . TraceLoggerOptions ;
_entityBinder . UpdateObject ( ) ;
2017-08-05 12:13:53 -04:00
TraceLoggerOptions options = ( TraceLoggerOptions ) _entityBinder . Entity ;
options . Condition = Encoding . UTF8 . GetBytes ( txtCondition . Text ) ;
Array . Resize ( ref options . Condition , 1000 ) ;
InteropEmu . DebugSetTraceOptions ( options ) ;
2017-03-04 15:18:00 -05:00
}
2016-09-03 21:52:59 -04:00
2017-03-04 15:18:00 -05:00
private void btnStartLogging_Click ( object sender , EventArgs e )
{
using ( SaveFileDialog sfd = new SaveFileDialog ( ) ) {
sfd . FileName = "Trace logs (*.txt)|*.txt" ;
sfd . FileName = "Trace - " + InteropEmu . GetRomInfo ( ) . GetRomName ( ) + ".txt" ;
sfd . InitialDirectory = ConfigManager . DebuggerFolder ;
if ( sfd . ShowDialog ( ) = = DialogResult . OK ) {
_lastFilename = sfd . FileName ;
SetOptions ( ) ;
InteropEmu . DebugStartTraceLogger ( sfd . FileName ) ;
btnStartLogging . Enabled = false ;
btnStopLogging . Enabled = true ;
btnOpenTrace . Enabled = false ;
2016-09-03 21:52:59 -04:00
2017-03-04 15:18:00 -05:00
_loggingEnabled = true ;
}
}
2016-01-10 19:56:40 -05:00
}
private void btnStopLogging_Click ( object sender , EventArgs e )
{
InteropEmu . DebugStopTraceLogger ( ) ;
2016-09-03 21:52:59 -04:00
btnStartLogging . Enabled = true ;
btnStopLogging . Enabled = false ;
2017-03-04 15:18:00 -05:00
btnOpenTrace . Enabled = true ;
2016-09-03 21:52:59 -04:00
}
private void btnOpenTrace_Click ( object sender , EventArgs e )
{
try {
2017-03-04 15:18:00 -05:00
System . Diagnostics . Process . Start ( _lastFilename ) ;
2016-09-03 21:52:59 -04:00
} catch { }
2016-01-10 19:56:40 -05:00
}
2017-03-04 15:18:00 -05:00
2017-08-06 16:23:22 -04:00
protected override bool ProcessCmdKey ( ref Message msg , Keys keyData )
2017-03-04 15:18:00 -05:00
{
2017-08-06 16:23:22 -04:00
switch ( keyData ) {
case Keys . C | Keys . Control :
2017-09-12 19:39:03 -04:00
if ( _previousTrace ! = null & & ! this . txtCondition . Focused & & txtTraceLog . SelectionStart > = 0 ) {
2017-08-06 16:23:22 -04:00
string [ ] lines = _previousTrace . Split ( '\n' ) ;
StringBuilder sb = new StringBuilder ( ) ;
2017-09-12 19:39:03 -04:00
for ( int i = txtTraceLog . SelectionStart , end = txtTraceLog . SelectionStart + txtTraceLog . SelectionLength ; i < = end & & i < lines . Length ; i + + ) {
2017-08-06 16:23:22 -04:00
sb . AppendLine ( lines [ i ] ) ;
}
Clipboard . SetText ( sb . ToString ( ) ) ;
2017-09-12 19:39:03 -04:00
return true ;
2017-08-06 16:23:22 -04:00
}
2017-09-12 19:39:03 -04:00
break ;
2017-08-06 16:23:22 -04:00
}
return base . ProcessCmdKey ( ref msg , keyData ) ;
}
2017-08-06 17:53:18 -04:00
2017-08-06 16:23:22 -04:00
private void RefreshLog ( bool scrollToBottom )
{
if ( _refreshRunning ) {
return ;
2017-03-04 15:18:00 -05:00
}
2017-08-06 16:23:22 -04:00
2017-08-14 23:44:01 -04:00
//Make sure labels are up to date
DebugWorkspaceManager . GetWorkspace ( ) ;
2017-08-06 16:23:22 -04:00
_refreshRunning = true ;
SetOptions ( ) ;
Task . Run ( ( ) = > {
//Update trace log in another thread for performance
DebugState state = new DebugState ( ) ;
InteropEmu . DebugGetState ( ref state ) ;
if ( _previousCycleCount ! = state . CPU . CycleCount ) {
string newTrace = InteropEmu . DebugGetExecutionTrace ( ( UInt32 ) _lineCount ) ;
_previousCycleCount = state . CPU . CycleCount ;
_previousTrace = newTrace ;
int index = 0 ;
string line = null ;
Func < bool > readLine = ( ) = > {
if ( index < newTrace . Length ) {
int endOfLineIndex = newTrace . IndexOf ( '\n' , index ) ;
line = newTrace . Substring ( index , endOfLineIndex - index ) ;
index = endOfLineIndex + 1 ;
return true ;
} else {
return false ;
}
} ;
List < int > programCounter = new List < int > ( 30000 ) ;
List < string > byteCode = new List < string > ( 30000 ) ;
List < string > lineContent = new List < string > ( 30000 ) ;
List < int > indent = new List < int > ( 30000 ) ;
char [ ] splitter = new char [ ] { ' ' } ;
while ( readLine ( ) ) {
programCounter . Add ( Int32 . Parse ( line . Substring ( 0 , 4 ) , System . Globalization . NumberStyles . HexNumber ) ) ;
byteCode . Add ( line . Substring ( 6 , 11 ) ) ;
lineContent . Add ( line . Substring ( 19 ) ) ;
indent . Add ( 6 ) ;
}
this . BeginInvoke ( ( Action ) ( ( ) = > {
txtTraceLog . ShowContentNotes = chkShowByteCode . Checked ;
txtTraceLog . ShowSingleContentLineNotes = chkShowByteCode . Checked ;
txtTraceLog . LineIndentations = indent . ToArray ( ) ;
txtTraceLog . LineNumbers = programCounter . ToArray ( ) ;
txtTraceLog . TextLineNotes = byteCode . ToArray ( ) ;
2017-09-12 19:39:03 -04:00
txtTraceLog . TextLines = lineContent . ToArray ( ) ;
2017-08-06 16:23:22 -04:00
if ( scrollToBottom ) {
txtTraceLog . ScrollToLineIndex ( txtTraceLog . LineCount - 1 ) ;
}
} ) ) ;
}
_refreshRunning = false ;
} ) ;
2017-03-04 15:18:00 -05:00
}
private void UpdateMenu ( )
{
mnu30000Lines . Checked = _lineCount = = 30000 ;
mnu10000Lines . Checked = _lineCount = = 10000 ;
mnu1000Lines . Checked = _lineCount = = 1000 ;
mnu100Lines . Checked = _lineCount = = 100 ;
2017-08-06 16:23:22 -04:00
if ( _lineCount > = 1000 ) {
2017-03-04 15:18:00 -05:00
tmrUpdateLog . Interval = 250 ;
} else {
tmrUpdateLog . Interval = 150 ;
}
}
private void tmrUpdateLog_Tick ( object sender , EventArgs e )
{
2017-08-05 12:13:53 -04:00
if ( txtCondition . Text . Length > 0 ) {
EvalResultType resultType ;
InteropEmu . DebugEvaluateExpression ( txtCondition . Text , out resultType ) ;
picExpressionWarning . Visible = ( resultType = = EvalResultType . Invalid ) ;
} else {
picExpressionWarning . Visible = false ;
}
2017-03-04 15:18:00 -05:00
if ( mnuAutoRefresh . Checked ) {
2017-08-06 16:23:22 -04:00
RefreshLog ( false ) ;
2017-03-04 15:18:00 -05:00
}
}
private void mnu30000Lines_Click ( object sender , EventArgs e )
{
_lineCount = 30000 ;
UpdateMenu ( ) ;
}
private void mnu10000Lines_Click ( object sender , EventArgs e )
{
_lineCount = 10000 ;
UpdateMenu ( ) ;
}
private void mnu1000Lines_Click ( object sender , EventArgs e )
{
_lineCount = 1000 ;
UpdateMenu ( ) ;
}
private void mnu100Lines_Click ( object sender , EventArgs e )
{
_lineCount = 100 ;
UpdateMenu ( ) ;
}
private void mnuRefresh_Click ( object sender , EventArgs e )
{
2017-08-06 16:23:22 -04:00
RefreshLog ( false ) ;
2017-03-04 15:18:00 -05:00
}
2016-01-10 19:56:40 -05:00
}
}