taking care of memory mapped vars

This commit is contained in:
Irmen de Jong 2019-06-26 03:28:34 +02:00
parent 060e05c868
commit 595e58ec46
7 changed files with 107 additions and 35 deletions

View File

@ -29,6 +29,7 @@ dependencies {
compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
// freeCompilerArgs += "-XXLanguage:+NewInference"
}
}

View File

@ -21,9 +21,20 @@ class RuntimeVariables {
vars[scope] = where
}
fun defineMemory(scope: INameScope, name: String, address: Int) {
val where = memvars.getValue(scope)
where[name] = address
memvars[scope] = where
}
fun set(scope: INameScope, name: String, value: RuntimeValue) {
val where = vars.getValue(scope)
val existing = where[name] ?: throw NoSuchElementException("no such runtime variable: ${scope.name}.$name")
val existing = where[name]
if(existing==null) {
if(memvars.getValue(scope)[name]!=null)
throw NoSuchElementException("this is a memory mapped var, not a normal var: ${scope.name}.$name")
throw NoSuchElementException("no such runtime variable: ${scope.name}.$name")
}
if(existing.type!=value.type)
throw VmExecutionException("new value is of different datatype ${value.type} expected ${existing.type} for $name")
where[name] = value
@ -32,13 +43,18 @@ class RuntimeVariables {
fun get(scope: INameScope, name: String): RuntimeValue {
val where = vars.getValue(scope)
val value = where[name]
if(value!=null)
return value
throw NoSuchElementException("no such runtime variable: ${scope.name}.$name")
val value = where[name] ?: throw NoSuchElementException("no such runtime variable: ${scope.name}.$name")
return value
}
fun getMemoryAddress(scope: INameScope, name: String): Int {
val where = memvars.getValue(scope)
val address = where[name] ?: throw NoSuchElementException("no such runtime memory-variable: ${scope.name}.$name")
return address
}
private val vars = mutableMapOf<INameScope, MutableMap<String, RuntimeValue>>().withDefault { mutableMapOf() }
private val memvars = mutableMapOf<INameScope, MutableMap<String, Int>>().withDefault { mutableMapOf() }
}
@ -133,7 +149,7 @@ class AstVm(val program: Program) {
}
private fun executeStatement(sub: INameScope, stmt: IStatement) {
val evalCtx = EvalContext(program, runtimeVariables, functions, ::executeSubroutine)
val evalCtx = EvalContext(program, mem, runtimeVariables, functions, ::executeSubroutine)
instructionCounter++
if(instructionCounter % 100 == 0)
Thread.sleep(1)
@ -185,10 +201,22 @@ class AstVm(val program: Program) {
val value = evaluate(stmt.value, evalCtx)
when {
target.identifier!=null -> {
val ident = stmt.definingScope().lookup(target.identifier.nameInSource, stmt) as? VarDecl
val decl = stmt.definingScope().lookup(target.identifier.nameInSource, stmt) as? VarDecl
?: throw VmExecutionException("can't find assignment target ${target.identifier}")
val identScope = ident.definingScope()
runtimeVariables.set(identScope, ident.name, value)
if(decl.type==VarDeclType.MEMORY) {
val address = runtimeVariables.getMemoryAddress(decl.definingScope(), decl.name)
when(decl.datatype) {
DataType.UBYTE -> mem.setUByte(address, value.byteval!!)
DataType.BYTE -> mem.setSByte(address, value.byteval!!)
DataType.UWORD -> mem.setUWord(address, value.wordval!!)
DataType.WORD -> mem.setSWord(address, value.wordval!!)
DataType.FLOAT -> mem.setFloat(address, value.floatval!!)
DataType.STR -> mem.setString(address, value.str!!)
DataType.STR_S -> mem.setScreencodeString(address, value.str!!)
else -> TODO("set memvar $decl")
}
} else
runtimeVariables.set(decl.definingScope(), decl.name, value)
}
target.memoryAddress!=null -> {
TODO("assign memory $stmt")
@ -196,7 +224,6 @@ class AstVm(val program: Program) {
target.arrayindexed!=null -> {
val array = evaluate(target.arrayindexed.identifier, evalCtx)
val index = evaluate(target.arrayindexed.arrayspec.index, evalCtx)
val value = evaluate(stmt.value, evalCtx)
when(array.type) {
DataType.ARRAY_UB -> {
if(value.type!=DataType.UBYTE)
@ -227,9 +254,9 @@ class AstVm(val program: Program) {
if(array.type in ArrayDatatypes)
array.array!![index.integerValue()] = value.numericValue()
else if(array.type in StringDatatypes) {
val index = index.integerValue()
val indexInt = index.integerValue()
val newchr = Petscii.decodePetscii(listOf(value.numericValue().toShort()), true)
val newstr = array.str!!.replaceRange(index, index+1, newchr)
val newstr = array.str!!.replaceRange(indexInt, indexInt+1, newchr)
val ident = stmt.definingScope().lookup(target.arrayindexed.identifier.nameInSource, stmt) as? VarDecl
?: throw VmExecutionException("can't find assignment target ${target.identifier}")
val identScope = ident.definingScope()
@ -367,7 +394,7 @@ class AstVm(val program: Program) {
}
private fun evaluate(args: List<IExpression>): List<RuntimeValue> = args.map {
evaluate(it, EvalContext(program, runtimeVariables, functions, ::executeSubroutine))
evaluate(it, EvalContext(program, mem, runtimeVariables, functions, ::executeSubroutine))
}
private fun performSyscall(sub: Subroutine, args: List<RuntimeValue>) {

View File

@ -5,8 +5,8 @@ import prog8.compiler.RuntimeValue
import prog8.compiler.RuntimeValueRange
import kotlin.math.abs
class EvalContext(val program: Program, val runtimeVars: RuntimeVariables,
val functions: BuiltinFunctions,
class EvalContext(val program: Program, val mem: Memory,
val runtimeVars: RuntimeVariables, val functions: BuiltinFunctions,
val executeSubroutine: (sub: Subroutine, args: List<RuntimeValue>) -> List<RuntimeValue>)
fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
@ -31,14 +31,24 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
">=" -> RuntimeValue(DataType.UBYTE, if (left >= right) 1 else 0)
"==" -> RuntimeValue(DataType.UBYTE, if (left == right) 1 else 0)
"!=" -> RuntimeValue(DataType.UBYTE, if (left != right) 1 else 0)
"+" -> {
val result = left.add(right)
RuntimeValue(result.type, result.numericValue())
"+" -> left.add(right)
"-" -> left.sub(right)
"*" -> left.mul(right)
"/" -> left.div(right)
"<<" -> {
var result = left
repeat(right.integerValue()) {result = result.shl()}
result
}
"-" -> {
val result = left.sub(right)
RuntimeValue(result.type, result.numericValue())
">>" -> {
var result = left
repeat(right.integerValue()) {result = result.shr()}
result
}
"%" -> left.remainder(right)
"|" -> left.or(right)
"&" -> left.and(right)
"^" -> left.xor(right)
else -> TODO("binexpression operator ${expr.operator}")
}
}
@ -74,8 +84,21 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
val scope = expr.definingScope()
val variable = scope.lookup(expr.nameInSource, expr)
if(variable is VarDecl) {
val stmt = scope.lookup(listOf(variable.name), expr)!!
return ctx.runtimeVars.get(stmt.definingScope(), variable.name)
if(variable.type==VarDeclType.VAR)
return ctx.runtimeVars.get(variable.definingScope(), variable.name)
else {
val address = ctx.runtimeVars.getMemoryAddress(variable.definingScope(), variable.name)
return when(variable.datatype) {
DataType.UBYTE -> RuntimeValue(DataType.UBYTE, ctx.mem.getUByte(address))
DataType.BYTE -> RuntimeValue(DataType.BYTE, ctx.mem.getSByte(address))
DataType.UWORD -> RuntimeValue(DataType.UWORD, ctx.mem.getUWord(address))
DataType.WORD -> RuntimeValue(DataType.WORD, ctx.mem.getSWord(address))
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, ctx.mem.getFloat(address))
DataType.STR -> RuntimeValue(DataType.STR, str=ctx.mem.getString(address))
DataType.STR_S -> RuntimeValue(DataType.STR_S, str=ctx.mem.getScreencodeString(address))
else -> TODO("memvar $variable")
}
}
} else
TODO("weird ref $variable")
}

View File

@ -99,4 +99,24 @@ class Memory {
for(i in 0 until numbytes)
mem[to+i] = mem[from+i]
}
fun getScreencodeString(strAddress: Int): String? {
// lowercase Screencodes
val screencodes = mutableListOf<Short>()
var addr = strAddress
while(true) {
val byte = mem[addr++]
if(byte==0.toShort()) break
screencodes.add(byte)
}
return Petscii.decodeScreencode(screencodes, true)
}
fun setScreencodeString(address: Int, str: String) {
// lowercase screencodes
val screencodes = Petscii.encodeScreencode(str, true)
var addr = address
for (c in screencodes) mem[addr++] = c
mem[addr] = 0
}
}

View File

@ -49,7 +49,12 @@ class VariablesCreator(private val runtimeVariables: RuntimeVariables, private v
runtimeVariables.define(decl.definingScope(), decl.name, value)
}
VarDeclType.MEMORY -> {
// TODO register memory mapped vars?
if(decl.value !is LiteralValue) {
TODO("evaluate vardecl expression $decl")
//RuntimeValue(decl.datatype, num = evaluate(decl.value!!, program, runtimeVariables, executeSubroutine).numericValue())
} else {
runtimeVariables.defineMemory(decl.definingScope(), decl.name, (decl.value as LiteralValue).asIntegerValue!!)
}
}
VarDeclType.CONST -> {
// consts should have been const-folded away

View File

@ -236,7 +236,7 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?=
}
}
fun remainder(other: RuntimeValue): RuntimeValue? {
fun remainder(other: RuntimeValue): RuntimeValue {
val v1 = numericValue()
val v2 = other.numericValue()
val result = v1.toDouble() % v2.toDouble()

View File

@ -6,20 +6,16 @@
~ main {
sub start() {
uword uw = $ab34
str name = "irmen de jong"
ubyte u1 = 100
ubyte u2 = 30
c64scr.print_ub(len(name))
c64scr.print_ub(u1 % u2)
c64.CHROUT('\n')
c64scr.print_ub(strlen(name))
c64scr.print_ub(u1 / u2)
c64.CHROUT('\n')
c64scr.print(name)
c64scr.print_ub(u2 * 2)
c64.CHROUT('\n')
name[6] = 0
c64scr.print_ub(strlen(name))
c64scr.print_ub(u2 * 7)
c64.CHROUT('\n')
c64scr.print(name)
c64.CHROUT('\n')
}
}