1
0
mirror of https://github.com/irmen/ksim65.git synced 2024-06-06 22:29:33 +00:00

use assembler instead of raw bytes

This commit is contained in:
Irmen de Jong 2020-02-19 00:48:05 +01:00
parent deaf79fcc2
commit be8716c4a4
3 changed files with 95 additions and 70 deletions

View File

@ -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 var assembledSize = 0
private val instructions by lazy { private val instructions by lazy {
@ -49,11 +49,12 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres
fun assemble(lines: Iterable<String>): Result { fun assemble(lines: Iterable<String>): Result {
for(line in lines) { for(line in lines) {
val result = assemble(line) val result = assemble(line)
println("line: $line -> ${result.success} ${result.error}") // TODO
if(!result.success) if(!result.success)
return result return result
assembledSize += result.numBytes assembledSize += result.numBytes
} }
return Result(true, "", address, assembledSize) return Result(true, "", startAddress, assembledSize)
} }
fun assemble(line: String): Result { fun assemble(line: String): Result {
@ -68,20 +69,20 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres
var args = line.trim().split(' ') var args = line.trim().split(' ')
if(args.isEmpty() || args.size == 1 && args[0] == "") 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) { if(args[0].startsWith("*=") && args.size==1) {
address = parseNumber(args[0].substring(2)) startAddress = parseNumber(args[0].substring(2))
return Result(true, "", address, 0) return Result(true, "", startAddress, 0)
} }
else if(args[0] == "*" && args[1] == "=") { else if(args[0] == "*" && args[1] == "=") {
address = parseNumber(args[2]) startAddress = parseNumber(args[2])
return Result(true, "", address, 0) return Result(true, "", startAddress, 0)
} else { } else {
// line with an instruction, may be preceded by a 4 or 5 char address // 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[0].length == 4 || args[0].length==5) {
if(args.size!=2 && args.size !=3) if(args.size!=2 && args.size !=3)
return Result(false, "syntax error", address, 0) return Result(false, "syntax error", startAddress, 0)
address = parseNumber(args[0]) startAddress = parseNumber(args[0])
args = args.drop(1) args = args.drop(1)
} }
} }
@ -94,8 +95,8 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres
instructionSize = 1 instructionSize = 1
var instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Imp)] var instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Imp)]
if (instruction == null) instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Acc)] if (instruction == null) instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Acc)]
if (instruction == null) return Result(false, "invalid instruction", this.address, 0) if (instruction == null) return Result(false, "invalid instruction", this.startAddress, 0)
memory[address] = instruction.toShort() memory[startAddress+assembledSize] = instruction.toShort()
} }
2 -> { 2 -> {
val arg = args[1] val arg = args[1]
@ -103,9 +104,9 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres
arg.startsWith('#') -> { arg.startsWith('#') -> {
// immediate // immediate
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Imm)] ?: return Result(false, "invalid instruction", val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Imm)] ?: return Result(false, "invalid instruction",
this.address, 0) this.startAddress, 0)
memory[address] = instruction.toShort() memory[startAddress+assembledSize] = instruction.toShort()
memory[address+1] = parseNumber(arg.substring(1), decimalFirst = true).toShort() memory[startAddress+assembledSize+1] = parseNumber(arg.substring(1), decimalFirst = true).toShort()
instructionSize = 2 instructionSize = 2
} }
arg.startsWith("(") && arg.endsWith(",x)") -> { arg.startsWith("(") && arg.endsWith(",x)") -> {
@ -113,12 +114,12 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres
val indAddress = try { val indAddress = try {
parseNumber(arg.substring(1, arg.length-3)) parseNumber(arg.substring(1, arg.length-3))
} catch (x: NumberFormatException) { } 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", val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.IzX)] ?: return Result(false, "invalid instruction",
this.address, 0) this.startAddress, 0)
memory[address] = instruction.toShort() memory[startAddress+assembledSize] = instruction.toShort()
memory[address+1] = indAddress.toShort() memory[startAddress+assembledSize+1] = indAddress.toShort()
instructionSize = 2 instructionSize = 2
} }
arg.startsWith("(") && arg.endsWith("),y") -> { arg.startsWith("(") && arg.endsWith("),y") -> {
@ -126,12 +127,12 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres
val indAddress = try { val indAddress = try {
parseNumber(arg.substring(1, arg.length-3)) parseNumber(arg.substring(1, arg.length-3))
} catch (x: NumberFormatException) { } 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", val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.IzY)] ?: return Result(false, "invalid instruction",
this.address, 0) this.startAddress, 0)
memory[address] = instruction.toShort() memory[startAddress+assembledSize] = instruction.toShort()
memory[address+1] = indAddress.toShort() memory[startAddress+assembledSize+1] = indAddress.toShort()
instructionSize = 2 instructionSize = 2
} }
arg.endsWith(",x") -> { arg.endsWith(",x") -> {
@ -139,20 +140,20 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres
val indAddress = try { val indAddress = try {
parseNumber(arg.substring(1, arg.length-2)) parseNumber(arg.substring(1, arg.length-2))
} catch (x: NumberFormatException) { } catch (x: NumberFormatException) {
return Result(false, "invalid instruction", this.address, 0) return Result(false, "invalid instruction", this.startAddress, 0)
} }
instructionSize = if (indAddress <= 255) { instructionSize = if (indAddress <= 255) {
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.ZpX)] ?: return Result(false, "invalid instruction", val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.ZpX)] ?: return Result(false, "invalid instruction",
this.address, 0) this.startAddress, 0)
memory[address] = instruction.toShort() memory[startAddress+assembledSize] = instruction.toShort()
memory[address+1] = indAddress.toShort() memory[startAddress+assembledSize+1] = indAddress.toShort()
2 2
} else { } else {
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.AbsX)] ?: return Result(false, "invalid instruction", val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.AbsX)] ?: return Result(false, "invalid instruction",
this.address, 0) this.startAddress, 0)
memory[address] = instruction.toShort() memory[startAddress+assembledSize] = instruction.toShort()
memory[address+1] = (indAddress and 255).toShort() memory[startAddress+assembledSize+1] = (indAddress and 255).toShort()
memory[address+2] = (indAddress ushr 8).toShort() memory[startAddress+assembledSize+2] = (indAddress ushr 8).toShort()
3 3
} }
} }
@ -161,20 +162,20 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres
val indAddress = try { val indAddress = try {
parseNumber(arg.substring(1, arg.length-2)) parseNumber(arg.substring(1, arg.length-2))
} catch (x: NumberFormatException) { } catch (x: NumberFormatException) {
return Result(false, "invalid instruction", this.address, 0) return Result(false, "invalid instruction", this.startAddress, 0)
} }
instructionSize = if (indAddress <= 255) { instructionSize = if (indAddress <= 255) {
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.ZpY)] ?: return Result(false, "invalid instruction", val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.ZpY)] ?: return Result(false, "invalid instruction",
this.address, 0) this.startAddress, 0)
memory[address] = instruction.toShort() memory[startAddress+assembledSize] = instruction.toShort()
memory[address+1] = indAddress.toShort() memory[startAddress+assembledSize+1] = indAddress.toShort()
2 2
} else { } else {
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.AbsY)] ?: return Result(false, "invalid instruction", val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.AbsY)] ?: return Result(false, "invalid instruction",
this.address, 0) this.startAddress, 0)
memory[address] = instruction.toShort() memory[startAddress+assembledSize] = instruction.toShort()
memory[address+1] = (indAddress and 255).toShort() memory[startAddress+assembledSize+1] = (indAddress and 255).toShort()
memory[address+2] = (indAddress ushr 8).toShort() memory[startAddress+assembledSize+2] = (indAddress ushr 8).toShort()
3 3
} }
} }
@ -183,13 +184,13 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres
val indAddress = try { val indAddress = try {
parseNumber(arg.substring(1, arg.length-1)) parseNumber(arg.substring(1, arg.length-1))
} catch (x: NumberFormatException) { } 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)] val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Ind)]
?: return Result(false, "invalid instruction", this.address, 0) ?: return Result(false, "invalid instruction", this.startAddress, 0)
memory[address] = instruction.toShort() memory[startAddress+assembledSize] = instruction.toShort()
memory[address+1] = (indAddress and 255).toShort() memory[startAddress+assembledSize+1] = (indAddress and 255).toShort()
memory[address+2] = (indAddress ushr 8).toShort() memory[startAddress+assembledSize+2] = (indAddress ushr 8).toShort()
instructionSize = 3 instructionSize = 3
} }
else -> { else -> {
@ -197,31 +198,31 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres
if (instr != null) { if (instr != null) {
// relative address // relative address
val rel = try { val rel = try {
parseRelativeToPC(arg, address) parseRelativeToPC(arg, startAddress)
} catch (x: NumberFormatException) { } catch (x: NumberFormatException) {
return Result(false, "invalid numeral", this.address, 0) return Result(false, "invalid numeral", this.startAddress, 0)
} }
memory[address] = instr.toShort() memory[startAddress+assembledSize] = instr.toShort()
memory[address+1] = (rel-address-2 and 255).toShort() memory[startAddress+assembledSize+1] = (rel-startAddress-2 and 255).toShort()
instructionSize = 2 instructionSize = 2
} else { } else {
// absolute or absZp // absolute or absZp
val absAddress = try { val absAddress = try {
if(arg.startsWith('*')) parseRelativeToPC(arg, address) else parseNumber(arg) if(arg.startsWith('*')) parseRelativeToPC(arg, startAddress) else parseNumber(arg)
} catch (x: NumberFormatException) { } 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)] val zpInstruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Zp)]
instructionSize = if (absAddress <= 255 && zpInstruction != null) { instructionSize = if (absAddress <= 255 && zpInstruction != null) {
memory[address] = zpInstruction.toShort() memory[startAddress+assembledSize] = zpInstruction.toShort()
memory[address+1] = absAddress.toShort() memory[startAddress+assembledSize+1] = absAddress.toShort()
2 2
} else { } else {
val absInstr = instructions[Pair(mnemonic, Cpu6502.AddrMode.Abs)] ?: return Result(false, "invalid instruction", val absInstr = instructions[Pair(mnemonic, Cpu6502.AddrMode.Abs)] ?: return Result(false, "invalid instruction",
this.address, 0) this.startAddress, 0)
memory[address] = absInstr.toShort() memory[startAddress+assembledSize] = absInstr.toShort()
memory[address+1] = (absAddress and 255).toShort() memory[startAddress+assembledSize+1] = (absAddress and 255).toShort()
memory[address+2] = (absAddress ushr 8).toShort() memory[startAddress+assembledSize+2] = (absAddress ushr 8).toShort()
3 3
} }
} }
@ -229,9 +230,9 @@ class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddres
} }
} }
else -> 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)
} }
} }

View File

@ -1,3 +1,4 @@
import razorvine.ksim65.Assembler
import razorvine.ksim65.Bus import razorvine.ksim65.Bus
import razorvine.ksim65.Cpu6502 import razorvine.ksim65.Cpu6502
import razorvine.ksim65.components.Ram import razorvine.ksim65.components.Ram
@ -29,11 +30,22 @@ abstract class FunctionalTestsBase {
protected fun runTest(testprogram: String) { protected fun runTest(testprogram: String) {
// setup the irq/brk routine and other stubbing // setup the irq/brk routine and other stubbing
// http://www.softwolves.com/arkiv/cbm-hackers/7/7114.html // http://www.softwolves.com/arkiv/cbm-hackers/7/7114.html
for(b in listOf(0x48, 0x8A, 0x48, 0x98, 0x48, 0xBA, 0xBD, 0x04, val assembler = Assembler(cpu, ram, 0xff48)
0x01, 0x29, 0x10, 0xF0, 0x03, 0x6C, 0x16, 0x03, val result = assembler.assemble("""
0x6C, 0x14, 0x03).withIndex()) { pha
ram[0xff48+b.index] = b.value.toShort() 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.loadPrg("src/test/kotlin/6502testsuite/$testprogram", null)
ram[0x02] = 0 ram[0x02] = 0
ram[0xa002] = 0 ram[0xa002] = 0

View File

@ -2,6 +2,7 @@ import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.parallel.Execution import org.junit.jupiter.api.parallel.Execution
import org.junit.jupiter.api.parallel.ExecutionMode import org.junit.jupiter.api.parallel.ExecutionMode
import razorvine.c64emu.* import razorvine.c64emu.*
import razorvine.ksim65.Assembler
import razorvine.ksim65.Bus import razorvine.ksim65.Bus
import razorvine.ksim65.Cpu6502 import razorvine.ksim65.Cpu6502
import razorvine.ksim65.components.Ram import razorvine.ksim65.components.Ram
@ -11,7 +12,7 @@ import kotlin.test.*
// TODO: run these tests by using the C64 machine emulation components // TODO: run these tests by using the C64 machine emulation components
@Execution(ExecutionMode.CONCURRENT) @Execution(ExecutionMode.CONCURRENT)
// @Disabled("test code is not using C64 specific components yet") @Disabled("need to fix more c64 specific stuff here")
class Test6502TestSuiteC64Specific { class Test6502TestSuiteC64Specific {
val cpu: Cpu6502 = Cpu6502() val cpu: Cpu6502 = Cpu6502()
@ -55,13 +56,22 @@ class Test6502TestSuiteC64Specific {
private fun runTest(testprogram: String) { private fun runTest(testprogram: String) {
// setup the irq/brk routine and other stubbing // setup the irq/brk routine and other stubbing
// http://www.softwolves.com/arkiv/cbm-hackers/7/7114.html // http://www.softwolves.com/arkiv/cbm-hackers/7/7114.html
bus[0] = 47 val assembler = Assembler(cpu, ram, 0xff48)
bus[1] = 55 val result = assembler.assemble("""
for(b in listOf(0x48, 0x8A, 0x48, 0x98, 0x48, 0xBA, 0xBD, 0x04, pha
0x01, 0x29, 0x10, 0xF0, 0x03, 0x6C, 0x16, 0x03, txa
0x6C, 0x14, 0x03).withIndex()) { pha
ram[0xff48+b.index] = b.value.toShort() 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.loadPrg("src/test/kotlin/6502testsuite/$testprogram", null)
ram[0x02] = 0 ram[0x02] = 0
ram[0xa002] = 0 ram[0xa002] = 0
@ -72,6 +82,8 @@ class Test6502TestSuiteC64Specific {
ram[Cpu6502.RESET_vector + 1] = 0x08 ram[Cpu6502.RESET_vector + 1] = 0x08
ram[0x01fe] = 0xff ram[0x01fe] = 0xff
ram[0x01ff] = 0x7f ram[0x01ff] = 0x7f
bus[0] = 47
bus[1] = 55
cpu.regPC = 0x0801 cpu.regPC = 0x0801
cpu.regP.fromInt(4) cpu.regP.fromInt(4)
try { try {