From 38efaae7b28db8d85b5be8342606ffd8876a54aa Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 6 Nov 2022 12:40:39 +0100 Subject: [PATCH] ir/vm: syscall params in high base register to avoid push/pop --- .../codegen/intermediate/BuiltinFuncGen.kt | 20 +-- .../codegen/intermediate/ExpressionGen.kt | 147 +++++++----------- .../codegen/intermediate/RegisterPool.kt | 10 +- compiler/res/prog8lib/virtual/conv.p8 | 4 +- compiler/res/prog8lib/virtual/floats.p8 | 8 +- compiler/res/prog8lib/virtual/math.p8 | 4 +- compiler/res/prog8lib/virtual/string.p8 | 4 +- compiler/res/prog8lib/virtual/syslib.p8 | 18 +-- compiler/res/prog8lib/virtual/textio.p8 | 8 +- docs/source/todo.rst | 7 +- examples/test.p8 | 18 ++- .../src/prog8/intermediate/IMSyscall.kt | 4 +- virtualmachine/src/prog8/vm/SysCalls.kt | 108 ++++++------- virtualmachine/src/prog8/vm/VirtualMachine.kt | 19 ++- 14 files changed, 186 insertions(+), 193 deletions(-) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt index 1e81a1495..4678e12ff 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt @@ -71,11 +71,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe else -> throw IllegalArgumentException("weird type") } val result = mutableListOf() - result += exprGen.translateExpression(call.args[0], 0, -1) + result += exprGen.translateExpression(call.args[0], SyscallRegisterBase, -1) result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, value = array.length) it += IRInstruction(Opcode.SYSCALL, value = syscall.number) - if (resultRegister != 0) + if(resultRegister!=0) it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0) } return result @@ -94,11 +94,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe else -> throw IllegalArgumentException("weird type") } val result = mutableListOf() - result += exprGen.translateExpression(call.args[0], 0, -1) + result += exprGen.translateExpression(call.args[0], SyscallRegisterBase, -1) result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, value = array.length) it += IRInstruction(Opcode.SYSCALL, value = syscall.number) - if (resultRegister != 0) + if(resultRegister!=0) it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0) } return result @@ -213,9 +213,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe else -> throw IllegalArgumentException("weird type to reverse") } val result = mutableListOf() - result += exprGen.translateExpression(call.args[0], 0, -1) + result += exprGen.translateExpression(call.args[0], SyscallRegisterBase, -1) result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, value = array.length) it += IRInstruction(Opcode.SYSCALL, value = syscall.number) } return result @@ -235,9 +235,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe else -> throw IllegalArgumentException("weird type to sort") } val result = mutableListOf() - result += exprGen.translateExpression(call.args[0], 0, -1) + result += exprGen.translateExpression(call.args[0], SyscallRegisterBase, -1) result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, value = array.length) it += IRInstruction(Opcode.SYSCALL, value = syscall.number) } return result diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 6a890f51d..d1a4ab85d 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -10,7 +10,7 @@ import prog8.intermediate.* internal class ExpressionGen(private val codeGen: IRCodeGen) { fun translateExpression(expr: PtExpression, resultRegister: Int, resultFpRegister: Int): IRCodeChunks { - require(codeGen.registers.peekNext() > resultRegister) + require(codeGen.registers.peekNext() > resultRegister || resultRegister >= SyscallRegisterBase) return when (expr) { is PtMachineRegister -> { @@ -101,49 +101,33 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val iterable = codeGen.symbolTable.flat.getValue(check.iterable.targetName) as StStaticVariable when(iterable.dt) { DataType.STR -> { - val push = IRCodeChunk(null, null) - push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1) - result += push - result += translateExpression(check.element, 0, -1) - result += translateExpression(check.iterable, 1, -1) - val syscall = IRCodeChunk(null, null) - syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.STRING_CONTAINS.number) - syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1) - if(resultRegister!=0) - syscall += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0) - result += syscall + result += translateExpression(check.element, SyscallRegisterBase, -1) + result += translateExpression(check.iterable, SyscallRegisterBase+1, -1) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.STRING_CONTAINS.number) + if(resultRegister!=0) + it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0) + } } DataType.ARRAY_UB, DataType.ARRAY_B -> { - val push = IRCodeChunk(null, null) - push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1) - push += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=2) - result += push - result += translateExpression(check.element, 0, -1) - result += translateExpression(check.iterable, 1, -1) - val syscall = IRCodeChunk(null, null) - syscall += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=2, value = iterable.length!!) - syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.BYTEARRAY_CONTAINS.number) - syscall += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=2) - syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1) - if(resultRegister!=0) - syscall += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0) - result += syscall + result += translateExpression(check.element, SyscallRegisterBase, -1) + result += translateExpression(check.iterable, SyscallRegisterBase+1, -1) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=SyscallRegisterBase+2, value = iterable.length!!) + it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.BYTEARRAY_CONTAINS.number) + if(resultRegister!=0) + it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0) + } } DataType.ARRAY_UW, DataType.ARRAY_W -> { - val push = IRCodeChunk(null, null) - push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1) - push += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=2) - result += push - result += translateExpression(check.element, 0, -1) - result += translateExpression(check.iterable, 1, -1) - val syscall = IRCodeChunk(null, null) - syscall += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=2, value = iterable.length!!) - syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.WORDARRAY_CONTAINS.number) - syscall += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=2) - syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1) - if(resultRegister!=0) - syscall += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0) - result += syscall + result += translateExpression(check.element, SyscallRegisterBase, -1) + result += translateExpression(check.iterable, SyscallRegisterBase+1, -1) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=SyscallRegisterBase+2, value = iterable.length!!) + it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.WORDARRAY_CONTAINS.number) + if(resultRegister!=0) + it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0) + } } DataType.ARRAY_F -> throw AssemblyError("containment check in float-array not supported") else -> throw AssemblyError("weird iterable dt ${iterable.dt} for ${check.iterable.targetName}") @@ -332,23 +316,18 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister), null) } else { if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) { - require(codeGen.registers.peekNext() > 1) - val push = IRCodeChunk(null, null) - push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1) - result += push - result += translateExpression(binExpr.left, 0, -1) - result += translateExpression(binExpr.right, 1, -1) - val syscall = IRCodeChunk(null, null) - syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number) - if(resultRegister!=0) - syscall += IRInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=0) - syscall += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=1, value=0) - syscall += if(greaterEquals) - IRInstruction(Opcode.SGES, IRDataType.BYTE, reg1=resultRegister, reg2=1) - else - IRInstruction(Opcode.SGTS, IRDataType.BYTE, reg1=resultRegister, reg2=1) - syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1) - result += syscall + result += translateExpression(binExpr.left, SyscallRegisterBase, -1) + result += translateExpression(binExpr.right, SyscallRegisterBase+1, -1) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number) + if(resultRegister!=0) + it += IRInstruction(Opcode.LOADR, vmDt, reg1 = resultRegister, reg2 = 0) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = 0) + it += if (greaterEquals) + IRInstruction(Opcode.SGES, IRDataType.BYTE, reg1 = resultRegister, reg2 = 1) + else + IRInstruction(Opcode.SGTS, IRDataType.BYTE, reg1 = resultRegister, reg2 = 1) + } } else { val rightResultReg = codeGen.registers.nextFree() result += translateExpression(binExpr.left, resultRegister, -1) @@ -388,23 +367,18 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister), null) } else { if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) { - require(codeGen.registers.peekNext() > 1) - val push = IRCodeChunk(null, null) - push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1) - result += push - result += translateExpression(binExpr.left, 0, -1) - result += translateExpression(binExpr.right, 1, -1) - val syscall = IRCodeChunk(null, null) - syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number) - if(resultRegister!=0) - syscall += IRInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=0) - syscall += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=1, value=0) - syscall += if(lessEquals) - IRInstruction(Opcode.SLES, IRDataType.BYTE, reg1=resultRegister, reg2=1) - else - IRInstruction(Opcode.SLTS, IRDataType.BYTE, reg1=resultRegister, reg2=1) - syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1) - result += syscall + result += translateExpression(binExpr.left, SyscallRegisterBase, -1) + result += translateExpression(binExpr.right, SyscallRegisterBase+1, -1) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number) + if(resultRegister!=0) + it += IRInstruction(Opcode.LOADR, vmDt, reg1 = resultRegister, reg2 = 0) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = 0) + it += if (lessEquals) + IRInstruction(Opcode.SLES, IRDataType.BYTE, reg1 = resultRegister, reg2 = 1) + else + IRInstruction(Opcode.SLTS, IRDataType.BYTE, reg1 = resultRegister, reg2 = 1) + } } else { val rightResultReg = codeGen.registers.nextFree() result += translateExpression(binExpr.left, resultRegister, -1) @@ -440,21 +414,16 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } } else { if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) { - require(codeGen.registers.peekNext() > 1) - val push = IRCodeChunk(null, null) - push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1) - result += push - result += translateExpression(binExpr.left, 0, -1) - result += translateExpression(binExpr.right, 1, -1) - val syscall = IRCodeChunk(null, null) - syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number) - syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1) - if(resultRegister!=0) - syscall += IRInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=0) - if(!notEquals) - syscall += IRInstruction(Opcode.INV, vmDt, reg1=resultRegister) - syscall += IRInstruction(Opcode.AND, vmDt, reg1=resultRegister, value=1) - result += syscall + result += translateExpression(binExpr.left, SyscallRegisterBase, -1) + result += translateExpression(binExpr.right, SyscallRegisterBase+1, -1) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number) + if(resultRegister!=0) + it += IRInstruction(Opcode.LOADR, vmDt, reg1 = resultRegister, reg2 = 0) + if (!notEquals) + it += IRInstruction(Opcode.INV, vmDt, reg1 = resultRegister) + it += IRInstruction(Opcode.AND, vmDt, reg1 = resultRegister, value = 1) + } } else { val rightResultReg = codeGen.registers.nextFree() result += translateExpression(binExpr.left, resultRegister, -1) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt index 0d5ba036e..7d9b5516f 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt @@ -1,10 +1,12 @@ package prog8.codegen.intermediate import prog8.code.core.AssemblyError +import prog8.intermediate.SyscallRegisterBase internal class RegisterPool { - private var firstFree: Int=3 // integer registers 0,1,2 are reserved - private var firstFreeFloat: Int=0 + // reserve 0,1,2 for return values of subroutine calls and syscalls + private var firstFree: Int=3 + private var firstFreeFloat: Int=3 fun peekNext() = firstFree fun peekNextFloat() = firstFreeFloat @@ -12,7 +14,7 @@ internal class RegisterPool { fun nextFree(): Int { val result = firstFree firstFree++ - if(firstFree>65535) + if(firstFree >= SyscallRegisterBase) throw AssemblyError("out of virtual registers (int)") return result } @@ -20,7 +22,7 @@ internal class RegisterPool { fun nextFreeFloat(): Int { val result = firstFreeFloat firstFreeFloat++ - if(firstFreeFloat>65535) + 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 35775bed8..2c74fba9d 100644 --- a/compiler/res/prog8lib/virtual/conv.p8 +++ b/compiler/res/prog8lib/virtual/conv.p8 @@ -196,7 +196,7 @@ 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 r0,conv.str2uword.string + loadm.w r65500,conv.str2uword.string syscall 11 return }} @@ -207,7 +207,7 @@ 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 r0,conv.str2word.string + loadm.w r65500,conv.str2word.string syscall 12 return }} diff --git a/compiler/res/prog8lib/virtual/floats.p8 b/compiler/res/prog8lib/virtual/floats.p8 index ce9edf992..af4135ccf 100644 --- a/compiler/res/prog8lib/virtual/floats.p8 +++ b/compiler/res/prog8lib/virtual/floats.p8 @@ -10,7 +10,7 @@ floats { sub print_f(float value) { ; ---- prints the floating point value (without a newline). %ir {{ - loadm.f fr0,floats.print_f.value + loadm.f fr65500,floats.print_f.value syscall 25 return }} @@ -133,9 +133,9 @@ sub rndf() -> float { sub rndseedf(ubyte s1, ubyte s2, ubyte s3) { %ir {{ - loadm.b r0,floats.rndseedf.s1 - loadm.b r1,floats.rndseedf.s2 - loadm.b r2,floats.rndseedf.s3 + loadm.b r65500,floats.rndseedf.s1 + loadm.b r65501,floats.rndseedf.s2 + loadm.b r65502,floats.rndseedf.s3 syscall 32 }} } diff --git a/compiler/res/prog8lib/virtual/math.p8 b/compiler/res/prog8lib/virtual/math.p8 index 9a752c3ff..bdccb0ae5 100644 --- a/compiler/res/prog8lib/virtual/math.p8 +++ b/compiler/res/prog8lib/virtual/math.p8 @@ -176,8 +176,8 @@ math { sub rndseed(uword seed1, uword seed2) { ; -- reset the pseudo RNG's seed values. Defaults are: $a55a, $7653. %ir {{ - loadm.w r0,math.rndseed.seed1 - loadm.w r1,math.rndseed.seed2 + loadm.w r65500,math.rndseed.seed1 + loadm.w r65501,math.rndseed.seed2 syscall 31 return }} diff --git a/compiler/res/prog8lib/virtual/string.p8 b/compiler/res/prog8lib/virtual/string.p8 index 03d0b5c38..9c5833b87 100644 --- a/compiler/res/prog8lib/virtual/string.p8 +++ b/compiler/res/prog8lib/virtual/string.p8 @@ -84,8 +84,8 @@ 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 r0,string.compare.st1 - loadm.w r1,string.compare.st2 + loadm.w r65500,string.compare.st1 + loadm.w r65501,string.compare.st2 syscall 29 return }} diff --git a/compiler/res/prog8lib/virtual/syslib.p8 b/compiler/res/prog8lib/virtual/syslib.p8 index 8a20c3411..bcdb7edb5 100644 --- a/compiler/res/prog8lib/virtual/syslib.p8 +++ b/compiler/res/prog8lib/virtual/syslib.p8 @@ -15,7 +15,7 @@ sys { sub wait(uword jiffies) { ; --- wait approximately the given number of jiffies (1/60th seconds) %ir {{ - loadm.w r0,sys.wait.jiffies + loadm.w r65500,sys.wait.jiffies syscall 13 }} } @@ -62,7 +62,7 @@ sys { sub exit(ubyte returnvalue) { ; -- immediately exit the program with a return code in the A register %ir {{ - loadm.b r0,sys.exit.returnvalue + loadm.b r65500,sys.exit.returnvalue syscall 1 }} } @@ -82,31 +82,31 @@ sys { sub gfx_enable(ubyte mode) { %ir {{ - loadm.b r0,sys.gfx_enable.mode + loadm.b r65500,sys.gfx_enable.mode syscall 8 }} } sub gfx_clear(ubyte color) { %ir {{ - loadm.b r0,sys.gfx_clear.color + loadm.b r65500,sys.gfx_clear.color syscall 9 }} } sub gfx_plot(uword xx, uword yy, ubyte color) { %ir {{ - loadm.w r0,sys.gfx_plot.xx - loadm.w r1,sys.gfx_plot.yy - loadm.b r2,sys.gfx_plot.color + loadm.w r65500,sys.gfx_plot.xx + loadm.w r65501,sys.gfx_plot.yy + loadm.b r65502,sys.gfx_plot.color syscall 10 }} } sub gfx_getpixel(uword xx, uword yy) -> ubyte { %ir {{ - loadm.w r0,sys.gfx_getpixel.xx - loadm.w r1,sys.gfx_getpixel.yy + loadm.w r65500,sys.gfx_getpixel.xx + loadm.w r65501,sys.gfx_getpixel.yy syscall 30 return }} diff --git a/compiler/res/prog8lib/virtual/textio.p8 b/compiler/res/prog8lib/virtual/textio.p8 index 166199c05..dd6fcc810 100644 --- a/compiler/res/prog8lib/virtual/textio.p8 +++ b/compiler/res/prog8lib/virtual/textio.p8 @@ -7,7 +7,7 @@ txt { sub clear_screen() { str @shared sequence = "\x1b[2J\x1B[H" %ir {{ - load.w r0,txt.clear_screen.sequence + load.w r65500,txt.clear_screen.sequence syscall 3 }} } @@ -30,14 +30,14 @@ sub uppercase() { sub chrout(ubyte char) { %ir {{ - loadm.b r0,txt.chrout.char + loadm.b r65500,txt.chrout.char syscall 2 }} } sub print (str text) { %ir {{ - loadm.w r0,txt.print.text + loadm.w r65500,txt.print.text syscall 3 }} } @@ -114,7 +114,7 @@ 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 r0,txt.input_chars.buffer + loadm.w r65500,txt.input_chars.buffer syscall 6 return }} diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 4982d6873..d18bdc074 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,6 +3,9 @@ TODO For next release ^^^^^^^^^^^^^^^^ +- add a pget() to gfx2 to get the pixel color value +- ir: write addresses as hex into p8ir file + ... @@ -17,14 +20,13 @@ Future Things and Ideas ^^^^^^^^^^^^^^^^^^^^^^^ Compiler: -- ir/vm: SYSCALL opcode should take args in r65500, r65501 etc instead of r0, r1. Then also remove excess PUSH/POP of regs to save them. +- ir: register allocation per data type a specific allocation, so we are certain when a reg is used it's just for one specific datatype - create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code - ir: mechanism to determine for chunks which registers are getting input values from "outside" - ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk) - ir: peephole opt: renumber registers in chunks to start with 1 again every time (but keep entry values in mind!) - ir peephole opt: reuse registers in chunks (but keep result registers in mind that pass values out!) - ir: add more optimizations in IRPeepholeOptimizer -- ir: write addresses as hex into p8ir file - see if we can let for loops skip the loop if end { vm.reset() } Syscall.EXIT ->{ - vm.exit() + vm.exit(vm.registers.getUB(SyscallRegisterBase).toInt()) } Syscall.PRINT_C -> { - val char = vm.registers.getUB(0).toInt() + val char = vm.registers.getUB(SyscallRegisterBase).toInt() print(Char(char)) } Syscall.PRINT_S -> { - var addr = vm.registers.getUW(0).toInt() + var addr = vm.registers.getUW(SyscallRegisterBase).toInt() while(true) { val char = vm.memory.getUB(addr).toInt() if(char==0) @@ -107,21 +109,21 @@ object SysCalls { } } Syscall.PRINT_U8 -> { - print(vm.registers.getUB(0)) + print(vm.registers.getUB(SyscallRegisterBase)) } Syscall.PRINT_U16 -> { - print(vm.registers.getUW(0)) + print(vm.registers.getUW(SyscallRegisterBase)) } Syscall.INPUT -> { var input = readln() - val maxlen = vm.registers.getUB(1).toInt() + val maxlen = vm.registers.getUB(SyscallRegisterBase+1).toInt() if(maxlen>0) input = input.substring(0, min(input.length, maxlen)) - vm.memory.setString(vm.registers.getUW(0).toInt(), input, true) + vm.memory.setString(vm.registers.getUW(SyscallRegisterBase).toInt(), input, true) vm.registers.setUW(0, input.length.toUShort()) } Syscall.SLEEP -> { - val duration = vm.registers.getUW(0).toLong() + val duration = vm.registers.getUW(SyscallRegisterBase).toLong() Thread.sleep(duration) } Syscall.GFX_ENABLE -> vm.gfx_enable() @@ -129,13 +131,13 @@ object SysCalls { Syscall.GFX_PLOT -> vm.gfx_plot() Syscall.GFX_GETPIXEL ->vm.gfx_getpixel() Syscall.WAIT -> { - val millis = vm.registers.getUW(0).toLong() * 1000/60 + val millis = vm.registers.getUW(SyscallRegisterBase).toLong() * 1000/60 Thread.sleep(millis) } Syscall.WAITVSYNC -> vm.waitvsync() Syscall.SORT_UBYTE -> { - val address = vm.registers.getUW(0).toInt() - val length = vm.registers.getUB(1).toInt() + val address = vm.registers.getUW(SyscallRegisterBase).toInt() + val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() val array = IntProgression.fromClosedRange(address, address+length-1, 1).map { vm.memory.getUB(it) }.sorted() @@ -144,8 +146,8 @@ object SysCalls { } } Syscall.SORT_BYTE -> { - val address = vm.registers.getUW(0).toInt() - val length = vm.registers.getUB(1).toInt() + val address = vm.registers.getUW(SyscallRegisterBase).toInt() + val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() val array = IntProgression.fromClosedRange(address, address+length-1, 1).map { vm.memory.getSB(it) }.sorted() @@ -154,8 +156,8 @@ object SysCalls { } } Syscall.SORT_UWORD -> { - val address = vm.registers.getUW(0).toInt() - val length = vm.registers.getUB(1).toInt() + val address = vm.registers.getUW(SyscallRegisterBase).toInt() + val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() val array = IntProgression.fromClosedRange(address, address+length*2-2, 2).map { vm.memory.getUW(it) }.sorted() @@ -164,8 +166,8 @@ object SysCalls { } } Syscall.SORT_WORD -> { - val address = vm.registers.getUW(0).toInt() - val length = vm.registers.getUB(1).toInt() + val address = vm.registers.getUW(SyscallRegisterBase).toInt() + val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() val array = IntProgression.fromClosedRange(address, address+length*2-2, 2).map { vm.memory.getSW(it) }.sorted() @@ -174,8 +176,8 @@ object SysCalls { } } Syscall.REVERSE_BYTES -> { - val address = vm.registers.getUW(0).toInt() - val length = vm.registers.getUB(1).toInt() + val address = vm.registers.getUW(SyscallRegisterBase).toInt() + val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() val array = IntProgression.fromClosedRange(address, address+length-1, 1).map { vm.memory.getUB(it) }.reversed() @@ -184,8 +186,8 @@ object SysCalls { } } Syscall.REVERSE_WORDS -> { - val address = vm.registers.getUW(0).toInt() - val length = vm.registers.getUB(1).toInt() + val address = vm.registers.getUW(SyscallRegisterBase).toInt() + val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() val array = IntProgression.fromClosedRange(address, address+length*2-2, 2).map { vm.memory.getUW(it) }.reversed() @@ -194,8 +196,8 @@ object SysCalls { } } Syscall.REVERSE_FLOATS -> { - val address = vm.registers.getUW(0).toInt() - val length = vm.registers.getUB(1).toInt() + val address = vm.registers.getUW(SyscallRegisterBase).toInt() + val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() val array = IntProgression.fromClosedRange(address, address+length*4-2, 4).map { vm.memory.getFloat(it) }.reversed() @@ -204,8 +206,8 @@ object SysCalls { } } Syscall.ANY_BYTE -> { - val address = vm.registers.getUW(0).toInt() - val length = vm.registers.getUB(1).toInt() + val address = vm.registers.getUW(SyscallRegisterBase).toInt() + val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2) if(addresses.any { vm.memory.getUB(it).toInt()!=0 }) vm.registers.setUB(0, 1u) @@ -213,8 +215,8 @@ object SysCalls { vm.registers.setUB(0, 0u) } Syscall.ANY_WORD -> { - val address = vm.registers.getUW(0).toInt() - val length = vm.registers.getUB(1).toInt() + val address = vm.registers.getUW(SyscallRegisterBase).toInt() + val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2) if(addresses.any { vm.memory.getUW(it).toInt()!=0 }) vm.registers.setUB(0, 1u) @@ -222,8 +224,8 @@ object SysCalls { vm.registers.setUB(0, 0u) } Syscall.ANY_FLOAT -> { - val address = vm.registers.getUW(0).toInt() - val length = vm.registers.getUB(1).toInt() + val address = vm.registers.getUW(SyscallRegisterBase).toInt() + val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() val addresses = IntProgression.fromClosedRange(address, address+length*4-2, 4) if(addresses.any { vm.memory.getFloat(it).toInt()!=0 }) vm.registers.setUB(0, 1u) @@ -231,8 +233,8 @@ object SysCalls { vm.registers.setUB(0, 0u) } Syscall.ALL_BYTE -> { - val address = vm.registers.getUW(0).toInt() - val length = vm.registers.getUB(1).toInt() + val address = vm.registers.getUW(SyscallRegisterBase).toInt() + val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2) if(addresses.all { vm.memory.getUB(it).toInt()!=0 }) vm.registers.setUB(0, 1u) @@ -240,8 +242,8 @@ object SysCalls { vm.registers.setUB(0, 0u) } Syscall.ALL_WORD -> { - val address = vm.registers.getUW(0).toInt() - val length = vm.registers.getUB(1).toInt() + val address = vm.registers.getUW(SyscallRegisterBase).toInt() + val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2) if(addresses.all { vm.memory.getUW(it).toInt()!=0 }) vm.registers.setUB(0, 1u) @@ -249,8 +251,8 @@ object SysCalls { vm.registers.setUB(0, 0u) } Syscall.ALL_FLOAT -> { - val address = vm.registers.getUW(0).toInt() - val length = vm.registers.getUB(1).toInt() + val address = vm.registers.getUW(SyscallRegisterBase).toInt() + val length = vm.registers.getUB(SyscallRegisterBase+1).toInt() val addresses = IntProgression.fromClosedRange(address, address+length*4-2, 4) if(addresses.all { vm.memory.getFloat(it).toInt()!=0 }) vm.registers.setUB(0, 1u) @@ -258,11 +260,11 @@ object SysCalls { vm.registers.setUB(0, 0u) } Syscall.PRINT_F -> { - val value = vm.registers.getFloat(0) + val value = vm.registers.getFloat(SyscallRegisterBase) print(value) } Syscall.STR_TO_UWORD -> { - val stringAddr = vm.registers.getUW(0) + val stringAddr = vm.registers.getUW(SyscallRegisterBase) val string = vm.memory.getString(stringAddr.toInt()).takeWhile { it.isDigit() } val value = try { string.toUShort() @@ -272,7 +274,7 @@ object SysCalls { vm.registers.setUW(0, value) } Syscall.STR_TO_WORD -> { - val stringAddr = vm.registers.getUW(0) + val stringAddr = vm.registers.getUW(SyscallRegisterBase) val string = vm.memory.getString(stringAddr.toInt()).takeWhile { it.isDigit() } val value = try { string.toShort() @@ -282,8 +284,8 @@ object SysCalls { vm.registers.setSW(0, value) } Syscall.COMPARE_STRINGS -> { - val firstAddr = vm.registers.getUW(0) - val secondAddr = vm.registers.getUW(1) + val firstAddr = vm.registers.getUW(SyscallRegisterBase) + val secondAddr = vm.registers.getUW(SyscallRegisterBase+1) val first = vm.memory.getString(firstAddr.toInt()) val second = vm.memory.getString(secondAddr.toInt()) val comparison = first.compareTo(second) @@ -295,14 +297,14 @@ object SysCalls { vm.registers.setSB(0, 1) } Syscall.RNDFSEED -> { - val seed1 = vm.registers.getUB(0) - val seed2 = vm.registers.getUB(1) - val seed3 = vm.registers.getUB(2) + val seed1 = vm.registers.getUB(SyscallRegisterBase) + val seed2 = vm.registers.getUB(SyscallRegisterBase+1) + val seed3 = vm.registers.getUB(SyscallRegisterBase+2) vm.randomSeedFloat(seed1, seed2, seed3) } Syscall.RNDSEED -> { - val seed1 = vm.registers.getUW(0) - val seed2 = vm.registers.getUW(1) + val seed1 = vm.registers.getUW(SyscallRegisterBase) + val seed2 = vm.registers.getUW(SyscallRegisterBase+1) vm.randomSeed(seed1, seed2) } Syscall.RND -> { @@ -315,15 +317,15 @@ object SysCalls { vm.registers.setFloat(0, vm.randomGeneratorFloats.nextFloat()) } Syscall.STRING_CONTAINS -> { - val char = vm.registers.getUB(0).toInt().toChar() - val stringAddr = vm.registers.getUW(1) + val char = vm.registers.getUB(SyscallRegisterBase).toInt().toChar() + val stringAddr = vm.registers.getUW(SyscallRegisterBase+1) val string = vm.memory.getString(stringAddr.toInt()) vm.registers.setUB(0, if(char in string) 1u else 0u) } Syscall.BYTEARRAY_CONTAINS -> { - val value = vm.registers.getUB(0) - var array = vm.registers.getUW(1).toInt() - var length = vm.registers.getUB(2) + val value = vm.registers.getUB(SyscallRegisterBase) + var array = vm.registers.getUW(SyscallRegisterBase+1).toInt() + var length = vm.registers.getUB(SyscallRegisterBase+2) while(length>0u) { if(vm.memory.getUB(array)==value) { vm.registers.setUB(0, 1u) @@ -336,9 +338,9 @@ object SysCalls { } Syscall.WORDARRAY_CONTAINS -> { // r0.w = value, r1.w = array, r2.b = array length - val value = vm.registers.getUW(0) - var array = vm.registers.getUW(1).toInt() - var length = vm.registers.getUB(2) + val value = vm.registers.getUW(SyscallRegisterBase) + var array = vm.registers.getUW(SyscallRegisterBase+1).toInt() + var length = vm.registers.getUB(SyscallRegisterBase+2) while(length>0u) { if(vm.memory.getUW(array)==value) { vm.registers.setUB(0, 1u) diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 31c93b265..0d0a7765d 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -92,8 +92,8 @@ class VirtualMachine(irProgram: IRProgram) { statusZero = false } - fun exit() { - throw ProgramExitException(registers.getUW(0).toInt()) + fun exit(statuscode: Int) { + throw ProgramExitException(statuscode) } fun step(count: Int=1) { @@ -118,7 +118,7 @@ class VirtualMachine(irProgram: IRProgram) { } null -> { - exit() // end of program reached + exit(0) // end of program reached } else -> { @@ -574,7 +574,7 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsRETURN() { if(callStack.isEmpty()) - exit() + exit(0) else { val (chunk, idx) = callStack.pop() pcChunk = chunk @@ -2108,7 +2108,7 @@ class VirtualMachine(irProgram: IRProgram) { private var window: GraphicsWindow? = null fun gfx_enable() { - window = when(registers.getUB(0).toInt()) { + window = when(registers.getUB(SyscallRegisterBase).toInt()) { 0 -> GraphicsWindow(320, 240, 3) 1 -> GraphicsWindow(640, 480, 2) else -> throw IllegalArgumentException("invalid screen mode") @@ -2117,18 +2117,21 @@ class VirtualMachine(irProgram: IRProgram) { } fun gfx_clear() { - window?.clear(registers.getUB(0).toInt()) + window?.clear(registers.getUB(SyscallRegisterBase).toInt()) } fun gfx_plot() { - window?.plot(registers.getUW(0).toInt(), registers.getUW(1).toInt(), registers.getUB(2).toInt()) + window?.plot(registers.getUW(SyscallRegisterBase).toInt(), + registers.getUW(SyscallRegisterBase+1).toInt(), + registers.getUB(SyscallRegisterBase+2).toInt()) } fun gfx_getpixel() { if(window==null) registers.setUB(0, 0u) else { - val color = Color(window!!.getpixel(registers.getUW(0).toInt(), registers.getUW(1).toInt())) + val color = Color(window!!.getpixel(registers.getUW(SyscallRegisterBase).toInt(), + registers.getUW(SyscallRegisterBase+1).toInt())) registers.setUB(0, color.green.toUByte()) } }