From 595e58ec46c161643e6d3eb78f356af9effba378 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 26 Jun 2019 03:28:34 +0200 Subject: [PATCH] taking care of memory mapped vars --- compiler/build.gradle | 1 + compiler/src/prog8/astvm/AstVm.kt | 53 +++++++++++++++----- compiler/src/prog8/astvm/Expressions.kt | 43 ++++++++++++---- compiler/src/prog8/astvm/Memory.kt | 20 ++++++++ compiler/src/prog8/astvm/VariablesCreator.kt | 7 ++- compiler/src/prog8/compiler/RuntimeValue.kt | 2 +- examples/test.p8 | 16 +++--- 7 files changed, 107 insertions(+), 35 deletions(-) diff --git a/compiler/build.gradle b/compiler/build.gradle index 31a466a64..55b310638 100644 --- a/compiler/build.gradle +++ b/compiler/build.gradle @@ -29,6 +29,7 @@ dependencies { compileKotlin { kotlinOptions { jvmTarget = "1.8" + // freeCompilerArgs += "-XXLanguage:+NewInference" } } diff --git a/compiler/src/prog8/astvm/AstVm.kt b/compiler/src/prog8/astvm/AstVm.kt index a724a3e58..eaba1afb6 100644 --- a/compiler/src/prog8/astvm/AstVm.kt +++ b/compiler/src/prog8/astvm/AstVm.kt @@ -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>().withDefault { mutableMapOf() } + private val memvars = mutableMapOf>().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): List = args.map { - evaluate(it, EvalContext(program, runtimeVariables, functions, ::executeSubroutine)) + evaluate(it, EvalContext(program, mem, runtimeVariables, functions, ::executeSubroutine)) } private fun performSyscall(sub: Subroutine, args: List) { diff --git a/compiler/src/prog8/astvm/Expressions.kt b/compiler/src/prog8/astvm/Expressions.kt index dd9649f34..1e085f1d8 100644 --- a/compiler/src/prog8/astvm/Expressions.kt +++ b/compiler/src/prog8/astvm/Expressions.kt @@ -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) -> List) 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") } diff --git a/compiler/src/prog8/astvm/Memory.kt b/compiler/src/prog8/astvm/Memory.kt index b6050b315..9aeaa0cce 100644 --- a/compiler/src/prog8/astvm/Memory.kt +++ b/compiler/src/prog8/astvm/Memory.kt @@ -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() + 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 + } } diff --git a/compiler/src/prog8/astvm/VariablesCreator.kt b/compiler/src/prog8/astvm/VariablesCreator.kt index d9752d026..c0ee2bb78 100644 --- a/compiler/src/prog8/astvm/VariablesCreator.kt +++ b/compiler/src/prog8/astvm/VariablesCreator.kt @@ -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 diff --git a/compiler/src/prog8/compiler/RuntimeValue.kt b/compiler/src/prog8/compiler/RuntimeValue.kt index 901641cfc..65364fcf9 100644 --- a/compiler/src/prog8/compiler/RuntimeValue.kt +++ b/compiler/src/prog8/compiler/RuntimeValue.kt @@ -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() diff --git a/examples/test.p8 b/examples/test.p8 index cc12662e2..d36309ba2 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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') - } }