1
0
mirror of https://github.com/fadden/6502bench.git synced 2025-07-05 20:23:56 +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:
Andy McFadden
2019-09-02 15:57:59 -07:00
parent 54e7f68490
commit 431ad94d95
8 changed files with 64 additions and 23 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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:"/>

View File

@ -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++) {