1
0
mirror of https://github.com/fadden/6502bench.git synced 2025-02-06 23:30:56 +00:00

Add more detail to cross references

In the cross-reference table we now indicate whether the reference
source is doing a read, write, read-modify-write, branch, subroutine
call, is just referencing the address, or is part of the data.
This commit is contained in:
Andy McFadden 2019-04-11 16:23:02 -07:00
parent 84eceee085
commit 47b1363738
10 changed files with 303 additions and 95 deletions

View File

@ -33,7 +33,18 @@ namespace Asm65 {
NoCont, // RTS, BRK, ... (jump to new address, not specified in operand) NoCont, // RTS, BRK, ... (jump to new address, not specified in operand)
CallSubroutine, // JSR, JSL (jump to new address, and also continue to next) CallSubroutine, // JSR, JSL (jump to new address, and also continue to next)
ConditionalBranch // BCC, BEQ, ... (jump to new address and/or continue to next) ConditionalBranch // BCC, BEQ, ... (jump to new address and/or continue to next)
}; }
/// <summary>
/// Effect of executing an instruction on memory.
/// </summary>
public enum MemoryEffect {
Unknown = 0,
None, // e.g. TAX, PEA addr, LDA #imm
Read, // e.g. LDA addr
Write, // e.g. STA addr
ReadModifyWrite // e.g. LSR addr
}
/// <summary> /// <summary>
/// Addressing mode. This uses the same distinctions as Eyes & Lichty, which for /// Addressing mode. This uses the same distinctions as Eyes & Lichty, which for
@ -160,6 +171,22 @@ namespace Asm65 {
/// </summary> /// </summary>
public FlowEffect Effect { get; private set; } public FlowEffect Effect { get; private set; }
/// <summary>
/// Effect this instruction has on memory.
/// </summary>
public MemoryEffect MemEffect {
get {
// If we do this a lot, we should probably just go through and set the
// mem effect to "none" in all the immediate-mode op definitions.
if (IsImmediate) {
return MemoryEffect.None;
} else {
return BaseMemEffect;
}
}
}
private MemoryEffect BaseMemEffect { get; set; }
/// <summary> /// <summary>
/// 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.
@ -221,6 +248,7 @@ namespace Asm65 {
this.Mnemonic = src.Mnemonic; this.Mnemonic = src.Mnemonic;
this.FlagsAffected = src.FlagsAffected; this.FlagsAffected = src.FlagsAffected;
this.Effect = src.Effect; this.Effect = src.Effect;
this.BaseMemEffect = src.BaseMemEffect;
this.CycDef = src.CycDef; this.CycDef = src.CycDef;
this.IsOperandWidthUnambiguous = src.IsOperandWidthUnambiguous; this.IsOperandWidthUnambiguous = src.IsOperandWidthUnambiguous;
this.StatusFlagUpdater = src.StatusFlagUpdater; this.StatusFlagUpdater = src.StatusFlagUpdater;
@ -247,10 +275,10 @@ namespace Asm65 {
/// <summary> /// <summary>
/// True if this operation is a branch instruction (conditional branch, /// True if this operation is any type of branch instruction (conditional branch,
/// unconditional branch/jump, subroutine call). /// unconditional branch/jump, subroutine call).
/// </summary> /// </summary>
public bool IsBranch { public bool IsBranchOrSubCall {
get { get {
return Effect == FlowEffect.Branch || return Effect == FlowEffect.Branch ||
Effect == FlowEffect.ConditionalBranch || Effect == FlowEffect.ConditionalBranch ||
@ -258,6 +286,15 @@ namespace Asm65 {
} }
} }
/// <summary>
/// True if this operation is a subroutine call.
/// </summary>
public bool IsSubroutineCall {
get {
return Effect == FlowEffect.CallSubroutine;
}
}
/// <summary> /// <summary>
/// True if the operand is an immediate value, which should be prefixed with '#'. /// True if the operand is an immediate value, which should be prefixed with '#'.
/// </summary> /// </summary>
@ -270,11 +307,11 @@ namespace Asm65 {
} }
/// <summary> /// <summary>
/// True if the operand is an "extended immediate" value, which includes PEA /// True if the operand is an "extended immediate" value, which includes PEA in
/// as well as Imm. /// addition to Imm/ImmLongA/ImmLongXY.
/// </summary> /// </summary>
public bool IsExtendedImmediate { public bool IsExtendedImmediate {
get { // should this include PER as well? get {
return IsImmediate || AddrMode == AddressMode.StackAbs; return IsImmediate || AddrMode == AddressMode.StackAbs;
} }
} }
@ -748,24 +785,28 @@ namespace Asm65 {
private static OpDef OpADC = new OpDef() { private static OpDef OpADC = new OpDef() {
Mnemonic = OpName.ADC, Mnemonic = OpName.ADC,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Read,
FlagsAffected = FlagsAffected_NVZC, FlagsAffected = FlagsAffected_NVZC,
StatusFlagUpdater = FlagUpdater_NVZC StatusFlagUpdater = FlagUpdater_NVZC
}; };
private static OpDef OpAND = new OpDef() { private static OpDef OpAND = new OpDef() {
Mnemonic = OpName.AND, Mnemonic = OpName.AND,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Read,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ // special handling for imm StatusFlagUpdater = FlagUpdater_NZ // special handling for imm
}; };
private static OpDef OpASL = new OpDef() { private static OpDef OpASL = new OpDef() {
Mnemonic = OpName.ASL, Mnemonic = OpName.ASL,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite,
FlagsAffected = FlagsAffected_NZC, FlagsAffected = FlagsAffected_NZC,
StatusFlagUpdater = FlagUpdater_NZC StatusFlagUpdater = FlagUpdater_NZC
}; };
private static OpDef OpBCC = new OpDef() { private static OpDef OpBCC = new OpDef() {
Mnemonic = OpName.BCC, Mnemonic = OpName.BCC,
Effect = FlowEffect.ConditionalBranch, Effect = FlowEffect.ConditionalBranch,
BaseMemEffect = MemoryEffect.None,
StatusFlagUpdater = delegate(StatusFlags flags, int immVal, StatusFlagUpdater = delegate(StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
condBranchTakenFlags.C = 0; condBranchTakenFlags.C = 0;
@ -776,6 +817,7 @@ namespace Asm65 {
private static OpDef OpBCS = new OpDef() { private static OpDef OpBCS = new OpDef() {
Mnemonic = OpName.BCS, Mnemonic = OpName.BCS,
Effect = FlowEffect.ConditionalBranch, Effect = FlowEffect.ConditionalBranch,
BaseMemEffect = MemoryEffect.None,
StatusFlagUpdater = delegate (StatusFlags flags, int immVal, StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
condBranchTakenFlags.C = 1; condBranchTakenFlags.C = 1;
@ -786,6 +828,7 @@ namespace Asm65 {
private static OpDef OpBEQ = new OpDef() { private static OpDef OpBEQ = new OpDef() {
Mnemonic = OpName.BEQ, Mnemonic = OpName.BEQ,
Effect = FlowEffect.ConditionalBranch, Effect = FlowEffect.ConditionalBranch,
BaseMemEffect = MemoryEffect.None,
StatusFlagUpdater = delegate (StatusFlags flags, int immVal, StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
condBranchTakenFlags.Z = 1; condBranchTakenFlags.Z = 1;
@ -796,12 +839,14 @@ namespace Asm65 {
private static OpDef OpBIT = new OpDef() { private static OpDef OpBIT = new OpDef() {
Mnemonic = OpName.BIT, Mnemonic = OpName.BIT,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZC, // special handling for imm FlagsAffected = FlagsAffected_NZC, // special handling for imm
StatusFlagUpdater = FlagUpdater_NZC // special handling for imm StatusFlagUpdater = FlagUpdater_NZC // special handling for imm
}; };
private static OpDef OpBMI = new OpDef() { private static OpDef OpBMI = new OpDef() {
Mnemonic = OpName.BMI, Mnemonic = OpName.BMI,
Effect = FlowEffect.ConditionalBranch, Effect = FlowEffect.ConditionalBranch,
BaseMemEffect = MemoryEffect.None,
StatusFlagUpdater = delegate (StatusFlags flags, int immVal, StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
condBranchTakenFlags.N = 1; condBranchTakenFlags.N = 1;
@ -812,6 +857,7 @@ namespace Asm65 {
private static OpDef OpBNE = new OpDef() { private static OpDef OpBNE = new OpDef() {
Mnemonic = OpName.BNE, Mnemonic = OpName.BNE,
Effect = FlowEffect.ConditionalBranch, Effect = FlowEffect.ConditionalBranch,
BaseMemEffect = MemoryEffect.None,
StatusFlagUpdater = delegate (StatusFlags flags, int immVal, StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
condBranchTakenFlags.Z = 0; condBranchTakenFlags.Z = 0;
@ -822,6 +868,7 @@ namespace Asm65 {
private static OpDef OpBPL = new OpDef() { private static OpDef OpBPL = new OpDef() {
Mnemonic = OpName.BPL, Mnemonic = OpName.BPL,
Effect = FlowEffect.ConditionalBranch, Effect = FlowEffect.ConditionalBranch,
BaseMemEffect = MemoryEffect.None,
StatusFlagUpdater = delegate (StatusFlags flags, int immVal, StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
condBranchTakenFlags.N = 0; condBranchTakenFlags.N = 0;
@ -831,19 +878,23 @@ namespace Asm65 {
}; };
private static OpDef OpBRA = new OpDef() { private static OpDef OpBRA = new OpDef() {
Mnemonic = OpName.BRA, Mnemonic = OpName.BRA,
Effect = FlowEffect.Branch Effect = FlowEffect.Branch,
BaseMemEffect = MemoryEffect.None
}; };
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
}; };
private static OpDef OpBRL = new OpDef() { private static OpDef OpBRL = new OpDef() {
Mnemonic = OpName.BRL, Mnemonic = OpName.BRL,
Effect = FlowEffect.Branch Effect = FlowEffect.Branch,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpBVC = new OpDef() { private static OpDef OpBVC = new OpDef() {
Mnemonic = OpName.BVC, Mnemonic = OpName.BVC,
Effect = FlowEffect.ConditionalBranch, Effect = FlowEffect.ConditionalBranch,
BaseMemEffect = MemoryEffect.None,
StatusFlagUpdater = delegate (StatusFlags flags, int immVal, StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
condBranchTakenFlags.V = 0; condBranchTakenFlags.V = 0;
@ -854,6 +905,7 @@ namespace Asm65 {
private static OpDef OpBVS = new OpDef() { private static OpDef OpBVS = new OpDef() {
Mnemonic = OpName.BVS, Mnemonic = OpName.BVS,
Effect = FlowEffect.ConditionalBranch, Effect = FlowEffect.ConditionalBranch,
BaseMemEffect = MemoryEffect.None,
StatusFlagUpdater = delegate (StatusFlags flags, int immVal, StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
condBranchTakenFlags.V = 1; condBranchTakenFlags.V = 1;
@ -864,6 +916,7 @@ namespace Asm65 {
private static OpDef OpCLC = new OpDef() { private static OpDef OpCLC = new OpDef() {
Mnemonic = OpName.CLC, Mnemonic = OpName.CLC,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_C, FlagsAffected = FlagsAffected_C,
StatusFlagUpdater = delegate (StatusFlags flags, int immVal, StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
@ -874,6 +927,7 @@ namespace Asm65 {
private static OpDef OpCLD = new OpDef() { private static OpDef OpCLD = new OpDef() {
Mnemonic = OpName.CLD, Mnemonic = OpName.CLD,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_D, FlagsAffected = FlagsAffected_D,
StatusFlagUpdater = delegate (StatusFlags flags, int immVal, StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
@ -884,6 +938,7 @@ namespace Asm65 {
private static OpDef OpCLI = new OpDef() { private static OpDef OpCLI = new OpDef() {
Mnemonic = OpName.CLI, Mnemonic = OpName.CLI,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_I, FlagsAffected = FlagsAffected_I,
StatusFlagUpdater = delegate (StatusFlags flags, int immVal, StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
@ -894,6 +949,7 @@ namespace Asm65 {
private static OpDef OpCLV = new OpDef() { private static OpDef OpCLV = new OpDef() {
Mnemonic = OpName.CLV, Mnemonic = OpName.CLV,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_V, FlagsAffected = FlagsAffected_V,
StatusFlagUpdater = delegate (StatusFlags flags, int immVal, StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
@ -904,246 +960,293 @@ namespace Asm65 {
private static OpDef OpCMP = new OpDef() { private static OpDef OpCMP = new OpDef() {
Mnemonic = OpName.CMP, Mnemonic = OpName.CMP,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Read,
FlagsAffected = FlagsAffected_NZC, FlagsAffected = FlagsAffected_NZC,
StatusFlagUpdater = FlagUpdater_NZC StatusFlagUpdater = FlagUpdater_NZC
}; };
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
}; };
private static OpDef OpCPX = new OpDef() { private static OpDef OpCPX = new OpDef() {
Mnemonic = OpName.CPX, Mnemonic = OpName.CPX,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Read,
FlagsAffected = FlagsAffected_NZC, FlagsAffected = FlagsAffected_NZC,
StatusFlagUpdater = FlagUpdater_NZC StatusFlagUpdater = FlagUpdater_NZC
}; };
private static OpDef OpCPY = new OpDef() { private static OpDef OpCPY = new OpDef() {
Mnemonic = OpName.CPY, Mnemonic = OpName.CPY,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Read,
FlagsAffected = FlagsAffected_NZC, FlagsAffected = FlagsAffected_NZC,
StatusFlagUpdater = FlagUpdater_NZC StatusFlagUpdater = FlagUpdater_NZC
}; };
private static OpDef OpDEC = new OpDef() { private static OpDef OpDEC = new OpDef() {
Mnemonic = OpName.DEC, Mnemonic = OpName.DEC,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpDEX = new OpDef() { private static OpDef OpDEX = new OpDef() {
Mnemonic = OpName.DEX, Mnemonic = OpName.DEX,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpDEY = new OpDef() { private static OpDef OpDEY = new OpDef() {
Mnemonic = OpName.DEY, Mnemonic = OpName.DEY,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpEOR = new OpDef() { private static OpDef OpEOR = new OpDef() {
Mnemonic = OpName.EOR, Mnemonic = OpName.EOR,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Read,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpINC = new OpDef() { private static OpDef OpINC = new OpDef() {
Mnemonic = OpName.INC, Mnemonic = OpName.INC,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpINX = new OpDef() { private static OpDef OpINX = new OpDef() {
Mnemonic = OpName.INX, Mnemonic = OpName.INX,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpINY = new OpDef() { private static OpDef OpINY = new OpDef() {
Mnemonic = OpName.INY, Mnemonic = OpName.INY,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpJML = new OpDef() { private static OpDef OpJML = new OpDef() {
Mnemonic = OpName.JML, // technically JMP with long operand, but JML is convention Mnemonic = OpName.JML, // technically JMP with long operand, but JML is convention
Effect = FlowEffect.Branch, Effect = FlowEffect.Branch,
BaseMemEffect = MemoryEffect.None,
IsOperandWidthUnambiguous = true, IsOperandWidthUnambiguous = true,
}; };
private static OpDef OpJMP = new OpDef() { private static OpDef OpJMP = new OpDef() {
Mnemonic = OpName.JMP, Mnemonic = OpName.JMP,
Effect = FlowEffect.Branch, Effect = FlowEffect.Branch,
BaseMemEffect = MemoryEffect.None,
IsOperandWidthUnambiguous = true IsOperandWidthUnambiguous = true
}; };
private static OpDef OpJSL = new OpDef() { private static OpDef OpJSL = new OpDef() {
Mnemonic = OpName.JSL, // technically JSR with long operand, but JSL is convention Mnemonic = OpName.JSL, // technically JSR with long operand, but JSL is convention
Effect = FlowEffect.CallSubroutine, Effect = FlowEffect.CallSubroutine,
BaseMemEffect = MemoryEffect.None,
IsOperandWidthUnambiguous = true, IsOperandWidthUnambiguous = true,
StatusFlagUpdater = FlagUpdater_Subroutine StatusFlagUpdater = FlagUpdater_Subroutine
}; };
private static OpDef OpJSR = new OpDef() { private static OpDef OpJSR = new OpDef() {
Mnemonic = OpName.JSR, Mnemonic = OpName.JSR,
Effect = FlowEffect.CallSubroutine, Effect = FlowEffect.CallSubroutine,
BaseMemEffect = MemoryEffect.None,
IsOperandWidthUnambiguous = true, IsOperandWidthUnambiguous = true,
StatusFlagUpdater = FlagUpdater_Subroutine StatusFlagUpdater = FlagUpdater_Subroutine
}; };
private static OpDef OpLDA = new OpDef() { private static OpDef OpLDA = new OpDef() {
Mnemonic = OpName.LDA, Mnemonic = OpName.LDA,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Read,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ // special handling for imm StatusFlagUpdater = FlagUpdater_NZ // special handling for imm
}; };
private static OpDef OpLDX = new OpDef() { private static OpDef OpLDX = new OpDef() {
Mnemonic = OpName.LDX, Mnemonic = OpName.LDX,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Read,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ // special handling for imm StatusFlagUpdater = FlagUpdater_NZ // special handling for imm
}; };
private static OpDef OpLDY = new OpDef() { private static OpDef OpLDY = new OpDef() {
Mnemonic = OpName.LDY, Mnemonic = OpName.LDY,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Read,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ // special handling for imm StatusFlagUpdater = FlagUpdater_NZ // special handling for imm
}; };
private static OpDef OpLSR = new OpDef() { private static OpDef OpLSR = new OpDef() {
Mnemonic = OpName.LSR, Mnemonic = OpName.LSR,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite,
FlagsAffected = FlagsAffected_NZC, FlagsAffected = FlagsAffected_NZC,
StatusFlagUpdater = FlagUpdater_NZC StatusFlagUpdater = FlagUpdater_NZC
}; };
private static OpDef OpMVN = new OpDef() { private static OpDef OpMVN = new OpDef() {
Mnemonic = OpName.MVN, Mnemonic = OpName.MVN,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None // not quite right, but what is?
}; };
private static OpDef OpMVP = new OpDef() { private static OpDef OpMVP = new OpDef() {
Mnemonic = OpName.MVP, Mnemonic = OpName.MVP,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpNOP = new OpDef() { private static OpDef OpNOP = new OpDef() {
Mnemonic = OpName.NOP, Mnemonic = OpName.NOP,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpORA = new OpDef() { private static OpDef OpORA = new OpDef() {
Mnemonic = OpName.ORA, Mnemonic = OpName.ORA,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Read,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ // special handling for imm StatusFlagUpdater = FlagUpdater_NZ // special handling for imm
}; };
private static OpDef OpPEA = new OpDef() { private static OpDef OpPEA = new OpDef() {
Mnemonic = OpName.PEA, Mnemonic = OpName.PEA,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpPEI = new OpDef() { private static OpDef OpPEI = new OpDef() {
Mnemonic = OpName.PEI, Mnemonic = OpName.PEI,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Read
}; };
private static OpDef OpPER = new OpDef() { private static OpDef OpPER = new OpDef() {
Mnemonic = OpName.PER, Mnemonic = OpName.PER,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpPHA = new OpDef() { private static OpDef OpPHA = new OpDef() {
Mnemonic = OpName.PHA, Mnemonic = OpName.PHA,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpPHB = new OpDef() { private static OpDef OpPHB = new OpDef() {
Mnemonic = OpName.PHB, Mnemonic = OpName.PHB,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpPHD = new OpDef() { private static OpDef OpPHD = new OpDef() {
Mnemonic = OpName.PHD, Mnemonic = OpName.PHD,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpPHK = new OpDef() { private static OpDef OpPHK = new OpDef() {
Mnemonic = OpName.PHK, Mnemonic = OpName.PHK,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpPHP = new OpDef() { private static OpDef OpPHP = new OpDef() {
Mnemonic = OpName.PHP, Mnemonic = OpName.PHP,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpPHX = new OpDef() { private static OpDef OpPHX = new OpDef() {
Mnemonic = OpName.PHX, Mnemonic = OpName.PHX,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpPHY = new OpDef() { private static OpDef OpPHY = new OpDef() {
Mnemonic = OpName.PHY, Mnemonic = OpName.PHY,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpPLA = new OpDef() { private static OpDef OpPLA = new OpDef() {
Mnemonic = OpName.PLA, Mnemonic = OpName.PLA,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpPLB = new OpDef() { private static OpDef OpPLB = new OpDef() {
Mnemonic = OpName.PLB, Mnemonic = OpName.PLB,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpPLD = new OpDef() { private static OpDef OpPLD = new OpDef() {
Mnemonic = OpName.PLD, Mnemonic = OpName.PLD,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpPLP = new OpDef() { private static OpDef OpPLP = new OpDef() {
Mnemonic = OpName.PLP, Mnemonic = OpName.PLP,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_All, FlagsAffected = FlagsAffected_All,
StatusFlagUpdater = FlagUpdater_PLP StatusFlagUpdater = FlagUpdater_PLP
}; };
private static OpDef OpPLX = new OpDef() { private static OpDef OpPLX = new OpDef() {
Mnemonic = OpName.PLX, Mnemonic = OpName.PLX,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpPLY = new OpDef() { private static OpDef OpPLY = new OpDef() {
Mnemonic = OpName.PLY, Mnemonic = OpName.PLY,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpREP = new OpDef() { private static OpDef OpREP = new OpDef() {
Mnemonic = OpName.REP, Mnemonic = OpName.REP,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_All, FlagsAffected = FlagsAffected_All,
StatusFlagUpdater = FlagUpdater_REP StatusFlagUpdater = FlagUpdater_REP
}; };
private static OpDef OpROL = new OpDef() { private static OpDef OpROL = new OpDef() {
Mnemonic = OpName.ROL, Mnemonic = OpName.ROL,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite,
FlagsAffected = FlagsAffected_NZC, FlagsAffected = FlagsAffected_NZC,
StatusFlagUpdater = FlagUpdater_ROL StatusFlagUpdater = FlagUpdater_ROL
}; };
private static OpDef OpROR = new OpDef() { private static OpDef OpROR = new OpDef() {
Mnemonic = OpName.ROR, Mnemonic = OpName.ROR,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite,
FlagsAffected = FlagsAffected_NZC, FlagsAffected = FlagsAffected_NZC,
StatusFlagUpdater = FlagUpdater_ROR StatusFlagUpdater = FlagUpdater_ROR
}; };
private static OpDef OpRTI = new OpDef() { private static OpDef OpRTI = new OpDef() {
Mnemonic = OpName.RTI, Mnemonic = OpName.RTI,
Effect = FlowEffect.NoCont Effect = FlowEffect.NoCont,
BaseMemEffect = MemoryEffect.None,
}; };
private static OpDef OpRTL = new OpDef() { private static OpDef OpRTL = new OpDef() {
Mnemonic = OpName.RTL, Mnemonic = OpName.RTL,
Effect = FlowEffect.NoCont Effect = FlowEffect.NoCont,
BaseMemEffect = MemoryEffect.None,
}; };
private static OpDef OpRTS = new OpDef() { private static OpDef OpRTS = new OpDef() {
Mnemonic = OpName.RTS, Mnemonic = OpName.RTS,
Effect = FlowEffect.NoCont Effect = FlowEffect.NoCont,
BaseMemEffect = MemoryEffect.None,
}; };
private static OpDef OpSBC = new OpDef() { private static OpDef OpSBC = new OpDef() {
Mnemonic = OpName.SBC, Mnemonic = OpName.SBC,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Read,
FlagsAffected = FlagsAffected_NVZC, FlagsAffected = FlagsAffected_NVZC,
StatusFlagUpdater = FlagUpdater_NVZC StatusFlagUpdater = FlagUpdater_NVZC
}; };
private static OpDef OpSEC = new OpDef() { private static OpDef OpSEC = new OpDef() {
Mnemonic = OpName.SEC, Mnemonic = OpName.SEC,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_C, FlagsAffected = FlagsAffected_C,
StatusFlagUpdater = delegate (StatusFlags flags, int immVal, StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
@ -1154,6 +1257,7 @@ namespace Asm65 {
private static OpDef OpSED = new OpDef() { private static OpDef OpSED = new OpDef() {
Mnemonic = OpName.SED, Mnemonic = OpName.SED,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_D, FlagsAffected = FlagsAffected_D,
StatusFlagUpdater = delegate (StatusFlags flags, int immVal, StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
@ -1164,6 +1268,7 @@ namespace Asm65 {
private static OpDef OpSEI = new OpDef() { private static OpDef OpSEI = new OpDef() {
Mnemonic = OpName.SEI, Mnemonic = OpName.SEI,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_I, FlagsAffected = FlagsAffected_I,
StatusFlagUpdater = delegate (StatusFlags flags, int immVal, StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
ref StatusFlags condBranchTakenFlags) { ref StatusFlags condBranchTakenFlags) {
@ -1174,126 +1279,150 @@ namespace Asm65 {
private static OpDef OpSEP = new OpDef() { private static OpDef OpSEP = new OpDef() {
Mnemonic = OpName.SEP, Mnemonic = OpName.SEP,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_All, FlagsAffected = FlagsAffected_All,
StatusFlagUpdater = FlagUpdater_SEP StatusFlagUpdater = FlagUpdater_SEP
}; };
private static OpDef OpSTA = new OpDef() { private static OpDef OpSTA = new OpDef() {
Mnemonic = OpName.STA, Mnemonic = OpName.STA,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Write,
}; };
private static OpDef OpSTP = new OpDef() { private static OpDef OpSTP = new OpDef() {
Mnemonic = OpName.STP, Mnemonic = OpName.STP,
Effect = FlowEffect.NoCont Effect = FlowEffect.NoCont,
BaseMemEffect = MemoryEffect.None,
}; };
private static OpDef OpSTX = new OpDef() { private static OpDef OpSTX = new OpDef() {
Mnemonic = OpName.STX, Mnemonic = OpName.STX,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Write,
}; };
private static OpDef OpSTY = new OpDef() { private static OpDef OpSTY = new OpDef() {
Mnemonic = OpName.STY, Mnemonic = OpName.STY,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Write,
}; };
private static OpDef OpSTZ = new OpDef() { private static OpDef OpSTZ = new OpDef() {
Mnemonic = OpName.STZ, Mnemonic = OpName.STZ,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Write,
}; };
private static OpDef OpTAX = new OpDef() { private static OpDef OpTAX = new OpDef() {
Mnemonic = OpName.TAX, Mnemonic = OpName.TAX,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpTAY = new OpDef() { private static OpDef OpTAY = new OpDef() {
Mnemonic = OpName.TAY, Mnemonic = OpName.TAY,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpTCD = new OpDef() { private static OpDef OpTCD = new OpDef() {
Mnemonic = OpName.TCD, Mnemonic = OpName.TCD,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpTCS = new OpDef() { private static OpDef OpTCS = new OpDef() {
Mnemonic = OpName.TCS, Mnemonic = OpName.TCS,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpTDC = new OpDef() { private static OpDef OpTDC = new OpDef() {
Mnemonic = OpName.TDC, Mnemonic = OpName.TDC,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpTRB = new OpDef() { private static OpDef OpTRB = new OpDef() {
Mnemonic = OpName.TRB, Mnemonic = OpName.TRB,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite,
FlagsAffected = FlagsAffected_Z, FlagsAffected = FlagsAffected_Z,
StatusFlagUpdater = FlagUpdater_Z StatusFlagUpdater = FlagUpdater_Z
}; };
private static OpDef OpTSB = new OpDef() { private static OpDef OpTSB = new OpDef() {
Mnemonic = OpName.TSB, Mnemonic = OpName.TSB,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite,
FlagsAffected = FlagsAffected_Z, FlagsAffected = FlagsAffected_Z,
StatusFlagUpdater = FlagUpdater_Z StatusFlagUpdater = FlagUpdater_Z
}; };
private static OpDef OpTSC = new OpDef() { private static OpDef OpTSC = new OpDef() {
Mnemonic = OpName.TSC, Mnemonic = OpName.TSC,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpTSX = new OpDef() { private static OpDef OpTSX = new OpDef() {
Mnemonic = OpName.TSX, Mnemonic = OpName.TSX,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpTXA = new OpDef() { private static OpDef OpTXA = new OpDef() {
Mnemonic = OpName.TXA, Mnemonic = OpName.TXA,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpTXS = new OpDef() { private static OpDef OpTXS = new OpDef() {
Mnemonic = OpName.TXS, Mnemonic = OpName.TXS,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpTXY = new OpDef() { private static OpDef OpTXY = new OpDef() {
Mnemonic = OpName.TXY, Mnemonic = OpName.TXY,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpTYA = new OpDef() { private static OpDef OpTYA = new OpDef() {
Mnemonic = OpName.TYA, Mnemonic = OpName.TYA,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpTYX = new OpDef() { private static OpDef OpTYX = new OpDef() {
Mnemonic = OpName.TYX, Mnemonic = OpName.TYX,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpWAI = new OpDef() { private static OpDef OpWAI = new OpDef() {
Mnemonic = OpName.WAI, Mnemonic = OpName.WAI,
Effect = FlowEffect.Cont // when I=1 (interrupts disabled), continues on interrupt Effect = FlowEffect.Cont, // when I=1 (interrupts disabled), continues on interrupt
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpWDM = new OpDef() { private static OpDef OpWDM = new OpDef() {
Mnemonic = OpName.WDM, Mnemonic = OpName.WDM,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpXBA = new OpDef() { private static OpDef OpXBA = new OpDef() {
Mnemonic = OpName.XBA, Mnemonic = OpName.XBA,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
private static OpDef OpXCE = new OpDef() { private static OpDef OpXCE = new OpDef() {
Mnemonic = OpName.XCE, Mnemonic = OpName.XCE,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_C, FlagsAffected = FlagsAffected_C,
StatusFlagUpdater = FlagUpdater_XCE StatusFlagUpdater = FlagUpdater_XCE
}; };
@ -2698,18 +2827,21 @@ namespace Asm65 {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.ANC, Mnemonic = OpName.ANC,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZC, FlagsAffected = FlagsAffected_NZC,
StatusFlagUpdater = FlagUpdater_NZC StatusFlagUpdater = FlagUpdater_NZC
}; };
private static OpDef OpANE = new OpDef() { private static OpDef OpANE = new OpDef() {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.ANE, Mnemonic = OpName.ANE,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpALR = new OpDef() { private static OpDef OpALR = new OpDef() {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.ALR, Mnemonic = OpName.ALR,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZC, FlagsAffected = FlagsAffected_NZC,
StatusFlagUpdater = FlagUpdater_NZC StatusFlagUpdater = FlagUpdater_NZC
}; };
@ -2717,6 +2849,7 @@ namespace Asm65 {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.ARR, Mnemonic = OpName.ARR,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NVZC, FlagsAffected = FlagsAffected_NVZC,
StatusFlagUpdater = FlagUpdater_NVZC StatusFlagUpdater = FlagUpdater_NVZC
}; };
@ -2724,23 +2857,27 @@ namespace Asm65 {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.DCP, Mnemonic = OpName.DCP,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite,
FlagsAffected = FlagsAffected_C, FlagsAffected = FlagsAffected_C,
StatusFlagUpdater = FlagUpdater_C StatusFlagUpdater = FlagUpdater_C
}; };
private static OpDef OpDOP = new OpDef() { private static OpDef OpDOP = new OpDef() { // double-byte NOP
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.DOP, Mnemonic = OpName.DOP,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpJAM = new OpDef() { private static OpDef OpJAM = new OpDef() {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.JAM, Mnemonic = OpName.JAM,
Effect = FlowEffect.NoCont Effect = FlowEffect.NoCont,
BaseMemEffect = MemoryEffect.None
}; };
private static OpDef OpISC = new OpDef() { private static OpDef OpISC = new OpDef() {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.ISC, Mnemonic = OpName.ISC,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite,
FlagsAffected = FlagsAffected_NVZC, FlagsAffected = FlagsAffected_NVZC,
StatusFlagUpdater = FlagUpdater_NVZC StatusFlagUpdater = FlagUpdater_NVZC
}; };
@ -2748,6 +2885,7 @@ namespace Asm65 {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.LAS, Mnemonic = OpName.LAS,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Read,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
@ -2755,20 +2893,15 @@ namespace Asm65 {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.LAX, Mnemonic = OpName.LAX,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Read,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
//private static OpDef OpLXA = new OpDef() {
// IsUndocumented = true,
// Mnemonic = OpName.LXA,
// Effect = FlowEffect.Cont,
// FlagsAffected = FlagsAffected_NZ,
// StatusFlagUpdater = FlagUpdater_NZ
//};
private static OpDef OpRLA = new OpDef() { private static OpDef OpRLA = new OpDef() {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.RLA, Mnemonic = OpName.RLA,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite,
FlagsAffected = FlagsAffected_NZC, FlagsAffected = FlagsAffected_NZC,
StatusFlagUpdater = FlagUpdater_NZC StatusFlagUpdater = FlagUpdater_NZC
}; };
@ -2776,6 +2909,7 @@ namespace Asm65 {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.RRA, Mnemonic = OpName.RRA,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite,
FlagsAffected = FlagsAffected_NVZC, FlagsAffected = FlagsAffected_NVZC,
StatusFlagUpdater = FlagUpdater_NVZC StatusFlagUpdater = FlagUpdater_NVZC
}; };
@ -2783,6 +2917,7 @@ namespace Asm65 {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.SAX, Mnemonic = OpName.SAX,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Write,
FlagsAffected = FlagsAffected_NZ, FlagsAffected = FlagsAffected_NZ,
StatusFlagUpdater = FlagUpdater_NZ StatusFlagUpdater = FlagUpdater_NZ
}; };
@ -2790,33 +2925,33 @@ namespace Asm65 {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.SBX, Mnemonic = OpName.SBX,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None,
FlagsAffected = FlagsAffected_NZC, FlagsAffected = FlagsAffected_NZC,
StatusFlagUpdater = FlagUpdater_NZC StatusFlagUpdater = FlagUpdater_NZC
}; };
private static OpDef OpSHA = new OpDef() { private static OpDef OpSHA = new OpDef() {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.SHA, Mnemonic = OpName.SHA,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
}; BaseMemEffect = MemoryEffect.Write
private static OpDef OpTAS = new OpDef() {
IsUndocumented = true,
Mnemonic = OpName.TAS,
Effect = FlowEffect.Cont
}; };
private static OpDef OpSHX = new OpDef() { private static OpDef OpSHX = new OpDef() {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.SHX, Mnemonic = OpName.SHX,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Write
}; };
private static OpDef OpSHY = new OpDef() { private static OpDef OpSHY = new OpDef() {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.SHY, Mnemonic = OpName.SHY,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Write
}; };
private static OpDef OpSLO = new OpDef() { private static OpDef OpSLO = new OpDef() {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.SLO, Mnemonic = OpName.SLO,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite,
FlagsAffected = FlagsAffected_NZC, FlagsAffected = FlagsAffected_NZC,
StatusFlagUpdater = FlagUpdater_NZC StatusFlagUpdater = FlagUpdater_NZC
}; };
@ -2824,14 +2959,23 @@ namespace Asm65 {
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.SRE, Mnemonic = OpName.SRE,
Effect = FlowEffect.Cont, Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.ReadModifyWrite,
FlagsAffected = FlagsAffected_NZC, FlagsAffected = FlagsAffected_NZC,
StatusFlagUpdater = FlagUpdater_NZC StatusFlagUpdater = FlagUpdater_NZC
}; };
private static OpDef OpTOP = new OpDef() { private static OpDef OpTAS = new OpDef() {
IsUndocumented = true,
Mnemonic = OpName.TAS,
Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.Write
};
private static OpDef OpTOP = new OpDef() { // triple-byte NOP
IsUndocumented = true, IsUndocumented = true,
Mnemonic = OpName.TOP, Mnemonic = OpName.TOP,
Effect = FlowEffect.Cont Effect = FlowEffect.Cont,
BaseMemEffect = MemoryEffect.None
}; };
public static readonly OpDef OpSLO_DPIndexXInd = new OpDef(OpSLO) { public static readonly OpDef OpSLO_DPIndexXInd = new OpDef(OpSLO) {
Opcode = 0x03, Opcode = 0x03,
AddrMode = AddressMode.DPIndexXInd, AddrMode = AddressMode.DPIndexXInd,

View File

@ -4003,6 +4003,7 @@ namespace SourceGen.AppForms {
return; return;
} }
// TODO(someday): localization
Asm65.Formatter formatter = mOutputFormatter; Asm65.Formatter formatter = mOutputFormatter;
bool showBank = !mProject.CpuDef.HasAddr16; bool showBank = !mProject.CpuDef.HasAddr16;
for (int i = 0; i < xrefs.Count; i++) { for (int i = 0; i < xrefs.Count; i++) {
@ -4011,15 +4012,36 @@ namespace SourceGen.AppForms {
string typeStr; string typeStr;
switch (xr.Type) { switch (xr.Type) {
case XrefSet.XrefType.BranchOperand: case XrefSet.XrefType.SubCallOp:
typeStr = "call ";
break;
case XrefSet.XrefType.BranchOp:
typeStr = "branch "; typeStr = "branch ";
break; break;
case XrefSet.XrefType.InstrOperand: case XrefSet.XrefType.RefFromData:
typeStr = "instr ";
break;
case XrefSet.XrefType.DataOperand:
typeStr = "data "; typeStr = "data ";
break; break;
case XrefSet.XrefType.MemAccessOp:
switch (xr.AccType) {
case OpDef.MemoryEffect.Read:
typeStr = "read ";
break;
case OpDef.MemoryEffect.Write:
typeStr = "write ";
break;
case OpDef.MemoryEffect.ReadModifyWrite:
typeStr = "rmw ";
break;
case OpDef.MemoryEffect.None: // e.g. LDA #<symbol, PEA addr
typeStr = "ref ";
break;
case OpDef.MemoryEffect.Unknown:
default:
Debug.Assert(false);
typeStr = "??! ";
break;
}
break;
default: default:
Debug.Assert(false); Debug.Assert(false);
typeStr = "??? "; typeStr = "??? ";

View File

@ -336,9 +336,10 @@ namespace SourceGen.AsmGen {
// The assembler works correctly if the symbol is defined as a two-digit hex // The assembler works correctly if the symbol is defined as a two-digit hex
// value (e.g. "foo equ $80") but fails if it's four (e.g. "foo equ $0080"). We // value (e.g. "foo equ $80") but fails if it's four (e.g. "foo equ $0080"). We
// output symbols with minimal digits, but we have no control over labels when // output symbols with minimal digits, but this doesn't help if the code itself
// the code has a zero-page EQU. So if the operand is a reference to a user // lives on zero page. If the operand is a reference to a zero-page user label,
// label, we need to output the instruction as hex. // we need to output the instruction as hex.
// More info: https://github.com/apple2accumulator/merlin32/issues/8
if (op == OpDef.OpPEI_StackDPInd || if (op == OpDef.OpPEI_StackDPInd ||
op == OpDef.OpSTY_DPIndexX || op == OpDef.OpSTY_DPIndexX ||
op == OpDef.OpSTX_DPIndexY || op == OpDef.OpSTX_DPIndexY ||

View File

@ -537,7 +537,7 @@ namespace SourceGen {
bool doBranch, doContinue; bool doBranch, doContinue;
// Check for branching. // Check for branching.
if (op.IsBranch) { if (op.IsBranchOrSubCall) {
if (mAnattribs[offset].IsOperandOffsetDirect) { if (mAnattribs[offset].IsOperandOffsetDirect) {
branchOffset = mAnattribs[offset].OperandOffset; branchOffset = mAnattribs[offset].OperandOffset;
} }

View File

@ -347,6 +347,15 @@ namespace SourceGen {
isBigEndian); isBigEndian);
} }
/// <summary>
/// Given a reference from srcOffset to targetOffset, check to see if there's a
/// nearby location that we'd prefer to refer to. For example, if targetOffset points
/// into the middle of an instruction, we'd rather have it refer to the first byte.
/// </summary>
/// <param name="srcOffset">Reference source.</param>
/// <param name="targetOffset">Reference target.</param>
/// <returns>New value for targetOffset, or original value if nothing better was
/// found.</returns>
private int FindAlternateTarget(int srcOffset, int targetOffset) { private int FindAlternateTarget(int srcOffset, int targetOffset) {
int origTargetOffset = targetOffset; int origTargetOffset = targetOffset;
@ -393,7 +402,7 @@ namespace SourceGen {
// Source is an instruction, so we have an instruction referencing an instruction. // Source is an instruction, so we have an instruction referencing an instruction.
// Could be a branch, an address push, or self-modifying code. // Could be a branch, an address push, or self-modifying code.
OpDef op = mProject.CpuDef.GetOpDef(mProject.FileData[srcOffset]); OpDef op = mProject.CpuDef.GetOpDef(mProject.FileData[srcOffset]);
if (op.IsBranch) { if (op.IsBranchOrSubCall) {
// Don't mess with jumps and branches -- always go directly to the // Don't mess with jumps and branches -- always go directly to the
// target address. // target address.
} else if (op == OpDef.OpPEA_StackAbs || op == OpDef.OpPER_StackPCRelLong) { } else if (op == OpDef.OpPEA_StackAbs || op == OpDef.OpPER_StackPCRelLong) {

View File

@ -478,7 +478,8 @@ namespace SourceGen {
reanalysisTimer.EndTask("GenerateXrefs"); reanalysisTimer.EndTask("GenerateXrefs");
reanalysisTimer.StartTask("GenerateActiveDefSymbolList"); reanalysisTimer.StartTask("GenerateActiveDefSymbolList");
// Generate the list of project/platform symbols that are being used. // Generate the list of project/platform symbols that are being used. This forms
// the list of EQUates at the top of the file.
GenerateActiveDefSymbolList(); GenerateActiveDefSymbolList();
reanalysisTimer.EndTask("GenerateActiveDefSymbolList"); reanalysisTimer.EndTask("GenerateActiveDefSymbolList");
@ -792,15 +793,19 @@ namespace SourceGen {
Anattrib attr = mAnattribs[offset]; Anattrib attr = mAnattribs[offset];
XrefSet.XrefType xrefType = XrefSet.XrefType.Unknown; XrefSet.XrefType xrefType = XrefSet.XrefType.Unknown;
OpDef.MemoryEffect accType = OpDef.MemoryEffect.Unknown;
if (attr.IsInstruction) { if (attr.IsInstruction) {
OpDef op = CpuDef.GetOpDef(FileData[offset]); OpDef op = CpuDef.GetOpDef(FileData[offset]);
if (op.IsBranch) { if (op.IsSubroutineCall) {
xrefType = XrefSet.XrefType.BranchOperand; xrefType = XrefSet.XrefType.SubCallOp;
} else if (op.IsBranchOrSubCall) {
xrefType = XrefSet.XrefType.BranchOp;
} else { } else {
xrefType = XrefSet.XrefType.InstrOperand; xrefType = XrefSet.XrefType.MemAccessOp;
accType = op.MemEffect;
} }
} else if (attr.IsData || attr.IsInlineData) { } else if (attr.IsData || attr.IsInlineData) {
xrefType = XrefSet.XrefType.DataOperand; xrefType = XrefSet.XrefType.RefFromData;
} }
bool hasZeroOffsetSym = false; bool hasZeroOffsetSym = false;
@ -825,7 +830,8 @@ namespace SourceGen {
mAnattribs[operandOffset].Address; mAnattribs[operandOffset].Address;
} }
AddXref(symOffset, new XrefSet.Xref(offset, true, xrefType, adj)); AddXref(symOffset,
new XrefSet.Xref(offset, true, xrefType, accType, adj));
if (adj == 0) { if (adj == 0) {
hasZeroOffsetSym = true; hasZeroOffsetSym = true;
} }
@ -838,7 +844,8 @@ namespace SourceGen {
if (operandOffset >= 0) { if (operandOffset >= 0) {
adj = defSym.Value - operandOffset; adj = defSym.Value - operandOffset;
} }
defSym.Xrefs.Add(new XrefSet.Xref(offset, true, xrefType, adj)); defSym.Xrefs.Add(
new XrefSet.Xref(offset, true, xrefType, accType, adj));
} else { } else {
Debug.WriteLine("NOTE: not xrefing '" + sym.Label + "'"); Debug.WriteLine("NOTE: not xrefing '" + sym.Label + "'");
Debug.Assert(false); // not possible? Debug.Assert(false); // not possible?
@ -849,7 +856,8 @@ namespace SourceGen {
Debug.Assert(attr.IsData || attr.IsInlineData); Debug.Assert(attr.IsData || attr.IsInlineData);
int operandOffset = RawData.GetWord(mFileData, offset, int operandOffset = RawData.GetWord(mFileData, offset,
dfd.Length, dfd.FormatType == FormatDescriptor.Type.NumericBE); dfd.Length, dfd.FormatType == FormatDescriptor.Type.NumericBE);
AddXref(operandOffset, new XrefSet.Xref(offset, false, xrefType, 0)); AddXref(operandOffset,
new XrefSet.Xref(offset, false, xrefType, accType, 0));
} }
// Look for instruction offset references. We skip this if we've already // Look for instruction offset references. We skip this if we've already
@ -857,7 +865,8 @@ namespace SourceGen {
// just leave a duplicate entry. (The symbolic ref wins because we need // just leave a duplicate entry. (The symbolic ref wins because we need
// it for the label localizer and possibly the label refactorer.) // it for the label localizer and possibly the label refactorer.)
if (!hasZeroOffsetSym && attr.IsInstructionStart && attr.OperandOffset >= 0) { if (!hasZeroOffsetSym && attr.IsInstructionStart && attr.OperandOffset >= 0) {
AddXref(attr.OperandOffset, new XrefSet.Xref(offset, false, xrefType, 0)); AddXref(attr.OperandOffset,
new XrefSet.Xref(offset, false, xrefType, accType, 0));
} }
} }
@ -1492,13 +1501,15 @@ namespace SourceGen {
} }
/// <summary> /// <summary>
/// Updates all symbolic references to the old label. /// Updates all symbolic references to the old label. Call this after replacing
/// mAnattribs[labelOffset].Symbol.
/// </summary> /// </summary>
/// <param name="labelOffset">Offset with the just-renamed label.</param> /// <param name="labelOffset">Offset with the just-renamed label.</param>
/// <param name="oldLabel">Previous value.</param> /// <param name="oldLabel">Previous value.</param>
private void RefactorLabel(int labelOffset, string oldLabel) { private void RefactorLabel(int labelOffset, string oldLabel) {
if (!mXrefs.TryGetValue(labelOffset, out XrefSet xrefs)) { if (!mXrefs.TryGetValue(labelOffset, out XrefSet xrefs)) {
// This can happen if you add a label in the middle of nowhere and rename it. // This can happen if you add a label in a file section that nothing references,
// and then rename it.
Debug.WriteLine("RefactorLabel: no references to " + oldLabel); Debug.WriteLine("RefactorLabel: no references to " + oldLabel);
return; return;
} }
@ -1548,7 +1559,7 @@ namespace SourceGen {
continue; continue;
} }
Debug.WriteLine("Replacing symbol at +" + xr.Offset.ToString("x6") + Debug.WriteLine("Replacing OpFor symbol at +" + xr.Offset.ToString("x6") +
" with " + newLabel); " with " + newLabel);
OperandFormats[xr.Offset] = FormatDescriptor.Create( OperandFormats[xr.Offset] = FormatDescriptor.Create(
dfd.Length, new WeakSymbolRef(newLabel, dfd.SymbolRef.ValuePart), dfd.Length, new WeakSymbolRef(newLabel, dfd.SymbolRef.ValuePart),

View File

@ -127,7 +127,7 @@ code, but also needs to know how to handle the corner cases.</p>
<p>Bugs:</p> <p>Bugs:</p>
<ul> <ul>
<li>Undocumented opcodes: <code>SHA (ZP),Y</code> ($93) is not supported; <li>Undocumented opcode <code>SHA (ZP),Y</code> ($93) is not supported;
the assembler appears to be expecting <code>SHA ABS,X</code> instead.</li> the assembler appears to be expecting <code>SHA ABS,X</code> instead.</li>
<li>BRK, COP, and WDM are not allowed to have operands.</li> <li>BRK, COP, and WDM are not allowed to have operands.</li>
</ul> </ul>
@ -166,7 +166,6 @@ code, but also needs to know how to handle the corner cases.</p>
<li>PC relative branches don't wrap around at bank boundaries.</li> <li>PC relative branches don't wrap around at bank boundaries.</li>
<li>BRK &lt;arg&gt; is assembled to opcode $05 rather than $00.</li> <li>BRK &lt;arg&gt; is assembled to opcode $05 rather than $00.</li>
<li>WDM is not supported.</li> <li>WDM is not supported.</li>
<li>Source file names may not have spaces in them on Windows.</li>
</ul> </ul>
<p>Quirks:</p> <p>Quirks:</p>
@ -178,8 +177,8 @@ code, but also needs to know how to handle the corner cases.</p>
more common interpretation would be <code>label >> (8 - 16)</code>. more common interpretation would be <code>label >> (8 - 16)</code>.
(This is actually somewhat convenient, since none of the expressions (This is actually somewhat convenient, since none of the expressions
SourceGen currently generates require parenthesis.)</li> SourceGen currently generates require parenthesis.)</li>
<li>Undocumented opcodes: SBX ($cb) uses the mnemonic AXS. All other <li>Undocumented opcode <code>SBX</code> ($cb) uses the mnemonic AXS. All
opcodes match up with the "unintended opcodes" document.</li> other opcodes match up with the "unintended opcodes" document.</li>
<li>ca65 is implemented as a single-pass assembler, so label widths <li>ca65 is implemented as a single-pass assembler, so label widths
can't always be known in time. For example, if you use some zero-page can't always be known in time. For example, if you use some zero-page
labels, but they're defined via .ORG $0000 after the point where the labels, but they're defined via .ORG $0000 after the point where the
@ -224,7 +223,8 @@ code, but also needs to know how to handle the corner cases.</p>
<li>Values loaded into registers are implicitly mod 256 or 65536. There <li>Values loaded into registers are implicitly mod 256 or 65536. There
is no need to explicitly mask an expression.</li> is no need to explicitly mask an expression.</li>
<li>The assembler tracks register widths when it sees SEP/REP instructions, <li>The assembler tracks register widths when it sees SEP/REP instructions,
but doesn't attempt to track the emulation flag. So if you issue a REP but doesn't attempt to track the emulation flag. So if you issue a
<code>REP #$20</code>
while in emulation mode, the assembler will incorrectly assume long while in emulation mode, the assembler will incorrectly assume long
registers. (Really I just want to be able to turn the width-tracking registers. (Really I just want to be able to turn the width-tracking
off, but there's no way to do that.)</li> off, but there's no way to do that.)</li>

View File

@ -216,10 +216,20 @@ For each reference, the file offset, address, and some details about the
type of reference will be shown.</p> type of reference will be shown.</p>
<p>The reference type indicates whether the origin is an instruction or <p>The reference type indicates whether the origin is an instruction or
data operand. Branch instructions are called out separately. In data operand, and provides an indication of the nature of the reference:</p>
addition, it will be identified as a numeric or symbolic reference. <ul>
Symbolic references may be offset from the actual operand value; if this <li>call - subroutine call (e.g. JSR addr, JSL addr)</li>
is the case, the adjustment will be shown as well.</p> <li>branch - conditional or unconditional branch (e.g. JMP addr, BCC addr)</li>
<li>read - read from memory (e.g. LDA addr, BIT addr)</li>
<li>write - write to memory (e.g. STA addr)</li>
<li>rmw - read-modify-write (e.g. LSR addr, TSB addr)</li>
<li>ref - address reference only (e.g. LDA #&lt;addr, PEA addr)</li>
<li>data - address referenced by data (e.g. .DD2 addr)</li>
</ul>
<p>In addition, the source will be identified as a symbolic ("Sym") or
numeric ("Num") reference. Symbolic references may be offset from the
actual operand value; if this is the case, the adjustment will be shown
as well.</p>
<p>Double-clicking on a reference moves the code list selection to that <p>Double-clicking on a reference moves the code list selection to that
reference, and adds the previous selection to the navigation stack.</p> reference, and adds the previous selection to the navigation stack.</p>

View File

@ -215,7 +215,7 @@ namespace SourceGen {
/// <summary> /// <summary>
/// Generates a unique address symbol. Does not add the symbol to the list. /// Generates a unique address symbol. Does not add the symbol to the list.
/// </summary> /// </summary>
/// <param name="addr">Address label will be applied to</param> /// <param name="addr">Address that label will be applied to.</param>
/// <param name="symbols">Symbol table.</param> /// <param name="symbols">Symbol table.</param>
/// <param name="prefix">Prefix to use; must start with a letter.</param> /// <param name="prefix">Prefix to use; must start with a letter.</param>
/// <returns>Newly-created, unique symbol.</returns> /// <returns>Newly-created, unique symbol.</returns>
@ -239,7 +239,7 @@ namespace SourceGen {
sb.Append(index); sb.Append(index);
label = sb.ToString(); label = sb.ToString();
} while (index <= MAX_RENAME && symbols.TryGetValue(label, out unused)); } while (index <= MAX_RENAME && symbols.TryGetValue(label, out unused));
if (index == MAX_RENAME) { if (index > MAX_RENAME) {
// I give up // I give up
throw new Exception("Too many identical symbols"); throw new Exception("Too many identical symbols");
} }

View File

@ -28,12 +28,16 @@ namespace SourceGen {
public class XrefSet : IEnumerable<XrefSet.Xref> { public class XrefSet : IEnumerable<XrefSet.Xref> {
/// <summary> /// <summary>
/// Reference type. This is mostly useful for display to the user. /// Reference type. This is mostly useful for display to the user.
///
/// The enum is in priority order, i.e. the lowest-valued
/// item "wins" in situations where only one value is used.
/// </summary> /// </summary>
public enum XrefType { public enum XrefType {
Unknown = 0, Unknown = 0,
InstrOperand, // generic instruction operand SubCallOp, // subroutine call
BranchOperand, // branch instruction BranchOp, // branch instruction
DataOperand // e.g. ".dd2 <address>" RefFromData, // reference in data area, e.g. ".dd2 <address>"
MemAccessOp, // instruction that accesses memory, or refers to an address
} }
/// <summary> /// <summary>
@ -41,7 +45,7 @@ namespace SourceGen {
/// </summary> /// </summary>
public class Xref { public class Xref {
/// <summary> /// <summary>
/// Offset of start of instruction or data with the reference. /// Offset of start of instruction or data that refers to the target offset.
/// </summary> /// </summary>
public int Offset { get; private set; } public int Offset { get; private set; }
@ -55,22 +59,29 @@ namespace SourceGen {
/// </summary> /// </summary>
public XrefType Type { get; private set; } public XrefType Type { get; private set; }
/// <summary>
/// For Type==MemAccessOp, what type of memory access is performed.
/// </summary>
public Asm65.OpDef.MemoryEffect AccType { get; private set; }
/// <summary> /// <summary>
/// Adjustment to symbol. For example, "LDA label+2" adds an xref entry to /// Adjustment to symbol. For example, "LDA label+2" adds an xref entry to
/// "label", with an adjustment of +2. /// "label", with an adjustment of +2.
/// </summary> /// </summary>
public int Adjustment { get; private set; } public int Adjustment { get; private set; }
public Xref(int offset, bool isSymbolic, XrefType type, int adjustment) { public Xref(int offset, bool isSymbolic, XrefType type,
Asm65.OpDef.MemoryEffect accType, int adjustment) {
Offset = offset; Offset = offset;
IsSymbolic = isSymbolic; IsSymbolic = isSymbolic;
Type = type; Type = type;
AccType = accType;
Adjustment = adjustment; Adjustment = adjustment;
} }
public override string ToString() { public override string ToString() {
return "Xref off=+" + Offset.ToString("x6") + " sym=" + IsSymbolic + return "Xref off=+" + Offset.ToString("x6") + " sym=" + IsSymbolic +
" type=" + Type + " adj=" + Adjustment; " type=" + Type + " accType= " + AccType + " adj=" + Adjustment;
} }
} }