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