From 6d7d5a4d137e53a963156755e27d95c3bb4cc825 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 2 Sep 2018 19:20:06 +0200 Subject: [PATCH] tweaks --- il65/src/il65/compiler/Petscii.kt | 29 +-- il65/src/il65/stackvm/StackVm.kt | 393 ++++++++++++++++++------------ il65/test/UnitTests.kt | 24 +- 3 files changed, 267 insertions(+), 179 deletions(-) diff --git a/il65/src/il65/compiler/Petscii.kt b/il65/src/il65/compiler/Petscii.kt index ee10aee38..ed6a31396 100644 --- a/il65/src/il65/compiler/Petscii.kt +++ b/il65/src/il65/compiler/Petscii.kt @@ -1043,21 +1043,18 @@ class Petscii { ) // encoding: from unicode to Petscii/Screencodes (0-255) - private val encodingPetsciiLowercase = decodingPetsciiLowercase.mapIndexed { index, unicode -> Pair(unicode, index) }.toMap() - private val encodingPetsciiUppercase = decodingPetsciiUppercase.mapIndexed { index, unicode -> Pair(unicode, index) }.toMap() - private val encodingScreencodeLowercase = decodingScreencodeLowercase.mapIndexed { index, unicode -> Pair(unicode, index) }.toMap() - private val encodingScreencodeUppercase = decodingScreencodeUppercase.mapIndexed { index, unicode -> Pair(unicode, index) }.toMap() + private val encodingPetsciiLowercase = decodingPetsciiLowercase.withIndex().associate{it.value to it.index} + private val encodingPetsciiUppercase = decodingPetsciiUppercase.withIndex().associate{it.value to it.index} + private val encodingScreencodeLowercase = decodingScreencodeLowercase.withIndex().associate{it.value to it.index} + private val encodingScreencodeUppercase = decodingScreencodeUppercase.withIndex().associate{it.value to it.index} - fun encodePetscii(text: String, lowercase: Boolean = false): ShortArray { - val result = ShortArray(text.length) + fun encodePetscii(text: String, lowercase: Boolean = false): List { val lookup = if(lowercase) encodingPetsciiLowercase else encodingPetsciiUppercase - text.forEachIndexed { index, c -> - val petscii = lookup[c] ?: throw CompilerException("no Petscii character for '$c'") - result[index] = petscii.toShort() + return text.map { + val petscii = lookup[it] ?: throw CompilerException("no Petscii character for '$it'") + petscii.toShort() } - - return result } fun decodePetscii(petscii: Iterable, lowercase: Boolean = false): String { @@ -1065,14 +1062,12 @@ class Petscii { return petscii.map { decodeTable[it.toInt()] }.joinToString("") } - fun encodeScreencode(text: String, lowercase: Boolean = false): ShortArray { - val result = ShortArray(text.length) + fun encodeScreencode(text: String, lowercase: Boolean = false): List { val lookup = if(lowercase) encodingScreencodeLowercase else encodingScreencodeUppercase - text.forEachIndexed { index, c -> - val screencode = lookup[c] ?: throw CompilerException("no Screencode character for '$c'") - result[index] = screencode.toShort() + return text.map{ + val screencode = lookup[it] ?: throw CompilerException("no Screencode character for '$it'") + screencode.toShort() } - return result } fun decodeScreencode(screencode: Iterable, lowercase: Boolean = false): String { diff --git a/il65/src/il65/stackvm/StackVm.kt b/il65/src/il65/stackvm/StackVm.kt index 1d6836592..a3e623746 100644 --- a/il65/src/il65/stackvm/StackVm.kt +++ b/il65/src/il65/stackvm/StackVm.kt @@ -3,7 +3,7 @@ package il65.stackvm import il65.ast.DataType import il65.compiler.Mflpt5 import il65.compiler.Petscii -import java.io.FileOutputStream +import java.io.File import java.io.PrintWriter import java.util.* import kotlin.math.max @@ -13,12 +13,13 @@ enum class Opcode { // pushing values on the (evaluation) stack PUSH, // push constant byte value - PUSH_LOCAL, // push block-local variable + PUSH_VAR, // push a variable + DUP, // push topmost value once again // popping values off the (evaluation) stack, possibly storing them in another location DISCARD, // discard X bytes from the top of the stack POP_MEM, // pop value into destination memory address - POP_LOCAL, // pop value into block-local variable + POP_VAR, // pop value into variable // numeric and bitwise arithmetic ADD, @@ -30,27 +31,27 @@ enum class Opcode { SHL, SHL_MEM, SHL_MEM_W, - SHL_LOCAL, + SHL_VAR, SHR, SHR_MEM, SHR_MEM_W, - SHR_LOCAL, + SHR_VAR, ROL, ROL_MEM, ROL_MEM_W, - ROL_LOCAL, + ROL_VAR, ROR, ROR_MEM, ROR_MEM_W, - ROR_LOCAL, + ROR_VAR, ROL2, ROL2_MEM, ROL2_MEM_W, - ROL2_LOCAL, + ROL2_VAR, ROR2, ROR2_MEM, ROR2_MEM_W, - ROR2_LOCAL, + ROR2_VAR, AND, OR, XOR, @@ -62,16 +63,24 @@ enum class Opcode { INC, INC_MEM, INC_MEM_W, - INC_LOCAL, + INC_VAR, DEC, DEC_MEM, DEC_MEM_W, - DEC_LOCAL, + DEC_VAR, // comparisons (?) // branching JUMP, + BCS, + BCC, + //BEQ, // @todo not implemented status flag Z + //BNE, // @todo not implemented status flag Z + //BVS, // @todo not implemented status flag V + //BVC, // @todo not implemented status flag V + //BMI, // @todo not implemented status flag N + //BPL, // @todo not implemented status flag N // subroutine calling CALL, @@ -79,16 +88,18 @@ enum class Opcode { SYSCALL, // misc + SWAP, SEC, CLC, TERMINATE } enum class Syscall(val callNr: Short) { - WRITECHR(10), - WRITESTR(11), - WRITE_NUM(12), - WRITE_CHAR(13) + WRITE_MEMCHR(10), // print a single char from the memory + WRITE_MEMSTR(11), // print a 0-terminated petscii string from the memory + WRITE_NUM(12), // pop from the evaluation stack and print it as a number + WRITE_CHAR(13), // pop from the evaluation stack and print it as a single petscii character + WRITE_VAR(14), // print the number or string from the given variable } class Memory { @@ -148,27 +159,31 @@ class Memory { } -data class Value(val type: DataType, private val value: Number) -{ +data class Value(val type: DataType, private val numericvalue: Number?, val stringvalue: String?=null) { private var byteval: Short? = null private var wordval: Int? = null private var floatval: Double? = null init { when(type) { - DataType.BYTE -> byteval = (value.toInt() and 255).toShort() - DataType.WORD -> wordval = value.toInt() and 65535 - DataType.FLOAT -> floatval = value.toDouble() - else -> throw VmExecutionException("invalid value datatype $type") + DataType.BYTE -> byteval = (numericvalue!!.toInt() and 255).toShort() + DataType.WORD -> wordval = numericvalue!!.toInt() and 65535 + DataType.FLOAT -> floatval = numericvalue!!.toDouble() + DataType.STR -> if(stringvalue==null) throw VmExecutionException("expect stringvalue for STR type") + else -> throw VmExecutionException("invalid datatype $type") } } + override fun toString(): String { + return "$type: $numericvalue $stringvalue" + } + fun numericValue(): Number { return when(type) { DataType.BYTE -> byteval!! DataType.WORD-> wordval!! DataType.FLOAT -> floatval!! - else -> throw VmExecutionException("invalid datatype") + else -> throw VmExecutionException("invalid datatype for numeric value: $type") } } @@ -177,7 +192,7 @@ data class Value(val type: DataType, private val value: Number) DataType.BYTE -> byteval!!.toInt() DataType.WORD-> wordval!! DataType.FLOAT -> floatval!!.toInt() - else -> throw VmExecutionException("invalid datatype") + else -> throw VmExecutionException("invalid datatype for integer value: $type") } } @@ -360,9 +375,25 @@ data class Value(val type: DataType, private val value: Number) } -data class Instruction(val opcode: Opcode, val args: List) { +data class Instruction(val opcode: Opcode, + val args: List = emptyList(), + val subArgAllocations: List = emptyList(), + val callLabel: String? = null) { lateinit var next: Instruction var nextAlt: Instruction? = null + + init { + if(callLabel!=null) { + if(args.size!=subArgAllocations.size) + throw VmExecutionException("for $opcode the subArgAllocations size is not the same as the arg list size") + } + } + override fun toString(): String { + return if(callLabel==null) + "$opcode $args" + else + "$opcode $callLabel $args $subArgAllocations" + } } @@ -377,72 +408,92 @@ private class MyStack : Stack() { fun pop2() : Pair = Pair(pop(), pop()) - fun printTop(amount: Int) { - peek(amount).reversed().forEach { println(" $it") } + fun printTop(amount: Int, output: PrintWriter) { + peek(amount).reversed().forEach { output.println(" $it") } } } -class Program { - var prog: List = listOf() +class Program (prog: List, labels: Map, val variables: Map) { - fun load(prog: List) { - this.prog = prog.plus(listOf( - Instruction(Opcode.TERMINATE, listOf()), - Instruction(Opcode.TERMINATE, listOf()) - )) - connectPointers() + val program: List = prog.plus(listOf( + Instruction(Opcode.TERMINATE, listOf()), + Instruction(Opcode.TERMINATE, listOf()) + )) + + init { + connect(labels) } - fun connectPointers() { - val it1 = prog.iterator() - val it2 = prog.iterator() + private fun connect(labels: Map) { + val it1 = program.iterator() + val it2 = program.iterator() it2.next() while(it1.hasNext() && it2.hasNext()) { val instr = it1.next() val nextInstr = it2.next() when(instr.opcode) { - Opcode.TERMINATE -> instr.next = instr - Opcode.CALL -> TODO() - Opcode.JUMP -> TODO() - Opcode.RETURN -> TODO() + Opcode.TERMINATE -> instr.next = instr // won't ever execute a next instruction + Opcode.RETURN -> instr.next = instr // kinda a special one, in actuality the return instruction is dynamic + Opcode.JUMP -> labels[instr.callLabel]?.let {instr.next=it} + Opcode.BCC -> labels[instr.callLabel]?.let {instr.next=it} + Opcode.BCS -> labels[instr.callLabel]?.let {instr.next=it} + Opcode.CALL -> { + val jumpInstr = labels[instr.callLabel] ?: throw VmExecutionException("undefined label: ${instr.callLabel}") + instr.next=jumpInstr + instr.nextAlt = nextInstr // instruction to return to + } else -> instr.next = nextInstr } } } } -class StackVm(val vmOutputFile: String) { + +class StackVm(val traceOutputFile: String?) { val mem = Memory() - private val es = MyStack() + private val evalstack = MyStack() // evaluation stack + private val callstack = MyStack() // subroutine call stack (@todo maybe use evalstack as well for this?) + private var variables = mutableMapOf() // all variables (set of all vars used by all blocks/subroutines) key = their fully scoped name private var carry: Boolean = false private var program = listOf() - private var output = PrintWriter(FileOutputStream(vmOutputFile, true)) + private var traceOutput = if(traceOutputFile!=null) File(traceOutputFile).printWriter() else null fun run(program: Program) { - this.program = program.prog + this.program = program.program + this.variables = program.variables.toMutableMap() var ins = this.program[0] - output.println("---- new session at ${Date()} ----") try { while (true) { ins = dispatch(ins) + + if(evalstack.size > 128) + throw VmExecutionException("too many values on evaluation stack") + if(callstack.size > 128) + throw VmExecutionException("too many nested/recursive calls") } } catch (x: VmTerminationException) { - output.println("---- session ended ----") - output.flush() - output.close() - println("Execution terminated.") + println("\n\nExecution terminated.") + } finally { + traceOutput?.close() } + } fun dispatch(ins: Instruction) : Instruction { - println("dispatching: $ins") + traceOutput?.println("\n$ins") when (ins.opcode) { - Opcode.PUSH -> es.push(ins.args[0]) - Opcode.DISCARD -> es.pop() + Opcode.PUSH -> evalstack.push(ins.args[0]) + Opcode.DUP -> evalstack.push(evalstack.peek()) + Opcode.DISCARD -> evalstack.pop() + Opcode.SWAP -> { + val (top, second) = evalstack.pop2() + evalstack.push(top) + evalstack.push(second) + } Opcode.POP_MEM -> { - val value = es.pop() + val value = evalstack.pop() val address = ins.args[0].integerValue() when (value.type) { DataType.BYTE -> mem.setByte(address, value.integerValue().toShort()) @@ -452,89 +503,98 @@ class StackVm(val vmOutputFile: String) { } } Opcode.ADD -> { - val (top, second) = es.pop2() - es.push(second.add(top)) + val (top, second) = evalstack.pop2() + evalstack.push(second.add(top)) } Opcode.SUB -> { - val (top, second) = es.pop2() - es.push(second.sub(top)) + val (top, second) = evalstack.pop2() + evalstack.push(second.sub(top)) } Opcode.MUL -> { - val (top, second) = es.pop2() - es.push(second.mul(top)) + val (top, second) = evalstack.pop2() + evalstack.push(second.mul(top)) } Opcode.DIV -> { - val (top, second) = es.pop2() - es.push(second.div(top)) + val (top, second) = evalstack.pop2() + evalstack.push(second.div(top)) } Opcode.POW -> { - val (top, second) = es.pop2() - es.push(second.pow(top)) + val (top, second) = evalstack.pop2() + evalstack.push(second.pow(top)) } Opcode.NEG -> { - val v = es.pop() - es.push(v.neg()) + val v = evalstack.pop() + evalstack.push(v.neg()) } Opcode.SHL -> { - val v = es.pop() - es.push(v.shl()) + val v = evalstack.pop() + evalstack.push(v.shl()) } Opcode.SHR -> { - val v = es.pop() - es.push(v.shr()) + val v = evalstack.pop() + evalstack.push(v.shr()) } Opcode.ROL -> { - val v = es.pop() + val v = evalstack.pop() val (result, newCarry) = v.rol(carry) this.carry = newCarry - es.push(result) + evalstack.push(result) } Opcode.ROL2 -> { - val v = es.pop() - es.push(v.rol2()) + val v = evalstack.pop() + evalstack.push(v.rol2()) } Opcode.ROR -> { - val v = es.pop() + val v = evalstack.pop() val (result, newCarry) = v.ror(carry) this.carry = newCarry - es.push(result) + evalstack.push(result) } Opcode.ROR2 -> { - val v = es.pop() - es.push(v.ror2()) + val v = evalstack.pop() + evalstack.push(v.ror2()) } Opcode.AND -> { - val (top, second) = es.pop2() - es.push(second.and(top)) + val (top, second) = evalstack.pop2() + evalstack.push(second.and(top)) } Opcode.OR -> { - val (top, second) = es.pop2() - es.push(second.or(top)) + val (top, second) = evalstack.pop2() + evalstack.push(second.or(top)) } Opcode.XOR -> { - val (top, second) = es.pop2() - es.push(second.xor(top)) + val (top, second) = evalstack.pop2() + evalstack.push(second.xor(top)) } Opcode.INV -> { - val v = es.pop() - es.push(v.inv()) + val v = evalstack.pop() + evalstack.push(v.inv()) } Opcode.INC -> { - val v = es.pop() - es.push(v.inc()) + val v = evalstack.pop() + evalstack.push(v.inc()) } Opcode.DEC -> { - val v = es.pop() - es.push(v.dec()) + val v = evalstack.pop() + evalstack.push(v.dec()) } Opcode.SYSCALL -> { val callId = ins.args[0].integerValue().toShort() val syscall = Syscall.values().first { it.callNr == callId } when (syscall) { - Syscall.WRITECHR -> output.print(Petscii.decodePetscii(listOf(mem.getByte(ins.args[1].integerValue())), true)) - Syscall.WRITESTR -> output.print(mem.getString(ins.args[1].integerValue())) - Syscall.WRITE_NUM -> output.print(es.pop().numericValue()) - Syscall.WRITE_CHAR -> output.print(Petscii.decodePetscii(listOf(es.pop().integerValue().toShort()), true)) + Syscall.WRITE_MEMCHR -> print(Petscii.decodePetscii(listOf(mem.getByte(ins.args[1].integerValue())), true)) + Syscall.WRITE_MEMSTR -> print(mem.getString(ins.args[1].integerValue())) + Syscall.WRITE_NUM -> print(evalstack.pop().numericValue()) + Syscall.WRITE_CHAR -> print(Petscii.decodePetscii(listOf(evalstack.pop().integerValue().toShort()), true)) + Syscall.WRITE_VAR -> { + val varname = ins.args[1].stringvalue ?: throw VmExecutionException("$syscall expects string argument (the variable name)") + val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname") + when(variable.type) { + DataType.BYTE, DataType.WORD, DataType.FLOAT -> print(variable.numericValue()) + DataType.STR -> print(variable.stringvalue) + else -> throw VmExecutionException("invalid datatype") + } + } else -> throw VmExecutionException("unimplemented syscall $syscall") } } @@ -640,22 +700,73 @@ class StackVm(val vmOutputFile: String) { mem.setWord(addr, newValue.integerValue()) } - Opcode.JUMP -> {} // do nothing; the next instruction is wired up already - Opcode.CALL -> TODO() - Opcode.RETURN -> TODO() - Opcode.PUSH_LOCAL -> TODO() - Opcode.POP_LOCAL -> TODO() - Opcode.INC_LOCAL -> TODO() - Opcode.DEC_LOCAL -> TODO() - Opcode.SHL_LOCAL -> TODO() - Opcode.SHR_LOCAL -> TODO() - Opcode.ROL_LOCAL -> TODO() - Opcode.ROR_LOCAL -> TODO() - Opcode.ROL2_LOCAL -> TODO() - Opcode.ROR2_LOCAL -> TODO() + Opcode.JUMP -> {} // do nothing; the next instruction is wired up already to the jump target + Opcode.BCS -> return if(carry) ins.next else ins.nextAlt!! + Opcode.BCC -> return if(carry) ins.nextAlt!! else ins.next + Opcode.CALL -> callstack.push(ins.nextAlt) + Opcode.RETURN -> return callstack.pop() + Opcode.PUSH_VAR -> { + val varname = ins.args[0].stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)") + val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname") + evalstack.push(variable) + } + Opcode.POP_VAR -> { + val value = evalstack.pop() + val varname = ins.args[0].stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)") + val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname") + if(variable.type!=value.type) throw VmExecutionException("value datatype ${value.type} is not the same as variable datatype ${variable.type}") + variables[varname] = value + } + Opcode.SHL_VAR -> { + val varname = ins.args[0].stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)") + val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname") + variables[varname] = variable.shl() + } + Opcode.SHR_VAR -> { + val varname = ins.args[0].stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)") + val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname") + variables[varname] = variable.shr() + } + Opcode.ROL_VAR -> { + val varname = ins.args[0].stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)") + val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname") + val (newValue, newCarry) = variable.rol(carry) + variables[varname] = newValue + carry = newCarry + } + Opcode.ROR_VAR -> { + val varname = ins.args[0].stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)") + val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname") + val (newValue, newCarry) = variable.ror(carry) + variables[varname] = newValue + carry = newCarry + } + Opcode.ROL2_VAR -> { + val varname = ins.args[0].stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)") + val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname") + variables[varname] = variable.rol2() + } + Opcode.ROR2_VAR -> { + val varname = ins.args[0].stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)") + val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname") + variables[varname] = variable.ror2() + } + Opcode.INC_VAR -> { + val varname = ins.args[0].stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)") + val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname") + variables[varname] = variable.inc() + } + Opcode.DEC_VAR -> { + val varname = ins.args[0].stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)") + val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname") + variables[varname] = variable.dec() + } + } + + if(traceOutput!=null) { + traceOutput?.println(" evalstack (size=${evalstack.size}):") + evalstack.printTop(4, traceOutput!!) } - println(" es:") - es.printTop(5) return ins.next } @@ -663,47 +774,29 @@ class StackVm(val vmOutputFile: String) { fun main(args: Array) { - val vm = StackVm(vmOutputFile = "vmout.txt") - val program = Program() - program.load(listOf( - Instruction(Opcode.PUSH, listOf(Value(DataType.BYTE, 100))), - Instruction(Opcode.PUSH, listOf(Value(DataType.BYTE, 133))), - Instruction(Opcode.ADD, emptyList()), - Instruction(Opcode.PUSH, listOf(Value(DataType.BYTE, 3))), - Instruction(Opcode.DIV, emptyList()), - Instruction(Opcode.INC, emptyList()), - Instruction(Opcode.PUSH, listOf(Value(DataType.BYTE, 2))), - Instruction(Opcode.SHR, emptyList()), - Instruction(Opcode.SYSCALL, listOf(Value(DataType.BYTE, Syscall.WRITESTR.callNr), Value(DataType.WORD, 0x1000))), - Instruction(Opcode.SYSCALL, listOf(Value(DataType.BYTE, Syscall.WRITE_NUM.callNr))), - Instruction(Opcode.PUSH, listOf(Value(DataType.BYTE, Petscii.encodePetscii("@", true)[0]))), - Instruction(Opcode.SYSCALL, listOf(Value(DataType.BYTE, Syscall.WRITE_CHAR.callNr))), - - Instruction(Opcode.CLC, emptyList()), - Instruction(Opcode.PUSH, listOf(Value(DataType.WORD, 2))), - Instruction(Opcode.ROR2, emptyList()), - Instruction(Opcode.ROR2, emptyList()), - Instruction(Opcode.ROR2, emptyList()), - Instruction(Opcode.ROR2, emptyList()), - Instruction(Opcode.ROR2, emptyList()), - Instruction(Opcode.ROR2, emptyList()), - Instruction(Opcode.ROR2, emptyList()), - Instruction(Opcode.ROR2, emptyList()), - Instruction(Opcode.ROR2, emptyList()), - Instruction(Opcode.ROR2, emptyList()), - Instruction(Opcode.CLC, emptyList()), - Instruction(Opcode.PUSH, listOf(Value(DataType.WORD, 16384))), - Instruction(Opcode.ROL2, emptyList()), - Instruction(Opcode.ROL2, emptyList()), - Instruction(Opcode.ROL2, emptyList()), - Instruction(Opcode.ROL2, emptyList()), - Instruction(Opcode.ROL2, emptyList()), - Instruction(Opcode.ROL2, emptyList()), - Instruction(Opcode.ROL2, emptyList()), - Instruction(Opcode.ROL2, emptyList()), - Instruction(Opcode.ROL2, emptyList()), - Instruction(Opcode.ROL2, emptyList()) - )) + val vm = StackVm(traceOutputFile = "vmtrace.txt") vm.mem.setString(0x1000, "Hallo!\n") + + val instructions = listOf( + Instruction(Opcode.SYSCALL, listOf(Value(DataType.BYTE, Syscall.WRITE_VAR.callNr), Value(DataType.STR, null, stringvalue = "main.var1"))), + Instruction(Opcode.SYSCALL, listOf(Value(DataType.BYTE, Syscall.WRITE_MEMSTR.callNr), Value(DataType.WORD, 0x1000))), + Instruction(Opcode.SYSCALL, listOf(Value(DataType.BYTE, Syscall.WRITE_VAR.callNr), Value(DataType.STR, null, "main.var2"))), + Instruction(Opcode.PUSH, listOf(Value(DataType.WORD, 12345))), + Instruction(Opcode.POP_VAR, listOf(Value(DataType.STR, null, "main.var2"))), + Instruction(Opcode.SYSCALL, listOf(Value(DataType.BYTE, Syscall.WRITE_VAR.callNr), Value(DataType.STR, null, "main.var2"))), + Instruction(Opcode.DEC_VAR, listOf(Value(DataType.STR, null, "main.var2"))), + Instruction(Opcode.SYSCALL, listOf(Value(DataType.BYTE, Syscall.WRITE_VAR.callNr), Value(DataType.STR, null, "main.var2"))), + Instruction(Opcode.SHR_VAR, listOf(Value(DataType.STR, null, "main.var2"))), + Instruction(Opcode.SYSCALL, listOf(Value(DataType.BYTE, Syscall.WRITE_VAR.callNr), Value(DataType.STR, null, "main.var2"))), + Instruction(Opcode.TERMINATE) + ) + + val labels = listOf(Pair("derp", instructions[0])).toMap() + val variables = mapOf( + "main.var1" to Value(DataType.STR, null, "Dit is variabele main.var1!\n"), + "main.var2" to Value(DataType.WORD, 9999) + ) + + val program = Program(instructions, labels, variables) vm.run(program) } \ No newline at end of file diff --git a/il65/test/UnitTests.kt b/il65/test/UnitTests.kt index 7a7b47b6d..a5e4f7d28 100644 --- a/il65/test/UnitTests.kt +++ b/il65/test/UnitTests.kt @@ -210,9 +210,9 @@ class TestPetscii { @Test fun testLowercase() { assertThat(Petscii.encodePetscii("hello WORLD 123 @!£", true), equalTo( - shortArrayOf(72, 69, 76, 76, 79, 32, 0xd7, 0xcf, 0xd2, 0xcc, 0xc4, 32, 49, 50, 51, 32, 64, 33, 0x5c))) - assertThat(Petscii.encodePetscii("\uf11a", true), equalTo(shortArrayOf(0x12))) // reverse vid - assertThat(Petscii.encodePetscii("✓", true), equalTo(shortArrayOf(0xfa))) + listOf(72, 69, 76, 76, 79, 32, 0xd7, 0xcf, 0xd2, 0xcc, 0xc4, 32, 49, 50, 51, 32, 64, 33, 0x5c))) + assertThat(Petscii.encodePetscii("\uf11a", true), equalTo(listOf(0x12))) // reverse vid + assertThat(Petscii.encodePetscii("✓", true), equalTo(listOf(0xfa))) assertFailsWith { Petscii.encodePetscii("π", true) } assertFailsWith { Petscii.encodePetscii("♥", true) } @@ -224,10 +224,10 @@ class TestPetscii { @Test fun testUppercase() { assertThat(Petscii.encodePetscii("HELLO 123 @!£"), equalTo( - shortArrayOf(72, 69, 76, 76, 79, 32, 49, 50, 51, 32, 64, 33, 0x5c))) - assertThat(Petscii.encodePetscii("\uf11a"), equalTo(shortArrayOf(0x12))) // reverse vid - assertThat(Petscii.encodePetscii("♥"), equalTo(shortArrayOf(0xd3))) - assertThat(Petscii.encodePetscii("π"), equalTo(shortArrayOf(0xff))) + listOf(72, 69, 76, 76, 79, 32, 49, 50, 51, 32, 64, 33, 0x5c))) + assertThat(Petscii.encodePetscii("\uf11a"), equalTo(listOf(0x12))) // reverse vid + assertThat(Petscii.encodePetscii("♥"), equalTo(listOf(0xd3))) + assertThat(Petscii.encodePetscii("π"), equalTo(listOf(0xff))) assertFailsWith { Petscii.encodePetscii("✓") } assertThat(Petscii.decodePetscii(listOf(72, 0x5c, 0xd3, 0xff)), equalTo("H£♥π")) @@ -238,9 +238,9 @@ class TestPetscii { @Test fun testScreencodeLowercase() { assertThat(Petscii.encodeScreencode("hello WORLD 123 @!£", true), equalTo( - shortArrayOf(0x08, 0x05, 0x0c, 0x0c, 0x0f, 0x20, 0x57, 0x4f, 0x52, 0x4c, 0x44, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c) + listOf(0x08, 0x05, 0x0c, 0x0c, 0x0f, 0x20, 0x57, 0x4f, 0x52, 0x4c, 0x44, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c) )) - assertThat(Petscii.encodeScreencode("✓", true), equalTo(shortArrayOf(0x7a))) + assertThat(Petscii.encodeScreencode("✓", true), equalTo(listOf(0x7a))) assertFailsWith { Petscii.encodeScreencode("♥", true) } assertFailsWith { Petscii.encodeScreencode("π", true) } @@ -252,9 +252,9 @@ class TestPetscii { @Test fun testScreencodeUppercase() { assertThat(Petscii.encodeScreencode("WORLD 123 @!£"), equalTo( - shortArrayOf(0x17, 0x0f, 0x12, 0x0c, 0x04, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c))) - assertThat(Petscii.encodeScreencode("♥"), equalTo(shortArrayOf(0x53))) - assertThat(Petscii.encodeScreencode("π"), equalTo(shortArrayOf(0x5e))) + listOf(0x17, 0x0f, 0x12, 0x0c, 0x04, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c))) + assertThat(Petscii.encodeScreencode("♥"), equalTo(listOf(0x53))) + assertThat(Petscii.encodeScreencode("π"), equalTo(listOf(0x5e))) assertFailsWith { Petscii.encodeScreencode("✓") } assertFailsWith { Petscii.encodeScreencode("hello") }