1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-05-31 22:41:37 +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>
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>
/// Indexer. Returns the definition of opcode N.
/// </summary>

View File

@ -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.
/// </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; }
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,

View File

@ -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) {

View File

@ -61,6 +61,9 @@ ASCII.</p>
<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
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>

View File

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