From 7c4846700b19091cd61e0f3c8c083566ed5eb48e Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 27 Oct 2018 22:08:46 +0200 Subject: [PATCH] simplified opcodes (removed COPY_XXX and MEM signed/unsigned distinction) --- compiler/examples/test.p8 | 14 ++ compiler/src/prog8/ast/AstChecker.kt | 10 +- .../src/prog8/ast/AstIdentifiersChecker.kt | 4 +- compiler/src/prog8/compiler/Compiler.kt | 8 +- .../compiler/intermediate/Instruction.kt | 4 - .../intermediate/IntermediateProgram.kt | 49 ++-- .../src/prog8/compiler/intermediate/Opcode.kt | 44 +--- .../src/prog8/compiler/target/c64/AsmGen.kt | 232 ++++-------------- compiler/src/prog8/stackvm/Program.kt | 10 - compiler/src/prog8/stackvm/StackVm.kt | 106 ++------ compiler/test/StackVMOpcodeTests.kt | 53 +--- 11 files changed, 131 insertions(+), 403 deletions(-) diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index 16e4e6dd0..a7f1c578e 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -50,12 +50,26 @@ sub start() { ; all possible assignments to a BYTE VARIABLE + +assignments: A = 42 A = Y + A = X + Y = X A = ub + X = ub + Y = ub A = mubyte + X = mubyte + Y = mubyte A = ubarr1[2] + X = ubarr1[2] + Y = ubarr1[2] A = ubmatrix1[1,2] + X = ubmatrix1[1,2] + Y = ubmatrix1[1,2] + + diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index d0cdf1a78..240a6baf7 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -459,8 +459,8 @@ class AstChecker(private val namespace: INameScope, if(arraySize > 51) err("float arrayspec length must be 1-51") DataType.MATRIX_B, DataType.MATRIX_UB -> - if(arraySize > 256) - err("invalid matrix size, must be 1-256") + if(arraySize > 32768) + err("invalid matrix size, must be 1-32768") else -> {} } } @@ -936,8 +936,8 @@ class AstChecker(private val namespace: INameScope, (targetDt==DataType.MATRIX_B && value.type==DataType.ARRAY_B)) { val arraySpecSize = arrayspec.size() if(arraySpecSize!=null && arraySpecSize>0) { - if(arraySpecSize<1 || arraySpecSize>256) - return err("invalid matrix size, must be 1-256") + if(arraySpecSize<1 || arraySpecSize>32768) + return err("invalid matrix size, must be 1-32768") val constX = arrayspec.x.constValue(namespace, heap) val constY = arrayspec.y?.constValue(namespace, heap) if (constX?.asIntegerValue == null || (constY!=null && constY.asIntegerValue == null)) @@ -949,7 +949,7 @@ class AstChecker(private val namespace: INameScope, return err("initializer matrix size mismatch (expecting $expectedSize, got ${matrix.size} elements)") return true } - return err("invalid matrix size, must be 1-256") + return err("invalid matrix size, must be 1-32768") } return err("invalid matrix initialization value of type ${value.type} - expecting byte arrayspec") } diff --git a/compiler/src/prog8/ast/AstIdentifiersChecker.kt b/compiler/src/prog8/ast/AstIdentifiersChecker.kt index f48107438..09a4c7ea7 100644 --- a/compiler/src/prog8/ast/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/ast/AstIdentifiersChecker.kt @@ -126,7 +126,7 @@ class AstIdentifiersChecker : IAstProcessor { if(forLoop.decltype!=null) checkResult.add(SyntaxError("register loop variables cannot be explicitly declared with a datatype", forLoop.position)) if(forLoop.loopRegister == Register.X || forLoop.loopRegister==Register.XY || forLoop.loopRegister==Register.AX) - checkResult.add(SyntaxError("it's not possible to write to the X register because it's used as an internal pointer", forLoop.position)) + printWarning("possible problem writing to the X register, because it's used as an internal pointer", forLoop.position) } else if(forLoop.loopVar!=null) { val varName = forLoop.loopVar.nameInSource.last() when (forLoop.decltype) { @@ -148,7 +148,7 @@ class AstIdentifiersChecker : IAstProcessor { override fun process(assignTarget: AssignTarget): AssignTarget { if(assignTarget.register==Register.X || assignTarget.register==Register.AX || assignTarget.register==Register.XY) - checkResult.add(SyntaxError("it's not possible to write to the X register because it's used as an internal pointer", assignTarget.position)) + printWarning("possible problem writing to the X register, because it's used as an internal pointer", assignTarget.position) return super.process(assignTarget) } } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index fdda23571..bb699e009 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -350,14 +350,12 @@ private class StatementTranslator(private val prog: IntermediateProgram, private fun opcodePopmem(dt: DataType): Opcode { return when (dt) { - DataType.UBYTE -> Opcode.POP_MEM_UB - DataType.BYTE -> Opcode.POP_MEM_B - DataType.UWORD -> Opcode.POP_MEM_UW - DataType.WORD -> Opcode.POP_MEM_W + DataType.UBYTE, DataType.BYTE -> Opcode.POP_MEM_BYTE + DataType.UWORD, DataType.WORD -> Opcode.POP_MEM_WORD DataType.FLOAT -> Opcode.POP_MEM_FLOAT DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F, DataType.MATRIX_UB, - DataType.ARRAY_B, DataType.ARRAY_W, DataType.MATRIX_B -> Opcode.POP_MEM_UW + DataType.ARRAY_B, DataType.ARRAY_W, DataType.MATRIX_B -> Opcode.POP_MEM_WORD } } diff --git a/compiler/src/prog8/compiler/intermediate/Instruction.kt b/compiler/src/prog8/compiler/intermediate/Instruction.kt index 269393c11..ac9a48dfb 100644 --- a/compiler/src/prog8/compiler/intermediate/Instruction.kt +++ b/compiler/src/prog8/compiler/intermediate/Instruction.kt @@ -25,10 +25,6 @@ open class Instruction(val opcode: Opcode, // opcodes that manipulate a variable "${opcode.toString().toLowerCase()} ${callLabel?:""} ${callLabel2?:""}".trimEnd() } - opcode in setOf(Opcode.COPY_MEM_BYTE, Opcode.COPY_MEM_WORD, Opcode.COPY_MEM_FLOAT) -> { - // opcodes with two (address) args - "${opcode.toString().toLowerCase()} $arg $arg2" - } callLabel==null -> "${opcode.toString().toLowerCase()} $argStr" else -> "${opcode.toString().toLowerCase()} $callLabel $argStr" } diff --git a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt index 59ff8b144..db6eee886 100644 --- a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt +++ b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt @@ -79,54 +79,47 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap when (it[0].value.opcode) { Opcode.PUSH_VAR_BYTE -> if (it[1].value.opcode == Opcode.POP_VAR_BYTE) { - if (it[0].value.callLabel != it[1].value.callLabel) - instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_VAR_BYTE, null, null, it[0].value.callLabel, it[1].value.callLabel) - else + if (it[0].value.callLabel == it[1].value.callLabel) { instructionsToReplace[it[0].index] = Instruction(Opcode.NOP) - instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + } } Opcode.PUSH_VAR_WORD -> if (it[1].value.opcode == Opcode.POP_VAR_WORD) { - if (it[0].value.callLabel != it[1].value.callLabel) - instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_VAR_WORD, null, null, it[0].value.callLabel, it[1].value.callLabel) - else + if (it[0].value.callLabel == it[1].value.callLabel) { instructionsToReplace[it[0].index] = Instruction(Opcode.NOP) - instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + } } Opcode.PUSH_VAR_FLOAT -> if (it[1].value.opcode == Opcode.POP_VAR_FLOAT) { - if (it[0].value.callLabel != it[1].value.callLabel) - instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_VAR_FLOAT, null, null, it[0].value.callLabel, it[1].value.callLabel) - else + if (it[0].value.callLabel == it[1].value.callLabel) { instructionsToReplace[it[0].index] = Instruction(Opcode.NOP) - instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + } } Opcode.PUSH_MEM_B, Opcode.PUSH_MEM_UB -> - if(it[1].value.opcode == Opcode.POP_MEM_B || it[1].value.opcode == Opcode.POP_MEM_UB) { - if(it[0].value.arg != it[1].value.arg) - instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_MEM_BYTE, it[0].value.arg, it[1].value.arg) - else + if(it[1].value.opcode == Opcode.POP_MEM_BYTE) { + if(it[0].value.arg == it[1].value.arg) { instructionsToReplace[it[0].index] = Instruction(Opcode.NOP) - instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + } } Opcode.PUSH_MEM_W, Opcode.PUSH_MEM_UW -> - if(it[1].value.opcode == Opcode.POP_MEM_W || it[1].value.opcode == Opcode.POP_MEM_UW) { - if(it[0].value.arg != it[1].value.arg) - instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_MEM_WORD, it[0].value.arg, it[1].value.arg) - else + if(it[1].value.opcode == Opcode.POP_MEM_WORD) { + if(it[0].value.arg == it[1].value.arg) { instructionsToReplace[it[0].index] = Instruction(Opcode.NOP) - instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + } } Opcode.PUSH_MEM_FLOAT -> if(it[1].value.opcode == Opcode.POP_MEM_FLOAT) { - if(it[0].value.arg != it[1].value.arg) - instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_MEM_FLOAT, it[0].value.arg, it[1].value.arg) - else + if(it[0].value.arg == it[1].value.arg) { instructionsToReplace[it[0].index] = Instruction(Opcode.NOP) - instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + } } - else -> { - } + else -> {} } } diff --git a/compiler/src/prog8/compiler/intermediate/Opcode.kt b/compiler/src/prog8/compiler/intermediate/Opcode.kt index fb4ce6526..cc7c1bf23 100644 --- a/compiler/src/prog8/compiler/intermediate/Opcode.kt +++ b/compiler/src/prog8/compiler/intermediate/Opcode.kt @@ -19,23 +19,13 @@ enum class Opcode { DISCARD_BYTE, // discard top byte value DISCARD_WORD, // discard top word value DISCARD_FLOAT, // discard top float value - POP_MEM_B, // pop byte value into destination memory address - POP_MEM_UB, // pop byte value into destination memory address - POP_MEM_W, // pop word value into destination memory address - POP_MEM_UW, // pop word value into destination memory address + POP_MEM_BYTE, // pop (u)byte value into destination memory address + POP_MEM_WORD, // pop (u)word value into destination memory address POP_MEM_FLOAT, // pop float value into destination memory address - POP_VAR_BYTE, // pop byte value into variable (byte, ubyte) - POP_VAR_WORD, // pop word value into variable (word, uword) + POP_VAR_BYTE, // pop (u)byte value into variable + POP_VAR_WORD, // pop (u)word value into variable POP_VAR_FLOAT, // pop float value into variable - // optimized copying of one var to another (replaces push+pop) - COPY_VAR_BYTE, - COPY_VAR_WORD, - COPY_VAR_FLOAT, - COPY_MEM_BYTE, - COPY_MEM_WORD, - COPY_MEM_FLOAT, - // numeric arithmetic ADD_UB, ADD_B, @@ -233,32 +223,6 @@ val opcodesWithVarArgument = setOf( Opcode.ROL2_VAR_BYTE, Opcode.ROL2_VAR_WORD, Opcode.ROR2_VAR_BYTE, Opcode.ROR2_VAR_WORD, Opcode.POP_VAR_BYTE, Opcode.POP_VAR_WORD, Opcode.POP_VAR_FLOAT, Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_WORD, Opcode.PUSH_VAR_FLOAT, - Opcode.COPY_VAR_BYTE, Opcode.COPY_VAR_WORD, Opcode.COPY_VAR_FLOAT, Opcode.READ_INDEXED_VAR_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.READ_INDEXED_VAR_FLOAT, Opcode.WRITE_INDEXED_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD, Opcode.WRITE_INDEXED_VAR_FLOAT ) - -val pushOpcodes = setOf( - Opcode.PUSH_BYTE, - Opcode.PUSH_WORD, - Opcode.PUSH_FLOAT, - Opcode.PUSH_MEM_B, - Opcode.PUSH_MEM_UB, - Opcode.PUSH_MEM_W, - Opcode.PUSH_MEM_UW, - Opcode.PUSH_MEM_FLOAT, - Opcode.PUSH_VAR_BYTE, - Opcode.PUSH_VAR_WORD, - Opcode.PUSH_VAR_FLOAT -) - -val popOpcodes = setOf( - Opcode.POP_MEM_B, - Opcode.POP_MEM_UB, - Opcode.POP_MEM_W, - Opcode.POP_MEM_UW, - Opcode.POP_MEM_FLOAT, - Opcode.POP_VAR_BYTE, - Opcode.POP_VAR_WORD, - Opcode.POP_VAR_FLOAT -) diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 754c5387f..b316bb70f 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -445,14 +445,14 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, // """ // } - Opcode.POP_MEM_B, Opcode.POP_MEM_UB -> { + Opcode.POP_MEM_BYTE -> { """ inx lda ${ESTACK_LO.toHex()},x sta ${ins.arg!!.integerValue().toHex()} """ } - Opcode.POP_MEM_W, Opcode.POP_MEM_UW -> { + Opcode.POP_MEM_WORD -> { """ inx lda ${ESTACK_LO.toHex()},x @@ -481,102 +481,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, " lda #<${ins.callLabel} | ldy #>${ins.callLabel} | jsr prog8_lib.pop_var_float" } - Opcode.COPY_VAR_BYTE -> { - when { - ins.callLabel2 in registerStrings -> { - val reg2 = ins.callLabel2!!.toLowerCase() - if (ins.callLabel in registerStrings) { - val reg1 = ins.callLabel!!.toLowerCase() - // register -> register - return when { - reg1 == "a" -> " ta$reg2" - reg2 == "a" -> " t${reg1}a" - else -> " t${reg1}a | ta$reg2" // 6502 doesn't have tyx/txy - } - } - // var -> reg - return " ld${ins.callLabel2.toLowerCase()} ${ins.callLabel}" - } - ins.callLabel in registerStrings -> - // reg -> var - return " st${ins.callLabel!!.toLowerCase()} ${ins.callLabel2}" - else -> - // var -> var - return " lda ${ins.callLabel} | sta ${ins.callLabel2}" - } - } - Opcode.COPY_VAR_WORD -> { - when { - ins.callLabel2 in registerStrings -> { - if (ins.callLabel in registerStrings) { - // copying registerpair -> registerpair - when { - ins.callLabel == "AX" -> return when (ins.callLabel2) { - "AY" -> " txy" - "XY" -> " stx ${C64Zeropage.SCRATCH_B1.toHex()} | tax | ldy ${C64Zeropage.SCRATCH_B1.toHex()}" - else -> "" - } - ins.callLabel == "AY" -> return when (ins.callLabel2) { - "AX" -> " sty ${C64Zeropage.SCRATCH_B1.toHex()} | ldx ${C64Zeropage.SCRATCH_B1.toHex()}" - "XY" -> " tax" - else -> "" - } - else /* XY */ -> return when (ins.callLabel2) { - "AX" -> " txa | sty ${C64Zeropage.SCRATCH_B1.toHex()} | ldx ${C64Zeropage.SCRATCH_B1.toHex()}" - "AY" -> " txa" - else -> "" - } - } - } - // wvar -> regpair - val regpair = ins.callLabel2!!.toLowerCase() - return " ld${regpair[0]} ${ins.callLabel} | ld${regpair[1]} ${ins.callLabel}+1" - } - ins.callLabel in registerStrings -> { - // regpair->wvar - val regpair = ins.callLabel!!.toLowerCase() - return " st${regpair[0]} ${ins.callLabel2} | st${regpair[1]} ${ins.callLabel2}+1" - } - else -> { - // wvar->wvar - return " lda ${ins.callLabel} | sta ${ins.callLabel2} | " + - " lda ${ins.callLabel}+1 | sta ${ins.callLabel2}+1" - } - } - } - Opcode.COPY_VAR_FLOAT -> { - """ - lda #<${ins.callLabel} - ldy #>${ins.callLabel} - sta ${C64Zeropage.SCRATCH_W1} - sty ${C64Zeropage.SCRATCH_W1+1} - lda #<${ins.callLabel2} - ldy #>${ins.callLabel2} - jsr prog8_lib.copy_float - """ - } - - Opcode.COPY_MEM_BYTE -> " lda ${ins.arg!!.integerValue().toHex()} | sta ${ins.arg2!!.integerValue().toHex()}" - Opcode.COPY_MEM_WORD -> { - """ - lda ${ins.arg!!.integerValue().toHex()} - sta ${ins.arg2!!.integerValue().toHex()} - lda ${(ins.arg.integerValue()+1).toHex()} - sta ${(ins.arg2.integerValue()+1).toHex()} - """ - } - Opcode.COPY_MEM_FLOAT -> { - """ - lda #<${ins.arg!!.integerValue().toHex()} - ldy #>${ins.arg.integerValue().toHex()} - sta ${C64Zeropage.SCRATCH_W1} - sty ${C64Zeropage.SCRATCH_W1+1} - lda #<${ins.arg2!!.integerValue().toHex()} - ldy #>${ins.arg2.integerValue().toHex()} - jsr prog8_lib.copy_float - """ - } - Opcode.INC_VAR_UB, Opcode.INC_VAR_B -> { when (ins.callLabel) { "A" -> " clc | adc #1" @@ -750,22 +654,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, val opcodes = segment.map { it.opcode } val result = mutableListOf() - // check for direct var assignments that should have been converted into COPY_VAR_XXX opcodes - if((opcodes[0]==Opcode.PUSH_VAR_BYTE && opcodes[1]==Opcode.POP_VAR_BYTE) || - (opcodes[0]==Opcode.PUSH_VAR_WORD && opcodes[1]==Opcode.POP_VAR_WORD) || - (opcodes[0]==Opcode.PUSH_VAR_FLOAT && opcodes[1]==Opcode.POP_VAR_FLOAT) || - (opcodes[0]==Opcode.PUSH_MEM_B && opcodes[1]==Opcode.POP_MEM_B) || - (opcodes[0]==Opcode.PUSH_MEM_B && opcodes[1]==Opcode.POP_MEM_UB) || - (opcodes[0]==Opcode.PUSH_MEM_UB && opcodes[1]==Opcode.POP_MEM_B) || - (opcodes[0]==Opcode.PUSH_MEM_UB && opcodes[1]==Opcode.POP_MEM_UB) || - (opcodes[0]==Opcode.PUSH_MEM_W && opcodes[1]==Opcode.POP_MEM_W) || - (opcodes[0]==Opcode.PUSH_MEM_W && opcodes[1]==Opcode.POP_MEM_UW) || - (opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[1]==Opcode.POP_MEM_W) || - (opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[1]==Opcode.POP_MEM_UW) || - (opcodes[0]==Opcode.PUSH_MEM_FLOAT && opcodes[1]==Opcode.POP_MEM_FLOAT)) { - throw AssemblyError("push+pop var/mem should have been changed into COPY_VAR_XXX opcode") - } - // check for operations that modify a single value, by putting it on the stack (and popping it afterwards) if((opcodes[0]==Opcode.PUSH_VAR_BYTE && opcodes[2]==Opcode.POP_VAR_BYTE) || (opcodes[0]==Opcode.PUSH_VAR_WORD && opcodes[2]==Opcode.POP_VAR_WORD) || @@ -778,10 +666,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } } } - else if((opcodes[0]==Opcode.PUSH_MEM_UB && opcodes[2]==Opcode.POP_MEM_UB) || - (opcodes[0]==Opcode.PUSH_MEM_B && opcodes[2]==Opcode.POP_MEM_B) || - (opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[2]==Opcode.POP_MEM_UW) || - (opcodes[0]==Opcode.PUSH_MEM_W && opcodes[2]==Opcode.POP_MEM_W) || + else if((opcodes[0]==Opcode.PUSH_MEM_UB && opcodes[2]==Opcode.POP_MEM_BYTE) || + (opcodes[0]==Opcode.PUSH_MEM_B && opcodes[2]==Opcode.POP_MEM_BYTE) || + (opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[2]==Opcode.POP_MEM_WORD) || + (opcodes[0]==Opcode.PUSH_MEM_W && opcodes[2]==Opcode.POP_MEM_WORD) || (opcodes[0]==Opcode.PUSH_MEM_FLOAT && opcodes[2]==Opcode.POP_MEM_FLOAT)) { if(segment[0].arg==segment[2].arg) { val fragment = sameMemOperation(segment[0].arg!!.integerValue(), segment[1]) @@ -1022,7 +910,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, private val patterns = listOf( // ----------- assignment to BYTE VARIABLE ---------------- - // note: var=var is done via COPY_VAR_BYTE opcode elsewhere. + // @todo var=var // var = bytevalue AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_VAR_BYTE)) { segment -> when (segment[1].callLabel) { @@ -1032,6 +920,39 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, " lda #${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].callLabel}" } }, + // var = other var + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_VAR_BYTE)) { segment -> + when(segment[1].callLabel) { + "A" -> + when(segment[0].callLabel) { + "A" -> null + "X" -> " txa" + "Y" -> " tya" + else -> " lda ${segment[0].callLabel}" + } + "X" -> + when(segment[0].callLabel) { + "A" -> " tax" + "X" -> null + "Y" -> " tya | tax" + else -> " ldx ${segment[0].callLabel}" + } + "Y" -> + when(segment[0].callLabel) { + "A" -> " tay" + "X" -> " txa | tay" + "Y" -> null + else -> " ldy ${segment[0].callLabel}" + } + else -> + when(segment[0].callLabel) { + "A" -> " sta ${segment[1].callLabel}" + "X" -> " stx ${segment[1].callLabel}" + "Y" -> " sty ${segment[1].callLabel}" + else -> " lda ${segment[0].callLabel} | sta ${segment[1].callLabel}" + } + } + }, // var = mem (u)byte AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.POP_VAR_BYTE)) { segment -> when(segment[1].callLabel) { @@ -1083,24 +1004,13 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, // ----------- assignment to MEMORY BYTE ---------------- - // note: mem=mem is done via COPY_MEM_BYTE opcode elsewhere. + // @todo mem=mem // mem = (u)byte value - AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_MEM_B)) { segment -> - " lda #${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].arg!!.integerValue().toHex()}" - }, - AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_MEM_UB)) { segment -> + AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_MEM_BYTE)) { segment -> " lda #${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].arg!!.integerValue().toHex()}" }, // mem = (u)bytevar - AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_MEM_B)) { segment -> - when(segment[0].callLabel) { - "A" -> " sta ${segment[1].arg!!.integerValue().toHex()}" - "X" -> " stx ${segment[1].arg!!.integerValue().toHex()}" - "Y" -> " sty ${segment[1].arg!!.integerValue().toHex()}" - else -> " lda ${segment[0].callLabel} | sta ${segment[1].arg!!.integerValue().toHex()}" - } - }, - AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_MEM_UB)) { segment -> + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_MEM_BYTE)) { segment -> when(segment[0].callLabel) { "A" -> " sta ${segment[1].arg!!.integerValue().toHex()}" "X" -> " stx ${segment[1].arg!!.integerValue().toHex()}" @@ -1109,17 +1019,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } }, // mem = (u)bytearray[indexvalue] - AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_MEM_B)) { segment -> - val address = segment[2].arg!!.integerValue().toHex() - val index = segment[0].arg!!.integerValue() - when(segment[1].callLabel) { - "AX" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address" - "AY" -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address" - "XY" -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address" - else -> " lda ${segment[1].callLabel}+$index | sta $address" - } - }, - AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_MEM_UB)) { segment -> + AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_MEM_BYTE)) { segment -> val address = segment[2].arg!!.integerValue().toHex() val index = segment[0].arg!!.integerValue() when(segment[1].callLabel) { @@ -1131,8 +1031,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, + // ----------- assignment to WORD VARIABLE ---------------- - // note: var=var is done via COPY_VAR_WORD opcode elsewhere. + // @todo var=var // var = wordvalue AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_VAR_WORD)) { segment -> val number = segment[0].arg!!.integerValue().toHex() @@ -1276,17 +1177,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, // ----------- assignment to MEMORY WORD ---------------- - // note: mem=mem is done via COPY_MEM_WORD opcode elsewhere. + // @todo mem=mem // mem = (u)word value - AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_MEM_W)) { segment -> - """ - lda #<${segment[0].arg!!.integerValue().toHex()} - sta ${segment[1].arg!!.integerValue().toHex()} - lda #>${segment[0].arg!!.integerValue().toHex()} - sta ${(segment[1].arg!!.integerValue()+1).toHex()} - """ - }, - AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_MEM_UW)) { segment -> + AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_MEM_WORD)) { segment -> """ lda #<${segment[0].arg!!.integerValue().toHex()} sta ${segment[1].arg!!.integerValue().toHex()} @@ -1295,21 +1188,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, """ }, // mem = (u)word var - AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_W)) { segment -> - when(segment[0].callLabel) { - "AX" -> " sta ${segment[1].arg!!.integerValue().toHex()} | stx ${(segment[1].arg!!.integerValue()+1).toHex()}" - "AY" -> " sta ${segment[1].arg!!.integerValue().toHex()} | sty ${(segment[1].arg!!.integerValue()+1).toHex()}" - "XY" -> " stx ${segment[1].arg!!.integerValue().toHex()} | sty ${(segment[1].arg!!.integerValue()+1).toHex()}" - else -> - """ - lda ${segment[0].callLabel} - sta ${segment[1].arg!!.integerValue().toHex()} - lda ${segment[0].callLabel}+1 - sta ${(segment[1].arg!!.integerValue()+1).toHex()} - """ - } - }, - AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_UW)) { segment -> + AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_WORD)) { segment -> when(segment[0].callLabel) { "AX" -> " sta ${segment[1].arg!!.integerValue().toHex()} | stx ${(segment[1].arg!!.integerValue()+1).toHex()}" "AY" -> " sta ${segment[1].arg!!.integerValue().toHex()} | sty ${(segment[1].arg!!.integerValue()+1).toHex()}" @@ -1324,16 +1203,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } }, // mem = (u)wordarray[indexvalue] - AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_MEM_W)) { segment -> - val index = segment[0].arg!!.integerValue()*2 - """ - lda ${segment[1].callLabel}+$index - ldy ${segment[1].callLabel}+1+$index - sta ${segment[2].arg!!.integerValue().toHex()} - sty ${(segment[2].arg!!.integerValue()+1).toHex()} - """ - }, - AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_MEM_UW)) { segment -> + AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_MEM_WORD)) { segment -> val index = segment[0].arg!!.integerValue()*2 """ lda ${segment[1].callLabel}+$index @@ -1343,7 +1213,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, """ }, // assignment: mem uword = ubytearray[index_byte] - AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.UB2UWORD, Opcode.POP_MEM_UW)) { segment -> + AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.UB2UWORD, Opcode.POP_MEM_WORD)) { segment -> val index = segment[0].arg!!.integerValue() when(segment[1].callLabel) { "AX" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta ${segment[3].arg!!.integerValue().toHex()} | lda #0 | sta ${(segment[3].arg!!.integerValue()+1).toHex()}" diff --git a/compiler/src/prog8/stackvm/Program.kt b/compiler/src/prog8/stackvm/Program.kt index cf046d9b3..615cc9b44 100644 --- a/compiler/src/prog8/stackvm/Program.kt +++ b/compiler/src/prog8/stackvm/Program.kt @@ -124,16 +124,6 @@ class Program (val name: String, val args = if(parts.size==2) parts[1] else null val instruction = when(opcode) { Opcode.LINE -> Instruction(opcode, null, callLabel = args) - Opcode.COPY_VAR_BYTE, Opcode.COPY_VAR_WORD, Opcode.COPY_VAR_FLOAT -> { - val (v1, v2) = args!!.split(splitpattern, limit = 2) - Instruction(opcode, null, null, v1, v2) - } - Opcode.COPY_MEM_BYTE, Opcode.COPY_MEM_WORD, Opcode.COPY_MEM_FLOAT -> { - val (v1, v2) = args!!.split(splitpattern, limit = 2) - val address1 = getArgValue(v1, heap) - val address2 = getArgValue(v2, heap) - Instruction(opcode, address1, address2) - } Opcode.JUMP, Opcode.CALL, Opcode.BNEG, Opcode.BPOS, Opcode.BZ, Opcode.BNZ, Opcode.BCS, Opcode.BCC -> { if(args!!.startsWith('$')) { diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 9155df572..ceb0f8c2d 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -218,30 +218,24 @@ class StackVm(private var traceOutputFile: String?) { } } - private fun checkDt(value: Value?, expected: DataType) { - if(value==null) - throw VmExecutionException("expected value") - if(value.type!=expected) - throw VmExecutionException("expected $expected value, found ${value.type}") - } - - private fun checkDt(value: Value?, expected: Set) { + private fun checkDt(value: Value?, vararg expected: DataType) { if(value==null) throw VmExecutionException("expected value") if(value.type !in expected) - throw VmExecutionException("incompatible type found ${value.type}") + throw VmExecutionException("incompatible type ${value.type}") } + private fun dispatch(ins: Instruction) : Instruction { traceOutput?.println("\n$ins") when (ins.opcode) { Opcode.NOP -> {} Opcode.PUSH_BYTE -> { - checkDt(ins.arg, setOf(DataType.UBYTE, DataType.BYTE)) + checkDt(ins.arg, DataType.UBYTE, DataType.BYTE) evalstack.push(ins.arg) } Opcode.PUSH_WORD -> { - checkDt(ins.arg, setOf(DataType.UWORD, DataType.WORD) + IterableDatatypes) + checkDt(ins.arg, *(setOf(DataType.UWORD, DataType.WORD) + IterableDatatypes).toTypedArray()) evalstack.push(ins.arg) } Opcode.PUSH_FLOAT -> { @@ -280,29 +274,23 @@ class StackVm(private var traceOutputFile: String?) { val value = evalstack.pop() checkDt(value, DataType.FLOAT) } - Opcode.POP_MEM_UB -> { + Opcode.POP_MEM_BYTE -> { val value = evalstack.pop() - checkDt(value, DataType.UBYTE) + checkDt(value, DataType.BYTE, DataType.UBYTE) val address = ins.arg!!.integerValue() - mem.setUByte(address, value.integerValue().toShort()) + if(value.type==DataType.BYTE) + mem.setSByte(address, value.integerValue().toShort()) + else + mem.setUByte(address, value.integerValue().toShort()) } - Opcode.POP_MEM_B -> { + Opcode.POP_MEM_WORD -> { val value = evalstack.pop() - checkDt(value, DataType.BYTE) + checkDt(value, DataType.WORD, DataType.UWORD) val address = ins.arg!!.integerValue() - mem.setSByte(address, value.integerValue().toShort()) - } - Opcode.POP_MEM_UW -> { - val value = evalstack.pop() - checkDt(value, DataType.UWORD) - val address = ins.arg!!.integerValue() - mem.setUWord(address, value.integerValue()) - } - Opcode.POP_MEM_W -> { - val value = evalstack.pop() - checkDt(value, DataType.WORD) - val address = ins.arg!!.integerValue() - mem.setSWord(address, value.integerValue()) + if(value.type==DataType.WORD) + mem.setSWord(address, value.integerValue()) + else + mem.setUWord(address, value.integerValue()) } Opcode.POP_MEM_FLOAT -> { val value = evalstack.pop() @@ -765,12 +753,12 @@ class StackVm(private var traceOutputFile: String?) { } Opcode.PUSH_VAR_BYTE -> { val value = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - checkDt(value, setOf(DataType.UBYTE, DataType.BYTE)) + checkDt(value, DataType.UBYTE, DataType.BYTE) evalstack.push(value) } Opcode.PUSH_VAR_WORD -> { val value = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - checkDt(value, setOf(DataType.UWORD, DataType.WORD, DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.MATRIX_UB)) + checkDt(value, *(setOf(DataType.UWORD, DataType.WORD) + IterableDatatypes).toTypedArray()) evalstack.push(value) } Opcode.PUSH_VAR_FLOAT -> { @@ -780,62 +768,22 @@ class StackVm(private var traceOutputFile: String?) { } Opcode.POP_VAR_BYTE -> { val value = evalstack.pop() - checkDt(value, setOf(DataType.UBYTE, DataType.BYTE)) + checkDt(value, DataType.UBYTE, DataType.BYTE) val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - checkDt(variable, setOf(DataType.UBYTE, DataType.BYTE)) + checkDt(variable, DataType.UBYTE, DataType.BYTE) if(value.type!=variable.type) throw VmExecutionException("datatype mismatch") variables[ins.callLabel!!] = value } Opcode.POP_VAR_WORD -> { val value = evalstack.pop() - checkDt(value, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)) + checkDt(value, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS) val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - checkDt(variable, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)) + checkDt(variable, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS) if(value.type!=variable.type) throw VmExecutionException("datatype mismatch") variables[ins.callLabel!!] = value } - Opcode.COPY_VAR_BYTE -> { - val source = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - val dest = variables[ins.callLabel2] ?: throw VmExecutionException("unknown variable: ${ins.callLabel2}") - checkDt(source, setOf(DataType.UBYTE, DataType.BYTE)) - checkDt(dest, setOf(DataType.UBYTE, DataType.BYTE)) - if(dest.type!=source.type) - throw VmExecutionException("datatype mismatch") - variables[ins.callLabel2!!] = source - } - Opcode.COPY_VAR_WORD -> { - val source = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - val dest = variables[ins.callLabel2] ?: throw VmExecutionException("unknown variable: ${ins.callLabel2}") - checkDt(source, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)) - checkDt(dest, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)) - if(dest.type!=source.type) - throw VmExecutionException("datatype mismatch") - variables[ins.callLabel2!!] = source - } - Opcode.COPY_VAR_FLOAT -> { - val source = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - val dest = variables[ins.callLabel2] ?: throw VmExecutionException("unknown variable: ${ins.callLabel2}") - checkDt(source, DataType.FLOAT) - checkDt(dest, DataType.FLOAT) - variables[ins.callLabel2!!] = source - } - Opcode.COPY_MEM_BYTE -> { - val sourceAddr = ins.arg!!.integerValue() - val destAddr = ins.arg2!!.integerValue() - mem.setUByte(destAddr, mem.getUByte(sourceAddr)) - } - Opcode.COPY_MEM_WORD -> { - val sourceAddr = ins.arg!!.integerValue() - val destAddr = ins.arg2!!.integerValue() - mem.setUWord(destAddr, mem.getUWord(sourceAddr)) - } - Opcode.COPY_MEM_FLOAT -> { - val sourceAddr = ins.arg!!.integerValue() - val destAddr = ins.arg2!!.integerValue() - mem.setFloat(destAddr, mem.getFloat(sourceAddr)) - } Opcode.POP_VAR_FLOAT -> { val value = evalstack.pop() checkDt(value, DataType.FLOAT) @@ -1275,7 +1223,7 @@ class StackVm(private var traceOutputFile: String?) { // store byte value on the stack in variable[index] (index is on the stack as well) val index = evalstack.pop().integerValue() val value = evalstack.pop() - checkDt(value, setOf(DataType.UBYTE, DataType.BYTE)) + 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 @@ -1302,7 +1250,7 @@ class StackVm(private var traceOutputFile: String?) { // store word value on the stack in variable[index] (index is on the stack as well) val index = evalstack.pop().integerValue() val value = evalstack.pop() - checkDt(value, setOf(DataType.UWORD, DataType.WORD)) + 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 @@ -1570,7 +1518,7 @@ class StackVm(private var traceOutputFile: String?) { } Syscall.FUNC_WRD -> { val value = evalstack.pop() - checkDt(value, setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD)) + checkDt(value, DataType.UBYTE, DataType.BYTE, DataType.UWORD) when(value.type) { DataType.UBYTE, DataType.BYTE -> evalstack.push(Value(DataType.WORD, value.integerValue())) DataType.UWORD -> { @@ -1587,7 +1535,7 @@ class StackVm(private var traceOutputFile: String?) { } Syscall.FUNC_UWRD -> { val value = evalstack.pop() - checkDt(value, setOf(DataType.UBYTE, DataType.BYTE, DataType.WORD)) + checkDt(value, DataType.UBYTE, DataType.BYTE, DataType.WORD) when(value.type) { DataType.UBYTE -> evalstack.push(Value(DataType.UWORD, value.integerValue())) DataType.UWORD -> evalstack.push(value) diff --git a/compiler/test/StackVMOpcodeTests.kt b/compiler/test/StackVMOpcodeTests.kt index e67a20102..c9e5c4bb3 100644 --- a/compiler/test/StackVMOpcodeTests.kt +++ b/compiler/test/StackVMOpcodeTests.kt @@ -222,10 +222,10 @@ class TestStackVmOpcodes { Instruction(Opcode.PUSH_WORD, Value(DataType.WORD, -23456)), Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 177)), Instruction(Opcode.PUSH_BYTE, Value(DataType.BYTE, -55)), - Instruction(Opcode.POP_MEM_B, Value(DataType.UWORD, 0x2000)), - Instruction(Opcode.POP_MEM_UB, Value(DataType.UWORD, 0x2001)), - Instruction(Opcode.POP_MEM_W, Value(DataType.UWORD, 0x3000)), - Instruction(Opcode.POP_MEM_UW, Value(DataType.UWORD, 0x3002)), + Instruction(Opcode.POP_MEM_BYTE, Value(DataType.UWORD, 0x2000)), + Instruction(Opcode.POP_MEM_BYTE, Value(DataType.UWORD, 0x2001)), + Instruction(Opcode.POP_MEM_WORD, Value(DataType.UWORD, 0x3000)), + Instruction(Opcode.POP_MEM_WORD, Value(DataType.UWORD, 0x3002)), Instruction(Opcode.POP_MEM_FLOAT, Value(DataType.UWORD, 0x4000))) vm.load(makeProg(ins), null) assertEquals(0, vm.mem.getUWord(0x2000)) @@ -281,51 +281,6 @@ class TestStackVmOpcodes { } } - @Test - fun testCopyVar() { - val ins = mutableListOf( - Instruction(Opcode.COPY_VAR_BYTE, null, null, "bvar1", "bvar2"), - Instruction(Opcode.COPY_VAR_WORD, null, null, "wvar1", "wvar2"), - Instruction(Opcode.COPY_VAR_FLOAT, null, null, "fvar1", "fvar2"), - Instruction(Opcode.COPY_VAR_WORD, null, null, "wvar1", "bvar2")) - val vars = mapOf( - "bvar1" to Value(DataType.UBYTE, 1), - "bvar2" to Value(DataType.UBYTE, 2), - "wvar1" to Value(DataType.UWORD, 1111), - "wvar2" to Value(DataType.UWORD, 2222), - "fvar1" to Value(DataType.FLOAT, 11.11), - "fvar2" to Value(DataType.FLOAT, 22.22) - ) - vm.load(makeProg(ins, vars), null) - assertEquals(12, vm.variables.size) - vm.step(3) - assertEquals(Value(DataType.UBYTE, 1), vm.variables["bvar2"]) - assertEquals(Value(DataType.UWORD, 1111), vm.variables["wvar2"]) - assertEquals(Value(DataType.FLOAT, 11.11), vm.variables["fvar2"]) - assertFailsWith { - vm.step(1) - } - } - - @Test - fun testCopyMem() { - val ins = mutableListOf( - Instruction(Opcode.COPY_MEM_BYTE, Value(DataType.UWORD, 0xc000), Value(DataType.UWORD, 0xc001)), - Instruction(Opcode.COPY_MEM_WORD, Value(DataType.UWORD, 0xc100), Value(DataType.UWORD, 0xc102)), - Instruction(Opcode.COPY_MEM_FLOAT, Value(DataType.UWORD, 0xc200), Value(DataType.UWORD, 0xc300))) - val mem=mapOf(0xc000 to listOf(Value(DataType.UBYTE, 0x45)), - 0xc100 to listOf(Value(DataType.UWORD, 0xc2ca)), - 0xc200 to listOf(Value(DataType.FLOAT, 42.25))) - vm.load(makeProg(ins, mem=mem), null) - assertEquals(0, vm.mem.getUByte(0xc001)) - assertEquals(0, vm.mem.getUWord(0xc102)) - assertEquals(0.0, vm.mem.getFloat(0xc300)) - vm.step(3) - assertEquals(0x45, vm.mem.getUByte(0xc001)) - assertEquals(0xc2ca, vm.mem.getUWord(0xc102)) - assertEquals(42.25, vm.mem.getFloat(0xc300)) - } - @Test fun testAdd() { testBinaryOperator(Value(DataType.UBYTE, 140), Opcode.ADD_UB, Value(DataType.UBYTE, 222), Value(DataType.UBYTE, 106))