package cpu import "fmt" type opcodeEntry struct { name string mode AddrMode cycles int pageCrossPenalty bool exec func(c *CPU, op operand) } var opcodeTable [256]opcodeEntry func def(code uint8, name string, mode AddrMode, cycles int, pageCrossPenalty bool, exec func(*CPU, operand)) { opcodeTable[code] = opcodeEntry{name, mode, cycles, pageCrossPenalty, exec} } func init() { for i := 0; i < 256; i++ { code := uint8(i) opcodeTable[i] = opcodeEntry{ name: "???", mode: ModeImplied, exec: func(c *CPU, op operand) { panic(fmt.Sprintf("cpu: unimplemented or illegal opcode 0x%02X", code)) }, } } // load accumulator def(0xA9, "LDA", ModeImmediate, 2, false, ldaExec) def(0xA5, "LDA", ModeZeroPage, 3, false, ldaExec) def(0xB5, "LDA", ModeZeroPageX, 4, false, ldaExec) def(0xAD, "LDA", ModeAbsolute, 4, false, ldaExec) def(0xBD, "LDA", ModeAbsoluteX, 4, true, ldaExec) def(0xB9, "LDA", ModeAbsoluteY, 4, true, ldaExec) def(0xA1, "LDA", ModeIndirectX, 6, false, ldaExec) def(0xB1, "LDA", ModeIndirectY, 5, true, ldaExec) // load X def(0xA2, "LDX", ModeImmediate, 2, false, ldxExec) def(0xA6, "LDX", ModeZeroPage, 3, false, ldxExec) def(0xB6, "LDX", ModeZeroPageY, 4, false, ldxExec) def(0xAE, "LDX", ModeAbsolute, 4, false, ldxExec) def(0xBE, "LDX", ModeAbsoluteY, 4, true, ldxExec) // load Y def(0xA0, "LDY", ModeImmediate, 2, false, ldyExec) def(0xA4, "LDY", ModeZeroPage, 3, false, ldyExec) def(0xB4, "LDY", ModeZeroPageX, 4, false, ldyExec) def(0xAC, "LDY", ModeAbsolute, 4, false, ldyExec) def(0xBC, "LDY", ModeAbsoluteX, 4, true, ldyExec) // store accumulator def(0x85, "STA", ModeZeroPage, 3, false, staExec) def(0x95, "STA", ModeZeroPageX, 4, false, staExec) def(0x8D, "STA", ModeAbsolute, 4, false, staExec) def(0x9D, "STA", ModeAbsoluteX, 5, false, staExec) def(0x99, "STA", ModeAbsoluteY, 5, false, staExec) def(0x81, "STA", ModeIndirectX, 6, false, staExec) def(0x91, "STA", ModeIndirectY, 6, false, staExec) // store X def(0x86, "STX", ModeZeroPage, 3, false, stxExec) def(0x96, "STX", ModeZeroPageY, 4, false, stxExec) def(0x8E, "STX", ModeAbsolute, 4, false, stxExec) // store Y def(0x84, "STY", ModeZeroPage, 3, false, styExec) def(0x94, "STY", ModeZeroPageX, 4, false, styExec) def(0x8C, "STY", ModeAbsolute, 4, false, styExec) // transfer accumulator to X def(0xAA, "TAX", ModeImplied, 2, false, taxExec) // transfer x to accumulator def(0x8A, "TXA", ModeImplied, 2, false, txaExec) // transfer accumulator to Y def(0xA8, "TAY", ModeImplied, 2, false, tayExec) // transfer y to accumulator def(0x98, "TYA", ModeImplied, 2, false, tyaExec) // transfer stack pointer to x def(0xBA, "TSX", ModeImplied, 2, false, tsxExec) // transfer x to stack pointer def(0x9A, "TXS", ModeImplied, 2, false, txsExec) // push accumulator def(0x48, "PHA", ModeImplied, 3, false, phaExec) // pull accumulator def(0x68, "PLA", ModeImplied, 4, false, plaExec) // originally personal homepage, now PHP: Hypertext Preprocessor // totally not push processor status (SR) def(0x08, "PHP", ModeImplied, 3, false, phpExec) // pull processor status (SR) def(0x28, "PLP", ModeImplied, 4, false, plpExec) // add with carry def(0x69, "ADC", ModeImmediate, 2, false, adcExec) def(0x65, "ADC", ModeZeroPage, 3, false, adcExec) def(0x75, "ADC", ModeZeroPageX, 4, false, adcExec) def(0x6D, "ADC", ModeAbsolute, 4, false, adcExec) def(0x7D, "ADC", ModeAbsoluteX, 4, true, adcExec) def(0x79, "ADC", ModeAbsoluteY, 4, true, adcExec) def(0x61, "ADC", ModeIndirectX, 6, false, adcExec) def(0x71, "ADC", ModeIndirectY, 5, true, adcExec) // subtract with carry def(0xE9, "SBC", ModeImmediate, 2, false, sbcExec) def(0xEB, "SBC", ModeImmediate, 2, false, sbcExec) def(0xE5, "SBC", ModeZeroPage, 3, false, sbcExec) def(0xF5, "SBC", ModeZeroPageX, 4, false, sbcExec) def(0xED, "SBC", ModeAbsolute, 4, false, sbcExec) def(0xFD, "SBC", ModeAbsoluteX, 4, true, sbcExec) def(0xF9, "SBC", ModeAbsoluteY, 4, true, sbcExec) def(0xE1, "SBC", ModeIndirectX, 6, false, sbcExec) def(0xF1, "SBC", ModeIndirectY, 5, true, sbcExec) // and (with accumulator) def(0x29, "AND", ModeImmediate, 2, false, andExec) def(0x25, "AND", ModeZeroPage, 3, false, andExec) def(0x35, "AND", ModeZeroPageX, 4, false, andExec) def(0x2D, "AND", ModeAbsolute, 4, false, andExec) def(0x3D, "AND", ModeAbsoluteX, 4, true, andExec) def(0x39, "AND", ModeAbsoluteY, 4, true, andExec) def(0x21, "AND", ModeIndirectX, 6, false, andExec) def(0x31, "AND", ModeIndirectY, 5, true, andExec) // or with accumulator def(0x09, "ORA", ModeImmediate, 2, false, oraExec) def(0x05, "ORA", ModeZeroPage, 3, false, oraExec) def(0x15, "ORA", ModeZeroPageX, 4, false, oraExec) def(0x0D, "ORA", ModeAbsolute, 4, false, oraExec) def(0x1D, "ORA", ModeAbsoluteX, 4, true, oraExec) def(0x19, "ORA", ModeAbsoluteY, 4, true, oraExec) def(0x01, "ORA", ModeIndirectX, 6, false, oraExec) def(0x11, "ORA", ModeIndirectY, 5, true, oraExec) // exclusive or (with accumulator) def(0x49, "EOR", ModeImmediate, 2, false, eorExec) def(0x45, "EOR", ModeZeroPage, 3, false, eorExec) def(0x55, "EOR", ModeZeroPageX, 4, false, eorExec) def(0x4D, "EOR", ModeAbsolute, 4, false, eorExec) def(0x5D, "EOR", ModeAbsoluteX, 4, true, eorExec) def(0x59, "EOR", ModeAbsoluteY, 4, true, eorExec) def(0x41, "EOR", ModeIndirectX, 6, false, eorExec) def(0x51, "EOR", ModeIndirectY, 5, true, eorExec) // bit test def(0x24, "BIT", ModeZeroPage, 3, false, bitExec) def(0x2C, "BIT", ModeAbsolute, 4, false, bitExec) // arithmetic shift left def(0x0A, "ASL", ModeAccumulator, 2, false, aslExec) def(0x06, "ASL", ModeZeroPage, 5, false, aslExec) def(0x16, "ASL", ModeZeroPageX, 6, false, aslExec) def(0x0E, "ASL", ModeAbsolute, 6, false, aslExec) def(0x1E, "ASL", ModeAbsoluteX, 7, false, aslExec) // logical shift right def(0x4A, "LSR", ModeAccumulator, 2, false, lsrExec) def(0x46, "LSR", ModeZeroPage, 5, false, lsrExec) def(0x56, "LSR", ModeZeroPageX, 6, false, lsrExec) def(0x4E, "LSR", ModeAbsolute, 6, false, lsrExec) def(0x5E, "LSR", ModeAbsoluteX, 7, false, lsrExec) // rotate left def(0x2A, "ROL", ModeAccumulator, 2, false, rolExec) def(0x26, "ROL", ModeZeroPage, 5, false, rolExec) def(0x36, "ROL", ModeZeroPageX, 6, false, rolExec) def(0x2E, "ROL", ModeAbsolute, 6, false, rolExec) def(0x3E, "ROL", ModeAbsoluteX, 7, false, rolExec) // rotate right def(0x6A, "ROR", ModeAccumulator, 2, false, rorExec) def(0x66, "ROR", ModeZeroPage, 5, false, rorExec) def(0x76, "ROR", ModeZeroPageX, 6, false, rorExec) def(0x6E, "ROR", ModeAbsolute, 6, false, rorExec) def(0x7E, "ROR", ModeAbsoluteX, 7, false, rorExec) // increment def(0xE6, "INC", ModeZeroPage, 5, false, incExec) def(0xF6, "INC", ModeZeroPageX, 6, false, incExec) def(0xEE, "INC", ModeAbsolute, 6, false, incExec) def(0xFE, "INC", ModeAbsoluteX, 7, false, incExec) // decrement def(0xC6, "DEC", ModeZeroPage, 5, false, decExec) def(0xD6, "DEC", ModeZeroPageX, 6, false, decExec) def(0xCE, "DEC", ModeAbsolute, 6, false, decExec) def(0xDE, "DEC", ModeAbsoluteX, 7, false, decExec) // increment x def(0xE8, "INX", ModeImplied, 2, false, inxExec) // decrement x def(0xCA, "DEX", ModeImplied, 2, false, dexExec) // increment y def(0xC8, "INY", ModeImplied, 2, false, inyExec) // decrement y def(0x88, "DEY", ModeImplied, 2, false, deyExec) // compare (with accumulator) def(0xC9, "CMP", ModeImmediate, 2, false, cmpExec) def(0xC5, "CMP", ModeZeroPage, 3, false, cmpExec) def(0xD5, "CMP", ModeZeroPageX, 4, false, cmpExec) def(0xCD, "CMP", ModeAbsolute, 4, false, cmpExec) def(0xDD, "CMP", ModeAbsoluteX, 4, true, cmpExec) def(0xD9, "CMP", ModeAbsoluteY, 4, true, cmpExec) def(0xC1, "CMP", ModeIndirectX, 6, false, cmpExec) def(0xD1, "CMP", ModeIndirectY, 5, true, cmpExec) // compare with X def(0xE0, "CPX", ModeImmediate, 2, false, cpxExec) def(0xE4, "CPX", ModeZeroPage, 3, false, cpxExec) def(0xEC, "CPX", ModeAbsolute, 4, false, cpxExec) // compare with y def(0xC0, "CPY", ModeImmediate, 2, false, cpyExec) def(0xC4, "CPY", ModeZeroPage, 3, false, cpyExec) def(0xCC, "CPY", ModeAbsolute, 4, false, cpyExec) // branch on carry clear def(0x90, "BCC", ModeRelative, 2, false, bccExec) // branch on carry set def(0xB0, "BCS", ModeRelative, 2, false, bcsExec) // branch on not equal (zero clear) def(0xD0, "BNE", ModeRelative, 2, false, bneExec) // branch on equal (zero set) def(0xF0, "BEQ", ModeRelative, 2, false, beqExec) // branch on plus (negative clear) def(0x10, "BPL", ModeRelative, 2, false, bplExec) // branch on minus (negative set) def(0x30, "BMI", ModeRelative, 2, false, bmiExec) // branch on overflow clear def(0x50, "BVC", ModeRelative, 2, false, bvcExec) // branch on overflow set def(0x70, "BVS", ModeRelative, 2, false, bvsExec) // jump def(0x4C, "JMP", ModeAbsolute, 3, false, jmpExec) def(0x6C, "JMP", ModeIndirect, 5, false, jmpExec) // jump subroutine def(0x20, "JSR", ModeAbsolute, 6, false, jsrExec) // return from subroutine def(0x60, "RTS", ModeImplied, 6, false, rtsExec) // return from interrupt def(0x40, "RTI", ModeImplied, 6, false, rtiExec) // clear carry def(0x18, "CLC", ModeImplied, 2, false, clcExec) // set carry def(0x38, "SEC", ModeImplied, 2, false, secExec) // clear interrupt disable def(0x58, "CLI", ModeImplied, 2, false, cliExec) // set interrupt disable def(0x78, "SEI", ModeImplied, 2, false, seiExec) // clear decimal def(0xD8, "CLD", ModeImplied, 2, false, cldExec) // set decimal def(0xF8, "SED", ModeImplied, 2, false, sedExec) // clear overflow def(0xB8, "CLV", ModeImplied, 2, false, clvExec) // break / interrupt def(0x00, "BRK", ModeImplied, 7, false, brkExec) // no operation def(0xEA, "NOP", ModeImplied, 2, false, nopExec) def(0x1A, "NOP", ModeImplied, 2, false, nopExec) def(0x3A, "NOP", ModeImplied, 2, false, nopExec) def(0x5A, "NOP", ModeImplied, 2, false, nopExec) def(0x7A, "NOP", ModeImplied, 2, false, nopExec) def(0xDA, "NOP", ModeImplied, 2, false, nopExec) def(0xFA, "NOP", ModeImplied, 2, false, nopExec) def(0x80, "NOP", ModeImmediate, 2, false, nopExec) def(0x82, "NOP", ModeImmediate, 2, false, nopExec) def(0x89, "NOP", ModeImmediate, 2, false, nopExec) def(0xC2, "NOP", ModeImmediate, 2, false, nopExec) def(0xE2, "NOP", ModeImmediate, 2, false, nopExec) def(0x04, "NOP", ModeZeroPage, 3, false, nopExec) def(0x44, "NOP", ModeZeroPage, 3, false, nopExec) def(0x64, "NOP", ModeZeroPage, 3, false, nopExec) def(0x14, "NOP", ModeZeroPageX, 4, false, nopExec) def(0x34, "NOP", ModeZeroPageX, 4, false, nopExec) def(0x54, "NOP", ModeZeroPageX, 4, false, nopExec) def(0x74, "NOP", ModeZeroPageX, 4, false, nopExec) def(0xD4, "NOP", ModeZeroPageX, 4, false, nopExec) def(0xF4, "NOP", ModeZeroPageX, 4, false, nopExec) def(0x0C, "NOP", ModeAbsolute, 4, false, nopExec) def(0x1C, "NOP", ModeAbsoluteX, 4, true, nopExec) def(0x3C, "NOP", ModeAbsoluteX, 4, true, nopExec) def(0x5C, "NOP", ModeAbsoluteX, 4, true, nopExec) def(0x7C, "NOP", ModeAbsoluteX, 4, true, nopExec) def(0xDC, "NOP", ModeAbsoluteX, 4, true, nopExec) def(0xFC, "NOP", ModeAbsoluteX, 4, true, nopExec) // JAM is sometimes also referred to as HLT or KIL def(0x02, "JAM", ModeImplied, 2, false, jamExec) def(0x12, "JAM", ModeImplied, 2, false, jamExec) def(0x22, "JAM", ModeImplied, 2, false, jamExec) def(0x32, "JAM", ModeImplied, 2, false, jamExec) def(0x42, "JAM", ModeImplied, 2, false, jamExec) def(0x52, "JAM", ModeImplied, 2, false, jamExec) def(0x62, "JAM", ModeImplied, 2, false, jamExec) def(0x72, "JAM", ModeImplied, 2, false, jamExec) def(0x92, "JAM", ModeImplied, 2, false, jamExec) def(0xB2, "JAM", ModeImplied, 2, false, jamExec) def(0xD2, "JAM", ModeImplied, 2, false, jamExec) def(0xF2, "JAM", ModeImplied, 2, false, jamExec) def(0x0B, "ANC", ModeImmediate, 2, false, ancExec) def(0x2B, "ANC", ModeImmediate, 2, false, ancExec) def(0x4B, "ALR", ModeImmediate, 2, false, alrExec) def(0x6B, "ARR", ModeImmediate, 2, false, arrExec) def(0x8B, "ANE", ModeImmediate, 2, false, aneExec) def(0xAB, "LXA", ModeImmediate, 2, false, lxaExec) def(0xCB, "AXS", ModeImmediate, 2, false, axsExec) def(0xBB, "LAS", ModeAbsoluteY, 4, true, lasExec) def(0x93, "AHX", ModeIndirectY, 6, false, ahxExec) def(0x9F, "AHX", ModeAbsoluteY, 5, false, ahxExec) def(0x9B, "TAS", ModeAbsoluteY, 5, false, tasExec) def(0x9C, "SHY", ModeAbsoluteX, 5, false, shyExec) def(0x9E, "SHX", ModeAbsoluteY, 5, false, shxExec) // illegal / undocumented instructions def(0xA7, "LAX", ModeZeroPage, 3, false, laxExec) def(0xB7, "LAX", ModeZeroPageY, 4, false, laxExec) def(0xAF, "LAX", ModeAbsolute, 4, false, laxExec) def(0xBF, "LAX", ModeAbsoluteY, 4, true, laxExec) def(0xA3, "LAX", ModeIndirectX, 6, false, laxExec) def(0xB3, "LAX", ModeIndirectY, 5, true, laxExec) def(0x87, "SAX", ModeZeroPage, 3, false, saxExec) def(0x97, "SAX", ModeZeroPageY, 4, false, saxExec) def(0x8F, "SAX", ModeAbsolute, 4, false, saxExec) def(0x83, "SAX", ModeIndirectX, 6, false, saxExec) def(0xC7, "DCP", ModeZeroPage, 5, false, dcpExec) def(0xD7, "DCP", ModeZeroPageX, 6, false, dcpExec) def(0xCF, "DCP", ModeAbsolute, 6, false, dcpExec) def(0xDF, "DCP", ModeAbsoluteX, 7, false, dcpExec) def(0xDB, "DCP", ModeAbsoluteY, 7, false, dcpExec) def(0xC3, "DCP", ModeIndirectX, 8, false, dcpExec) def(0xD3, "DCP", ModeIndirectY, 8, false, dcpExec) def(0x07, "SLO", ModeZeroPage, 5, false, sloExec) def(0x17, "SLO", ModeZeroPageX, 6, false, sloExec) def(0x0F, "SLO", ModeAbsolute, 6, false, sloExec) def(0x1F, "SLO", ModeAbsoluteX, 7, false, sloExec) def(0x1B, "SLO", ModeAbsoluteY, 7, false, sloExec) def(0x03, "SLO", ModeIndirectX, 8, false, sloExec) def(0x13, "SLO", ModeIndirectY, 8, false, sloExec) def(0x27, "RLA", ModeZeroPage, 5, false, rlaExec) def(0x37, "RLA", ModeZeroPageX, 6, false, rlaExec) def(0x2F, "RLA", ModeAbsolute, 6, false, rlaExec) def(0x3F, "RLA", ModeAbsoluteX, 7, false, rlaExec) def(0x3B, "RLA", ModeAbsoluteY, 7, false, rlaExec) def(0x23, "RLA", ModeIndirectX, 8, false, rlaExec) def(0x33, "RLA", ModeIndirectY, 8, false, rlaExec) def(0x47, "SRE", ModeZeroPage, 5, false, sreExec) def(0x57, "SRE", ModeZeroPageX, 6, false, sreExec) def(0x4F, "SRE", ModeAbsolute, 6, false, sreExec) def(0x5F, "SRE", ModeAbsoluteX, 7, false, sreExec) def(0x5B, "SRE", ModeAbsoluteY, 7, false, sreExec) def(0x43, "SRE", ModeIndirectX, 8, false, sreExec) def(0x53, "SRE", ModeIndirectY, 8, false, sreExec) def(0x67, "RRA", ModeZeroPage, 5, false, rraExec) def(0x77, "RRA", ModeZeroPageX, 6, false, rraExec) def(0x6F, "RRA", ModeAbsolute, 6, false, rraExec) def(0x7F, "RRA", ModeAbsoluteX, 7, false, rraExec) def(0x7B, "RRA", ModeAbsoluteY, 7, false, rraExec) def(0x63, "RRA", ModeIndirectX, 8, false, rraExec) def(0x73, "RRA", ModeIndirectY, 8, false, rraExec) def(0xE7, "ISC", ModeZeroPage, 5, false, iscExec) def(0xF7, "ISC", ModeZeroPageX, 6, false, iscExec) def(0xEF, "ISC", ModeAbsolute, 6, false, iscExec) def(0xFF, "ISC", ModeAbsoluteX, 7, false, iscExec) def(0xFB, "ISC", ModeAbsoluteY, 7, false, iscExec) def(0xE3, "ISC", ModeIndirectX, 8, false, iscExec) def(0xF3, "ISC", ModeIndirectY, 8, false, iscExec) }