from collections import namedtuple
from enum import Enum

Instruction = namedtuple("Instruction", ["bytecode", "size_bytes", "cycles"])
NamedInstruction = namedtuple("NamedInstruction", ["bytecode", "size_bytes", "cycles", "name", "mode"])
PyNamedInstruction = namedtuple("NamedInstruction", ["bytecode", "size_bytes", "cycles", "name", "mode", "function"])
InstructionSet = namedtuple("InstructionSet", ["name", "modes"])


class AddressModes(Enum):
    IMMEDIATE = 0
    ZEROPAGE = 1
    ZEROPAGE_X = 2
    ZEROPAGE_Y = 20   # this is only used in LDX and STX in place of ZEROPAGE_X
    ABSOLUTE = 3
    ABSOLUTE_X = 4
    ABSOLUTE_Y = 5
    INDIRECT_X = 6
    INDIRECT_Y = 7
    IMPLIED = 10
    RELATIVE = 11
    ACCUMULATOR = 12
    INDIRECT = 13

INSTRUCTION_SET = {
    "ADC": InstructionSet(name="adc",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=0x69, size_bytes=2, cycles=2),
                                 AddressModes.ZEROPAGE:   Instruction(bytecode=0x65, size_bytes=2, cycles=3),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0x75, size_bytes=2, cycles=4),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x6D, size_bytes=3, cycles=4),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0x7D, size_bytes=3, cycles=4.1),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0x79, size_bytes=3, cycles=4.1),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0x61, size_bytes=2, cycles=6),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0x71, size_bytes=2, cycles=5.1),
                                }
                          ),
    "AND": InstructionSet(name="and",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=0x29, size_bytes=2, cycles=2),
                                 AddressModes.ZEROPAGE:   Instruction(bytecode=0x25, size_bytes=2, cycles=3),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0x35, size_bytes=2, cycles=4),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x2D, size_bytes=3, cycles=4),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0x3D, size_bytes=3, cycles=4.1),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0x39, size_bytes=3, cycles=4.1),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0x21, size_bytes=2, cycles=6),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0x31, size_bytes=2, cycles=5.1),
                                }
                          ),
    "ASL": InstructionSet(name="asl",
                          modes={AddressModes.ACCUMULATOR:Instruction(bytecode=0x0A, size_bytes=1, cycles=2),
                                 AddressModes.ZEROPAGE:   Instruction(bytecode=0x06, size_bytes=2, cycles=5),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0x16, size_bytes=2, cycles=6),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x0E, size_bytes=3, cycles=6),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0x1E, size_bytes=3, cycles=7),
                                }
                          ),
    "BCC": InstructionSet(name="bcc",
                          modes={AddressModes.RELATIVE:   Instruction(bytecode=0x90, size_bytes=2, cycles=2.12)}),
    "BCS": InstructionSet(name="bcs",
                          modes={AddressModes.RELATIVE:   Instruction(bytecode=0xB0, size_bytes=2, cycles=2.12)}),
    "BEQ": InstructionSet(name="beq",
                          modes={AddressModes.RELATIVE:   Instruction(bytecode=0xF0, size_bytes=2, cycles=2.12)}),
    "BIT": InstructionSet(name="bit",
                          modes={AddressModes.ZEROPAGE:   Instruction(bytecode=0x24, size_bytes=2, cycles=3),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x2C, size_bytes=3, cycles=4),
                                }
                          ),
    "BMI": InstructionSet(name="bmi",
                          modes={AddressModes.RELATIVE:   Instruction(bytecode=0x30, size_bytes=2, cycles=2.12)}),
    "BNE": InstructionSet(name="bne",
                          modes={AddressModes.RELATIVE:   Instruction(bytecode=0xD0, size_bytes=2, cycles=2.12)}),
    "BPL": InstructionSet(name="bpl",
                          modes={AddressModes.RELATIVE:   Instruction(bytecode=0x10, size_bytes=2, cycles=2.12)}),
    # note that the size of BRK is slightly controversial, because BRK forces PC+2 to be pushed onto the stack,
    # meaning that the instruction immediately after BRK will never be executed unless there is a workaround applied
    # therefore BRK should usually be followed by NOP, and many assemblers seem to do this
    "BRK": InstructionSet(name="brk",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0x00, size_bytes=1, cycles=7)}),
    "BVC": InstructionSet(name="bvc",
                          modes={AddressModes.RELATIVE:   Instruction(bytecode=0x50, size_bytes=2, cycles=2.12)}),
    "BVS": InstructionSet(name="bvs",
                          modes={AddressModes.RELATIVE:   Instruction(bytecode=0x70, size_bytes=2, cycles=2.12)}),
    "CLC": InstructionSet(name="clc",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0x18, size_bytes=1, cycles=2)}),
    "CLD": InstructionSet(name="cld",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0xD8, size_bytes=1, cycles=2)}),
    "CLI": InstructionSet(name="cli",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0x58, size_bytes=1, cycles=2)}),
    "CLV": InstructionSet(name="clv",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0xB8, size_bytes=1, cycles=2)}),
    "CMP": InstructionSet(name="cmp",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=0xC9, size_bytes=2, cycles=2),
                                 AddressModes.ZEROPAGE:   Instruction(bytecode=0xC5, size_bytes=2, cycles=3),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0xD5, size_bytes=2, cycles=4),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0xCD, size_bytes=3, cycles=4),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0xDD, size_bytes=3, cycles=4.1),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0xD9, size_bytes=3, cycles=4.1),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0xC1, size_bytes=2, cycles=6),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0xD1, size_bytes=2, cycles=5.1),
                                }
                          ),
    "CPX": InstructionSet(name="cpx",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=0xE0, size_bytes=2, cycles=2),
                                 AddressModes.ZEROPAGE:   Instruction(bytecode=0xE4, size_bytes=2, cycles=3),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0xEC, size_bytes=3, cycles=4),
                                }
                          ),
    "CPY": InstructionSet(name="cpy",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=0xC0, size_bytes=2, cycles=2),
                                 AddressModes.ZEROPAGE:   Instruction(bytecode=0xC4, size_bytes=2, cycles=3),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0xCC, size_bytes=3, cycles=4),
                                }
                          ),
    "DEC": InstructionSet(name="dec",
                          modes={AddressModes.ZEROPAGE:   Instruction(bytecode=0xC6, size_bytes=2, cycles=5),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0xD6, size_bytes=2, cycles=6),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0xCE, size_bytes=3, cycles=6),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0xDE, size_bytes=3, cycles=7),
                                }
                          ),
    "DEX": InstructionSet(name="dex",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0xCA, size_bytes=1, cycles=2)}),
    "DEY": InstructionSet(name="dey",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0x88, size_bytes=1, cycles=2)}),
    "EOR": InstructionSet(name="eor",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=0x49, size_bytes=2, cycles=2),
                                 AddressModes.ZEROPAGE:   Instruction(bytecode=0x45, size_bytes=2, cycles=3),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0x55, size_bytes=2, cycles=4),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x4D, size_bytes=3, cycles=4),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0x5D, size_bytes=3, cycles=4.1),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0x59, size_bytes=3, cycles=4.1),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0x41, size_bytes=2, cycles=6),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0x51, size_bytes=2, cycles=5.1),
                                }
                          ),
    "INC": InstructionSet(name="inc",
                          modes={AddressModes.ZEROPAGE:   Instruction(bytecode=0xE6, size_bytes=2, cycles=5),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0xF6, size_bytes=2, cycles=6),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0xEE, size_bytes=3, cycles=6),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0xFE, size_bytes=3, cycles=7),
                                 }
                          ),
    "INX": InstructionSet(name="inx",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0xE8, size_bytes=1, cycles=2)}),
    "INY": InstructionSet(name="iny",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0xC8, size_bytes=1, cycles=2)}),
    "JMP": InstructionSet(name="jmp",
                          modes={AddressModes.ABSOLUTE:   Instruction(bytecode=0x4C, size_bytes=3, cycles=3),
                                 AddressModes.INDIRECT:   Instruction(bytecode=0x6C, size_bytes=3, cycles=5),
                                 }
                          ),
    "JSR": InstructionSet(name="jsr",
                          modes={AddressModes.ABSOLUTE:   Instruction(bytecode=0x20, size_bytes=3, cycles=6)}),
    "LDA": InstructionSet(name="lda",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=0xA9, size_bytes=2, cycles=2),
                                 AddressModes.ZEROPAGE:   Instruction(bytecode=0xA5, size_bytes=2, cycles=3),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0xB5, size_bytes=2, cycles=4),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0xAD, size_bytes=3, cycles=4),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0xBD, size_bytes=3, cycles=4.1),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0xB9, size_bytes=3, cycles=4.1),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0xA1, size_bytes=2, cycles=6),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0xB1, size_bytes=2, cycles=5.1),
                                 }
                          ),
    "LDX": InstructionSet(name="ldx",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=0xA2, size_bytes=2, cycles=2),
                                 AddressModes.ZEROPAGE:   Instruction(bytecode=0xA6, size_bytes=2, cycles=3),
                                 AddressModes.ZEROPAGE_Y: Instruction(bytecode=0xB6, size_bytes=2, cycles=4),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0xAE, size_bytes=3, cycles=4),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0xBE, size_bytes=3, cycles=4.1),
                                 }
                          ),
    "LDY": InstructionSet(name="ldy",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=0xA0, size_bytes=2, cycles=2),
                                 AddressModes.ZEROPAGE:   Instruction(bytecode=0xA4, size_bytes=2, cycles=3),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0xB4, size_bytes=2, cycles=4),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0xAC, size_bytes=3, cycles=4),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0xBC, size_bytes=3, cycles=4.1),
                                }
                          ),
    "LSR": InstructionSet(name="lsr",
                          modes={AddressModes.ACCUMULATOR:Instruction(bytecode=0x4A, size_bytes=1, cycles=2),
                                 AddressModes.ZEROPAGE:   Instruction(bytecode=0x46, size_bytes=2, cycles=5),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0x56, size_bytes=2, cycles=6),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x4E, size_bytes=3, cycles=6),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0x5E, size_bytes=3, cycles=7),
                                 }
                          ),
    "NOP": InstructionSet(name="nop",
                          # the codes after the first code are undocumented NOP codes
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=[0xEA, 0x1A, 0x3A, 0x5A, 0x7A, 0xDA, 0xFA], size_bytes=1, cycles=2)}),
    "ORA": InstructionSet(name="ora",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=0x09, size_bytes=2, cycles=2),
                                 AddressModes.ZEROPAGE:   Instruction(bytecode=0x05, size_bytes=2, cycles=3),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0x15, size_bytes=2, cycles=4),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x0D, size_bytes=3, cycles=4),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0x1D, size_bytes=3, cycles=4.1),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0x19, size_bytes=3, cycles=4.1),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0x01, size_bytes=2, cycles=6),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0x11, size_bytes=2, cycles=5.1),
                                 }
                          ),
    "PHA": InstructionSet(name="pha",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0x48, size_bytes=1, cycles=3)}),
    "PHP": InstructionSet(name="php",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0x08, size_bytes=1, cycles=3)}),
    "PLA": InstructionSet(name="pla",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0x68, size_bytes=1, cycles=4)}),
    "PLP": InstructionSet(name="plp",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0x28, size_bytes=1, cycles=4)}),
    "ROL": InstructionSet(name="rol",
                          modes={AddressModes.ACCUMULATOR:Instruction(bytecode=0x2A, size_bytes=1, cycles=2),
                                 AddressModes.ZEROPAGE:   Instruction(bytecode=0x26, size_bytes=2, cycles=5),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0x36, size_bytes=2, cycles=6),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x2E, size_bytes=3, cycles=6),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0x3E, size_bytes=3, cycles=7),
                                 }
                          ),
    "ROR": InstructionSet(name="ror",
                          modes={AddressModes.ACCUMULATOR:Instruction(bytecode=0x6A, size_bytes=1, cycles=2),
                                 AddressModes.ZEROPAGE:   Instruction(bytecode=0x66, size_bytes=2, cycles=5),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0x76, size_bytes=2, cycles=6),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x6E, size_bytes=3, cycles=6),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0x7E, size_bytes=3, cycles=7),
                                 }
                          ),
    "RTI": InstructionSet(name="rti",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0x40, size_bytes=1, cycles=6)}),
    "RTS": InstructionSet(name="rts",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0x60, size_bytes=1, cycles=6)}),
    "SBC": InstructionSet(name="sbc",
                          # the second code for the immediate version is an illegal opcode
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=[0xE9, 0xEB], size_bytes=2, cycles=2),
                                 AddressModes.ZEROPAGE:   Instruction(bytecode=0xE5, size_bytes=2, cycles=3),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0xF5, size_bytes=2, cycles=4),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0xED, size_bytes=3, cycles=4),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0xFD, size_bytes=3, cycles=4.1),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0xF9, size_bytes=3, cycles=4.1),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0xE1, size_bytes=2, cycles=6),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0xF1, size_bytes=2, cycles=5.1),
                                 }
                          ),
    "SEC": InstructionSet(name="sec",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0x38, size_bytes=1, cycles=2)}),
    "SED": InstructionSet(name="sed",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0xF8, size_bytes=1, cycles=2)}),
    "SEI": InstructionSet(name="sei",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0x78, size_bytes=1, cycles=2)}),
    "STA": InstructionSet(name="sta",
                          modes={AddressModes.ZEROPAGE:   Instruction(bytecode=0x85, size_bytes=2, cycles=3),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0x95, size_bytes=2, cycles=4),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x8D, size_bytes=3, cycles=4),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0x9D, size_bytes=3, cycles=5),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0x99, size_bytes=3, cycles=5),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0x81, size_bytes=2, cycles=6),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0x91, size_bytes=2, cycles=6),
                                 }
                          ),
    "STX": InstructionSet(name="stx",
                          modes={AddressModes.ZEROPAGE:   Instruction(bytecode=0x86, size_bytes=2, cycles=3),
                                 AddressModes.ZEROPAGE_Y: Instruction(bytecode=0x96, size_bytes=2, cycles=4),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x8E, size_bytes=3, cycles=4),
                                 }
                          ),
    "STY": InstructionSet(name="sty",
                          modes={AddressModes.ZEROPAGE:   Instruction(bytecode=0x84, size_bytes=2, cycles=3),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0x94, size_bytes=2, cycles=4),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x8C, size_bytes=3, cycles=4),
                                 }
                          ),
    "TAX": InstructionSet(name="tax",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0xAA, size_bytes=1, cycles=2)}),
    "TAY": InstructionSet(name="tay",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0xA8, size_bytes=1, cycles=2)}),
    "TSX": InstructionSet(name="tsx",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0xBA, size_bytes=1, cycles=2)}),
    "TXA": InstructionSet(name="txa",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0x8A, size_bytes=1, cycles=2)}),
    "TXS": InstructionSet(name="txs",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0x9A, size_bytes=1, cycles=2)}),
    "TYA": InstructionSet(name="tya",
                          modes={AddressModes.IMPLIED:    Instruction(bytecode=0x98, size_bytes=1, cycles=2)}),

    # Undocumented instructions below here
    # naming convention is from http://nesdev.com/undocumented_opcodes.txt, several others exist
    "DOP": InstructionSet(name="dop",
                          modes={AddressModes.ZEROPAGE:   Instruction(bytecode=[0x04, 0x14, 0x44, 0x64], size_bytes=2, cycles=3),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=[0x14, 0x34, 0x54, 0x74, 0xD4, 0xF4], size_bytes=2, cycles=4),
                                 AddressModes.IMMEDIATE:  Instruction(bytecode=[0x80, 0x82, 0x89, 0xC2, 0xE2], size_bytes=2, cycles=2),
                                 }
                          ),
    "TOP": InstructionSet(name="top",
                          modes={AddressModes.ABSOLUTE:   Instruction(bytecode=0x0C, size_bytes=3, cycles=4),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=[0x1C, 0x3C, 0x5C, 0x7C, 0xDC, 0xFC], size_bytes=3, cycles=4.1),
                                 }
                          ),
    "KIL": InstructionSet(name="kil",
                      modes={AddressModes.IMPLIED:        Instruction(bytecode=[0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, 0x92, 0xB2, 0xD2, 0xF2], size_bytes=1, cycles=1),
                             }
                         ),
    "LAX": InstructionSet(name="lax",
                          modes={AddressModes.ZEROPAGE:   Instruction(bytecode=0xA7, size_bytes=2, cycles=3),
                                 AddressModes.ZEROPAGE_Y: Instruction(bytecode=0xB7, size_bytes=2, cycles=4),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0xAF, size_bytes=3, cycles=4),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0xBF, size_bytes=3, cycles=4.1),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0xA3, size_bytes=2, cycles=6),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0xB3, size_bytes=2, cycles=5.1),
                                 }
                          ),
    "AAX": InstructionSet(name="aax",
                          modes={AddressModes.ZEROPAGE:   Instruction(bytecode=0x87, size_bytes=2, cycles=3),
                                 AddressModes.ZEROPAGE_Y: Instruction(bytecode=0x97, size_bytes=2, cycles=4),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0x83, size_bytes=2, cycles=6),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x8F, size_bytes=3, cycles=4),
                                 }
                          ),
    "DCP": InstructionSet(name="dcp",
                          modes={AddressModes.ZEROPAGE:   Instruction(bytecode=0xC7, size_bytes=2, cycles=5),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0xD7, size_bytes=2, cycles=6),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0xCF, size_bytes=3, cycles=6),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0xDF, size_bytes=3, cycles=7),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0xDB, size_bytes=3, cycles=7),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0xC3, size_bytes=2, cycles=8),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0xD3, size_bytes=2, cycles=8),
                                 }
                          ),
    "ISC": InstructionSet(name="isc",
                          modes={AddressModes.ZEROPAGE:   Instruction(bytecode=0xE7, size_bytes=2, cycles=5),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0xF7, size_bytes=2, cycles=6),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0xEF, size_bytes=3, cycles=6),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0xFF, size_bytes=3, cycles=7),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0xFB, size_bytes=3, cycles=7),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0xE3, size_bytes=2, cycles=8),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0xF3, size_bytes=2, cycles=8),
                                 }
                          ),
    "SLO": InstructionSet(name="slo",
                          modes={AddressModes.ZEROPAGE:   Instruction(bytecode=0x07, size_bytes=2, cycles=5),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0x17, size_bytes=2, cycles=6),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x0F, size_bytes=3, cycles=6),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0x1F, size_bytes=3, cycles=7),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0x1B, size_bytes=3, cycles=7),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0x03, size_bytes=2, cycles=8),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0x13, size_bytes=2, cycles=8),
                                 }
                          ),
    "RLA": InstructionSet(name="rla",
                          modes={AddressModes.ZEROPAGE:   Instruction(bytecode=0x27, size_bytes=2, cycles=5),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0x37, size_bytes=2, cycles=6),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x2F, size_bytes=3, cycles=6),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0x3F, size_bytes=3, cycles=7),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0x3B, size_bytes=3, cycles=7),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0x23, size_bytes=2, cycles=8),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0x33, size_bytes=2, cycles=8),
                                 }
                          ),
    "SRE": InstructionSet(name="sre",
                          modes={AddressModes.ZEROPAGE:   Instruction(bytecode=0x47, size_bytes=2, cycles=5),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0x57, size_bytes=2, cycles=6),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x4F, size_bytes=3, cycles=6),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0x5F, size_bytes=3, cycles=7),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0x5B, size_bytes=3, cycles=7),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0x43, size_bytes=2, cycles=8),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0x53, size_bytes=2, cycles=8),
                                 }
                          ),
    "RRA": InstructionSet(name="rra",
                          modes={AddressModes.ZEROPAGE:   Instruction(bytecode=0x67, size_bytes=2, cycles=5),
                                 AddressModes.ZEROPAGE_X: Instruction(bytecode=0x77, size_bytes=2, cycles=6),
                                 AddressModes.ABSOLUTE:   Instruction(bytecode=0x6F, size_bytes=3, cycles=6),
                                 AddressModes.ABSOLUTE_X: Instruction(bytecode=0x7F, size_bytes=3, cycles=7),
                                 AddressModes.ABSOLUTE_Y: Instruction(bytecode=0x7B, size_bytes=3, cycles=7),
                                 AddressModes.INDIRECT_X: Instruction(bytecode=0x63, size_bytes=2, cycles=8),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0x73, size_bytes=2, cycles=8),
                                 }
                          ),
    # Implemented but untested
    "ARR": InstructionSet(name="arr",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=0x6B, size_bytes=2, cycles=2),
                                 }
                          ),
    "ASR": InstructionSet(name="asr",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=0x4B, size_bytes=2, cycles=2),
                                 }
                          ),
    "ATX": InstructionSet(name="atx",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=0xAB, size_bytes=2, cycles=2),
                                 }
                          ),
    "AAC": InstructionSet(name="aac",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=[0x0B, 0x2B], size_bytes=2, cycles=2),
                                 }
                          ),
    "AXA": InstructionSet(name="axa",
                          modes={AddressModes.ABSOLUTE_Y: Instruction(bytecode=0x9F, size_bytes=3, cycles=5),
                                 AddressModes.INDIRECT_Y: Instruction(bytecode=0x93, size_bytes=2, cycles=6),
                                 }
                          ),
    "AXS": InstructionSet(name="axs",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=0xCB, size_bytes=2, cycles=2),
                                 }
                          ),
    "LAR": InstructionSet(name="lar",
                          modes={AddressModes.ABSOLUTE_Y: Instruction(bytecode=0xBB, size_bytes=3, cycles=4.1),
                                 }
                          ),
    "SXA": InstructionSet(name="sxa",
                          modes={AddressModes.ABSOLUTE_Y: Instruction(bytecode=0x9E, size_bytes=3, cycles=5),
                                 }
                          ),
    "SYA": InstructionSet(name="sya",
                          modes={AddressModes.ABSOLUTE_X: Instruction(bytecode=0x9C, size_bytes=3, cycles=5),
                                 }
                          ),
    "XAA": InstructionSet(name="xaa",
                          modes={AddressModes.IMMEDIATE:  Instruction(bytecode=0x8B, size_bytes=2, cycles=2),
                                 }
                          ),
    "XAS": InstructionSet(name="xas",
                          modes={AddressModes.ABSOLUTE_Y: Instruction(bytecode=0x9B, size_bytes=3, cycles=5),
                                 }
                          ),
}