diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 426460364..bf60062aa 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -1552,17 +1552,19 @@ internal class Compiler(private val program: Program) { private fun translate(loop: ForLoop) { if(loop.body.containsNoCodeNorVars()) return prog.line(loop.position) - val loopVarName: String - val loopVarDt: DataType + val loopVarName: String? + val loopRegister: Register? + val loopvalueDt: DataType if(loop.loopRegister!=null) { - val reg = loop.loopRegister - loopVarName = reg.name - loopVarDt = DataType.UBYTE + loopVarName = null + loopRegister = loop.loopRegister + loopvalueDt = DataType.UBYTE } else { val loopvar = loop.loopVar!!.targetVarDecl(program.namespace)!! loopVarName = loopvar.scopedname - loopVarDt = loopvar.datatype + loopvalueDt = loopvar.datatype + loopRegister = null } if(loop.iterable is RangeExpr) { @@ -1575,7 +1577,7 @@ internal class Compiler(private val program: Program) { throw CompilerException("loop over just 1 value should have been optimized away") if((range.last-range.first) % range.step != 0) throw CompilerException("range first and last must be exactly inclusive") - when (loopVarDt) { + when (loopvalueDt) { DataType.UBYTE -> { if (range.first < 0 || range.first > 255 || range.last < 0 || range.last > 255) throw CompilerException("range out of bounds for ubyte") @@ -1594,7 +1596,7 @@ internal class Compiler(private val program: Program) { } else -> throw CompilerException("range must be byte or word") } - translateForOverConstantRange(loopVarName, loopVarDt, range, loop.body) + translateForOverConstantRange(loopVarName, loopRegister, loopvalueDt, range, loop.body) } else { // loop over a range where one or more of the start, last or step values is not a constant if(loop.loopRegister!=null) { @@ -1613,7 +1615,7 @@ internal class Compiler(private val program: Program) { val iterableValue = vardecl.value as LiteralValue if(iterableValue.type !in IterableDatatypes) throw CompilerException("loop over something that isn't iterable ${loop.iterable}") - translateForOverIterableVar(loop, loopVarDt, iterableValue) + translateForOverIterableVar(loop, loopvalueDt, iterableValue) } loop.iterable is LiteralValue -> throw CompilerException("literal value in loop must have been moved to heap already $loop") else -> throw CompilerException("loopvar is something strange ${loop.iterable}") @@ -1706,7 +1708,7 @@ internal class Compiler(private val program: Program) { continueStmtLabelStack.pop() } - private fun translateForOverConstantRange(varname: String, varDt: DataType, range: IntProgression, body: AnonymousScope) { + private fun translateForOverConstantRange(varname: String?, loopregister: Register?, varDt: DataType, range: IntProgression, body: AnonymousScope) { /** * for LV in start..last { body } * (and we already know that the range is not empty, and first and last are exactly inclusive.) @@ -1734,7 +1736,9 @@ internal class Compiler(private val program: Program) { breakStmtLabelStack.push(breakLabel) prog.instr(opcodePush(varDt), RuntimeValue(varDt, range.first)) - prog.instr(opcodePopvar(varDt), callLabel = varname) + val variableLabel = varname ?: loopregister?.name + + prog.instr(opcodePopvar(varDt), callLabel = variableLabel) prog.label(loopLabel) translate(body) prog.label(continueLabel) @@ -1742,25 +1746,25 @@ internal class Compiler(private val program: Program) { when { range.step in 1..numberOfIncDecsForOptimize -> { repeat(range.step) { - prog.instr(opcodeIncvar(varDt), callLabel = varname) + prog.instr(opcodeIncvar(varDt), callLabel = variableLabel) } } range.step in -1 downTo -numberOfIncDecsForOptimize -> { repeat(abs(range.step)) { - prog.instr(opcodeDecvar(varDt), callLabel = varname) + prog.instr(opcodeDecvar(varDt), callLabel = variableLabel) } } range.step>numberOfIncDecsForOptimize -> { - prog.instr(opcodePushvar(varDt), callLabel = varname) + prog.instr(opcodePushvar(varDt), callLabel = variableLabel) prog.instr(opcodePush(varDt), RuntimeValue(varDt, range.step)) prog.instr(opcodeAdd(varDt)) - prog.instr(opcodePopvar(varDt), callLabel = varname) + prog.instr(opcodePopvar(varDt), callLabel = variableLabel) } range.step { - prog.instr(opcodePushvar(varDt), callLabel = varname) + prog.instr(opcodePushvar(varDt), callLabel = variableLabel) prog.instr(opcodePush(varDt), RuntimeValue(varDt, abs(range.step))) prog.instr(opcodeSub(varDt)) - prog.instr(opcodePopvar(varDt), callLabel = varname) + prog.instr(opcodePopvar(varDt), callLabel = variableLabel) } } @@ -1768,7 +1772,7 @@ internal class Compiler(private val program: Program) { // optimize for the for loop that counts to 0 prog.instr(if(range.first>0) Opcode.BPOS else Opcode.BNEG, callLabel = loopLabel) } else { - prog.instr(opcodePushvar(varDt), callLabel = varname) + prog.instr(opcodePushvar(varDt), callLabel = variableLabel) val checkValue = when (varDt) { DataType.UBYTE -> (range.last + range.step) and 255 diff --git a/compiler/src/prog8/compiler/Main.kt b/compiler/src/prog8/compiler/Main.kt index 1e9917632..cf92d4cda 100644 --- a/compiler/src/prog8/compiler/Main.kt +++ b/compiler/src/prog8/compiler/Main.kt @@ -88,7 +88,7 @@ fun compileProgram(filepath: Path, programAst.checkValid(compilerOptions) // check if final tree is valid programAst.checkRecursion() // check if there are recursive subroutine calls - // printAst(programAst) + printAst(programAst) // namespace.debugPrint() if(generateVmCode) { diff --git a/compiler/src/prog8/vm/astvm/AstVm.kt b/compiler/src/prog8/vm/astvm/AstVm.kt index 72f4db1f4..dc3c6083c 100644 --- a/compiler/src/prog8/vm/astvm/AstVm.kt +++ b/compiler/src/prog8/vm/astvm/AstVm.kt @@ -10,9 +10,11 @@ import prog8.vm.RuntimeValue import prog8.vm.RuntimeValueRange import prog8.compiler.target.c64.Petscii import java.awt.EventQueue +import java.util.* import kotlin.NoSuchElementException import kotlin.concurrent.fixedRateTimer -import kotlin.math.min +import kotlin.math.* +import kotlin.random.Random class VmExecutionException(msg: String?) : Exception(msg) @@ -128,6 +130,13 @@ class AstVm(val program: Program) { val bootTime = System.currentTimeMillis() var rtcOffset = bootTime + private val rnd = Random(0) + private val statusFlagsSave = Stack() + private val registerXsave = Stack() + private val registerYsave = Stack() + private val registerAsave = Stack() + + init { // observe the jiffyclock mem.observe(0xa0, 0xa1, 0xa2) @@ -236,8 +245,7 @@ class AstVm(val program: Program) { } private val runtimeVariables = RuntimeVariables() - private val functions = BuiltinFunctions() - private val evalCtx = EvalContext(program, mem, statusflags, runtimeVariables, functions, ::executeSubroutine) + private val evalCtx = EvalContext(program, mem, statusflags, runtimeVariables, ::performBuiltinFunction, ::executeSubroutine) class LoopControlBreak : Exception() class LoopControlContinue : Exception() @@ -324,7 +332,7 @@ class AstVm(val program: Program) { executeSwap(stmt) } else { val args = evaluate(stmt.arglist) - functions.performBuiltinFunction(target.name, args, statusflags) + performBuiltinFunction(target.name, args, statusflags) } } else -> { @@ -363,6 +371,16 @@ class AstVm(val program: Program) { stmt.target.arrayindexed != null -> { TODO("postincrdecr array $stmt") } + stmt.target.register != null -> { + var value = runtimeVariables.get(program.namespace, stmt.target.register!!.name) + value = when { + stmt.operator == "++" -> value.add(RuntimeValue(value.type, 1)) + stmt.operator == "--" -> value.sub(RuntimeValue(value.type, 1)) + else -> throw VmExecutionException("strange postincdec operator $stmt") + } + runtimeVariables.set(program.namespace, stmt.target.register!!.name, value) + } + else -> throw VmExecutionException("empty postincrdecr? $stmt") } } is Jump -> throw LoopControlJump(stmt.identifier, stmt.address, stmt.generatedLabel) @@ -629,5 +647,199 @@ class AstVm(val program: Program) { else -> TODO("syscall ${sub.scopedname} $sub") } } + + private fun performBuiltinFunction(name: String, args: List, statusflags: StatusFlags): RuntimeValue? { + return when (name) { + "rnd" -> RuntimeValue(DataType.UBYTE, rnd.nextInt() and 255) + "rndw" -> RuntimeValue(DataType.UWORD, rnd.nextInt() and 65535) + "rndf" -> RuntimeValue(DataType.FLOAT, rnd.nextDouble()) + "lsb" -> RuntimeValue(DataType.UBYTE, args[0].integerValue() and 255) + "msb" -> RuntimeValue(DataType.UBYTE, (args[0].integerValue() ushr 8) and 255) + "sin" -> RuntimeValue(DataType.FLOAT, sin(args[0].numericValue().toDouble())) + "sin8" -> { + val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI + RuntimeValue(DataType.BYTE, (127.0 * sin(rad)).toShort()) + } + "sin8u" -> { + val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI + RuntimeValue(DataType.UBYTE, (128.0 + 127.5 * sin(rad)).toShort()) + } + "sin16" -> { + val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI + RuntimeValue(DataType.BYTE, (32767.0 * sin(rad)).toShort()) + } + "sin16u" -> { + val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI + RuntimeValue(DataType.UBYTE, (32768.0 + 32767.5 * sin(rad)).toShort()) + } + "cos" -> RuntimeValue(DataType.FLOAT, cos(args[0].numericValue().toDouble())) + "cos8" -> { + val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI + RuntimeValue(DataType.BYTE, (127.0 * cos(rad)).toShort()) + } + "cos8u" -> { + val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI + RuntimeValue(DataType.UBYTE, (128.0 + 127.5 * cos(rad)).toShort()) + } + "cos16" -> { + val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI + RuntimeValue(DataType.BYTE, (32767.0 * cos(rad)).toShort()) + } + "cos16u" -> { + val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI + RuntimeValue(DataType.UBYTE, (32768.0 + 32767.5 * cos(rad)).toShort()) + } + "tan" -> RuntimeValue(DataType.FLOAT, tan(args[0].numericValue().toDouble())) + "atan" -> RuntimeValue(DataType.FLOAT, atan(args[0].numericValue().toDouble())) + "ln" -> RuntimeValue(DataType.FLOAT, ln(args[0].numericValue().toDouble())) + "log2" -> RuntimeValue(DataType.FLOAT, log2(args[0].numericValue().toDouble())) + "sqrt" -> RuntimeValue(DataType.FLOAT, sqrt(args[0].numericValue().toDouble())) + "sqrt16" -> RuntimeValue(DataType.UBYTE, sqrt(args[0].wordval!!.toDouble()).toInt()) + "rad" -> RuntimeValue(DataType.FLOAT, Math.toRadians(args[0].numericValue().toDouble())) + "deg" -> RuntimeValue(DataType.FLOAT, Math.toDegrees(args[0].numericValue().toDouble())) + "round" -> RuntimeValue(DataType.FLOAT, round(args[0].numericValue().toDouble())) + "floor" -> RuntimeValue(DataType.FLOAT, floor(args[0].numericValue().toDouble())) + "ceil" -> RuntimeValue(DataType.FLOAT, ceil(args[0].numericValue().toDouble())) + "rol" -> { + val (result, newCarry) = args[0].rol(statusflags.carry) + statusflags.carry = newCarry + return result + } + "rol2" -> args[0].rol2() + "ror" -> { + val (result, newCarry) = args[0].ror(statusflags.carry) + statusflags.carry = newCarry + return result + } + "ror2" -> args[0].ror2() + "lsl" -> args[0].shl() + "lsr" -> args[0].shr() + "abs" -> { + when (args[0].type) { + DataType.UBYTE -> args[0] + DataType.BYTE -> RuntimeValue(DataType.UBYTE, abs(args[0].numericValue().toDouble())) + DataType.UWORD -> args[0] + DataType.WORD -> RuntimeValue(DataType.UWORD, abs(args[0].numericValue().toDouble())) + DataType.FLOAT -> RuntimeValue(DataType.FLOAT, abs(args[0].numericValue().toDouble())) + else -> TODO("strange abs type") + } + } + "max" -> { + val numbers = args.map { it.numericValue().toDouble() } + RuntimeValue(args[0].type, numbers.max()) + } + "min" -> { + val numbers = args.map { it.numericValue().toDouble() } + RuntimeValue(args[0].type, numbers.min()) + } + "avg" -> { + val numbers = args.map { it.numericValue().toDouble() } + RuntimeValue(DataType.FLOAT, numbers.average()) + } + "sum" -> { + val sum = args.map { it.numericValue().toDouble() }.sum() + when (args[0].type) { + DataType.UBYTE -> RuntimeValue(DataType.UWORD, sum) + DataType.BYTE -> RuntimeValue(DataType.WORD, sum) + DataType.UWORD -> RuntimeValue(DataType.UWORD, sum) + DataType.WORD -> RuntimeValue(DataType.WORD, sum) + DataType.FLOAT -> RuntimeValue(DataType.FLOAT, sum) + else -> TODO("weird sum type") + } + } + "any" -> { + val numbers = args.map { it.numericValue().toDouble() } + RuntimeValue(DataType.UBYTE, if (numbers.any { it != 0.0 }) 1 else 0) + } + "all" -> { + val numbers = args.map { it.numericValue().toDouble() } + RuntimeValue(DataType.UBYTE, if (numbers.all { it != 0.0 }) 1 else 0) + } + "swap" -> + throw VmExecutionException("swap() cannot be implemented as a function") + "strlen" -> { + val zeroIndex = args[0].str!!.indexOf(0.toChar()) + if (zeroIndex >= 0) + RuntimeValue(DataType.UBYTE, zeroIndex) + else + RuntimeValue(DataType.UBYTE, args[0].str!!.length) + } + "memset" -> { + val target = args[0].array!! + val amount = args[1].integerValue() + val value = args[2].integerValue() + for (i in 0 until amount) { + target[i] = value + } + null + } + "memsetw" -> { + val target = args[0].array!! + val amount = args[1].integerValue() + val value = args[2].integerValue() + for (i in 0 until amount step 2) { + target[i * 2] = value and 255 + target[i * 2 + 1] = value ushr 8 + } + null + } + "memcopy" -> { + val source = args[0].array!! + val dest = args[1].array!! + val amount = args[2].integerValue() + for(i in 0 until amount) { + dest[i] = source[i] + } + null + } + "mkword" -> { + val result = (args[1].integerValue() shl 8) or args[0].integerValue() + RuntimeValue(DataType.UWORD, result) + } + "set_carry" -> { + statusflags.carry=true + null + } + "clear_carry" -> { + statusflags.carry=false + null + } + "set_irqd" -> { + statusflags.irqd=true + null + } + "clear_irqd" -> { + statusflags.irqd=false + null + } + "read_flags" -> { + val carry = if(statusflags.carry) 1 else 0 + val zero = if(statusflags.zero) 2 else 0 + val irqd = if(statusflags.irqd) 4 else 0 + val negative = if(statusflags.negative) 128 else 0 + RuntimeValue(DataType.UBYTE, carry or zero or irqd or negative) + } + "rsave" -> { + statusFlagsSave.push(statusflags) + registerAsave.push(runtimeVariables.get(program.namespace, Register.A.name)) + registerXsave.push(runtimeVariables.get(program.namespace, Register.X.name)) + registerYsave.push(runtimeVariables.get(program.namespace, Register.Y.name)) + null + } + "rrestore" -> { + val flags = statusFlagsSave.pop() + statusflags.carry = flags.carry + statusflags.negative = flags.negative + statusflags.zero = flags.zero + statusflags.irqd = flags.irqd + runtimeVariables.set(program.namespace, Register.A.name, registerAsave.pop()) + runtimeVariables.set(program.namespace, Register.X.name, registerXsave.pop()) + runtimeVariables.set(program.namespace, Register.Y.name, registerYsave.pop()) + null + } + else -> TODO("builtin function $name") + } + } + } diff --git a/compiler/src/prog8/vm/astvm/BuiltinFunctions.kt b/compiler/src/prog8/vm/astvm/BuiltinFunctions.kt deleted file mode 100644 index 2060252a5..000000000 --- a/compiler/src/prog8/vm/astvm/BuiltinFunctions.kt +++ /dev/null @@ -1,204 +0,0 @@ -package prog8.vm.astvm - -import prog8.ast.base.DataType -import prog8.vm.RuntimeValue -import java.lang.Math.toDegrees -import java.lang.Math.toRadians -import java.util.* -import kotlin.math.* -import kotlin.random.Random - - -class BuiltinFunctions { - - private val rnd = Random(0) - private val statusFlagsSave = Stack() - - - fun performBuiltinFunction(name: String, args: List, statusflags: StatusFlags): RuntimeValue? { - return when (name) { - "rnd" -> RuntimeValue(DataType.UBYTE, rnd.nextInt() and 255) - "rndw" -> RuntimeValue(DataType.UWORD, rnd.nextInt() and 65535) - "rndf" -> RuntimeValue(DataType.FLOAT, rnd.nextDouble()) - "lsb" -> RuntimeValue(DataType.UBYTE, args[0].integerValue() and 255) - "msb" -> RuntimeValue(DataType.UBYTE, (args[0].integerValue() ushr 8) and 255) - "sin" -> RuntimeValue(DataType.FLOAT, sin(args[0].numericValue().toDouble())) - "sin8" -> { - val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.BYTE, (127.0 * sin(rad)).toShort()) - } - "sin8u" -> { - val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.UBYTE, (128.0 + 127.5 * sin(rad)).toShort()) - } - "sin16" -> { - val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.BYTE, (32767.0 * sin(rad)).toShort()) - } - "sin16u" -> { - val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.UBYTE, (32768.0 + 32767.5 * sin(rad)).toShort()) - } - "cos" -> RuntimeValue(DataType.FLOAT, cos(args[0].numericValue().toDouble())) - "cos8" -> { - val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.BYTE, (127.0 * cos(rad)).toShort()) - } - "cos8u" -> { - val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.UBYTE, (128.0 + 127.5 * cos(rad)).toShort()) - } - "cos16" -> { - val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.BYTE, (32767.0 * cos(rad)).toShort()) - } - "cos16u" -> { - val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI - RuntimeValue(DataType.UBYTE, (32768.0 + 32767.5 * cos(rad)).toShort()) - } - "tan" -> RuntimeValue(DataType.FLOAT, tan(args[0].numericValue().toDouble())) - "atan" -> RuntimeValue(DataType.FLOAT, atan(args[0].numericValue().toDouble())) - "ln" -> RuntimeValue(DataType.FLOAT, ln(args[0].numericValue().toDouble())) - "log2" -> RuntimeValue(DataType.FLOAT, log2(args[0].numericValue().toDouble())) - "sqrt" -> RuntimeValue(DataType.FLOAT, sqrt(args[0].numericValue().toDouble())) - "sqrt16" -> RuntimeValue(DataType.UBYTE, sqrt(args[0].wordval!!.toDouble()).toInt()) - "rad" -> RuntimeValue(DataType.FLOAT, toRadians(args[0].numericValue().toDouble())) - "deg" -> RuntimeValue(DataType.FLOAT, toDegrees(args[0].numericValue().toDouble())) - "round" -> RuntimeValue(DataType.FLOAT, round(args[0].numericValue().toDouble())) - "floor" -> RuntimeValue(DataType.FLOAT, floor(args[0].numericValue().toDouble())) - "ceil" -> RuntimeValue(DataType.FLOAT, ceil(args[0].numericValue().toDouble())) - "rol" -> { - val (result, newCarry) = args[0].rol(statusflags.carry) - statusflags.carry = newCarry - return result - } - "rol2" -> args[0].rol2() - "ror" -> { - val (result, newCarry) = args[0].ror(statusflags.carry) - statusflags.carry = newCarry - return result - } - "ror2" -> args[0].ror2() - "lsl" -> args[0].shl() - "lsr" -> args[0].shr() - "abs" -> { - when (args[0].type) { - DataType.UBYTE -> args[0] - DataType.BYTE -> RuntimeValue(DataType.UBYTE, abs(args[0].numericValue().toDouble())) - DataType.UWORD -> args[0] - DataType.WORD -> RuntimeValue(DataType.UWORD, abs(args[0].numericValue().toDouble())) - DataType.FLOAT -> RuntimeValue(DataType.FLOAT, abs(args[0].numericValue().toDouble())) - else -> TODO("strange abs type") - } - } - "max" -> { - val numbers = args.map { it.numericValue().toDouble() } - RuntimeValue(args[0].type, numbers.max()) - } - "min" -> { - val numbers = args.map { it.numericValue().toDouble() } - RuntimeValue(args[0].type, numbers.min()) - } - "avg" -> { - val numbers = args.map { it.numericValue().toDouble() } - RuntimeValue(DataType.FLOAT, numbers.average()) - } - "sum" -> { - val sum = args.map { it.numericValue().toDouble() }.sum() - when (args[0].type) { - DataType.UBYTE -> RuntimeValue(DataType.UWORD, sum) - DataType.BYTE -> RuntimeValue(DataType.WORD, sum) - DataType.UWORD -> RuntimeValue(DataType.UWORD, sum) - DataType.WORD -> RuntimeValue(DataType.WORD, sum) - DataType.FLOAT -> RuntimeValue(DataType.FLOAT, sum) - else -> TODO("weird sum type") - } - } - "any" -> { - val numbers = args.map { it.numericValue().toDouble() } - RuntimeValue(DataType.UBYTE, if (numbers.any { it != 0.0 }) 1 else 0) - } - "all" -> { - val numbers = args.map { it.numericValue().toDouble() } - RuntimeValue(DataType.UBYTE, if (numbers.all { it != 0.0 }) 1 else 0) - } - "swap" -> - throw VmExecutionException("swap() cannot be implemented as a function") - "strlen" -> { - val zeroIndex = args[0].str!!.indexOf(0.toChar()) - if (zeroIndex >= 0) - RuntimeValue(DataType.UBYTE, zeroIndex) - else - RuntimeValue(DataType.UBYTE, args[0].str!!.length) - } - "memset" -> { - val target = args[0].array!! - val amount = args[1].integerValue() - val value = args[2].integerValue() - for (i in 0 until amount) { - target[i] = value - } - null - } - "memsetw" -> { - val target = args[0].array!! - val amount = args[1].integerValue() - val value = args[2].integerValue() - for (i in 0 until amount step 2) { - target[i * 2] = value and 255 - target[i * 2 + 1] = value ushr 8 - } - null - } - "memcopy" -> { - val source = args[0].array!! - val dest = args[1].array!! - val amount = args[2].integerValue() - for(i in 0 until amount) { - dest[i] = source[i] - } - null - } - "mkword" -> { - val result = (args[1].integerValue() shl 8) or args[0].integerValue() - RuntimeValue(DataType.UWORD, result) - } - "set_carry" -> { - statusflags.carry=true - null - } - "clear_carry" -> { - statusflags.carry=false - null - } - "set_irqd" -> { - statusflags.irqd=true - null - } - "clear_irqd" -> { - statusflags.irqd=false - null - } - "read_flags" -> { - val carry = if(statusflags.carry) 1 else 0 - val zero = if(statusflags.zero) 2 else 0 - val irqd = if(statusflags.irqd) 4 else 0 - val negative = if(statusflags.negative) 128 else 0 - RuntimeValue(DataType.UBYTE, carry or zero or irqd or negative) - } - "rsave" -> { - statusFlagsSave.push(statusflags) - null - } - "rrestore" -> { - val flags = statusFlagsSave.pop() - statusflags.carry = flags.carry - statusflags.negative = flags.negative - statusflags.zero = flags.zero - statusflags.irqd = flags.irqd - null - } - else -> TODO("builtin function $name") - } - } -} diff --git a/compiler/src/prog8/vm/astvm/Expressions.kt b/compiler/src/prog8/vm/astvm/Expressions.kt index d2eccdd0e..1afbbc66c 100644 --- a/compiler/src/prog8/vm/astvm/Expressions.kt +++ b/compiler/src/prog8/vm/astvm/Expressions.kt @@ -14,7 +14,8 @@ import prog8.vm.RuntimeValueRange import kotlin.math.abs class EvalContext(val program: Program, val mem: Memory, val statusflags: StatusFlags, - val runtimeVars: RuntimeVariables, val functions: BuiltinFunctions, + val runtimeVars: RuntimeVariables, + val performBuiltinFunction: (String, List, StatusFlags) -> RuntimeValue?, val executeSubroutine: (sub: Subroutine, args: List, startlabel: Label?) -> List) fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue { @@ -122,7 +123,7 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue { results[0] } is BuiltinFunctionStatementPlaceholder -> { - val result = ctx.functions.performBuiltinFunction(sub.name, args, ctx.statusflags) + val result = ctx.performBuiltinFunction(sub.name, args, ctx.statusflags) ?: throw VmExecutionException("expected 1 result from functioncall $expr") result } diff --git a/compiler/src/prog8/vm/stackvm/StackVm.kt b/compiler/src/prog8/vm/stackvm/StackVm.kt index c33675629..302f0c192 100644 --- a/compiler/src/prog8/vm/stackvm/StackVm.kt +++ b/compiler/src/prog8/vm/stackvm/StackVm.kt @@ -1863,8 +1863,8 @@ class StackVm(private var traceOutputFile: String?) { } Opcode.RRESTORE -> { variables["A"] = evalstack.pop() - variables["X"] = evalstack.pop() variables["Y"] = evalstack.pop() + variables["X"] = evalstack.pop() P_carry = evalstack.pop().asBoolean P_irqd = evalstack.pop().asBoolean } diff --git a/examples/test.p8 b/examples/test.p8 index d6516b9cb..13f7f63ff 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -4,14 +4,39 @@ ~ main { sub start() { - c64scr.print("you start here! --> S\n") - for A in 0 to 16 { - for Y in 0 to 39 { - if rnd() >128 c64.CHROUT(109) - else c64.CHROUT(110) - } + A=0 + Y=0 + ubyte aa =0 + + while Y<10 { + rsave() + c64scr.print_ub(Y) + c64.CHROUT(',') + rrestore() + Y++ } - c64scr.print(" x <-- try to find your way here!") + c64.CHROUT('!') + c64.CHROUT('!') + c64.CHROUT('\n') + +; repeat { +; c64scr.print_ub(A) +; c64.CHROUT(',') +; A-- +; } until A<5 +; +; c64.CHROUT('!') +; c64.CHROUT('!') +; c64.CHROUT('\n') +; +; for A in 0 to 4 { +; for Y in 0 to 3 { +; c64scr.print_ub(A) +; c64.CHROUT(',') +; c64scr.print_ub(Y) +; c64.CHROUT('\n') +; } +; } } }