mirror of
https://github.com/fadden/6502bench.git
synced 2024-08-17 22:29:08 +00:00
Modified the asm source generators and on-screen display to show the DP arg for BBR/BBS as hex. The instructions are otherwise treated as relative branches, e.g. the DP arg doesn't get factored into the cross-reference table. ACME/cc65 put the bit number in the mnemonic, 64tass wants it to be in the first argument, and Merlin32 wants nothing to do with any of this because it's incompatible with the 65816. Added an "all ops" test for W65C02.
3808 lines
154 KiB
C#
3808 lines
154 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 and/or continue to next)
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effect of executing an instruction on memory.
|
|
/// </summary>
|
|
public enum MemoryEffect {
|
|
Unknown = 0,
|
|
None, // e.g. TAX, PEA addr, LDA #imm
|
|
Read, // e.g. LDA addr
|
|
Write, // e.g. STA addr
|
|
ReadModifyWrite // e.g. LSR addr
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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="prevFlags">Previous flags value.</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="newFlags">New flags value. For conditional branches, this is
|
|
/// the value to use when the branch is not taken.</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) {
|
|
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;
|
|
}
|
|
}
|
|
}
|