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) // encoding: from unicode to Petscii/Screencodes (0-255)
private val encodingPetsciiLowercase = decodingPetsciiLowercase.mapIndexed { index, unicode -> Pair(unicode, index) }.toMap() private val encodingPetsciiLowercase = decodingPetsciiLowercase.withIndex().associate{it.value to it.index}
private val encodingPetsciiUppercase = decodingPetsciiUppercase.mapIndexed { index, unicode -> Pair(unicode, index) }.toMap() private val encodingPetsciiUppercase = decodingPetsciiUppercase.withIndex().associate{it.value to it.index}
private val encodingScreencodeLowercase = decodingScreencodeLowercase.mapIndexed { index, unicode -> Pair(unicode, index) }.toMap() private val encodingScreencodeLowercase = decodingScreencodeLowercase.withIndex().associate{it.value to it.index}
private val encodingScreencodeUppercase = decodingScreencodeUppercase.mapIndexed { index, unicode -> Pair(unicode, index) }.toMap() private val encodingScreencodeUppercase = decodingScreencodeUppercase.withIndex().associate{it.value to it.index}
fun encodePetscii(text: String, lowercase: Boolean = false): ShortArray { fun encodePetscii(text: String, lowercase: Boolean = false): List<Short> {
val result = ShortArray(text.length)
val lookup = if(lowercase) encodingPetsciiLowercase else encodingPetsciiUppercase val lookup = if(lowercase) encodingPetsciiLowercase else encodingPetsciiUppercase
text.forEachIndexed { index, c -> return text.map {
val petscii = lookup[c] ?: throw CompilerException("no Petscii character for '$c'") val petscii = lookup[it] ?: throw CompilerException("no Petscii character for '$it'")
result[index] = petscii.toShort() petscii.toShort()
} }
return result
} }
fun decodePetscii(petscii: Iterable<Short>, lowercase: Boolean = false): String { fun decodePetscii(petscii: Iterable<Short>, lowercase: Boolean = false): String {
@ -1065,14 +1062,12 @@ class Petscii {
return petscii.map { decodeTable[it.toInt()] }.joinToString("") return petscii.map { decodeTable[it.toInt()] }.joinToString("")
} }
fun encodeScreencode(text: String, lowercase: Boolean = false): ShortArray { fun encodeScreencode(text: String, lowercase: Boolean = false): List<Short> {
val result = ShortArray(text.length)
val lookup = if(lowercase) encodingScreencodeLowercase else encodingScreencodeUppercase val lookup = if(lowercase) encodingScreencodeLowercase else encodingScreencodeUppercase
text.forEachIndexed { index, c -> return text.map{
val screencode = lookup[c] ?: throw CompilerException("no Screencode character for '$c'") val screencode = lookup[it] ?: throw CompilerException("no Screencode character for '$it'")
result[index] = screencode.toShort() screencode.toShort()
} }
return result
} }
fun decodeScreencode(screencode: Iterable<Short>, lowercase: Boolean = false): String { fun decodeScreencode(screencode: Iterable<Short>, lowercase: Boolean = false): String {

View File

@ -3,7 +3,7 @@ package il65.stackvm
import il65.ast.DataType import il65.ast.DataType
import il65.compiler.Mflpt5 import il65.compiler.Mflpt5
import il65.compiler.Petscii import il65.compiler.Petscii
import java.io.FileOutputStream import java.io.File
import java.io.PrintWriter import java.io.PrintWriter
import java.util.* import java.util.*
import kotlin.math.max import kotlin.math.max
@ -13,12 +13,13 @@ enum class Opcode {
// pushing values on the (evaluation) stack // pushing values on the (evaluation) stack
PUSH, // push constant byte value 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 // popping values off the (evaluation) stack, possibly storing them in another location
DISCARD, // discard X bytes from the top of the stack DISCARD, // discard X bytes from the top of the stack
POP_MEM, // pop value into destination memory address 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 // numeric and bitwise arithmetic
ADD, ADD,
@ -30,27 +31,27 @@ enum class Opcode {
SHL, SHL,
SHL_MEM, SHL_MEM,
SHL_MEM_W, SHL_MEM_W,
SHL_LOCAL, SHL_VAR,
SHR, SHR,
SHR_MEM, SHR_MEM,
SHR_MEM_W, SHR_MEM_W,
SHR_LOCAL, SHR_VAR,
ROL, ROL,
ROL_MEM, ROL_MEM,
ROL_MEM_W, ROL_MEM_W,
ROL_LOCAL, ROL_VAR,
ROR, ROR,
ROR_MEM, ROR_MEM,
ROR_MEM_W, ROR_MEM_W,
ROR_LOCAL, ROR_VAR,
ROL2, ROL2,
ROL2_MEM, ROL2_MEM,
ROL2_MEM_W, ROL2_MEM_W,
ROL2_LOCAL, ROL2_VAR,
ROR2, ROR2,
ROR2_MEM, ROR2_MEM,
ROR2_MEM_W, ROR2_MEM_W,
ROR2_LOCAL, ROR2_VAR,
AND, AND,
OR, OR,
XOR, XOR,
@ -62,16 +63,24 @@ enum class Opcode {
INC, INC,
INC_MEM, INC_MEM,
INC_MEM_W, INC_MEM_W,
INC_LOCAL, INC_VAR,
DEC, DEC,
DEC_MEM, DEC_MEM,
DEC_MEM_W, DEC_MEM_W,
DEC_LOCAL, DEC_VAR,
// comparisons (?) // comparisons (?)
// branching // branching
JUMP, 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 // subroutine calling
CALL, CALL,
@ -79,16 +88,18 @@ enum class Opcode {
SYSCALL, SYSCALL,
// misc // misc
SWAP,
SEC, SEC,
CLC, CLC,
TERMINATE TERMINATE
} }
enum class Syscall(val callNr: Short) { enum class Syscall(val callNr: Short) {
WRITECHR(10), WRITE_MEMCHR(10), // print a single char from the memory
WRITESTR(11), WRITE_MEMSTR(11), // print a 0-terminated petscii string from the memory
WRITE_NUM(12), WRITE_NUM(12), // pop from the evaluation stack and print it as a number
WRITE_CHAR(13) 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 { 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 byteval: Short? = null
private var wordval: Int? = null private var wordval: Int? = null
private var floatval: Double? = null private var floatval: Double? = null
init { init {
when(type) { when(type) {
DataType.BYTE -> byteval = (value.toInt() and 255).toShort() DataType.BYTE -> byteval = (numericvalue!!.toInt() and 255).toShort()
DataType.WORD -> wordval = value.toInt() and 65535 DataType.WORD -> wordval = numericvalue!!.toInt() and 65535
DataType.FLOAT -> floatval = value.toDouble() DataType.FLOAT -> floatval = numericvalue!!.toDouble()
else -> throw VmExecutionException("invalid value datatype $type") 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 { fun numericValue(): Number {
return when(type) { return when(type) {
DataType.BYTE -> byteval!! DataType.BYTE -> byteval!!
DataType.WORD-> wordval!! DataType.WORD-> wordval!!
DataType.FLOAT -> floatval!! 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.BYTE -> byteval!!.toInt()
DataType.WORD-> wordval!! DataType.WORD-> wordval!!
DataType.FLOAT -> floatval!!.toInt() 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 lateinit var next: Instruction
var nextAlt: Instruction? = null 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 pop2() : Pair<T, T> = Pair(pop(), pop())
fun printTop(amount: Int) { fun printTop(amount: Int, output: PrintWriter) {
peek(amount).reversed().forEach { println(" $it") } peek(amount).reversed().forEach { output.println(" $it") }
} }
} }
class Program { class Program (prog: List<Instruction>, labels: Map<String, Instruction>, val variables: Map<String, Value>) {
var prog: List<Instruction> = listOf()
fun load(prog: List<Instruction>) { val program: List<Instruction> = prog.plus(listOf(
this.prog = prog.plus(listOf( Instruction(Opcode.TERMINATE, listOf()),
Instruction(Opcode.TERMINATE, listOf()), Instruction(Opcode.TERMINATE, listOf())
Instruction(Opcode.TERMINATE, listOf()) ))
))
connectPointers() init {
connect(labels)
} }
fun connectPointers() { private fun connect(labels: Map<String, Instruction>) {
val it1 = prog.iterator() val it1 = program.iterator()
val it2 = prog.iterator() val it2 = program.iterator()
it2.next() it2.next()
while(it1.hasNext() && it2.hasNext()) { while(it1.hasNext() && it2.hasNext()) {
val instr = it1.next() val instr = it1.next()
val nextInstr = it2.next() val nextInstr = it2.next()
when(instr.opcode) { when(instr.opcode) {
Opcode.TERMINATE -> instr.next = instr Opcode.TERMINATE -> instr.next = instr // won't ever execute a next instruction
Opcode.CALL -> TODO() Opcode.RETURN -> instr.next = instr // kinda a special one, in actuality the return instruction is dynamic
Opcode.JUMP -> TODO() Opcode.JUMP -> labels[instr.callLabel]?.let {instr.next=it}
Opcode.RETURN -> TODO() 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 else -> instr.next = nextInstr
} }
} }
} }
} }
class StackVm(val vmOutputFile: String) {
class StackVm(val traceOutputFile: String?) {
val mem = Memory() 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 carry: Boolean = false
private var program = listOf<Instruction>() 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) { fun run(program: Program) {
this.program = program.prog this.program = program.program
this.variables = program.variables.toMutableMap()
var ins = this.program[0] var ins = this.program[0]
output.println("---- new session at ${Date()} ----")
try { try {
while (true) { while (true) {
ins = dispatch(ins) 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) { } catch (x: VmTerminationException) {
output.println("---- session ended ----") println("\n\nExecution terminated.")
output.flush() } finally {
output.close() traceOutput?.close()
println("Execution terminated.")
} }
} }
fun dispatch(ins: Instruction) : Instruction { fun dispatch(ins: Instruction) : Instruction {
println("dispatching: $ins") traceOutput?.println("\n$ins")
when (ins.opcode) { when (ins.opcode) {
Opcode.PUSH -> es.push(ins.args[0]) Opcode.PUSH -> evalstack.push(ins.args[0])
Opcode.DISCARD -> es.pop() 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 -> { Opcode.POP_MEM -> {
val value = es.pop() val value = evalstack.pop()
val address = ins.args[0].integerValue() val address = ins.args[0].integerValue()
when (value.type) { when (value.type) {
DataType.BYTE -> mem.setByte(address, value.integerValue().toShort()) DataType.BYTE -> mem.setByte(address, value.integerValue().toShort())
@ -452,89 +503,98 @@ class StackVm(val vmOutputFile: String) {
} }
} }
Opcode.ADD -> { Opcode.ADD -> {
val (top, second) = es.pop2() val (top, second) = evalstack.pop2()
es.push(second.add(top)) evalstack.push(second.add(top))
} }
Opcode.SUB -> { Opcode.SUB -> {
val (top, second) = es.pop2() val (top, second) = evalstack.pop2()
es.push(second.sub(top)) evalstack.push(second.sub(top))
} }
Opcode.MUL -> { Opcode.MUL -> {
val (top, second) = es.pop2() val (top, second) = evalstack.pop2()
es.push(second.mul(top)) evalstack.push(second.mul(top))
} }
Opcode.DIV -> { Opcode.DIV -> {
val (top, second) = es.pop2() val (top, second) = evalstack.pop2()
es.push(second.div(top)) evalstack.push(second.div(top))
} }
Opcode.POW -> { Opcode.POW -> {
val (top, second) = es.pop2() val (top, second) = evalstack.pop2()
es.push(second.pow(top)) evalstack.push(second.pow(top))
} }
Opcode.NEG -> { Opcode.NEG -> {
val v = es.pop() val v = evalstack.pop()
es.push(v.neg()) evalstack.push(v.neg())
} }
Opcode.SHL -> { Opcode.SHL -> {
val v = es.pop() val v = evalstack.pop()
es.push(v.shl()) evalstack.push(v.shl())
} }
Opcode.SHR -> { Opcode.SHR -> {
val v = es.pop() val v = evalstack.pop()
es.push(v.shr()) evalstack.push(v.shr())
} }
Opcode.ROL -> { Opcode.ROL -> {
val v = es.pop() val v = evalstack.pop()
val (result, newCarry) = v.rol(carry) val (result, newCarry) = v.rol(carry)
this.carry = newCarry this.carry = newCarry
es.push(result) evalstack.push(result)
} }
Opcode.ROL2 -> { Opcode.ROL2 -> {
val v = es.pop() val v = evalstack.pop()
es.push(v.rol2()) evalstack.push(v.rol2())
} }
Opcode.ROR -> { Opcode.ROR -> {
val v = es.pop() val v = evalstack.pop()
val (result, newCarry) = v.ror(carry) val (result, newCarry) = v.ror(carry)
this.carry = newCarry this.carry = newCarry
es.push(result) evalstack.push(result)
} }
Opcode.ROR2 -> { Opcode.ROR2 -> {
val v = es.pop() val v = evalstack.pop()
es.push(v.ror2()) evalstack.push(v.ror2())
} }
Opcode.AND -> { Opcode.AND -> {
val (top, second) = es.pop2() val (top, second) = evalstack.pop2()
es.push(second.and(top)) evalstack.push(second.and(top))
} }
Opcode.OR -> { Opcode.OR -> {
val (top, second) = es.pop2() val (top, second) = evalstack.pop2()
es.push(second.or(top)) evalstack.push(second.or(top))
} }
Opcode.XOR -> { Opcode.XOR -> {
val (top, second) = es.pop2() val (top, second) = evalstack.pop2()
es.push(second.xor(top)) evalstack.push(second.xor(top))
} }
Opcode.INV -> { Opcode.INV -> {
val v = es.pop() val v = evalstack.pop()
es.push(v.inv()) evalstack.push(v.inv())
} }
Opcode.INC -> { Opcode.INC -> {
val v = es.pop() val v = evalstack.pop()
es.push(v.inc()) evalstack.push(v.inc())
} }
Opcode.DEC -> { Opcode.DEC -> {
val v = es.pop() val v = evalstack.pop()
es.push(v.dec()) evalstack.push(v.dec())
} }
Opcode.SYSCALL -> { Opcode.SYSCALL -> {
val callId = ins.args[0].integerValue().toShort() val callId = ins.args[0].integerValue().toShort()
val syscall = Syscall.values().first { it.callNr == callId } val syscall = Syscall.values().first { it.callNr == callId }
when (syscall) { when (syscall) {
Syscall.WRITECHR -> output.print(Petscii.decodePetscii(listOf(mem.getByte(ins.args[1].integerValue())), true)) Syscall.WRITE_MEMCHR -> print(Petscii.decodePetscii(listOf(mem.getByte(ins.args[1].integerValue())), true))
Syscall.WRITESTR -> output.print(mem.getString(ins.args[1].integerValue())) Syscall.WRITE_MEMSTR -> print(mem.getString(ins.args[1].integerValue()))
Syscall.WRITE_NUM -> output.print(es.pop().numericValue()) Syscall.WRITE_NUM -> print(evalstack.pop().numericValue())
Syscall.WRITE_CHAR -> output.print(Petscii.decodePetscii(listOf(es.pop().integerValue().toShort()), true)) 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") else -> throw VmExecutionException("unimplemented syscall $syscall")
} }
} }
@ -640,22 +700,73 @@ class StackVm(val vmOutputFile: String) {
mem.setWord(addr, newValue.integerValue()) mem.setWord(addr, newValue.integerValue())
} }
Opcode.JUMP -> {} // do nothing; the next instruction is wired up already Opcode.JUMP -> {} // do nothing; the next instruction is wired up already to the jump target
Opcode.CALL -> TODO() Opcode.BCS -> return if(carry) ins.next else ins.nextAlt!!
Opcode.RETURN -> TODO() Opcode.BCC -> return if(carry) ins.nextAlt!! else ins.next
Opcode.PUSH_LOCAL -> TODO() Opcode.CALL -> callstack.push(ins.nextAlt)
Opcode.POP_LOCAL -> TODO() Opcode.RETURN -> return callstack.pop()
Opcode.INC_LOCAL -> TODO() Opcode.PUSH_VAR -> {
Opcode.DEC_LOCAL -> TODO() val varname = ins.args[0].stringvalue ?: throw VmExecutionException("${ins.opcode} expects string argument (the variable name)")
Opcode.SHL_LOCAL -> TODO() val variable = variables[varname] ?: throw VmExecutionException("unknown variable: $varname")
Opcode.SHR_LOCAL -> TODO() evalstack.push(variable)
Opcode.ROL_LOCAL -> TODO() }
Opcode.ROR_LOCAL -> TODO() Opcode.POP_VAR -> {
Opcode.ROL2_LOCAL -> TODO() val value = evalstack.pop()
Opcode.ROR2_LOCAL -> TODO() 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 return ins.next
} }
@ -663,47 +774,29 @@ class StackVm(val vmOutputFile: String) {
fun main(args: Array<String>) { fun main(args: Array<String>) {
val vm = StackVm(vmOutputFile = "vmout.txt") val vm = StackVm(traceOutputFile = "vmtrace.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())
))
vm.mem.setString(0x1000, "Hallo!\n") 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) vm.run(program)
} }

View File

@ -210,9 +210,9 @@ class TestPetscii {
@Test @Test
fun testLowercase() { fun testLowercase() {
assertThat(Petscii.encodePetscii("hello WORLD 123 @!£", true), equalTo( 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))) 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(shortArrayOf(0x12))) // reverse vid assertThat(Petscii.encodePetscii("\uf11a", true), equalTo(listOf<Short>(0x12))) // reverse vid
assertThat(Petscii.encodePetscii("", true), equalTo(shortArrayOf(0xfa))) assertThat(Petscii.encodePetscii("", true), equalTo(listOf<Short>(0xfa)))
assertFailsWith<CompilerException> { Petscii.encodePetscii("π", true) } assertFailsWith<CompilerException> { Petscii.encodePetscii("π", true) }
assertFailsWith<CompilerException> { Petscii.encodePetscii("", true) } assertFailsWith<CompilerException> { Petscii.encodePetscii("", true) }
@ -224,10 +224,10 @@ class TestPetscii {
@Test @Test
fun testUppercase() { fun testUppercase() {
assertThat(Petscii.encodePetscii("HELLO 123 @!£"), equalTo( assertThat(Petscii.encodePetscii("HELLO 123 @!£"), equalTo(
shortArrayOf(72, 69, 76, 76, 79, 32, 49, 50, 51, 32, 64, 33, 0x5c))) listOf<Short>(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("\uf11a"), equalTo(listOf<Short>(0x12))) // reverse vid
assertThat(Petscii.encodePetscii(""), equalTo(shortArrayOf(0xd3))) assertThat(Petscii.encodePetscii(""), equalTo(listOf<Short>(0xd3)))
assertThat(Petscii.encodePetscii("π"), equalTo(shortArrayOf(0xff))) assertThat(Petscii.encodePetscii("π"), equalTo(listOf<Short>(0xff)))
assertFailsWith<CompilerException> { Petscii.encodePetscii("") } assertFailsWith<CompilerException> { Petscii.encodePetscii("") }
assertThat(Petscii.decodePetscii(listOf(72, 0x5c, 0xd3, 0xff)), equalTo("H£♥π")) assertThat(Petscii.decodePetscii(listOf(72, 0x5c, 0xd3, 0xff)), equalTo("H£♥π"))
@ -238,9 +238,9 @@ class TestPetscii {
@Test @Test
fun testScreencodeLowercase() { fun testScreencodeLowercase() {
assertThat(Petscii.encodeScreencode("hello WORLD 123 @!£", true), equalTo( 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) }
assertFailsWith<CompilerException> { Petscii.encodeScreencode("π", true) } assertFailsWith<CompilerException> { Petscii.encodeScreencode("π", true) }
@ -252,9 +252,9 @@ class TestPetscii {
@Test @Test
fun testScreencodeUppercase() { fun testScreencodeUppercase() {
assertThat(Petscii.encodeScreencode("WORLD 123 @!£"), equalTo( assertThat(Petscii.encodeScreencode("WORLD 123 @!£"), equalTo(
shortArrayOf(0x17, 0x0f, 0x12, 0x0c, 0x04, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c))) listOf<Short>(0x17, 0x0f, 0x12, 0x0c, 0x04, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c)))
assertThat(Petscii.encodeScreencode(""), equalTo(shortArrayOf(0x53))) assertThat(Petscii.encodeScreencode(""), equalTo(listOf<Short>(0x53)))
assertThat(Petscii.encodeScreencode("π"), equalTo(shortArrayOf(0x5e))) assertThat(Petscii.encodeScreencode("π"), equalTo(listOf<Short>(0x5e)))
assertFailsWith<CompilerException> { Petscii.encodeScreencode("") } assertFailsWith<CompilerException> { Petscii.encodeScreencode("") }
assertFailsWith<CompilerException> { Petscii.encodeScreencode("hello") } assertFailsWith<CompilerException> { Petscii.encodeScreencode("hello") }