From 1f4f9278ddaec5ce737894c35eda05599b6876e6 Mon Sep 17 00:00:00 2001 From: Felipe Lima Date: Sat, 27 Jun 2015 17:47:02 -0700 Subject: [PATCH] Implements a few more instructions --- app/src/main/kotlin/android/emu6502/CPU.kt | 14 +- .../android/emu6502/instructions/impl/AND.kt | 7 +- .../android/emu6502/instructions/impl/DEX.kt | 2 +- .../android/emu6502/instructions/impl/DEY.kt | 13 + .../android/emu6502/instructions/impl/LDA.kt | 5 + .../android/emu6502/instructions/impl/SEI.kt | 10 + .../android/emu6502/instructions/impl/STA.kt | 6 +- .../test/java/android/emu6502/CPUTest.java | 232 ++++++++++++++++++ 8 files changed, 280 insertions(+), 9 deletions(-) create mode 100644 app/src/main/kotlin/android/emu6502/instructions/impl/DEY.kt create mode 100644 app/src/main/kotlin/android/emu6502/instructions/impl/SEI.kt diff --git a/app/src/main/kotlin/android/emu6502/CPU.kt b/app/src/main/kotlin/android/emu6502/CPU.kt index f9b42d8..16e7392 100644 --- a/app/src/main/kotlin/android/emu6502/CPU.kt +++ b/app/src/main/kotlin/android/emu6502/CPU.kt @@ -44,7 +44,9 @@ class CPU(val memory: Memory) { Pair(Instruction.BNE, BNE(this)), Pair(Instruction.JMP, JMP(this)), Pair(Instruction.JSR, JSR(this)), - Pair(Instruction.RTS, RTS(this)) + Pair(Instruction.RTS, RTS(this)), + Pair(Instruction.SEI, SEI(this)), + Pair(Instruction.DEY, DEY(this)) // Pair(Instruction.BPL, BPL(this)), // Pair(Instruction.BMI, BMI(this)), // Pair(Instruction.BVC, BVC(this)), @@ -59,7 +61,6 @@ class CPU(val memory: Memory) { // Pair(Instruction.CLC, CLC(this)), // Pair(Instruction.SEC, SEC(this)), // Pair(Instruction.CLI, CLI(this)), -// Pair(Instruction.SEI, SEI(this)), // Pair(Instruction.CLV, CLV(this)), // Pair(Instruction.CLD, CLD(this)), // Pair(Instruction.SED, SED(this)), @@ -69,7 +70,6 @@ class CPU(val memory: Memory) { // Pair(Instruction.TXA, TXA(this)), // Pair(Instruction.TAY, TAY(this)), // Pair(Instruction.TYA, TYA(this)), -// Pair(Instruction.DEY, DEY(this)), // Pair(Instruction.INY, INY(this)), // Pair(Instruction.ROR, ROR(this)), // Pair(Instruction.ROL, ROL(this)), @@ -106,8 +106,8 @@ class CPU(val memory: Memory) { val function = target.method target.operation.function() } else { - Log.e(TAG, "Address $" + PC.toHexString() + " - unknown opcode " + instruction.toHexString()) - stop() + throw Exception( + "Address $" + PC.toHexString() + " - unknown opcode " + instruction.toHexString()) } } @@ -131,6 +131,10 @@ class CPU(val memory: Memory) { setSVFlagsForValue(X) } + fun setSZflagsForRegY() { + setSVFlagsForValue(Y) + } + private fun setSVFlagsForValue(value: Int) { if (value != 0) { P = P.and(0xfd) diff --git a/app/src/main/kotlin/android/emu6502/instructions/impl/AND.kt b/app/src/main/kotlin/android/emu6502/instructions/impl/AND.kt index a180c90..a6fc33f 100644 --- a/app/src/main/kotlin/android/emu6502/instructions/impl/AND.kt +++ b/app/src/main/kotlin/android/emu6502/instructions/impl/AND.kt @@ -5,6 +5,9 @@ import android.emu6502.instructions.BaseInstruction import android.emu6502.instructions.Instruction /** bitwise AND with accumulator */ -class AND(cpu: CPU) - : BaseInstruction(Instruction.AND, cpu.instructionList) { +class AND(private val cpu: CPU) : BaseInstruction(Instruction.AND, cpu.instructionList) { + override fun immediate() { + cpu.A = cpu.A.and(cpu.popByte()) + cpu.setSZFlagsForRegA() + } } \ 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 index 089c7df..c5dd738 100644 --- a/app/src/main/kotlin/android/emu6502/instructions/impl/DEX.kt +++ b/app/src/main/kotlin/android/emu6502/instructions/impl/DEX.kt @@ -4,7 +4,7 @@ import android.emu6502.CPU import android.emu6502.instructions.BaseInstruction import android.emu6502.instructions.Instruction -/**DEcrement X */ +/** DEcrement X */ class DEX(private val cpu: CPU) : BaseInstruction(Instruction.DEX, cpu.instructionList) { override fun single() { cpu.X = (cpu.X - 1).and(0xff) diff --git a/app/src/main/kotlin/android/emu6502/instructions/impl/DEY.kt b/app/src/main/kotlin/android/emu6502/instructions/impl/DEY.kt new file mode 100644 index 0000000..f75dd78 --- /dev/null +++ b/app/src/main/kotlin/android/emu6502/instructions/impl/DEY.kt @@ -0,0 +1,13 @@ +package android.emu6502.instructions.impl + +import android.emu6502.CPU +import android.emu6502.instructions.BaseInstruction +import android.emu6502.instructions.Instruction + +/** DEcrement Y */ +class DEY(private val cpu: CPU) : BaseInstruction(Instruction.DEY, cpu.instructionList) { + override fun single() { + cpu.Y = (cpu.Y - 1).and(0xff) + cpu.setSZflagsForRegY() + } +} 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 ff71ff8..cccd7c6 100644 --- a/app/src/main/kotlin/android/emu6502/instructions/impl/LDA.kt +++ b/app/src/main/kotlin/android/emu6502/instructions/impl/LDA.kt @@ -10,4 +10,9 @@ class LDA(private val cpu: CPU) : BaseInstruction(Instruction.LDA, cpu.instructi cpu.A = cpu.popByte() cpu.setSZFlagsForRegA() } + + override fun zeroPage() { + cpu.A = cpu.memory.get(cpu.popByte()) + cpu.setSZFlagsForRegA() + } } diff --git a/app/src/main/kotlin/android/emu6502/instructions/impl/SEI.kt b/app/src/main/kotlin/android/emu6502/instructions/impl/SEI.kt new file mode 100644 index 0000000..f3b6b1d --- /dev/null +++ b/app/src/main/kotlin/android/emu6502/instructions/impl/SEI.kt @@ -0,0 +1,10 @@ +package android.emu6502.instructions.impl + +import android.emu6502.CPU +import android.emu6502.instructions.BaseInstruction +import android.emu6502.instructions.Instruction + +/** SEt Interrupt */ +class SEI(private val cpu: CPU) : BaseInstruction(Instruction.SEI, cpu.instructionList) { +} + diff --git a/app/src/main/kotlin/android/emu6502/instructions/impl/STA.kt b/app/src/main/kotlin/android/emu6502/instructions/impl/STA.kt index 2d34aea..185651c 100644 --- a/app/src/main/kotlin/android/emu6502/instructions/impl/STA.kt +++ b/app/src/main/kotlin/android/emu6502/instructions/impl/STA.kt @@ -10,7 +10,11 @@ class STA(private val memory: Memory, private val cpu: CPU) : BaseInstruction(Instruction.STA, cpu.instructionList) { override fun absolute() { - memory.storeByte(cpu.popWord(), cpu.A); + memory.storeByte(cpu.popWord(), cpu.A) + } + + override fun zeroPage() { + memory.storeByte(cpu.popByte(), cpu.A) } } diff --git a/app/src/test/java/android/emu6502/CPUTest.java b/app/src/test/java/android/emu6502/CPUTest.java index 34474a8..a658ccd 100644 --- a/app/src/test/java/android/emu6502/CPUTest.java +++ b/app/src/test/java/android/emu6502/CPUTest.java @@ -142,4 +142,236 @@ public class CPUTest { assertThat(cpu.getPC(), equalTo(0x0603)); assertThat(cpu.flags(), equalTo("00110000")); } + + @Test public void testSnake() { + List lines = ImmutableList.of( + "define appleL $00 ; screen location of apple, low byte", + "define appleH $01 ; screen location of apple, high byte", + "define snakeHeadL $10 ; screen location of snake head, low byte", + "define snakeHeadH $11 ; screen location of snake head, high byte", + "define snakeBodyStart $12 ; start of snake body byte pairs", + "define snakeDirection $02 ; direction (possible values are below)", + "define snakeLength $03 ; snake length, in bytes", + "; Directions (each using a separate bit)", + "define movingUp 1", + "define movingRight 2", + "define movingDown 4", + "define movingLeft 8", + "; ASCII values of keys controlling the snake", + "define ASCII_w $77", + "define ASCII_a $61", + "define ASCII_s $73", + "define ASCII_d $64", + "; System variables", + "define sysRandom $fe", + "define sysLastKey $ff", + " jsr init", + " jsr loop", + "init:", + " jsr initSnake", + " jsr generateApplePosition", + " rts", + "initSnake:", + " lda #movingRight ;start direction", + " sta snakeDirection", + " lda #4 ;start length (2 segments)", + " sta snakeLength", + " ", + " lda #$11", + " sta snakeHeadL", + " ", + " lda #$10", + " sta snakeBodyStart", + " ", + " lda #$0f", + " sta $14 ; body segment 1", + " ", + " lda #$04", + " sta snakeHeadH", + " sta $13 ; body segment 1", + " sta $15 ; body segment 2", + " rts", + "generateApplePosition:", + " ;load a new random byte into $00", + " lda sysRandom", + " sta appleL", + " ;load a new random number from 2 to 5 into $01", + " lda sysRandom", + " and #$03 ;mask out lowest 2 bits", + " clc", + " adc #2", + " sta appleH", + " rts", + "loop:", + " jsr readKeys", + " jsr checkCollision", + " jsr updateSnake", + " jsr drawApple", + " jsr drawSnake", + " jsr spinWheels", + " jmp loop", + "readKeys:", + " lda sysLastKey", + " cmp #ASCII_w", + " beq upKey", + " cmp #ASCII_d", + " beq rightKey", + " cmp #ASCII_s", + " beq downKey", + " cmp #ASCII_a", + " beq leftKey", + " rts", + "upKey:", + " lda #movingDown", + " bit snakeDirection", + " bne illegalMove", + + " lda #movingUp", + " sta snakeDirection", + " rts", + "rightKey:", + " lda #movingLeft", + " bit snakeDirection", + " bne illegalMove", + " lda #movingRight", + " sta snakeDirection", + " rts", + "downKey:", + " lda #movingUp", + " bit snakeDirection", + " bne illegalMove", + " lda #movingDown", + " sta snakeDirection", + " rts", + "leftKey:", + " lda #movingRight", + " bit snakeDirection", + " bne illegalMove", + " lda #movingLeft", + " sta snakeDirection", + " rts", + "illegalMove:", + " rts", + "checkCollision:", + " jsr checkAppleCollision", + " jsr checkSnakeCollision", + " rts", + "checkAppleCollision:", + " lda appleL", + " cmp snakeHeadL", + " bne doneCheckingAppleCollision", + " lda appleH", + " cmp snakeHeadH", + " bne doneCheckingAppleCollision", + " ;eat apple", + " inc snakeLength", + " inc snakeLength ;increase length", + " jsr generateApplePosition", + "doneCheckingAppleCollision:", + " rts", + "checkSnakeCollision:", + " ldx #2 ;start with second segment", + "snakeCollisionLoop:", + " lda snakeHeadL,x", + " cmp snakeHeadL", + " bne continueCollisionLoop", + "maybeCollided:", + " lda snakeHeadH,x", + " cmp snakeHeadH", + " beq didCollide", + "continueCollisionLoop:", + " inx", + " inx", + " cpx snakeLength ;got to last section with no collision", + " beq didntCollide", + " jmp snakeCollisionLoop", + "didCollide:", + " jmp gameOver", + "didntCollide:", + " rts", + "updateSnake:", + " ldx snakeLength", + " dex", + " txa", + "updateloop:", + " lda snakeHeadL,x", + " sta snakeBodyStart,x", + " dex", + " bpl updateloop", + " lda snakeDirection", + " lsr", + " bcs up", + " lsr", + " bcs right", + " lsr", + " bcs down", + " lsr", + " bcs left", + "up:", + " lda snakeHeadL", + " sec", + " sbc #$20", + " sta snakeHeadL", + " bcc upup", + " rts", + "upup:", + " dec snakeHeadH", + " lda #$1", + " cmp snakeHeadH", + " beq collision", + " rts", + "right:", + " inc snakeHeadL", + " lda #$1f", + " bit snakeHeadL", + " beq collision", + " rts", + "down:", + " lda snakeHeadL", + " clc", + " adc #$20", + " sta snakeHeadL", + " bcs downdown", + " rts", + "downdown:", + " inc snakeHeadH", + " lda #$6", + " cmp snakeHeadH", + " beq collision", + " rts", + "left:", + " dec snakeHeadL", + " lda snakeHeadL", + " and #$1f", + " cmp #$1f", + " beq collision", + " rts", + "collision:", + " jmp gameOver", + "drawApple:", + " ldy #0", + " lda sysRandom", + " sta (appleL),y", + " rts", + "drawSnake:", + " ldx #0", + " lda #1", + " sta (snakeHeadL,x) ; paint head", + " ", + " ldx snakeLength", + " lda #0", + " sta (snakeHeadL,x) ; erase end of tail", + " rts", + "spinWheels:", + " ldx #0", + "spinloop:", + " nop", + " nop", + " dex", + " bne spinloop", + " rts", + "gameOver:", "\n"); + assembler.assembleCode(lines); + cpu.execute(); + } }