diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index a0f971603..d9aa532a2 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -308,6 +308,8 @@ internal class AstChecker(private val program: Program, err("subroutines can only be defined in the scope of a block or within another subroutine") if(subroutine.isAsmSubroutine) { + if(compilerOptions.compTarget.name==VMTarget.NAME) + err("cannot use asmsub for vm target, use regular subs") if(subroutine.asmParameterRegisters.size != subroutine.parameters.size) err("number of asm parameter registers is not the isSameAs as number of parameters") if(subroutine.asmReturnvaluesRegisters.size != subroutine.returntypes.size) diff --git a/compiler/test/vm/TestCompilerVirtual.kt b/compiler/test/vm/TestCompilerVirtual.kt index 06007a04a..ff0d5ba81 100644 --- a/compiler/test/vm/TestCompilerVirtual.kt +++ b/compiler/test/vm/TestCompilerVirtual.kt @@ -14,6 +14,7 @@ import prog8.intermediate.IRFileReader import prog8.intermediate.IRSubroutine import prog8.intermediate.Opcode import prog8.vm.VmRunner +import prog8tests.helpers.ErrorReporterForTests import prog8tests.helpers.compileText import kotlin.io.path.readText @@ -218,7 +219,7 @@ main { } } - test("asmsub for virtual target") { + test("asmsub for virtual target not supported") { val src = """ main { sub start() { @@ -230,6 +231,28 @@ main { lda #99 tay rts + }} + } +}""" + val othertarget = Cx16Target() + compileText(othertarget, true, src, writeAssembly = true) shouldNotBe null + + val target = VMTarget() + val errors = ErrorReporterForTests() + compileText(target, false, src, writeAssembly = false, errors = errors) shouldBe null + errors.errors.size shouldBe 1 + errors.errors[0] shouldContain "cannot use asmsub for vm target" + } + + test("asmsub for virtual target not supported even with IR") { + val src = """ +main { + sub start() { + void test(42) + } + + asmsub test(ubyte xx @A) -> ubyte @Y { + %ir {{ return }} } @@ -237,13 +260,52 @@ main { val othertarget = Cx16Target() compileText(othertarget, true, src, writeAssembly = true) shouldNotBe null + val target = VMTarget() + val errors = ErrorReporterForTests() + compileText(target, false, src, writeAssembly = false, errors = errors) shouldBe null + errors.errors.size shouldBe 1 + errors.errors[0] shouldContain "cannot use asmsub for vm target" + } + + test("inline asm for virtual target should be IR") { + val src = """ +main { + sub start() { + %asm {{ + lda #99 + tay + rts + }} + } +}""" + val othertarget = Cx16Target() + compileText(othertarget, true, src, writeAssembly = true) shouldNotBe null + val target = VMTarget() val result = compileText(target, false, src, writeAssembly = true)!! val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir") val exc = shouldThrow { VmRunner().runProgram(virtfile.readText()) } - exc.message shouldContain("does not support non-IR asmsubs") + exc.message shouldContain("does not support real inlined assembly") + } + + test("inline asm for virtual target with IR is accepted") { + val src = """ +main { + sub start() { + %ir {{ + return + }} + } +}""" + val othertarget = Cx16Target() + compileText(othertarget, true, src, writeAssembly = true) shouldNotBe null + + val target = VMTarget() + val result = compileText(target, false, src, writeAssembly = true)!! + val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir") + VmRunner().runProgram(virtfile.readText()) } test("addresses from labels/subroutines not yet supported in VM") { diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index 8de6a244a..d5e7f3ec3 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -38,14 +38,7 @@ class VmProgramLoader { block.children.forEach { child -> when(child) { - is IRAsmSubroutine -> { - if(!child.asmChunk.isIR) - throw IRParseException("vm currently does not support non-IR asmsubs: ${child.label}") - else { - val replacement = addAssemblyToProgram(child.asmChunk, programChunks, variableAddresses) - chunkReplacements += replacement - } - } + is IRAsmSubroutine -> throw IRParseException("vm does not support asmsubs (use normal sub): ${child.label}") is IRCodeChunk -> programChunks += child is IRInlineAsmChunk -> { val replacement = addAssemblyToProgram(child, programChunks, variableAddresses) diff --git a/virtualmachine/test/TestVm.kt b/virtualmachine/test/TestVm.kt index 1eed3887a..d826c3a4a 100644 --- a/virtualmachine/test/TestVm.kt +++ b/virtualmachine/test/TestVm.kt @@ -2,7 +2,6 @@ import io.kotest.assertions.throwables.shouldThrowWithMessage import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.collections.shouldBeEmpty import io.kotest.matchers.shouldBe -import io.kotest.matchers.shouldNotBe import prog8.code.core.* import prog8.code.target.VMTarget import prog8.intermediate.* @@ -84,7 +83,7 @@ class TestVm: FunSpec( { } } - test("non-IR asmsub not supported in vm") { + test("asmsub not supported in vm even with IR") { val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget()) val block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY) val startSub = IRAsmSubroutine( @@ -93,33 +92,16 @@ class TestVm: FunSpec( { emptySet(), emptyList(), emptyList(), - IRInlineAsmChunk("main.asmstart", "inlined asm here", false, null), + IRInlineAsmChunk("main.asmstart", "return", false, null), Position.DUMMY ) block += startSub program.addBlock(block) - shouldThrowWithMessage("vm currently does not support non-IR asmsubs: main.asmstart") { + shouldThrowWithMessage("vm does not support asmsubs (use normal sub): main.asmstart") { VirtualMachine(program) } } - test("IR asmsub ok in vm") { - val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget()) - val block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY) - val startSub = IRAsmSubroutine( - "main.start", - 0x2000u, - emptySet(), - emptyList(), - emptyList(), - IRInlineAsmChunk("main.start", "return", true, null), - Position.DUMMY - ) - block += startSub - program.addBlock(block) - VirtualMachine(program).run() - } - test("vmrunner") { val runner = VmRunner() val irSource="""