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) // 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) }