1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-10-31 19:04:44 +00:00

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.
This commit is contained in:
Andy McFadden 2019-10-22 09:58:23 -07:00
parent 7bbccaf71f
commit 1b0ee7de21
5 changed files with 55 additions and 15 deletions

View File

@ -242,6 +242,14 @@ namespace Asm65 {
/// <returns>Instruction definition.</returns> /// <returns>Instruction definition.</returns>
public OpDef GetOpDef(int op) { return mOpDefs[op]; } public OpDef GetOpDef(int op) { return mOpDefs[op]; }
/// <summary>
/// Returns the set of cycle mods for the given instruction that are in effect
/// for the current CPU.
/// </summary>
/// <param name="op">Instruction opcode number (0-255).</param>
/// <returns>Reduced cycle mod set.</returns>
public OpDef.CycleMod GetOpCycleMod(int op) { return mCycleMods[op]; }
/// <summary> /// <summary>
/// Indexer. Returns the definition of opcode N. /// Indexer. Returns the definition of opcode N.
/// </summary> /// </summary>

View File

@ -196,6 +196,10 @@ namespace Asm65 {
/// Cycles required. The low 8 bits hold the base cycle count, the remaining bits /// Cycles required. The low 8 bits hold the base cycle count, the remaining bits
/// are defined by the CycleMod enum. /// are defined by the CycleMod enum.
/// </summary> /// </summary>
/// <remaks>
/// 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().
/// </remaks>
private int CycDef { get; set; } private int CycDef { get; set; }
public int Cycles { get { return CycDef & 0xff; } } public int Cycles { get { return CycDef & 0xff; } }
public CycleMod CycleMods { get { return (CycleMod)(CycDef & ~0xff); } } public CycleMod CycleMods { get { return (CycleMod)(CycDef & ~0xff); } }
@ -301,8 +305,14 @@ namespace Asm65 {
new StatusFlags() { Z = 1 }; new StatusFlags() { Z = 1 };
private static StatusFlags FlagsAffected_C = private static StatusFlags FlagsAffected_C =
new StatusFlags() { C = 1 }; 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 = private static StatusFlags FlagsAffected_NZ =
new StatusFlags() { N = 1, Z = 1 }; new StatusFlags() { N = 1, Z = 1 };
private static StatusFlags FlagsAffected_NVZ =
new StatusFlags() { N = 1, V = 1, Z = 1 };
private static StatusFlags FlagsAffected_NZC = private static StatusFlags FlagsAffected_NZC =
new StatusFlags() { N = 1, Z = 1, C = 1 }; new StatusFlags() { N = 1, Z = 1, C = 1 };
private static StatusFlags FlagsAffected_NVZC = private static StatusFlags FlagsAffected_NVZC =
@ -626,6 +636,11 @@ namespace Asm65 {
flags.Z = flags.N = TriState16.INDETERMINATE; flags.Z = flags.N = TriState16.INDETERMINATE;
return flags; 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, private static StatusFlags FlagUpdater_NZC(StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
flags.C = flags.Z = flags.N = TriState16.INDETERMINATE; flags.C = flags.Z = flags.N = TriState16.INDETERMINATE;
@ -879,8 +894,8 @@ namespace Asm65 {
Mnemonic = OpName.BIT, Mnemonic = OpName.BIT,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None, BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZC, // special handling for imm FlagsAffected = FlagsAffected_NVZ, // special handling for imm
StatusFlagUpdater = FlagUpdater_NZC // special handling for imm StatusFlagUpdater = FlagUpdater_NVZ // special handling for imm
}; };
private static OpDef OpBMI = new OpDef() { private static OpDef OpBMI = new OpDef() {
Mnemonic = OpName.BMI, Mnemonic = OpName.BMI,
@ -923,7 +938,14 @@ namespace Asm65 {
private static OpDef OpBRK = new OpDef() { private static OpDef OpBRK = new OpDef() {
Mnemonic = OpName.BRK, Mnemonic = OpName.BRK,
Effect = FlowEffect.NoCont, 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() { private static OpDef OpBRL = new OpDef() {
Mnemonic = OpName.BRL, Mnemonic = OpName.BRL,
@ -1006,7 +1028,8 @@ namespace Asm65 {
private static OpDef OpCOP = new OpDef() { private static OpDef OpCOP = new OpDef() {
Mnemonic = OpName.COP, Mnemonic = OpName.COP,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_DI
}; };
private static OpDef OpCPX = new OpDef() { private static OpDef OpCPX = new OpDef() {
Mnemonic = OpName.CPX, Mnemonic = OpName.CPX,
@ -1264,6 +1287,7 @@ namespace Asm65 {
Mnemonic = OpName.RTI, Mnemonic = OpName.RTI,
Effect = FlowEffect.NoCont, Effect = FlowEffect.NoCont,
BaseMemEffect = MemoryEffect.None, BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_All
}; };
private static OpDef OpRTL = new OpDef() { private static OpDef OpRTL = new OpDef() {
Mnemonic = OpName.RTL, Mnemonic = OpName.RTL,
@ -1462,7 +1486,7 @@ namespace Asm65 {
Mnemonic = OpName.XCE, Mnemonic = OpName.XCE,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None, BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_C, FlagsAffected = FlagsAffected_MXCE,
StatusFlagUpdater = FlagUpdater_XCE StatusFlagUpdater = FlagUpdater_XCE
}; };
@ -2880,7 +2904,9 @@ namespace Asm65 {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.ANE, Mnemonic = OpName.ANE,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpALR = new OpDef() { private static OpDef OpALR = new OpDef() {
IsUndocumented = true, IsUndocumented = true,
@ -2903,8 +2929,8 @@ namespace Asm65 {
Mnemonic = OpName.DCP, Mnemonic = OpName.DCP,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite, BaseMemEffect = MemoryEffect.ReadModifyWrite,
FlagsAffected = FlagsAffected_C, FlagsAffected = FlagsAffected_NZC,
StatusFlagUpdater = FlagUpdater_C StatusFlagUpdater = FlagUpdater_NZC
}; };
private static OpDef OpDOP = new OpDef() { // double-byte NOP private static OpDef OpDOP = new OpDef() { // double-byte NOP
IsUndocumented = true, IsUndocumented = true,
@ -2962,9 +2988,7 @@ namespace Asm65 {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.SAX, Mnemonic = OpName.SAX,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Write, BaseMemEffect = MemoryEffect.Write
FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpSBX = new OpDef() { private static OpDef OpSBX = new OpDef() {
IsUndocumented = true, IsUndocumented = true,

View File

@ -3608,6 +3608,10 @@ namespace SourceGen {
sb.Append("\u2022Cycles: "); sb.Append("\u2022Cycles: ");
int cycles = op.Cycles; 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; Asm65.OpDef.CycleMod cycMods = op.CycleMods;
sb.Append(cycles.ToString()); sb.Append(cycles.ToString());
if (cycMods != 0) { if (cycMods != 0) {

View File

@ -61,6 +61,9 @@ ASCII.</p>
<p>This opens a window with a summary of all 256 opcodes. The CPU can <p>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 be chosen from the pop-up list at the bottom. Undocumented opcodes are
shown in italics.</p> shown in italics.</p>
<p>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.</p>
</div> </div>

View File

@ -141,8 +141,8 @@ namespace SourceGen.Tools.WpfGui {
// Populate the items source. // Populate the items source.
InstructionItems.Clear(); InstructionItems.Clear();
CpuDef cpuDef = CpuDef.GetBestMatch(item.Type, true, false); CpuDef cpuDef = CpuDef.GetBestMatch(item.Type, true, false);
for (int i = 0; i < 256; i++) { for (int opc = 0; opc < 256; opc++) {
OpDef op = cpuDef[i]; OpDef op = cpuDef[opc];
int opLen = op.GetLength(StatusFlags.AllIndeterminate); int opLen = op.GetLength(StatusFlags.AllIndeterminate);
string sampleValue = "$12"; string sampleValue = "$12";
@ -169,11 +169,12 @@ namespace SourceGen.Tools.WpfGui {
} }
string cycles = op.Cycles.ToString(); string cycles = op.Cycles.ToString();
if (op.CycleMods != 0) { OpDef.CycleMod mods = cpuDef.GetOpCycleMod(opc);
if (mods != 0) {
cycles += '+'; cycles += '+';
} }
InstructionItems.Add(new InstructionItem(mFormatter.FormatHexValue(i, 2), InstructionItems.Add(new InstructionItem(mFormatter.FormatHexValue(opc, 2),
instrSample, flags.ToString(), cycles, instrSample, flags.ToString(), cycles,
mOpDesc.GetShortDescription(op.Mnemonic), mOpDesc.GetShortDescription(op.Mnemonic),
mOpDesc.GetAddressModeDescription(op.AddrMode), mOpDesc.GetAddressModeDescription(op.AddrMode),