From ca2eede5859838cf28cf13b1e8e3d6ad0b763c5c Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 15 Oct 2019 22:28:48 +0200 Subject: [PATCH] prepare for extra cycles in addrmode/instructions --- src/main/kotlin/razorvine/ksim65/Cpu6502.kt | 32 +++++++++++++++----- src/main/kotlin/razorvine/ksim65/Cpu65C02.kt | 26 +++++++++------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/razorvine/ksim65/Cpu6502.kt b/src/main/kotlin/razorvine/ksim65/Cpu6502.kt index 36ed6b8..5150da5 100644 --- a/src/main/kotlin/razorvine/ksim65/Cpu6502.kt +++ b/src/main/kotlin/razorvine/ksim65/Cpu6502.kt @@ -9,7 +9,6 @@ import razorvine.ksim65.components.UByte /** * 6502 cpu simulation (the NMOS version) including the 'illegal' opcodes. * TODO: actually implement the illegal opcodes, see http://www.ffd2.com/fridge/docs/6502-NMOS.extra.opcodes - * TODO: add the optional additional cycles to certain instructions and addressing modes */ open class Cpu6502 : BusComponent() { open val name = "6502" @@ -285,8 +284,10 @@ open class Cpu6502 : BusComponent() { regPC++ instrCycles = currentInstruction.cycles - applyAddressingMode(currentInstruction.mode) - dispatchOpcode(currentOpcode) + val extraCycleFromAddr = applyAddressingMode(currentInstruction.mode) + val extraCycleFromInstr = dispatchOpcode(currentOpcode) + if(extraCycleFromAddr and extraCycleFromInstr) + instrCycles++ } instrCycles-- @@ -631,45 +632,57 @@ open class Cpu6502 : BusComponent() { /* fe */ Instruction("inc", AddrMode.AbsX, 7), /* ff */ Instruction("isc", AddrMode.AbsX, 7)).toTypedArray() - protected open fun applyAddressingMode(addrMode: AddrMode) { - when (addrMode) { + protected open fun applyAddressingMode(addrMode: AddrMode): Boolean { + // an addressing mode can cause an extra clock cycle on certain instructions + return when (addrMode) { AddrMode.Imp, AddrMode.Acc -> { fetchedData = regA + false } AddrMode.Imm -> { fetchedData = readPc() + false } AddrMode.Zp -> { fetchedAddress = readPc() + false } AddrMode.ZpX -> { // note: zeropage index will not leave Zp when page boundary is crossed fetchedAddress = (readPc()+regX) and 0xff + false } AddrMode.ZpY -> { // note: zeropage index will not leave Zp when page boundary is crossed fetchedAddress = (readPc()+regY) and 0xff + false } AddrMode.Rel -> { val relative = readPc() fetchedAddress = if (relative >= 0x80) { regPC-(256-relative) and 0xffff } else regPC+relative and 0xffff + false } AddrMode.Abs -> { val lo = readPc() val hi = readPc() fetchedAddress = lo or (hi shl 8) + false } AddrMode.AbsX -> { val lo = readPc() val hi = readPc() fetchedAddress = regX+(lo or (hi shl 8)) and 0xffff + // if this address is a different page, extra clock cycle: + (fetchedAddress and 0xff00) != hi shl 8 } AddrMode.AbsY -> { val lo = readPc() val hi = readPc() fetchedAddress = regY+(lo or (hi shl 8)) and 0xffff + // if this address is a different page, extra clock cycle: + (fetchedAddress and 0xff00) != hi shl 8 } AddrMode.Ind -> { var lo = readPc() @@ -686,6 +699,7 @@ open class Cpu6502 : BusComponent() { hi = read(fetchedAddress+1) } fetchedAddress = lo or (hi shl 8) + false } AddrMode.IzX -> { // note: not able to fetch an address which crosses the (zero)page boundary @@ -693,6 +707,7 @@ open class Cpu6502 : BusComponent() { val lo = read((fetchedAddress+regX) and 0xff) val hi = read((fetchedAddress+regX+1) and 0xff) fetchedAddress = lo or (hi shl 8) + false } AddrMode.IzY -> { // note: not able to fetch an address which crosses the (zero)page boundary @@ -700,6 +715,7 @@ open class Cpu6502 : BusComponent() { val lo = read(fetchedAddress) val hi = read((fetchedAddress+1) and 0xff) fetchedAddress = regY+(lo or (hi shl 8)) and 0xffff + false } AddrMode.Zpr, AddrMode.Izp, AddrMode.IaX -> { // addressing mode used by the 65C02 only @@ -708,7 +724,7 @@ open class Cpu6502 : BusComponent() { } } - protected open fun dispatchOpcode(opcode: Int) { + protected open fun dispatchOpcode(opcode: Int): Boolean { when (opcode) { 0x00 -> iBrk() 0x01 -> iOra() @@ -966,9 +982,9 @@ open class Cpu6502 : BusComponent() { 0xfd -> iSbc() 0xfe -> iInc() 0xff -> iIsc() - else -> { /* can't occur */ - } + else -> { /* can't occur */ } } + return false // TODO determine if instructions can cause extra clock cycle } diff --git a/src/main/kotlin/razorvine/ksim65/Cpu65C02.kt b/src/main/kotlin/razorvine/ksim65/Cpu65C02.kt index 6cc4910..2be8f1a 100644 --- a/src/main/kotlin/razorvine/ksim65/Cpu65C02.kt +++ b/src/main/kotlin/razorvine/ksim65/Cpu65C02.kt @@ -4,7 +4,6 @@ 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 : Cpu6502() { override val name = "65C02" @@ -56,9 +55,10 @@ class Cpu65C02 : Cpu6502() { // 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 -> { + override fun applyAddressingMode(addrMode: AddrMode): Boolean { + return 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 -> { @@ -69,15 +69,16 @@ class Cpu65C02 : Cpu6502() { lo = read(fetchedAddress) hi = read(fetchedAddress+1) fetchedAddress = lo or (hi shl 8) + false } AddrMode.Zpr -> { // addressing mode used by the 65C02 only - // combination of zp addresssing + relative branch addressing + // combination of zp addressing + relative branch addressing fetchedAddress = readPc() val relative = readPc() - fetchedAddressZpr = if (relative >= 0x80) { - regPC-(256-relative) and 0xffff - } else regPC+relative and 0xffff + fetchedAddressZpr = + if (relative >= 0x80) regPC-(256-relative) and 0xffff else regPC+relative and 0xffff + false } AddrMode.Izp -> { // addressing mode used by the 65C02 only @@ -85,6 +86,7 @@ class Cpu65C02 : Cpu6502() { val lo = read((fetchedAddress) and 0xff) val hi = read((fetchedAddress+1) and 0xff) fetchedAddress = lo or (hi shl 8) + false } AddrMode.IaX -> { // addressing mode used by the 65C02 only @@ -94,11 +96,13 @@ class Cpu65C02 : Cpu6502() { lo = read((fetchedAddress+regX) and 0xffff) hi = read((fetchedAddress+regX+1) and 0xffff) fetchedAddress = lo or (hi shl 8) + // if this address is a different page, extra clock cycle: + (fetchedAddress and 0xff00) != hi shl 8 } } } - override fun dispatchOpcode(opcode: Int) { + override fun dispatchOpcode(opcode: Int): Boolean { when (opcode) { 0x00 -> iBrk() 0x01 -> iOra() @@ -356,9 +360,9 @@ class Cpu65C02 : Cpu6502() { 0xfd -> iSbc() 0xfe -> iInc() 0xff -> iBbs7() - else -> { /* can't occur */ - } + else -> { /* can't occur */ } } + return false // TODO determine if instructions can cause extra clock cycle } // opcode list: http://www.oxyron.de/html/opcodesc02.html