diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt index f083d2850..e7da4225f 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt @@ -74,10 +74,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe val left = exprGen.translateExpression(call.args[0]) val right = exprGen.translateExpression(call.args[1]) val targetReg = codeGen.registers.nextFree() - addToResult(result, left, 65500, -1) - addToResult(result, right, 65501, -1) - addInstr(result, IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.COMPARE_STRINGS.number), null) - addInstr(result, IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=targetReg, reg2=0), null) + addToResult(result, left, SyscallRegisterBase, -1) + addToResult(result, right, SyscallRegisterBase+1, -1) + addInstr(result, IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=targetReg, immediate = IMSyscall.COMPARE_STRINGS.number), null) return ExpressionCodeResult(result, IRDataType.BYTE, targetReg, -1) } @@ -111,10 +110,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe addToResult(result, tr, SyscallRegisterBase, -1) result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, immediate = array.length) - it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number) - // SysCall call convention: return value in register r0 - if(tr.resultReg!=0) - it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = tr.resultReg, reg2 = 0) + it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=tr.resultReg, immediate = syscall.number) } return ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1) } @@ -136,10 +132,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe addToResult(result, tr, SyscallRegisterBase, -1) result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, immediate = array.length) - it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number) - // SysCall call convention: return value in register r0 - if(tr.resultReg!=0) - it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = tr.resultReg, reg2 = 0) + it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=tr.resultReg, immediate = syscall.number) } return ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1) } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index c77fb0e4d..d8f9d21ed 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -116,8 +116,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { addToResult(result, tr, SyscallRegisterBase+1, -1) val resultReg = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.STRING_CONTAINS.number) - it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultReg, reg2=0) + it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=resultReg, immediate = IMSyscall.STRING_CONTAINS.number) } return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) } @@ -129,8 +128,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val resultReg = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=SyscallRegisterBase+2, immediate = iterable.length!!) - it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.BYTEARRAY_CONTAINS.number) - it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultReg, reg2=0) + it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=resultReg, immediate = IMSyscall.BYTEARRAY_CONTAINS.number) } // SysCall call convention: return value in register r0 return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) @@ -143,8 +141,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val resultReg = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=SyscallRegisterBase+2, immediate = iterable.length!!) - it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.WORDARRAY_CONTAINS.number) - it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultReg, reg2=0) + it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=resultReg, immediate = IMSyscall.WORDARRAY_CONTAINS.number) } return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) } @@ -469,8 +466,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val rightTr = translateExpression(binExpr.right) addToResult(result, rightTr, SyscallRegisterBase+1, -1) result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.COMPARE_STRINGS.number) - // SysCall call convention: return value in register r0 + it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1 = leftTr.resultReg, immediate = IMSyscall.COMPARE_STRINGS.number) val zeroReg = codeGen.registers.nextFree() it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = zeroReg, immediate = 0) it += if (greaterEquals) @@ -524,17 +520,15 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { addToResult(result, leftTr, SyscallRegisterBase, -1) val rightTr = translateExpression(binExpr.right) addToResult(result, rightTr, SyscallRegisterBase+1, -1) - val resultReg = codeGen.registers.nextFree() + val resultReg = codeGen.registers.nextFree() // TODO reuse leftTr resultreg? result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.COMPARE_STRINGS.number) - // SysCall call convention: return value in register r0 + it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=resultReg, immediate = IMSyscall.COMPARE_STRINGS.number) val zeroReg = codeGen.registers.nextFree() it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = zeroReg, immediate = 0) it += if (lessEquals) - IRInstruction(Opcode.SLES, IRDataType.BYTE, reg1 = 0, reg2 = zeroReg) + IRInstruction(Opcode.SLES, IRDataType.BYTE, reg1 = resultReg, reg2 = zeroReg) else - IRInstruction(Opcode.SLTS, IRDataType.BYTE, reg1 = 0, reg2 = zeroReg) - it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultReg, reg2=0) + IRInstruction(Opcode.SLTS, IRDataType.BYTE, reg1 = resultReg, reg2 = zeroReg) } return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) } else { @@ -581,11 +575,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { addToResult(result, rightTr, SyscallRegisterBase+1, -1) val resultRegister = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.COMPARE_STRINGS.number) - // SysCall call convention: return value in register r0 + it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=resultRegister, immediate = IMSyscall.COMPARE_STRINGS.number) if (!notEquals) - it += IRInstruction(Opcode.INV, vmDt, reg1 = 0) - it += IRInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=0) + it += IRInstruction(Opcode.INV, vmDt, reg1 = resultRegister) it += IRInstruction(Opcode.AND, vmDt, reg1 = resultRegister, immediate = 1) } return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt index 555d961e7..915805a83 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt @@ -5,7 +5,7 @@ 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 SYSCALL/DIVMOD fixed? + // TODO set this back to 0 once 'resultRegister' has been removed everywhere and DIVMOD fixed to not use r0? private var firstFree: Int=3 private var firstFreeFloat: Int=3 diff --git a/compiler/res/prog8lib/virtual/conv.p8 b/compiler/res/prog8lib/virtual/conv.p8 index 696c0fc44..1b914e6ab 100644 --- a/compiler/res/prog8lib/virtual/conv.p8 +++ b/compiler/res/prog8lib/virtual/conv.p8 @@ -197,7 +197,7 @@ sub str2uword(str string) -> uword { ; (any non-digit character will terminate the number string that is parsed) %ir {{ loadm.w r65500,conv.str2uword.string - syscall 11 + syscallr.w r0,11 returnreg.w r0 }} } @@ -208,7 +208,7 @@ sub str2word(str string) -> word { ; (any non-digit character will terminate the number string that is parsed) %ir {{ loadm.w r65500,conv.str2word.string - syscall 12 + syscallr.w r0,12 returnreg.w r0 }} } diff --git a/compiler/res/prog8lib/virtual/floats.p8 b/compiler/res/prog8lib/virtual/floats.p8 index 473bf89db..46103a4b5 100644 --- a/compiler/res/prog8lib/virtual/floats.p8 +++ b/compiler/res/prog8lib/virtual/floats.p8 @@ -126,7 +126,7 @@ sub ceil(float value) -> float { sub rndf() -> float { %ir {{ - syscall 35 + syscallr.f fr0,35 returnreg.f fr0 }} } diff --git a/compiler/res/prog8lib/virtual/math.p8 b/compiler/res/prog8lib/virtual/math.p8 index ecc65f00f..a2864721c 100644 --- a/compiler/res/prog8lib/virtual/math.p8 +++ b/compiler/res/prog8lib/virtual/math.p8 @@ -161,14 +161,14 @@ math { sub rnd() -> ubyte { %ir {{ - syscall 33 + syscallr.b r0,33 returnreg.b r0 }} } sub rndw() -> uword { %ir {{ - syscall 34 + syscallr.w r0,34 returnreg.w r0 }} } diff --git a/compiler/res/prog8lib/virtual/string.p8 b/compiler/res/prog8lib/virtual/string.p8 index ea795eada..b896d966b 100644 --- a/compiler/res/prog8lib/virtual/string.p8 +++ b/compiler/res/prog8lib/virtual/string.p8 @@ -86,7 +86,7 @@ string { %ir {{ loadm.w r65500,string.compare.st1 loadm.w r65501,string.compare.st2 - syscall 29 + syscallr.b r0,29 returnreg.b r0 }} } diff --git a/compiler/res/prog8lib/virtual/syslib.p8 b/compiler/res/prog8lib/virtual/syslib.p8 index 259b007b4..deff5d683 100644 --- a/compiler/res/prog8lib/virtual/syslib.p8 +++ b/compiler/res/prog8lib/virtual/syslib.p8 @@ -107,7 +107,7 @@ sys { %ir {{ loadm.w r65500,sys.gfx_getpixel.xx loadm.w r65501,sys.gfx_getpixel.yy - syscall 30 + syscallr.b r0,30 returnreg.b r0 }} } diff --git a/compiler/res/prog8lib/virtual/textio.p8 b/compiler/res/prog8lib/virtual/textio.p8 index 15017af03..fc3ad881a 100644 --- a/compiler/res/prog8lib/virtual/textio.p8 +++ b/compiler/res/prog8lib/virtual/textio.p8 @@ -123,7 +123,7 @@ sub input_chars (uword buffer) -> ubyte { ; It assumes the keyboard is selected as I/O channel! %ir {{ loadm.w r65500,txt.input_chars.buffer - syscall 6 + syscallr.b r0,6 returnreg.b r0 }} } diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index b92dfb2cf..af54538bf 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -52,7 +52,8 @@ jump location - continue running at instruction number g jumpa address - continue running at memory address (note: only used to encode a physical cpu jump to fixed address instruction) call location - save current instruction location+1, continue execution at instruction nr given by location. Expect no return value. callrval reg1, location - like call but expects a return value from a returnreg instruction, and puts that in reg1 -syscall value - do a systemcall identified by call number +syscall value - do a systemcall identified by call number, no result value +syscallr reg1, value - do a systemcall identified by call number, result value is set into reg1 return - restore last saved instruction location and continue at that instruction. No return value. returnreg reg1 - like return, but also returns a value to the caller via reg1 @@ -237,6 +238,7 @@ enum class Opcode { CALL, CALLRVAL, SYSCALL, + SYSCALLR, RETURN, RETURNREG, @@ -386,6 +388,7 @@ val OpcodesThatBranch = setOf( Opcode.CALL, Opcode.CALLRVAL, Opcode.SYSCALL, + Opcode.SYSCALLR, Opcode.BSTCC, Opcode.BSTCS, Opcode.BSTEQ, @@ -517,6 +520,7 @@ val instructionFormats = mutableMapOf( Opcode.CALL to InstructionFormat.from("N,r1,fr1,r1,fr1,r1 | F,>fr1"), Opcode.BSTCC to InstructionFormat.from("N, require(immediate in -128..255) {"immediate value out of range for byte: $immediate"} - IRDataType.WORD -> require(immediate in -32768..65535) {"immediate value out of range for word: $immediate"} - IRDataType.FLOAT, null -> {} + if(opcode!=Opcode.SYSCALL && opcode!=Opcode.SYSCALLR) { + when (type) { + IRDataType.BYTE -> require(immediate in -128..255) { "immediate value out of range for byte: $immediate" } + IRDataType.WORD -> require(immediate in -32768..65535) { "immediate value out of range for word: $immediate" } + IRDataType.FLOAT, null -> {} + } } } reg1direction = format.reg1 @@ -725,6 +731,12 @@ data class IRInstruction( else require(reg1!=reg2) {"$opcode: reg1 and reg2 should be different"} } + + if(opcode==Opcode.SYSCALL || opcode==Opcode.SYSCALLR) { + require(immediate!=null) { + "syscall needs immediate integer for the syscall number" + } + } } fun addUsedRegistersCounts( diff --git a/intermediate/src/prog8/intermediate/Utils.kt b/intermediate/src/prog8/intermediate/Utils.kt index 7d26609a3..041d8b6c6 100644 --- a/intermediate/src/prog8/intermediate/Utils.kt +++ b/intermediate/src/prog8/intermediate/Utils.kt @@ -182,7 +182,7 @@ fun parseIRCodeLine(line: String, location: Pair?, placeholder throw IRParseException("invalid fpReg1 for $line") if(format.fpReg2==OperandDirection.UNUSED && fpReg2!=null) throw IRParseException("invalid fpReg2 for $line") - if(format.immediate) { + if(format.immediate && opcode!=Opcode.SYSCALL && opcode!=Opcode.SYSCALLR) { if(immediateInt==null && immediateFp==null && labelSymbol==null) throw IRParseException("needs value or symbol for $line") when (type) { @@ -222,5 +222,10 @@ fun parseIRCodeLine(line: String, location: Pair?, placeholder return left(IRInstruction(opcode, type, reg1, labelSymbol = reg)) } + if(opcode==Opcode.SYSCALLR && type==IRDataType.FLOAT) { + immediateInt = immediateFp!!.toInt() + immediateFp = null + } + return left(IRInstruction(opcode, type, reg1, reg2, fpReg1, fpReg2, immediateInt, immediateFp, address, labelSymbol = labelSymbol)) } diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 08d99d35a..534b81bf5 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -178,7 +178,8 @@ class VirtualMachine(irProgram: IRProgram) { Opcode.JUMPA -> throw IllegalArgumentException("vm program can't jump to system memory address (JUMPA)") Opcode.CALL -> InsCALL(ins) Opcode.CALLRVAL -> InsCALLRVAL(ins) - Opcode.SYSCALL -> InsSYSCALL(ins) + Opcode.SYSCALL -> InsSYSCALL(ins, false) + Opcode.SYSCALLR -> InsSYSCALL(ins, true) Opcode.RETURN -> InsRETURN() Opcode.RETURNREG -> InsRETURNREG(ins) Opcode.BSTCC -> InsBSTCC(ins) @@ -360,7 +361,7 @@ class VirtualMachine(irProgram: IRProgram) { nextPc() } - private fun InsSYSCALL(i: IRInstruction) { + private fun InsSYSCALL(i: IRInstruction, hasReturnReg: Boolean) { val call = Syscall.values()[i.immediate!!] SysCalls.call(call, this) nextPc() diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index ff8dbce1f..b3d23c110 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -100,7 +100,7 @@ class VmProgramLoader { private fun pass2translateSyscalls(chunks: MutableList) { chunks.forEach { chunk -> chunk.instructions.withIndex().forEach { (index, ins) -> - if(ins.opcode == Opcode.SYSCALL) { + if(ins.opcode == Opcode.SYSCALL || ins.opcode==Opcode.SYSCALLR) { // convert IR Syscall to VM Syscall val vmSyscall = when(ins.immediate!!) { IMSyscall.SORT_UBYTE.number -> Syscall.SORT_UBYTE