From be8716c4a488851bf180c0f784cf34c578529f28 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 19 Feb 2020 00:48:05 +0100 Subject: [PATCH] use assembler instead of raw bytes --- src/main/kotlin/razorvine/ksim65/Assembler.kt | 115 +++++++++--------- src/test/kotlin/FunctionalTestsBase.kt | 22 +++- .../kotlin/Test6502TestSuiteC64Specific.kt | 28 +++-- 3 files changed, 95 insertions(+), 70 deletions(-) diff --git a/src/main/kotlin/razorvine/ksim65/Assembler.kt b/src/main/kotlin/razorvine/ksim65/Assembler.kt index cd8d45f..584eada 100644 --- a/src/main/kotlin/razorvine/ksim65/Assembler.kt +++ b/src/main/kotlin/razorvine/ksim65/Assembler.kt @@ -33,7 +33,7 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres } - private var address = initialStartAddress ?: 0 + private var startAddress = initialStartAddress ?: 0 private var assembledSize = 0 private val instructions by lazy { @@ -49,11 +49,12 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres fun assemble(lines: Iterable): Result { for(line in lines) { val result = assemble(line) + println("line: $line -> ${result.success} ${result.error}") // TODO if(!result.success) return result assembledSize += result.numBytes } - return Result(true, "", address, assembledSize) + return Result(true, "", startAddress, assembledSize) } fun assemble(line: String): Result { @@ -68,20 +69,20 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres var args = line.trim().split(' ') if(args.isEmpty() || args.size == 1 && args[0] == "") - return Result(true, "", address, 0) + return Result(true, "", startAddress, 0) if(args[0].startsWith("*=") && args.size==1) { - address = parseNumber(args[0].substring(2)) - return Result(true, "", address, 0) + startAddress = parseNumber(args[0].substring(2)) + return Result(true, "", startAddress, 0) } else if(args[0] == "*" && args[1] == "=") { - address = parseNumber(args[2]) - return Result(true, "", address, 0) + startAddress = parseNumber(args[2]) + return Result(true, "", startAddress, 0) } else { // line with an instruction, may be preceded by a 4 or 5 char address if(args[0].length == 4 || args[0].length==5) { if(args.size!=2 && args.size !=3) - return Result(false, "syntax error", address, 0) - address = parseNumber(args[0]) + return Result(false, "syntax error", startAddress, 0) + startAddress = parseNumber(args[0]) args = args.drop(1) } } @@ -94,8 +95,8 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres instructionSize = 1 var instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Imp)] if (instruction == null) instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Acc)] - if (instruction == null) return Result(false, "invalid instruction", this.address, 0) - memory[address] = instruction.toShort() + if (instruction == null) return Result(false, "invalid instruction", this.startAddress, 0) + memory[startAddress+assembledSize] = instruction.toShort() } 2 -> { val arg = args[1] @@ -103,9 +104,9 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres arg.startsWith('#') -> { // immediate val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Imm)] ?: return Result(false, "invalid instruction", - this.address, 0) - memory[address] = instruction.toShort() - memory[address+1] = parseNumber(arg.substring(1), decimalFirst = true).toShort() + this.startAddress, 0) + memory[startAddress+assembledSize] = instruction.toShort() + memory[startAddress+assembledSize+1] = parseNumber(arg.substring(1), decimalFirst = true).toShort() instructionSize = 2 } arg.startsWith("(") && arg.endsWith(",x)") -> { @@ -113,12 +114,12 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres val indAddress = try { parseNumber(arg.substring(1, arg.length-3)) } catch (x: NumberFormatException) { - return Result(false, "invalid instruction", this.address, 0) + return Result(false, "invalid instruction", this.startAddress, 0) } val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.IzX)] ?: return Result(false, "invalid instruction", - this.address, 0) - memory[address] = instruction.toShort() - memory[address+1] = indAddress.toShort() + this.startAddress, 0) + memory[startAddress+assembledSize] = instruction.toShort() + memory[startAddress+assembledSize+1] = indAddress.toShort() instructionSize = 2 } arg.startsWith("(") && arg.endsWith("),y") -> { @@ -126,12 +127,12 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres val indAddress = try { parseNumber(arg.substring(1, arg.length-3)) } catch (x: NumberFormatException) { - return Result(false, "invalid instruction", this.address, 0) + return Result(false, "invalid instruction", this.startAddress, 0) } val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.IzY)] ?: return Result(false, "invalid instruction", - this.address, 0) - memory[address] = instruction.toShort() - memory[address+1] = indAddress.toShort() + this.startAddress, 0) + memory[startAddress+assembledSize] = instruction.toShort() + memory[startAddress+assembledSize+1] = indAddress.toShort() instructionSize = 2 } arg.endsWith(",x") -> { @@ -139,20 +140,20 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres val indAddress = try { parseNumber(arg.substring(1, arg.length-2)) } catch (x: NumberFormatException) { - return Result(false, "invalid instruction", this.address, 0) + return Result(false, "invalid instruction", this.startAddress, 0) } instructionSize = if (indAddress <= 255) { val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.ZpX)] ?: return Result(false, "invalid instruction", - this.address, 0) - memory[address] = instruction.toShort() - memory[address+1] = indAddress.toShort() + this.startAddress, 0) + memory[startAddress+assembledSize] = instruction.toShort() + memory[startAddress+assembledSize+1] = indAddress.toShort() 2 } else { val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.AbsX)] ?: return Result(false, "invalid instruction", - this.address, 0) - memory[address] = instruction.toShort() - memory[address+1] = (indAddress and 255).toShort() - memory[address+2] = (indAddress ushr 8).toShort() + this.startAddress, 0) + memory[startAddress+assembledSize] = instruction.toShort() + memory[startAddress+assembledSize+1] = (indAddress and 255).toShort() + memory[startAddress+assembledSize+2] = (indAddress ushr 8).toShort() 3 } } @@ -161,20 +162,20 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres val indAddress = try { parseNumber(arg.substring(1, arg.length-2)) } catch (x: NumberFormatException) { - return Result(false, "invalid instruction", this.address, 0) + return Result(false, "invalid instruction", this.startAddress, 0) } instructionSize = if (indAddress <= 255) { val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.ZpY)] ?: return Result(false, "invalid instruction", - this.address, 0) - memory[address] = instruction.toShort() - memory[address+1] = indAddress.toShort() + this.startAddress, 0) + memory[startAddress+assembledSize] = instruction.toShort() + memory[startAddress+assembledSize+1] = indAddress.toShort() 2 } else { val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.AbsY)] ?: return Result(false, "invalid instruction", - this.address, 0) - memory[address] = instruction.toShort() - memory[address+1] = (indAddress and 255).toShort() - memory[address+2] = (indAddress ushr 8).toShort() + this.startAddress, 0) + memory[startAddress+assembledSize] = instruction.toShort() + memory[startAddress+assembledSize+1] = (indAddress and 255).toShort() + memory[startAddress+assembledSize+2] = (indAddress ushr 8).toShort() 3 } } @@ -183,13 +184,13 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres val indAddress = try { parseNumber(arg.substring(1, arg.length-1)) } catch (x: NumberFormatException) { - return Result(false, "invalid instruction", this.address, 0) + return Result(false, "invalid instruction", this.startAddress, 0) } val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Ind)] - ?: return Result(false, "invalid instruction", this.address, 0) - memory[address] = instruction.toShort() - memory[address+1] = (indAddress and 255).toShort() - memory[address+2] = (indAddress ushr 8).toShort() + ?: return Result(false, "invalid instruction", this.startAddress, 0) + memory[startAddress+assembledSize] = instruction.toShort() + memory[startAddress+assembledSize+1] = (indAddress and 255).toShort() + memory[startAddress+assembledSize+2] = (indAddress ushr 8).toShort() instructionSize = 3 } else -> { @@ -197,31 +198,31 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres if (instr != null) { // relative address val rel = try { - parseRelativeToPC(arg, address) + parseRelativeToPC(arg, startAddress) } catch (x: NumberFormatException) { - return Result(false, "invalid numeral", this.address, 0) + return Result(false, "invalid numeral", this.startAddress, 0) } - memory[address] = instr.toShort() - memory[address+1] = (rel-address-2 and 255).toShort() + memory[startAddress+assembledSize] = instr.toShort() + memory[startAddress+assembledSize+1] = (rel-startAddress-2 and 255).toShort() instructionSize = 2 } else { // absolute or absZp val absAddress = try { - if(arg.startsWith('*')) parseRelativeToPC(arg, address) else parseNumber(arg) + if(arg.startsWith('*')) parseRelativeToPC(arg, startAddress) else parseNumber(arg) } catch (x: NumberFormatException) { - return Result(false, "invalid numeral", this.address, 0) + return Result(false, "invalid numeral", this.startAddress, 0) } val zpInstruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Zp)] instructionSize = if (absAddress <= 255 && zpInstruction != null) { - memory[address] = zpInstruction.toShort() - memory[address+1] = absAddress.toShort() + memory[startAddress+assembledSize] = zpInstruction.toShort() + memory[startAddress+assembledSize+1] = absAddress.toShort() 2 } else { val absInstr = instructions[Pair(mnemonic, Cpu6502.AddrMode.Abs)] ?: return Result(false, "invalid instruction", - this.address, 0) - memory[address] = absInstr.toShort() - memory[address+1] = (absAddress and 255).toShort() - memory[address+2] = (absAddress ushr 8).toShort() + this.startAddress, 0) + memory[startAddress+assembledSize] = absInstr.toShort() + memory[startAddress+assembledSize+1] = (absAddress and 255).toShort() + memory[startAddress+assembledSize+2] = (absAddress ushr 8).toShort() 3 } } @@ -229,9 +230,9 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres } } else -> - return Result(false, "syntax error", this.address, 0) + return Result(false, "syntax error", this.startAddress, 0) } - return Result(true, "", this.address, instructionSize) + return Result(true, "", this.startAddress, instructionSize) } } diff --git a/src/test/kotlin/FunctionalTestsBase.kt b/src/test/kotlin/FunctionalTestsBase.kt index 4908a5b..4cc0436 100644 --- a/src/test/kotlin/FunctionalTestsBase.kt +++ b/src/test/kotlin/FunctionalTestsBase.kt @@ -1,3 +1,4 @@ +import razorvine.ksim65.Assembler import razorvine.ksim65.Bus import razorvine.ksim65.Cpu6502 import razorvine.ksim65.components.Ram @@ -29,11 +30,22 @@ abstract class FunctionalTestsBase { protected fun runTest(testprogram: String) { // setup the irq/brk routine and other stubbing // http://www.softwolves.com/arkiv/cbm-hackers/7/7114.html - for(b in listOf(0x48, 0x8A, 0x48, 0x98, 0x48, 0xBA, 0xBD, 0x04, - 0x01, 0x29, 0x10, 0xF0, 0x03, 0x6C, 0x16, 0x03, - 0x6C, 0x14, 0x03).withIndex()) { - ram[0xff48+b.index] = b.value.toShort() - } + val assembler = Assembler(cpu, ram, 0xff48) + val result = assembler.assemble(""" + pha + txa + pha + tya + pha + tsx + lda ${'$'}0104,x + and #${'$'}10 + beq *+5 + jmp (${'$'}0316) + jmp (${'$'}0314) +""".lines()) + assertTrue(result.success) + ram.loadPrg("src/test/kotlin/6502testsuite/$testprogram", null) ram[0x02] = 0 ram[0xa002] = 0 diff --git a/src/test/kotlin/Test6502TestSuiteC64Specific.kt b/src/test/kotlin/Test6502TestSuiteC64Specific.kt index 968276d..c0c3844 100644 --- a/src/test/kotlin/Test6502TestSuiteC64Specific.kt +++ b/src/test/kotlin/Test6502TestSuiteC64Specific.kt @@ -2,6 +2,7 @@ import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.parallel.Execution import org.junit.jupiter.api.parallel.ExecutionMode import razorvine.c64emu.* +import razorvine.ksim65.Assembler import razorvine.ksim65.Bus import razorvine.ksim65.Cpu6502 import razorvine.ksim65.components.Ram @@ -11,7 +12,7 @@ import kotlin.test.* // TODO: run these tests by using the C64 machine emulation components @Execution(ExecutionMode.CONCURRENT) -// @Disabled("test code is not using C64 specific components yet") +@Disabled("need to fix more c64 specific stuff here") class Test6502TestSuiteC64Specific { val cpu: Cpu6502 = Cpu6502() @@ -55,13 +56,22 @@ class Test6502TestSuiteC64Specific { private fun runTest(testprogram: String) { // setup the irq/brk routine and other stubbing // http://www.softwolves.com/arkiv/cbm-hackers/7/7114.html - bus[0] = 47 - bus[1] = 55 - for(b in listOf(0x48, 0x8A, 0x48, 0x98, 0x48, 0xBA, 0xBD, 0x04, - 0x01, 0x29, 0x10, 0xF0, 0x03, 0x6C, 0x16, 0x03, - 0x6C, 0x14, 0x03).withIndex()) { - ram[0xff48+b.index] = b.value.toShort() - } + val assembler = Assembler(cpu, ram, 0xff48) + val result = assembler.assemble(""" + pha + txa + pha + tya + pha + tsx + lda ${'$'}0104,x + and #${'$'}10 + beq *+5 + jmp (${'$'}0316) + jmp (${'$'}0314) +""".lines()) + assertTrue(result.success) + ram.loadPrg("src/test/kotlin/6502testsuite/$testprogram", null) ram[0x02] = 0 ram[0xa002] = 0 @@ -72,6 +82,8 @@ class Test6502TestSuiteC64Specific { ram[Cpu6502.RESET_vector + 1] = 0x08 ram[0x01fe] = 0xff ram[0x01ff] = 0x7f + bus[0] = 47 + bus[1] = 55 cpu.regPC = 0x0801 cpu.regP.fromInt(4) try {