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