mirror of
https://github.com/fadden/6502bench.git
synced 2025-07-06 11:24:01 +00:00
Make "smart" PLP handling optional
We try to be clever with PHP/PLP, but sometimes we get it wrong. If we get it wrong a lot, we want to turn it off. Now we can.
This commit is contained in:
@ -146,6 +146,11 @@ namespace SourceGen {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private StatusFlags mEntryFlags;
|
private StatusFlags mEntryFlags;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// User-configurable analysis parameters.
|
||||||
|
/// </summary>
|
||||||
|
private ProjectProperties.AnalysisParameters mAnalysisParameters;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Debug trace log.
|
/// Debug trace log.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -168,7 +173,8 @@ namespace SourceGen {
|
|||||||
/// <param name="debugLog">Object that receives debug log messages.</param>
|
/// <param name="debugLog">Object that receives debug log messages.</param>
|
||||||
public CodeAnalysis(byte[] data, CpuDef cpuDef, Anattrib[] anattribs,
|
public CodeAnalysis(byte[] data, CpuDef cpuDef, Anattrib[] anattribs,
|
||||||
AddressMap addrMap, TypeHint[] hints, StatusFlags[] statusFlagOverrides,
|
AddressMap addrMap, TypeHint[] hints, StatusFlags[] statusFlagOverrides,
|
||||||
StatusFlags entryFlags, ScriptManager scriptMan, DebugLog debugLog) {
|
StatusFlags entryFlags, ProjectProperties.AnalysisParameters parms,
|
||||||
|
ScriptManager scriptMan, DebugLog debugLog) {
|
||||||
mFileData = data;
|
mFileData = data;
|
||||||
mCpuDef = cpuDef;
|
mCpuDef = cpuDef;
|
||||||
mAnattribs = anattribs;
|
mAnattribs = anattribs;
|
||||||
@ -177,6 +183,7 @@ namespace SourceGen {
|
|||||||
mStatusFlagOverrides = statusFlagOverrides;
|
mStatusFlagOverrides = statusFlagOverrides;
|
||||||
mEntryFlags = entryFlags;
|
mEntryFlags = entryFlags;
|
||||||
mScriptManager = scriptMan;
|
mScriptManager = scriptMan;
|
||||||
|
mAnalysisParameters = parms;
|
||||||
mDebugLog = debugLog;
|
mDebugLog = debugLog;
|
||||||
|
|
||||||
mScriptSupport = new ScriptSupport(this);
|
mScriptSupport = new ScriptSupport(this);
|
||||||
@ -789,6 +796,7 @@ namespace SourceGen {
|
|||||||
backOffsetLimit = 0;
|
backOffsetLimit = 0;
|
||||||
}
|
}
|
||||||
StatusFlags flags = StatusFlags.AllIndeterminate;
|
StatusFlags flags = StatusFlags.AllIndeterminate;
|
||||||
|
if (mAnalysisParameters.SmartPlpHandling) {
|
||||||
for (int offset = plpOffset - 1; offset >= backOffsetLimit; offset--) {
|
for (int offset = plpOffset - 1; offset >= backOffsetLimit; offset--) {
|
||||||
Anattrib attr = mAnattribs[offset];
|
Anattrib attr = mAnattribs[offset];
|
||||||
if (!attr.IsInstructionStart || !attr.IsVisited) {
|
if (!attr.IsInstructionStart || !attr.IsVisited) {
|
||||||
@ -801,6 +809,7 @@ namespace SourceGen {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Transfer the 'E' flag.
|
// Transfer the 'E' flag.
|
||||||
flags.E = mAnattribs[plpOffset].StatusFlags.E;
|
flags.E = mAnattribs[plpOffset].StatusFlags.E;
|
||||||
|
@ -618,8 +618,8 @@ namespace SourceGen {
|
|||||||
reanalysisTimer.StartTask("CodeAnalysis.Analyze");
|
reanalysisTimer.StartTask("CodeAnalysis.Analyze");
|
||||||
|
|
||||||
CodeAnalysis ca = new CodeAnalysis(mFileData, CpuDef, mAnattribs, AddrMap,
|
CodeAnalysis ca = new CodeAnalysis(mFileData, CpuDef, mAnattribs, AddrMap,
|
||||||
TypeHints, StatusFlagOverrides, ProjectProps.EntryFlags, mScriptManager,
|
TypeHints, StatusFlagOverrides, ProjectProps.EntryFlags,
|
||||||
debugLog);
|
ProjectProps.AnalysisParams, mScriptManager, debugLog);
|
||||||
|
|
||||||
ca.Analyze();
|
ca.Analyze();
|
||||||
reanalysisTimer.EndTask("CodeAnalysis.Analyze");
|
reanalysisTimer.EndTask("CodeAnalysis.Analyze");
|
||||||
|
@ -219,6 +219,7 @@ namespace SourceGen {
|
|||||||
public string DefaultTextScanMode { get; set; }
|
public string DefaultTextScanMode { get; set; }
|
||||||
public int MinCharsForString { get; set; }
|
public int MinCharsForString { get; set; }
|
||||||
public bool SeekNearbyTargets { get; set; }
|
public bool SeekNearbyTargets { get; set; }
|
||||||
|
public bool SmartPlpHandling { get; set; }
|
||||||
|
|
||||||
public SerAnalysisParameters() { }
|
public SerAnalysisParameters() { }
|
||||||
public SerAnalysisParameters(ProjectProperties.AnalysisParameters src) {
|
public SerAnalysisParameters(ProjectProperties.AnalysisParameters src) {
|
||||||
@ -226,6 +227,7 @@ namespace SourceGen {
|
|||||||
DefaultTextScanMode = src.DefaultTextScanMode.ToString();
|
DefaultTextScanMode = src.DefaultTextScanMode.ToString();
|
||||||
MinCharsForString = src.MinCharsForString;
|
MinCharsForString = src.MinCharsForString;
|
||||||
SeekNearbyTargets = src.SeekNearbyTargets;
|
SeekNearbyTargets = src.SeekNearbyTargets;
|
||||||
|
SmartPlpHandling = src.SmartPlpHandling;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public class SerAddressMap {
|
public class SerAddressMap {
|
||||||
@ -511,6 +513,13 @@ namespace SourceGen {
|
|||||||
spf.ProjectProps.AnalysisParams.MinCharsForString;
|
spf.ProjectProps.AnalysisParams.MinCharsForString;
|
||||||
proj.ProjectProps.AnalysisParams.SeekNearbyTargets =
|
proj.ProjectProps.AnalysisParams.SeekNearbyTargets =
|
||||||
spf.ProjectProps.AnalysisParams.SeekNearbyTargets;
|
spf.ProjectProps.AnalysisParams.SeekNearbyTargets;
|
||||||
|
if (spf._ContentVersion < 2) {
|
||||||
|
// This was made optional in v1.3. Default it to true for older projects.
|
||||||
|
proj.ProjectProps.AnalysisParams.SmartPlpHandling = true;
|
||||||
|
} else {
|
||||||
|
proj.ProjectProps.AnalysisParams.SmartPlpHandling =
|
||||||
|
spf.ProjectProps.AnalysisParams.SmartPlpHandling;
|
||||||
|
}
|
||||||
|
|
||||||
// Deserialize ProjectProperties: external file identifiers.
|
// Deserialize ProjectProperties: external file identifiers.
|
||||||
Debug.Assert(proj.ProjectProps.PlatformSymbolFileIdentifiers.Count == 0);
|
Debug.Assert(proj.ProjectProps.PlatformSymbolFileIdentifiers.Count == 0);
|
||||||
|
@ -51,18 +51,22 @@ namespace SourceGen {
|
|||||||
public TextScanMode DefaultTextScanMode { get; set; }
|
public TextScanMode DefaultTextScanMode { get; set; }
|
||||||
public int MinCharsForString { get; set; }
|
public int MinCharsForString { get; set; }
|
||||||
public bool SeekNearbyTargets { get; set; }
|
public bool SeekNearbyTargets { get; set; }
|
||||||
|
public bool SmartPlpHandling { get; set; }
|
||||||
|
|
||||||
public AnalysisParameters() {
|
public AnalysisParameters() {
|
||||||
|
// Set default values.
|
||||||
AnalyzeUncategorizedData = true;
|
AnalyzeUncategorizedData = true;
|
||||||
DefaultTextScanMode = TextScanMode.LowHighAscii;
|
DefaultTextScanMode = TextScanMode.LowHighAscii;
|
||||||
MinCharsForString = DataAnalysis.DEFAULT_MIN_STRING_LENGTH;
|
MinCharsForString = DataAnalysis.DEFAULT_MIN_STRING_LENGTH;
|
||||||
SeekNearbyTargets = true;
|
SeekNearbyTargets = true;
|
||||||
|
SmartPlpHandling = true;
|
||||||
}
|
}
|
||||||
public AnalysisParameters(AnalysisParameters src) {
|
public AnalysisParameters(AnalysisParameters src) {
|
||||||
AnalyzeUncategorizedData = src.AnalyzeUncategorizedData;
|
AnalyzeUncategorizedData = src.AnalyzeUncategorizedData;
|
||||||
DefaultTextScanMode = src.DefaultTextScanMode;
|
DefaultTextScanMode = src.DefaultTextScanMode;
|
||||||
MinCharsForString = src.MinCharsForString;
|
MinCharsForString = src.MinCharsForString;
|
||||||
SeekNearbyTargets = src.SeekNearbyTargets;
|
SeekNearbyTargets = src.SeekNearbyTargets;
|
||||||
|
SmartPlpHandling = src.SmartPlpHandling;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,15 +244,18 @@ status flag override to get correct disassembly.</p>
|
|||||||
<p>The instruction that is most likely to cause problems is <code>PLP</code>,
|
<p>The instruction that is most likely to cause problems is <code>PLP</code>,
|
||||||
which pulls the processor status flags off of the stack. SourceGen
|
which pulls the processor status flags off of the stack. SourceGen
|
||||||
doesn't try to track stack contents, so it can't know what values may
|
doesn't try to track stack contents, so it can't know what values may
|
||||||
be pulled. In many cases the PLP appears not long after a PHP, so
|
be pulled. In many cases the <code>PLP</code> appears not long after a
|
||||||
SourceGen will scan backward through the file to find the nearest PHP,
|
<code>PHP</code>, so SourceGen will scan backward through the file to
|
||||||
and use the status flags from that. If no PHP can be found, then all
|
find the nearest <code>PHP</code>, and use the status flags from that. If
|
||||||
|
no <code>PHP</code> can be found, then all
|
||||||
flags are set to "indeterminate". (The boot loader in the Apple II 5.25"
|
flags are set to "indeterminate". (The boot loader in the Apple II 5.25"
|
||||||
floppy disk controller is an example where SourceGen gets it wrong. The
|
floppy disk controller is an example where SourceGen gets it wrong. The
|
||||||
code does <code>CLC</code>/<code>PHP</code>, followed a bit later by the
|
code does <code>CLC</code>/<code>PHP</code>, followed a bit later by the
|
||||||
<code>PLP</code>, but it's actually using the stack to pass the carry
|
<code>PLP</code>, but it's actually using the stack to pass the carry
|
||||||
flag around. Flagging the carry bit as indeterminate with a status flag
|
flag around. Flagging the carry bit as indeterminate with a status flag
|
||||||
override on the instruction following the PLP fixes things.)</p>
|
override on the instruction following the PLP fixes things.) The
|
||||||
|
"smart" behavior can be disabled in the project properties if it's coming
|
||||||
|
out wrong more often than right.</p>
|
||||||
|
|
||||||
<p>Some other things that the code analyzer can't recognize automatically:</p>
|
<p>Some other things that the code analyzer can't recognize automatically:</p>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -227,11 +227,17 @@ entry point hint) will use this value. This is chiefly of value for
|
|||||||
|
|
||||||
<p>If "analyze uncategorized data" is checked, SourceGen will attempt to
|
<p>If "analyze uncategorized data" is checked, SourceGen will attempt to
|
||||||
identify character strings and regions that are filled with a repeated
|
identify character strings and regions that are filled with a repeated
|
||||||
value. If it's
|
value. If it's not checked, anything that isn't detected as code or
|
||||||
not checked, anything that isn't detected as code or explicitly formatted
|
explicitly formatted as data will be shown as individual byte values.</p>
|
||||||
will simply be shown as a byte value.</p>
|
|
||||||
<p>If "seek nearby targets" is checked, the analyzer will try to use
|
<p>If "seek nearby targets" is checked, the analyzer will try to use
|
||||||
nearby labels for data loads and stores.</p>
|
nearby labels for data loads and stores, adjusting them to fit
|
||||||
|
(e.g. <code>LDA LABEL+1</code>). If not enabled, labels are only used
|
||||||
|
when they match exactly.</p>
|
||||||
|
<p>If "smart PLP handling" is checked, the analyzer will try to use
|
||||||
|
the processor status flags from a nearby <code>PHP</code> when a
|
||||||
|
<code>PLP</code> is encountered. If not enabled, all flags are set to
|
||||||
|
"indeterminate" following a <code>PLP</code>.</p>
|
||||||
|
|
||||||
<p>The "default text encoding" setting has two effects. First, it
|
<p>The "default text encoding" setting has two effects. First, it
|
||||||
specifies which character encoding to use when searching for strings in
|
specifies which character encoding to use when searching for strings in
|
||||||
uncategorized data. Second, if an assembler has a notion of preferred
|
uncategorized data. Second, if an assembler has a notion of preferred
|
||||||
|
@ -94,10 +94,12 @@ limitations under the License.
|
|||||||
<GroupBox Header="Analysis Parameters" Grid.Column="1" Grid.Row="0" Grid.RowSpan="2"
|
<GroupBox Header="Analysis Parameters" Grid.Column="1" Grid.Row="0" Grid.RowSpan="2"
|
||||||
Margin="4,0,0,0" Padding="2,4">
|
Margin="4,0,0,0" Padding="2,4">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<CheckBox Name="analyzeUncategorizedCheckBox" Content="Analyze uncategorized data"
|
<CheckBox Content="Analyze uncategorized data"
|
||||||
IsChecked="{Binding AnalyzeUncategorizedData}"/>
|
IsChecked="{Binding AnalyzeUncategorizedData}"/>
|
||||||
<CheckBox Name="seekAltTargetCheckBox" Margin="0,4,0,0" Content="Seek nearby targets"
|
<CheckBox Margin="0,4,0,0" Content="Seek nearby targets"
|
||||||
IsChecked="{Binding SeekNearbyTargets}"/>
|
IsChecked="{Binding SeekNearbyTargets}"/>
|
||||||
|
<CheckBox Margin="0,4,0,0" Content="Smart PLP handling"
|
||||||
|
IsChecked="{Binding SmartPlpHandling}"/>
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal" Margin="0,4,0,0">
|
<StackPanel Orientation="Horizontal" Margin="0,4,0,0">
|
||||||
<TextBlock Margin="0,3,0,0" Text="Default text encoding:"/>
|
<TextBlock Margin="0,3,0,0" Text="Default text encoding:"/>
|
||||||
|
@ -275,6 +275,14 @@ namespace SourceGen.WpfGui {
|
|||||||
IsDirty = true;
|
IsDirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public bool SmartPlpHandling {
|
||||||
|
get { return mWorkProps.AnalysisParams.SmartPlpHandling; }
|
||||||
|
set {
|
||||||
|
mWorkProps.AnalysisParams.SmartPlpHandling = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
IsDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Loaded_General() {
|
private void Loaded_General() {
|
||||||
for (int i = 0; i < CpuItems.Length; i++) {
|
for (int i = 0; i < CpuItems.Length; i++) {
|
||||||
|
Reference in New Issue
Block a user