From 1b0ee7de212a9c742b68ff161b0cfb00399ec186 Mon Sep 17 00:00:00 2001
From: Andy McFadden
Date: Tue, 22 Oct 2019 09:58:23 -0700
Subject: [PATCH] Fix display of instruction attributes
The "affected flags" constants were incorrect for BIT, BRK, COP,
RTI, XCE, and the undocmented instructions ANE, DCP, and SAX. The
constants are used for the changed-flag summary shown in the info
window and the instruction chart.
Of greater import: the status flag updater for BIT was incorrectly
marking N/V/C as indeterminate instead of N/V/Z. The undocmented
instructions ANE, DCP, and SAX were also incorrect.
The cycle counts shown in line comments are computed correctly, but
the counts shown in the info window and instruction chart were
displaying the full set of modifiers, ignoring the CPU type. That's
okay for the info window, which spells the modifiers out, though
it'd be better if the bits were explicitly marked as being applicable
to the current CPU or a different one.
---
Asm65/CpuDef.cs | 8 ++++
Asm65/OpDef.cs | 46 ++++++++++++++-----
SourceGen/MainController.cs | 4 ++
SourceGen/RuntimeData/Help/tools.html | 3 ++
.../Tools/WpfGui/InstructionChart.xaml.cs | 9 ++--
5 files changed, 55 insertions(+), 15 deletions(-)
diff --git a/Asm65/CpuDef.cs b/Asm65/CpuDef.cs
index 1f26d2d..6d4eb2d 100644
--- a/Asm65/CpuDef.cs
+++ b/Asm65/CpuDef.cs
@@ -242,6 +242,14 @@ namespace Asm65 {
/// Instruction definition.
public OpDef GetOpDef(int op) { return mOpDefs[op]; }
+ ///
+ /// Returns the set of cycle mods for the given instruction that are in effect
+ /// for the current CPU.
+ ///
+ /// Instruction opcode number (0-255).
+ /// Reduced cycle mod set.
+ public OpDef.CycleMod GetOpCycleMod(int op) { return mCycleMods[op]; }
+
///
/// Indexer. Returns the definition of opcode N.
///
diff --git a/Asm65/OpDef.cs b/Asm65/OpDef.cs
index 3c15cee..eb1ba92 100644
--- a/Asm65/OpDef.cs
+++ b/Asm65/OpDef.cs
@@ -196,6 +196,10 @@ namespace Asm65 {
/// Cycles required. The low 8 bits hold the base cycle count, the remaining bits
/// are defined by the CycleMod enum.
///
+ ///
+ /// This always returns the full set of possible cycle mods. In most cases you want
+ /// the set that has irrelevant mods masked out. See CpuDef.GetOpCycleMod().
+ ///
private int CycDef { get; set; }
public int Cycles { get { return CycDef & 0xff; } }
public CycleMod CycleMods { get { return (CycleMod)(CycDef & ~0xff); } }
@@ -301,8 +305,14 @@ namespace Asm65 {
new StatusFlags() { Z = 1 };
private static StatusFlags FlagsAffected_C =
new StatusFlags() { C = 1 };
+ private static StatusFlags FlagsAffected_MXCE =
+ new StatusFlags() { M = 1, X = 1, C = 1, E = 1 };
+ private static StatusFlags FlagsAffected_DI =
+ new StatusFlags() { D = 1, I = 1 };
private static StatusFlags FlagsAffected_NZ =
new StatusFlags() { N = 1, Z = 1 };
+ private static StatusFlags FlagsAffected_NVZ =
+ new StatusFlags() { N = 1, V = 1, Z = 1 };
private static StatusFlags FlagsAffected_NZC =
new StatusFlags() { N = 1, Z = 1, C = 1 };
private static StatusFlags FlagsAffected_NVZC =
@@ -626,6 +636,11 @@ namespace Asm65 {
flags.Z = flags.N = TriState16.INDETERMINATE;
return flags;
}
+ private static StatusFlags FlagUpdater_NVZ(StatusFlags flags, int immVal,
+ ref StatusFlags condBranchTakenFlags) {
+ flags.Z = flags.V = flags.N = TriState16.INDETERMINATE;
+ return flags;
+ }
private static StatusFlags FlagUpdater_NZC(StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) {
flags.C = flags.Z = flags.N = TriState16.INDETERMINATE;
@@ -879,8 +894,8 @@ namespace Asm65 {
Mnemonic = OpName.BIT,
Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
- FlagsAffected = FlagsAffected_NZC, // special handling for imm
- StatusFlagUpdater = FlagUpdater_NZC // special handling for imm
+ FlagsAffected = FlagsAffected_NVZ, // special handling for imm
+ StatusFlagUpdater = FlagUpdater_NVZ // special handling for imm
};
private static OpDef OpBMI = new OpDef() {
Mnemonic = OpName.BMI,
@@ -923,7 +938,14 @@ namespace Asm65 {
private static OpDef OpBRK = new OpDef() {
Mnemonic = OpName.BRK,
Effect = FlowEffect.NoCont,
- BaseMemEffect = MemoryEffect.None
+ BaseMemEffect = MemoryEffect.None,
+ // On 6502/65C02 this also affects the 'B' flag, which overlaps with X. Nobody
+ // really cares though. On 6502 this doesn't clear the 'D' flag.
+ //
+ // We don't set a StatusFlagUpdater because the flags are only changed for the
+ // software break handler function. If we could actually track this into that,
+ // we'd need to configure the flags appropriately based on CPU type.
+ FlagsAffected = FlagsAffected_DI
};
private static OpDef OpBRL = new OpDef() {
Mnemonic = OpName.BRL,
@@ -1006,7 +1028,8 @@ namespace Asm65 {
private static OpDef OpCOP = new OpDef() {
Mnemonic = OpName.COP,
Effect = FlowEffect.Cont,
- BaseMemEffect = MemoryEffect.None
+ BaseMemEffect = MemoryEffect.None,
+ FlagsAffected = FlagsAffected_DI
};
private static OpDef OpCPX = new OpDef() {
Mnemonic = OpName.CPX,
@@ -1264,6 +1287,7 @@ namespace Asm65 {
Mnemonic = OpName.RTI,
Effect = FlowEffect.NoCont,
BaseMemEffect = MemoryEffect.None,
+ FlagsAffected = FlagsAffected_All
};
private static OpDef OpRTL = new OpDef() {
Mnemonic = OpName.RTL,
@@ -1462,7 +1486,7 @@ namespace Asm65 {
Mnemonic = OpName.XCE,
Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
- FlagsAffected = FlagsAffected_C,
+ FlagsAffected = FlagsAffected_MXCE,
StatusFlagUpdater = FlagUpdater_XCE
};
@@ -2880,7 +2904,9 @@ namespace Asm65 {
IsUndocumented = true,
Mnemonic = OpName.ANE,
Effect = FlowEffect.Cont,
- BaseMemEffect = MemoryEffect.None
+ BaseMemEffect = MemoryEffect.None,
+ FlagsAffected = FlagsAffected_NZ,
+ StatusFlagUpdater = FlagUpdater_NZ
};
private static OpDef OpALR = new OpDef() {
IsUndocumented = true,
@@ -2903,8 +2929,8 @@ namespace Asm65 {
Mnemonic = OpName.DCP,
Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite,
- FlagsAffected = FlagsAffected_C,
- StatusFlagUpdater = FlagUpdater_C
+ FlagsAffected = FlagsAffected_NZC,
+ StatusFlagUpdater = FlagUpdater_NZC
};
private static OpDef OpDOP = new OpDef() { // double-byte NOP
IsUndocumented = true,
@@ -2962,9 +2988,7 @@ namespace Asm65 {
IsUndocumented = true,
Mnemonic = OpName.SAX,
Effect = FlowEffect.Cont,
- BaseMemEffect = MemoryEffect.Write,
- FlagsAffected = FlagsAffected_NZ,
- StatusFlagUpdater = FlagUpdater_NZ
+ BaseMemEffect = MemoryEffect.Write
};
private static OpDef OpSBX = new OpDef() {
IsUndocumented = true,
diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs
index 73c6565..0492a8c 100644
--- a/SourceGen/MainController.cs
+++ b/SourceGen/MainController.cs
@@ -3608,6 +3608,10 @@ namespace SourceGen {
sb.Append("\u2022Cycles: ");
int cycles = op.Cycles;
+ // TODO: diff GetOpCycleMod vs. op.CycleMods to show which bits apply to
+ // current CPU vs. other CPUs
+ //Asm65.OpDef.CycleMod cycMods =
+ // mProject.CpuDef.GetOpCycleMod(mProject.FileData[line.FileOffset]);
Asm65.OpDef.CycleMod cycMods = op.CycleMods;
sb.Append(cycles.ToString());
if (cycMods != 0) {
diff --git a/SourceGen/RuntimeData/Help/tools.html b/SourceGen/RuntimeData/Help/tools.html
index 987f2f4..6a95891 100644
--- a/SourceGen/RuntimeData/Help/tools.html
+++ b/SourceGen/RuntimeData/Help/tools.html
@@ -61,6 +61,9 @@ ASCII.
This opens a window with a summary of all 256 opcodes. The CPU can
be chosen from the pop-up list at the bottom. Undocumented opcodes are
shown in italics.
+The status flags affected by each instruction are shown for the 65816
+implementation. The only significant difference vs. 6502/65C02
+is in the way the BRK instruction affects the D and B/X flags.
diff --git a/SourceGen/Tools/WpfGui/InstructionChart.xaml.cs b/SourceGen/Tools/WpfGui/InstructionChart.xaml.cs
index 3633f39..93aeed9 100644
--- a/SourceGen/Tools/WpfGui/InstructionChart.xaml.cs
+++ b/SourceGen/Tools/WpfGui/InstructionChart.xaml.cs
@@ -141,8 +141,8 @@ namespace SourceGen.Tools.WpfGui {
// Populate the items source.
InstructionItems.Clear();
CpuDef cpuDef = CpuDef.GetBestMatch(item.Type, true, false);
- for (int i = 0; i < 256; i++) {
- OpDef op = cpuDef[i];
+ for (int opc = 0; opc < 256; opc++) {
+ OpDef op = cpuDef[opc];
int opLen = op.GetLength(StatusFlags.AllIndeterminate);
string sampleValue = "$12";
@@ -169,11 +169,12 @@ namespace SourceGen.Tools.WpfGui {
}
string cycles = op.Cycles.ToString();
- if (op.CycleMods != 0) {
+ OpDef.CycleMod mods = cpuDef.GetOpCycleMod(opc);
+ if (mods != 0) {
cycles += '+';
}
- InstructionItems.Add(new InstructionItem(mFormatter.FormatHexValue(i, 2),
+ InstructionItems.Add(new InstructionItem(mFormatter.FormatHexValue(opc, 2),
instrSample, flags.ToString(), cycles,
mOpDesc.GetShortDescription(op.Mnemonic),
mOpDesc.GetAddressModeDescription(op.AddrMode),