mirror of
https://github.com/irmen/prog8.git
synced 2024-06-25 15:29:45 +00:00
vm syscall instruction no longer fixed to r0
This commit is contained in:
parent
5196443b26
commit
ac21e1be5c
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}}
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ sub ceil(float value) -> float {
|
|||
|
||||
sub rndf() -> float {
|
||||
%ir {{
|
||||
syscall 35
|
||||
syscallr.f fr0,35
|
||||
returnreg.f fr0
|
||||
}}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}}
|
||||
}
|
||||
|
|
|
@ -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,<a"),
|
||||
Opcode.CALLRVAL to InstructionFormat.from("BW,>r1,<a | F,>fr1,<a"),
|
||||
Opcode.SYSCALL to InstructionFormat.from("N,<i"),
|
||||
Opcode.SYSCALLR to InstructionFormat.from("BW,>r1,<i | F,>fr1,<i"),
|
||||
Opcode.RETURN to InstructionFormat.from("N"),
|
||||
Opcode.RETURNREG to InstructionFormat.from("BW,>r1 | F,>fr1"),
|
||||
Opcode.BSTCC to InstructionFormat.from("N,<a"),
|
||||
|
@ -695,7 +699,7 @@ data class IRInstruction(
|
|||
if(format.fpReg1==OperandDirection.UNUSED) require(fpReg1==null) { "invalid fpReg1" }
|
||||
if(format.fpReg2==OperandDirection.UNUSED) require(fpReg2==null) { "invalid fpReg2" }
|
||||
if(format.immediate) {
|
||||
if(type==IRDataType.FLOAT) require(immediateFp !=null) {"missing immediate fp value"}
|
||||
if(type==IRDataType.FLOAT && opcode!=Opcode.SYSCALLR) require(immediateFp !=null) {"missing immediate fp value"}
|
||||
else require(immediate!=null || labelSymbol!=null) {"missing immediate value or labelsymbol"}
|
||||
}
|
||||
if(type!=IRDataType.FLOAT)
|
||||
|
@ -703,10 +707,12 @@ data class IRInstruction(
|
|||
if(format.address!=OperandDirection.UNUSED)
|
||||
require(address!=null || labelSymbol!=null) {"missing an address or labelsymbol"}
|
||||
if(format.immediate && (immediate!=null || immediateFp!=null)) {
|
||||
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 -> {}
|
||||
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(
|
||||
|
|
|
@ -182,7 +182,7 @@ fun parseIRCodeLine(line: String, location: Pair<IRCodeChunk, Int>?, 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<IRCodeChunk, Int>?, 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))
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -100,7 +100,7 @@ class VmProgramLoader {
|
|||
private fun pass2translateSyscalls(chunks: MutableList<IRCodeChunk>) {
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue
Block a user