#define op(id, name, ...) case id: return instruction##name(__VA_ARGS__);
#define fp(name) &SPC700::algorithm##name

auto SPC700::instruction() -> void {
  switch(fetch()) {
  op(0x00, NoOperation)
  op(0x01, CallTable, 0)
  op(0x02, AbsoluteBitSet, 0, true)
  op(0x03, BranchBit, 0, true)
  op(0x04, DirectRead, fp(OR), A)
  op(0x05, AbsoluteRead, fp(OR), A)
  op(0x06, IndirectXRead, fp(OR))
  op(0x07, IndexedIndirectRead, fp(OR), X)
  op(0x08, ImmediateRead, fp(OR), A)
  op(0x09, DirectDirectModify, fp(OR))
  op(0x0a, AbsoluteBitModify, 0)
  op(0x0b, DirectModify, fp(ASL))
  op(0x0c, AbsoluteModify, fp(ASL))
  op(0x0d, Push, P)
  op(0x0e, TestSetBitsAbsolute, true)
  op(0x0f, Break)
  op(0x10, Branch, NF == 0)
  op(0x11, CallTable, 1)
  op(0x12, AbsoluteBitSet, 0, false)
  op(0x13, BranchBit, 0, false)
  op(0x14, DirectIndexedRead, fp(OR), A, X)
  op(0x15, AbsoluteIndexedRead, fp(OR), X)
  op(0x16, AbsoluteIndexedRead, fp(OR), Y)
  op(0x17, IndirectIndexedRead, fp(OR), Y)
  op(0x18, DirectImmediateModify, fp(OR))
  op(0x19, IndirectXWriteIndirectY, fp(OR))
  op(0x1a, DirectModifyWord, -1)
  op(0x1b, DirectIndexedModify, fp(ASL), X)
  op(0x1c, ImpliedModify, fp(ASL), A)
  op(0x1d, ImpliedModify, fp(DEC), X)
  op(0x1e, AbsoluteRead, fp(CMP), X)
  op(0x1f, JumpIndirectX)
  op(0x20, FlagSet, PF, false)
  op(0x21, CallTable, 2)
  op(0x22, AbsoluteBitSet, 1, true)
  op(0x23, BranchBit, 1, true)
  op(0x24, DirectRead, fp(AND), A)
  op(0x25, AbsoluteRead, fp(AND), A)
  op(0x26, IndirectXRead, fp(AND))
  op(0x27, IndexedIndirectRead, fp(AND), X)
  op(0x28, ImmediateRead, fp(AND), A)
  op(0x29, DirectDirectModify, fp(AND))
  op(0x2a, AbsoluteBitModify, 1)
  op(0x2b, DirectModify, fp(ROL))
  op(0x2c, AbsoluteModify, fp(ROL))
  op(0x2d, Push, A)
  op(0x2e, BranchNotDirect)
  op(0x2f, Branch, true)
  op(0x30, Branch, NF == 1)
  op(0x31, CallTable, 3)
  op(0x32, AbsoluteBitSet, 1, false)
  op(0x33, BranchBit, 1, false)
  op(0x34, DirectIndexedRead, fp(AND), A, X)
  op(0x35, AbsoluteIndexedRead, fp(AND), X)
  op(0x36, AbsoluteIndexedRead, fp(AND), Y)
  op(0x37, IndirectIndexedRead, fp(AND), Y)
  op(0x38, DirectImmediateModify, fp(AND))
  op(0x39, IndirectXWriteIndirectY, fp(AND))
  op(0x3a, DirectModifyWord, +1)
  op(0x3b, DirectIndexedModify, fp(ROL), X)
  op(0x3c, ImpliedModify, fp(ROL), A)
  op(0x3d, ImpliedModify, fp(INC), X)
  op(0x3e, DirectRead, fp(CMP), X)
  op(0x3f, CallAbsolute)
  op(0x40, FlagSet, PF, true)
  op(0x41, CallTable, 4)
  op(0x42, AbsoluteBitSet, 2, true)
  op(0x43, BranchBit, 2, true)
  op(0x44, DirectRead, fp(EOR), A)
  op(0x45, AbsoluteRead, fp(EOR), A)
  op(0x46, IndirectXRead, fp(EOR))
  op(0x47, IndexedIndirectRead, fp(EOR), X)
  op(0x48, ImmediateRead, fp(EOR), A)
  op(0x49, DirectDirectModify, fp(EOR))
  op(0x4a, AbsoluteBitModify, 2)
  op(0x4b, DirectModify, fp(LSR))
  op(0x4c, AbsoluteModify, fp(LSR))
  op(0x4d, Push, X)
  op(0x4e, TestSetBitsAbsolute, false)
  op(0x4f, CallPage)
  op(0x50, Branch, VF == 0)
  op(0x51, CallTable, 5)
  op(0x52, AbsoluteBitSet, 2, false)
  op(0x53, BranchBit, 2, false)
  op(0x54, DirectIndexedRead, fp(EOR), A, X)
  op(0x55, AbsoluteIndexedRead, fp(EOR), X)
  op(0x56, AbsoluteIndexedRead, fp(EOR), Y)
  op(0x57, IndirectIndexedRead, fp(EOR), Y)
  op(0x58, DirectImmediateModify, fp(EOR))
  op(0x59, IndirectXWriteIndirectY, fp(EOR))
  op(0x5a, DirectCompareWord, fp(CPW))
  op(0x5b, DirectIndexedModify, fp(LSR), X)
  op(0x5c, ImpliedModify, fp(LSR), A)
  op(0x5d, Transfer, A, X)
  op(0x5e, AbsoluteRead, fp(CMP), Y)
  op(0x5f, JumpAbsolute)
  op(0x60, FlagSet, CF, false)
  op(0x61, CallTable, 6)
  op(0x62, AbsoluteBitSet, 3, true)
  op(0x63, BranchBit, 3, true)
  op(0x64, DirectRead, fp(CMP), A)
  op(0x65, AbsoluteRead, fp(CMP), A)
  op(0x66, IndirectXRead, fp(CMP))
  op(0x67, IndexedIndirectRead, fp(CMP), X)
  op(0x68, ImmediateRead, fp(CMP), A)
  op(0x69, DirectDirectCompare, fp(CMP))
  op(0x6a, AbsoluteBitModify, 3)
  op(0x6b, DirectModify, fp(ROR))
  op(0x6c, AbsoluteModify, fp(ROR))
  op(0x6d, Push, Y)
  op(0x6e, BranchNotDirectDecrement)
  op(0x6f, ReturnSubroutine)
  op(0x70, Branch, VF == 1)
  op(0x71, CallTable, 7)
  op(0x72, AbsoluteBitSet, 3, false)
  op(0x73, BranchBit, 3, false)
  op(0x74, DirectIndexedRead, fp(CMP), A, X)
  op(0x75, AbsoluteIndexedRead, fp(CMP), X)
  op(0x76, AbsoluteIndexedRead, fp(CMP), Y)
  op(0x77, IndirectIndexedRead, fp(CMP), Y)
  op(0x78, DirectImmediateCompare, fp(CMP))
  op(0x79, IndirectXCompareIndirectY, fp(CMP))
  op(0x7a, DirectReadWord, fp(ADW))
  op(0x7b, DirectIndexedModify, fp(ROR), X)
  op(0x7c, ImpliedModify, fp(ROR), A)
  op(0x7d, Transfer, X, A)
  op(0x7e, DirectRead, fp(CMP), Y)
  op(0x7f, ReturnInterrupt)
  op(0x80, FlagSet, CF, true)
  op(0x81, CallTable, 8)
  op(0x82, AbsoluteBitSet, 4, true)
  op(0x83, BranchBit, 4, true)
  op(0x84, DirectRead, fp(ADC), A)
  op(0x85, AbsoluteRead, fp(ADC), A)
  op(0x86, IndirectXRead, fp(ADC))
  op(0x87, IndexedIndirectRead, fp(ADC), X)
  op(0x88, ImmediateRead, fp(ADC), A)
  op(0x89, DirectDirectModify, fp(ADC))
  op(0x8a, AbsoluteBitModify, 4)
  op(0x8b, DirectModify, fp(DEC))
  op(0x8c, AbsoluteModify, fp(DEC))
  op(0x8d, ImmediateRead, fp(LD), Y)
  op(0x8e, PullP)
  op(0x8f, DirectImmediateWrite)
  op(0x90, Branch, CF == 0)
  op(0x91, CallTable, 9)
  op(0x92, AbsoluteBitSet, 4, false)
  op(0x93, BranchBit, 4, false)
  op(0x94, DirectIndexedRead, fp(ADC), A, X)
  op(0x95, AbsoluteIndexedRead, fp(ADC), X)
  op(0x96, AbsoluteIndexedRead, fp(ADC), Y)
  op(0x97, IndirectIndexedRead, fp(ADC), Y)
  op(0x98, DirectImmediateModify, fp(ADC))
  op(0x99, IndirectXWriteIndirectY, fp(ADC))
  op(0x9a, DirectReadWord, fp(SBW))
  op(0x9b, DirectIndexedModify, fp(DEC), X)
  op(0x9c, ImpliedModify, fp(DEC), A)
  op(0x9d, Transfer, S, X)
  op(0x9e, Divide)
  op(0x9f, ExchangeNibble)
  op(0xa0, FlagSet, IF, true)
  op(0xa1, CallTable, 10)
  op(0xa2, AbsoluteBitSet, 5, true)
  op(0xa3, BranchBit, 5, true)
  op(0xa4, DirectRead, fp(SBC), A)
  op(0xa5, AbsoluteRead, fp(SBC), A)
  op(0xa6, IndirectXRead, fp(SBC))
  op(0xa7, IndexedIndirectRead, fp(SBC), X)
  op(0xa8, ImmediateRead, fp(SBC), A)
  op(0xa9, DirectDirectModify, fp(SBC))
  op(0xaa, AbsoluteBitModify, 5)
  op(0xab, DirectModify, fp(INC))
  op(0xac, AbsoluteModify, fp(INC))
  op(0xad, ImmediateRead, fp(CMP), Y)
  op(0xae, Pull, A)
  op(0xaf, IndirectXIncrementWrite, A)
  op(0xb0, Branch, CF == 1)
  op(0xb1, CallTable, 11)
  op(0xb2, AbsoluteBitSet, 5, false)
  op(0xb3, BranchBit, 5, false)
  op(0xb4, DirectIndexedRead, fp(SBC), A, X)
  op(0xb5, AbsoluteIndexedRead, fp(SBC), X)
  op(0xb6, AbsoluteIndexedRead, fp(SBC), Y)
  op(0xb7, IndirectIndexedRead, fp(SBC), Y)
  op(0xb8, DirectImmediateModify, fp(SBC))
  op(0xb9, IndirectXWriteIndirectY, fp(SBC))
  op(0xba, DirectReadWord, fp(LDW))
  op(0xbb, DirectIndexedModify, fp(INC), X)
  op(0xbc, ImpliedModify, fp(INC), A)
  op(0xbd, Transfer, X, S)
  op(0xbe, DecimalAdjustSub)
  op(0xbf, IndirectXIncrementRead, A)
  op(0xc0, FlagSet, IF, false)
  op(0xc1, CallTable, 12)
  op(0xc2, AbsoluteBitSet, 6, true)
  op(0xc3, BranchBit, 6, true)
  op(0xc4, DirectWrite, A)
  op(0xc5, AbsoluteWrite, A)
  op(0xc6, IndirectXWrite, A)
  op(0xc7, IndexedIndirectWrite, A, X)
  op(0xc8, ImmediateRead, fp(CMP), X)
  op(0xc9, AbsoluteWrite, X)
  op(0xca, AbsoluteBitModify, 6)
  op(0xcb, DirectWrite, Y)
  op(0xcc, AbsoluteWrite, Y)
  op(0xcd, ImmediateRead, fp(LD), X)
  op(0xce, Pull, X)
  op(0xcf, Multiply)
  op(0xd0, Branch, ZF == 0)
  op(0xd1, CallTable, 13)
  op(0xd2, AbsoluteBitSet, 6, false)
  op(0xd3, BranchBit, 6, false)
  op(0xd4, DirectIndexedWrite, A, X)
  op(0xd5, AbsoluteIndexedWrite, X)
  op(0xd6, AbsoluteIndexedWrite, Y)
  op(0xd7, IndirectIndexedWrite, A, Y)
  op(0xd8, DirectWrite, X)
  op(0xd9, DirectIndexedWrite, X, Y)
  op(0xda, DirectWriteWord)
  op(0xdb, DirectIndexedWrite, Y, X)
  op(0xdc, ImpliedModify, fp(DEC), Y)
  op(0xdd, Transfer, Y, A)
  op(0xde, BranchNotDirectIndexed, X)
  op(0xdf, DecimalAdjustAdd)
  op(0xe0, OverflowClear)
  op(0xe1, CallTable, 14)
  op(0xe2, AbsoluteBitSet, 7, true)
  op(0xe3, BranchBit, 7, true)
  op(0xe4, DirectRead, fp(LD), A)
  op(0xe5, AbsoluteRead, fp(LD), A)
  op(0xe6, IndirectXRead, fp(LD))
  op(0xe7, IndexedIndirectRead, fp(LD), X)
  op(0xe8, ImmediateRead, fp(LD), A)
  op(0xe9, AbsoluteRead, fp(LD), X)
  op(0xea, AbsoluteBitModify, 7)
  op(0xeb, DirectRead, fp(LD), Y)
  op(0xec, AbsoluteRead, fp(LD), Y)
  op(0xed, ComplementCarry)
  op(0xee, Pull, Y)
  op(0xef, Wait)
  op(0xf0, Branch, ZF == 1)
  op(0xf1, CallTable, 15)
  op(0xf2, AbsoluteBitSet, 7, false)
  op(0xf3, BranchBit, 7, false)
  op(0xf4, DirectIndexedRead, fp(LD), A, X)
  op(0xf5, AbsoluteIndexedRead, fp(LD), X)
  op(0xf6, AbsoluteIndexedRead, fp(LD), Y)
  op(0xf7, IndirectIndexedRead, fp(LD), Y)
  op(0xf8, DirectRead, fp(LD), X)
  op(0xf9, DirectIndexedRead, fp(LD), X, Y)
  op(0xfa, DirectDirectWrite)
  op(0xfb, DirectIndexedRead, fp(LD), Y, X)
  op(0xfc, ImpliedModify, fp(INC), Y)
  op(0xfd, Transfer, A, Y)
  op(0xfe, BranchNotYDecrement)
  op(0xff, Stop)
  }
}

#undef op
#undef fp
