package razorvine.ksim65 import razorvine.ksim65.components.Address /** * 65C02 cpu simulation (the CMOS version of the 6502). * TODO: add the optional additional cycles to certain instructions and addressing modes */ class Cpu65C02(stopOnBrk: Boolean = false) : Cpu6502(stopOnBrk) { override val name = "65C02" enum class Wait { Normal, Waiting, Stopped } var waiting: Wait = Wait.Normal companion object { const val NMI_vector = Cpu6502.NMI_vector const val RESET_vector = Cpu6502.RESET_vector const val IRQ_vector = Cpu6502.NMI_vector const val resetCycles = Cpu6502.resetCycles } /** * Process once clock cycle in the cpu */ override fun clock() { when (waiting) { Wait.Normal -> super.clock() Wait.Waiting -> { if (pendingInterrupt != null) { // continue execution after hardware interrupt waiting = Wait.Normal instrCycles = 1 } } Wait.Stopped -> { if (pendingInterrupt != null) { // jump to reset vector after hardware interrupt regPC = readWord(RESET_vector) } } } } /** * Execute one single complete instruction */ override fun step() { if (waiting == Wait.Normal) { while (instrCycles > 0) clock() clock() if (waiting == Wait.Normal) while (instrCycles > 0) clock() else { totalCycles += instrCycles instrCycles = 0 } } } // branch-relative address fetched by the ZpR addressing mode private var fetchedAddressZpr: Address = 0 override fun applyAddressingMode(addrMode: AddrMode) { when (addrMode) { AddrMode.Imp, AddrMode.Acc, AddrMode.Imm, AddrMode.Zp, AddrMode.ZpX, AddrMode.ZpY, AddrMode.Rel, AddrMode.Abs, AddrMode.AbsX, AddrMode.AbsY, AddrMode.IzX, AddrMode.IzY -> { super.applyAddressingMode(addrMode) } AddrMode.Ind -> { var lo = readPc() var hi = readPc() fetchedAddress = lo or (hi shl 8) // 65c02 doesn't have the page bug of the 6502 lo = read(fetchedAddress) hi = read(fetchedAddress + 1) fetchedAddress = lo or (hi shl 8) } AddrMode.Zpr -> { // addressing mode used by the 65C02 only // combination of zp addresssing + relative branch addressing fetchedAddress = readPc() val relative = readPc() fetchedAddressZpr = if (relative >= 0x80) { regPC - (256 - relative) and 0xffff } else regPC + relative and 0xffff } AddrMode.Izp -> { // addressing mode used by the 65C02 only fetchedAddress = readPc() val lo = read((fetchedAddress) and 0xff) val hi = read((fetchedAddress + 1) and 0xff) fetchedAddress = lo or (hi shl 8) } AddrMode.IaX -> { // addressing mode used by the 65C02 only var lo = readPc() var hi = readPc() fetchedAddress = lo or (hi shl 8) lo = read((fetchedAddress + regX) and 0xffff) hi = read((fetchedAddress + regX + 1) and 0xffff) fetchedAddress = lo or (hi shl 8) } } } override fun dispatchOpcode(opcode: Int) { when (opcode) { 0x00 -> iBrk() 0x01 -> iOra() 0x02 -> iNop() 0x03 -> iNop() 0x04 -> iTsb() 0x05 -> iOra() 0x06 -> iAsl() 0x07 -> iRmb0() 0x08 -> iPhp() 0x09 -> iOra() 0x0a -> iAsl() 0x0b -> iNop() 0x0c -> iTsb() 0x0d -> iOra() 0x0e -> iAsl() 0x0f -> iBbr0() 0x10 -> iBpl() 0x11 -> iOra() 0x12 -> iOra() 0x13 -> iNop() 0x14 -> iTrb() 0x15 -> iOra() 0x16 -> iAsl() 0x17 -> iRmb1() 0x18 -> iClc() 0x19 -> iOra() 0x1a -> iInc() 0x1b -> iNop() 0x1c -> iTrb() 0x1d -> iOra() 0x1e -> iAsl() 0x1f -> iBbr1() 0x20 -> iJsr() 0x21 -> iAnd() 0x22 -> iNop() 0x23 -> iNop() 0x24 -> iBit() 0x25 -> iAnd() 0x26 -> iRol() 0x27 -> iRmb2() 0x28 -> iPlp() 0x29 -> iAnd() 0x2a -> iRol() 0x2b -> iNop() 0x2c -> iBit() 0x2d -> iAnd() 0x2e -> iRol() 0x2f -> iBbr2() 0x30 -> iBmi() 0x31 -> iAnd() 0x32 -> iAnd() 0x33 -> iNop() 0x34 -> iBit() 0x35 -> iAnd() 0x36 -> iRol() 0x37 -> iRmb3() 0x38 -> iSec() 0x39 -> iAnd() 0x3a -> iDec() 0x3b -> iNop() 0x3c -> iBit() 0x3d -> iAnd() 0x3e -> iRol() 0x3f -> iBbr3() 0x40 -> iRti() 0x41 -> iEor() 0x42 -> iNop() 0x43 -> iNop() 0x44 -> iNop() 0x45 -> iEor() 0x46 -> iLsr() 0x47 -> iRmb4() 0x48 -> iPha() 0x49 -> iEor() 0x4a -> iLsr() 0x4b -> iNop() 0x4c -> iJmp() 0x4d -> iEor() 0x4e -> iLsr() 0x4f -> iBbr4() 0x50 -> iBvc() 0x51 -> iEor() 0x52 -> iEor() 0x53 -> iNop() 0x54 -> iNop() 0x55 -> iEor() 0x56 -> iLsr() 0x57 -> iRmb5() 0x58 -> iCli() 0x59 -> iEor() 0x5a -> iPhy() 0x5b -> iNop() 0x5c -> iNop() 0x5d -> iEor() 0x5e -> iLsr() 0x5f -> iBbr5() 0x60 -> iRts() 0x61 -> iAdc() 0x62 -> iNop() 0x63 -> iNop() 0x64 -> iStz() 0x65 -> iAdc() 0x66 -> iRor() 0x67 -> iRmb6() 0x68 -> iPla() 0x69 -> iAdc() 0x6a -> iRor() 0x6b -> iNop() 0x6c -> iJmp() 0x6d -> iAdc() 0x6e -> iRor() 0x6f -> iBbr6() 0x70 -> iBvs() 0x71 -> iAdc() 0x72 -> iAdc() 0x73 -> iNop() 0x74 -> iStz() 0x75 -> iAdc() 0x76 -> iRor() 0x77 -> iRmb7() 0x78 -> iSei() 0x79 -> iAdc() 0x7a -> iPly() 0x7b -> iNop() 0x7c -> iJmp() 0x7d -> iAdc() 0x7e -> iRor() 0x7f -> iBbr7() 0x80 -> iBra() 0x81 -> iSta() 0x82 -> iNop() 0x83 -> iNop() 0x84 -> iSty() 0x85 -> iSta() 0x86 -> iStx() 0x87 -> iSmb0() 0x88 -> iDey() 0x89 -> iBit() 0x8a -> iTxa() 0x8b -> iNop() 0x8c -> iSty() 0x8d -> iSta() 0x8e -> iStx() 0x8f -> iBbs0() 0x90 -> iBcc() 0x91 -> iSta() 0x92 -> iSta() 0x93 -> iNop() 0x94 -> iSty() 0x95 -> iSta() 0x96 -> iStx() 0x97 -> iSmb1() 0x98 -> iTya() 0x99 -> iSta() 0x9a -> iTxs() 0x9b -> iNop() 0x9c -> iStz() 0x9d -> iSta() 0x9e -> iStz() 0x9f -> iBbs1() 0xa0 -> iLdy() 0xa1 -> iLda() 0xa2 -> iLdx() 0xa3 -> iNop() 0xa4 -> iLdy() 0xa5 -> iLda() 0xa6 -> iLdx() 0xa7 -> iSmb2() 0xa8 -> iTay() 0xa9 -> iLda() 0xaa -> iTax() 0xab -> iNop() 0xac -> iLdy() 0xad -> iLda() 0xae -> iLdx() 0xaf -> iBbs2() 0xb0 -> iBcs() 0xb1 -> iLda() 0xb2 -> iLda() 0xb3 -> iNop() 0xb4 -> iLdy() 0xb5 -> iLda() 0xb6 -> iLdx() 0xb7 -> iSmb3() 0xb8 -> iClv() 0xb9 -> iLda() 0xba -> iTsx() 0xbb -> iNop() 0xbc -> iLdy() 0xbd -> iLda() 0xbe -> iLdx() 0xbf -> iBbs3() 0xc0 -> iCpy() 0xc1 -> iCmp() 0xc2 -> iNop() 0xc3 -> iNop() 0xc4 -> iCpy() 0xc5 -> iCmp() 0xc6 -> iDec() 0xc7 -> iSmb4() 0xc8 -> iIny() 0xc9 -> iCmp() 0xca -> iDex() 0xcb -> iWai() 0xcc -> iCpy() 0xcd -> iCmp() 0xce -> iDec() 0xcf -> iBbs4() 0xd0 -> iBne() 0xd1 -> iCmp() 0xd2 -> iCmp() 0xd3 -> iNop() 0xd4 -> iNop() 0xd5 -> iCmp() 0xd6 -> iDec() 0xd7 -> iSmb5() 0xd8 -> iCld() 0xd9 -> iCmp() 0xda -> iPhx() 0xdb -> iStp() 0xdc -> iNop() 0xdd -> iCmp() 0xde -> iDec() 0xdf -> iBbs5() 0xe0 -> iCpx() 0xe1 -> iSbc() 0xe2 -> iNop() 0xe3 -> iNop() 0xe4 -> iCpx() 0xe5 -> iSbc() 0xe6 -> iInc() 0xe7 -> iSmb6() 0xe8 -> iInx() 0xe9 -> iSbc() 0xea -> iNop() 0xeb -> iNop() 0xec -> iCpx() 0xed -> iSbc() 0xee -> iInc() 0xef -> iBbs6() 0xf0 -> iBeq() 0xf1 -> iSbc() 0xf2 -> iSbc() 0xf3 -> iNop() 0xf4 -> iNop() 0xf5 -> iSbc() 0xf6 -> iInc() 0xf7 -> iSmb7() 0xf8 -> iSed() 0xf9 -> iSbc() 0xfa -> iPlx() 0xfb -> iNop() 0xfc -> iNop() 0xfd -> iSbc() 0xfe -> iInc() 0xff -> iBbs7() else -> { /* can't occur */ } } } // opcode list: http://www.oxyron.de/html/opcodesc02.html override val instructions: Array = listOf( /* 00 */ Instruction("brk", AddrMode.Imp, 7), /* 01 */ Instruction("ora", AddrMode.IzX, 6), /* 02 */ Instruction("nop", AddrMode.Imm, 2), /* 03 */ Instruction("nop", AddrMode.Imp, 1), /* 04 */ Instruction("tsb", AddrMode.Zp, 5), /* 05 */ Instruction("ora", AddrMode.Zp, 3), /* 06 */ Instruction("asl", AddrMode.Zp, 5), /* 07 */ Instruction("rmb0", AddrMode.Zp, 5), /* 08 */ Instruction("php", AddrMode.Imp, 3), /* 09 */ Instruction("ora", AddrMode.Imm, 2), /* 0a */ Instruction("asl", AddrMode.Acc, 2), /* 0b */ Instruction("nop", AddrMode.Imp, 1), /* 0c */ Instruction("tsb", AddrMode.Abs, 6), /* 0d */ Instruction("ora", AddrMode.Abs, 4), /* 0e */ Instruction("asl", AddrMode.Abs, 6), /* 0f */ Instruction("bbr0", AddrMode.Zpr, 5), /* 10 */ Instruction("bpl", AddrMode.Rel, 2), /* 11 */ Instruction("ora", AddrMode.IzY, 5), /* 12 */ Instruction("ora", AddrMode.Izp, 5), /* 13 */ Instruction("nop", AddrMode.Imp, 1), /* 14 */ Instruction("trb", AddrMode.Zp, 5), /* 15 */ Instruction("ora", AddrMode.ZpX, 4), /* 16 */ Instruction("asl", AddrMode.ZpX, 6), /* 17 */ Instruction("rmb1", AddrMode.Zp, 5), /* 18 */ Instruction("clc", AddrMode.Imp, 2), /* 19 */ Instruction("ora", AddrMode.AbsY, 4), /* 1a */ Instruction("inc", AddrMode.Acc, 2), /* 1b */ Instruction("nop", AddrMode.Imp, 1), /* 1c */ Instruction("trb", AddrMode.Abs, 6), /* 1d */ Instruction("ora", AddrMode.AbsX, 4), /* 1e */ Instruction("asl", AddrMode.AbsX, 6), /* 1f */ Instruction("bbr1", AddrMode.Zpr, 5), /* 20 */ Instruction("jsr", AddrMode.Abs, 6), /* 21 */ Instruction("and", AddrMode.IzX, 6), /* 22 */ Instruction("nop", AddrMode.Imm, 2), /* 23 */ Instruction("nop", AddrMode.Imp, 1), /* 24 */ Instruction("bit", AddrMode.Zp, 3), /* 25 */ Instruction("and", AddrMode.Zp, 3), /* 26 */ Instruction("rol", AddrMode.Zp, 5), /* 27 */ Instruction("rmb2", AddrMode.Zp, 5), /* 28 */ Instruction("plp", AddrMode.Imp, 4), /* 29 */ Instruction("and", AddrMode.Imm, 2), /* 2a */ Instruction("rol", AddrMode.Acc, 2), /* 2b */ Instruction("nop", AddrMode.Imp, 1), /* 2c */ Instruction("bit", AddrMode.Abs, 4), /* 2d */ Instruction("and", AddrMode.Abs, 4), /* 2e */ Instruction("rol", AddrMode.Abs, 6), /* 2f */ Instruction("bbr2", AddrMode.Zpr, 5), /* 30 */ Instruction("bmi", AddrMode.Rel, 2), /* 31 */ Instruction("and", AddrMode.IzY, 5), /* 32 */ Instruction("and", AddrMode.Izp, 5), /* 33 */ Instruction("nop", AddrMode.Imp, 1), /* 34 */ Instruction("bit", AddrMode.ZpX, 4), /* 35 */ Instruction("and", AddrMode.ZpX, 4), /* 36 */ Instruction("rol", AddrMode.ZpX, 6), /* 37 */ Instruction("rmb3", AddrMode.Zp, 5), /* 38 */ Instruction("sec", AddrMode.Imp, 2), /* 39 */ Instruction("and", AddrMode.AbsY, 4), /* 3a */ Instruction("dec", AddrMode.Acc, 2), /* 3b */ Instruction("nop", AddrMode.Imp, 1), /* 3c */ Instruction("bit", AddrMode.AbsX, 4), /* 3d */ Instruction("and", AddrMode.AbsX, 4), /* 3e */ Instruction("rol", AddrMode.AbsX, 6), /* 3f */ Instruction("bbr3", AddrMode.Zpr, 5), /* 40 */ Instruction("rti", AddrMode.Imp, 6), /* 41 */ Instruction("eor", AddrMode.IzX, 6), /* 42 */ Instruction("nop", AddrMode.Imm, 2), /* 43 */ Instruction("nop", AddrMode.Imp, 1), /* 44 */ Instruction("nop", AddrMode.Zp, 3), /* 45 */ Instruction("eor", AddrMode.Zp, 3), /* 46 */ Instruction("lsr", AddrMode.Zp, 5), /* 47 */ Instruction("rmb4", AddrMode.Zp, 5), /* 48 */ Instruction("pha", AddrMode.Imp, 3), /* 49 */ Instruction("eor", AddrMode.Imm, 2), /* 4a */ Instruction("lsr", AddrMode.Acc, 2), /* 4b */ Instruction("nop", AddrMode.Imp, 1), /* 4c */ Instruction("jmp", AddrMode.Abs, 3), /* 4d */ Instruction("eor", AddrMode.Abs, 4), /* 4e */ Instruction("lsr", AddrMode.Abs, 6), /* 4f */ Instruction("bbr4", AddrMode.Zpr, 5), /* 50 */ Instruction("bvc", AddrMode.Rel, 2), /* 51 */ Instruction("eor", AddrMode.IzY, 5), /* 52 */ Instruction("eor", AddrMode.Izp, 5), /* 53 */ Instruction("nop", AddrMode.Imp, 1), /* 54 */ Instruction("nop", AddrMode.ZpX, 4), /* 55 */ Instruction("eor", AddrMode.ZpX, 4), /* 56 */ Instruction("lsr", AddrMode.ZpX, 6), /* 57 */ Instruction("rmb5", AddrMode.Zp, 5), /* 58 */ Instruction("cli", AddrMode.Imp, 2), /* 59 */ Instruction("eor", AddrMode.AbsY, 4), /* 5a */ Instruction("phy", AddrMode.Imp, 3), /* 5b */ Instruction("nop", AddrMode.Imp, 1), /* 5c */ Instruction("nop", AddrMode.Abs, 8), /* 5d */ Instruction("eor", AddrMode.AbsX, 4), /* 5e */ Instruction("lsr", AddrMode.AbsX, 6), /* 5f */ Instruction("bbr5", AddrMode.Zpr, 5), /* 60 */ Instruction("rts", AddrMode.Imp, 6), /* 61 */ Instruction("adc", AddrMode.IzX, 6), /* 62 */ Instruction("nop", AddrMode.Imm, 2), /* 63 */ Instruction("nop", AddrMode.Imp, 1), /* 64 */ Instruction("stz", AddrMode.Zp, 3), /* 65 */ Instruction("adc", AddrMode.Zp, 3), /* 66 */ Instruction("ror", AddrMode.Zp, 5), /* 67 */ Instruction("rmb6", AddrMode.Zp, 5), /* 68 */ Instruction("pla", AddrMode.Imp, 4), /* 69 */ Instruction("adc", AddrMode.Imm, 2), /* 6a */ Instruction("ror", AddrMode.Acc, 2), /* 6b */ Instruction("nop", AddrMode.Imp, 1), /* 6c */ Instruction("jmp", AddrMode.Ind, 6), /* 6d */ Instruction("adc", AddrMode.Abs, 4), /* 6e */ Instruction("ror", AddrMode.Abs, 6), /* 6f */ Instruction("bbr6", AddrMode.Zpr, 5), /* 70 */ Instruction("bvs", AddrMode.Rel, 2), /* 71 */ Instruction("adc", AddrMode.IzY, 5), /* 72 */ Instruction("adc", AddrMode.Izp, 5), /* 73 */ Instruction("nop", AddrMode.Imp, 1), /* 74 */ Instruction("stz", AddrMode.ZpX, 4), /* 75 */ Instruction("adc", AddrMode.ZpX, 4), /* 76 */ Instruction("ror", AddrMode.ZpX, 6), /* 77 */ Instruction("rmb7", AddrMode.Zp, 5), /* 78 */ Instruction("sei", AddrMode.Imp, 2), /* 79 */ Instruction("adc", AddrMode.AbsY, 4), /* 7a */ Instruction("ply", AddrMode.Imp, 4), /* 7b */ Instruction("nop", AddrMode.Imp, 1), /* 7c */ Instruction("jmp", AddrMode.IaX, 6), /* 7d */ Instruction("adc", AddrMode.AbsX, 4), /* 7e */ Instruction("ror", AddrMode.AbsX, 6), /* 7f */ Instruction("bbr7", AddrMode.Zpr, 5), /* 80 */ Instruction("bra", AddrMode.Rel, 3), /* 81 */ Instruction("sta", AddrMode.IzX, 6), /* 82 */ Instruction("nop", AddrMode.Imm, 2), /* 83 */ Instruction("nop", AddrMode.Imp, 1), /* 84 */ Instruction("sty", AddrMode.Zp, 3), /* 85 */ Instruction("sta", AddrMode.Zp, 3), /* 86 */ Instruction("stx", AddrMode.Zp, 3), /* 87 */ Instruction("smb0", AddrMode.Zp, 5), /* 88 */ Instruction("dey", AddrMode.Imp, 2), /* 89 */ Instruction("bit", AddrMode.Imm, 2), /* 8a */ Instruction("txa", AddrMode.Imp, 2), /* 8b */ Instruction("nop", AddrMode.Imp, 1), /* 8c */ Instruction("sty", AddrMode.Abs, 4), /* 8d */ Instruction("sta", AddrMode.Abs, 4), /* 8e */ Instruction("stx", AddrMode.Abs, 4), /* 8f */ Instruction("bbs0", AddrMode.Zpr, 5), /* 90 */ Instruction("bcc", AddrMode.Rel, 2), /* 91 */ Instruction("sta", AddrMode.IzY, 6), /* 92 */ Instruction("sta", AddrMode.Izp, 5), /* 93 */ Instruction("nop", AddrMode.Imp, 1), /* 94 */ Instruction("sty", AddrMode.ZpX, 4), /* 95 */ Instruction("sta", AddrMode.ZpX, 4), /* 96 */ Instruction("stx", AddrMode.ZpY, 4), /* 97 */ Instruction("smb1", AddrMode.Zp, 5), /* 98 */ Instruction("tya", AddrMode.Imp, 2), /* 99 */ Instruction("sta", AddrMode.AbsY, 5), /* 9a */ Instruction("txs", AddrMode.Imp, 2), /* 9b */ Instruction("nop", AddrMode.Imp, 1), /* 9c */ Instruction("stz", AddrMode.Abs, 4), /* 9d */ Instruction("sta", AddrMode.AbsX, 5), /* 9e */ Instruction("stz", AddrMode.AbsX, 5), /* 9f */ Instruction("bbs1", AddrMode.Zpr, 5), /* a0 */ Instruction("ldy", AddrMode.Imm, 2), /* a1 */ Instruction("lda", AddrMode.IzX, 6), /* a2 */ Instruction("ldx", AddrMode.Imm, 2), /* a3 */ Instruction("nop", AddrMode.Imp, 1), /* a4 */ Instruction("ldy", AddrMode.Zp, 3), /* a5 */ Instruction("lda", AddrMode.Zp, 3), /* a6 */ Instruction("ldx", AddrMode.Zp, 3), /* a7 */ Instruction("smb2", AddrMode.Zp, 5), /* a8 */ Instruction("tay", AddrMode.Imp, 2), /* a9 */ Instruction("lda", AddrMode.Imm, 2), /* aa */ Instruction("tax", AddrMode.Imp, 2), /* ab */ Instruction("nop", AddrMode.Imp, 1), /* ac */ Instruction("ldy", AddrMode.Abs, 4), /* ad */ Instruction("lda", AddrMode.Abs, 4), /* ae */ Instruction("ldx", AddrMode.Abs, 4), /* af */ Instruction("bbs2", AddrMode.Zpr, 5), /* b0 */ Instruction("bcs", AddrMode.Rel, 2), /* b1 */ Instruction("lda", AddrMode.IzY, 5), /* b2 */ Instruction("lda", AddrMode.Izp, 5), /* b3 */ Instruction("nop", AddrMode.Imp, 1), /* b4 */ Instruction("ldy", AddrMode.ZpX, 4), /* b5 */ Instruction("lda", AddrMode.ZpX, 4), /* b6 */ Instruction("ldx", AddrMode.ZpY, 4), /* b7 */ Instruction("smb3", AddrMode.Zp, 5), /* b8 */ Instruction("clv", AddrMode.Imp, 2), /* b9 */ Instruction("lda", AddrMode.AbsY, 4), /* ba */ Instruction("tsx", AddrMode.Imp, 2), /* bb */ Instruction("nop", AddrMode.Imp, 1), /* bc */ Instruction("ldy", AddrMode.AbsX, 4), /* bd */ Instruction("lda", AddrMode.AbsX, 4), /* be */ Instruction("ldx", AddrMode.AbsY, 4), /* bf */ Instruction("bbs3", AddrMode.Zpr, 5), /* c0 */ Instruction("cpy", AddrMode.Imm, 2), /* c1 */ Instruction("cmp", AddrMode.IzX, 6), /* c2 */ Instruction("nop", AddrMode.Imm, 2), /* c3 */ Instruction("nop", AddrMode.Imp, 1), /* c4 */ Instruction("cpy", AddrMode.Zp, 3), /* c5 */ Instruction("cmp", AddrMode.Zp, 3), /* c6 */ Instruction("dec", AddrMode.Zp, 5), /* c7 */ Instruction("smb4", AddrMode.Zp, 5), /* c8 */ Instruction("iny", AddrMode.Imp, 2), /* c9 */ Instruction("cmp", AddrMode.Imm, 2), /* ca */ Instruction("dex", AddrMode.Imp, 2), /* cb */ Instruction("wai", AddrMode.Imp, 3), /* cc */ Instruction("cpy", AddrMode.Abs, 4), /* cd */ Instruction("cmp", AddrMode.Abs, 4), /* ce */ Instruction("dec", AddrMode.Abs, 6), /* cf */ Instruction("bbs4", AddrMode.Zpr, 5), /* d0 */ Instruction("bne", AddrMode.Rel, 2), /* d1 */ Instruction("cmp", AddrMode.IzY, 5), /* d2 */ Instruction("cmp", AddrMode.Izp, 5), /* d3 */ Instruction("nop", AddrMode.Imp, 1), /* d4 */ Instruction("nop", AddrMode.ZpX, 4), /* d5 */ Instruction("cmp", AddrMode.ZpX, 4), /* d6 */ Instruction("dec", AddrMode.ZpX, 6), /* d7 */ Instruction("smb5", AddrMode.Zp, 5), /* d8 */ Instruction("cld", AddrMode.Imp, 2), /* d9 */ Instruction("cmp", AddrMode.AbsY, 4), /* da */ Instruction("phx", AddrMode.Imp, 3), /* db */ Instruction("stp", AddrMode.Imp, 3), /* dc */ Instruction("nop", AddrMode.Abs, 4), /* dd */ Instruction("cmp", AddrMode.AbsX, 4), /* de */ Instruction("dec", AddrMode.AbsX, 7), /* df */ Instruction("bbs5", AddrMode.Zpr, 5), /* e0 */ Instruction("cpx", AddrMode.Imm, 2), /* e1 */ Instruction("sbc", AddrMode.IzX, 6), /* e2 */ Instruction("nop", AddrMode.Imm, 2), /* e3 */ Instruction("nop", AddrMode.Imp, 1), /* e4 */ Instruction("cpx", AddrMode.Zp, 3), /* e5 */ Instruction("sbc", AddrMode.Zp, 3), /* e6 */ Instruction("inc", AddrMode.Zp, 5), /* e7 */ Instruction("smb6", AddrMode.Zp, 5), /* e8 */ Instruction("inx", AddrMode.Imp, 2), /* e9 */ Instruction("sbc", AddrMode.Imm, 2), /* ea */ Instruction("nop", AddrMode.Imp, 2), /* eb */ Instruction("nop", AddrMode.Imp, 1), /* ec */ Instruction("cpx", AddrMode.Abs, 4), /* ed */ Instruction("sbc", AddrMode.Abs, 4), /* ee */ Instruction("inc", AddrMode.Abs, 6), /* ef */ Instruction("bbs6", AddrMode.Zpr, 5), /* f0 */ Instruction("beq", AddrMode.Rel, 2), /* f1 */ Instruction("sbc", AddrMode.IzY, 5), /* f2 */ Instruction("sbc", AddrMode.Izp, 5), /* f3 */ Instruction("nop", AddrMode.Imp, 1), /* f4 */ Instruction("nop", AddrMode.ZpX, 4), /* f5 */ Instruction("sbc", AddrMode.ZpX, 4), /* f6 */ Instruction("inc", AddrMode.ZpX, 6), /* f7 */ Instruction("smb7", AddrMode.Zp, 5), /* f8 */ Instruction("sed", AddrMode.Imp, 2), /* f9 */ Instruction("sbc", AddrMode.AbsY, 4), /* fa */ Instruction("plx", AddrMode.Imp, 4), /* fb */ Instruction("nop", AddrMode.Imp, 1), /* fc */ Instruction("nop", AddrMode.AbsX, 4), /* fd */ Instruction("sbc", AddrMode.AbsX, 4), /* fe */ Instruction("inc", AddrMode.AbsX, 7), /* ff */ Instruction("bbs7", AddrMode.Zpr, 5) ).toTypedArray() override fun iBrk() { // handle BRK ('software interrupt') or a real hardware IRQ val interrupt = pendingInterrupt val nmi = interrupt?.first == true if (interrupt != null) { pushStackAddr(regPC - 1) } else { regPC++ pushStackAddr(regPC) } regP.B = interrupt == null pushStack(regP) regP.I = true // interrupts are now disabled regP.D = false // this is different from NMOS 6502 regPC = readWord(if (nmi) Cpu6502.NMI_vector else Cpu6502.IRQ_vector) pendingInterrupt = null } override fun iBit() { val data = getFetched() regP.Z = (regA and data) == 0 if (currentInstruction.mode != AddrMode.Imm) { regP.V = (data and 0b01000000) != 0 regP.N = (data and 0b10000000) != 0 } } override fun iAdc() { val value = getFetched() if (regP.D) { // BCD add // see http://www.6502.org/tutorials/decimal_mode.html // and https://sourceforge.net/p/vice-emu/code/HEAD/tree/trunk/vice/src/65c02core.c#l542 // (the implementation below is based on the code used by Vice) var tmp = (regA and 0x0f) + (value and 0x0f) + if (regP.C) 1 else 0 var tmp2 = (regA and 0xf0) + (value and 0xf0) if (tmp > 9) { tmp2 += 0x10 tmp += 6 } regP.V = (regA xor value).inv() and (regA xor tmp2) and 0b10000000 != 0 if (tmp2 > 0x90) tmp2 += 0x60 regP.C = tmp2 >= 0x100 tmp = (tmp and 0x0f) + (tmp2 and 0xf0) regP.N = (tmp and 0b10000000) != 0 regP.Z = tmp == 0 regA = tmp and 0xff } else { // normal add (identical to 6502) val tmp = value + regA + if (regP.C) 1 else 0 regP.N = (tmp and 0b10000000) != 0 regP.Z = (tmp and 0xff) == 0 regP.V = (regA xor value).inv() and (regA xor tmp) and 0b10000000 != 0 regP.C = tmp > 0xff regA = tmp and 0xff } } override fun iSbc() { // see http://www.6502.org/tutorials/decimal_mode.html // and https://sourceforge.net/p/vice-emu/code/HEAD/tree/trunk/vice/src/65c02core.c#l1205 // (the implementation below is based on the code used by Vice) val value = getFetched() var tmp = (regA - value - if (regP.C) 0 else 1) and 0xffff regP.V = (regA xor tmp) and (regA xor value) and 0b10000000 != 0 if (regP.D) { if (tmp > 0xff) tmp = (tmp - 0x60) and 0xffff val tmp2 = ((regA and 0x0f) - (value and 0x0f) - if (regP.C) 0 else 1) and 0xffff if (tmp2 > 0xff) tmp -= 6 } regP.C = (regA - if (regP.C) 0 else 1) >= value regP.Z = (tmp and 0xff) == 0 regP.N = (tmp and 0b10000000) != 0 regA = tmp and 0xff } override fun iDec() { if (currentInstruction.mode == AddrMode.Acc) { regA = (regA - 1) and 0xff regP.Z = regA == 0 regP.N = (regA and 0b10000000) != 0 } else super.iDec() } override fun iInc() { if (currentInstruction.mode == AddrMode.Acc) { regA = (regA + 1) and 0xff regP.Z = regA == 0 regP.N = (regA and 0b10000000) != 0 } else super.iInc() } private fun iBra() { // unconditional branch regPC = fetchedAddress } private fun iTrb() { val data = getFetched() regP.Z = data and regA == 0 write(fetchedAddress, data and regA.inv()) } private fun iTsb() { val data = getFetched() regP.Z = data and regA == 0 write(fetchedAddress, data or regA) } private fun iStz() { write(fetchedAddress, 0) } private fun iWai() { waiting = Wait.Waiting } private fun iStp() { waiting = Wait.Stopped } private fun iPhx() { pushStack(regX) } private fun iPlx() { regX = popStack() regP.Z = regX == 0 regP.N = (regX and 0b10000000) != 0 } private fun iPhy() { pushStack(regY) } private fun iPly() { regY = popStack() regP.Z = regY == 0 regP.N = (regY and 0b10000000) != 0 } private fun iBbr0() { val data = getFetched() if (data and 1 == 0) regPC = fetchedAddressZpr } private fun iBbr1() { val data = getFetched() if (data and 2 == 0) regPC = fetchedAddressZpr } private fun iBbr2() { val data = getFetched() if (data and 4 == 0) regPC = fetchedAddressZpr } private fun iBbr3() { val data = getFetched() if (data and 8 == 0) regPC = fetchedAddressZpr } private fun iBbr4() { val data = getFetched() if (data and 16 == 0) regPC = fetchedAddressZpr } private fun iBbr5() { val data = getFetched() if (data and 32 == 0) regPC = fetchedAddressZpr } private fun iBbr6() { val data = getFetched() if (data and 64 == 0) regPC = fetchedAddressZpr } private fun iBbr7() { val data = getFetched() if (data and 128 == 0) regPC = fetchedAddressZpr } private fun iBbs0() { val data = getFetched() if (data and 1 != 0) regPC = fetchedAddressZpr } private fun iBbs1() { val data = getFetched() if (data and 2 != 0) regPC = fetchedAddressZpr } private fun iBbs2() { val data = getFetched() if (data and 4 != 0) regPC = fetchedAddressZpr } private fun iBbs3() { val data = getFetched() if (data and 8 != 0) regPC = fetchedAddressZpr } private fun iBbs4() { val data = getFetched() if (data and 16 != 0) regPC = fetchedAddressZpr } private fun iBbs5() { val data = getFetched() if (data and 32 != 0) regPC = fetchedAddressZpr } private fun iBbs6() { val data = getFetched() if (data and 64 != 0) regPC = fetchedAddressZpr } private fun iBbs7() { val data = getFetched() if (data and 128 != 0) regPC = fetchedAddressZpr } private fun iSmb0() { val data = getFetched() write(fetchedAddress, data or 1) } private fun iSmb1() { val data = getFetched() write(fetchedAddress, data or 2) } private fun iSmb2() { val data = getFetched() write(fetchedAddress, data or 4) } private fun iSmb3() { val data = getFetched() write(fetchedAddress, data or 8) } private fun iSmb4() { val data = getFetched() write(fetchedAddress, data or 16) } private fun iSmb5() { val data = getFetched() write(fetchedAddress, data or 32) } private fun iSmb6() { val data = getFetched() write(fetchedAddress, data or 64) } private fun iSmb7() { val data = getFetched() write(fetchedAddress, data or 128) } private fun iRmb0() { val data = getFetched() write(fetchedAddress, data and 0b11111110) } private fun iRmb1() { val data = getFetched() write(fetchedAddress, data and 0b11111101) } private fun iRmb2() { val data = getFetched() write(fetchedAddress, data and 0b11111011) } private fun iRmb3() { val data = getFetched() write(fetchedAddress, data and 0b11110111) } private fun iRmb4() { val data = getFetched() write(fetchedAddress, data and 0b11101111) } private fun iRmb5() { val data = getFetched() write(fetchedAddress, data and 0b11011111) } private fun iRmb6() { val data = getFetched() write(fetchedAddress, data and 0b10111111) } private fun iRmb7() { val data = getFetched() write(fetchedAddress, data and 0b01111111) } }