From bc15178a8ead6db9ce4a5a82508e948a0b680135 Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Mon, 6 Jul 2020 08:27:42 -0700 Subject: [PATCH] Tweak M/X/E flag handling The decision of how to handle indeterminate M/X flag values is made in StatusFlags. This provides consistent behavior throughout the app. This was being done for M/X but not for E. This change also renames the M/X tests, prefixing them with "Is" to emphasize that they are boolean rather than tri-state. There should be no change in behavior from this. --- Asm65/CpuDef.cs | 10 +++++----- Asm65/OpDef.cs | 4 ++-- Asm65/StatusFlags.cs | 28 ++++++++++++++++++++++++++-- SourceGen/AsmGen/GenCommon.cs | 6 +++--- SourceGen/LineListGen.cs | 8 ++++---- 5 files changed, 40 insertions(+), 16 deletions(-) diff --git a/Asm65/CpuDef.cs b/Asm65/CpuDef.cs index 6d4eb2d..b854deb 100644 --- a/Asm65/CpuDef.cs +++ b/Asm65/CpuDef.cs @@ -281,25 +281,25 @@ namespace Asm65 { // appropriately. So there's no ambiguity here even when there's ambiguity. We // make a similar statement about the E flag. if ((mods & OpDef.CycleMod.OneIfM0) != 0) { - if (!flags.ShortM) { + if (!flags.IsShortM) { cycles++; } mods &= ~OpDef.CycleMod.OneIfM0; } if ((mods & OpDef.CycleMod.TwoIfM0) != 0) { - if (!flags.ShortM) { + if (!flags.IsShortM) { cycles += 2; } mods &= ~OpDef.CycleMod.TwoIfM0; } if ((mods & OpDef.CycleMod.OneIfX0) != 0) { - if (!flags.ShortX) { + if (!flags.IsShortX) { cycles++; } mods &= ~OpDef.CycleMod.OneIfX0; } if ((mods & OpDef.CycleMod.OneIfE0) != 0) { - if (flags.E == 0) { + if (!flags.IsEmulationMode) { cycles++; } mods &= ~OpDef.CycleMod.OneIfE0; @@ -323,7 +323,7 @@ namespace Asm65 { } } if ((mods & OpDef.CycleMod.OneIfBranchPage) != 0) { - if (branchCrossesPage && flags.E != 0) { + if (branchCrossesPage && flags.IsEmulationMode) { cycles++; // +1 unless we're in native mode on 65816 } mods &= ~OpDef.CycleMod.OneIfBranchPage; diff --git a/Asm65/OpDef.cs b/Asm65/OpDef.cs index b2d7865..1c304dc 100644 --- a/Asm65/OpDef.cs +++ b/Asm65/OpDef.cs @@ -518,10 +518,10 @@ namespace Asm65 { return 4; case AddressMode.ImmLongA: - bool shortM = flags.ShortM; + bool shortM = flags.IsShortM; return shortM ? 2 : 3; case AddressMode.ImmLongXY: - bool shortX = flags.ShortX; + bool shortX = flags.IsShortX; return shortX ? 2 : 3; default: diff --git a/Asm65/StatusFlags.cs b/Asm65/StatusFlags.cs index 77417f3..6aedfa6 100644 --- a/Asm65/StatusFlags.cs +++ b/Asm65/StatusFlags.cs @@ -132,6 +132,9 @@ namespace Asm65 { } } + /// + /// X (index register width) flag. For an unambiguous value, use IsShortX. + /// public int X { get { return mState.GetBit((int)FlagBits.X); @@ -149,6 +152,9 @@ namespace Asm65 { } } + /// + /// M (accumulator width) flag. For an unambiguous value, use IsShortM. + /// public int M { get { return mState.GetBit((int)FlagBits.M); @@ -200,6 +206,9 @@ namespace Asm65 { } } + /// + /// E (emulation) flag. For an unambiguous value, use IsEmulationMode. + /// public int E { get { return mState.GetBit((int)FlagBits.E); @@ -225,7 +234,10 @@ namespace Asm65 { /// Returns true if the current processor status flags are configured for a short /// (8-bit) accumulator. /// - public bool ShortM { + /// + /// This is where we decide how to treat ambiguous status flags. + /// + public bool IsShortM { get { // E==1 --> true (we're in emulation mode) // E==0 || E==? : native / assumed native @@ -239,13 +251,25 @@ namespace Asm65 { /// Returns true if the current processor status flags are configured for short /// (8-bit) X/Y registers. /// - public bool ShortX { + public bool IsShortX { get { // (same logic as ShortM) return (E == 1) || (X != 0); } } + /// + /// Returns true if the current processor status flags are configured for execution + /// in native mode. + /// + public bool IsEmulationMode { + get { + // E==1 : emulation --> true + // E==0 || E==? : native / assumed native --> false + return E == 1; + } + } + /// /// Access the value as a single integer. Used for serialization. /// diff --git a/SourceGen/AsmGen/GenCommon.cs b/SourceGen/AsmGen/GenCommon.cs index b31f79c..b622694 100644 --- a/SourceGen/AsmGen/GenCommon.cs +++ b/SourceGen/AsmGen/GenCommon.cs @@ -87,8 +87,8 @@ namespace SourceGen.AsmGen { // that in the ORG output handler. if (proj.CpuDef.HasEmuFlag) { StatusFlags curFlags = attr.StatusFlags; - curFlags.M = attr.StatusFlags.ShortM ? 1 : 0; - curFlags.X = attr.StatusFlags.ShortX ? 1 : 0; + curFlags.M = attr.StatusFlags.IsShortM ? 1 : 0; + curFlags.X = attr.StatusFlags.IsShortX ? 1 : 0; if (curFlags.M != prevFlags.M || curFlags.X != prevFlags.X) { // changed, output directive gen.OutputRegWidthDirective(offset, prevFlags.M, prevFlags.X, @@ -355,7 +355,7 @@ namespace SourceGen.AsmGen { // Assemblers like Merlin32 try to be helpful and track SEP/REP, but they do the // wrong thing if we're in emulation mode. Force flags back to short. if (proj.CpuDef.HasEmuFlag && gen.Quirks.TracksSepRepNotEmu && op == OpDef.OpREP_Imm) { - if ((operand & 0x30) != 0 && attr.StatusFlags.E == 1) { + if ((operand & 0x30) != 0 && attr.StatusFlags.IsEmulationMode) { gen.OutputRegWidthDirective(offset, 0, 0, 1, 1); } } diff --git a/SourceGen/LineListGen.cs b/SourceGen/LineListGen.cs index de68cc1..e7cc11c 100644 --- a/SourceGen/LineListGen.cs +++ b/SourceGen/LineListGen.cs @@ -928,8 +928,8 @@ namespace SourceGen { if (attr.IsInstructionStart) { prevFlags = attr.StatusFlags; // Apply the same tweak here that we do to curFlags below. - prevFlags.M = attr.StatusFlags.ShortM ? 1 : 0; - prevFlags.X = attr.StatusFlags.ShortX ? 1 : 0; + prevFlags.M = attr.StatusFlags.IsShortM ? 1 : 0; + prevFlags.X = attr.StatusFlags.IsShortX ? 1 : 0; Debug.WriteLine("GenerateLineList startOff=+" + startOffset.ToString("x6") + " using initial flags from +" + scanoff.ToString("x6") + ": " + prevFlags); @@ -1017,8 +1017,8 @@ namespace SourceGen { // assembler something. So we tweak our local copy and propagate it. string operandStr = string.Empty; StatusFlags curFlags = attr.StatusFlags; - curFlags.M = attr.StatusFlags.ShortM ? 1 : 0; - curFlags.X = attr.StatusFlags.ShortX ? 1 : 0; + curFlags.M = attr.StatusFlags.IsShortM ? 1 : 0; + curFlags.X = attr.StatusFlags.IsShortX ? 1 : 0; if (curFlags.M != prevFlags.M) { operandStr = (curFlags.M == 0) ? "longm" : "shortm"; }