fixed astvm postincrdecr and rsave/rrestore

This commit is contained in:
Irmen de Jong 2019-07-10 07:41:28 +02:00
parent 34dcce67e4
commit 20379b5927
7 changed files with 275 additions and 237 deletions

View File

@ -1552,17 +1552,19 @@ internal class Compiler(private val program: Program) {
private fun translate(loop: ForLoop) { private fun translate(loop: ForLoop) {
if(loop.body.containsNoCodeNorVars()) return if(loop.body.containsNoCodeNorVars()) return
prog.line(loop.position) prog.line(loop.position)
val loopVarName: String val loopVarName: String?
val loopVarDt: DataType val loopRegister: Register?
val loopvalueDt: DataType
if(loop.loopRegister!=null) { if(loop.loopRegister!=null) {
val reg = loop.loopRegister loopVarName = null
loopVarName = reg.name loopRegister = loop.loopRegister
loopVarDt = DataType.UBYTE loopvalueDt = DataType.UBYTE
} else { } else {
val loopvar = loop.loopVar!!.targetVarDecl(program.namespace)!! val loopvar = loop.loopVar!!.targetVarDecl(program.namespace)!!
loopVarName = loopvar.scopedname loopVarName = loopvar.scopedname
loopVarDt = loopvar.datatype loopvalueDt = loopvar.datatype
loopRegister = null
} }
if(loop.iterable is RangeExpr) { 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") throw CompilerException("loop over just 1 value should have been optimized away")
if((range.last-range.first) % range.step != 0) if((range.last-range.first) % range.step != 0)
throw CompilerException("range first and last must be exactly inclusive") throw CompilerException("range first and last must be exactly inclusive")
when (loopVarDt) { when (loopvalueDt) {
DataType.UBYTE -> { DataType.UBYTE -> {
if (range.first < 0 || range.first > 255 || range.last < 0 || range.last > 255) if (range.first < 0 || range.first > 255 || range.last < 0 || range.last > 255)
throw CompilerException("range out of bounds for ubyte") 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") else -> throw CompilerException("range must be byte or word")
} }
translateForOverConstantRange(loopVarName, loopVarDt, range, loop.body) translateForOverConstantRange(loopVarName, loopRegister, loopvalueDt, range, loop.body)
} else { } else {
// loop over a range where one or more of the start, last or step values is not a constant // loop over a range where one or more of the start, last or step values is not a constant
if(loop.loopRegister!=null) { if(loop.loopRegister!=null) {
@ -1613,7 +1615,7 @@ internal class Compiler(private val program: Program) {
val iterableValue = vardecl.value as LiteralValue val iterableValue = vardecl.value as LiteralValue
if(iterableValue.type !in IterableDatatypes) if(iterableValue.type !in IterableDatatypes)
throw CompilerException("loop over something that isn't iterable ${loop.iterable}") 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") 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}") else -> throw CompilerException("loopvar is something strange ${loop.iterable}")
@ -1706,7 +1708,7 @@ internal class Compiler(private val program: Program) {
continueStmtLabelStack.pop() 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 } * for LV in start..last { body }
* (and we already know that the range is not empty, and first and last are exactly inclusive.) * (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) breakStmtLabelStack.push(breakLabel)
prog.instr(opcodePush(varDt), RuntimeValue(varDt, range.first)) 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) prog.label(loopLabel)
translate(body) translate(body)
prog.label(continueLabel) prog.label(continueLabel)
@ -1742,25 +1746,25 @@ internal class Compiler(private val program: Program) {
when { when {
range.step in 1..numberOfIncDecsForOptimize -> { range.step in 1..numberOfIncDecsForOptimize -> {
repeat(range.step) { repeat(range.step) {
prog.instr(opcodeIncvar(varDt), callLabel = varname) prog.instr(opcodeIncvar(varDt), callLabel = variableLabel)
} }
} }
range.step in -1 downTo -numberOfIncDecsForOptimize -> { range.step in -1 downTo -numberOfIncDecsForOptimize -> {
repeat(abs(range.step)) { repeat(abs(range.step)) {
prog.instr(opcodeDecvar(varDt), callLabel = varname) prog.instr(opcodeDecvar(varDt), callLabel = variableLabel)
} }
} }
range.step>numberOfIncDecsForOptimize -> { 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(opcodePush(varDt), RuntimeValue(varDt, range.step))
prog.instr(opcodeAdd(varDt)) prog.instr(opcodeAdd(varDt))
prog.instr(opcodePopvar(varDt), callLabel = varname) prog.instr(opcodePopvar(varDt), callLabel = variableLabel)
} }
range.step<numberOfIncDecsForOptimize -> { range.step<numberOfIncDecsForOptimize -> {
prog.instr(opcodePushvar(varDt), callLabel = varname) prog.instr(opcodePushvar(varDt), callLabel = variableLabel)
prog.instr(opcodePush(varDt), RuntimeValue(varDt, abs(range.step))) prog.instr(opcodePush(varDt), RuntimeValue(varDt, abs(range.step)))
prog.instr(opcodeSub(varDt)) 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 // optimize for the for loop that counts to 0
prog.instr(if(range.first>0) Opcode.BPOS else Opcode.BNEG, callLabel = loopLabel) prog.instr(if(range.first>0) Opcode.BPOS else Opcode.BNEG, callLabel = loopLabel)
} else { } else {
prog.instr(opcodePushvar(varDt), callLabel = varname) prog.instr(opcodePushvar(varDt), callLabel = variableLabel)
val checkValue = val checkValue =
when (varDt) { when (varDt) {
DataType.UBYTE -> (range.last + range.step) and 255 DataType.UBYTE -> (range.last + range.step) and 255

View File

@ -88,7 +88,7 @@ fun compileProgram(filepath: Path,
programAst.checkValid(compilerOptions) // check if final tree is valid programAst.checkValid(compilerOptions) // check if final tree is valid
programAst.checkRecursion() // check if there are recursive subroutine calls programAst.checkRecursion() // check if there are recursive subroutine calls
// printAst(programAst) printAst(programAst)
// namespace.debugPrint() // namespace.debugPrint()
if(generateVmCode) { if(generateVmCode) {

View File

@ -10,9 +10,11 @@ import prog8.vm.RuntimeValue
import prog8.vm.RuntimeValueRange import prog8.vm.RuntimeValueRange
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.c64.Petscii
import java.awt.EventQueue import java.awt.EventQueue
import java.util.*
import kotlin.NoSuchElementException import kotlin.NoSuchElementException
import kotlin.concurrent.fixedRateTimer import kotlin.concurrent.fixedRateTimer
import kotlin.math.min import kotlin.math.*
import kotlin.random.Random
class VmExecutionException(msg: String?) : Exception(msg) class VmExecutionException(msg: String?) : Exception(msg)
@ -128,6 +130,13 @@ class AstVm(val program: Program) {
val bootTime = System.currentTimeMillis() val bootTime = System.currentTimeMillis()
var rtcOffset = bootTime var rtcOffset = bootTime
private val rnd = Random(0)
private val statusFlagsSave = Stack<StatusFlags>()
private val registerXsave = Stack<RuntimeValue>()
private val registerYsave = Stack<RuntimeValue>()
private val registerAsave = Stack<RuntimeValue>()
init { init {
// observe the jiffyclock // observe the jiffyclock
mem.observe(0xa0, 0xa1, 0xa2) mem.observe(0xa0, 0xa1, 0xa2)
@ -236,8 +245,7 @@ class AstVm(val program: Program) {
} }
private val runtimeVariables = RuntimeVariables() private val runtimeVariables = RuntimeVariables()
private val functions = BuiltinFunctions() private val evalCtx = EvalContext(program, mem, statusflags, runtimeVariables, ::performBuiltinFunction, ::executeSubroutine)
private val evalCtx = EvalContext(program, mem, statusflags, runtimeVariables, functions, ::executeSubroutine)
class LoopControlBreak : Exception() class LoopControlBreak : Exception()
class LoopControlContinue : Exception() class LoopControlContinue : Exception()
@ -324,7 +332,7 @@ class AstVm(val program: Program) {
executeSwap(stmt) executeSwap(stmt)
} else { } else {
val args = evaluate(stmt.arglist) val args = evaluate(stmt.arglist)
functions.performBuiltinFunction(target.name, args, statusflags) performBuiltinFunction(target.name, args, statusflags)
} }
} }
else -> { else -> {
@ -363,6 +371,16 @@ class AstVm(val program: Program) {
stmt.target.arrayindexed != null -> { stmt.target.arrayindexed != null -> {
TODO("postincrdecr array $stmt") 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) 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") else -> TODO("syscall ${sub.scopedname} $sub")
} }
} }
private fun performBuiltinFunction(name: String, args: List<RuntimeValue>, 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")
}
}
} }

View File

@ -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<StatusFlags>()
fun performBuiltinFunction(name: String, args: List<RuntimeValue>, 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")
}
}
}

View File

@ -14,7 +14,8 @@ import prog8.vm.RuntimeValueRange
import kotlin.math.abs import kotlin.math.abs
class EvalContext(val program: Program, val mem: Memory, val statusflags: StatusFlags, class EvalContext(val program: Program, val mem: Memory, val statusflags: StatusFlags,
val runtimeVars: RuntimeVariables, val functions: BuiltinFunctions, val runtimeVars: RuntimeVariables,
val performBuiltinFunction: (String, List<RuntimeValue>, StatusFlags) -> RuntimeValue?,
val executeSubroutine: (sub: Subroutine, args: List<RuntimeValue>, startlabel: Label?) -> List<RuntimeValue>) val executeSubroutine: (sub: Subroutine, args: List<RuntimeValue>, startlabel: Label?) -> List<RuntimeValue>)
fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue { fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
@ -122,7 +123,7 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
results[0] results[0]
} }
is BuiltinFunctionStatementPlaceholder -> { 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") ?: throw VmExecutionException("expected 1 result from functioncall $expr")
result result
} }

View File

@ -1863,8 +1863,8 @@ class StackVm(private var traceOutputFile: String?) {
} }
Opcode.RRESTORE -> { Opcode.RRESTORE -> {
variables["A"] = evalstack.pop() variables["A"] = evalstack.pop()
variables["X"] = evalstack.pop()
variables["Y"] = evalstack.pop() variables["Y"] = evalstack.pop()
variables["X"] = evalstack.pop()
P_carry = evalstack.pop().asBoolean P_carry = evalstack.pop().asBoolean
P_irqd = evalstack.pop().asBoolean P_irqd = evalstack.pop().asBoolean
} }

View File

@ -4,14 +4,39 @@
~ main { ~ main {
sub start() { sub start() {
c64scr.print("you start here! --> S\n") A=0
for A in 0 to 16 { Y=0
for Y in 0 to 39 { ubyte aa =0
if rnd() >128 c64.CHROUT(109)
else c64.CHROUT(110) 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')
; }
; }
} }
} }