From 75d8c832ad8fca46e641a513095130bcfd49bfd4 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 28 Jun 2019 01:21:31 +0200 Subject: [PATCH] implemented Jump --- compiler/src/prog8/astvm/AstVm.kt | 78 +++++++++++++++++++------ compiler/src/prog8/astvm/Expressions.kt | 4 +- examples/test.p8 | 11 ++++ 3 files changed, 72 insertions(+), 21 deletions(-) diff --git a/compiler/src/prog8/astvm/AstVm.kt b/compiler/src/prog8/astvm/AstVm.kt index a981b56e2..c2088bb18 100644 --- a/compiler/src/prog8/astvm/AstVm.kt +++ b/compiler/src/prog8/astvm/AstVm.kt @@ -136,7 +136,7 @@ class AstVm(val program: Program) { for (s in b.statements.filterIsInstance()) { if (s.name == initvarsSubName) { try { - executeSubroutine(s, emptyList()) + executeSubroutine(s, emptyList(), null) } catch (x: LoopControlReturn) { // regular return } @@ -145,11 +145,36 @@ class AstVm(val program: Program) { } } - val entrypoint = program.entrypoint() ?: throw VmTerminationException("no valid entrypoint found") - try { - executeSubroutine(entrypoint, emptyList()) - } catch (x: LoopControlReturn) { - // regular return + var entrypoint: Subroutine? = program.entrypoint() ?: throw VmTerminationException("no valid entrypoint found") + var startlabel: Label? = null + + while(entrypoint!=null) { + try { + executeSubroutine(entrypoint, emptyList(), startlabel) + entrypoint = null + } catch (rx: LoopControlReturn) { + // regular return + } catch (jx: LoopControlJump) { + if (jx.address != null) + throw VmTerminationException("doesn't support jumping to machine address ${jx.address}") + when { + jx.generatedLabel != null -> { + val label = entrypoint.getLabelOrVariable(jx.generatedLabel) as Label + TODO("$label") + } + jx.identifier != null -> { + when (val jumptarget = entrypoint.lookup(jx.identifier.nameInSource, jx.identifier.parent)) { + is Label -> { + startlabel = jumptarget + entrypoint = jumptarget.definingSubroutine() + } + is Subroutine -> entrypoint = jumptarget + else -> throw VmTerminationException("weird jump target $jumptarget") + } + } + else -> throw VmTerminationException("unspecified jump target") + } + } } println("PROGRAM EXITED!") dialog.title = "PROGRAM EXITED" @@ -167,8 +192,10 @@ class AstVm(val program: Program) { class LoopControlBreak : Exception() class LoopControlContinue : Exception() class LoopControlReturn(val returnvalues: List) : Exception() + class LoopControlJump(val identifier: IdentifierReference?, val address: Int?, val generatedLabel: String?) : Exception() - internal fun executeSubroutine(sub: Subroutine, arguments: List): List { + + internal fun executeSubroutine(sub: Subroutine, arguments: List, startlabel: Label?=null): List { assert(!sub.isAsmSubroutine) if (sub.statements.isEmpty()) throw VmTerminationException("scope contains no statements: $sub") @@ -182,8 +209,16 @@ class AstVm(val program: Program) { EvalContext(program, mem, statusflags, runtimeVariables, functions, ::executeSubroutine)) } + val statements = sub.statements.iterator() + if(startlabel!=null) { + do { + val stmt = statements.next() + } while(stmt!==startlabel) + } + try { - for (s in sub.statements) { + while(statements.hasNext()) { + val s = statements.next() try { executeStatement(sub, s) } @@ -230,7 +265,7 @@ class AstVm(val program: Program) { if (target.isAsmSubroutine) { performSyscall(target, args) } else { - executeSubroutine(target, args) + executeSubroutine(target, args, null) // any return value(s) are discarded } } @@ -286,18 +321,11 @@ class AstVm(val program: Program) { } } } - is Jump -> { - TODO("jump $stmt") - } + is Jump -> throw LoopControlJump(stmt.identifier, stmt.address, stmt.generatedLabel) is InlineAssembly -> { if (sub is Subroutine) { - when (sub.scopedname) { - "c64flt.print_f" -> { - val arg = runtimeVariables.get(sub, sub.parameters.single().name) - performSyscall(sub, listOf(arg)) - } - else -> TODO("simulate asm subroutine ${sub.scopedname}") - } + val args = sub.parameters.map { runtimeVariables.get(sub, it.name) } + performSyscall(sub, args) throw LoopControlReturn(emptyList()) } throw VmExecutionException("can't execute inline assembly in $sub") @@ -497,6 +525,18 @@ class AstVm(val program: Program) { val number = args[1].byteval!! dialog.canvas.printText("$prefix${number.toString(2).padStart(8, '0')}", 1, true) } + "c64scr.clear_screenchars" -> { + dialog.canvas.clearScreen(6) + } + "c64scr.clear_screen" -> { + dialog.canvas.clearScreen(args[0].integerValue()) + } + "c64scr.setcc" -> { + dialog.canvas.setChar(args[0].integerValue(), args[1].integerValue(), args[2].integerValue().toShort()) + } + "c64scr.plot" -> { + dialog.canvas.setCursorPos(args[0].integerValue(), args[1].integerValue()) + } "c64.CHROUT" -> { dialog.canvas.printChar(args[0].byteval!!) } diff --git a/compiler/src/prog8/astvm/Expressions.kt b/compiler/src/prog8/astvm/Expressions.kt index 2671db1b4..9a6c54bd9 100644 --- a/compiler/src/prog8/astvm/Expressions.kt +++ b/compiler/src/prog8/astvm/Expressions.kt @@ -7,7 +7,7 @@ import kotlin.math.abs class EvalContext(val program: Program, val mem: Memory, val statusflags: StatusFlags, val runtimeVars: RuntimeVariables, val functions: BuiltinFunctions, - val executeSubroutine: (sub: Subroutine, args: List) -> List) + val executeSubroutine: (sub: Subroutine, args: List, startlabel: Label?) -> List) fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue { val constval = expr.constValue(ctx.program) @@ -117,7 +117,7 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue { val args = expr.arglist.map { evaluate(it, ctx) } return when(sub) { is Subroutine -> { - val results = ctx.executeSubroutine(sub, args) + val results = ctx.executeSubroutine(sub, args, null) if(results.size!=1) throw VmExecutionException("expected 1 result from functioncall $expr") results[0] diff --git a/examples/test.p8 b/examples/test.p8 index 2aac98e3b..d96456bbf 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -9,7 +9,18 @@ ubyte[100] arr1 ubyte[100] arr2 + _lp: memcopy(arr1, arr2, len(arr2)) + c64scr.setcc(20,10,65,2) + goto x + c64scr.setcc(20,10,65,2) + } + + sub x() { + +derp: + c64scr.print("ey\n") + goto derp }