diff --git a/compiler/test/vm/TestCompilerVirtual.kt b/compiler/test/vm/TestCompilerVirtual.kt index 610d244f6..ccf7c449d 100644 --- a/compiler/test/vm/TestCompilerVirtual.kt +++ b/compiler/test/vm/TestCompilerVirtual.kt @@ -1,6 +1,7 @@ package prog8tests.vm import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import prog8.code.target.Cx16Target import prog8.code.target.VMTarget @@ -32,11 +33,15 @@ main { test("compile virtual: array with pointers") { val src = """ main { - sub start() { - ubyte variable - uword[] words = [1111,2222,"three",&variable] - variable = 2222 in words + str localstr = "hello" + ubyte[] otherarray = [1,2,3] + uword[] words = [1111,2222,"three",&localstr,&otherarray] + uword @shared zz = &words + ubyte result = 2222 in words + zz = words[2] + zz++ + zz = words[3] } }""" val othertarget = Cx16Target() @@ -105,4 +110,31 @@ mylabel_inside: VmRunner().runProgram(virtfile.readText()) } + test("case sensitive symbols") { + val src = """ +%zeropage basicsafe + +main { + sub start() { + ubyte bytevar = 11 ; var at 0 + ubyte byteVAR = 22 ; var at 1 + ubyte ByteVar = 33 ; var at 2 + ubyte @shared total = bytevar+byteVAR+ByteVar ; var at 3 + goto skipLABEL +SkipLabel: + return +skipLABEL: + bytevar = 42 + } +}""" + val othertarget = Cx16Target() + compileText(othertarget, true, src, writeAssembly = true, keepIR=true) shouldNotBe null + val target = VMTarget() + val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!! + val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt") + VmRunner().runAndTestProgram(virtfile.readText()) { vm -> + vm.memory.getUB(0) shouldBe 42u + vm.memory.getUB(3) shouldBe 66u + } + } }) \ No newline at end of file diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 7d4e85a53..9cdc963af 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,8 +3,9 @@ TODO For next release ^^^^^^^^^^^^^^^^ +- fix vm symbol case insensitivity (TestCompilerVirtual) - fix vm crash in TestCompilerVirtual: array with pointers -- fix vm crash (parseValue error) in examples/vm/textelite.p8 (Assembler) +- fix vm crash (parseValue error) in examples/vm/textelite.p8 (Assembler, caused by above?) ... diff --git a/intermediate/src/prog8/intermediate/IRFileWriter.kt b/intermediate/src/prog8/intermediate/IRFileWriter.kt index cb7e83af0..db8d12673 100644 --- a/intermediate/src/prog8/intermediate/IRFileWriter.kt +++ b/intermediate/src/prog8/intermediate/IRFileWriter.kt @@ -121,8 +121,11 @@ class IRFileWriter(private val irProgram: IRProgram) { variable.onetimeInitializationArrayValue!!.joinToString(",") { if(it.number!=null) it.number!!.toInt().toString() - else - "&${it.addressOf!!.joinToString(".")}" + else { + val target = variable.lookup(it.addressOf!!) + ?: throw InternalCompilerException("symbol not found: ${it.addressOf} in ${variable.scopedName}") + "&${target.scopedName.joinToString(".")}" + } } } else { (1..variable.length!!).joinToString(",") { "0" } diff --git a/virtualmachine/src/prog8/vm/Assembler.kt b/virtualmachine/src/prog8/vm/Assembler.kt index 11d8b897b..f362b7269 100644 --- a/virtualmachine/src/prog8/vm/Assembler.kt +++ b/virtualmachine/src/prog8/vm/Assembler.kt @@ -17,6 +17,8 @@ class Assembler { fun initializeMemory(memsrc: String, memory: Memory) { symbolAddresses.clear() + val arrayValuePlaceholders = mutableListOf>() + val instrPattern = Regex("""var (.+) @([0-9]+) ([a-z]+)(\[[0-9]+\])? (.+)""", RegexOption.IGNORE_CASE) for(line in memsrc.lines()) { if(line.isBlank() || line.startsWith(';')) @@ -58,18 +60,33 @@ class Assembler { } } "uword", "word" -> { - val array = values.split(',').map { parseValue(Opcode.LOADCPU, it.trim(), 0).toInt() } - require(array.size==numArrayElts || array.size==1) - if(numArrayElts>array.size) { - val value = array.single().toUShort() - repeat(numArrayElts) { - memory.setUW(address, value) - address += 2 - } + if(arrayspec.isBlank()) { + // single value + val value = parseValue(Opcode.LOADCPU, values.trim(), 0).toInt() + memory.setUW(address, value.toUShort()) + address += 2 } else { - for (value in array) { - memory.setUW(address, value.toUShort()) - address += 2 + // array initializer + val array = values.split(',').withIndex().map {(index, value) -> + val tv = value.trim() + if(tv.startsWith('&')) { + arrayValuePlaceholders += Pair(address+index*2, tv.drop(1)) + 9999 // will be replaced with correct value at the end. + } else + parseValue(Opcode.LOADCPU, tv, 0).toInt() + } + require(array.size==numArrayElts || array.size==1) + if(numArrayElts>array.size) { + val value = array.single().toUShort() + repeat(numArrayElts) { + memory.setUW(address, value) + address += 2 + } + } else { + for (value in array) { + memory.setUW(address, value.toUShort()) + address += 2 + } } } } @@ -93,6 +110,12 @@ class Assembler { } } } + + // correct the addres-of values in array initializers + arrayValuePlaceholders.forEach { (address, symbol) -> + val addr = this.symbolAddresses.getValue(symbol) + memory.setUW(address, addr.toUShort()) + } } fun assembleProgram(source: CharSequence): List { diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 57dbebd72..14084b0b9 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -2106,6 +2106,10 @@ class VirtualMachine(val memory: Memory, program: List, val cx16vir // probably called via reflection class VmRunner: IVirtualMachineRunner { override fun runProgram(source: String) { + runAndTestProgram(source) { /* no tests */ } + } + + fun runAndTestProgram(source: String, test: (VirtualMachine) -> Unit) { val (memsrc, programsrc) = source.split("------PROGRAM------".toRegex(), 2) val memory = Memory() val assembler = Assembler() @@ -2113,5 +2117,6 @@ class VmRunner: IVirtualMachineRunner { val program = assembler.assembleProgram(programsrc) val vm = VirtualMachine(memory, program, assembler.cx16virtualregBaseAdress) vm.run() + test(vm) } } \ No newline at end of file