diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index c0e211cee..3c9fefdbf 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -27,31 +27,34 @@ sub start() { ; } - float[10] farr - float f = 3.3 - memory float mflt = $c000 - memory float[10] mfarr = $d000 - ubyte i=3 - - mflt = 55.44 ; @todo fix memory variables for stackvm???! (or proper error) - mfarr[2] = 44.44 ; @todo fix memory variables for stackvm???! (or proper error) - - farr[2] = 4.44 - farr[2] = f - farr[2] = mflt - farr[2] = farr[3] - farr[2] = mfarr[3] - farr[Y] = 4.44 - farr[Y] = f - farr[Y] = mflt - farr[Y] = farr[3] - farr[Y] = mfarr[3] - farr[i] = 4.44 - farr[i] = f - farr[i] = mflt - farr[i] = farr[3] - farr[i] = mfarr[3] + ubyte bv = 99 + word wv = 14443 + float fv = 3.14 + memory ubyte mb = $c000 + memory word mw = $c100 + memory float mf = $c200 + memory ubyte[10] mba = $d000 + memory word[10] mwa = $d100 + memory float[10] mfa = $d200 + memory str mstr = $d300 + memory str_p mstrp = $d300 + memory str_s mstrs = $d300 + memory str_ps mstrps = $d300 + mb = 5 + mb = Y + mb = bv + mw = 22334 + mw = wv + mf = 4.45 + mf = fv + mba[9] = 5 + mba[9] = Y + mba[9] = bv + mwa[9] = 22334 + mwa[9] = wv + mfa[9] = 5.667 + mfa[9] = fv return } diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index 75aa6616d..0436fb35b 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -755,7 +755,7 @@ class AstChecker(private val namespace: INameScope, // check out of bounds val index = (arrayIndexedExpression.arrayspec.x as? LiteralValue)?.asIntegerValue if(index!=null && (index<0 || index>=arraysize)) - checkResult.add(ExpressionError("arrayspec index out of bounds", arrayIndexedExpression.arrayspec.position)) + checkResult.add(ExpressionError("array index out of bounds", arrayIndexedExpression.arrayspec.position)) } else if(target.datatype in StringDatatypes) { // check string lengths val heapId = (target.value as LiteralValue).heapId!! @@ -896,9 +896,9 @@ class AstChecker(private val namespace: INameScope, return err("initializer arrayspec size mismatch (expecting $expectedSize, got $arraySize)") return true } - return err("invalid byte arrayspec size, must be 1-256") + return err("invalid byte array size, must be 1-256") } - return err("invalid byte arrayspec initialization value ${value.type}, expected $targetDt") + return err("invalid byte array initialization value ${value.type}, expected $targetDt") } DataType.ARRAY_UW, DataType.ARRAY_W -> { // value may be either a single word, or a word arrayspec diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index c7133a62e..e282353c0 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -177,7 +177,7 @@ private class StatementTranslator(private val prog: IntermediateProgram, if(subroutine.isNotEmpty()) throw CompilerException("kernel subroutines (with memory address) can't have a body: $subroutine") - prog.symbolDef(subroutine.scopedname, subroutine.asmAddress) + prog.memoryPointer(subroutine.scopedname, subroutine.asmAddress, DataType.UBYTE) // the datatype is a bit of a dummy in this case } return super.process(subroutine) } @@ -555,9 +555,7 @@ private class StatementTranslator(private val prog: IntermediateProgram, } is IdentifierReference -> translate(expr) is ArrayIndexedExpression -> translate(expr, false) - is RangeExpr -> { - TODO("TRANSLATE range $expr") - } + is RangeExpr -> throw CompilerException("it's not possible to just have a range expression that has to be translated") else -> { val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr") when(lv.type) { @@ -800,59 +798,68 @@ private class StatementTranslator(private val prog: IntermediateProgram, val valueA: IExpression val valueX: IExpression val paramDt = arg.first.resultingDatatype(namespace, heap) - if(paramDt==DataType.UBYTE) { - valueA=arg.first - valueX=LiteralValue.optimalInteger(0, callPosition) - val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, callPosition)), null, valueA, callPosition) - val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, callPosition)), null, valueX, callPosition) - assignA.linkParents(arguments[0].parent) - assignX.linkParents(arguments[0].parent) - translate(assignA) - translate(assignX) - } else if(paramDt==DataType.UWORD) { - translate(arg.first) - prog.instr(Opcode.POP_REGAX_WORD) - } else - TODO("pass parameter of type $paramDt in registers ${arg.second.registerOrPair}") + when (paramDt) { + DataType.UBYTE -> { + valueA=arg.first + valueX=LiteralValue.optimalInteger(0, callPosition) + val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, callPosition)), null, valueA, callPosition) + val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, callPosition)), null, valueX, callPosition) + assignA.linkParents(arguments[0].parent) + assignX.linkParents(arguments[0].parent) + translate(assignA) + translate(assignX) + } + DataType.UWORD -> { + translate(arg.first) + prog.instr(Opcode.POP_REGAX_WORD) + } + else -> TODO("pass parameter of type $paramDt in registers ${arg.second.registerOrPair}") + } } AY -> { val valueA: IExpression val valueY: IExpression val paramDt = arg.first.resultingDatatype(namespace, heap) - if(paramDt==DataType.UBYTE) { - valueA=arg.first - valueY=LiteralValue.optimalInteger(0, callPosition) - val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, callPosition)), null, valueA, callPosition) - val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, callPosition)), null, valueY, callPosition) - assignA.linkParents(arguments[0].parent) - assignY.linkParents(arguments[0].parent) - translate(assignA) - translate(assignY) - } else if(paramDt==DataType.UWORD) { - translate(arg.first) - prog.instr(Opcode.POP_REGAY_WORD) - } else - TODO("pass parameter of type $paramDt in registers ${arg.second.registerOrPair}") + when (paramDt) { + DataType.UBYTE -> { + valueA=arg.first + valueY=LiteralValue.optimalInteger(0, callPosition) + val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, callPosition)), null, valueA, callPosition) + val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, callPosition)), null, valueY, callPosition) + assignA.linkParents(arguments[0].parent) + assignY.linkParents(arguments[0].parent) + translate(assignA) + translate(assignY) + } + DataType.UWORD -> { + translate(arg.first) + prog.instr(Opcode.POP_REGAY_WORD) + } + else -> TODO("pass parameter of type $paramDt in registers ${arg.second.registerOrPair}") + } } XY -> { // TODO: save X on stack & restore after call val valueX: IExpression val valueY: IExpression val paramDt = arg.first.resultingDatatype(namespace, heap) - if(paramDt==DataType.UBYTE) { - valueX=arg.first - valueY=LiteralValue.optimalInteger(0, callPosition) - val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, callPosition)), null, valueX, callPosition) - val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, callPosition)), null, valueY, callPosition) - assignX.linkParents(arguments[0].parent) - assignY.linkParents(arguments[0].parent) - translate(assignX) - translate(assignY) - } else if(paramDt==DataType.UWORD) { - translate(arg.first) - prog.instr(Opcode.POP_REGXY_WORD) - } else - TODO("pass parameter of type $paramDt in registers ${arg.second.registerOrPair}") + when (paramDt) { + DataType.UBYTE -> { + valueX=arg.first + valueY=LiteralValue.optimalInteger(0, callPosition) + val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, callPosition)), null, valueX, callPosition) + val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, callPosition)), null, valueY, callPosition) + assignX.linkParents(arguments[0].parent) + assignY.linkParents(arguments[0].parent) + translate(assignX) + translate(assignY) + } + DataType.UWORD -> { + translate(arg.first) + prog.instr(Opcode.POP_REGXY_WORD) + } + else -> TODO("pass parameter of type $paramDt in registers ${arg.second.registerOrPair}") + } } } } @@ -1226,7 +1233,6 @@ private class StatementTranslator(private val prog: IntermediateProgram, else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") } } - // todo: maybe if you assign byte or word to arrayspec, clear it with that value? DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") null -> throw CompilerException("could not determine targetdt") @@ -1793,7 +1799,7 @@ private class StatementTranslator(private val prog: IntermediateProgram, val postIncr = PostIncrDecr(makeAssignmentTarget(), "--", range.position) postIncr.linkParents(range.parent) translate(postIncr) - TODO("signed numbers and/or special condition are needed for decreasing for loop. Try an increasing loop and/or constant loop values instead? At: ${range.position}") + TODO("signed numbers and/or special condition are needed for decreasing for loop. Try an increasing loop and/or constant loop values instead? At: ${range.position}") // fix with signed numbers } else -> { TODO("non-literal-const or other-than-one step increment code At: ${range.position}") diff --git a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt index fe969d016..67aa70a44 100644 --- a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt +++ b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt @@ -13,7 +13,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap var address: Int?, val instructions: MutableList = mutableListOf(), val variables: MutableMap = mutableMapOf(), - val integerConstants: MutableMap = mutableMapOf(), + val memoryPointers: MutableMap> = mutableMapOf(), val labels: MutableMap = mutableMapOf()) { val numVariables: Int @@ -276,7 +276,10 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap } VarDeclType.CONST -> {} // constants are all folded away VarDeclType.MEMORY -> { - currentBlock.integerConstants[scopedname] = (decl.value as LiteralValue).asIntegerValue!! + val lv = decl.value as LiteralValue + if(lv.type!=DataType.UWORD && lv.type!=DataType.UBYTE) + throw CompilerException("expected integer memory address $lv") + currentBlock.memoryPointers[scopedname] = Pair(lv.asIntegerValue!!, decl.datatype) } } } @@ -299,8 +302,8 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap currentBlock.instructions.removeAt(currentBlock.instructions.lastIndex) } - fun symbolDef(name: String, value: Int) { - currentBlock.integerConstants[name] = value + fun memoryPointer(name: String, address: Int, datatype: DataType) { + currentBlock.memoryPointers[name] = Pair(address, datatype) } fun newBlock(scopedname: String, shortname: String, address: Int?) { @@ -337,6 +340,11 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap out.println("${variable.key} ${variable.value.type.toString().toLowerCase()} $valuestr") } out.println("%end_variables") + out.println("%memorypointers") + for(iconst in blk.memoryPointers) { + out.println("${iconst.key} ${iconst.value.second.toString().toLowerCase()} uw:${iconst.value.first.toString(16)}") + } + out.println("%end_memorypointers") out.println("%instructions") val labels = blk.labels.entries.associateBy({it.value}) {it.key} for(instr in blk.instructions) { diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index bf8638a18..201fa64e4 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -42,7 +42,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, callLabel2 = if (it.callLabel2 != null) symname(it.callLabel2, block) else null) } }.toMutableList() - val newConstants = block.integerConstants.map { symname(it.key, block) to it.value }.toMap().toMutableMap() + val newConstants = block.memoryPointers.map { symname(it.key, block) to it.value }.toMap().toMutableMap() newblocks.add(IntermediateProgram.ProgramBlock( block.scopedname, block.shortname, @@ -216,8 +216,8 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } private fun memdefs2asm(block: IntermediateProgram.ProgramBlock) { - for(m in block.integerConstants) { - out("\t${m.key} = ${m.value.toHex()}") + for(m in block.memoryPointers) { + out("\t${m.key} = ${m.value.first.toHex()}") } } @@ -473,10 +473,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } Opcode.READ_INDEXED_VAR_BYTE -> { - TODO("$ins") + TODO("$ins") // byte[i] } Opcode.READ_INDEXED_VAR_WORD -> { - TODO("$ins") + TODO("$ins") // word[i] } Opcode.READ_INDEXED_VAR_FLOAT -> { """ @@ -486,10 +486,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, """ } Opcode.WRITE_INDEXED_VAR_BYTE -> { - TODO("$ins") + TODO("$ins") // byte[i]=... } Opcode.WRITE_INDEXED_VAR_WORD -> { - TODO("$ins") + TODO("$ins") // word[i]=... } Opcode.WRITE_INDEXED_VAR_FLOAT -> { """ diff --git a/compiler/src/prog8/stackvm/Program.kt b/compiler/src/prog8/stackvm/Program.kt index a1defb2cc..311843dcf 100644 --- a/compiler/src/prog8/stackvm/Program.kt +++ b/compiler/src/prog8/stackvm/Program.kt @@ -10,6 +10,7 @@ import java.util.regex.Pattern class Program (val name: String, val program: MutableList, val variables: Map, + val memoryPointers: Map>, val labels: Map, val memory: Map>, val heap: HeapValues) @@ -29,6 +30,7 @@ class Program (val name: String, val heap = HeapValues() val program = mutableListOf() val variables = mutableMapOf() + val memoryPointers = mutableMapOf>() val labels = mutableMapOf() while(lines.hasNext()) { @@ -40,16 +42,17 @@ class Program (val name: String, else if(line=="%heap") loadHeap(lines, heap) else if(line.startsWith("%block ")) - loadBlock(lines, heap, program, variables, labels) + loadBlock(lines, heap, program, variables, memoryPointers, labels) else throw VmExecutionException("syntax error at line ${lineNr + 1}") } - return Program(filename, program, variables, labels, memory, heap) + return Program(filename, program, variables, memoryPointers, labels, memory, heap) } private fun loadBlock(lines: Iterator>, heap: HeapValues, program: MutableList, variables: MutableMap, + memoryPointers: MutableMap>, labels: MutableMap) { while(true) { @@ -60,6 +63,8 @@ class Program (val name: String, return else if(line=="%variables") loadVars(lines, variables) + else if(line=="%memorypointers") + loadMemoryPointers(lines, memoryPointers, heap) else if(line=="%instructions") { val (blockInstructions, blockLabels) = loadInstructions(lines, heap) program.addAll(blockInstructions) @@ -177,12 +182,12 @@ class Program (val name: String, } private fun loadVars(lines: Iterator>, - vars: MutableMap): Map { + vars: MutableMap) { val splitpattern = Pattern.compile("\\s+") while(true) { val (_, line) = lines.next() if(line=="%end_variables") - return vars + return val (name, typeStr, valueStr) = line.split(splitpattern, limit = 3) if(valueStr[0] !='"' && ':' !in valueStr) throw VmExecutionException("missing value type character") @@ -220,6 +225,23 @@ class Program (val name: String, } } + private fun loadMemoryPointers(lines: Iterator>, + pointers: MutableMap>, + heap: HeapValues) { + val splitpattern = Pattern.compile("\\s+") + while(true) { + val (_, line) = lines.next() + if(line=="%end_memorypointers") + return + val (name, typeStr, valueStr) = line.split(splitpattern, limit = 3) + if(valueStr[0] !='"' && ':' !in valueStr) + throw VmExecutionException("missing value type character") + val type = DataType.valueOf(typeStr.toUpperCase()) + val value = getArgValue(valueStr, heap)!!.integerValue() + pointers[name] = Pair(value, type) + } + } + private fun loadMemory(lines: Iterator>, memory: MutableMap>): Map> { while(true) { val (lineNr, line) = lines.next() diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 6e31e54df..480521384 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -104,6 +104,8 @@ class StackVm(private var traceOutputFile: String?) { private set var variables = mutableMapOf() // all variables (set of all vars used by all blocks/subroutines) key = their fully scoped name private set + var memoryPointers = mutableMapOf>() // all named pointers + private set var evalstack = MyStack() private set var callstack = MyStack() @@ -125,6 +127,7 @@ class StackVm(private var traceOutputFile: String?) { this.canvas = canvas canvas?.requestFocusInWindow() variables = program.variables.toMutableMap() + memoryPointers = program.memoryPointers.toMutableMap() if("A" in variables || "X" in variables || "Y" in variables) throw VmExecutionException("program contains variable(s) for the reserved registers A/X/Y") @@ -218,6 +221,15 @@ class StackVm(private var traceOutputFile: String?) { } + private fun getVar(name: String): Value { + val result = variables[name] + if(result!=null) + return result + if(name in memoryPointers) + throw VmExecutionException("variable is memory-mapped: $name = ${memoryPointers[name]}") + throw VmExecutionException("unknown variable: $name") + } + private fun dispatch(ins: Instruction) : Instruction { traceOutput?.println("\n$ins") when (ins.opcode) { @@ -749,17 +761,17 @@ class StackVm(private var traceOutputFile: String?) { return callstack.pop() } Opcode.PUSH_VAR_BYTE -> { - val value = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val value = getVar(ins.callLabel!!) checkDt(value, DataType.UBYTE, DataType.BYTE) evalstack.push(value) } Opcode.PUSH_VAR_WORD -> { - val value = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val value = getVar(ins.callLabel!!) checkDt(value, *(setOf(DataType.UWORD, DataType.WORD) + IterableDatatypes).toTypedArray()) evalstack.push(value) } Opcode.PUSH_VAR_FLOAT -> { - val value = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val value = getVar(ins.callLabel!!) checkDt(value, DataType.FLOAT) evalstack.push(value) } @@ -796,145 +808,145 @@ class StackVm(private var traceOutputFile: String?) { Opcode.POP_VAR_BYTE -> { val value = evalstack.pop() checkDt(value, DataType.UBYTE, DataType.BYTE) - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UBYTE, DataType.BYTE) if(value.type!=variable.type) throw VmExecutionException("datatype mismatch") - variables[ins.callLabel!!] = value + variables[ins.callLabel] = value } Opcode.POP_VAR_WORD -> { val value = evalstack.pop() checkDt(value, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS) - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS) if(value.type!=variable.type) throw VmExecutionException("datatype mismatch") - variables[ins.callLabel!!] = value + variables[ins.callLabel] = value } Opcode.POP_VAR_FLOAT -> { val value = evalstack.pop() checkDt(value, DataType.FLOAT) - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.FLOAT) - variables[ins.callLabel!!] = value + variables[ins.callLabel] = value } Opcode.SHL_VAR_BYTE -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UBYTE) - variables[ins.callLabel!!] = variable.shl() + variables[ins.callLabel] =variable.shl() } Opcode.SHL_VAR_WORD -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UWORD) - variables[ins.callLabel!!] = variable.shl() + variables[ins.callLabel] =variable.shl() } Opcode.SHR_VAR_BYTE -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UBYTE) - variables[ins.callLabel!!] = variable.shr() + variables[ins.callLabel] =variable.shr() } Opcode.SHR_VAR_WORD -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UWORD) - variables[ins.callLabel!!] = variable.shr() + variables[ins.callLabel] =variable.shr() } Opcode.ROL_VAR_BYTE -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UBYTE) val (newValue, newCarry) = variable.rol(P_carry) - variables[ins.callLabel!!] = newValue + variables[ins.callLabel] =newValue P_carry = newCarry } Opcode.ROL_VAR_WORD -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UWORD) val (newValue, newCarry) = variable.rol(P_carry) - variables[ins.callLabel!!] = newValue + variables[ins.callLabel] =newValue P_carry = newCarry } Opcode.ROR_VAR_BYTE -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UBYTE) val (newValue, newCarry) = variable.ror(P_carry) - variables[ins.callLabel!!] = newValue + variables[ins.callLabel] =newValue P_carry = newCarry } Opcode.ROR_VAR_WORD -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UWORD) val (newValue, newCarry) = variable.ror(P_carry) - variables[ins.callLabel!!] = newValue + variables[ins.callLabel] =newValue P_carry = newCarry } Opcode.ROL2_VAR_BYTE -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UBYTE) - variables[ins.callLabel!!] = variable.rol2() + variables[ins.callLabel] =variable.rol2() } Opcode.ROL2_VAR_WORD -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UWORD) - variables[ins.callLabel!!] = variable.rol2() + variables[ins.callLabel] =variable.rol2() } Opcode.ROR2_VAR_BYTE -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UBYTE) - variables[ins.callLabel!!] = variable.ror2() + variables[ins.callLabel] =variable.ror2() } Opcode.ROR2_VAR_WORD -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UWORD) - variables[ins.callLabel!!] = variable.ror2() + variables[ins.callLabel] =variable.ror2() } Opcode.INC_VAR_UB -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UBYTE) - variables[ins.callLabel!!] = variable.inc() + variables[ins.callLabel] =variable.inc() } Opcode.INC_VAR_B -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.BYTE) - variables[ins.callLabel!!] = variable.inc() + variables[ins.callLabel] =variable.inc() } Opcode.INC_VAR_UW -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UWORD) - variables[ins.callLabel!!] = variable.inc() + variables[ins.callLabel] =variable.inc() } Opcode.INC_VAR_W -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.WORD) - variables[ins.callLabel!!] = variable.inc() + variables[ins.callLabel] =variable.inc() } Opcode.INC_VAR_F -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.FLOAT) - variables[ins.callLabel!!] = variable.inc() + variables[ins.callLabel] =variable.inc() } Opcode.DEC_VAR_UB -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UBYTE) - variables[ins.callLabel!!] = variable.dec() + variables[ins.callLabel] =variable.dec() } Opcode.DEC_VAR_B -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.BYTE) - variables[ins.callLabel!!] = variable.dec() + variables[ins.callLabel] =variable.dec() } Opcode.DEC_VAR_UW -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UWORD) - variables[ins.callLabel!!] = variable.dec() + variables[ins.callLabel] =variable.dec() } Opcode.DEC_VAR_W -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.WORD) - variables[ins.callLabel!!] = variable.dec() + variables[ins.callLabel] =variable.dec() } Opcode.DEC_VAR_F -> { - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.FLOAT) - variables[ins.callLabel!!] = variable.dec() + variables[ins.callLabel] =variable.dec() } Opcode.LSB -> { val v = evalstack.pop() @@ -1194,7 +1206,7 @@ class StackVm(private var traceOutputFile: String?) { Opcode.READ_INDEXED_VAR_BYTE -> { // put the byte value of variable[index] onto the stack val index = evalstack.pop().integerValue() - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) if(variable.type==DataType.UWORD) { // assume the variable is a pointer (address) and get the ubyte value from that memory location evalstack.push(Value(DataType.UBYTE, mem.getUByte(variable.integerValue()))) @@ -1212,7 +1224,7 @@ class StackVm(private var traceOutputFile: String?) { Opcode.READ_INDEXED_VAR_WORD -> { // put the word value of variable[index] onto the stack val index = evalstack.pop().integerValue() - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) if(variable.type==DataType.UWORD) { // assume the variable is a pointer (address) and get the word value from that memory location evalstack.push(Value(DataType.UWORD, mem.getUWord(variable.integerValue()))) @@ -1229,7 +1241,7 @@ class StackVm(private var traceOutputFile: String?) { Opcode.READ_INDEXED_VAR_FLOAT -> { // put the f;pat value of variable[index] onto the stack val index = evalstack.pop().integerValue() - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + val variable = getVar(ins.callLabel!!) if(variable.type==DataType.UWORD) { // assume the variable is a pointer (address) and get the float value from that memory location evalstack.push(Value(DataType.UWORD, mem.getFloat(variable.integerValue()))) @@ -1246,25 +1258,44 @@ class StackVm(private var traceOutputFile: String?) { val index = evalstack.pop().integerValue() val value = evalstack.pop() checkDt(value, DataType.UBYTE, DataType.BYTE) - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - if(variable.type==DataType.UWORD) { - // assume the variable is a pointer (address) and write the byte value to that memory location - mem.setUByte(variable.integerValue(), value.integerValue().toShort()) + val varname = ins.callLabel!! + val memloc = memoryPointers[varname] + if(memloc!=null) { + // variable is the name of a pointer, write the byte value to that memory location + if(value.type==DataType.UBYTE) { + if(memloc.second!=DataType.ARRAY_UB) + throw VmExecutionException("invalid memory pointer type $memloc") + mem.setUByte(memloc.first, value.integerValue().toShort()) + } + else { + if(memloc.second!=DataType.ARRAY_B) + throw VmExecutionException("invalid memory pointer type $memloc") + mem.setSByte(memloc.first, value.integerValue().toShort()) + } } else { - // set indexed byte element in the arrayspec - val array = heap.get(variable.heapId) - when(array.type) { - DataType.ARRAY_UB -> array.array!![index] = value.integerValue() - DataType.ARRAY_B -> array.array!![index] = value.integerValue() - DataType.STR, - DataType.STR_P, - DataType.STR_S, - DataType.STR_PS -> { - val chars = array.str!!.toCharArray() - chars[index] = Petscii.decodePetscii(listOf(value.integerValue().toShort()), true)[0] - heap.update(variable.heapId, chars.joinToString("")) + val variable = getVar(varname) + if (variable.type == DataType.UWORD) { + // assume the variable is a pointer (address) and write the byte value to that memory location + if(value.type==DataType.UBYTE) + mem.setUByte(variable.integerValue(), value.integerValue().toShort()) + else + mem.setSByte(variable.integerValue(), value.integerValue().toShort()) + } else { + // set indexed byte element in the arrayspec + val array = heap.get(variable.heapId) + when (array.type) { + DataType.ARRAY_UB -> array.array!![index] = value.integerValue() + DataType.ARRAY_B -> array.array!![index] = value.integerValue() + DataType.STR, + DataType.STR_P, + DataType.STR_S, + DataType.STR_PS -> { + val chars = array.str!!.toCharArray() + chars[index] = Petscii.decodePetscii(listOf(value.integerValue().toShort()), true)[0] + heap.update(variable.heapId, chars.joinToString("")) + } + else -> throw VmExecutionException("not a proper array/string var with byte elements") } - else -> throw VmExecutionException("not a proper array/string var with byte elements") } } } @@ -1273,19 +1304,37 @@ class StackVm(private var traceOutputFile: String?) { val index = evalstack.pop().integerValue() val value = evalstack.pop() checkDt(value, DataType.UWORD, DataType.WORD) - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - if(variable.type==DataType.UWORD) { - // assume the variable is a pointer (address) and write the word value to that memory location - mem.setUWord(variable.integerValue(), value.integerValue()) - } else { - // set indexed word element in the arrayspec - val array = heap.get(variable.heapId) - when(array.type) { - DataType.ARRAY_UW -> array.array!![index] = value.integerValue() - DataType.ARRAY_W -> array.array!![index] = value.integerValue() - else -> throw VmExecutionException("not a proper arrayspec var with word elements") + val varname = ins.callLabel!! + val memloc = memoryPointers[varname] + if(memloc!=null) { + // variable is the name of a pointer, write the word value to that memory location + if(value.type==DataType.UWORD) { + if(memloc.second!=DataType.ARRAY_UW) + throw VmExecutionException("invalid memory pointer type $memloc") + mem.setUWord(memloc.first, value.integerValue()) + } + else { + if(memloc.second!=DataType.ARRAY_W) + throw VmExecutionException("invalid memory pointer type $memloc") + mem.setSWord(memloc.first, value.integerValue()) + } + } else { + val variable = getVar(varname) + if (variable.type == DataType.UWORD) { + // assume the variable is a pointer (address) and write the word value to that memory location + if(value.type==DataType.UWORD) + mem.setUWord(variable.integerValue(), value.integerValue()) + else + mem.setSWord(variable.integerValue(), value.integerValue()) + } else { + // set indexed word element in the arrayspec + val array = heap.get(variable.heapId) + when (array.type) { + DataType.ARRAY_UW -> array.array!![index] = value.integerValue() + DataType.ARRAY_W -> array.array!![index] = value.integerValue() + else -> throw VmExecutionException("not a proper arrayspec var with word elements") + } } - } } Opcode.WRITE_INDEXED_VAR_FLOAT -> { @@ -1293,16 +1342,25 @@ class StackVm(private var traceOutputFile: String?) { val index = evalstack.pop().integerValue() val value = evalstack.pop() checkDt(value, DataType.FLOAT) - val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - if(variable.type==DataType.UWORD) { - // assume the variable is a pointer (address) and write the float value to that memory location - mem.setFloat(variable.integerValue(), value.numericValue().toDouble()) + val varname = ins.callLabel!! + val memloc = memoryPointers[varname] + if(memloc!=null) { + // variable is the name of a pointer, write the float value to that memory location + if(memloc.second!=DataType.ARRAY_F) + throw VmExecutionException("invalid memory pointer type $memloc") + mem.setFloat(memloc.first, value.numericValue().toDouble()) } else { - // set indexed float element in the arrayspec - val array = heap.get(variable.heapId) - if(array.type!=DataType.ARRAY_F) - throw VmExecutionException("not a proper arrayspec var with float elements") - array.doubleArray!![index] = value.numericValue().toDouble() + val variable = getVar(varname) + if (variable.type == DataType.UWORD) { + // assume the variable is a pointer (address) and write the float value to that memory location + mem.setFloat(variable.integerValue(), value.numericValue().toDouble()) + } else { + // set indexed float element in the arrayspec + val array = heap.get(variable.heapId) + if (array.type != DataType.ARRAY_F) + throw VmExecutionException("not a proper arrayspec var with float elements") + array.doubleArray!![index] = value.numericValue().toDouble() + } } } Opcode.RSAVE -> { diff --git a/compiler/test/StackVMOpcodeTests.kt b/compiler/test/StackVMOpcodeTests.kt index a433dacf6..ee7ac724b 100644 --- a/compiler/test/StackVMOpcodeTests.kt +++ b/compiler/test/StackVMOpcodeTests.kt @@ -51,12 +51,13 @@ class TestStackVmOpcodes { private val vm = StackVm(null) - fun makeProg(ins: MutableList, + private fun makeProg(ins: MutableList, vars: Map?=null, + memoryPointers: Map>?=null, labels: Map?=null, mem: Map>?=null) : Program { val heap = HeapValues() - return Program("test", ins, vars ?: mapOf(), labels ?: mapOf(), mem ?: mapOf(), heap) + return Program("test", ins, vars ?: mapOf(), memoryPointers ?: mapOf(), labels ?: mapOf(), mem ?: mapOf(), heap) } @Test diff --git a/prog8lib/prog8lib.p8 b/prog8lib/prog8lib.p8 index 37d8e8067..b8e3c003d 100644 --- a/prog8lib/prog8lib.p8 +++ b/prog8lib/prog8lib.p8 @@ -45,9 +45,15 @@ w2float push_float rts + +push_float_from_indexed_var + rts pop_var_float rts + +pop_float_to_indexed_var + rts pop_mem_float rts