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),