mirror of
https://github.com/fadden/6502bench.git
synced 2024-12-12 05:31:04 +00:00
3811 lines
155 KiB
C#
3811 lines
155 KiB
C#
/*
|
|
* Copyright 2018 faddenSoft
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
using System;
|
|
using System.Diagnostics;
|
|
|
|
namespace Asm65 {
|
|
/// <summary>
|
|
/// Operation code definitions for all 65xx-series CPUs.
|
|
///
|
|
/// Instances are immutable.
|
|
/// </summary>
|
|
public class OpDef {
|
|
/// <summary>
|
|
/// Effect an instruction has on code flow.
|
|
/// </summary>
|
|
public enum FlowEffect {
|
|
Unknown = 0,
|
|
Branch, // JMP, BRA, BRL, ... (jump to new address specified in operand)
|
|
Cont, // LDA, STA, PHP, NOP, ... (always continue to next instruction)
|
|
NoCont, // RTS, BRK, ... (jump to new address, not specified in operand)
|
|
CallSubroutine, // JSR, JSL (jump to new address, and also continue to next)
|
|
ConditionalBranch // BCC, BEQ, ... (jump to new address, 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>
|
|
/// Addressing mode. This uses the same distinctions as Eyes & Lichty, which for
|
|
/// most purposes has some redundancy (e.g. StackRTI is only ever used with RTI, so
|
|
/// in most cases it could be considered Implied).
|
|
///
|
|
/// The mode, combined with the processor flags on the 65816, determines the number
|
|
/// of bytes required by the instruction.
|
|
/// </summary>
|
|
public enum AddressMode : byte {
|
|
Unknown = 0, // format bytes (example)
|
|
Abs, // OP addr 3
|
|
AbsInd, // OP (addr) 3 (JMP)
|
|
AbsIndLong, // OP [addr] 3 (JML)
|
|
AbsIndexX, // OP addr,X 3
|
|
AbsIndexXInd, // OP (addr,X) 3 (JMP/JSR)
|
|
AbsIndexXLong, // OP long,X 4
|
|
AbsIndexY, // OP addr,Y 3
|
|
AbsLong, // OP long 4
|
|
Acc, // OP A 1
|
|
BlockMove, // OP srcb,dstb 3 (MVN/MVP)
|
|
DP, // OP dp 2
|
|
DPInd, // OP (dp) 2
|
|
DPIndIndexY, // OP (dp),Y 2
|
|
DPIndIndexYLong, // OP [dp],Y 2
|
|
DPIndLong, // OP [dp] 2
|
|
DPIndexX, // OP dp,X 2
|
|
DPIndexXInd, // OP (dp,X) 2
|
|
DPIndexY, // OP dp,Y 2
|
|
DPPCRel, // OP dp,label 3 (BBR/BBS)
|
|
Imm, // OP #const8 2
|
|
ImmLongA, // OP #const8/16 2 or 3, depending on 'm' flag
|
|
ImmLongXY, // OP #const8/16 2 or 3, depending on 'x' flag
|
|
Implied, // OP 1
|
|
PCRel, // OP label 2 (BCC, BNE, ...)
|
|
PCRelLong, // OP label 3 (BRL)
|
|
StackAbs, // OP addr 3 (PEA)
|
|
StackDPInd, // OP (dp) 2 (PEI)
|
|
StackInt, // OP 2 (BRK, COP)
|
|
StackPCRelLong, // OP label 3 (PER)
|
|
StackPull, // OP 1 (PLA, PLX, ...)
|
|
StackPush, // OP 1 (PHA, PHX, ...)
|
|
StackRTI, // OP 1 (RTI)
|
|
StackRTL, // OP 1 (RTL)
|
|
StackRTS, // OP 1 (RTS)
|
|
StackRel, // OP sr,S 2
|
|
StackRelIndIndexY, // OP (sr,S),Y 2
|
|
WDM // OP 2?
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cycle count modifiers. This is meant to be bitwise-ORed with the base value.
|
|
///
|
|
/// This defines things generally, with some modifiers noted as being specific to
|
|
/// certain CPUs. The actual instruction definitions may choose to include or
|
|
/// exclude bits according to the CPU being defined.
|
|
/// </summary>
|
|
[FlagsAttribute]
|
|
public enum CycleMod {
|
|
// Data from chapter 19 of Eyes & Lichty.
|
|
OneIfM0 = 1 << 8, // +1 if M=0 (16-bit mem/accumulator)
|
|
TwoIfM0 = 1 << 9, // +2 if M=0 (16-bit mem/accumulator)
|
|
OneIfX0 = 1 << 10, // +1 if X=0 (16-bit index regs)
|
|
OneIfDpNonzero = 1 << 11, // +1 if DP reg != 0
|
|
OneIfIndexPage = 1 << 12, // +1 if indexing crosses page boundary
|
|
OneIfD1 = 1 << 13, // +1 if D=1 (decimal mode) ONLY on 65C02
|
|
OneIfBranchTaken = 1 << 14, // +1 if conditional branch taken
|
|
OneIfBranchPage = 1 << 15, // +1 if branch crosses page UNLESS '816 native
|
|
OneIfE0 = 1 << 16, // +1 if 65816/865816 native mode (E=0)
|
|
OneIf65C02 = 1 << 17, // +1 if 65C02
|
|
MinusOneIfNoPage = 1 << 18, // -1 if 65C02 and no page boundary crossed
|
|
BlockMove = 1 << 19, // +7 per byte moved
|
|
}
|
|
|
|
/// <summary>
|
|
/// Width disambiguation requirement.
|
|
/// </summary>
|
|
public enum WidthDisambiguation : byte {
|
|
None = 0,
|
|
ForceDirect, // only needed for forward DP label refs in single-pass assemblers
|
|
ForceAbs,
|
|
ForceLong,
|
|
ForceLongMaybe // add opcode suffix but not operand prefix
|
|
|
|
// May want an additional item: "force long if operand suffix specified". This
|
|
// would let us generate LDAL for assemblers that like to have that made explicit,
|
|
// while avoiding prepending it to operands that are unambiguously long (e.g.
|
|
// $ff1122). The counter-argument is that the operand prefix is still useful
|
|
// for humans when looking at labels, e.g. "a:FOO" vs. "f:FOO", because the value
|
|
// of the label may not be apparent.
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Opcode numeric value, e.g. BRK is $00.
|
|
/// </summary>
|
|
public byte Opcode { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Addressing mode. Determines length of instruction (mostly) and decoding of operand.
|
|
/// </summary>
|
|
public AddressMode AddrMode { get; private set; }
|
|
|
|
/// <summary>
|
|
/// True if this is an undocumented opcode.
|
|
/// </summary>
|
|
public bool IsUndocumented { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Instruction mnemonic, e.g. LDA for Load Accumulator.
|
|
/// </summary>
|
|
public string Mnemonic { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Indication of which flags are affected by an instruction. Unaffected flags
|
|
/// will have the value TriState16.UNSPECIFIED.
|
|
///
|
|
/// This is not equivalent to the code flow status flag updater -- this just notes which
|
|
/// flags are modified directly by the instruction. This is used for display in the
|
|
/// info window and instruction chart, not analysis.
|
|
/// </summary>
|
|
public StatusFlags FlagsAffected { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Effect this instruction has on code flow.
|
|
/// </summary>
|
|
public FlowEffect Effect { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Effect this instruction has on memory.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// We don't consider execution to have a memory effect, so "LDA $1000" is Read but
|
|
/// "JMP $1000" is None. That's because the instruction itself doesn't access the
|
|
/// memory at $1000, it just changes the program counter to point there.
|
|
/// </remarks>
|
|
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>
|
|
/// 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); } }
|
|
|
|
/// <summary>
|
|
/// True if this is a numbered bit operation, i.e. BBR/BBS/RMB/SMB on the W65C02.
|
|
/// </summary>
|
|
public bool IsNumberedBitOp { get; private set; }
|
|
|
|
/// <summary>
|
|
/// True if the instruction's address mode is a direct page access.
|
|
/// </summary>
|
|
public bool IsDirectPageInstruction {
|
|
get {
|
|
switch (AddrMode) {
|
|
case AddressMode.DP:
|
|
case AddressMode.DPInd:
|
|
case AddressMode.DPIndexX:
|
|
case AddressMode.DPIndexXInd:
|
|
case AddressMode.DPIndexY:
|
|
case AddressMode.DPIndIndexY:
|
|
case AddressMode.DPIndIndexYLong:
|
|
case AddressMode.DPIndLong:
|
|
case AddressMode.StackDPInd:
|
|
// not currently handling DPPCRel as DP
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the instruction's operand is a stack-relative offset.
|
|
/// </summary>
|
|
public bool IsStackRelInstruction {
|
|
get {
|
|
return AddrMode == AddressMode.StackRel ||
|
|
AddrMode == AddressMode.StackRelIndIndexY;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// True for instructions that index off of the operand. The goal is to identify
|
|
/// instructions like "LDA $1234,Y" that may not access the address specified by
|
|
/// their operand. So "(dp,X)" returns true, but "(dp),Y" does not.
|
|
/// </summary>
|
|
public bool IsIndexedAccessInstruction {
|
|
get {
|
|
return AddrMode == AddressMode.AbsIndexX ||
|
|
AddrMode == AddressMode.AbsIndexXInd ||
|
|
AddrMode == AddressMode.AbsIndexY ||
|
|
AddrMode == AddressMode.DPIndexX ||
|
|
AddrMode == AddressMode.DPIndexXInd ||
|
|
AddrMode == AddressMode.DPIndexY;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// True for instructions that dereference the operand.
|
|
/// </summary>
|
|
public bool IsPointerAccessInstruction {
|
|
get {
|
|
return AddrMode == AddressMode.DPIndexXInd ||
|
|
AddrMode == AddressMode.DPInd ||
|
|
AddrMode == AddressMode.DPIndLong ||
|
|
AddrMode == AddressMode.DPIndIndexY ||
|
|
AddrMode == AddressMode.DPIndIndexYLong ||
|
|
// indirect JMP/JSR
|
|
AddrMode == AddressMode.AbsInd ||
|
|
AddrMode == AddressMode.AbsIndLong ||
|
|
AddrMode == AddressMode.AbsIndexXInd;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if this is an absolute-address instruction whose operand is combined with
|
|
/// the Program Bank Register.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// As noted in Eyes & Lichty, the Absolute addressing mode uses the Data Bank Register
|
|
/// if locating data, or the Program Bank Register if transferring control. When
|
|
/// we "LDA symbol" we can only care about the 16-bit value because we can't know what B
|
|
/// will hold at run time. When we "JMP symbol" we can either (1) complain if it's in
|
|
/// a different bank, (2) complain if a bank is specified at all, or (3) just not care.
|
|
/// All three approaches are in use.
|
|
///
|
|
/// This call is a way to know that the instruction is merged with the PBR rather than
|
|
/// the DBR.
|
|
/// </remarks>
|
|
public bool IsAbsolutePBR {
|
|
get {
|
|
// Too lazy to add new field. Set for:
|
|
// JSR abs
|
|
// JMP abs
|
|
// JMP (abs,X)
|
|
// JSR (abs,X)
|
|
return Opcode == 0x20 || Opcode == 0x4c || Opcode == 0x7c || Opcode == 0xfc;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the operand's width is uniquely determined by the opcode mnemonic, even
|
|
/// if the operation supports operands with varying widths.
|
|
///
|
|
/// Certain ops (ADC AND CMP EOR LDA ORA SBC STA) can be direct page, absolute, or
|
|
/// absolute long. "LDA 0" could mean LDA $00 (A5), LDA $0000 (AD), or LDA $000000 (AF).
|
|
/// Similar ambiguities exist for some indexed modes. Assemblers generally use the
|
|
/// smallest form, but allow a longer form to be selected by modifying the opcode
|
|
/// (e.g. LDA: and LDAL) or operand (e.g. LDA >0).
|
|
///
|
|
/// Most operations that access memory require disambiguation for direct page vs.
|
|
/// absolute. Generally speaking, if the operand's high byte is empty, disambiguation
|
|
/// is required.
|
|
///
|
|
/// The JMP/JML and JSR/JSL mnemonics are commonly used (and, in some assemblers,
|
|
/// required to be used) to avoid the ambiguity. For these instructions, we want
|
|
/// to avoid modifying the mnemonic, so we set this flag.
|
|
/// </summary>
|
|
private bool IsOperandWidthUnambiguous { get; set; }
|
|
|
|
/// <summary>
|
|
/// Flag update delegate, used for code flow analysis.
|
|
/// </summary>
|
|
/// <param name="flags">Current flags, to be modified by delegate. For conditional
|
|
/// branches, this value will be used when the branch is not taken.</param>
|
|
/// <param name="immVal">Immediate mode value, if any. Value may be 0-255
|
|
/// for an 8-bit operand, or 0-65535 for a 16-bit operand, or -1 if this is
|
|
/// not an immediate-mode instruction.</param>
|
|
/// <param name="branchTakenFlags">For conditional branches, this is the updated
|
|
/// value when the branch is taken.</param>
|
|
private delegate StatusFlags FlagUpdater(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags);
|
|
private FlagUpdater StatusFlagUpdater { get; set; }
|
|
|
|
/// <summary>
|
|
/// Nullary constructor. Most things are left at default values.
|
|
/// </summary>
|
|
public OpDef() {
|
|
StatusFlagUpdater = FlagUpdater_NoChange;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Copy constructor.
|
|
/// </summary>
|
|
/// <param name="src">Object to copy from</param>
|
|
public OpDef(OpDef src) {
|
|
this.Opcode = src.Opcode;
|
|
this.AddrMode = src.AddrMode;
|
|
this.IsUndocumented = src.IsUndocumented;
|
|
this.IsNumberedBitOp = src.IsNumberedBitOp;
|
|
this.Mnemonic = src.Mnemonic;
|
|
this.FlagsAffected = src.FlagsAffected;
|
|
this.Effect = src.Effect;
|
|
this.BaseMemEffect = src.BaseMemEffect;
|
|
this.CycDef = src.CycDef;
|
|
this.IsOperandWidthUnambiguous = src.IsOperandWidthUnambiguous;
|
|
this.StatusFlagUpdater = src.StatusFlagUpdater;
|
|
}
|
|
|
|
private static StatusFlags FlagsAffected_V =
|
|
new StatusFlags() { V = 1 };
|
|
private static StatusFlags FlagsAffected_D =
|
|
new StatusFlags() { D = 1 };
|
|
private static StatusFlags FlagsAffected_I =
|
|
new StatusFlags() { I = 1 };
|
|
private static StatusFlags FlagsAffected_Z =
|
|
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 =
|
|
new StatusFlags() { N = 1, V = 1, Z = 1, C = 1 };
|
|
private static StatusFlags FlagsAffected_All =
|
|
new StatusFlags() { N = 1, V = 1, M = 1, X = 1, D = 1, I = 1, Z = 1, C = 1 };
|
|
|
|
|
|
/// <summary>
|
|
/// True if this operation is any type of branch instruction (conditional branch,
|
|
/// unconditional branch/jump, subroutine call).
|
|
/// </summary>
|
|
public bool IsBranchOrSubCall {
|
|
get {
|
|
return Effect == FlowEffect.Branch ||
|
|
Effect == FlowEffect.ConditionalBranch ||
|
|
Effect == FlowEffect.CallSubroutine;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if this operation is a subroutine call.
|
|
/// </summary>
|
|
public bool IsSubroutineCall {
|
|
get {
|
|
return Effect == FlowEffect.CallSubroutine;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the operand is an immediate value, which should be prefixed with '#'.
|
|
/// </summary>
|
|
public bool IsImmediate {
|
|
get {
|
|
return AddrMode == AddressMode.Imm ||
|
|
AddrMode == AddressMode.ImmLongA ||
|
|
AddrMode == AddressMode.ImmLongXY;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the operand is an "extended immediate" value, which includes PEA and MVN/MVP
|
|
/// in addition to Imm/ImmLongA/ImmLongXY.
|
|
/// </summary>
|
|
public bool IsExtendedImmediate {
|
|
get {
|
|
return IsImmediate || AddrMode == AddressMode.StackAbs ||
|
|
AddrMode == AddressMode.BlockMove;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the operand's width could be ambiguous. Generally speaking, assemblers
|
|
/// will use the shortest form possible, so disambiguation is about using a longer
|
|
/// form than may appear to be required.
|
|
/// </summary>
|
|
public bool IsWidthPotentiallyAmbiguous {
|
|
get {
|
|
if (IsOperandWidthUnambiguous) {
|
|
// JMP has Abs and AbsLong forms, but those are universally distinguished
|
|
// with unique mnemonics (JMP vs. JML). We don't want to generate "JMPL"
|
|
// or "JMP >long". Ditto for JSR/JSL.
|
|
return false;
|
|
}
|
|
switch (AddrMode) {
|
|
case AddressMode.Abs: // LDA $0000 vs LDA $00
|
|
case AddressMode.AbsLong: // LDA $000000 vs LDA $0000/LDA $00
|
|
case AddressMode.AbsIndexX: // LDA $0000,X vs LDA $00,X
|
|
case AddressMode.AbsIndexXLong: // LDA $000000,X vs LDA $0000,X/LDA $00,X
|
|
return true;
|
|
case AddressMode.AbsIndexY: // LDX $0000,Y vs LDX $00,Y
|
|
// AbsIndexY is widely used, but DPIndexY is only available for LDX/STX,
|
|
// and STX doesn't have AbsIndexY. So this is only ambiguous for LDX.
|
|
// We want to compare by opcode instance, rather than the byte code
|
|
// numeric value, to manage different instruction sets.
|
|
// (This also applies to the undocumented LAX instruction.)
|
|
if (this == OpLDX_AbsIndexY || this == OpLAX_AbsIndexY) {
|
|
return true;
|
|
}
|
|
return false;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a value that indicates what sort of disambiguation is required. Only call
|
|
/// this if IsWidthPotentiallyAmbiguous is true.
|
|
/// </summary>
|
|
/// <param name="instrWidth">Instruction width, including opcode.</param>
|
|
/// <param name="operandValue">Operand value, extracted from byte stream.</param>
|
|
/// <returns>Width disambiguation value.</returns>
|
|
public static WidthDisambiguation GetWidthDisambiguation(int instrWidth,
|
|
int operandValue) {
|
|
Debug.Assert(instrWidth > 2 && instrWidth <= 4); // zero-page ops are not ambiguous
|
|
if (instrWidth == 3 && operandValue < 0x100) {
|
|
return WidthDisambiguation.ForceAbs;
|
|
} else if (instrWidth == 4) {
|
|
if (operandValue < 0x10000) {
|
|
return WidthDisambiguation.ForceLong;
|
|
} else {
|
|
// The width disambiguator may be helpful for humans when reading labels
|
|
// whose value is not immediately apparent. "LDA a:FOO" vs. "LDA f:FOO"
|
|
// could be nice.
|
|
return WidthDisambiguation.ForceLongMaybe;
|
|
}
|
|
} else {
|
|
return WidthDisambiguation.None;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the full length of the instruction. Some 65816 operations use
|
|
/// a different number of bytes in 16-bit mode, so we need to know what the
|
|
/// M/X status flags are.
|
|
/// </summary>
|
|
/// <param name="flags">Current status flags.</param>
|
|
/// <returns>Length, in bytes.</returns>
|
|
public int GetLength(StatusFlags flags) {
|
|
switch (AddrMode) {
|
|
case AddressMode.Unknown:
|
|
case AddressMode.Acc:
|
|
case AddressMode.Implied:
|
|
case AddressMode.StackPull:
|
|
case AddressMode.StackPush:
|
|
case AddressMode.StackRTI:
|
|
case AddressMode.StackRTL:
|
|
case AddressMode.StackRTS:
|
|
return 1;
|
|
case AddressMode.DP:
|
|
case AddressMode.DPIndexX:
|
|
case AddressMode.DPIndexY:
|
|
case AddressMode.DPIndexXInd:
|
|
case AddressMode.DPInd:
|
|
case AddressMode.DPIndLong:
|
|
case AddressMode.DPIndIndexY:
|
|
case AddressMode.DPIndIndexYLong:
|
|
case AddressMode.Imm:
|
|
case AddressMode.PCRel:
|
|
case AddressMode.StackDPInd:
|
|
case AddressMode.StackInt:
|
|
case AddressMode.StackRel:
|
|
case AddressMode.StackRelIndIndexY:
|
|
case AddressMode.WDM:
|
|
return 2;
|
|
case AddressMode.Abs:
|
|
case AddressMode.AbsIndexX:
|
|
case AddressMode.AbsIndexY:
|
|
case AddressMode.AbsIndexXInd:
|
|
case AddressMode.AbsInd:
|
|
case AddressMode.AbsIndLong:
|
|
case AddressMode.BlockMove:
|
|
case AddressMode.DPPCRel:
|
|
case AddressMode.PCRelLong:
|
|
case AddressMode.StackAbs:
|
|
case AddressMode.StackPCRelLong:
|
|
return 3;
|
|
|
|
case AddressMode.AbsLong:
|
|
case AddressMode.AbsIndexXLong:
|
|
return 4;
|
|
|
|
case AddressMode.ImmLongA:
|
|
bool shortM = flags.IsShortM;
|
|
return shortM ? 2 : 3;
|
|
case AddressMode.ImmLongXY:
|
|
bool shortX = flags.IsShortX;
|
|
return shortX ? 2 : 3;
|
|
|
|
default:
|
|
Debug.Assert(false, "Unknown address mode " + AddrMode);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Return value from branch evaluation functions.
|
|
/// </summary>
|
|
public enum BranchTaken { Indeterminate = 0, Never, Always };
|
|
|
|
/// <summary>
|
|
/// Determines whether a branch is always taken, never taken, or is indeterminate
|
|
/// (i.e. it's taken some of the time but not taken others).
|
|
/// </summary>
|
|
/// <param name="flagVal">Processor status flag value.</param>
|
|
/// <param name="branchVal">Bit value corresponding to branch-taken.</param>
|
|
/// <returns>Branch taken indication.</returns>
|
|
private static BranchTaken FlagToBT(int flagVal, int branchVal) {
|
|
if (flagVal == TriState16.INDETERMINATE) {
|
|
return BranchTaken.Indeterminate;
|
|
} else if (flagVal == TriState16.UNSPECIFIED) {
|
|
// should never happen
|
|
Debug.Assert(false);
|
|
return BranchTaken.Indeterminate;
|
|
} else if (flagVal == branchVal) {
|
|
return BranchTaken.Always;
|
|
} else {
|
|
return BranchTaken.Never;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines if a conditional branch is always taken, based on the status flags. Only
|
|
/// call here for branch instructions.
|
|
/// </summary>
|
|
/// <param name="op">Conditional branch instruction.</param>
|
|
/// <param name="flags">Processor status flags.</param>
|
|
/// <returns>Whether the branch is sometimes, always, or never taken.</returns>
|
|
public static BranchTaken IsBranchTaken(OpDef op, StatusFlags flags) {
|
|
// Could add a delegate to every OpDef, but that seems silly.
|
|
switch (op.Opcode) {
|
|
case 0x10: // BPL
|
|
return FlagToBT(flags.N, 0);
|
|
case 0x30: // BMI
|
|
return FlagToBT(flags.N, 1);
|
|
case 0x50: // BVC
|
|
return FlagToBT(flags.V, 0);
|
|
case 0x70: // BVS
|
|
return FlagToBT(flags.V, 1);
|
|
case 0x90: // BCC
|
|
return FlagToBT(flags.C, 0);
|
|
case 0xb0: // BCS
|
|
return FlagToBT(flags.C, 1);
|
|
case 0xd0: // BNE
|
|
return FlagToBT(flags.Z, 0);
|
|
case 0xf0: // BEQ
|
|
return FlagToBT(flags.Z, 1);
|
|
default:
|
|
if ((op.Opcode & 0x0f) == 0x0f) {
|
|
// assume W65C02 BBR/BBS
|
|
return BranchTaken.Indeterminate;
|
|
}
|
|
// Not a conditional branch.
|
|
throw new Exception("Not a conditional branch");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the raw operand value.
|
|
/// </summary>
|
|
/// <param name="data">65xx code.</param>
|
|
/// <param name="offset">Offset of opcode.</param>
|
|
/// <param name="flags">Current status flags (need M/X).</param>
|
|
/// <returns>Operand value, or -1 if the instruction doesn't have an operand.</returns>
|
|
public int GetOperand(byte[] data, int offset, StatusFlags flags) {
|
|
switch (GetLength(flags)) {
|
|
case 1:
|
|
return -1;
|
|
case 2:
|
|
return data[offset + 1];
|
|
case 3:
|
|
return (data[offset + 2] << 8) | data[offset + 1];
|
|
case 4:
|
|
return (data[offset + 3] << 16) | (data[offset + 2] << 8) | data[offset + 1];
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes the changes the instruction will have on the status flags.
|
|
/// </summary>
|
|
/// <param name="curFlags">Current status flags. This is used as the initial value
|
|
/// for the return values, and determines whether 65816 immediate operands are
|
|
/// treated as 8- or 16-bit.</param>
|
|
/// <param name="data">65xx data stream.</param>
|
|
/// <param name="offset">Offset of opcode.</param>
|
|
/// <param name="newFlags">Effect this instruction has on flags.</param>
|
|
/// <param name="condBranchTakenFlags">Effect this conditional branch instruction
|
|
/// has on flags when the branch is taken. If this is not a conditional branch,
|
|
/// the value can be ignored.</param>
|
|
public void ComputeFlagChanges(StatusFlags curFlags, byte[] data, int offset,
|
|
out StatusFlags newFlags, out StatusFlags condBranchTakenFlags) {
|
|
int immVal = -1;
|
|
|
|
switch (AddrMode) {
|
|
case AddressMode.Imm:
|
|
case AddressMode.ImmLongA:
|
|
case AddressMode.ImmLongXY:
|
|
if (GetLength(curFlags) == 2) {
|
|
// 8-bit operand
|
|
immVal = data[offset + 1];
|
|
} else {
|
|
// 16-bit operand; make as such by negating it
|
|
// (if it's zero, 8 vs. 16 doesn't matter)
|
|
immVal = -((data[offset + 2]) << 16 | data[offset + 1]);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
condBranchTakenFlags = curFlags;
|
|
// Invoke the flag update delegate.
|
|
newFlags = StatusFlagUpdater(curFlags, immVal, ref condBranchTakenFlags);
|
|
|
|
// TODO(maybe): there are some constraints we can impose: if Z=1 then
|
|
// N=0, and if N=1 then Z=0. I'm not sure this is actually useful though.
|
|
}
|
|
|
|
private static StatusFlags FlagUpdater_NoChange(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
return flags;
|
|
}
|
|
private static StatusFlags FlagUpdater_Subroutine(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
// The correct way to do this is to merge the flags from all code
|
|
// that RTS/RTLs back to here, but that's generally hard to do, especially
|
|
// since this will often be used to call into external code. The easiest
|
|
// thing to do is scramble CZVN and leave IDXM alone.
|
|
//
|
|
// We also use this for BRK, because it either halts execution, in which
|
|
// case the flags don't matter, or it's performing some sort of special action
|
|
// (e.g. Apple /// SOS call) and the flags are altered.
|
|
return FlagUpdater_NVZC(flags, immVal, ref condBranchTakenFlags);
|
|
}
|
|
private static StatusFlags FlagUpdater_Z(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
flags.Z = TriState16.INDETERMINATE;
|
|
return flags;
|
|
}
|
|
private static StatusFlags FlagUpdater_C(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
flags.C = TriState16.INDETERMINATE;
|
|
return flags;
|
|
}
|
|
private static StatusFlags FlagUpdater_NZ(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
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;
|
|
return flags;
|
|
}
|
|
private static StatusFlags FlagUpdater_NVZC(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
flags.C = flags.Z = flags.V = flags.N = TriState16.INDETERMINATE;
|
|
return flags;
|
|
}
|
|
private static StatusFlags FlagUpdater_LoadImm(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
// We can set the N/Z flags based on the value loaded.
|
|
flags.Z = (immVal != 0) ? 0 : 1;
|
|
if (immVal >= 0) {
|
|
// 8-bit operand
|
|
flags.N = (immVal >> 7) & 0x01;
|
|
} else {
|
|
// 16-bit operand
|
|
immVal = -immVal;
|
|
flags.N = (immVal >> 15) & 0x01;
|
|
}
|
|
return flags;
|
|
}
|
|
private static StatusFlags FlagUpdater_ANDImm(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
// If we LDA #$81, LDX #$00, AND #$01, Z flag is clear (for us, Z=unknown).
|
|
// AND #00 --> Z=1, else Z=unknown
|
|
// AND #7f --> N=0, else N=unknown
|
|
if (immVal == 0) {
|
|
flags.Z = 1; // acc is now zero
|
|
} else {
|
|
flags.Z = TriState16.INDETERMINATE; // may or may not be zero
|
|
}
|
|
bool hiBitClear;
|
|
if (immVal >= 0) {
|
|
// 8-bit operand
|
|
hiBitClear = ((immVal >> 7) & 0x01) == 0;
|
|
} else {
|
|
// 16-bit operand
|
|
immVal = -immVal;
|
|
hiBitClear = ((immVal >> 15) & 0x01) == 0;
|
|
}
|
|
if (hiBitClear) {
|
|
flags.N = 0;
|
|
} else {
|
|
flags.N = TriState16.INDETERMINATE;
|
|
}
|
|
return flags;
|
|
}
|
|
private static StatusFlags FlagUpdater_ORAImm(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
// If we LDA #$80, LDX #$00, ORA #$00, the N flag will be set (for us, N=unknown).
|
|
// ORA #00 --> Z=unknown, else Z=0
|
|
// ORA #80 --> N=1, else N=unknown
|
|
if (immVal != 0) {
|
|
flags.Z = 0; // acc is now nonzero
|
|
} else {
|
|
flags.Z = TriState16.INDETERMINATE; // may or may not be zero
|
|
}
|
|
bool hiBitSet;
|
|
if (immVal >= 0) {
|
|
// 8-bit operand
|
|
hiBitSet = ((immVal >> 7) & 0x01) != 0;
|
|
} else {
|
|
// 16-bit operand
|
|
immVal = -immVal;
|
|
hiBitSet = ((immVal >> 15) & 0x01) != 0;
|
|
}
|
|
if (hiBitSet) {
|
|
flags.N = 1;
|
|
} else {
|
|
flags.N = TriState16.INDETERMINATE;
|
|
}
|
|
return flags;
|
|
}
|
|
private static StatusFlags FlagUpdater_LSR(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
flags.C = flags.Z = TriState16.INDETERMINATE;
|
|
flags.N = 0; // always shifts 0 into high bit
|
|
return flags;
|
|
}
|
|
private static StatusFlags FlagUpdater_ROL(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
// this rotates the N flag into C, so set C=N
|
|
// if carry is one, set Z=0; otherwise set Z/N=indeterminate
|
|
// (if Z=1 we should set Z=C, but this seems rare and I don't entirely trust Z)
|
|
if (flags.C == 1) {
|
|
flags.C = flags.N;
|
|
flags.Z = 0;
|
|
flags.N = TriState16.INDETERMINATE;
|
|
} else {
|
|
flags.C = flags.N;
|
|
flags.Z = flags.N = TriState16.INDETERMINATE;
|
|
}
|
|
return flags;
|
|
}
|
|
private static StatusFlags FlagUpdater_ROR(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
// if carry is set, set Z=0 and N=1;
|
|
// if carry is clear, set N=0;
|
|
// if carry is clear and Z=1, everything is zero and no flags change
|
|
// (this seems unlikely, so I'm going to assume we've mis-read a flag and ignore this)
|
|
// otherwise, Z/N/C=indeterminate
|
|
if (flags.C == 1) {
|
|
flags.Z = 0;
|
|
flags.N = 1;
|
|
flags.C = TriState16.INDETERMINATE;
|
|
} else if (flags.C == 0) {
|
|
flags.N = 0;
|
|
flags.Z = flags.C = TriState16.INDETERMINATE;
|
|
} else {
|
|
flags.C = flags.Z = flags.N = TriState16.INDETERMINATE;
|
|
}
|
|
return flags;
|
|
}
|
|
private static StatusFlags FlagUpdater_PLP(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
// All flags are unknown. The caller may be able to match with a previous
|
|
// PHP to get something less fuzzy.
|
|
flags.C = flags.Z = flags.I = flags.D = flags.X = flags.M = flags.V = flags.N =
|
|
TriState16.INDETERMINATE;
|
|
return flags;
|
|
}
|
|
private static StatusFlags FlagUpdater_REP(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.C)) != 0) {
|
|
flags.C = 0;
|
|
}
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.Z)) != 0) {
|
|
flags.Z = 0;
|
|
}
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.I)) != 0) {
|
|
flags.I = 0;
|
|
}
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.D)) != 0) {
|
|
flags.D = 0;
|
|
}
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.X)) != 0) {
|
|
flags.X = 0;
|
|
}
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.M)) != 0) {
|
|
flags.M = 0;
|
|
}
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.V)) != 0) {
|
|
flags.V = 0;
|
|
}
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.N)) != 0) {
|
|
flags.N = 0;
|
|
}
|
|
return flags;
|
|
}
|
|
private static StatusFlags FlagUpdater_SEP(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.C)) != 0) {
|
|
flags.C = 1;
|
|
}
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.Z)) != 0) {
|
|
flags.Z = 1;
|
|
}
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.I)) != 0) {
|
|
flags.I = 1;
|
|
}
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.D)) != 0) {
|
|
flags.D = 1;
|
|
}
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.X)) != 0) {
|
|
flags.X = 1;
|
|
}
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.M)) != 0) {
|
|
flags.M = 1;
|
|
}
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.V)) != 0) {
|
|
flags.V = 1;
|
|
}
|
|
if ((immVal & (1 << (int)StatusFlags.FlagBits.N)) != 0) {
|
|
flags.N = 1;
|
|
}
|
|
return flags;
|
|
}
|
|
private static StatusFlags FlagUpdater_XCE(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
// We want the 'E' flag to always have a definite value. If we don't know
|
|
// what's in the carry flag, guess it's a return to emulation.
|
|
StatusFlags newFlags = flags;
|
|
if (flags.C == 0) {
|
|
// transition to native
|
|
newFlags.E = 0;
|
|
newFlags.X = newFlags.M = 1;
|
|
} else /*C==1 or C==?*/ {
|
|
// transition to emulation
|
|
// The registers will be treated as short by the CPU, ignoring M/X, but
|
|
// the assembler won't generally know that. Set the flags to definite
|
|
// values here so we generate the necessary directives.
|
|
newFlags.E = 1;
|
|
newFlags.X = newFlags.M = 1;
|
|
}
|
|
newFlags.C = flags.E;
|
|
return newFlags;
|
|
}
|
|
|
|
|
|
// ======================================================================================
|
|
// Base operation definitions, one per op.
|
|
//
|
|
|
|
private static OpDef OpUnknown = new OpDef() {
|
|
Mnemonic = OpName.Unknown,
|
|
Effect = FlowEffect.Cont
|
|
};
|
|
private static OpDef OpADC = new OpDef() {
|
|
Mnemonic = OpName.ADC,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Read,
|
|
FlagsAffected = FlagsAffected_NVZC,
|
|
StatusFlagUpdater = FlagUpdater_NVZC
|
|
// We can assert C=0 after ADC #$00, but only if C=0 on entry. Doesn't seem useful.
|
|
};
|
|
private static OpDef OpAND = new OpDef() {
|
|
Mnemonic = OpName.AND,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Read,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ // special handling for imm
|
|
};
|
|
private static OpDef OpASL = new OpDef() {
|
|
Mnemonic = OpName.ASL,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite,
|
|
FlagsAffected = FlagsAffected_NZC,
|
|
StatusFlagUpdater = FlagUpdater_NZC
|
|
};
|
|
private static OpDef OpBCC = new OpDef() {
|
|
Mnemonic = OpName.BCC,
|
|
Effect = FlowEffect.ConditionalBranch,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
StatusFlagUpdater = delegate(StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
condBranchTakenFlags.C = 0;
|
|
flags.C = 1;
|
|
return flags;
|
|
}
|
|
};
|
|
private static OpDef OpBCS = new OpDef() {
|
|
Mnemonic = OpName.BCS,
|
|
Effect = FlowEffect.ConditionalBranch,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
condBranchTakenFlags.C = 1;
|
|
flags.C = 0;
|
|
return flags;
|
|
}
|
|
};
|
|
private static OpDef OpBEQ = new OpDef() {
|
|
Mnemonic = OpName.BEQ,
|
|
Effect = FlowEffect.ConditionalBranch,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
condBranchTakenFlags.Z = 1;
|
|
flags.Z = 0;
|
|
return flags;
|
|
}
|
|
};
|
|
private static OpDef OpBIT = new OpDef() {
|
|
Mnemonic = OpName.BIT,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NVZ, // special handling for imm
|
|
StatusFlagUpdater = FlagUpdater_NVZ // special handling for imm
|
|
};
|
|
private static OpDef OpBMI = new OpDef() {
|
|
Mnemonic = OpName.BMI,
|
|
Effect = FlowEffect.ConditionalBranch,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
// It's potentially useful to update Z here and in BPL. For example, if the
|
|
// branch succeeds, it's likely that whatever set N=1 also set Z=0. However,
|
|
// you can set Z independently with TRB/TSB and BIT #imm (and of course PHA/PLP).
|
|
// These things are rare, but its best to stick with what we know must be true.
|
|
condBranchTakenFlags.N = 1;
|
|
flags.N = 0;
|
|
return flags;
|
|
}
|
|
};
|
|
private static OpDef OpBNE = new OpDef() {
|
|
Mnemonic = OpName.BNE,
|
|
Effect = FlowEffect.ConditionalBranch,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
condBranchTakenFlags.Z = 0;
|
|
flags.Z = 1;
|
|
return flags;
|
|
}
|
|
};
|
|
private static OpDef OpBPL = new OpDef() {
|
|
Mnemonic = OpName.BPL,
|
|
Effect = FlowEffect.ConditionalBranch,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
condBranchTakenFlags.N = 0;
|
|
flags.N = 1;
|
|
return flags;
|
|
}
|
|
};
|
|
private static OpDef OpBRA = new OpDef() {
|
|
Mnemonic = OpName.BRA,
|
|
Effect = FlowEffect.Branch,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpBRK = new OpDef() {
|
|
Mnemonic = OpName.BRK,
|
|
Effect = FlowEffect.NoCont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
// On 6502 this doesn't clear the 'D' flag. Easier to explain that in text than
|
|
// create a separate definition.
|
|
//
|
|
// The processor status flags have the 'B' flag set on 6502/65C02/65816 emu mode
|
|
// when pushed onto the stack, but it doesn't affect the actual processor status
|
|
// flag in the code executed next.
|
|
FlagsAffected = FlagsAffected_DI,
|
|
// We don't try to track execution into the software break routine, but we do
|
|
// handle operating system calls that return with the flags altered. So if BRK
|
|
// does continue, we want to mark NVZC as indeterminate, just like we would for
|
|
// a general subroutine call.
|
|
StatusFlagUpdater = FlagUpdater_Subroutine
|
|
};
|
|
private static OpDef OpBRL = new OpDef() {
|
|
Mnemonic = OpName.BRL,
|
|
Effect = FlowEffect.Branch,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpBVC = new OpDef() {
|
|
Mnemonic = OpName.BVC,
|
|
Effect = FlowEffect.ConditionalBranch,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
condBranchTakenFlags.V = 0;
|
|
flags.V = 1;
|
|
return flags;
|
|
}
|
|
};
|
|
private static OpDef OpBVS = new OpDef() {
|
|
Mnemonic = OpName.BVS,
|
|
Effect = FlowEffect.ConditionalBranch,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
condBranchTakenFlags.V = 1;
|
|
flags.V = 0;
|
|
return flags;
|
|
}
|
|
};
|
|
private static OpDef OpCLC = new OpDef() {
|
|
Mnemonic = OpName.CLC,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_C,
|
|
StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
flags.C = 0;
|
|
return flags;
|
|
}
|
|
};
|
|
private static OpDef OpCLD = new OpDef() {
|
|
Mnemonic = OpName.CLD,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_D,
|
|
StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
flags.D = 0;
|
|
return flags;
|
|
}
|
|
};
|
|
private static OpDef OpCLI = new OpDef() {
|
|
Mnemonic = OpName.CLI,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_I,
|
|
StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
flags.I = 0;
|
|
return flags;
|
|
}
|
|
};
|
|
private static OpDef OpCLV = new OpDef() {
|
|
Mnemonic = OpName.CLV,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_V,
|
|
StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
flags.V = 0;
|
|
return flags;
|
|
}
|
|
};
|
|
private static OpDef OpCMP = new OpDef() {
|
|
Mnemonic = OpName.CMP,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Read,
|
|
FlagsAffected = FlagsAffected_NZC,
|
|
StatusFlagUpdater = FlagUpdater_NZC
|
|
};
|
|
private static OpDef OpCOP = new OpDef() {
|
|
Mnemonic = OpName.COP,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_DI
|
|
};
|
|
private static OpDef OpCPX = new OpDef() {
|
|
Mnemonic = OpName.CPX,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Read,
|
|
FlagsAffected = FlagsAffected_NZC,
|
|
StatusFlagUpdater = FlagUpdater_NZC
|
|
};
|
|
private static OpDef OpCPY = new OpDef() {
|
|
Mnemonic = OpName.CPY,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Read,
|
|
FlagsAffected = FlagsAffected_NZC,
|
|
StatusFlagUpdater = FlagUpdater_NZC
|
|
};
|
|
private static OpDef OpDEC = new OpDef() {
|
|
Mnemonic = OpName.DEC,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpDEX = new OpDef() {
|
|
Mnemonic = OpName.DEX,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpDEY = new OpDef() {
|
|
Mnemonic = OpName.DEY,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpEOR = new OpDef() {
|
|
Mnemonic = OpName.EOR,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Read,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpINC = new OpDef() {
|
|
Mnemonic = OpName.INC,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpINX = new OpDef() {
|
|
Mnemonic = OpName.INX,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpINY = new OpDef() {
|
|
Mnemonic = OpName.INY,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpJML = new OpDef() {
|
|
Mnemonic = OpName.JML, // technically JMP with long operand, but JML is convention
|
|
Effect = FlowEffect.Branch,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
IsOperandWidthUnambiguous = true,
|
|
};
|
|
private static OpDef OpJMP = new OpDef() {
|
|
Mnemonic = OpName.JMP,
|
|
Effect = FlowEffect.Branch,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
IsOperandWidthUnambiguous = true
|
|
};
|
|
private static OpDef OpJSL = new OpDef() {
|
|
Mnemonic = OpName.JSL, // technically JSR with long operand, but JSL is convention
|
|
Effect = FlowEffect.CallSubroutine,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
IsOperandWidthUnambiguous = true,
|
|
StatusFlagUpdater = FlagUpdater_Subroutine
|
|
};
|
|
private static OpDef OpJSR = new OpDef() {
|
|
Mnemonic = OpName.JSR,
|
|
Effect = FlowEffect.CallSubroutine,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
IsOperandWidthUnambiguous = true,
|
|
StatusFlagUpdater = FlagUpdater_Subroutine
|
|
};
|
|
private static OpDef OpLDA = new OpDef() {
|
|
Mnemonic = OpName.LDA,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Read,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ // special handling for imm
|
|
};
|
|
private static OpDef OpLDX = new OpDef() {
|
|
Mnemonic = OpName.LDX,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Read,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ // special handling for imm
|
|
};
|
|
private static OpDef OpLDY = new OpDef() {
|
|
Mnemonic = OpName.LDY,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Read,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ // special handling for imm
|
|
};
|
|
private static OpDef OpLSR = new OpDef() {
|
|
Mnemonic = OpName.LSR,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite,
|
|
FlagsAffected = FlagsAffected_NZC,
|
|
StatusFlagUpdater = FlagUpdater_LSR
|
|
};
|
|
private static OpDef OpMVN = new OpDef() {
|
|
Mnemonic = OpName.MVN,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None // not quite right, but what is?
|
|
};
|
|
private static OpDef OpMVP = new OpDef() {
|
|
Mnemonic = OpName.MVP,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpNOP = new OpDef() {
|
|
Mnemonic = OpName.NOP,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpORA = new OpDef() {
|
|
Mnemonic = OpName.ORA,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Read,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ // special handling for imm
|
|
};
|
|
private static OpDef OpPEA = new OpDef() {
|
|
Mnemonic = OpName.PEA,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpPEI = new OpDef() {
|
|
Mnemonic = OpName.PEI,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Read
|
|
};
|
|
private static OpDef OpPER = new OpDef() {
|
|
Mnemonic = OpName.PER,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpPHA = new OpDef() {
|
|
Mnemonic = OpName.PHA,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpPHB = new OpDef() {
|
|
Mnemonic = OpName.PHB,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpPHD = new OpDef() {
|
|
Mnemonic = OpName.PHD,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpPHK = new OpDef() {
|
|
Mnemonic = OpName.PHK,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpPHP = new OpDef() {
|
|
Mnemonic = OpName.PHP,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpPHX = new OpDef() {
|
|
Mnemonic = OpName.PHX,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpPHY = new OpDef() {
|
|
Mnemonic = OpName.PHY,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpPLA = new OpDef() {
|
|
Mnemonic = OpName.PLA,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpPLB = new OpDef() {
|
|
Mnemonic = OpName.PLB,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpPLD = new OpDef() {
|
|
Mnemonic = OpName.PLD,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpPLP = new OpDef() {
|
|
Mnemonic = OpName.PLP,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_All,
|
|
StatusFlagUpdater = FlagUpdater_PLP
|
|
};
|
|
private static OpDef OpPLX = new OpDef() {
|
|
Mnemonic = OpName.PLX,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpPLY = new OpDef() {
|
|
Mnemonic = OpName.PLY,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpREP = new OpDef() {
|
|
Mnemonic = OpName.REP,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_All,
|
|
StatusFlagUpdater = FlagUpdater_REP
|
|
};
|
|
private static OpDef OpROL = new OpDef() {
|
|
Mnemonic = OpName.ROL,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite,
|
|
FlagsAffected = FlagsAffected_NZC,
|
|
StatusFlagUpdater = FlagUpdater_ROL
|
|
};
|
|
private static OpDef OpROR = new OpDef() {
|
|
Mnemonic = OpName.ROR,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite,
|
|
FlagsAffected = FlagsAffected_NZC,
|
|
StatusFlagUpdater = FlagUpdater_ROR
|
|
};
|
|
private static OpDef OpRTI = new OpDef() {
|
|
Mnemonic = OpName.RTI,
|
|
Effect = FlowEffect.NoCont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_All
|
|
};
|
|
private static OpDef OpRTL = new OpDef() {
|
|
Mnemonic = OpName.RTL,
|
|
Effect = FlowEffect.NoCont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
};
|
|
private static OpDef OpRTS = new OpDef() {
|
|
Mnemonic = OpName.RTS,
|
|
Effect = FlowEffect.NoCont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
};
|
|
private static OpDef OpSBC = new OpDef() {
|
|
Mnemonic = OpName.SBC,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Read,
|
|
FlagsAffected = FlagsAffected_NVZC,
|
|
StatusFlagUpdater = FlagUpdater_NVZC
|
|
};
|
|
private static OpDef OpSEC = new OpDef() {
|
|
Mnemonic = OpName.SEC,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_C,
|
|
StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
flags.C = 1;
|
|
return flags;
|
|
}
|
|
};
|
|
private static OpDef OpSED = new OpDef() {
|
|
Mnemonic = OpName.SED,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_D,
|
|
StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
flags.D = 1;
|
|
return flags;
|
|
}
|
|
};
|
|
private static OpDef OpSEI = new OpDef() {
|
|
Mnemonic = OpName.SEI,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_I,
|
|
StatusFlagUpdater = delegate (StatusFlags flags, int immVal,
|
|
ref StatusFlags condBranchTakenFlags) {
|
|
flags.I = 1;
|
|
return flags;
|
|
}
|
|
};
|
|
private static OpDef OpSEP = new OpDef() {
|
|
Mnemonic = OpName.SEP,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_All,
|
|
StatusFlagUpdater = FlagUpdater_SEP
|
|
};
|
|
private static OpDef OpSTA = new OpDef() {
|
|
Mnemonic = OpName.STA,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Write,
|
|
};
|
|
private static OpDef OpSTP = new OpDef() {
|
|
Mnemonic = OpName.STP,
|
|
Effect = FlowEffect.NoCont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
};
|
|
private static OpDef OpSTX = new OpDef() {
|
|
Mnemonic = OpName.STX,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Write,
|
|
};
|
|
private static OpDef OpSTY = new OpDef() {
|
|
Mnemonic = OpName.STY,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Write,
|
|
};
|
|
private static OpDef OpSTZ = new OpDef() {
|
|
Mnemonic = OpName.STZ,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Write,
|
|
};
|
|
private static OpDef OpTAX = new OpDef() {
|
|
Mnemonic = OpName.TAX,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpTAY = new OpDef() {
|
|
Mnemonic = OpName.TAY,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpTCD = new OpDef() {
|
|
Mnemonic = OpName.TCD,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpTCS = new OpDef() {
|
|
Mnemonic = OpName.TCS,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpTDC = new OpDef() {
|
|
Mnemonic = OpName.TDC,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpTRB = new OpDef() {
|
|
Mnemonic = OpName.TRB,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite,
|
|
FlagsAffected = FlagsAffected_Z,
|
|
StatusFlagUpdater = FlagUpdater_Z
|
|
};
|
|
private static OpDef OpTSB = new OpDef() {
|
|
Mnemonic = OpName.TSB,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite,
|
|
FlagsAffected = FlagsAffected_Z,
|
|
StatusFlagUpdater = FlagUpdater_Z
|
|
};
|
|
private static OpDef OpTSC = new OpDef() {
|
|
Mnemonic = OpName.TSC,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpTSX = new OpDef() {
|
|
Mnemonic = OpName.TSX,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpTXA = new OpDef() {
|
|
Mnemonic = OpName.TXA,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpTXS = new OpDef() {
|
|
Mnemonic = OpName.TXS,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpTXY = new OpDef() {
|
|
Mnemonic = OpName.TXY,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpTYA = new OpDef() {
|
|
Mnemonic = OpName.TYA,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpTYX = new OpDef() {
|
|
Mnemonic = OpName.TYX,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpWAI = new OpDef() {
|
|
Mnemonic = OpName.WAI,
|
|
Effect = FlowEffect.Cont, // when I=1 (interrupts disabled), continues on interrupt
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpWDM = new OpDef() {
|
|
Mnemonic = OpName.WDM,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpXBA = new OpDef() {
|
|
Mnemonic = OpName.XBA,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpXCE = new OpDef() {
|
|
Mnemonic = OpName.XCE,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_MXCE,
|
|
StatusFlagUpdater = FlagUpdater_XCE
|
|
};
|
|
|
|
|
|
#region 65816 Instructions
|
|
|
|
// ======================================================================================
|
|
// Operation + address mode definitions.
|
|
//
|
|
// It's possible for more than one definition to have the same opcode number. The
|
|
// 6502 only supports 8-bit LDA imm, while the 65816 version can be 8 or 16. There
|
|
// are minor differences in behavior for some opcodes on different CPUs.
|
|
//
|
|
// Significantly, the "invalid" 6502 ops overlap with official ops defined on later CPUs.
|
|
//
|
|
|
|
public static readonly OpDef OpInvalid = new OpDef(OpUnknown) {
|
|
AddrMode = AddressMode.Unknown
|
|
};
|
|
|
|
public static readonly OpDef OpBRK_Implied = new OpDef(OpBRK) { // 1-byte form
|
|
Opcode = 0x00,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 7 | (int)(CycleMod.OneIfE0)
|
|
};
|
|
public static readonly OpDef OpBRK_StackInt = new OpDef(OpBRK) { // 2-byte form
|
|
Opcode = 0x00,
|
|
AddrMode = AddressMode.StackInt,
|
|
CycDef = 7 | (int)(CycleMod.OneIfE0)
|
|
};
|
|
public static readonly OpDef OpORA_DPIndexXInd = new OpDef(OpORA) {
|
|
Opcode = 0x01,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpCOP_StackInt = new OpDef(OpCOP) {
|
|
Opcode = 0x02,
|
|
AddrMode = AddressMode.StackInt,
|
|
CycDef = 7 | (int)(CycleMod.OneIfE0)
|
|
};
|
|
public static readonly OpDef OpORA_StackRel = new OpDef(OpORA) {
|
|
Opcode = 0x03,
|
|
AddrMode = AddressMode.StackRel,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpTSB_DP = new OpDef(OpTSB) {
|
|
Opcode = 0x04,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5 | (int)(CycleMod.OneIfDpNonzero | CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpORA_DP = new OpDef(OpORA) {
|
|
Opcode = 0x05,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpASL_DP = new OpDef(OpASL) {
|
|
Opcode = 0x06,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5 | (int)(CycleMod.OneIfDpNonzero | CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpORA_DPIndLong = new OpDef(OpORA) {
|
|
Opcode = 0x07,
|
|
AddrMode = AddressMode.DPIndLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpPHP_StackPush = new OpDef(OpPHP) {
|
|
Opcode = 0x08,
|
|
AddrMode = AddressMode.StackPush,
|
|
CycDef = 3
|
|
};
|
|
public static readonly OpDef OpORA_ImmLongA = new OpDef(OpORA) {
|
|
Opcode = 0x09,
|
|
AddrMode = AddressMode.ImmLongA,
|
|
StatusFlagUpdater = FlagUpdater_ORAImm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpORA_Imm = new OpDef(OpORA) {
|
|
Opcode = 0x09,
|
|
AddrMode = AddressMode.Imm,
|
|
StatusFlagUpdater = FlagUpdater_ORAImm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpASL_Acc = new OpDef(OpASL) {
|
|
Opcode = 0x0a,
|
|
AddrMode = AddressMode.Acc,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpPHD_StackPush = new OpDef(OpPHD) {
|
|
Opcode = 0x0b,
|
|
AddrMode = AddressMode.StackPush,
|
|
CycDef = 4
|
|
};
|
|
public static readonly OpDef OpTSB_Abs = new OpDef(OpTSB) {
|
|
Opcode = 0x0c,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 6 | (int)(CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpORA_Abs = new OpDef(OpORA) {
|
|
Opcode = 0x0d,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpASL_Abs = new OpDef(OpASL) {
|
|
Opcode = 0x0e,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 6 | (int)(CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpORA_AbsLong = new OpDef(OpORA) {
|
|
Opcode = 0x0f,
|
|
AddrMode = AddressMode.AbsLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpBPL_PCRel = new OpDef(OpBPL) {
|
|
Opcode = 0x10,
|
|
AddrMode = AddressMode.PCRel,
|
|
CycDef = 2 | (int)(CycleMod.OneIfBranchTaken | CycleMod.OneIfBranchPage)
|
|
};
|
|
public static readonly OpDef OpORA_DPIndIndexY = new OpDef(OpORA) {
|
|
Opcode = 0x11,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpORA_DPInd = new OpDef(OpORA) {
|
|
Opcode = 0x12,
|
|
AddrMode = AddressMode.DPInd,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpORA_StackRelIndIndexY = new OpDef(OpORA) {
|
|
Opcode = 0x13,
|
|
AddrMode = AddressMode.StackRelIndIndexY,
|
|
CycDef = 7 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpTRB_DP = new OpDef(OpTRB) {
|
|
Opcode = 0x14,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5 | (int)(CycleMod.OneIfDpNonzero | CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpORA_DPIndexX = new OpDef(OpORA) {
|
|
Opcode = 0x15,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpASL_DPIndexX = new OpDef(OpASL) {
|
|
Opcode = 0x16,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 6 | (int)(CycleMod.OneIfDpNonzero | CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpORA_DPIndIndexYLong = new OpDef(OpORA) {
|
|
Opcode = 0x17,
|
|
AddrMode = AddressMode.DPIndIndexYLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpCLC_Implied = new OpDef(OpCLC) {
|
|
Opcode = 0x18,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpORA_AbsIndexY = new OpDef(OpORA) {
|
|
Opcode = 0x19,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpINC_Acc = new OpDef(OpINC) {
|
|
Opcode = 0x1a,
|
|
AddrMode = AddressMode.Acc,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpTCS_Implied = new OpDef(OpTCS) {
|
|
Opcode = 0x1b,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpTRB_Abs = new OpDef(OpTRB) {
|
|
Opcode = 0x1c,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 6 | (int)(CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpORA_AbsIndexX = new OpDef(OpORA) {
|
|
Opcode = 0x1d,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpASL_AbsIndexX = new OpDef(OpASL) {
|
|
Opcode = 0x1e,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 7 | (int)(CycleMod.TwoIfM0 | CycleMod.MinusOneIfNoPage)
|
|
};
|
|
public static readonly OpDef OpORA_AbsIndexXLong = new OpDef(OpORA) {
|
|
Opcode = 0x1f,
|
|
AddrMode = AddressMode.AbsIndexXLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpJSR_Abs = new OpDef(OpJSR) {
|
|
Opcode = 0x20,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpAND_DPIndexXInd = new OpDef(OpAND) {
|
|
Opcode = 0x21,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpJSR_AbsLong = new OpDef(OpJSL) {
|
|
Opcode = 0x22,
|
|
AddrMode = AddressMode.AbsLong,
|
|
CycDef = 8
|
|
};
|
|
public static readonly OpDef OpAND_StackRel = new OpDef(OpAND) {
|
|
Opcode = 0x23,
|
|
AddrMode = AddressMode.StackRel,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpBIT_DP = new OpDef(OpBIT) {
|
|
Opcode = 0x24,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpAND_DP = new OpDef(OpAND) {
|
|
Opcode = 0x25,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpROL_DP = new OpDef(OpROL) {
|
|
Opcode = 0x26,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5 | (int)(CycleMod.OneIfDpNonzero | CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpAND_DPIndLong = new OpDef(OpAND) {
|
|
Opcode = 0x27,
|
|
AddrMode = AddressMode.DPIndLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpPLP_StackPull = new OpDef(OpPLP) {
|
|
Opcode = 0x28,
|
|
AddrMode = AddressMode.StackPull,
|
|
CycDef = 4
|
|
};
|
|
public static readonly OpDef OpAND_ImmLongA = new OpDef(OpAND) {
|
|
Opcode = 0x29,
|
|
AddrMode = AddressMode.ImmLongA,
|
|
StatusFlagUpdater = FlagUpdater_ANDImm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpAND_Imm = new OpDef(OpAND) {
|
|
Opcode = 0x29,
|
|
AddrMode = AddressMode.Imm,
|
|
StatusFlagUpdater = FlagUpdater_ANDImm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpROL_Acc = new OpDef(OpROL) {
|
|
Opcode = 0x2a,
|
|
AddrMode = AddressMode.Acc,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpPLD_StackPull = new OpDef(OpPLD) {
|
|
Opcode = 0x2b,
|
|
AddrMode = AddressMode.StackPull,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBIT_Abs = new OpDef(OpBIT) {
|
|
Opcode = 0x2c,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpAND_Abs = new OpDef(OpAND) {
|
|
Opcode = 0x2d,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpROL_Abs = new OpDef(OpROL) {
|
|
Opcode = 0x2e,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 6 | (int)(CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpAND_AbsLong = new OpDef(OpAND) {
|
|
Opcode = 0x2f,
|
|
AddrMode = AddressMode.AbsLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpBMI_PCRel = new OpDef(OpBMI) {
|
|
Opcode = 0x30,
|
|
AddrMode = AddressMode.PCRel,
|
|
CycDef = 2 | (int)(CycleMod.OneIfBranchTaken | CycleMod.OneIfBranchPage)
|
|
};
|
|
public static readonly OpDef OpAND_DPIndIndexY = new OpDef(OpAND) {
|
|
Opcode = 0x31,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpAND_DPInd = new OpDef(OpAND) {
|
|
Opcode = 0x32,
|
|
AddrMode = AddressMode.DPInd,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpAND_StackRelIndIndexY = new OpDef(OpAND) {
|
|
Opcode = 0x33,
|
|
AddrMode = AddressMode.StackRelIndIndexY,
|
|
CycDef = 7 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpBIT_DPIndexX = new OpDef(OpBIT) {
|
|
Opcode = 0x34,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpAND_DPIndexX = new OpDef(OpAND) {
|
|
Opcode = 0x35,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpROL_DPIndexX = new OpDef(OpROL) {
|
|
Opcode = 0x36,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 6 | (int)(CycleMod.OneIfDpNonzero | CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpAND_DPIndIndexYLong = new OpDef(OpAND) {
|
|
Opcode = 0x37,
|
|
AddrMode = AddressMode.DPIndIndexYLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpSEC_Implied = new OpDef(OpSEC) {
|
|
Opcode = 0x38,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpAND_AbsIndexY = new OpDef(OpAND) {
|
|
Opcode = 0x39,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpDEC_Acc = new OpDef(OpDEC) {
|
|
Opcode = 0x3a,
|
|
AddrMode = AddressMode.Acc,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpTSC_Implied = new OpDef(OpTSC) {
|
|
Opcode = 0x3b,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpBIT_AbsIndexX = new OpDef(OpBIT) {
|
|
Opcode = 0x3c,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpAND_AbsIndexX = new OpDef(OpAND) {
|
|
Opcode = 0x3d,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpROL_AbsIndexX = new OpDef(OpROL) {
|
|
Opcode = 0x3e,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 7 | (int)(CycleMod.TwoIfM0 | CycleMod.MinusOneIfNoPage)
|
|
};
|
|
public static readonly OpDef OpAND_AbsIndexXLong = new OpDef(OpAND) {
|
|
Opcode = 0x3f,
|
|
AddrMode = AddressMode.AbsIndexXLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpRTI_StackRTI = new OpDef(OpRTI) {
|
|
Opcode = 0x40,
|
|
AddrMode = AddressMode.StackRTI,
|
|
CycDef = 6 | (int)(CycleMod.OneIfE0)
|
|
};
|
|
public static readonly OpDef OpEOR_DPIndexXInd = new OpDef(OpEOR) {
|
|
Opcode = 0x41,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpWDM_WDM = new OpDef(OpWDM) {
|
|
Opcode = 0x42,
|
|
AddrMode = AddressMode.WDM,
|
|
CycDef = 2 // arbitrary; actual time is undefined
|
|
};
|
|
public static readonly OpDef OpEOR_StackRel = new OpDef(OpEOR) {
|
|
Opcode = 0x43,
|
|
AddrMode = AddressMode.StackRel,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpMVP_BlockMove = new OpDef(OpMVP) {
|
|
Opcode = 0x44,
|
|
AddrMode = AddressMode.BlockMove,
|
|
CycDef = 7 | (int)(CycleMod.BlockMove)
|
|
};
|
|
public static readonly OpDef OpEOR_DP = new OpDef(OpEOR) {
|
|
Opcode = 0x45,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpLSR_DP = new OpDef(OpLSR) {
|
|
Opcode = 0x46,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5 | (int)(CycleMod.OneIfDpNonzero | CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpEOR_DPIndLong = new OpDef(OpEOR) {
|
|
Opcode = 0x47,
|
|
AddrMode = AddressMode.DPIndLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpPHA_StackPush = new OpDef(OpPHA) {
|
|
Opcode = 0x48,
|
|
AddrMode = AddressMode.StackPush,
|
|
CycDef = 3 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpEOR_ImmLongA = new OpDef(OpEOR) {
|
|
Opcode = 0x49,
|
|
AddrMode = AddressMode.ImmLongA,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpEOR_Imm = new OpDef(OpEOR) {
|
|
Opcode = 0x49,
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpLSR_Acc = new OpDef(OpLSR) {
|
|
Opcode = 0x4a,
|
|
AddrMode = AddressMode.Acc,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpPHK_StackPush = new OpDef(OpPHK) {
|
|
Opcode = 0x4b,
|
|
AddrMode = AddressMode.StackPush,
|
|
CycDef = 3
|
|
};
|
|
public static readonly OpDef OpJMP_Abs = new OpDef(OpJMP) {
|
|
Opcode = 0x4c,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 3
|
|
};
|
|
public static readonly OpDef OpEOR_Abs = new OpDef(OpEOR) {
|
|
Opcode = 0x4d,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpLSR_Abs = new OpDef(OpLSR) {
|
|
Opcode = 0x4e,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 6 | (int)(CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpEOR_AbsLong = new OpDef(OpEOR) {
|
|
Opcode = 0x4f,
|
|
AddrMode = AddressMode.AbsLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpBVC_PCRel = new OpDef(OpBVC) {
|
|
Opcode = 0x50,
|
|
AddrMode = AddressMode.PCRel,
|
|
CycDef = 2 | (int)(CycleMod.OneIfBranchTaken | CycleMod.OneIfBranchPage)
|
|
};
|
|
public static readonly OpDef OpEOR_DPIndIndexY = new OpDef(OpEOR) {
|
|
Opcode = 0x51,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpEOR_DPInd = new OpDef(OpEOR) {
|
|
Opcode = 0x52,
|
|
AddrMode = AddressMode.DPInd,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpEOR_StackRelIndIndexY = new OpDef(OpEOR) {
|
|
Opcode = 0x53,
|
|
AddrMode = AddressMode.StackRelIndIndexY,
|
|
CycDef = 7 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpMVN_BlockMove = new OpDef(OpMVN) {
|
|
Opcode = 0x54,
|
|
AddrMode = AddressMode.BlockMove,
|
|
CycDef = 7 | (int)(CycleMod.BlockMove)
|
|
};
|
|
public static readonly OpDef OpEOR_DPIndexX = new OpDef(OpEOR) {
|
|
Opcode = 0x55,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpLSR_DPIndexX = new OpDef(OpLSR) {
|
|
Opcode = 0x56,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 6 | (int)(CycleMod.OneIfDpNonzero | CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpEOR_DPIndIndexYLong = new OpDef(OpEOR) {
|
|
Opcode = 0x57,
|
|
AddrMode = AddressMode.DPIndIndexYLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpCLI_Implied = new OpDef(OpCLI) {
|
|
Opcode = 0x58,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpEOR_AbsIndexY = new OpDef(OpEOR) {
|
|
Opcode = 0x59,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpPHY_StackPush = new OpDef(OpPHY) {
|
|
Opcode = 0x5a,
|
|
AddrMode = AddressMode.StackPush,
|
|
CycDef = 3 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpTCD_Implied = new OpDef(OpTCD) {
|
|
Opcode = 0x5b,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpJMP_AbsLong = new OpDef(OpJML) {
|
|
Opcode = 0x5c,
|
|
AddrMode = AddressMode.AbsLong,
|
|
CycDef = 4
|
|
};
|
|
public static readonly OpDef OpEOR_AbsIndexX = new OpDef(OpEOR) {
|
|
Opcode = 0x5d,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpLSR_AbsIndexX = new OpDef(OpLSR) {
|
|
Opcode = 0x5e,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 7 | (int)(CycleMod.TwoIfM0 | CycleMod.MinusOneIfNoPage)
|
|
};
|
|
public static readonly OpDef OpEOR_AbsIndexXLong = new OpDef(OpEOR) {
|
|
Opcode = 0x5f,
|
|
AddrMode = AddressMode.AbsIndexXLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpRTS_StackRTS = new OpDef(OpRTS) {
|
|
Opcode = 0x60,
|
|
AddrMode = AddressMode.StackRTS,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpADC_DPIndexXInd = new OpDef(OpADC) {
|
|
Opcode = 0x61,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpPER_StackPCRelLong = new OpDef(OpPER) {
|
|
Opcode = 0x62,
|
|
AddrMode = AddressMode.StackPCRelLong,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpADC_StackRel = new OpDef(OpADC) {
|
|
Opcode = 0x63,
|
|
AddrMode = AddressMode.StackRel,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpSTZ_DP = new OpDef(OpSTZ) {
|
|
Opcode = 0x64,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpADC_DP = new OpDef(OpADC) {
|
|
Opcode = 0x65,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpROR_DP = new OpDef(OpROR) {
|
|
Opcode = 0x66,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5 | (int)(CycleMod.OneIfDpNonzero | CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpADC_DPIndLong = new OpDef(OpADC) {
|
|
Opcode = 0x67,
|
|
AddrMode = AddressMode.DPIndLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpPLA_StackPull = new OpDef(OpPLA) {
|
|
Opcode = 0x68,
|
|
AddrMode = AddressMode.StackPull,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpADC_ImmLongA = new OpDef(OpADC) {
|
|
Opcode = 0x69,
|
|
AddrMode = AddressMode.ImmLongA,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpADC_Imm = new OpDef(OpADC) {
|
|
Opcode = 0x69,
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpROR_Acc = new OpDef(OpROR) {
|
|
Opcode = 0x6a,
|
|
AddrMode = AddressMode.Acc,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpRTL_StackRTL = new OpDef(OpRTL) {
|
|
Opcode = 0x6b,
|
|
AddrMode = AddressMode.StackRTL,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpJMP_AbsInd = new OpDef(OpJMP) {
|
|
Opcode = 0x6c,
|
|
AddrMode = AddressMode.AbsInd,
|
|
CycDef = 5 | (int)(CycleMod.OneIf65C02)
|
|
// takes one extra cycle on CMOS 6502 if low byte is 0xff?? (it also has a bug)
|
|
};
|
|
public static readonly OpDef OpADC_Abs = new OpDef(OpADC) {
|
|
Opcode = 0x6d,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpROR_Abs = new OpDef(OpROR) {
|
|
Opcode = 0x6e,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 6 | (int)(CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpADC_AbsLong = new OpDef(OpADC) {
|
|
Opcode = 0x6f,
|
|
AddrMode = AddressMode.AbsLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpBVS_PCRel = new OpDef(OpBVS) {
|
|
Opcode = 0x70,
|
|
AddrMode = AddressMode.PCRel,
|
|
CycDef = 2 | (int)(CycleMod.OneIfBranchTaken | CycleMod.OneIfBranchPage)
|
|
};
|
|
public static readonly OpDef OpADC_DPIndIndexY = new OpDef(OpADC) {
|
|
Opcode = 0x71,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero |
|
|
CycleMod.OneIfIndexPage | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpADC_DPInd = new OpDef(OpADC) {
|
|
Opcode = 0x72,
|
|
AddrMode = AddressMode.DPInd,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpADC_StackRelIndIndexY = new OpDef(OpADC) {
|
|
Opcode = 0x73,
|
|
AddrMode = AddressMode.StackRelIndIndexY,
|
|
CycDef = 7 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpSTZ_DPIndexX = new OpDef(OpSTZ) {
|
|
Opcode = 0x74,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpADC_DPIndexX = new OpDef(OpADC) {
|
|
Opcode = 0x75,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpROR_DPIndexX = new OpDef(OpROR) {
|
|
Opcode = 0x76,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 6 | (int)(CycleMod.OneIfDpNonzero | CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpADC_DPIndIndexYLong = new OpDef(OpADC) {
|
|
Opcode = 0x77,
|
|
AddrMode = AddressMode.DPIndIndexYLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpSEI_Implied = new OpDef(OpSEI) {
|
|
Opcode = 0x78,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpADC_AbsIndexY = new OpDef(OpADC) {
|
|
Opcode = 0x79,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfIndexPage | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpPLY_StackPull = new OpDef(OpPLY) {
|
|
Opcode = 0x7a,
|
|
AddrMode = AddressMode.StackPull,
|
|
CycDef = 4 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpTDC_Implied = new OpDef(OpTDC) {
|
|
Opcode = 0x7b,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpJMP_AbsIndexXInd = new OpDef(OpJMP) {
|
|
Opcode = 0x7c,
|
|
AddrMode = AddressMode.AbsIndexXInd,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpADC_AbsIndexX = new OpDef(OpADC) {
|
|
Opcode = 0x7d,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfIndexPage | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpROR_AbsIndexX = new OpDef(OpROR) {
|
|
Opcode = 0x7e,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 7 | (int)(CycleMod.TwoIfM0 | CycleMod.MinusOneIfNoPage)
|
|
};
|
|
public static readonly OpDef OpADC_AbsIndexXLong = new OpDef(OpADC) {
|
|
Opcode = 0x7f,
|
|
AddrMode = AddressMode.AbsIndexXLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpBRA_PCRel = new OpDef(OpBRA) {
|
|
Opcode = 0x80,
|
|
AddrMode = AddressMode.PCRel,
|
|
CycDef = 3 | (int)(CycleMod.OneIfBranchPage)
|
|
};
|
|
public static readonly OpDef OpSTA_DPIndexXInd = new OpDef(OpSTA) {
|
|
Opcode = 0x81,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpBRL_PCRelLong = new OpDef(OpBRL) {
|
|
Opcode = 0x82,
|
|
AddrMode = AddressMode.PCRelLong,
|
|
CycDef = 4
|
|
};
|
|
public static readonly OpDef OpSTA_StackRel = new OpDef(OpSTA) {
|
|
Opcode = 0x83,
|
|
AddrMode = AddressMode.StackRel,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpSTY_DP = new OpDef(OpSTY) {
|
|
Opcode = 0x84,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfDpNonzero | CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpSTA_DP = new OpDef(OpSTA) {
|
|
Opcode = 0x85,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpSTX_DP = new OpDef(OpSTX) {
|
|
Opcode = 0x86,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfDpNonzero | CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpSTA_DPIndLong = new OpDef(OpSTA) {
|
|
Opcode = 0x87,
|
|
AddrMode = AddressMode.DPIndLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpDEY_Implied = new OpDef(OpDEY) {
|
|
Opcode = 0x88,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpBIT_ImmLongA = new OpDef(OpBIT) {
|
|
Opcode = 0x89,
|
|
AddrMode = AddressMode.ImmLongA,
|
|
FlagsAffected = FlagsAffected_Z, // special case
|
|
StatusFlagUpdater = FlagUpdater_Z,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpBIT_Imm = new OpDef(OpBIT) {
|
|
Opcode = 0x89,
|
|
AddrMode = AddressMode.Imm,
|
|
FlagsAffected = FlagsAffected_Z, // special case
|
|
StatusFlagUpdater = FlagUpdater_Z,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpTXA_Implied = new OpDef(OpTXA) {
|
|
Opcode = 0x8a,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpPHB_StackPush = new OpDef(OpPHB) {
|
|
Opcode = 0x8b,
|
|
AddrMode = AddressMode.StackPush,
|
|
CycDef = 3
|
|
};
|
|
public static readonly OpDef OpSTY_Abs = new OpDef(OpSTY) {
|
|
Opcode = 0x8c,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpSTA_Abs = new OpDef(OpSTA) {
|
|
Opcode = 0x8d,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpSTX_Abs = new OpDef(OpSTX) {
|
|
Opcode = 0x8e,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpSTA_AbsLong = new OpDef(OpSTA) {
|
|
Opcode = 0x8f,
|
|
AddrMode = AddressMode.AbsLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpBCC_PCRel = new OpDef(OpBCC) {
|
|
Opcode = 0x90,
|
|
AddrMode = AddressMode.PCRel,
|
|
CycDef = 2 | (int)(CycleMod.OneIfBranchTaken | CycleMod.OneIfBranchPage)
|
|
};
|
|
public static readonly OpDef OpSTA_DPIndIndexY = new OpDef(OpSTA) {
|
|
Opcode = 0x91,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpSTA_DPInd = new OpDef(OpSTA) {
|
|
Opcode = 0x92,
|
|
AddrMode = AddressMode.DPInd,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpSTA_StackRelIndIndexY = new OpDef(OpSTA) {
|
|
Opcode = 0x93,
|
|
AddrMode = AddressMode.StackRelIndIndexY,
|
|
CycDef = 7 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpSTY_DPIndexX = new OpDef(OpSTY) {
|
|
Opcode = 0x94,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfDpNonzero | CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpSTA_DPIndexX = new OpDef(OpSTA) {
|
|
Opcode = 0x95,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpSTX_DPIndexY = new OpDef(OpSTX) {
|
|
Opcode = 0x96,
|
|
AddrMode = AddressMode.DPIndexY,
|
|
CycDef = 4 | (int)(CycleMod.OneIfDpNonzero | CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpSTA_DPIndIndexYLong = new OpDef(OpSTA) {
|
|
Opcode = 0x97,
|
|
AddrMode = AddressMode.DPIndIndexYLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpTYA_Implied = new OpDef(OpTYA) {
|
|
Opcode = 0x98,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpSTA_AbsIndexY = new OpDef(OpSTA) {
|
|
Opcode = 0x99,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpTXS_Implied = new OpDef(OpTXS) {
|
|
Opcode = 0x9a,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpTXY_Implied = new OpDef(OpTXY) {
|
|
Opcode = 0x9b,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpSTZ_Abs = new OpDef(OpSTZ) {
|
|
Opcode = 0x9c,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpSTA_AbsIndexX = new OpDef(OpSTA) {
|
|
Opcode = 0x9d,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpSTZ_AbsIndexX = new OpDef(OpSTZ) {
|
|
Opcode = 0x9e,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpSTA_AbsIndexXLong = new OpDef(OpSTA) {
|
|
Opcode = 0x9f,
|
|
AddrMode = AddressMode.AbsIndexXLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpLDY_ImmLongXY = new OpDef(OpLDY) {
|
|
Opcode = 0xa0,
|
|
AddrMode = AddressMode.ImmLongXY,
|
|
StatusFlagUpdater = FlagUpdater_LoadImm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpLDY_Imm = new OpDef(OpLDY) {
|
|
Opcode = 0xa0,
|
|
AddrMode = AddressMode.Imm,
|
|
StatusFlagUpdater = FlagUpdater_LoadImm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpLDA_DPIndexXInd = new OpDef(OpLDA) {
|
|
Opcode = 0xa1,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpLDX_ImmLongXY = new OpDef(OpLDX) {
|
|
Opcode = 0xa2,
|
|
AddrMode = AddressMode.ImmLongXY,
|
|
StatusFlagUpdater = FlagUpdater_LoadImm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpLDX_Imm = new OpDef(OpLDX) {
|
|
Opcode = 0xa2,
|
|
AddrMode = AddressMode.Imm,
|
|
StatusFlagUpdater = FlagUpdater_LoadImm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpLDA_StackRel = new OpDef(OpLDA) {
|
|
Opcode = 0xa3,
|
|
AddrMode = AddressMode.StackRel,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpLDY_DP = new OpDef(OpLDY) {
|
|
Opcode = 0xa4,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfDpNonzero | CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpLDA_DP = new OpDef(OpLDA) {
|
|
Opcode = 0xa5,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpLDX_DP = new OpDef(OpLDX) {
|
|
Opcode = 0xa6,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfDpNonzero | CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpLDA_DPIndLong = new OpDef(OpLDA) {
|
|
Opcode = 0xa7,
|
|
AddrMode = AddressMode.DPIndLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpTAY_Implied = new OpDef(OpTAY) {
|
|
Opcode = 0xa8,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpLDA_ImmLongA = new OpDef(OpLDA) { // 16-bit CPU
|
|
Opcode = 0xa9,
|
|
AddrMode = AddressMode.ImmLongA,
|
|
StatusFlagUpdater = FlagUpdater_LoadImm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpLDA_Imm = new OpDef(OpLDA) { // 8-bit CPU
|
|
Opcode = 0xa9,
|
|
AddrMode = AddressMode.Imm,
|
|
StatusFlagUpdater = FlagUpdater_LoadImm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpTAX_Implied = new OpDef(OpTAX) {
|
|
Opcode = 0xaa,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpPLB_StackPull = new OpDef(OpPLB) {
|
|
Opcode = 0xab,
|
|
AddrMode = AddressMode.StackPull,
|
|
CycDef = 4
|
|
};
|
|
public static readonly OpDef OpLDY_Abs = new OpDef(OpLDY) {
|
|
Opcode = 0xac,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpLDA_Abs = new OpDef(OpLDA) {
|
|
Opcode = 0xad,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpLDX_Abs = new OpDef(OpLDX) {
|
|
Opcode = 0xae,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpLDA_AbsLong = new OpDef(OpLDA) {
|
|
Opcode = 0xaf,
|
|
AddrMode = AddressMode.AbsLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpBCS_PCRel = new OpDef(OpBCS) {
|
|
Opcode = 0xb0,
|
|
AddrMode = AddressMode.PCRel,
|
|
CycDef = 2 | (int)(CycleMod.OneIfBranchTaken | CycleMod.OneIfBranchPage)
|
|
};
|
|
public static readonly OpDef OpLDA_DPIndIndexY = new OpDef(OpLDA) {
|
|
Opcode = 0xb1,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpLDA_DPInd = new OpDef(OpLDA) {
|
|
Opcode = 0xb2,
|
|
AddrMode = AddressMode.DPInd,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpLDA_StackRelIndIndexY = new OpDef(OpLDA) {
|
|
Opcode = 0xb3,
|
|
AddrMode = AddressMode.StackRelIndIndexY,
|
|
CycDef = 7 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpLDY_DPIndexX = new OpDef(OpLDY) {
|
|
Opcode = 0xb4,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfDpNonzero | CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpLDA_DPIndexX = new OpDef(OpLDA) {
|
|
Opcode = 0xb5,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpLDX_DPIndexY = new OpDef(OpLDX) {
|
|
Opcode = 0xb6,
|
|
AddrMode = AddressMode.DPIndexY,
|
|
CycDef = 4 | (int)(CycleMod.OneIfDpNonzero | CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpLDA_DPIndIndexYLong = new OpDef(OpLDA) {
|
|
Opcode = 0xb7,
|
|
AddrMode = AddressMode.DPIndIndexYLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpCLV_Implied = new OpDef(OpCLV) {
|
|
Opcode = 0xb8,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpLDA_AbsIndexY = new OpDef(OpLDA) {
|
|
Opcode = 0xb9,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpTSX_Implied = new OpDef(OpTSX) {
|
|
Opcode = 0xba,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpTYX_Implied = new OpDef(OpTYX) {
|
|
Opcode = 0xbb,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpLDY_AbsIndexX = new OpDef(OpLDY) {
|
|
Opcode = 0xbc,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfIndexPage | CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpLDA_AbsIndexX = new OpDef(OpLDA) {
|
|
Opcode = 0xbd,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpLDX_AbsIndexY = new OpDef(OpLDX) {
|
|
Opcode = 0xbe,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 4 | (int)(CycleMod.OneIfIndexPage | CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpLDA_AbsIndexXLong = new OpDef(OpLDA) {
|
|
Opcode = 0xbf,
|
|
AddrMode = AddressMode.AbsIndexXLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpCPY_ImmLongXY = new OpDef(OpCPY) {
|
|
Opcode = 0xc0,
|
|
AddrMode = AddressMode.ImmLongXY,
|
|
CycDef = 2 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpCPY_Imm = new OpDef(OpCPY) {
|
|
Opcode = 0xc0,
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpCMP_DPIndexXInd = new OpDef(OpCMP) {
|
|
Opcode = 0xc1,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpREP_Imm = new OpDef(OpREP) {
|
|
Opcode = 0xc2,
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 3
|
|
};
|
|
public static readonly OpDef OpCMP_StackRel = new OpDef(OpCMP) {
|
|
Opcode = 0xc3,
|
|
AddrMode = AddressMode.StackRel,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpCPY_DP = new OpDef(OpCPY) {
|
|
Opcode = 0xc4,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfDpNonzero | CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpCMP_DP = new OpDef(OpCMP) {
|
|
Opcode = 0xc5,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpDEC_DP = new OpDef(OpDEC) {
|
|
Opcode = 0xc6,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5 | (int)(CycleMod.OneIfDpNonzero | CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpCMP_DPIndLong = new OpDef(OpCMP) {
|
|
Opcode = 0xc7,
|
|
AddrMode = AddressMode.DPIndLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpINY_Implied = new OpDef(OpINY) {
|
|
Opcode = 0xc8,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpCMP_ImmLongA = new OpDef(OpCMP) {
|
|
Opcode = 0xc9,
|
|
AddrMode = AddressMode.ImmLongA,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpCMP_Imm = new OpDef(OpCMP) {
|
|
Opcode = 0xc9,
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpDEX_Implied = new OpDef(OpDEX) {
|
|
Opcode = 0xca,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpWAI_Implied = new OpDef(OpWAI) {
|
|
Opcode = 0xcb,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 3 // 3 to shut down, more to restart
|
|
};
|
|
public static readonly OpDef OpCPY_Abs = new OpDef(OpCPY) {
|
|
Opcode = 0xcc,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpCMP_Abs = new OpDef(OpCMP) {
|
|
Opcode = 0xcd,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpDEC_Abs = new OpDef(OpDEC) {
|
|
Opcode = 0xce,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 6 | (int)(CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpCMP_AbsLong = new OpDef(OpCMP) {
|
|
Opcode = 0xcf,
|
|
AddrMode = AddressMode.AbsLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpBNE_PCRel = new OpDef(OpBNE) {
|
|
Opcode = 0xd0,
|
|
AddrMode = AddressMode.PCRel,
|
|
CycDef = 2 | (int)(CycleMod.OneIfBranchTaken | CycleMod.OneIfBranchPage)
|
|
};
|
|
public static readonly OpDef OpCMP_DPIndIndexY = new OpDef(OpCMP) {
|
|
Opcode = 0xd1,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpCMP_DPInd = new OpDef(OpCMP) {
|
|
Opcode = 0xd2,
|
|
AddrMode = AddressMode.DPInd,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpCMP_StackRelIndIndexY = new OpDef(OpCMP) {
|
|
Opcode = 0xd3,
|
|
AddrMode = AddressMode.StackRelIndIndexY,
|
|
CycDef = 7 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpPEI_StackDPInd = new OpDef(OpPEI) {
|
|
Opcode = 0xd4,
|
|
AddrMode = AddressMode.StackDPInd,
|
|
CycDef = 6 | (int)(CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpCMP_DPIndexX = new OpDef(OpCMP) {
|
|
Opcode = 0xd5,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpDEC_DPIndexX = new OpDef(OpDEC) {
|
|
Opcode = 0xd6,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 6 | (int)(CycleMod.OneIfDpNonzero | CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpCMP_DPIndIndexYLong = new OpDef(OpCMP) {
|
|
Opcode = 0xd7,
|
|
AddrMode = AddressMode.DPIndIndexYLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero)
|
|
};
|
|
public static readonly OpDef OpCLD_Implied = new OpDef(OpCLD) {
|
|
Opcode = 0xd8,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpCMP_AbsIndexY = new OpDef(OpCMP) {
|
|
Opcode = 0xd9,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpPHX_StackPush = new OpDef(OpPHX) {
|
|
Opcode = 0xda,
|
|
AddrMode = AddressMode.StackPush,
|
|
CycDef = 3 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpSTP_Implied = new OpDef(OpSTP) {
|
|
Opcode = 0xdb,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 3 // 3 to shut down, more to reset out
|
|
};
|
|
public static readonly OpDef OpJMP_AbsIndLong = new OpDef(OpJML) {
|
|
Opcode = 0xdc,
|
|
AddrMode = AddressMode.AbsIndLong,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpCMP_AbsIndexX = new OpDef(OpCMP) {
|
|
Opcode = 0xdd,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpDEC_AbsIndexX = new OpDef(OpDEC) {
|
|
Opcode = 0xde,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 7 | (int)(CycleMod.TwoIfM0 | CycleMod.MinusOneIfNoPage)
|
|
};
|
|
public static readonly OpDef OpCMP_AbsIndexXLong = new OpDef(OpCMP) {
|
|
Opcode = 0xdf,
|
|
AddrMode = AddressMode.AbsIndexXLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0)
|
|
};
|
|
public static readonly OpDef OpCPX_ImmLongXY = new OpDef(OpCPX) {
|
|
Opcode = 0xe0,
|
|
AddrMode = AddressMode.ImmLongXY,
|
|
CycDef = 2 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpCPX_Imm = new OpDef(OpCPX) {
|
|
Opcode = 0xe0,
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpSBC_DPIndexXInd = new OpDef(OpSBC) {
|
|
Opcode = 0xe1,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpSEP_Imm = new OpDef(OpSEP) {
|
|
Opcode = 0xe2,
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 3
|
|
};
|
|
public static readonly OpDef OpSBC_StackRel = new OpDef(OpSBC) {
|
|
Opcode = 0xe3,
|
|
AddrMode = AddressMode.StackRel,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpCPX_DP = new OpDef(OpCPX) {
|
|
Opcode = 0xe4,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfDpNonzero | CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpSBC_DP = new OpDef(OpSBC) {
|
|
Opcode = 0xe5,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpINC_DP = new OpDef(OpINC) {
|
|
Opcode = 0xe6,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5 | (int)(CycleMod.OneIfDpNonzero | CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpSBC_DPIndLong = new OpDef(OpSBC) {
|
|
Opcode = 0xe7,
|
|
AddrMode = AddressMode.DPIndLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpINX_Implied = new OpDef(OpINX) {
|
|
Opcode = 0xe8,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpSBC_ImmLongA = new OpDef(OpSBC) {
|
|
Opcode = 0xe9,
|
|
AddrMode = AddressMode.ImmLongA,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpSBC_Imm = new OpDef(OpSBC) {
|
|
Opcode = 0xe9,
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 2 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpNOP_Implied = new OpDef(OpNOP) {
|
|
Opcode = 0xea,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpXBA_Implied = new OpDef(OpXBA) {
|
|
Opcode = 0xeb,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 3
|
|
};
|
|
public static readonly OpDef OpCPX_Abs = new OpDef(OpCPX) {
|
|
Opcode = 0xec,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpSBC_Abs = new OpDef(OpSBC) {
|
|
Opcode = 0xed,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpINC_Abs = new OpDef(OpINC) {
|
|
Opcode = 0xee,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 6 | (int)(CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpSBC_AbsLong = new OpDef(OpSBC) {
|
|
Opcode = 0xef,
|
|
AddrMode = AddressMode.AbsLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpBEQ_PCRel = new OpDef(OpBEQ) {
|
|
Opcode = 0xf0,
|
|
AddrMode = AddressMode.PCRel,
|
|
CycDef = 2 | (int)(CycleMod.OneIfBranchTaken | CycleMod.OneIfBranchPage)
|
|
};
|
|
public static readonly OpDef OpSBC_DPIndIndexY = new OpDef(OpSBC) {
|
|
Opcode = 0xf1,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero |
|
|
CycleMod.OneIfIndexPage | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpSBC_DPInd = new OpDef(OpSBC) {
|
|
Opcode = 0xf2,
|
|
AddrMode = AddressMode.DPInd,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpSBC_StackRelIndIndexY = new OpDef(OpSBC) {
|
|
Opcode = 0xf3,
|
|
AddrMode = AddressMode.StackRelIndIndexY,
|
|
CycDef = 7 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpPEA_StackAbs = new OpDef(OpPEA) {
|
|
Opcode = 0xf4,
|
|
AddrMode = AddressMode.StackAbs,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpSBC_DPIndexX = new OpDef(OpSBC) {
|
|
Opcode = 0xf5,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpINC_DPIndexX = new OpDef(OpINC) {
|
|
Opcode = 0xf6,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 6 | (int)(CycleMod.OneIfDpNonzero | CycleMod.TwoIfM0)
|
|
};
|
|
public static readonly OpDef OpSBC_DPIndIndexYLong = new OpDef(OpSBC) {
|
|
Opcode = 0xf7,
|
|
AddrMode = AddressMode.DPIndIndexYLong,
|
|
CycDef = 6 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfDpNonzero | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpSED_Implied = new OpDef(OpSED) {
|
|
Opcode = 0xf8,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpSBC_AbsIndexY = new OpDef(OpSBC) {
|
|
Opcode = 0xf9,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfIndexPage | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpPLX_StackPull = new OpDef(OpPLX) {
|
|
Opcode = 0xfa,
|
|
AddrMode = AddressMode.StackPull,
|
|
CycDef = 4 | (int)(CycleMod.OneIfX0)
|
|
};
|
|
public static readonly OpDef OpXCE_Implied = new OpDef(OpXCE) {
|
|
Opcode = 0xfb,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpJSR_AbsIndexXInd = new OpDef(OpJSR) {
|
|
Opcode = 0xfc,
|
|
AddrMode = AddressMode.AbsIndexXInd,
|
|
CycDef = 8
|
|
};
|
|
public static readonly OpDef OpSBC_AbsIndexX = new OpDef(OpSBC) {
|
|
Opcode = 0xfd,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfIndexPage | CycleMod.OneIfD1)
|
|
};
|
|
public static readonly OpDef OpINC_AbsIndexX = new OpDef(OpINC) {
|
|
Opcode = 0xfe,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 7 | (int)(CycleMod.TwoIfM0 | CycleMod.MinusOneIfNoPage)
|
|
};
|
|
public static readonly OpDef OpSBC_AbsIndexXLong = new OpDef(OpSBC) {
|
|
Opcode = 0xff,
|
|
AddrMode = AddressMode.AbsIndexXLong,
|
|
CycDef = 5 | (int)(CycleMod.OneIfM0 | CycleMod.OneIfD1)
|
|
};
|
|
|
|
#endregion 65816 Instructions
|
|
|
|
#region Undocumented 6502
|
|
|
|
// ======================================================================================
|
|
// Undocumented 6502 instructions.
|
|
//
|
|
// There are 151 defined opcodes. The rest officially have undefined behavior. In
|
|
// most cases it's pretty stable, in others the behavior can differ between CPU
|
|
// variants.
|
|
//
|
|
// There is no universally agreed-upon set of mnemonics for these instructions. The
|
|
// mnemonics "XAS" and "AXS" sometimes mean one thing and sometimes another. The
|
|
// reference I've chosen to use as primary is "NMOS 6510 Unintended Opcodes":
|
|
// https://csdb.dk/release/?id=161035
|
|
//
|
|
// Other references:
|
|
// http://nesdev.com/undocumented_opcodes.txt
|
|
// http://visual6502.org/wiki/index.php?title=6502_all_256_Opcodes
|
|
// http://www.ffd2.com/fridge/docs/6502-NMOS.extra.opcodes
|
|
//
|
|
|
|
private static OpDef OpANC = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.ANC,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZC,
|
|
StatusFlagUpdater = FlagUpdater_NZC
|
|
};
|
|
private static OpDef OpANE = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.ANE,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpALR = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.ALR,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZC,
|
|
StatusFlagUpdater = FlagUpdater_NZC
|
|
};
|
|
private static OpDef OpARR = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.ARR,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NVZC,
|
|
StatusFlagUpdater = FlagUpdater_NVZC
|
|
};
|
|
private static OpDef OpDCP = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.DCP,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite,
|
|
FlagsAffected = FlagsAffected_NZC,
|
|
StatusFlagUpdater = FlagUpdater_NZC
|
|
};
|
|
private static OpDef OpDOP = new OpDef() { // double-byte NOP
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.DOP,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpJAM = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.JAM,
|
|
Effect = FlowEffect.NoCont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpISC = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.ISC,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite,
|
|
FlagsAffected = FlagsAffected_NVZC,
|
|
StatusFlagUpdater = FlagUpdater_NVZC
|
|
};
|
|
private static OpDef OpLAS = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.LAS,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Read,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpLAX = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.LAX,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Read,
|
|
FlagsAffected = FlagsAffected_NZ,
|
|
StatusFlagUpdater = FlagUpdater_NZ
|
|
};
|
|
private static OpDef OpRLA = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.RLA,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite,
|
|
FlagsAffected = FlagsAffected_NZC,
|
|
StatusFlagUpdater = FlagUpdater_NZC
|
|
};
|
|
private static OpDef OpRRA = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.RRA,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite,
|
|
FlagsAffected = FlagsAffected_NVZC,
|
|
StatusFlagUpdater = FlagUpdater_NVZC
|
|
};
|
|
private static OpDef OpSAX = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.SAX,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Write
|
|
};
|
|
private static OpDef OpSBX = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.SBX,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
FlagsAffected = FlagsAffected_NZC,
|
|
StatusFlagUpdater = FlagUpdater_NZC
|
|
};
|
|
private static OpDef OpSHA = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.SHA,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Write
|
|
};
|
|
private static OpDef OpSHX = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.SHX,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Write
|
|
};
|
|
private static OpDef OpSHY = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.SHY,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Write
|
|
};
|
|
private static OpDef OpSLO = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.SLO,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite,
|
|
FlagsAffected = FlagsAffected_NZC,
|
|
StatusFlagUpdater = FlagUpdater_NZC
|
|
};
|
|
private static OpDef OpSRE = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.SRE,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite,
|
|
FlagsAffected = FlagsAffected_NZC,
|
|
StatusFlagUpdater = FlagUpdater_NZC
|
|
};
|
|
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,
|
|
Mnemonic = OpName.TOP,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
|
|
public static readonly OpDef OpSLO_DPIndexXInd = new OpDef(OpSLO) {
|
|
Opcode = 0x03,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 8
|
|
};
|
|
public static readonly OpDef OpSLO_DP = new OpDef(OpSLO) {
|
|
Opcode = 0x07,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpSLO_Absolute = new OpDef(OpSLO) {
|
|
Opcode = 0x0f,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpSLO_DPIndIndexY = new OpDef(OpSLO) {
|
|
Opcode = 0x13,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 8
|
|
};
|
|
public static readonly OpDef OpSLO_DPIndexX = new OpDef(OpSLO) {
|
|
Opcode = 0x17,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpSLO_AbsIndexY = new OpDef(OpSLO) {
|
|
Opcode = 0x1b,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 7
|
|
};
|
|
public static readonly OpDef OpSLO_AbsIndexX = new OpDef(OpSLO) {
|
|
Opcode = 0x1f,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 7
|
|
};
|
|
public static readonly OpDef OpRLA_DPIndexXInd = new OpDef(OpRLA) {
|
|
Opcode = 0x23,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 8
|
|
};
|
|
public static readonly OpDef OpRLA_DP = new OpDef(OpRLA) {
|
|
Opcode = 0x27,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpRLA_Absolute = new OpDef(OpRLA) {
|
|
Opcode = 0x2f,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpRLA_DPIndIndexY = new OpDef(OpRLA) {
|
|
Opcode = 0x33,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 8
|
|
};
|
|
public static readonly OpDef OpRLA_DPIndexX = new OpDef(OpRLA) {
|
|
Opcode = 0x37,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpRLA_AbsIndexY = new OpDef(OpRLA) {
|
|
Opcode = 0x3b,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 7
|
|
};
|
|
public static readonly OpDef OpRLA_AbsIndexX = new OpDef(OpRLA) {
|
|
Opcode = 0x3f,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 7
|
|
};
|
|
public static readonly OpDef OpSRE_DPIndexXInd = new OpDef(OpSRE) {
|
|
Opcode = 0x43,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 8
|
|
};
|
|
public static readonly OpDef OpSRE_DP = new OpDef(OpSRE) {
|
|
Opcode = 0x47,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpSRE_Absolute = new OpDef(OpSRE) {
|
|
Opcode = 0x4f,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpSRE_DPIndIndexY = new OpDef(OpSRE) {
|
|
Opcode = 0x53,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 8
|
|
};
|
|
public static readonly OpDef OpSRE_DPIndexX = new OpDef(OpSRE) {
|
|
Opcode = 0x57,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpSRE_AbsIndexY = new OpDef(OpSRE) {
|
|
Opcode = 0x5b,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 7
|
|
};
|
|
public static readonly OpDef OpSRE_AbsIndexX = new OpDef(OpSRE) {
|
|
Opcode = 0x5f,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 7
|
|
};
|
|
public static readonly OpDef OpRRA_DPIndexXInd = new OpDef(OpRRA) {
|
|
Opcode = 0x63,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 8
|
|
};
|
|
public static readonly OpDef OpRRA_DP = new OpDef(OpRRA) {
|
|
Opcode = 0x67,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpRRA_Absolute = new OpDef(OpRRA) {
|
|
Opcode = 0x6f,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpRRA_DPIndIndexY = new OpDef(OpRRA) {
|
|
Opcode = 0x73,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 8
|
|
};
|
|
public static readonly OpDef OpRRA_DPIndexX = new OpDef(OpRRA) {
|
|
Opcode = 0x77,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpRRA_AbsIndexY = new OpDef(OpRRA) {
|
|
Opcode = 0x7b,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 7
|
|
};
|
|
public static readonly OpDef OpRRA_AbsIndexX = new OpDef(OpRRA) {
|
|
Opcode = 0x7f,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 7
|
|
};
|
|
public static readonly OpDef OpSAX_DPIndexXInd = new OpDef(OpSAX) {
|
|
Opcode = 0x83,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpSAX_DP = new OpDef(OpSAX) {
|
|
Opcode = 0x87,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3
|
|
};
|
|
public static readonly OpDef OpSAX_Absolute = new OpDef(OpSAX) {
|
|
Opcode = 0x8f,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4
|
|
};
|
|
public static readonly OpDef OpSAX_DPIndexY = new OpDef(OpSAX) {
|
|
Opcode = 0x97,
|
|
AddrMode = AddressMode.DPIndexY,
|
|
CycDef = 4
|
|
};
|
|
public static readonly OpDef OpLAX_DPIndexXInd = new OpDef(OpLAX) {
|
|
Opcode = 0xa3,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpLAX_DP = new OpDef(OpLAX) {
|
|
Opcode = 0xa7,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3
|
|
};
|
|
public static readonly OpDef OpLAX_Absolute = new OpDef(OpLAX) {
|
|
Opcode = 0xaf,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4
|
|
};
|
|
public static readonly OpDef OpLAX_DPIndIndexY = new OpDef(OpLAX) {
|
|
Opcode = 0xb3,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 5 | (int)(CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpLAX_DPIndexY = new OpDef(OpLAX) {
|
|
Opcode = 0xb7,
|
|
AddrMode = AddressMode.DPIndexY,
|
|
CycDef = 4
|
|
};
|
|
public static readonly OpDef OpLAX_AbsIndexY = new OpDef(OpLAX) {
|
|
Opcode = 0xbf,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 4 | (int)(CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpDCP_DPIndexXInd = new OpDef(OpDCP) {
|
|
Opcode = 0xc3,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 8
|
|
};
|
|
public static readonly OpDef OpDCP_DP = new OpDef(OpDCP) {
|
|
Opcode = 0xc7,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpDCP_Abs = new OpDef(OpDCP) {
|
|
Opcode = 0xcf,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpDCP_DPIndIndexY = new OpDef(OpDCP) {
|
|
Opcode = 0xd3,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 8
|
|
};
|
|
public static readonly OpDef OpDCP_DPIndexX = new OpDef(OpDCP) {
|
|
Opcode = 0xd7,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpDCP_AbsIndexY = new OpDef(OpDCP) {
|
|
Opcode = 0xdb,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 7
|
|
};
|
|
public static readonly OpDef OpDCP_AbsIndexX = new OpDef(OpDCP) {
|
|
Opcode = 0xdf,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 7
|
|
};
|
|
public static readonly OpDef OpISC_DPIndexXInd = new OpDef(OpISC) {
|
|
Opcode = 0xe3,
|
|
AddrMode = AddressMode.DPIndexXInd,
|
|
CycDef = 8
|
|
};
|
|
public static readonly OpDef OpISC_DP = new OpDef(OpISC) {
|
|
Opcode = 0xe7,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpISC_Abs = new OpDef(OpISC) {
|
|
Opcode = 0xef,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpISC_DPIndIndexY = new OpDef(OpISC) {
|
|
Opcode = 0xf3,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 8
|
|
};
|
|
public static readonly OpDef OpISC_DPIndexX = new OpDef(OpISC) {
|
|
Opcode = 0xf7,
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpISC_AbsIndexY = new OpDef(OpISC) {
|
|
Opcode = 0xfb,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 7
|
|
};
|
|
public static readonly OpDef OpISC_AbsIndexX = new OpDef(OpISC) {
|
|
Opcode = 0xff,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 7
|
|
};
|
|
public static readonly OpDef OpALR_Imm = new OpDef(OpALR) {
|
|
Opcode = 0x4b,
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpARR_Imm = new OpDef(OpARR) {
|
|
Opcode = 0x6b,
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpANE_Imm = new OpDef(OpANE) {
|
|
Opcode = 0x8b,
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpLAX_Imm = new OpDef(OpLAX) {
|
|
Opcode = 0xab,
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpSBX_Imm = new OpDef(OpSBX) {
|
|
Opcode = 0xcb,
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpDOP_Imm = new OpDef(OpDOP) {
|
|
// multiple opcodes
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpDOP_DP = new OpDef(OpDOP) {
|
|
// multiple opcodes
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3
|
|
};
|
|
public static readonly OpDef OpDOP_DPIndexX = new OpDef(OpDOP) {
|
|
// multiple opcodes
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 4
|
|
};
|
|
public static readonly OpDef OpTOP_Abs = new OpDef(OpTOP) {
|
|
Opcode = 0x0c,
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4
|
|
};
|
|
public static readonly OpDef OpTOP_AbsIndeX = new OpDef(OpTOP) {
|
|
// multiple opcodes
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 4 | (int)(CycleMod.OneIfIndexPage)
|
|
};
|
|
public static readonly OpDef OpJAM_Implied = new OpDef(OpJAM) {
|
|
// multiple opcodes
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 1
|
|
};
|
|
public static readonly OpDef OpTAS_AbsIndexY = new OpDef(OpTAS) {
|
|
Opcode = 0x9b,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpSHY_AbsIndexX = new OpDef(OpSHY) {
|
|
Opcode = 0x9c,
|
|
AddrMode = AddressMode.AbsIndexX,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpSHX_AbsIndexY = new OpDef(OpSHX) {
|
|
Opcode = 0x9e,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpSHA_DPIndIndexY = new OpDef(OpSHA) {
|
|
Opcode = 0x93,
|
|
AddrMode = AddressMode.DPIndIndexY,
|
|
CycDef = 6
|
|
};
|
|
public static readonly OpDef OpSHA_AbsIndexY = new OpDef(OpSHA) {
|
|
Opcode = 0x9f,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpANC_Imm = new OpDef(OpANC) {
|
|
// multiple opcodes
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpLAS_AbsIndexY = new OpDef(OpLAS) {
|
|
Opcode = 0xbb,
|
|
AddrMode = AddressMode.AbsIndexY,
|
|
CycDef = 4 | (int)(CycleMod.OneIfIndexPage)
|
|
};
|
|
|
|
#endregion Undocumented 6502
|
|
|
|
#region Undocumented 65C02
|
|
|
|
// ======================================================================================
|
|
// Undocumented 65C02 instructions.
|
|
//
|
|
// The 65C02 declared all undefined opcodes to be NOPs, but some of them can have
|
|
// side effects.
|
|
//
|
|
// References:
|
|
// http://laughtonelectronics.com/Arcana/KimKlone/Kimklone_opcode_mapping.html
|
|
//
|
|
|
|
// Most undocumented instructions are a single-byte, single-cycle NOP. I don't know
|
|
// if these are "undocumented" in the strictest sense of the word, but we'll treat
|
|
// them that way for disassembly purposes.
|
|
public static readonly OpDef OpNOP_65C02 = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.NOP,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.None,
|
|
AddrMode = AddressMode.Implied,
|
|
CycDef = 1
|
|
};
|
|
|
|
// 65C02 undocumented "Load and Discard" instruction. These cause bus traffic.
|
|
private static OpDef OpLDD = new OpDef() {
|
|
IsUndocumented = true,
|
|
Mnemonic = OpName.LDD,
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.Read,
|
|
AddrMode = AddressMode.Implied
|
|
};
|
|
public static readonly OpDef OpLDD_Absolute = new OpDef(OpLDD) {
|
|
// multiple opcodes
|
|
AddrMode = AddressMode.Abs,
|
|
CycDef = 4
|
|
};
|
|
public static readonly OpDef OpLDD_DP = new OpDef(OpLDD) {
|
|
// multiple opcodes
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 3
|
|
};
|
|
public static readonly OpDef OpLDD_DPIndexX = new OpDef(OpLDD) {
|
|
// multiple opcodes
|
|
AddrMode = AddressMode.DPIndexX,
|
|
CycDef = 4
|
|
};
|
|
public static readonly OpDef OpLDD_Imm = new OpDef(OpLDD) {
|
|
// multiple opcodes
|
|
AddrMode = AddressMode.Imm,
|
|
CycDef = 2
|
|
};
|
|
public static readonly OpDef OpLDD_Weird = new OpDef(OpLDD) {
|
|
// multiple opcodes
|
|
AddrMode = AddressMode.Abs, // not really, but has the right number of bytes
|
|
CycDef = 8
|
|
};
|
|
|
|
#endregion Undocumented
|
|
|
|
#region Rockwell extensions
|
|
|
|
// ======================================================================================
|
|
// Rockwell extensions to the 65C02.
|
|
//
|
|
// These are declared separately because they overlap with 65816 instructions. The
|
|
// 32 opcodes occupy the numbers $x7 and $xf.
|
|
//
|
|
|
|
private static OpDef OpBBR = new OpDef() {
|
|
IsNumberedBitOp = true,
|
|
Mnemonic = "???",
|
|
Effect = FlowEffect.ConditionalBranch,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpBBS = new OpDef() {
|
|
IsNumberedBitOp = true,
|
|
Mnemonic = "???",
|
|
Effect = FlowEffect.ConditionalBranch,
|
|
BaseMemEffect = MemoryEffect.None
|
|
};
|
|
private static OpDef OpRMB = new OpDef() {
|
|
IsNumberedBitOp = true,
|
|
Mnemonic = "???",
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite
|
|
};
|
|
private static OpDef OpSMB = new OpDef() {
|
|
IsNumberedBitOp = true,
|
|
Mnemonic = "???",
|
|
Effect = FlowEffect.Cont,
|
|
BaseMemEffect = MemoryEffect.ReadModifyWrite
|
|
};
|
|
|
|
public static readonly OpDef OpBBR0_DPPCRel = new OpDef(OpBBR) {
|
|
Mnemonic = OpName.BBR0,
|
|
Opcode = 0x0f,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBBR1_DPPCRel = new OpDef(OpBBR) {
|
|
Mnemonic = OpName.BBR1,
|
|
Opcode = 0x1f,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBBR2_DPPCRel = new OpDef(OpBBR) {
|
|
Mnemonic = OpName.BBR2,
|
|
Opcode = 0x2f,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBBR3_DPPCRel = new OpDef(OpBBR) {
|
|
Mnemonic = OpName.BBR3,
|
|
Opcode = 0x3f,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBBR4_DPPCRel = new OpDef(OpBBR) {
|
|
Mnemonic = OpName.BBR4,
|
|
Opcode = 0x4f,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBBR5_DPPCRel = new OpDef(OpBBR) {
|
|
Mnemonic = OpName.BBR5,
|
|
Opcode = 0x5f,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBBR6_DPPCRel = new OpDef(OpBBR) {
|
|
Mnemonic = OpName.BBR6,
|
|
Opcode = 0x6f,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBBR7_DPPCRel = new OpDef(OpBBR) {
|
|
Mnemonic = OpName.BBR7,
|
|
Opcode = 0x7f,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBBS0_DPPCRel = new OpDef(OpBBS) {
|
|
Mnemonic = OpName.BBS0,
|
|
Opcode = 0x8f,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBBS1_DPPCRel = new OpDef(OpBBS) {
|
|
Mnemonic = OpName.BBS1,
|
|
Opcode = 0x9f,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBBS2_DPPCRel = new OpDef(OpBBS) {
|
|
Mnemonic = OpName.BBS2,
|
|
Opcode = 0xaf,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBBS3_DPPCRel = new OpDef(OpBBS) {
|
|
Mnemonic = OpName.BBS3,
|
|
Opcode = 0xbf,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBBS4_DPPCRel = new OpDef(OpBBS) {
|
|
Mnemonic = OpName.BBS4,
|
|
Opcode = 0xcf,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBBS5_DPPCRel = new OpDef(OpBBS) {
|
|
Mnemonic = OpName.BBS5,
|
|
Opcode = 0xdf,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBBS6_DPPCRel = new OpDef(OpBBS) {
|
|
Mnemonic = OpName.BBS6,
|
|
Opcode = 0xef,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpBBS7_DPPCRel = new OpDef(OpBBS) {
|
|
Mnemonic = OpName.BBS7,
|
|
Opcode = 0xff,
|
|
AddrMode = AddressMode.DPPCRel,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpRMB0_DP = new OpDef(OpRMB) {
|
|
Mnemonic = OpName.RMB0,
|
|
Opcode = 0x07,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpRMB1_DP = new OpDef(OpRMB) {
|
|
Mnemonic = OpName.RMB1,
|
|
Opcode = 0x17,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpRMB2_DP = new OpDef(OpRMB) {
|
|
Mnemonic = OpName.RMB2,
|
|
Opcode = 0x27,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpRMB3_DP = new OpDef(OpRMB) {
|
|
Mnemonic = OpName.RMB3,
|
|
Opcode = 0x37,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpRMB4_DP = new OpDef(OpRMB) {
|
|
Mnemonic = OpName.RMB4,
|
|
Opcode = 0x47,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpRMB5_DP = new OpDef(OpRMB) {
|
|
Mnemonic = OpName.RMB5,
|
|
Opcode = 0x57,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpRMB6_DP = new OpDef(OpRMB) {
|
|
Mnemonic = OpName.RMB6,
|
|
Opcode = 0x67,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpRMB7_DP = new OpDef(OpRMB) {
|
|
Mnemonic = OpName.RMB7,
|
|
Opcode = 0x77,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpSMB0_DP = new OpDef(OpSMB) {
|
|
Mnemonic = OpName.SMB0,
|
|
Opcode = 0x87,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpSMB1_DP = new OpDef(OpSMB) {
|
|
Mnemonic = OpName.SMB1,
|
|
Opcode = 0x97,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpSMB2_DP = new OpDef(OpSMB) {
|
|
Mnemonic = OpName.SMB2,
|
|
Opcode = 0xa7,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpSMB3_DP = new OpDef(OpSMB) {
|
|
Mnemonic = OpName.SMB3,
|
|
Opcode = 0xb7,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpSMB4_DP = new OpDef(OpSMB) {
|
|
Mnemonic = OpName.SMB4,
|
|
Opcode = 0xc7,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpSMB5_DP = new OpDef(OpSMB) {
|
|
Mnemonic = OpName.SMB5,
|
|
Opcode = 0xd7,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpSMB6_DP = new OpDef(OpSMB) {
|
|
Mnemonic = OpName.SMB6,
|
|
Opcode = 0xe7,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
public static readonly OpDef OpSMB7_DP = new OpDef(OpSMB) {
|
|
Mnemonic = OpName.SMB7,
|
|
Opcode = 0xf7,
|
|
AddrMode = AddressMode.DP,
|
|
CycDef = 5
|
|
};
|
|
|
|
#endregion Rockwell extensions
|
|
|
|
|
|
/// <summary>
|
|
/// Generates one of the multiply-defined opcodes from a prototype. This is
|
|
/// particularly useful for undocumented opcodes that are repeated several times. In
|
|
/// a couple of cases (SBC, some NOPs), the undocumented opcode is just another
|
|
/// reference to an existing instruction.
|
|
/// </summary>
|
|
/// <param name="opcode">Instruction opcode.</param>
|
|
/// <param name="proto">Instruction prototype.</param>
|
|
/// <returns>Newly-created OpDef.</returns>
|
|
public static OpDef GenerateUndoc(byte opcode, OpDef proto) {
|
|
return new OpDef(proto) { Opcode = opcode, IsUndocumented = true };
|
|
}
|
|
|
|
public override string ToString() {
|
|
return Opcode.ToString("x2") + "/" + Mnemonic + " " + AddrMode;
|
|
}
|
|
}
|
|
}
|