fix memory pointer variables in the StackVm

This commit is contained in:
Irmen de Jong 2018-12-02 23:53:09 +01:00
parent 89ac374db9
commit 711d6f4ee5
9 changed files with 290 additions and 186 deletions

View File

@ -27,31 +27,34 @@ sub start() {
; } ; }
float[10] farr ubyte bv = 99
float f = 3.3 word wv = 14443
memory float mflt = $c000 float fv = 3.14
memory float[10] mfarr = $d000 memory ubyte mb = $c000
ubyte i=3 memory word mw = $c100
memory float mf = $c200
mflt = 55.44 ; @todo fix memory variables for stackvm???! (or proper error) memory ubyte[10] mba = $d000
mfarr[2] = 44.44 ; @todo fix memory variables for stackvm???! (or proper error) memory word[10] mwa = $d100
memory float[10] mfa = $d200
farr[2] = 4.44 memory str mstr = $d300
farr[2] = f memory str_p mstrp = $d300
farr[2] = mflt memory str_s mstrs = $d300
farr[2] = farr[3] memory str_ps mstrps = $d300
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]
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 return
} }

View File

@ -755,7 +755,7 @@ class AstChecker(private val namespace: INameScope,
// check out of bounds // check out of bounds
val index = (arrayIndexedExpression.arrayspec.x as? LiteralValue)?.asIntegerValue val index = (arrayIndexedExpression.arrayspec.x as? LiteralValue)?.asIntegerValue
if(index!=null && (index<0 || index>=arraysize)) 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) { } else if(target.datatype in StringDatatypes) {
// check string lengths // check string lengths
val heapId = (target.value as LiteralValue).heapId!! 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 err("initializer arrayspec size mismatch (expecting $expectedSize, got $arraySize)")
return true 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 -> { DataType.ARRAY_UW, DataType.ARRAY_W -> {
// value may be either a single word, or a word arrayspec // value may be either a single word, or a word arrayspec

View File

@ -177,7 +177,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
if(subroutine.isNotEmpty()) if(subroutine.isNotEmpty())
throw CompilerException("kernel subroutines (with memory address) can't have a body: $subroutine") 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) return super.process(subroutine)
} }
@ -555,9 +555,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
} }
is IdentifierReference -> translate(expr) is IdentifierReference -> translate(expr)
is ArrayIndexedExpression -> translate(expr, false) is ArrayIndexedExpression -> translate(expr, false)
is RangeExpr -> { is RangeExpr -> throw CompilerException("it's not possible to just have a range expression that has to be translated")
TODO("TRANSLATE range $expr")
}
else -> { else -> {
val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr") val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr")
when(lv.type) { when(lv.type) {
@ -800,59 +798,68 @@ private class StatementTranslator(private val prog: IntermediateProgram,
val valueA: IExpression val valueA: IExpression
val valueX: IExpression val valueX: IExpression
val paramDt = arg.first.resultingDatatype(namespace, heap) val paramDt = arg.first.resultingDatatype(namespace, heap)
if(paramDt==DataType.UBYTE) { when (paramDt) {
valueA=arg.first DataType.UBYTE -> {
valueX=LiteralValue.optimalInteger(0, callPosition) valueA=arg.first
val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, callPosition)), null, valueA, callPosition) valueX=LiteralValue.optimalInteger(0, callPosition)
val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, callPosition)), null, valueX, callPosition) val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, callPosition)), null, valueA, callPosition)
assignA.linkParents(arguments[0].parent) val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, callPosition)), null, valueX, callPosition)
assignX.linkParents(arguments[0].parent) assignA.linkParents(arguments[0].parent)
translate(assignA) assignX.linkParents(arguments[0].parent)
translate(assignX) translate(assignA)
} else if(paramDt==DataType.UWORD) { translate(assignX)
translate(arg.first) }
prog.instr(Opcode.POP_REGAX_WORD) DataType.UWORD -> {
} else translate(arg.first)
TODO("pass parameter of type $paramDt in registers ${arg.second.registerOrPair}") prog.instr(Opcode.POP_REGAX_WORD)
}
else -> TODO("pass parameter of type $paramDt in registers ${arg.second.registerOrPair}")
}
} }
AY -> { AY -> {
val valueA: IExpression val valueA: IExpression
val valueY: IExpression val valueY: IExpression
val paramDt = arg.first.resultingDatatype(namespace, heap) val paramDt = arg.first.resultingDatatype(namespace, heap)
if(paramDt==DataType.UBYTE) { when (paramDt) {
valueA=arg.first DataType.UBYTE -> {
valueY=LiteralValue.optimalInteger(0, callPosition) valueA=arg.first
val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, callPosition)), null, valueA, callPosition) valueY=LiteralValue.optimalInteger(0, callPosition)
val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, callPosition)), null, valueY, callPosition) val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, callPosition)), null, valueA, callPosition)
assignA.linkParents(arguments[0].parent) val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, callPosition)), null, valueY, callPosition)
assignY.linkParents(arguments[0].parent) assignA.linkParents(arguments[0].parent)
translate(assignA) assignY.linkParents(arguments[0].parent)
translate(assignY) translate(assignA)
} else if(paramDt==DataType.UWORD) { translate(assignY)
translate(arg.first) }
prog.instr(Opcode.POP_REGAY_WORD) DataType.UWORD -> {
} else translate(arg.first)
TODO("pass parameter of type $paramDt in registers ${arg.second.registerOrPair}") prog.instr(Opcode.POP_REGAY_WORD)
}
else -> TODO("pass parameter of type $paramDt in registers ${arg.second.registerOrPair}")
}
} }
XY -> { XY -> {
// TODO: save X on stack & restore after call // TODO: save X on stack & restore after call
val valueX: IExpression val valueX: IExpression
val valueY: IExpression val valueY: IExpression
val paramDt = arg.first.resultingDatatype(namespace, heap) val paramDt = arg.first.resultingDatatype(namespace, heap)
if(paramDt==DataType.UBYTE) { when (paramDt) {
valueX=arg.first DataType.UBYTE -> {
valueY=LiteralValue.optimalInteger(0, callPosition) valueX=arg.first
val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, callPosition)), null, valueX, callPosition) valueY=LiteralValue.optimalInteger(0, callPosition)
val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, callPosition)), null, valueY, callPosition) val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, callPosition)), null, valueX, callPosition)
assignX.linkParents(arguments[0].parent) val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, callPosition)), null, valueY, callPosition)
assignY.linkParents(arguments[0].parent) assignX.linkParents(arguments[0].parent)
translate(assignX) assignY.linkParents(arguments[0].parent)
translate(assignY) translate(assignX)
} else if(paramDt==DataType.UWORD) { translate(assignY)
translate(arg.first) }
prog.instr(Opcode.POP_REGXY_WORD) DataType.UWORD -> {
} else translate(arg.first)
TODO("pass parameter of type $paramDt in registers ${arg.second.registerOrPair}") 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") 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.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") 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") null -> throw CompilerException("could not determine targetdt")
@ -1793,7 +1799,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
val postIncr = PostIncrDecr(makeAssignmentTarget(), "--", range.position) val postIncr = PostIncrDecr(makeAssignmentTarget(), "--", range.position)
postIncr.linkParents(range.parent) postIncr.linkParents(range.parent)
translate(postIncr) 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 -> { else -> {
TODO("non-literal-const or other-than-one step increment code At: ${range.position}") TODO("non-literal-const or other-than-one step increment code At: ${range.position}")

View File

@ -13,7 +13,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
var address: Int?, var address: Int?,
val instructions: MutableList<Instruction> = mutableListOf(), val instructions: MutableList<Instruction> = mutableListOf(),
val variables: MutableMap<String, Value> = mutableMapOf(), val variables: MutableMap<String, Value> = mutableMapOf(),
val integerConstants: MutableMap<String, Int> = mutableMapOf(), val memoryPointers: MutableMap<String, Pair<Int, DataType>> = mutableMapOf(),
val labels: MutableMap<String, Instruction> = mutableMapOf()) val labels: MutableMap<String, Instruction> = mutableMapOf())
{ {
val numVariables: Int 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.CONST -> {} // constants are all folded away
VarDeclType.MEMORY -> { 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) currentBlock.instructions.removeAt(currentBlock.instructions.lastIndex)
} }
fun symbolDef(name: String, value: Int) { fun memoryPointer(name: String, address: Int, datatype: DataType) {
currentBlock.integerConstants[name] = value currentBlock.memoryPointers[name] = Pair(address, datatype)
} }
fun newBlock(scopedname: String, shortname: String, address: Int?) { 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("${variable.key} ${variable.value.type.toString().toLowerCase()} $valuestr")
} }
out.println("%end_variables") 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") out.println("%instructions")
val labels = blk.labels.entries.associateBy({it.value}) {it.key} val labels = blk.labels.entries.associateBy({it.value}) {it.key}
for(instr in blk.instructions) { for(instr in blk.instructions) {

View File

@ -42,7 +42,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
callLabel2 = if (it.callLabel2 != null) symname(it.callLabel2, block) else null) callLabel2 = if (it.callLabel2 != null) symname(it.callLabel2, block) else null)
} }
}.toMutableList() }.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( newblocks.add(IntermediateProgram.ProgramBlock(
block.scopedname, block.scopedname,
block.shortname, block.shortname,
@ -216,8 +216,8 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
} }
private fun memdefs2asm(block: IntermediateProgram.ProgramBlock) { private fun memdefs2asm(block: IntermediateProgram.ProgramBlock) {
for(m in block.integerConstants) { for(m in block.memoryPointers) {
out("\t${m.key} = ${m.value.toHex()}") 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 -> { Opcode.READ_INDEXED_VAR_BYTE -> {
TODO("$ins") TODO("$ins") // byte[i]
} }
Opcode.READ_INDEXED_VAR_WORD -> { Opcode.READ_INDEXED_VAR_WORD -> {
TODO("$ins") TODO("$ins") // word[i]
} }
Opcode.READ_INDEXED_VAR_FLOAT -> { Opcode.READ_INDEXED_VAR_FLOAT -> {
""" """
@ -486,10 +486,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
""" """
} }
Opcode.WRITE_INDEXED_VAR_BYTE -> { Opcode.WRITE_INDEXED_VAR_BYTE -> {
TODO("$ins") TODO("$ins") // byte[i]=...
} }
Opcode.WRITE_INDEXED_VAR_WORD -> { Opcode.WRITE_INDEXED_VAR_WORD -> {
TODO("$ins") TODO("$ins") // word[i]=...
} }
Opcode.WRITE_INDEXED_VAR_FLOAT -> { Opcode.WRITE_INDEXED_VAR_FLOAT -> {
""" """

View File

@ -10,6 +10,7 @@ import java.util.regex.Pattern
class Program (val name: String, class Program (val name: String,
val program: MutableList<Instruction>, val program: MutableList<Instruction>,
val variables: Map<String, Value>, val variables: Map<String, Value>,
val memoryPointers: Map<String, Pair<Int, DataType>>,
val labels: Map<String, Instruction>, val labels: Map<String, Instruction>,
val memory: Map<Int, List<Value>>, val memory: Map<Int, List<Value>>,
val heap: HeapValues) val heap: HeapValues)
@ -29,6 +30,7 @@ class Program (val name: String,
val heap = HeapValues() val heap = HeapValues()
val program = mutableListOf<Instruction>() val program = mutableListOf<Instruction>()
val variables = mutableMapOf<String, Value>() val variables = mutableMapOf<String, Value>()
val memoryPointers = mutableMapOf<String, Pair<Int, DataType>>()
val labels = mutableMapOf<String, Instruction>() val labels = mutableMapOf<String, Instruction>()
while(lines.hasNext()) { while(lines.hasNext()) {
@ -40,16 +42,17 @@ class Program (val name: String,
else if(line=="%heap") else if(line=="%heap")
loadHeap(lines, heap) loadHeap(lines, heap)
else if(line.startsWith("%block ")) 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}") 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<IndexedValue<String>>, private fun loadBlock(lines: Iterator<IndexedValue<String>>,
heap: HeapValues, heap: HeapValues,
program: MutableList<Instruction>, program: MutableList<Instruction>,
variables: MutableMap<String, Value>, variables: MutableMap<String, Value>,
memoryPointers: MutableMap<String, Pair<Int, DataType>>,
labels: MutableMap<String, Instruction>) labels: MutableMap<String, Instruction>)
{ {
while(true) { while(true) {
@ -60,6 +63,8 @@ class Program (val name: String,
return return
else if(line=="%variables") else if(line=="%variables")
loadVars(lines, variables) loadVars(lines, variables)
else if(line=="%memorypointers")
loadMemoryPointers(lines, memoryPointers, heap)
else if(line=="%instructions") { else if(line=="%instructions") {
val (blockInstructions, blockLabels) = loadInstructions(lines, heap) val (blockInstructions, blockLabels) = loadInstructions(lines, heap)
program.addAll(blockInstructions) program.addAll(blockInstructions)
@ -177,12 +182,12 @@ class Program (val name: String,
} }
private fun loadVars(lines: Iterator<IndexedValue<String>>, private fun loadVars(lines: Iterator<IndexedValue<String>>,
vars: MutableMap<String, Value>): Map<String, Value> { vars: MutableMap<String, Value>) {
val splitpattern = Pattern.compile("\\s+") val splitpattern = Pattern.compile("\\s+")
while(true) { while(true) {
val (_, line) = lines.next() val (_, line) = lines.next()
if(line=="%end_variables") if(line=="%end_variables")
return vars return
val (name, typeStr, valueStr) = line.split(splitpattern, limit = 3) val (name, typeStr, valueStr) = line.split(splitpattern, limit = 3)
if(valueStr[0] !='"' && ':' !in valueStr) if(valueStr[0] !='"' && ':' !in valueStr)
throw VmExecutionException("missing value type character") throw VmExecutionException("missing value type character")
@ -220,6 +225,23 @@ class Program (val name: String,
} }
} }
private fun loadMemoryPointers(lines: Iterator<IndexedValue<String>>,
pointers: MutableMap<String, Pair<Int, DataType>>,
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<IndexedValue<String>>, memory: MutableMap<Int, List<Value>>): Map<Int, List<Value>> { private fun loadMemory(lines: Iterator<IndexedValue<String>>, memory: MutableMap<Int, List<Value>>): Map<Int, List<Value>> {
while(true) { while(true) {
val (lineNr, line) = lines.next() val (lineNr, line) = lines.next()

View File

@ -104,6 +104,8 @@ class StackVm(private var traceOutputFile: String?) {
private set private set
var variables = mutableMapOf<String, Value>() // all variables (set of all vars used by all blocks/subroutines) key = their fully scoped name var variables = mutableMapOf<String, Value>() // all variables (set of all vars used by all blocks/subroutines) key = their fully scoped name
private set private set
var memoryPointers = mutableMapOf<String, Pair<Int, DataType>>() // all named pointers
private set
var evalstack = MyStack<Value>() var evalstack = MyStack<Value>()
private set private set
var callstack = MyStack<Instruction>() var callstack = MyStack<Instruction>()
@ -125,6 +127,7 @@ class StackVm(private var traceOutputFile: String?) {
this.canvas = canvas this.canvas = canvas
canvas?.requestFocusInWindow() canvas?.requestFocusInWindow()
variables = program.variables.toMutableMap() variables = program.variables.toMutableMap()
memoryPointers = program.memoryPointers.toMutableMap()
if("A" in variables || "X" in variables || "Y" in variables) if("A" in variables || "X" in variables || "Y" in variables)
throw VmExecutionException("program contains variable(s) for the reserved registers A/X/Y") 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 { private fun dispatch(ins: Instruction) : Instruction {
traceOutput?.println("\n$ins") traceOutput?.println("\n$ins")
when (ins.opcode) { when (ins.opcode) {
@ -749,17 +761,17 @@ class StackVm(private var traceOutputFile: String?) {
return callstack.pop() return callstack.pop()
} }
Opcode.PUSH_VAR_BYTE -> { 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) checkDt(value, DataType.UBYTE, DataType.BYTE)
evalstack.push(value) evalstack.push(value)
} }
Opcode.PUSH_VAR_WORD -> { 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()) checkDt(value, *(setOf(DataType.UWORD, DataType.WORD) + IterableDatatypes).toTypedArray())
evalstack.push(value) evalstack.push(value)
} }
Opcode.PUSH_VAR_FLOAT -> { Opcode.PUSH_VAR_FLOAT -> {
val value = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val value = getVar(ins.callLabel!!)
checkDt(value, DataType.FLOAT) checkDt(value, DataType.FLOAT)
evalstack.push(value) evalstack.push(value)
} }
@ -796,145 +808,145 @@ class StackVm(private var traceOutputFile: String?) {
Opcode.POP_VAR_BYTE -> { Opcode.POP_VAR_BYTE -> {
val value = evalstack.pop() val value = evalstack.pop()
checkDt(value, DataType.UBYTE, DataType.BYTE) 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) checkDt(variable, DataType.UBYTE, DataType.BYTE)
if(value.type!=variable.type) if(value.type!=variable.type)
throw VmExecutionException("datatype mismatch") throw VmExecutionException("datatype mismatch")
variables[ins.callLabel!!] = value variables[ins.callLabel] = value
} }
Opcode.POP_VAR_WORD -> { Opcode.POP_VAR_WORD -> {
val value = evalstack.pop() val value = evalstack.pop()
checkDt(value, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS) 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) checkDt(variable, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)
if(value.type!=variable.type) if(value.type!=variable.type)
throw VmExecutionException("datatype mismatch") throw VmExecutionException("datatype mismatch")
variables[ins.callLabel!!] = value variables[ins.callLabel] = value
} }
Opcode.POP_VAR_FLOAT -> { Opcode.POP_VAR_FLOAT -> {
val value = evalstack.pop() val value = evalstack.pop()
checkDt(value, DataType.FLOAT) checkDt(value, DataType.FLOAT)
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.FLOAT) checkDt(variable, DataType.FLOAT)
variables[ins.callLabel!!] = value variables[ins.callLabel] = value
} }
Opcode.SHL_VAR_BYTE -> { Opcode.SHL_VAR_BYTE -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UBYTE) checkDt(variable, DataType.UBYTE)
variables[ins.callLabel!!] = variable.shl() variables[ins.callLabel] =variable.shl()
} }
Opcode.SHL_VAR_WORD -> { Opcode.SHL_VAR_WORD -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UWORD) checkDt(variable, DataType.UWORD)
variables[ins.callLabel!!] = variable.shl() variables[ins.callLabel] =variable.shl()
} }
Opcode.SHR_VAR_BYTE -> { Opcode.SHR_VAR_BYTE -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UBYTE) checkDt(variable, DataType.UBYTE)
variables[ins.callLabel!!] = variable.shr() variables[ins.callLabel] =variable.shr()
} }
Opcode.SHR_VAR_WORD -> { Opcode.SHR_VAR_WORD -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UWORD) checkDt(variable, DataType.UWORD)
variables[ins.callLabel!!] = variable.shr() variables[ins.callLabel] =variable.shr()
} }
Opcode.ROL_VAR_BYTE -> { Opcode.ROL_VAR_BYTE -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UBYTE) checkDt(variable, DataType.UBYTE)
val (newValue, newCarry) = variable.rol(P_carry) val (newValue, newCarry) = variable.rol(P_carry)
variables[ins.callLabel!!] = newValue variables[ins.callLabel] =newValue
P_carry = newCarry P_carry = newCarry
} }
Opcode.ROL_VAR_WORD -> { Opcode.ROL_VAR_WORD -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UWORD) checkDt(variable, DataType.UWORD)
val (newValue, newCarry) = variable.rol(P_carry) val (newValue, newCarry) = variable.rol(P_carry)
variables[ins.callLabel!!] = newValue variables[ins.callLabel] =newValue
P_carry = newCarry P_carry = newCarry
} }
Opcode.ROR_VAR_BYTE -> { Opcode.ROR_VAR_BYTE -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UBYTE) checkDt(variable, DataType.UBYTE)
val (newValue, newCarry) = variable.ror(P_carry) val (newValue, newCarry) = variable.ror(P_carry)
variables[ins.callLabel!!] = newValue variables[ins.callLabel] =newValue
P_carry = newCarry P_carry = newCarry
} }
Opcode.ROR_VAR_WORD -> { Opcode.ROR_VAR_WORD -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UWORD) checkDt(variable, DataType.UWORD)
val (newValue, newCarry) = variable.ror(P_carry) val (newValue, newCarry) = variable.ror(P_carry)
variables[ins.callLabel!!] = newValue variables[ins.callLabel] =newValue
P_carry = newCarry P_carry = newCarry
} }
Opcode.ROL2_VAR_BYTE -> { Opcode.ROL2_VAR_BYTE -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UBYTE) checkDt(variable, DataType.UBYTE)
variables[ins.callLabel!!] = variable.rol2() variables[ins.callLabel] =variable.rol2()
} }
Opcode.ROL2_VAR_WORD -> { Opcode.ROL2_VAR_WORD -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UWORD) checkDt(variable, DataType.UWORD)
variables[ins.callLabel!!] = variable.rol2() variables[ins.callLabel] =variable.rol2()
} }
Opcode.ROR2_VAR_BYTE -> { Opcode.ROR2_VAR_BYTE -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UBYTE) checkDt(variable, DataType.UBYTE)
variables[ins.callLabel!!] = variable.ror2() variables[ins.callLabel] =variable.ror2()
} }
Opcode.ROR2_VAR_WORD -> { Opcode.ROR2_VAR_WORD -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UWORD) checkDt(variable, DataType.UWORD)
variables[ins.callLabel!!] = variable.ror2() variables[ins.callLabel] =variable.ror2()
} }
Opcode.INC_VAR_UB -> { Opcode.INC_VAR_UB -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UBYTE) checkDt(variable, DataType.UBYTE)
variables[ins.callLabel!!] = variable.inc() variables[ins.callLabel] =variable.inc()
} }
Opcode.INC_VAR_B -> { Opcode.INC_VAR_B -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.BYTE) checkDt(variable, DataType.BYTE)
variables[ins.callLabel!!] = variable.inc() variables[ins.callLabel] =variable.inc()
} }
Opcode.INC_VAR_UW -> { Opcode.INC_VAR_UW -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UWORD) checkDt(variable, DataType.UWORD)
variables[ins.callLabel!!] = variable.inc() variables[ins.callLabel] =variable.inc()
} }
Opcode.INC_VAR_W -> { Opcode.INC_VAR_W -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.WORD) checkDt(variable, DataType.WORD)
variables[ins.callLabel!!] = variable.inc() variables[ins.callLabel] =variable.inc()
} }
Opcode.INC_VAR_F -> { Opcode.INC_VAR_F -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.FLOAT) checkDt(variable, DataType.FLOAT)
variables[ins.callLabel!!] = variable.inc() variables[ins.callLabel] =variable.inc()
} }
Opcode.DEC_VAR_UB -> { Opcode.DEC_VAR_UB -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UBYTE) checkDt(variable, DataType.UBYTE)
variables[ins.callLabel!!] = variable.dec() variables[ins.callLabel] =variable.dec()
} }
Opcode.DEC_VAR_B -> { Opcode.DEC_VAR_B -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.BYTE) checkDt(variable, DataType.BYTE)
variables[ins.callLabel!!] = variable.dec() variables[ins.callLabel] =variable.dec()
} }
Opcode.DEC_VAR_UW -> { Opcode.DEC_VAR_UW -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UWORD) checkDt(variable, DataType.UWORD)
variables[ins.callLabel!!] = variable.dec() variables[ins.callLabel] =variable.dec()
} }
Opcode.DEC_VAR_W -> { Opcode.DEC_VAR_W -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.WORD) checkDt(variable, DataType.WORD)
variables[ins.callLabel!!] = variable.dec() variables[ins.callLabel] =variable.dec()
} }
Opcode.DEC_VAR_F -> { Opcode.DEC_VAR_F -> {
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.FLOAT) checkDt(variable, DataType.FLOAT)
variables[ins.callLabel!!] = variable.dec() variables[ins.callLabel] =variable.dec()
} }
Opcode.LSB -> { Opcode.LSB -> {
val v = evalstack.pop() val v = evalstack.pop()
@ -1194,7 +1206,7 @@ class StackVm(private var traceOutputFile: String?) {
Opcode.READ_INDEXED_VAR_BYTE -> { Opcode.READ_INDEXED_VAR_BYTE -> {
// put the byte value of variable[index] onto the stack // put the byte value of variable[index] onto the stack
val index = evalstack.pop().integerValue() 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) { if(variable.type==DataType.UWORD) {
// assume the variable is a pointer (address) and get the ubyte value from that memory location // 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()))) evalstack.push(Value(DataType.UBYTE, mem.getUByte(variable.integerValue())))
@ -1212,7 +1224,7 @@ class StackVm(private var traceOutputFile: String?) {
Opcode.READ_INDEXED_VAR_WORD -> { Opcode.READ_INDEXED_VAR_WORD -> {
// put the word value of variable[index] onto the stack // put the word value of variable[index] onto the stack
val index = evalstack.pop().integerValue() 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) { if(variable.type==DataType.UWORD) {
// assume the variable is a pointer (address) and get the word value from that memory location // 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()))) evalstack.push(Value(DataType.UWORD, mem.getUWord(variable.integerValue())))
@ -1229,7 +1241,7 @@ class StackVm(private var traceOutputFile: String?) {
Opcode.READ_INDEXED_VAR_FLOAT -> { Opcode.READ_INDEXED_VAR_FLOAT -> {
// put the f;pat value of variable[index] onto the stack // put the f;pat value of variable[index] onto the stack
val index = evalstack.pop().integerValue() 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) { if(variable.type==DataType.UWORD) {
// assume the variable is a pointer (address) and get the float value from that memory location // 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()))) 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 index = evalstack.pop().integerValue()
val value = evalstack.pop() val value = evalstack.pop()
checkDt(value, DataType.UBYTE, DataType.BYTE) checkDt(value, DataType.UBYTE, DataType.BYTE)
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val varname = ins.callLabel!!
if(variable.type==DataType.UWORD) { val memloc = memoryPointers[varname]
// assume the variable is a pointer (address) and write the byte value to that memory location if(memloc!=null) {
mem.setUByte(variable.integerValue(), value.integerValue().toShort()) // 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 { } else {
// set indexed byte element in the arrayspec val variable = getVar(varname)
val array = heap.get(variable.heapId) if (variable.type == DataType.UWORD) {
when(array.type) { // assume the variable is a pointer (address) and write the byte value to that memory location
DataType.ARRAY_UB -> array.array!![index] = value.integerValue() if(value.type==DataType.UBYTE)
DataType.ARRAY_B -> array.array!![index] = value.integerValue() mem.setUByte(variable.integerValue(), value.integerValue().toShort())
DataType.STR, else
DataType.STR_P, mem.setSByte(variable.integerValue(), value.integerValue().toShort())
DataType.STR_S, } else {
DataType.STR_PS -> { // set indexed byte element in the arrayspec
val chars = array.str!!.toCharArray() val array = heap.get(variable.heapId)
chars[index] = Petscii.decodePetscii(listOf(value.integerValue().toShort()), true)[0] when (array.type) {
heap.update(variable.heapId, chars.joinToString("")) 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 index = evalstack.pop().integerValue()
val value = evalstack.pop() val value = evalstack.pop()
checkDt(value, DataType.UWORD, DataType.WORD) checkDt(value, DataType.UWORD, DataType.WORD)
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val varname = ins.callLabel!!
if(variable.type==DataType.UWORD) { val memloc = memoryPointers[varname]
// assume the variable is a pointer (address) and write the word value to that memory location if(memloc!=null) {
mem.setUWord(variable.integerValue(), value.integerValue()) // variable is the name of a pointer, write the word value to that memory location
} else { if(value.type==DataType.UWORD) {
// set indexed word element in the arrayspec if(memloc.second!=DataType.ARRAY_UW)
val array = heap.get(variable.heapId) throw VmExecutionException("invalid memory pointer type $memloc")
when(array.type) { mem.setUWord(memloc.first, value.integerValue())
DataType.ARRAY_UW -> array.array!![index] = value.integerValue() }
DataType.ARRAY_W -> array.array!![index] = value.integerValue() else {
else -> throw VmExecutionException("not a proper arrayspec var with word elements") 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 -> { Opcode.WRITE_INDEXED_VAR_FLOAT -> {
@ -1293,16 +1342,25 @@ class StackVm(private var traceOutputFile: String?) {
val index = evalstack.pop().integerValue() val index = evalstack.pop().integerValue()
val value = evalstack.pop() val value = evalstack.pop()
checkDt(value, DataType.FLOAT) checkDt(value, DataType.FLOAT)
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") val varname = ins.callLabel!!
if(variable.type==DataType.UWORD) { val memloc = memoryPointers[varname]
// assume the variable is a pointer (address) and write the float value to that memory location if(memloc!=null) {
mem.setFloat(variable.integerValue(), value.numericValue().toDouble()) // 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 { } else {
// set indexed float element in the arrayspec val variable = getVar(varname)
val array = heap.get(variable.heapId) if (variable.type == DataType.UWORD) {
if(array.type!=DataType.ARRAY_F) // assume the variable is a pointer (address) and write the float value to that memory location
throw VmExecutionException("not a proper arrayspec var with float elements") mem.setFloat(variable.integerValue(), value.numericValue().toDouble())
array.doubleArray!![index] = 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 -> { Opcode.RSAVE -> {

View File

@ -51,12 +51,13 @@ class TestStackVmOpcodes {
private val vm = StackVm(null) private val vm = StackVm(null)
fun makeProg(ins: MutableList<Instruction>, private fun makeProg(ins: MutableList<Instruction>,
vars: Map<String, Value>?=null, vars: Map<String, Value>?=null,
memoryPointers: Map<String, Pair<Int, DataType>>?=null,
labels: Map<String, Instruction>?=null, labels: Map<String, Instruction>?=null,
mem: Map<Int, List<Value>>?=null) : Program { mem: Map<Int, List<Value>>?=null) : Program {
val heap = HeapValues() 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 @Test

View File

@ -45,9 +45,15 @@ w2float
push_float push_float
rts rts
push_float_from_indexed_var
rts
pop_var_float pop_var_float
rts rts
pop_float_to_indexed_var
rts
pop_mem_float pop_mem_float
rts rts