This commit is contained in:
Irmen de Jong 2018-09-02 19:20:06 +02:00
parent e39ae3c346
commit 6d7d5a4d13
3 changed files with 267 additions and 179 deletions

View File

@ -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<Short> {
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<Short>, 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<Short> {
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<Short>, lowercase: Boolean = false): String {

View File

@ -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<Value>) {
data class Instruction(val opcode: Opcode,
val args: List<Value> = emptyList(),
val subArgAllocations: List<String> = 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<T> : Stack<T>() {
fun pop2() : Pair<T, T> = 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<Instruction> = listOf()
class Program (prog: List<Instruction>, labels: Map<String, Instruction>, val variables: Map<String, Value>) {
fun load(prog: List<Instruction>) {
this.prog = prog.plus(listOf(
val program: List<Instruction> = prog.plus(listOf(
Instruction(Opcode.TERMINATE, listOf()),
Instruction(Opcode.TERMINATE, listOf())
))
connectPointers()
init {
connect(labels)
}
fun connectPointers() {
val it1 = prog.iterator()
val it2 = prog.iterator()
private fun connect(labels: Map<String, Instruction>) {
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<Value>()
private val evalstack = MyStack<Value>() // evaluation stack
private val callstack = MyStack<Instruction>() // subroutine call stack (@todo maybe use evalstack as well for this?)
private var variables = mutableMapOf<String, Value>() // 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<Instruction>()
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<String>) {
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)
}

View File

@ -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<Short>(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<Short>(0x12))) // reverse vid
assertThat(Petscii.encodePetscii("", true), equalTo(listOf<Short>(0xfa)))
assertFailsWith<CompilerException> { Petscii.encodePetscii("π", true) }
assertFailsWith<CompilerException> { 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<Short>(72, 69, 76, 76, 79, 32, 49, 50, 51, 32, 64, 33, 0x5c)))
assertThat(Petscii.encodePetscii("\uf11a"), equalTo(listOf<Short>(0x12))) // reverse vid
assertThat(Petscii.encodePetscii(""), equalTo(listOf<Short>(0xd3)))
assertThat(Petscii.encodePetscii("π"), equalTo(listOf<Short>(0xff)))
assertFailsWith<CompilerException> { 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<Short>(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<Short>(0x7a)))
assertFailsWith<CompilerException> { Petscii.encodeScreencode("", true) }
assertFailsWith<CompilerException> { 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<Short>(0x17, 0x0f, 0x12, 0x0c, 0x04, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c)))
assertThat(Petscii.encodeScreencode(""), equalTo(listOf<Short>(0x53)))
assertThat(Petscii.encodeScreencode("π"), equalTo(listOf<Short>(0x5e)))
assertFailsWith<CompilerException> { Petscii.encodeScreencode("") }
assertFailsWith<CompilerException> { Petscii.encodeScreencode("hello") }