mirror of
https://github.com/irmen/prog8.git
synced 2024-11-29 17:50:35 +00:00
fixed astvm postincrdecr and rsave/rrestore
This commit is contained in:
parent
34dcce67e4
commit
20379b5927
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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')
|
||||||
|
; }
|
||||||
|
; }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user