mirror of https://github.com/irmen/ksim65.git
955 lines
34 KiB
Kotlin
955 lines
34 KiB
Kotlin
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<Instruction> =
|
|
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)
|
|
}
|
|
}
|