diff --git a/app/build.gradle b/app/build.gradle index 8f5a7a4..fd2cf61 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -31,8 +31,6 @@ dependencies { compile 'com.google.guava:guava:20.0' testCompile 'junit:junit:4.12' + testCompile 'com.google.truth:truth:0.32' testCompile 'org.mockito:mockito-core:1.10.19' - testCompile 'org.hamcrest:hamcrest-integration:1.3' - testCompile 'org.hamcrest:hamcrest-core:1.3' - testCompile 'org.hamcrest:hamcrest-library:1.3' } diff --git a/app/src/main/kotlin/android/emu6502/nes/Cartridge.kt b/app/src/main/kotlin/android/emu6502/nes/Cartridge.kt new file mode 100644 index 0000000..cc9c542 --- /dev/null +++ b/app/src/main/kotlin/android/emu6502/nes/Cartridge.kt @@ -0,0 +1,41 @@ +package android.emu6502.nes + +import java.util.* + +data class Cartridge( + // @formatter:off + val pgr: ByteArray, // PRG-ROM banks + val chr: ByteArray, // CHR-ROM banks + val mapper: Byte, // mapper type + val mirror: Byte, // mirroring mode + val battery: Byte // battery present + // @formatter:on +) { + private val sram: ByteArray = ByteArray(0x2000) // Save RAM + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other?.javaClass != javaClass) return false + + other as Cartridge + + if (!Arrays.equals(pgr, other.pgr)) return false + if (!Arrays.equals(chr, other.chr)) return false + if (!Arrays.equals(sram, other.sram)) return false + if (mapper != other.mapper) return false + if (mirror != other.mirror) return false + if (battery != other.battery) return false + + return true + } + + override fun hashCode(): Int { + var result = Arrays.hashCode(pgr) + result = 31 * result + Arrays.hashCode(chr) + result = 31 * result + Arrays.hashCode(sram) + result = 31 * result + mapper + result = 31 * result + mirror + result = 31 * result + battery + return result + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/android/emu6502/nes/INESFileHeader.kt b/app/src/main/kotlin/android/emu6502/nes/INESFileHeader.kt new file mode 100644 index 0000000..e43a071 --- /dev/null +++ b/app/src/main/kotlin/android/emu6502/nes/INESFileHeader.kt @@ -0,0 +1,51 @@ +package android.emu6502.nes + +import android.emu6502.nes.INESFileParser.Companion.INES_FILE_MAGIC +import android.emu6502.nes.INESFileParser.Companion.PADDING +import java.util.* + +// http://wiki.nesdev.com/w/index.php/INES +// Sample header: +// 4e 45 53 1a 10 10 40 00 00 00 00 00 00 00 00 00 +data class INESFileHeader( + // @formatter:off + val magic: ByteArray, // Constant $4E $45 $53 $1A ("NES" followed by MS-DOS end-of-file) + val numPRG: Byte, // Size of PRG ROM in 16 KB units + val numCHR: Byte, // Size of CHR ROM in 8 KB units (Value 0 means the board uses CHR RAM) + val control1: Byte, // Flags 6 + val control2: Byte, // Flags 7 + val numRAM: Byte, // Size of PRG RAM in 8 KB units + val padding: ByteArray // 7 bytes, unused + // @formatter:on +) { + fun isValid() = + Arrays.equals(magic, INES_FILE_MAGIC) && Arrays.equals(padding, PADDING) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other?.javaClass != javaClass) return false + + other as INESFileHeader + + if (!Arrays.equals(magic, other.magic)) return false + if (numPRG != other.numPRG) return false + if (numCHR != other.numCHR) return false + if (control1 != other.control1) return false + if (control2 != other.control2) return false + if (numRAM != other.numRAM) return false + if (!Arrays.equals(padding, other.padding)) return false + + return true + } + + override fun hashCode(): Int { + var result = Arrays.hashCode(magic) + result = 31 * result + numPRG + result = 31 * result + numCHR + result = 31 * result + control1 + result = 31 * result + control2 + result = 31 * result + numRAM + result = 31 * result + Arrays.hashCode(padding) + return result + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/android/emu6502/nes/INESFileParser.kt b/app/src/main/kotlin/android/emu6502/nes/INESFileParser.kt new file mode 100644 index 0000000..6c0dcff --- /dev/null +++ b/app/src/main/kotlin/android/emu6502/nes/INESFileParser.kt @@ -0,0 +1,49 @@ +package android.emu6502.nes + +import java.io.DataInputStream +import java.io.File +import java.io.InputStream + +internal class INESFileParser { + companion object { + internal val INES_FILE_MAGIC = byteArrayOf(0x4e, 0x45, 0x53, 0x1a)/*0x4e45531a*/ + internal val PADDING = byteArrayOf(0, 0, 0, 0, 0, 0, 0) + + internal fun parseFileHeader(stream: InputStream): INESFileHeader { + val dataStream = DataInputStream(stream.buffered()) + return INESFileHeader( + (0..3).map { dataStream.readByte() }.toByteArray(), + dataStream.readByte(), + dataStream.readByte(), + dataStream.readByte(), + dataStream.readByte(), + dataStream.readByte(), + (0..6).map { dataStream.readByte() }.toByteArray()) + } + + internal fun parseCartridge(file: File): Cartridge { + val stream = file.inputStream() + stream.use { + val inesFileHeader = parseFileHeader(stream) + // mapper type + val control1 = inesFileHeader.control1.toInt() + val mapper1 = control1.shr(4) + val mapper2 = inesFileHeader.control2.toInt().shr(4) + val mapper = if (mapper1 != 0) mapper1 else mapper2 + // mirroring type + val mirror1 = control1.and(1) + val mirror2 = control1.shr(3).and(1) + val mirror = if (mirror1 != 0) mirror1 else mirror2.shl(1) + // battery-backed RAM + val battery = control1.shr(1).and(1).toByte() + // read prg-rom bank(s) + val pgr = ByteArray(inesFileHeader.numPRG.toInt() * 16384) + stream.read(pgr) + // read chr-rom bank(s) + val chr = ByteArray(inesFileHeader.numCHR.toInt() * 8192) + stream.read(chr) + return Cartridge(pgr, chr, mapper.toByte(), mirror.toByte(), battery) + } + } + } +} \ No newline at end of file diff --git a/app/src/test/java/android/emu6502/LabelsTest.java b/app/src/test/java/android/emu6502/LabelsTest.java deleted file mode 100644 index bff01a6..0000000 --- a/app/src/test/java/android/emu6502/LabelsTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package android.emu6502; - -import android.emu6502.instructions.Symbols; - -import org.junit.Test; - -import java.util.Collections; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.mock; - -public class LabelsTest { - private final Symbols symbols = new Symbols(); - private final Assembler assembler = new Assembler(new Memory(mock(Display.class)), symbols); - private final Labels labels = new Labels(assembler, symbols); - - @Test public void testAddLabel() { - labels.indexLines(Collections.singletonList("test:")); - assertThat(labels.get("test"), equalTo(assembler.getDefaultCodePC())); - } -} diff --git a/app/src/test/java/android/emu6502/AssemblerTest.java b/app/src/test/kotlin/android/emu6502/AssemblerTest.kt similarity index 61% rename from app/src/test/java/android/emu6502/AssemblerTest.java rename to app/src/test/kotlin/android/emu6502/AssemblerTest.kt index 96bfb59..3763814 100644 --- a/app/src/test/java/android/emu6502/AssemblerTest.java +++ b/app/src/test/kotlin/android/emu6502/AssemblerTest.kt @@ -1,46 +1,39 @@ -package android.emu6502; +package android.emu6502 -import com.google.common.collect.ImmutableList; +import android.emu6502.instructions.Symbols +import com.google.common.collect.ImmutableList +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.mockito.Mockito.mock -import android.emu6502.instructions.Symbols; +class AssemblerTest { + private val assembler = Assembler(Memory(mock(Display::class.java)), Symbols()) -import org.junit.Test; - -import java.util.List; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.text.IsEqualIgnoringCase.equalToIgnoringCase; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.mock; - -public class AssemblerTest { - private final Assembler assembler = new Assembler(new Memory(mock(Display.class)), new Symbols()); - - @Test public void testSimple() { - List lines = ImmutableList.of( + @Test fun testSimple() { + val lines = ImmutableList.of( "LDA #$01", "STA $0200", "LDA #$05", "STA $0201", "LDA #$08", - "STA $0202"); - assembler.assembleCode(lines); - assertThat(assembler.hexdump(), equalTo("0600: A9 01 8D 00 02 A9 05 8D 01 02 A9 08 8D 02 02")); + "STA $0202") + assembler.assembleCode(lines) + assertThat(assembler.hexdump()).isEqualTo("0600: A9 01 8D 00 02 A9 05 8D 01 02 A9 08 8D 02 02") } - @Test public void testWithComments() { - List lines = ImmutableList.of( - "LDA #$c0 ;Load the hex value $c0 into the A register", + @Test fun testWithComments() { + val lines = ImmutableList.of( + "LDA #\$c0 ;Load the hex value \$c0 into the A register", "TAX ;Transfer the value in the A register to X", "INX ;Increment the value in the X register", - "ADC #$c4 ;Add the hex value $c4 to the A register", - "BRK ;Break - we're done"); - assembler.assembleCode(lines); - assertThat(assembler.hexdump(), equalTo("0600: A9 C0 AA E8 69 C4 00")); + "ADC #\$c4 ;Add the hex value \$c4 to the A register", + "BRK ;Break - we're done") + assembler.assembleCode(lines) + assertThat(assembler.hexdump()).isEqualTo("0600: A9 C0 AA E8 69 C4 00") } - @Test public void testBranchAndLabel() { - List lines = ImmutableList.of( + @Test fun testBranchAndLabel() { + val lines = ImmutableList.of( "LDX #$08", "decrement:", "DEX", @@ -48,38 +41,38 @@ public class AssemblerTest { "CPX #$03", "BNE decrement", "STX $0201", - "BRK"); - assembler.assembleCode(lines); - assertThat(assembler.hexdump(), equalTo("0600: A2 08 CA 8E 00 02 E0 03 D0 F8 8E 01 02 00")); + "BRK") + assembler.assembleCode(lines) + assertThat(assembler.hexdump()).isEqualTo("0600: A2 08 CA 8E 00 02 E0 03 D0 F8 8E 01 02 00") } - @Test public void testRelative() { - List lines = ImmutableList.of( + @Test fun testRelative() { + val lines = ImmutableList.of( "LDA #$01", "CMP #$02", "BNE notequal", "STA $22", "notequal:", - "BRK"); + "BRK") - assembler.assembleCode(lines); - assertThat(assembler.hexdump(), equalTo("0600: A9 01 C9 02 D0 02 85 22 00")); + assembler.assembleCode(lines) + assertThat(assembler.hexdump()).isEqualTo("0600: A9 01 C9 02 D0 02 85 22 00") } - @Test public void testIndirect() { - List lines = ImmutableList.of( + @Test fun testIndirect() { + val lines = ImmutableList.of( "LDA #$01", - "STA $f0", - "LDA #$cc", - "STA $f1", - "JMP ($00f0) ;dereferences to $cc01"); + "STA \$f0", + "LDA #\$cc", + "STA \$f1", + "JMP ($00f0) ;dereferences to \$cc01") - assembler.assembleCode(lines); - assertThat(assembler.hexdump(), equalTo("0600: A9 01 85 F0 A9 CC 85 F1 6C F0 00")); + assembler.assembleCode(lines) + assertThat(assembler.hexdump()).isEqualTo("0600: A9 01 85 F0 A9 CC 85 F1 6C F0 00") } - @Test public void testIndirectX() { - List lines = ImmutableList.of( + @Test fun testIndirectX() { + val lines = ImmutableList.of( "LDX #$01", "LDA #$05", "STA $01", @@ -87,15 +80,15 @@ public class AssemblerTest { "STA $02", "LDY #$0a", "STY $0605", - "LDA ($00,X)"); + "LDA ($00,X)") - assembler.assembleCode(lines); - assertThat(assembler.hexdump(), - equalTo("0600: A2 01 A9 05 85 01 A9 06 85 02 A0 0A 8C 05 06 A1 \n0610: 00")); + assembler.assembleCode(lines) + assertThat(assembler.hexdump()) + .isEqualTo("0600: A2 01 A9 05 85 01 A9 06 85 02 A0 0A 8C 05 06 A1 \n0610: 00") } - @Test public void testIndirectY() { - List lines = ImmutableList.of( + @Test fun testIndirectY() { + val lines = ImmutableList.of( "LDY #$01", "LDA #$03", "STA $01", @@ -103,39 +96,39 @@ public class AssemblerTest { "STA $02", "LDX #$0a", "STX $0704", - "LDA ($01),Y"); + "LDA ($01),Y") - assembler.assembleCode(lines); - assertThat(assembler.hexdump(), - equalTo("0600: A0 01 A9 03 85 01 A9 07 85 02 A2 0A 8E 04 07 B1 \n0610: 01")); + assembler.assembleCode(lines) + assertThat(assembler.hexdump()) + .isEqualTo("0600: A0 01 A9 03 85 01 A9 07 85 02 A2 0A 8E 04 07 B1 \n0610: 01") } - @Test public void testJump() { - List lines = ImmutableList.of( + @Test fun testJump() { + val lines = ImmutableList.of( "LDA #$03", "JMP there", "BRK", "BRK", "BRK", "there:", - "STA $0200"); + "STA $0200") - assembler.assembleCode(lines); - assertThat(assembler.hexdump(), equalTo("0600: A9 03 4C 08 06 00 00 00 8D 00 02")); + assembler.assembleCode(lines) + assertThat(assembler.hexdump()).isEqualTo("0600: A9 03 4C 08 06 00 00 00 8D 00 02") } - @Test public void testSymbols() { - List lines = ImmutableList.of( - "define sysRandom $fe ; an adress", + @Test fun testSymbols() { + val lines = ImmutableList.of( + "define sysRandom \$fe ; an adress", "define a_dozen $0c ; a constant", - "LDA sysRandom ; equivalent to \"LDA $fe\"", - "LDX #a_dozen ; equivalent to \"LDX #$0c\""); - assembler.assembleCode(lines); - assertThat(assembler.hexdump(), equalTo("0600: A5 FE A2 0C")); + "LDA sysRandom ; equivalent to \"LDA \$fe\"", + "LDX #a_dozen ; equivalent to \"LDX #$0c\"") + assembler.assembleCode(lines) + assertThat(assembler.hexdump()).isEqualTo("0600: A5 FE A2 0C") } - @Test public void testSnake() { - List lines = ImmutableList.of( + @Test fun testSnake() { + val 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", @@ -154,8 +147,8 @@ public class AssemblerTest { "define ASCII_s $73", "define ASCII_d $64", "; System variables", - "define sysRandom $fe", - "define sysLastKey $ff", + "define sysRandom \$fe", + "define sysLastKey \$ff", " jsr init", " jsr loop", "init:", @@ -361,28 +354,28 @@ public class AssemblerTest { " dex", " bne spinloop", " rts", - "gameOver:", "\n"); - assembler.assembleCode(lines); - assertThat(assembler.hexdump(), equalToIgnoringCase( + "gameOver:", "\n") + assembler.assembleCode(lines) + assertThat(assembler.hexdump().toLowerCase()).isEqualTo( "0600: 20 06 06 20 38 06 20 0d 06 20 2a 06 60 a9 02 85 \n" + - "0610: 02 a9 04 85 03 a9 11 85 10 a9 10 85 12 a9 0f 85 \n" + - "0620: 14 a9 04 85 11 85 13 85 15 60 a5 fe 85 00 a5 fe \n" + - "0630: 29 03 18 69 02 85 01 60 20 4d 06 20 8d 06 20 c3 \n" + - "0640: 06 20 19 07 20 20 07 20 2d 07 4c 38 06 a5 ff c9 \n" + - "0650: 77 f0 0d c9 64 f0 14 c9 73 f0 1b c9 61 f0 22 60 \n" + - "0660: a9 04 24 02 d0 26 a9 01 85 02 60 a9 08 24 02 d0 \n" + - "0670: 1b a9 02 85 02 60 a9 01 24 02 d0 10 a9 04 85 02 \n" + - "0680: 60 a9 02 24 02 d0 05 a9 08 85 02 60 60 20 94 06 \n" + - "0690: 20 a8 06 60 a5 00 c5 10 d0 0d a5 01 c5 11 d0 07 \n" + - "06a0: e6 03 e6 03 20 2a 06 60 a2 02 b5 10 c5 10 d0 06 \n" + - "06b0: b5 11 c5 11 f0 09 e8 e8 e4 03 f0 06 4c aa 06 4c \n" + - "06c0: 35 07 60 a6 03 ca 8a b5 10 95 12 ca 10 f9 a5 02 \n" + - "06d0: 4a b0 09 4a b0 19 4a b0 1f 4a b0 2f a5 10 38 e9 \n" + - "06e0: 20 85 10 90 01 60 c6 11 a9 01 c5 11 f0 28 60 e6 \n" + - "06f0: 10 a9 1f 24 10 f0 1f 60 a5 10 18 69 20 85 10 b0 \n" + - "0700: 01 60 e6 11 a9 06 c5 11 f0 0c 60 c6 10 a5 10 29 \n" + - "0710: 1f c9 1f f0 01 60 4c 35 07 a0 00 a5 fe 91 00 60 \n" + - "0720: a2 00 a9 01 81 10 a6 03 a9 00 81 10 60 a2 00 ea \n" + - "0730: ea ca d0 fb 60")); + "0610: 02 a9 04 85 03 a9 11 85 10 a9 10 85 12 a9 0f 85 \n" + + "0620: 14 a9 04 85 11 85 13 85 15 60 a5 fe 85 00 a5 fe \n" + + "0630: 29 03 18 69 02 85 01 60 20 4d 06 20 8d 06 20 c3 \n" + + "0640: 06 20 19 07 20 20 07 20 2d 07 4c 38 06 a5 ff c9 \n" + + "0650: 77 f0 0d c9 64 f0 14 c9 73 f0 1b c9 61 f0 22 60 \n" + + "0660: a9 04 24 02 d0 26 a9 01 85 02 60 a9 08 24 02 d0 \n" + + "0670: 1b a9 02 85 02 60 a9 01 24 02 d0 10 a9 04 85 02 \n" + + "0680: 60 a9 02 24 02 d0 05 a9 08 85 02 60 60 20 94 06 \n" + + "0690: 20 a8 06 60 a5 00 c5 10 d0 0d a5 01 c5 11 d0 07 \n" + + "06a0: e6 03 e6 03 20 2a 06 60 a2 02 b5 10 c5 10 d0 06 \n" + + "06b0: b5 11 c5 11 f0 09 e8 e8 e4 03 f0 06 4c aa 06 4c \n" + + "06c0: 35 07 60 a6 03 ca 8a b5 10 95 12 ca 10 f9 a5 02 \n" + + "06d0: 4a b0 09 4a b0 19 4a b0 1f 4a b0 2f a5 10 38 e9 \n" + + "06e0: 20 85 10 90 01 60 c6 11 a9 01 c5 11 f0 28 60 e6 \n" + + "06f0: 10 a9 1f 24 10 f0 1f 60 a5 10 18 69 20 85 10 b0 \n" + + "0700: 01 60 e6 11 a9 06 c5 11 f0 0c 60 c6 10 a5 10 29 \n" + + "0710: 1f c9 1f f0 01 60 4c 35 07 a0 00 a5 fe 91 00 60 \n" + + "0720: a2 00 a9 01 81 10 a6 03 a9 00 81 10 60 a2 00 ea \n" + + "0730: ea ca d0 fb 60") } } diff --git a/app/src/test/java/android/emu6502/CPUTest.java b/app/src/test/kotlin/android/emu6502/CPUTest.kt similarity index 65% rename from app/src/test/java/android/emu6502/CPUTest.java rename to app/src/test/kotlin/android/emu6502/CPUTest.kt index 007efb5..0ce4dfa 100644 --- a/app/src/test/java/android/emu6502/CPUTest.java +++ b/app/src/test/kotlin/android/emu6502/CPUTest.kt @@ -1,59 +1,54 @@ -package android.emu6502; +package android.emu6502 -import com.google.common.collect.ImmutableList; +import android.emu6502.instructions.Symbols +import com.google.common.collect.ImmutableList +import org.hamcrest.CoreMatchers.equalTo +import org.junit.Assert.assertThat +import org.junit.Test +import org.mockito.Mockito.mock -import android.emu6502.instructions.Symbols; +class CPUTest { + private val memory = Memory(mock(Display::class.java)) + private val assembler = Assembler(memory, Symbols()) + private val cpu = CPU(memory) -import org.junit.Test; - -import java.util.List; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.mock; - -public class CPUTest { - private final Memory memory = new Memory(mock(Display.class)); - private final Assembler assembler = new Assembler(memory, new Symbols()); - private final CPU cpu = new CPU(memory); - - @Test public void testSimple() { - List lines = ImmutableList.of( + @Test fun testSimple() { + val lines = ImmutableList.of( "LDA #$01", "STA $0200", "LDA #$05", "STA $0201", "LDA #$08", - "STA $0202"); - assembler.assembleCode(lines); - cpu.testRun(); - assertThat(cpu.getA(), equalTo(0x08)); - assertThat(cpu.getX(), equalTo(0x00)); - assertThat(cpu.getY(), equalTo(0x00)); - assertThat(cpu.getSP(), equalTo(0xFF)); - assertThat(cpu.getPC(), equalTo(0x0610)); - assertThat(cpu.flags(), equalTo("00110000")); + "STA $0202") + assembler.assembleCode(lines) + cpu.testRun() + assertThat(cpu.A, equalTo(0x08)) + assertThat(cpu.X, equalTo(0x00)) + assertThat(cpu.Y, equalTo(0x00)) + assertThat(cpu.SP, equalTo(0xFF)) + assertThat(cpu.PC, equalTo(0x0610)) + assertThat(cpu.flags(), equalTo("00110000")) } - @Test public void testWithComments() { - List lines = ImmutableList.of( - "LDA #$c0 ;Load the hex value $c0 into the A register", + @Test fun testWithComments() { + val lines = ImmutableList.of( + "LDA #\$c0 ;Load the hex value \$c0 into the A register", "TAX ;Transfer the value in the A register to X", "INX ;Increment the value in the X register", - "ADC #$c4 ;Add the hex value $c4 to the A register", - "BRK ;Break - we're done"); - assembler.assembleCode(lines); - cpu.testRun(); - assertThat(cpu.getA(), equalTo(0x84)); - assertThat(cpu.getX(), equalTo(0xC1)); - assertThat(cpu.getY(), equalTo(0x00)); - assertThat(cpu.getSP(), equalTo(0xFF)); - assertThat(cpu.getPC(), equalTo(0x0607)); - assertThat(cpu.flags(), equalTo("10110001")); + "ADC #\$c4 ;Add the hex value \$c4 to the A register", + "BRK ;Break - we're done") + assembler.assembleCode(lines) + cpu.testRun() + assertThat(cpu.A, equalTo(0x84)) + assertThat(cpu.X, equalTo(0xC1)) + assertThat(cpu.Y, equalTo(0x00)) + assertThat(cpu.SP, equalTo(0xFF)) + assertThat(cpu.PC, equalTo(0x0607)) + assertThat(cpu.flags(), equalTo("10110001")) } - @Test public void testBranchAndLabel() { - List lines = ImmutableList.of( + @Test fun testBranchAndLabel() { + val lines = ImmutableList.of( "LDX #$08", "decrement:", @@ -62,19 +57,19 @@ public class CPUTest { "CPX #$03", "BNE decrement", "STX $0201", - "BRK"); - assembler.assembleCode(lines); - cpu.testRun(); - 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")); + "BRK") + assembler.assembleCode(lines) + cpu.testRun() + assertThat(cpu.A, equalTo(0x00)) + assertThat(cpu.X, equalTo(0x03)) + assertThat(cpu.Y, equalTo(0x00)) + assertThat(cpu.SP, equalTo(0xFF)) + assertThat(cpu.PC, equalTo(0x060e)) + assertThat(cpu.flags(), equalTo("00110011")) } - @Test public void testJump() { - List lines = ImmutableList.of( + @Test fun testJump() { + val lines = ImmutableList.of( "LDA #$03", "JMP there", "BRK", @@ -82,19 +77,19 @@ public class CPUTest { "BRK", "there:", - "STA $0200"); - assembler.assembleCode(lines); - cpu.testRun(); - assertThat(cpu.getA(), equalTo(0x03)); - assertThat(cpu.getX(), equalTo(0x00)); - assertThat(cpu.getY(), equalTo(0x00)); - assertThat(cpu.getSP(), equalTo(0xFF)); - assertThat(cpu.getPC(), equalTo(0x060c)); - assertThat(cpu.flags(), equalTo("00110000")); + "STA $0200") + assembler.assembleCode(lines) + cpu.testRun() + assertThat(cpu.A, equalTo(0x03)) + assertThat(cpu.X, equalTo(0x00)) + assertThat(cpu.Y, equalTo(0x00)) + assertThat(cpu.SP, equalTo(0xFF)) + assertThat(cpu.PC, equalTo(0x060c)) + assertThat(cpu.flags(), equalTo("00110000")) } - @Test public void testJumpToSubroutines() { - List lines = ImmutableList.of( + @Test fun testJumpToSubroutines() { + val lines = ImmutableList.of( "JSR init", "JSR loop", "JSR end", @@ -110,33 +105,33 @@ public class CPUTest { "RTS", "end:", - "BRK"); - assembler.assembleCode(lines); - cpu.testRun(); - assertThat(cpu.getA(), equalTo(0x00)); - assertThat(cpu.getX(), equalTo(0x05)); - assertThat(cpu.getY(), equalTo(0x00)); - assertThat(cpu.getSP(), equalTo(0xFD)); - assertThat(cpu.getPC(), equalTo(0x0613)); - assertThat(cpu.flags(), equalTo("00110011")); + "BRK") + assembler.assembleCode(lines) + cpu.testRun() + assertThat(cpu.A, equalTo(0x00)) + assertThat(cpu.X, equalTo(0x05)) + assertThat(cpu.Y, equalTo(0x00)) + assertThat(cpu.SP, equalTo(0xFD)) + assertThat(cpu.PC, equalTo(0x0613)) + assertThat(cpu.flags(), equalTo("00110011")) } - @Test public void testSymbols() { - List lines = ImmutableList.of( + @Test fun testSymbols() { + val lines = ImmutableList.of( "define a_dozen $0c ; a constant", - "LDX #a_dozen ; equivalent to \"LDX #$0c\""); - assembler.assembleCode(lines); - cpu.testRun(); - assertThat(cpu.getA(), equalTo(0x00)); - assertThat(cpu.getX(), equalTo(0x0C)); - assertThat(cpu.getY(), equalTo(0x00)); - assertThat(cpu.getSP(), equalTo(0xFF)); - assertThat(cpu.getPC(), equalTo(0x0603)); - assertThat(cpu.flags(), equalTo("00110000")); + "LDX #a_dozen ; equivalent to \"LDX #$0c\"") + assembler.assembleCode(lines) + cpu.testRun() + assertThat(cpu.A, equalTo(0x00)) + assertThat(cpu.X, equalTo(0x0C)) + assertThat(cpu.Y, equalTo(0x00)) + assertThat(cpu.SP, equalTo(0xFF)) + assertThat(cpu.PC, equalTo(0x0603)) + assertThat(cpu.flags(), equalTo("00110000")) } - @Test public void testSnake() { - List lines = ImmutableList.of( + @Test fun testSnake() { + val 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", @@ -155,8 +150,8 @@ public class CPUTest { "define ASCII_s $73", "define ASCII_d $64", "; System variables", - "define sysRandom $fe", - "define sysLastKey $ff", + "define sysRandom \$fe", + "define sysLastKey \$ff", " jsr init", " jsr loop", "init:", @@ -362,14 +357,14 @@ public class CPUTest { " dex", " bne spinloop", " rts", - "gameOver:", "\n"); - assembler.assembleCode(lines); - cpu.testRun(); - assertThat(cpu.getA(), equalTo(0x1f)); - assertThat(cpu.getX(), equalTo(0xff)); - assertThat(cpu.getY(), equalTo(0x00)); - assertThat(cpu.getSP(), equalTo(0xfb)); - assertThat(cpu.getPC(), equalTo(0x0736)); - assertThat(cpu.flags(), equalTo("00110011")); + "gameOver:", "\n") + assembler.assembleCode(lines) + cpu.testRun() + assertThat(cpu.A, equalTo(0x1f)) + assertThat(cpu.X, equalTo(0xff)) + assertThat(cpu.Y, equalTo(0x00)) + assertThat(cpu.SP, equalTo(0xfb)) + assertThat(cpu.PC, equalTo(0x0736)) + assertThat(cpu.flags(), equalTo("00110011")) } } diff --git a/app/src/test/kotlin/android/emu6502/LabelsTest.kt b/app/src/test/kotlin/android/emu6502/LabelsTest.kt new file mode 100644 index 0000000..f923af4 --- /dev/null +++ b/app/src/test/kotlin/android/emu6502/LabelsTest.kt @@ -0,0 +1,18 @@ +package android.emu6502 + +import android.emu6502.instructions.Symbols +import org.hamcrest.CoreMatchers.equalTo +import org.junit.Assert.assertThat +import org.junit.Test +import org.mockito.Mockito.mock + +class LabelsTest { + private val symbols = Symbols() + private val assembler = Assembler(Memory(mock(Display::class.java)), symbols) + private val labels = Labels(assembler, symbols) + + @Test fun testAddLabel() { + labels.indexLines(listOf("test:")) + assertThat(labels["test"], equalTo(assembler.defaultCodePC)) + } +} diff --git a/app/src/test/kotlin/android/emu6502/nes/INESFileParserTest.kt b/app/src/test/kotlin/android/emu6502/nes/INESFileParserTest.kt new file mode 100644 index 0000000..946155a --- /dev/null +++ b/app/src/test/kotlin/android/emu6502/nes/INESFileParserTest.kt @@ -0,0 +1,31 @@ +package android.emu6502.nes + +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Test +import java.io.File + +class INESFileParserTest { + val tempFile: File = File.createTempFile("foo", "bar") + + @Before fun setUp() { + tempFile.writeBytes((0..40).map(Int::toByte).toByteArray()) + } + + @After fun tearDown() { + tempFile.delete() + } + + @Test fun invalidHeader() { + assertThat(INESFileParser.parseFileHeader(tempFile.inputStream()).isValid()).isFalse() + } + + @Test fun validHeader() { + val testRom = javaClass.classLoader.getResource("roms/testrom.nes").toURI() + val header = INESFileParser.parseFileHeader(File(testRom).inputStream()) + assertThat(header).isEqualTo(INESFileHeader( + INESFileParser.INES_FILE_MAGIC, 0x10, 0x10, 0x40, 0x0, 0x0, INESFileParser.PADDING)) + assertThat(header.isValid()).isTrue() + } +} \ No newline at end of file diff --git a/app/src/test/resources/roms/testrom.nes b/app/src/test/resources/roms/testrom.nes new file mode 100755 index 0000000..4402e75 Binary files /dev/null and b/app/src/test/resources/roms/testrom.nes differ