mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 19:54:26 +00:00
fix memory pointer variables in the StackVm
This commit is contained in:
parent
89ac374db9
commit
711d6f4ee5
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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}")
|
||||
|
@ -13,7 +13,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
|
||||
var address: Int?,
|
||||
val instructions: MutableList<Instruction> = mutableListOf(),
|
||||
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 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) {
|
||||
|
@ -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 -> {
|
||||
"""
|
||||
|
@ -10,6 +10,7 @@ import java.util.regex.Pattern
|
||||
class Program (val name: String,
|
||||
val program: MutableList<Instruction>,
|
||||
val variables: Map<String, Value>,
|
||||
val memoryPointers: Map<String, Pair<Int, DataType>>,
|
||||
val labels: Map<String, Instruction>,
|
||||
val memory: Map<Int, List<Value>>,
|
||||
val heap: HeapValues)
|
||||
@ -29,6 +30,7 @@ class Program (val name: String,
|
||||
val heap = HeapValues()
|
||||
val program = mutableListOf<Instruction>()
|
||||
val variables = mutableMapOf<String, Value>()
|
||||
val memoryPointers = mutableMapOf<String, Pair<Int, DataType>>()
|
||||
val labels = mutableMapOf<String, Instruction>()
|
||||
|
||||
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<IndexedValue<String>>,
|
||||
heap: HeapValues,
|
||||
program: MutableList<Instruction>,
|
||||
variables: MutableMap<String, Value>,
|
||||
memoryPointers: MutableMap<String, Pair<Int, DataType>>,
|
||||
labels: MutableMap<String, Instruction>)
|
||||
{
|
||||
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<IndexedValue<String>>,
|
||||
vars: MutableMap<String, Value>): Map<String, Value> {
|
||||
vars: MutableMap<String, Value>) {
|
||||
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<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>> {
|
||||
while(true) {
|
||||
val (lineNr, line) = lines.next()
|
||||
|
@ -104,6 +104,8 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
private set
|
||||
var variables = mutableMapOf<String, Value>() // all variables (set of all vars used by all blocks/subroutines) key = their fully scoped name
|
||||
private set
|
||||
var memoryPointers = mutableMapOf<String, Pair<Int, DataType>>() // all named pointers
|
||||
private set
|
||||
var evalstack = MyStack<Value>()
|
||||
private set
|
||||
var callstack = MyStack<Instruction>()
|
||||
@ -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 -> {
|
||||
|
@ -51,12 +51,13 @@ class TestStackVmOpcodes {
|
||||
|
||||
private val vm = StackVm(null)
|
||||
|
||||
fun makeProg(ins: MutableList<Instruction>,
|
||||
private fun makeProg(ins: MutableList<Instruction>,
|
||||
vars: Map<String, Value>?=null,
|
||||
memoryPointers: Map<String, Pair<Int, DataType>>?=null,
|
||||
labels: Map<String, Instruction>?=null,
|
||||
mem: Map<Int, List<Value>>?=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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user