diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt index c50d70bd3..8de1d46e3 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt @@ -81,12 +81,13 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe val result = mutableListOf() val left = exprGen.translateExpression(call.args[0]) val right = exprGen.translateExpression(call.args[1]) - val targetReg = codeGen.registers.nextFree() - addToResult(result, left, SyscallRegisterBase, -1) - addToResult(result, right, SyscallRegisterBase+1, -1) + addToResult(result, left, left.resultReg, -1) + addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=left.resultReg), null) + addToResult(result, right, right.resultReg, -1) + addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=right.resultReg), null) addInstr(result, IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.COMPARE_STRINGS.number), null) - addInstr(result, IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=targetReg), null) - return ExpressionCodeResult(result, IRDataType.BYTE, targetReg, -1) + addInstr(result, IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=left.resultReg), null) + return ExpressionCodeResult(result, IRDataType.BYTE, left.resultReg, -1) } private fun funcCmp(call: PtBuiltinFunctionCall): ExpressionCodeResult { @@ -116,9 +117,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe } val result = mutableListOf() val tr = exprGen.translateExpression(call.args[0]) - addToResult(result, tr, SyscallRegisterBase, -1) + addToResult(result, tr, tr.resultReg, -1) result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, immediate = array.length) + it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length) + it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg) it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number) it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg) } @@ -139,9 +142,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe } val result = mutableListOf() val tr = exprGen.translateExpression(call.args[0]) - addToResult(result, tr, SyscallRegisterBase, -1) + addToResult(result, tr, tr.resultReg, -1) result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, immediate = array.length) + it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length) + it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg) it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number) it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg) } @@ -265,9 +270,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe } val result = mutableListOf() val tr = exprGen.translateExpression(call.args[0]) - addToResult(result, tr, SyscallRegisterBase, -1) + addToResult(result, tr, tr.resultReg, -1) result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, immediate = array.length) + it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length) + it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg) it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number) } return ExpressionCodeResult(result, IRDataType.BYTE, -1, -1) @@ -288,9 +295,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe } val result = mutableListOf() val tr = exprGen.translateExpression(call.args[0]) - addToResult(result, tr, SyscallRegisterBase, -1) + addToResult(result, tr, tr.resultReg, -1) result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, immediate = array.length) + it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length) + it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg) it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number) } return ExpressionCodeResult(result, IRDataType.BYTE, -1, -1) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 592b628cd..d29adec0c 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -111,42 +111,47 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { when(iterable.dt) { DataType.STR -> { tr = translateExpression(check.element) - addToResult(result, tr, SyscallRegisterBase, -1) + addToResult(result, tr, tr.resultReg, -1) + addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg), null) tr = translateExpression(check.iterable) - addToResult(result, tr, SyscallRegisterBase+1, -1) - val resultReg = codeGen.registers.nextFree() + addToResult(result, tr, tr.resultReg, -1) + addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg), null) result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.STRING_CONTAINS.number) - it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=resultReg) + it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg) } - return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) + return ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1) } DataType.ARRAY_UB, DataType.ARRAY_B -> { tr = translateExpression(check.element) - addToResult(result, tr, SyscallRegisterBase, -1) + addToResult(result, tr, tr.resultReg, -1) + addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg), null) tr = translateExpression(check.iterable) - addToResult(result, tr, SyscallRegisterBase+1, -1) - val resultReg = codeGen.registers.nextFree() + addToResult(result, tr, tr.resultReg, -1) result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=SyscallRegisterBase+2, immediate = iterable.length!!) + it += IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=tr.resultReg, immediate = iterable.length!!) + it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg) it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.BYTEARRAY_CONTAINS.number) - it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=resultReg) + it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg) } // SysCall call convention: return value in register r0 - return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) + return ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1) } DataType.ARRAY_UW, DataType.ARRAY_W -> { tr = translateExpression(check.element) - addToResult(result, tr, SyscallRegisterBase, -1) + addToResult(result, tr, tr.resultReg, -1) + addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg), null) tr = translateExpression(check.iterable) - addToResult(result, tr, SyscallRegisterBase+1, -1) - val resultReg = codeGen.registers.nextFree() + addToResult(result, tr, tr.resultReg, -1) result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=SyscallRegisterBase+2, immediate = iterable.length!!) + it += IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=tr.resultReg, immediate = iterable.length!!) + it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg) it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.WORDARRAY_CONTAINS.number) - it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=resultReg) + it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg) } - return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) + return ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1) } DataType.ARRAY_F -> throw AssemblyError("containment check in float-array not supported") else -> throw AssemblyError("weird iterable dt ${iterable.dt} for ${check.iterable.name}") diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt index 915805a83..3458c8026 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt @@ -1,11 +1,7 @@ package prog8.codegen.intermediate -import prog8.code.core.AssemblyError -import prog8.intermediate.SyscallRegisterBase - internal class RegisterPool { - // reserve 0,1,2 for return values of subroutine calls and syscalls - // TODO set this back to 0 once 'resultRegister' has been removed everywhere and DIVMOD fixed to not use r0? + // reserve 0,1,2 for return values of subroutine calls and syscalls in IR assembly code private var firstFree: Int=3 private var firstFreeFloat: Int=3 @@ -15,16 +11,12 @@ internal class RegisterPool { fun nextFree(): Int { val result = firstFree firstFree++ - if(firstFree >= SyscallRegisterBase) - throw AssemblyError("out of virtual registers (int)") return result } fun nextFreeFloat(): Int { val result = firstFreeFloat firstFreeFloat++ - if(firstFreeFloat >= SyscallRegisterBase) - throw AssemblyError("out of virtual registers (fp)") return result } } diff --git a/compiler/res/prog8lib/virtual/conv.p8 b/compiler/res/prog8lib/virtual/conv.p8 index 54f290b71..00c434b6e 100644 --- a/compiler/res/prog8lib/virtual/conv.p8 +++ b/compiler/res/prog8lib/virtual/conv.p8 @@ -196,7 +196,8 @@ sub str2uword(str string) -> uword { ; the number may NOT be preceded by a + sign and may NOT contain spaces ; (any non-digit character will terminate the number string that is parsed) %ir {{ - loadm.w r65500,conv.str2uword.string + loadm.w r65535,conv.str2uword.string + push.w r65535 syscall 11 pop.w r0 returnreg.w r0 @@ -208,7 +209,8 @@ sub str2word(str string) -> word { ; the number may be preceded by a + or - sign but may NOT contain spaces ; (any non-digit character will terminate the number string that is parsed) %ir {{ - loadm.w r65500,conv.str2word.string + loadm.w r65535,conv.str2word.string + push.w r65535 syscall 12 pop.w r0 returnreg.w r0 diff --git a/compiler/res/prog8lib/virtual/floats.p8 b/compiler/res/prog8lib/virtual/floats.p8 index 7df5973c1..9b71b9b57 100644 --- a/compiler/res/prog8lib/virtual/floats.p8 +++ b/compiler/res/prog8lib/virtual/floats.p8 @@ -10,7 +10,8 @@ floats { sub print_f(float value) { ; ---- prints the floating point value (without a newline). %ir {{ - loadm.f fr65500,floats.print_f.value + loadm.f fr65535,floats.print_f.value + push.f fr65535 syscall 25 return }} @@ -134,7 +135,8 @@ sub rndf() -> float { sub rndseedf(float seed) { %ir {{ - loadm.f fr65500,floats.rndseedf.seed + loadm.f fr65535,floats.rndseedf.seed + push.f fr65535 syscall 32 }} } diff --git a/compiler/res/prog8lib/virtual/math.p8 b/compiler/res/prog8lib/virtual/math.p8 index 24b08927b..932b8441d 100644 --- a/compiler/res/prog8lib/virtual/math.p8 +++ b/compiler/res/prog8lib/virtual/math.p8 @@ -178,8 +178,10 @@ math { sub rndseed(uword seed1, uword seed2) { ; -- reset the pseudo RNG's seed values. Defaults are: $a55a, $7653. %ir {{ - loadm.w r65500,math.rndseed.seed1 - loadm.w r65501,math.rndseed.seed2 + loadm.w r65535,math.rndseed.seed1 + push.w r65535 + loadm.w r65535,math.rndseed.seed2 + push.w r65535 syscall 31 return }} diff --git a/compiler/res/prog8lib/virtual/string.p8 b/compiler/res/prog8lib/virtual/string.p8 index dba18a17f..325606cc8 100644 --- a/compiler/res/prog8lib/virtual/string.p8 +++ b/compiler/res/prog8lib/virtual/string.p8 @@ -84,8 +84,10 @@ string { ; Note that you can also directly compare strings and string values with eachother using ; comparison operators ==, < etcetera (it will use strcmp for you under water automatically). %ir {{ - loadm.w r65500,string.compare.st1 - loadm.w r65501,string.compare.st2 + loadm.w r65535,string.compare.st1 + push.w r65535 + loadm.w r65535,string.compare.st2 + push.w r65535 syscall 29 pop.b r0 returnreg.b r0 diff --git a/compiler/res/prog8lib/virtual/syslib.p8 b/compiler/res/prog8lib/virtual/syslib.p8 index 043734427..ae00718d6 100644 --- a/compiler/res/prog8lib/virtual/syslib.p8 +++ b/compiler/res/prog8lib/virtual/syslib.p8 @@ -15,7 +15,8 @@ sys { sub wait(uword jiffies) { ; --- wait approximately the given number of jiffies (1/60th seconds) %ir {{ - loadm.w r65500,sys.wait.jiffies + loadm.w r65535,sys.wait.jiffies + push.w r65535 syscall 13 }} } @@ -62,7 +63,8 @@ sys { sub exit(ubyte returnvalue) { ; -- immediately exit the program with a return code in the A register %ir {{ - loadm.b r65500,sys.exit.returnvalue + loadm.b r65535,sys.exit.returnvalue + push.b r65535 syscall 1 }} } @@ -82,31 +84,38 @@ sys { sub gfx_enable(ubyte mode) { %ir {{ - loadm.b r65500,sys.gfx_enable.mode + loadm.b r65535,sys.gfx_enable.mode + push.b r65535 syscall 8 }} } sub gfx_clear(ubyte color) { %ir {{ - loadm.b r65500,sys.gfx_clear.color + loadm.b r65535,sys.gfx_clear.color + push.b r65535 syscall 9 }} } sub gfx_plot(uword xx, uword yy, ubyte color) { %ir {{ - loadm.w r65500,sys.gfx_plot.xx - loadm.w r65501,sys.gfx_plot.yy - loadm.b r65502,sys.gfx_plot.color + loadm.w r65535,sys.gfx_plot.xx + push.w r65535 + loadm.w r65535,sys.gfx_plot.yy + push.w r65535 + loadm.b r65535,sys.gfx_plot.color + push.b r65535 syscall 10 }} } sub gfx_getpixel(uword xx, uword yy) -> ubyte { %ir {{ - loadm.w r65500,sys.gfx_getpixel.xx - loadm.w r65501,sys.gfx_getpixel.yy + loadm.w r65535,sys.gfx_getpixel.xx + push.w r65535 + loadm.w r65535,sys.gfx_getpixel.yy + push.w r65535 syscall 30 pop.b r0 returnreg.b r0 diff --git a/compiler/res/prog8lib/virtual/textio.p8 b/compiler/res/prog8lib/virtual/textio.p8 index 2fb7de28f..de834dfb4 100644 --- a/compiler/res/prog8lib/virtual/textio.p8 +++ b/compiler/res/prog8lib/virtual/textio.p8 @@ -15,7 +15,8 @@ sub height() -> ubyte { sub clear_screen() { str @shared sequence = "\x1b[2J\x1B[H" %ir {{ - load.w r65500,txt.clear_screen.sequence + load.w r65535,txt.clear_screen.sequence + push.w r65535 syscall 3 }} } @@ -38,14 +39,16 @@ sub uppercase() { sub chrout(ubyte char) { %ir {{ - loadm.b r65500,txt.chrout.char + loadm.b r65535,txt.chrout.char + push.b r65535 syscall 2 }} } sub print (str text) { %ir {{ - loadm.w r65500,txt.print.text + loadm.w r65535,txt.print.text + push.w r65535 syscall 3 }} } @@ -122,7 +125,8 @@ sub input_chars (uword buffer) -> ubyte { ; ---- Input a string (max. 80 chars) from the keyboard. Returns length of input. (string is terminated with a 0 byte as well) ; It assumes the keyboard is selected as I/O channel! %ir {{ - loadm.w r65500,txt.input_chars.buffer + loadm.w r65535,txt.input_chars.buffer + push.w r65535 syscall 6 pop.b r0 returnreg.b r0 diff --git a/docs/source/todo.rst b/docs/source/todo.rst index b4046f519..f64b02443 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,7 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ -change syscalls to take parameters on value stack (not in r65500+ registers) +test vm array reverse, sort, string containment, string input, float array containment (how translated? there is no syscall) ... diff --git a/examples/test.p8 b/examples/test.p8 index 93b8b788a..a9f967b3f 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,12 +1,11 @@ %import textio -%zeropage basicsafe +%import math +%import floats +%import string + main { sub start() { - cx16.r1=0 - for cx16.r0 in 0 to 10 { - cx16.r1++ - } - txt.print_uw(cx16.r1) + math.rndseed(11111,22222) } } diff --git a/intermediate/src/prog8/intermediate/IMSyscall.kt b/intermediate/src/prog8/intermediate/IMSyscall.kt index 950db650e..9ef784d98 100644 --- a/intermediate/src/prog8/intermediate/IMSyscall.kt +++ b/intermediate/src/prog8/intermediate/IMSyscall.kt @@ -23,5 +23,3 @@ enum class IMSyscall(val number: Int) { BYTEARRAY_CONTAINS(10015), WORDARRAY_CONTAINS(10016) } - -const val SyscallRegisterBase = 65500 diff --git a/virtualmachine/src/prog8/vm/Registers.kt b/virtualmachine/src/prog8/vm/Registers.kt index 3d6ab7cfe..e296f2e7f 100644 --- a/virtualmachine/src/prog8/vm/Registers.kt +++ b/virtualmachine/src/prog8/vm/Registers.kt @@ -7,7 +7,7 @@ package prog8.vm */ class Registers { private val registers = Array(65536) { 0u } - private val floatRegisters = Array(65535) { 0f } + private val floatRegisters = Array(65536) { 0f } var cpuA: UByte = 0u var cpuX: UByte = 0u var cpuY: UByte = 0u diff --git a/virtualmachine/src/prog8/vm/SysCalls.kt b/virtualmachine/src/prog8/vm/SysCalls.kt index ce4ca0e6b..67061a597 100644 --- a/virtualmachine/src/prog8/vm/SysCalls.kt +++ b/virtualmachine/src/prog8/vm/SysCalls.kt @@ -1,7 +1,6 @@ package prog8.vm import prog8.code.core.AssemblyError -import prog8.intermediate.SyscallRegisterBase import kotlin.math.min /* @@ -92,14 +91,14 @@ object SysCalls { vm.reset(false) } Syscall.EXIT ->{ - vm.exit(vm.registers.getUB(SyscallRegisterBase).toInt()) + vm.exit(vm.valueStack.pop().toInt()) } Syscall.PRINT_C -> { - val char = vm.registers.getUB(SyscallRegisterBase).toInt() + val char = vm.valueStack.pop().toInt() print(Char(char)) } Syscall.PRINT_S -> { - var addr = vm.registers.getUW(SyscallRegisterBase).toInt() + var addr = vm.valueStack.popw().toInt() while(true) { val char = vm.memory.getUB(addr).toInt() if(char==0) @@ -109,21 +108,21 @@ object SysCalls { } } Syscall.PRINT_U8 -> { - print(vm.registers.getUB(SyscallRegisterBase)) + print(vm.valueStack.pop()) } Syscall.PRINT_U16 -> { - print(vm.registers.getUW(SyscallRegisterBase)) + print(vm.valueStack.popw()) } Syscall.INPUT -> { var input = readln() - val maxlen = vm.registers.getUB(SyscallRegisterBase+1).toInt() + val maxlen = vm.valueStack.pop().toInt() if(maxlen>0) input = input.substring(0, min(input.length, maxlen)) - vm.memory.setString(vm.registers.getUW(SyscallRegisterBase).toInt(), input, true) + vm.memory.setString(vm.valueStack.popw().toInt(), input, true) vm.valueStack.pushw(input.length.toUShort()) } Syscall.SLEEP -> { - val duration = vm.registers.getUW(SyscallRegisterBase).toLong() + val duration = vm.valueStack.popw().toLong() Thread.sleep(duration) } Syscall.GFX_ENABLE -> vm.gfx_enable() @@ -131,13 +130,13 @@ object SysCalls { Syscall.GFX_PLOT -> vm.gfx_plot() Syscall.GFX_GETPIXEL ->vm.gfx_getpixel() Syscall.WAIT -> { - val millis = vm.registers.getUW(SyscallRegisterBase).toLong() * 1000/60 + val millis = vm.valueStack.popw().toLong() * 1000/60 Thread.sleep(millis) } Syscall.WAITVSYNC -> vm.waitvsync() Syscall.SORT_UBYTE -> { - val address = vm.registers.getUW(SyscallRegisterBase).toInt() - val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() + val length = vm.valueStack.pop().toInt() + val address = vm.valueStack.popw().toInt() val array = IntProgression.fromClosedRange(address, address+length-1, 1).map { vm.memory.getUB(it) }.sorted() @@ -146,8 +145,8 @@ object SysCalls { } } Syscall.SORT_BYTE -> { - val address = vm.registers.getUW(SyscallRegisterBase).toInt() - val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() + val length = vm.valueStack.pop().toInt() + val address = vm.valueStack.popw().toInt() val array = IntProgression.fromClosedRange(address, address+length-1, 1).map { vm.memory.getSB(it) }.sorted() @@ -156,8 +155,8 @@ object SysCalls { } } Syscall.SORT_UWORD -> { - val address = vm.registers.getUW(SyscallRegisterBase).toInt() - val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() + val length = vm.valueStack.pop().toInt() + val address = vm.valueStack.popw().toInt() val array = IntProgression.fromClosedRange(address, address+length*2-2, 2).map { vm.memory.getUW(it) }.sorted() @@ -166,8 +165,8 @@ object SysCalls { } } Syscall.SORT_WORD -> { - val address = vm.registers.getUW(SyscallRegisterBase).toInt() - val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() + val length = vm.valueStack.pop().toInt() + val address = vm.valueStack.popw().toInt() val array = IntProgression.fromClosedRange(address, address+length*2-2, 2).map { vm.memory.getSW(it) }.sorted() @@ -176,8 +175,8 @@ object SysCalls { } } Syscall.REVERSE_BYTES -> { - val address = vm.registers.getUW(SyscallRegisterBase).toInt() - val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() + val length = vm.valueStack.pop().toInt() + val address = vm.valueStack.popw().toInt() val array = IntProgression.fromClosedRange(address, address+length-1, 1).map { vm.memory.getUB(it) }.reversed() @@ -186,8 +185,8 @@ object SysCalls { } } Syscall.REVERSE_WORDS -> { - val address = vm.registers.getUW(SyscallRegisterBase).toInt() - val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() + val length = vm.valueStack.pop().toInt() + val address = vm.valueStack.popw().toInt() val array = IntProgression.fromClosedRange(address, address+length*2-2, 2).map { vm.memory.getUW(it) }.reversed() @@ -196,8 +195,8 @@ object SysCalls { } } Syscall.REVERSE_FLOATS -> { - val address = vm.registers.getUW(SyscallRegisterBase).toInt() - val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() + val length = vm.valueStack.pop().toInt() + val address = vm.valueStack.popw().toInt() val array = IntProgression.fromClosedRange(address, address+length*4-2, 4).map { vm.memory.getFloat(it) }.reversed() @@ -206,8 +205,8 @@ object SysCalls { } } Syscall.ANY_BYTE -> { - val address = vm.registers.getUW(SyscallRegisterBase).toInt() - val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() + val length = vm.valueStack.pop().toInt() + val address = vm.valueStack.popw().toInt() val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2) if(addresses.any { vm.memory.getUB(it).toInt()!=0 }) vm.valueStack.push(1u) @@ -215,8 +214,8 @@ object SysCalls { vm.valueStack.push(0u) } Syscall.ANY_WORD -> { - val address = vm.registers.getUW(SyscallRegisterBase).toInt() - val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() + val length = vm.valueStack.pop().toInt() + val address = vm.valueStack.popw().toInt() val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2) if(addresses.any { vm.memory.getUW(it).toInt()!=0 }) vm.valueStack.push(1u) @@ -224,8 +223,8 @@ object SysCalls { vm.valueStack.push(0u) } Syscall.ANY_FLOAT -> { - val address = vm.registers.getUW(SyscallRegisterBase).toInt() - val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() + val length = vm.valueStack.pop().toInt() + val address = vm.valueStack.popw().toInt() val addresses = IntProgression.fromClosedRange(address, address+length*4-2, 4) if(addresses.any { vm.memory.getFloat(it).toInt()!=0 }) vm.valueStack.push(1u) @@ -233,8 +232,8 @@ object SysCalls { vm.valueStack.push(0u) } Syscall.ALL_BYTE -> { - val address = vm.registers.getUW(SyscallRegisterBase).toInt() - val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() + val length = vm.valueStack.pop().toInt() + val address = vm.valueStack.popw().toInt() val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2) if(addresses.all { vm.memory.getUB(it).toInt()!=0 }) vm.valueStack.push(1u) @@ -242,8 +241,8 @@ object SysCalls { vm.valueStack.push(0u) } Syscall.ALL_WORD -> { - val address = vm.registers.getUW(SyscallRegisterBase).toInt() - val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() + val length = vm.valueStack.pop().toInt() + val address = vm.valueStack.popw().toInt() val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2) if(addresses.all { vm.memory.getUW(it).toInt()!=0 }) vm.valueStack.push(1u) @@ -251,8 +250,8 @@ object SysCalls { vm.valueStack.push(0u) } Syscall.ALL_FLOAT -> { - val address = vm.registers.getUW(SyscallRegisterBase).toInt() - val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() + val length = vm.valueStack.pop().toInt() + val address = vm.valueStack.popw().toInt() val addresses = IntProgression.fromClosedRange(address, address+length*4-2, 4) if(addresses.all { vm.memory.getFloat(it).toInt()!=0 }) vm.valueStack.push(1u) @@ -260,11 +259,10 @@ object SysCalls { vm.valueStack.push(0u) } Syscall.PRINT_F -> { - val value = vm.registers.getFloat(SyscallRegisterBase) - print(value) + print(vm.valueStack.popf()) } Syscall.STR_TO_UWORD -> { - val stringAddr = vm.registers.getUW(SyscallRegisterBase) + val stringAddr = vm.valueStack.popw() val string = vm.memory.getString(stringAddr.toInt()).takeWhile { it.isDigit() } val value = try { string.toUShort() @@ -274,7 +272,7 @@ object SysCalls { vm.valueStack.pushw(value) } Syscall.STR_TO_WORD -> { - val stringAddr = vm.registers.getUW(SyscallRegisterBase) + val stringAddr = vm.valueStack.popw() val memstring = vm.memory.getString(stringAddr.toInt()) val match = Regex("^[+-]?\\d+").find(memstring) if(match==null) { @@ -289,8 +287,8 @@ object SysCalls { vm.valueStack.pushw(value.toUShort()) } Syscall.COMPARE_STRINGS -> { - val firstAddr = vm.registers.getUW(SyscallRegisterBase) - val secondAddr = vm.registers.getUW(SyscallRegisterBase+1) + val secondAddr = vm.valueStack.popw() + val firstAddr = vm.valueStack.popw() val first = vm.memory.getString(firstAddr.toInt()) val second = vm.memory.getString(secondAddr.toInt()) val comparison = first.compareTo(second) @@ -302,15 +300,15 @@ object SysCalls { vm.valueStack.push(1u) } Syscall.RNDFSEED -> { - val seed = vm.registers.getFloat(SyscallRegisterBase) + val seed = vm.valueStack.popf() if(seed>0) // always use negative seed, this mimics the behavior on CBM machines vm.randomSeedFloat(-seed) else vm.randomSeedFloat(seed) } Syscall.RNDSEED -> { - val seed1 = vm.registers.getUW(SyscallRegisterBase) - val seed2 = vm.registers.getUW(SyscallRegisterBase+1) + val seed2 = vm.valueStack.popw() + val seed1 = vm.valueStack.popw() vm.randomSeed(seed1, seed2) } Syscall.RND -> { @@ -323,15 +321,15 @@ object SysCalls { vm.valueStack.pushf(vm.randomGeneratorFloats.nextFloat()) } Syscall.STRING_CONTAINS -> { - val char = vm.registers.getUB(SyscallRegisterBase).toInt().toChar() - val stringAddr = vm.registers.getUW(SyscallRegisterBase+1) + val stringAddr = vm.valueStack.popw() + val char = vm.valueStack.pop().toInt().toChar() val string = vm.memory.getString(stringAddr.toInt()) vm.valueStack.push(if(char in string) 1u else 0u) } Syscall.BYTEARRAY_CONTAINS -> { - val value = vm.registers.getUB(SyscallRegisterBase) - var array = vm.registers.getUW(SyscallRegisterBase+1).toInt() - var length = vm.registers.getUB(SyscallRegisterBase+2) + var length = vm.valueStack.pop() + var array = vm.valueStack.popw().toInt() + val value = vm.valueStack.pop() while(length>0u) { if(vm.memory.getUB(array)==value) { vm.valueStack.push(1u) @@ -343,10 +341,9 @@ object SysCalls { vm.valueStack.push(0u) } Syscall.WORDARRAY_CONTAINS -> { - // r0.w = value, r1.w = array, r2.b = array length - val value = vm.registers.getUW(SyscallRegisterBase) - var array = vm.registers.getUW(SyscallRegisterBase+1).toInt() - var length = vm.registers.getUB(SyscallRegisterBase+2) + var length = vm.valueStack.pop() + var array = vm.valueStack.popw().toInt() + val value = vm.valueStack.popw() while(length>0u) { if(vm.memory.getUW(array)==value) { vm.valueStack.push(1u) diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 395f5167a..db434f601 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -117,17 +117,14 @@ class VirtualMachine(irProgram: IRProgram) { private fun stepNextChunk() { do { - val nextChunk = pcChunk.next - when (nextChunk) { + when (val nextChunk = pcChunk.next) { is IRCodeChunk -> { pcChunk = nextChunk pcIndex = 0 } - null -> { exit(0) // end of program reached } - else -> { throw IllegalArgumentException("VM cannot run code from non-code chunk $nextChunk") } @@ -142,8 +139,7 @@ class VirtualMachine(irProgram: IRProgram) { } private fun branchTo(i: IRInstruction) { - val target = i.branchTarget - when (target) { + when (val target = i.branchTarget) { is IRCodeChunk -> { pcChunk = target pcIndex = 0 @@ -154,7 +150,11 @@ class VirtualMachine(irProgram: IRProgram) { else throw IllegalArgumentException("no branchtarget in $i") } - else -> throw IllegalArgumentException("VM can't execute code in a non-codechunk: $target") + is IRInlineAsmChunk -> TODO() + is IRInlineBinaryChunk -> TODO() + else -> { + throw IllegalArgumentException("VM can't execute code in a non-codechunk: $target") + } } } @@ -335,7 +335,8 @@ class VirtualMachine(irProgram: IRProgram) { valueStack.pushw(value) } IRDataType.FLOAT -> { - throw IllegalArgumentException("can't PUSH a float") + val value = registers.getFloat(i.fpReg1!!) + valueStack.pushf(value) } } nextPc() @@ -343,26 +344,9 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsPOP(i: IRInstruction) { when(i.type!!) { - IRDataType.BYTE -> { - val value = valueStack.pop().toInt() - setResultReg(i.reg1!!, value, i.type!!) - } - IRDataType.WORD -> { - val msb = valueStack.pop() - val lsb = valueStack.pop() - val value = (msb.toInt() shl 8) + lsb.toInt() - setResultReg(i.reg1!!, value, i.type!!) - } - IRDataType.FLOAT -> { - // pop float; lsb is on bottom, msb on top - val b0 = valueStack.pop() - val b1 = valueStack.pop() - val b2 = valueStack.pop() - val b3 = valueStack.pop() - val bits = b3 + 256u*b2 + 65536u*b1 + 16777216u*b0 - val value = Float.fromBits(bits.toInt()) - registers.setFloat(i.fpReg1!!, value) - } + IRDataType.BYTE -> setResultReg(i.reg1!!, valueStack.pop().toInt(), i.type!!) + IRDataType.WORD -> setResultReg(i.reg1!!, valueStack.popw().toInt(), i.type!!) + IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, valueStack.popf()) } nextPc() } @@ -2289,7 +2273,7 @@ class VirtualMachine(irProgram: IRProgram) { private var window: GraphicsWindow? = null fun gfx_enable() { - window = when(registers.getUB(SyscallRegisterBase).toInt()) { + window = when(valueStack.pop().toInt()) { 0 -> GraphicsWindow(320, 240, 3) 1 -> GraphicsWindow(640, 480, 2) else -> throw IllegalArgumentException("invalid screen mode") @@ -2298,21 +2282,23 @@ class VirtualMachine(irProgram: IRProgram) { } fun gfx_clear() { - window?.clear(registers.getUB(SyscallRegisterBase).toInt()) + window?.clear(valueStack.pop().toInt()) } fun gfx_plot() { - window?.plot(registers.getUW(SyscallRegisterBase).toInt(), - registers.getUW(SyscallRegisterBase+1).toInt(), - registers.getUB(SyscallRegisterBase+2).toInt()) + val color = valueStack.pop() + val y = valueStack.popw() + val x = valueStack.popw() + window?.plot(x.toInt(), y.toInt(), color.toInt()) } fun gfx_getpixel() { if(window==null) registers.setUB(0, 0u) else { - val color = Color(window!!.getpixel(registers.getUW(SyscallRegisterBase).toInt(), - registers.getUW(SyscallRegisterBase+1).toInt())) + val y = valueStack.popw() + val x = valueStack.popw() + val color = Color(window!!.getpixel(x.toInt(), y.toInt())) registers.setUB(0, color.green.toUByte()) } } @@ -2351,6 +2337,22 @@ internal fun Stack.pushf(value: Float) { push(bits.toUByte()) } +internal fun Stack.popw(): UShort { + val msb = pop() + val lsb = pop() + return ((msb.toInt() shl 8) + lsb.toInt()).toUShort() +} + +internal fun Stack.popf(): Float { + // pop float; lsb is on bottom, msb on top + val b0 = pop() + val b1 = pop() + val b2 = pop() + val b3 = pop() + val bits = b3 + 256u*b2 + 65536u*b1 + 16777216u*b0 + return Float.fromBits(bits.toInt()) +} + // probably called via reflection class VmRunner: IVirtualMachineRunner { override fun runProgram(irSource: String) {