From 4f9f9c4b9b2291731c2f0c9f311321a21e6a4383 Mon Sep 17 00:00:00 2001 From: Felipe Lima Date: Tue, 16 Jun 2015 23:20:23 -0700 Subject: [PATCH] Fixes failing tests --- app/src/main/kotlin/android/emu6502/CPU.kt | 105 ++++++++++++------ app/src/main/kotlin/android/emu6502/Utils.kt | 4 - .../android/emu6502/instructions/impl/BNE.kt | 15 +++ .../android/emu6502/instructions/impl/BRK.kt | 2 +- .../android/emu6502/instructions/impl/CPX.kt | 13 +++ .../android/emu6502/instructions/impl/DEX.kt | 14 +++ .../android/emu6502/instructions/impl/LDA.kt | 4 +- .../android/emu6502/instructions/impl/LDX.kt | 6 +- .../android/emu6502/instructions/impl/LDY.kt | 3 +- .../android/emu6502/instructions/impl/ORA.kt | 3 +- .../android/emu6502/instructions/impl/STX.kt | 10 +- .../test/java/android/emu6502/CPUTest.java | 4 + 12 files changed, 137 insertions(+), 46 deletions(-) create mode 100644 app/src/main/kotlin/android/emu6502/instructions/impl/BNE.kt create mode 100644 app/src/main/kotlin/android/emu6502/instructions/impl/CPX.kt create mode 100644 app/src/main/kotlin/android/emu6502/instructions/impl/DEX.kt diff --git a/app/src/main/kotlin/android/emu6502/CPU.kt b/app/src/main/kotlin/android/emu6502/CPU.kt index 58ffd95..d63ed6d 100644 --- a/app/src/main/kotlin/android/emu6502/CPU.kt +++ b/app/src/main/kotlin/android/emu6502/CPU.kt @@ -8,7 +8,7 @@ import android.util.Log import java.util.HashMap import kotlin.reflect.KMemberFunction0 -class CPU(private val memory: Memory) { +class CPU(val memory: Memory) { // Accumulator var A: Int = 0 // Registers @@ -19,7 +19,7 @@ class CPU(private val memory: Memory) { // Stack pointer var SP: Int = 0xFF // Processor flags - var P: Int = 0 + var P: Int = 0x30 private var isRunning = false private var debug = false private var monitoring = false @@ -37,18 +37,19 @@ class CPU(private val memory: Memory) { Pair(Instruction.STX, STX(this)), Pair(Instruction.TAX, TAX(this)), Pair(Instruction.INX, INX(this)), - Pair(Instruction.ORA, ORA(this)) + Pair(Instruction.DEX, DEX(this)), + Pair(Instruction.ORA, ORA(this)), + Pair(Instruction.CPX, CPX(this)), + Pair(Instruction.BRK, BRK(this)), + Pair(Instruction.BNE, BNE(this)) // Pair(Instruction.BPL, BPL(this)), // Pair(Instruction.BMI, BMI(this)), // Pair(Instruction.BVC, BVC(this)), // Pair(Instruction.BVS, BVS(this)), // Pair(Instruction.BCC, BCC(this)), // Pair(Instruction.BCS, BCS(this)), -// Pair(Instruction.BNE, BNE(this)), // Pair(Instruction.BEQ, BEQ(this)), -// Pair(Instruction.BRK, BRK(this)), // Pair(Instruction.CMP, CMP(this)), -// Pair(Instruction.CPX, CPX(this)), // Pair(Instruction.CPY, CPY(this)), // Pair(Instruction.DEC, DEC(this)), // Pair(Instruction.EOR, EOR(this)), @@ -65,7 +66,6 @@ class CPU(private val memory: Memory) { // Pair(Instruction.LSR, LSR(this)), // Pair(Instruction.NOP, NOP(this)), // Pair(Instruction.TXA, TXA(this)), -// Pair(Instruction.DEX, DEX(this)), // Pair(Instruction.TAY, TAY(this)), // Pair(Instruction.TYA, TYA(this)), // Pair(Instruction.DEY, DEY(this)), @@ -124,14 +124,14 @@ class CPU(private val memory: Memory) { } fun setSZFlagsForRegA() { - setSZFlagsForValue(A) + setSVFlagsForValue(A) } fun setSZflagsForRegX() { - setSZFlagsForValue(X) + setSVFlagsForValue(X) } - private fun setSZFlagsForValue(value: Int) { + private fun setSVFlagsForValue(value: Int) { if (value != 0) { P = P.and(0xfd) } else { @@ -156,34 +156,34 @@ class CPU(private val memory: Memory) { setOverflow() } - if (decimalMode().isSet()) { - tmp = A.and(0xf) + value.and(0xf) + carry() + if (decimalMode()) { + tmp = A.and(0xf) + value.and(0xf) + P.and(1) if (tmp >= 10) { tmp = 0x10.or((tmp + 6).and(0xf)) } tmp += A.and(0xf0) + value.and(0xf0) if (tmp >= 160) { SEC() - if (overflow().isSet() && tmp >= 0x180) { + if (overflow() && tmp >= 0x180) { CLV() } tmp += 0x60 } else { CLC() - if (overflow().isSet() && tmp < 0x80) { + if (overflow() && tmp < 0x80) { CLV() } } } else { - tmp = A + value + carry() + tmp = A + value + P.and(1) if (tmp >= 0x100) { SEC() - if (overflow().isSet() && tmp >= 0x180) { + if (overflow() && tmp >= 0x180) { CLV() } } else { CLC() - if (overflow().isSet() && tmp < 0x80) { + if (overflow() && tmp < 0x80) { CLV() } } @@ -192,42 +192,85 @@ class CPU(private val memory: Memory) { setSZFlagsForRegA() } - fun overflow(): Int { - return P.and(0x40) + private fun overflow(): Boolean { + return P.and(0x40) != 0 } - fun decimalMode(): Int { - return P.and(8); + private fun decimalMode(): Boolean { + return P.and(8) != 0 } - fun carry(): Int { - return P.and(1); + private fun carry(): Boolean { + return P.and(1) != 0 } - fun negative(): Int { - return P.and(0x80); + private fun negative(): Boolean { + return P.and(0x80) != 0 } - fun zero(): Int { - return P.and(0x02); + fun zero(): Boolean { + return P.and(0x02) != 0 + } + + fun jumpBranch(offset: Int) { + if (offset > 0x7f) { + PC -= (0x100 - offset) + } else { + PC += offset + } + } + + fun doCompare(reg: Int, value: Int) { + if (reg >= value) { + SEC() + } else { + CLC() + } + setSVFlagsForValue(reg - value) } /** CLear Carry */ - fun CLC() { + private fun CLC() { P = P.and(0xfe) } /** SEt Carry */ - fun SEC() { + private fun SEC() { P = P.or(1) } /** CLear oVerflow */ - fun CLV() { + private fun CLV() { P = P.and(0xbf) } - fun setOverflow() { + private fun setOverflow() { P = P.or(0x40) } + + /** + * http://nesdev.com/6502.txt + * Returns the processor flags in the format SV-BDIZC + * Sign - this is set if the result of an operation is negative, cleared if positive. + * Overflow - when an arithmetic operation produces a result too large to be represented in a byte + * Unused - Supposed to be logical 1 at all times. + * Break - this is set when a software interrupt (BRK instruction) is executed. + * Decimal Mode - When set, and an Add with Carry or Subtract with Carry instruction is executed, + * the source values are treated as valid BCD (Binary Coded Decimal, eg. 0x00-0x99 = 0-99) numbers. + * The result generated is also a BCD number. + * Interrupt - If it is set, interrupts are disabled. If it is cleared, interrupts are enabled. + * Zero - this is set to 1 when any arithmetic or logical operation produces a zero result, and is + * set to 0 if the result is non-zero. + * Carry - this holds the carry out of the most significant bit in any arithmetic operation. + * In subtraction operations however, this flag is cleared - set to 0 - if a borrow is required, + * set to 1 - if no borrow is required. The carry flag is also used in shift and rotate logical + * operations. + * */ + fun flags(): String { + val flags = StringBuilder() + for (i in 7 downTo 0) { + flags.append(P.shr(i).and(1)) + } + return flags.toString() + } } \ No newline at end of file diff --git a/app/src/main/kotlin/android/emu6502/Utils.kt b/app/src/main/kotlin/android/emu6502/Utils.kt index 3311e51..0fdccb0 100644 --- a/app/src/main/kotlin/android/emu6502/Utils.kt +++ b/app/src/main/kotlin/android/emu6502/Utils.kt @@ -2,8 +2,4 @@ package android.emu6502 fun Int.toHexString(): String { return java.lang.String.format("%02X", this); -} - -fun Int.isSet(): Boolean { - return this != 0 } \ No newline at end of file diff --git a/app/src/main/kotlin/android/emu6502/instructions/impl/BNE.kt b/app/src/main/kotlin/android/emu6502/instructions/impl/BNE.kt new file mode 100644 index 0000000..fe30e84 --- /dev/null +++ b/app/src/main/kotlin/android/emu6502/instructions/impl/BNE.kt @@ -0,0 +1,15 @@ +package android.emu6502.instructions.impl + +import android.emu6502.CPU +import android.emu6502.instructions.BaseInstruction +import android.emu6502.instructions.Instruction + +/** Branch on Not Equal */ +final class BNE(private val cpu: CPU) : BaseInstruction(Instruction.BNE, cpu.instructionList) { + override fun branch() { + val offset = cpu.popByte() + if (!cpu.zero()) { + cpu.jumpBranch(offset) + } + } +} diff --git a/app/src/main/kotlin/android/emu6502/instructions/impl/BRK.kt b/app/src/main/kotlin/android/emu6502/instructions/impl/BRK.kt index 5dcedca..8241556 100644 --- a/app/src/main/kotlin/android/emu6502/instructions/impl/BRK.kt +++ b/app/src/main/kotlin/android/emu6502/instructions/impl/BRK.kt @@ -5,7 +5,7 @@ import android.emu6502.instructions.BaseInstruction import android.emu6502.instructions.Instruction /** BRreaK */ -final class BRK(private val cpu: CPU) : BaseInstruction(Instruction.INX, cpu.instructionList) { +final class BRK(private val cpu: CPU) : BaseInstruction(Instruction.BRK, cpu.instructionList) { override fun single() { cpu.stop() } diff --git a/app/src/main/kotlin/android/emu6502/instructions/impl/CPX.kt b/app/src/main/kotlin/android/emu6502/instructions/impl/CPX.kt new file mode 100644 index 0000000..745c120 --- /dev/null +++ b/app/src/main/kotlin/android/emu6502/instructions/impl/CPX.kt @@ -0,0 +1,13 @@ +package android.emu6502.instructions.impl + +import android.emu6502.CPU +import android.emu6502.instructions.BaseInstruction +import android.emu6502.instructions.Instruction + +/** ComPare X register */ +class CPX(private val cpu: CPU) : BaseInstruction(Instruction.CPX, cpu.instructionList) { + override fun immediate() { + val value = cpu.popByte() + cpu.doCompare(cpu.X, value) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/android/emu6502/instructions/impl/DEX.kt b/app/src/main/kotlin/android/emu6502/instructions/impl/DEX.kt new file mode 100644 index 0000000..089c7df --- /dev/null +++ b/app/src/main/kotlin/android/emu6502/instructions/impl/DEX.kt @@ -0,0 +1,14 @@ +package android.emu6502.instructions.impl + +import android.emu6502.CPU +import android.emu6502.instructions.BaseInstruction +import android.emu6502.instructions.Instruction + +/**DEcrement X */ +class DEX(private val cpu: CPU) : BaseInstruction(Instruction.DEX, cpu.instructionList) { + override fun single() { + cpu.X = (cpu.X - 1).and(0xff) + cpu.setSZflagsForRegX() + } +} + diff --git a/app/src/main/kotlin/android/emu6502/instructions/impl/LDA.kt b/app/src/main/kotlin/android/emu6502/instructions/impl/LDA.kt index 9421d4b..ff71ff8 100644 --- a/app/src/main/kotlin/android/emu6502/instructions/impl/LDA.kt +++ b/app/src/main/kotlin/android/emu6502/instructions/impl/LDA.kt @@ -5,9 +5,7 @@ import android.emu6502.instructions.BaseInstruction import android.emu6502.instructions.Instruction /** LoaD Accumulator */ -class LDA(private val cpu: CPU) - : BaseInstruction(Instruction.LDA, cpu.instructionList) { - +class LDA(private val cpu: CPU) : BaseInstruction(Instruction.LDA, cpu.instructionList) { override fun immediate() { cpu.A = cpu.popByte() cpu.setSZFlagsForRegA() diff --git a/app/src/main/kotlin/android/emu6502/instructions/impl/LDX.kt b/app/src/main/kotlin/android/emu6502/instructions/impl/LDX.kt index 17d56ea..8675773 100644 --- a/app/src/main/kotlin/android/emu6502/instructions/impl/LDX.kt +++ b/app/src/main/kotlin/android/emu6502/instructions/impl/LDX.kt @@ -5,5 +5,9 @@ import android.emu6502.instructions.BaseInstruction import android.emu6502.instructions.Instruction /** LoaD X register */ -class LDX(cpu: CPU) : BaseInstruction(Instruction.LDX, cpu.instructionList) { +class LDX(private val cpu: CPU) : BaseInstruction(Instruction.LDX, cpu.instructionList) { + override fun immediate() { + cpu.X = cpu.popByte() + cpu.setSZflagsForRegX() + } } diff --git a/app/src/main/kotlin/android/emu6502/instructions/impl/LDY.kt b/app/src/main/kotlin/android/emu6502/instructions/impl/LDY.kt index 9bd7dd3..b60b1ed 100644 --- a/app/src/main/kotlin/android/emu6502/instructions/impl/LDY.kt +++ b/app/src/main/kotlin/android/emu6502/instructions/impl/LDY.kt @@ -5,6 +5,5 @@ import android.emu6502.instructions.BaseInstruction import android.emu6502.instructions.Instruction /** LoaD Y register */ -class LDY(cpu: CPU) -: BaseInstruction(Instruction.LDY, cpu.instructionList) { +class LDY(cpu: CPU) : BaseInstruction(Instruction.LDY, cpu.instructionList) { } diff --git a/app/src/main/kotlin/android/emu6502/instructions/impl/ORA.kt b/app/src/main/kotlin/android/emu6502/instructions/impl/ORA.kt index 525be0c..d2a954b 100644 --- a/app/src/main/kotlin/android/emu6502/instructions/impl/ORA.kt +++ b/app/src/main/kotlin/android/emu6502/instructions/impl/ORA.kt @@ -5,6 +5,5 @@ import android.emu6502.instructions.BaseInstruction import android.emu6502.instructions.Instruction /** bitwise OR with Accumulator */ -class ORA(cpu: CPU) - : BaseInstruction(Instruction.ORA, cpu.instructionList) { +class ORA(cpu: CPU) : BaseInstruction(Instruction.ORA, cpu.instructionList) { } \ No newline at end of file diff --git a/app/src/main/kotlin/android/emu6502/instructions/impl/STX.kt b/app/src/main/kotlin/android/emu6502/instructions/impl/STX.kt index 1cb3df6..bd06cfc 100644 --- a/app/src/main/kotlin/android/emu6502/instructions/impl/STX.kt +++ b/app/src/main/kotlin/android/emu6502/instructions/impl/STX.kt @@ -5,6 +5,12 @@ import android.emu6502.instructions.BaseInstruction import android.emu6502.instructions.Instruction /** STore X register */ -class STX(cpu: CPU) -: BaseInstruction(Instruction.STX, cpu.instructionList) { +class STX(private val cpu: CPU) : BaseInstruction(Instruction.STX, cpu.instructionList) { + override fun zeroPage() { + cpu.memory.storeByte(cpu.popByte(), cpu.X) + } + + override fun absolute() { + cpu.memory.storeByte(cpu.popWord(), cpu.X) + } } diff --git a/app/src/test/java/android/emu6502/CPUTest.java b/app/src/test/java/android/emu6502/CPUTest.java index cc02166..2f6f552 100644 --- a/app/src/test/java/android/emu6502/CPUTest.java +++ b/app/src/test/java/android/emu6502/CPUTest.java @@ -38,6 +38,7 @@ public class CPUTest { assertThat(cpu.getY(), equalTo(0x00)); assertThat(cpu.getSP(), equalTo(0xFF)); assertThat(cpu.getPC(), equalTo(0x0610)); + assertThat(cpu.flags(), equalTo("00110000")); } @Test public void testWithComments() { @@ -54,6 +55,7 @@ public class CPUTest { assertThat(cpu.getY(), equalTo(0x00)); assertThat(cpu.getSP(), equalTo(0xFF)); assertThat(cpu.getPC(), equalTo(0x0607)); + assertThat(cpu.flags(), equalTo("10110001")); } @Test public void testBranchAndLabel() { @@ -67,10 +69,12 @@ public class CPUTest { "STX $0201", "BRK"); assembler.assembleCode(lines); + cpu.execute(); assertThat(cpu.getA(), equalTo(0x00)); assertThat(cpu.getX(), equalTo(0x03)); assertThat(cpu.getY(), equalTo(0x00)); assertThat(cpu.getSP(), equalTo(0xFF)); assertThat(cpu.getPC(), equalTo(0x060e)); + assertThat(cpu.flags(), equalTo("00110011")); } }