diff --git a/sim65/sim65.iml b/sim65/sim65.iml index 9c96a55d9..f439d557d 100644 --- a/sim65/sim65.iml +++ b/sim65/sim65.iml @@ -15,10 +15,12 @@ + + \ No newline at end of file diff --git a/sim65/src/Sim65Main.kt b/sim65/src/Sim65Main.kt index 7c2db9a0c..3ae2efa92 100644 --- a/sim65/src/Sim65Main.kt +++ b/sim65/src/Sim65Main.kt @@ -65,8 +65,8 @@ private fun startSimulator(args: Array) { bus.reset() - ram.load("sim65/ram.bin", 0x8000) - ram.load("sim65/bcdtest.bin", 0x1000) + ram.load("sim65/test/testfiles/ram.bin", 0x8000) + ram.load("sim65/test/testfiles/bcdtest.bin", 0x1000) //ram.dump(0x8000, 0x802f) //cpu.disassemble(ram, 0x8000, 0x802f) diff --git a/sim65/src/components/Cpu6502.kt b/sim65/src/components/Cpu6502.kt index ee5bbce38..121fd1beb 100644 --- a/sim65/src/components/Cpu6502.kt +++ b/sim65/src/components/Cpu6502.kt @@ -4,7 +4,7 @@ package sim65.components class InstructionError(msg: String) : RuntimeException(msg) interface ICpu { - fun disassemble(memory: Array, baseAddress: Address, from: Address, to: Address) + fun disassemble(memory: Array, baseAddress: Address, from: Address, to: Address): List fun disassemble(component: MemMappedComponent, from: Address, to: Address) = disassemble(component.cloneMem(), component.startAddress, from, to) @@ -30,10 +30,13 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu const val RESET_vector = 0xfffc const val IRQ_vector = 0xfffe - fun hexW(number: Address): String { + fun hexW(number: Address, allowSingleByte: Boolean = false): String { val msb = number ushr 8 val lsb = number and 255 - return hexB(msb) + hexB(lsb) + return if(msb==0 && allowSingleByte) + hexB(lsb) + else + hexB(msb) + hexB(lsb) } private const val hexdigits = "0123456789abcdef" @@ -130,38 +133,43 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu AddrMode.IzY to ::amIzy ) - override fun disassemble(memory: Array, baseAddress: Address, from: Address, to: Address) { + override fun disassemble(memory: Array, baseAddress: Address, from: Address, to: Address): List { var address = from - baseAddress val spacing1 = " " val spacing2 = " " val spacing3 = " " + val result = mutableListOf() + while (address <= (to - baseAddress)) { val byte = memory[address] - print("\$${hexW(address)} ${hexB(byte)} ") + var line = "\$${hexW(address)} ${hexB(byte)} " address++ val opcode = opcodes[byte.toInt()] if (!opcode.official && !illegalInstrsAllowed) { - println("$spacing1 ???") + line += "$spacing1 ???" } else { when (opcode.mode) { - AddrMode.Imp, AddrMode.Acc -> { - println("$spacing1 ${opcode.mnemonic}") + AddrMode.Acc -> { + line += "$spacing1 ${opcode.mnemonic} a" + } + AddrMode.Imp -> { + line += "$spacing1 ${opcode.mnemonic}" } AddrMode.Imm -> { val value = memory[address++] - println("${hexB(value)} $spacing2 ${opcode.mnemonic} #\$${hexB(value)}") + line += "${hexB(value)} $spacing2 ${opcode.mnemonic} #\$${hexB(value)}" } AddrMode.Zp -> { val zpAddr = memory[address++] - println("${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)}") + line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)}" } AddrMode.ZpX -> { val zpAddr = memory[address++] - println("${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},x") + line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},x" } AddrMode.ZpY -> { val zpAddr = memory[address++] - println("${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},y") + line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},y" } AddrMode.Rel -> { val rel = memory[address++] @@ -170,43 +178,46 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu address + rel else address - (256 - rel) - println("${hexB(rel)} $spacing2 ${opcode.mnemonic} \$${hexW(target)}") + line += "${hexB(rel)} $spacing2 ${opcode.mnemonic} \$${hexW(target, true)}" } AddrMode.Abs -> { val lo = memory[address++] val hi = memory[address++] val absAddr = lo.toInt() or (hi.toInt() shl 8) - println("${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)}") + line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)}" } AddrMode.AbsX -> { val lo = memory[address++] val hi = memory[address++] val absAddr = lo.toInt() or (hi.toInt() shl 8) - println("${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)},x") + line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)},x" } AddrMode.AbsY -> { val lo = memory[address++] val hi = memory[address++] val absAddr = lo.toInt() or (hi.toInt() shl 8) - println("${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)},y") + line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)},y" } AddrMode.Ind -> { val lo = memory[address++] val hi = memory[address++] val indirectAddr = lo.toInt() or (hi.toInt() shl 8) - println("${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} (\$${hexW(indirectAddr)})") + line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} (\$${hexW(indirectAddr)})" } AddrMode.IzX -> { val zpAddr = memory[address++] - println("${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)},x)") + line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)},x)" } AddrMode.IzY -> { val zpAddr = memory[address++] - println("${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)}),y") + line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)}),y" } } } + result.add(line) } + + return result } override fun reset() { diff --git a/sim65/test/DisassemTest.kt b/sim65/test/DisassemTest.kt new file mode 100644 index 000000000..21ae406f1 --- /dev/null +++ b/sim65/test/DisassemTest.kt @@ -0,0 +1,29 @@ +import org.junit.jupiter.api.Test +import sim65.components.* +import java.io.File +import kotlin.test.* + + +class TestDisassembler { + + @Test + fun testDisassembleAllOpcodes() { + val cpu = Cpu6502(true) + val memory = Ram(0, 0xffff) + memory.load("test/testfiles/disassem_instr_test.prg", 0x1000-2) + val result = cpu.disassemble(memory, 0x1000, 0x1221) + assertEquals(256, result.size) + assertEquals("\$1000 69 01 adc #\$01", result[0]) + + val reference = File("test/testfiles/disassem_ref_output.txt").readLines() + assertEquals(256, reference.size) + for(line in result.zip(reference)) { + if(line.first!=line.second) { + fail("disassembled instruction mismatch: '${line.first}', expected '${line.second}'") + } + } + } + +} + + diff --git a/sim65/test/testfiles/disassem_ref_output.txt b/sim65/test/testfiles/disassem_ref_output.txt new file mode 100644 index 000000000..826e46b2b --- /dev/null +++ b/sim65/test/testfiles/disassem_ref_output.txt @@ -0,0 +1,256 @@ +$1000 69 01 adc #$01 +$1002 65 02 adc $02 +$1004 75 03 adc $03,x +$1006 6d 05 04 adc $0405 +$1009 7d 07 06 adc $0607,x +$100c 79 09 08 adc $0809,y +$100f 61 0a adc ($0a,x) +$1011 71 0b adc ($0b),y +$1013 29 0c and #$0c +$1015 25 0d and $0d +$1017 35 0e and $0e,x +$1019 2d 10 0f and $0f10 +$101c 3d 12 11 and $1112,x +$101f 39 14 13 and $1314,y +$1022 21 15 and ($15,x) +$1024 31 16 and ($16),y +$1026 0a asl a +$1027 06 17 asl $17 +$1029 16 18 asl $18,x +$102b 0e 1a 19 asl $191a +$102e 1e 1c 1b asl $1b1c,x +$1031 90 1d bcc $1050 +$1033 b0 1e bcs $1053 +$1035 f0 1f beq $1056 +$1037 24 20 bit $20 +$1039 2c 22 21 bit $2122 +$103c 30 23 bmi $1061 +$103e d0 24 bne $1064 +$1040 10 25 bpl $1067 +$1042 00 brk +$1043 50 26 bvc $106b +$1045 70 27 bvs $106e +$1047 18 clc +$1048 d8 cld +$1049 58 cli +$104a b8 clv +$104b c9 28 cmp #$28 +$104d c5 29 cmp $29 +$104f d5 2a cmp $2a,x +$1051 cd 2c 2b cmp $2b2c +$1054 dd 2e 2d cmp $2d2e,x +$1057 d9 30 2f cmp $2f30,y +$105a c1 31 cmp ($31,x) +$105c d1 32 cmp ($32),y +$105e e0 33 cpx #$33 +$1060 e4 34 cpx $34 +$1062 ec 36 35 cpx $3536 +$1065 c0 37 cpy #$37 +$1067 c4 38 cpy $38 +$1069 cc 3a 39 cpy $393a +$106c c6 3b dec $3b +$106e d6 3c dec $3c,x +$1070 ce 3e 3d dec $3d3e +$1073 de 40 3f dec $3f40,x +$1076 ca dex +$1077 88 dey +$1078 49 41 eor #$41 +$107a 45 42 eor $42 +$107c 55 43 eor $43,x +$107e 4d 45 44 eor $4445 +$1081 5d 47 46 eor $4647,x +$1084 59 49 48 eor $4849,y +$1087 41 4a eor ($4a,x) +$1089 51 4b eor ($4b),y +$108b e6 4c inc $4c +$108d f6 4d inc $4d,x +$108f ee 4f 4e inc $4e4f +$1092 fe 51 50 inc $5051,x +$1095 e8 inx +$1096 c8 iny +$1097 4c 53 52 jmp $5253 +$109a 6c 55 54 jmp ($5455) +$109d 20 57 56 jsr $5657 +$10a0 a9 58 lda #$58 +$10a2 a5 59 lda $59 +$10a4 b5 5a lda $5a,x +$10a6 ad 5c 5b lda $5b5c +$10a9 bd 5e 5d lda $5d5e,x +$10ac b9 60 5f lda $5f60,y +$10af a1 61 lda ($61,x) +$10b1 b1 62 lda ($62),y +$10b3 a2 63 ldx #$63 +$10b5 a6 64 ldx $64 +$10b7 b6 65 ldx $65,y +$10b9 ae 67 66 ldx $6667 +$10bc be 69 68 ldx $6869,y +$10bf a0 6a ldy #$6a +$10c1 a4 6b ldy $6b +$10c3 b4 6c ldy $6c,x +$10c5 ac 6e 6d ldy $6d6e +$10c8 bc 70 6f ldy $6f70,x +$10cb 4a lsr a +$10cc 46 71 lsr $71 +$10ce 56 72 lsr $72,x +$10d0 4e 74 73 lsr $7374 +$10d3 5e 76 75 lsr $7576,x +$10d6 ea nop +$10d7 09 77 ora #$77 +$10d9 05 78 ora $78 +$10db 15 79 ora $79,x +$10dd 0d 7b 7a ora $7a7b +$10e0 1d 7d 7c ora $7c7d,x +$10e3 19 7f 7e ora $7e7f,y +$10e6 01 80 ora ($80,x) +$10e8 11 81 ora ($81),y +$10ea 48 pha +$10eb 08 php +$10ec 68 pla +$10ed 28 plp +$10ee 2a rol a +$10ef 26 82 rol $82 +$10f1 36 83 rol $83,x +$10f3 2e 85 84 rol $8485 +$10f6 3e 87 86 rol $8687,x +$10f9 6a ror a +$10fa 66 88 ror $88 +$10fc 76 89 ror $89,x +$10fe 6e 8b 8a ror $8a8b +$1101 7e 8d 8c ror $8c8d,x +$1104 40 rti +$1105 60 rts +$1106 e9 8e sbc #$8e +$1108 e5 8f sbc $8f +$110a f5 90 sbc $90,x +$110c ed 92 91 sbc $9192 +$110f fd 94 93 sbc $9394,x +$1112 f9 96 95 sbc $9596,y +$1115 e1 97 sbc ($97,x) +$1117 f1 98 sbc ($98),y +$1119 38 sec +$111a f8 sed +$111b 78 sei +$111c 85 99 sta $99 +$111e 95 9a sta $9a,x +$1120 8d 9c 9b sta $9b9c +$1123 9d 9e 9d sta $9d9e,x +$1126 99 a0 9f sta $9fa0,y +$1129 81 a1 sta ($a1,x) +$112b 91 a2 sta ($a2),y +$112d 86 a3 stx $a3 +$112f 96 a4 stx $a4,y +$1131 8e a6 a5 stx $a5a6 +$1134 84 a7 sty $a7 +$1136 94 a8 sty $a8,x +$1138 8c aa a9 sty $a9aa +$113b aa tax +$113c a8 tay +$113d ba tsx +$113e 8a txa +$113f 9a txs +$1140 98 tya +$1141 02 ??? +$1142 12 ??? +$1143 22 ??? +$1144 32 ??? +$1145 42 ??? +$1146 52 ??? +$1147 62 ??? +$1148 72 ??? +$1149 92 ??? +$114a b2 ??? +$114b d2 ??? +$114c f2 ??? +$114d 7a nop +$114e 5a nop +$114f 1a nop +$1150 3a nop +$1151 da nop +$1152 fa nop +$1153 80 00 nop #$00 +$1155 82 00 nop #$00 +$1157 89 00 nop #$00 +$1159 c2 00 nop #$00 +$115b e2 00 nop #$00 +$115d 04 00 nop $00 +$115f 64 00 nop $00 +$1161 44 00 nop $00 +$1163 0c 00 00 nop $0000 +$1166 14 00 nop $00,x +$1168 34 00 nop $00,x +$116a 54 00 nop $00,x +$116c 74 00 nop $00,x +$116e d4 00 nop $00,x +$1170 f4 00 nop $00,x +$1172 1c 00 00 nop $0000,x +$1175 3c 00 00 nop $0000,x +$1178 5c 00 00 nop $0000,x +$117b 7c 00 00 nop $0000,x +$117e dc 00 00 nop $0000,x +$1181 fc 00 00 nop $0000,x +$1184 ab 00 lax #$00 +$1186 a7 00 lax $00 +$1188 b7 00 lax $00,y +$118a af 00 00 lax $0000 +$118d bf 00 00 lax $0000,y +$1190 a3 00 lax ($00,x) +$1192 b3 00 lax ($00),y +$1194 87 00 sax $00 +$1196 97 00 sax $00,y +$1198 8f 00 00 sax $0000 +$119b 83 00 sax ($00,x) +$119d eb 00 sbc #$00 +$119f c7 00 dcp $00 +$11a1 d7 00 dcp $00,x +$11a3 cf 00 00 dcp $0000 +$11a6 df 00 00 dcp $0000,x +$11a9 db 00 00 dcp $0000,y +$11ac c3 00 dcp ($00,x) +$11ae d3 00 dcp ($00),y +$11b0 e7 00 isc $00 +$11b2 f7 00 isc $00,x +$11b4 ef 00 00 isc $0000 +$11b7 ff 00 00 isc $0000,x +$11ba fb 00 00 isc $0000,y +$11bd e3 00 isc ($00,x) +$11bf f3 00 isc ($00),y +$11c1 27 00 rla $00 +$11c3 37 00 rla $00,x +$11c5 2f 00 00 rla $0000 +$11c8 3f 00 00 rla $0000,x +$11cb 3b 00 00 rla $0000,y +$11ce 23 00 rla ($00,x) +$11d0 33 00 rla ($00),y +$11d2 67 00 rra $00 +$11d4 77 00 rra $00,x +$11d6 6f 00 00 rra $0000 +$11d9 7f 00 00 rra $0000,x +$11dc 7b 00 00 rra $0000,y +$11df 63 00 rra ($00,x) +$11e1 73 00 rra ($00),y +$11e3 07 00 slo $00 +$11e5 17 00 slo $00,x +$11e7 0f 00 00 slo $0000 +$11ea 1f 00 00 slo $0000,x +$11ed 1b 00 00 slo $0000,y +$11f0 03 00 slo ($00,x) +$11f2 13 00 slo ($00),y +$11f4 47 00 sre $00 +$11f6 57 00 sre $00,x +$11f8 4f 00 00 sre $0000 +$11fb 5f 00 00 sre $0000,x +$11fe 5b 00 00 sre $0000,y +$1201 43 00 sre ($00,x) +$1203 53 00 sre ($00),y +$1205 0b 00 anc #$00 +$1207 2b 00 anc #$00 +$1209 4b 00 alr #$00 +$120b 6b 00 arr #$00 +$120d 8b 00 xaa #$00 +$120f 93 00 ahx ($00),y +$1211 9f 00 00 ahx $0000,y +$1214 9b 00 00 tas $0000,y +$1217 9e 00 00 shx $0000,y +$121a 9c 00 00 shy $0000,x +$121d bb 00 00 las $0000,y +$1220 cb 00 axs #$00