mirror of
https://github.com/irmen/prog8.git
synced 2024-12-23 09:32:43 +00:00
tweak IR call args setting now via special SETPARAM instruction
This commit is contained in:
parent
b55be093be
commit
efd7d6f0c0
@ -82,9 +82,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])
|
||||
addToResult(result, left, left.resultReg, -1)
|
||||
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=left.resultReg), null)
|
||||
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1=left.resultReg, immediate = 0), null)
|
||||
addToResult(result, right, right.resultReg, -1)
|
||||
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=right.resultReg), null)
|
||||
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1=right.resultReg, immediate = 1), null)
|
||||
addInstr(result, IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.COMPARE_STRINGS.number), null)
|
||||
addInstr(result, IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=left.resultReg), null)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, left.resultReg, -1)
|
||||
@ -119,9 +119,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
val tr = exprGen.translateExpression(call.args[0])
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
|
||||
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1 = tr.resultReg, immediate = 0)
|
||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length)
|
||||
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
|
||||
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, reg1 = tr.resultReg, immediate = 1)
|
||||
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
|
||||
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
|
||||
}
|
||||
@ -144,9 +144,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
val tr = exprGen.translateExpression(call.args[0])
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
|
||||
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1 = tr.resultReg, immediate = 0)
|
||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length)
|
||||
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
|
||||
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, reg1 = tr.resultReg, immediate = 1)
|
||||
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
|
||||
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
|
||||
}
|
||||
@ -272,9 +272,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
val tr = exprGen.translateExpression(call.args[0])
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
|
||||
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1 = tr.resultReg, immediate = 0)
|
||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = if(array.dt==DataType.STR) array.length!!-1 else array.length)
|
||||
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
|
||||
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, reg1 = tr.resultReg, immediate = 1)
|
||||
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
|
||||
}
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
||||
@ -297,9 +297,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
val tr = exprGen.translateExpression(call.args[0])
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
|
||||
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1 = tr.resultReg, immediate = 0)
|
||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = if(array.dt==DataType.STR) array.length!!-1 else array.length)
|
||||
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
|
||||
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, reg1 = tr.resultReg, immediate = 1)
|
||||
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
|
||||
}
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
||||
|
@ -112,10 +112,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
DataType.STR -> {
|
||||
tr = translateExpression(check.element)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg), null)
|
||||
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, tr.resultReg, immediate = 0), null)
|
||||
tr = translateExpression(check.iterable)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg), null)
|
||||
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.WORD, tr.resultReg, immediate = 1), null)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.STRING_CONTAINS.number)
|
||||
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
|
||||
@ -125,13 +125,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
||||
tr = translateExpression(check.element)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg), null)
|
||||
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, tr.resultReg, immediate = 0), null)
|
||||
tr = translateExpression(check.iterable)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg)
|
||||
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, tr.resultReg, immediate = 1)
|
||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=tr.resultReg, immediate = iterable.length!!)
|
||||
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg)
|
||||
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, tr.resultReg, immediate = 2)
|
||||
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.BYTEARRAY_CONTAINS.number)
|
||||
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
|
||||
}
|
||||
@ -141,13 +141,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
||||
tr = translateExpression(check.element)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg), null)
|
||||
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.WORD, tr.resultReg, immediate = 0), null)
|
||||
tr = translateExpression(check.iterable)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg)
|
||||
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, tr.resultReg, immediate = 1)
|
||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=tr.resultReg, immediate = iterable.length!!)
|
||||
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg)
|
||||
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, tr.resultReg, immediate = 2)
|
||||
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.WORDARRAY_CONTAINS.number)
|
||||
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
|
||||
}
|
||||
@ -358,23 +358,33 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
when (val callTarget = codeGen.symbolTable.flat.getValue(fcall.name)) {
|
||||
is StSub -> {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
|
||||
val paramDt = codeGen.irType(parameter.type)
|
||||
val symbol = "${fcall.name}.${parameter.name}"
|
||||
if(codeGen.isZero(arg)) {
|
||||
addInstr(result, IRInstruction(Opcode.STOREZM, paramDt, labelSymbol = symbol), null)
|
||||
} else {
|
||||
if (paramDt == IRDataType.FLOAT) {
|
||||
val tr = translateExpression(arg)
|
||||
addToResult(result, tr, -1, tr.resultFpReg)
|
||||
addInstr(result, IRInstruction(Opcode.STOREM, paramDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol), null)
|
||||
} else {
|
||||
val tr = translateExpression(arg)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, IRInstruction(Opcode.STOREM, paramDt, reg1 = tr.resultReg, labelSymbol = symbol), null)
|
||||
}
|
||||
}
|
||||
for ((index, argspec) in fcall.args.zip(callTarget.parameters).withIndex()) {
|
||||
val (arg, param) = argspec
|
||||
val paramDt = codeGen.irType(param.type)
|
||||
val tr = translateExpression(arg)
|
||||
result += tr.chunks
|
||||
if(paramDt==IRDataType.FLOAT)
|
||||
addInstr(result, IRInstruction(Opcode.SETPARAM, paramDt, fpReg1 = tr.resultFpReg, immediate = index), null)
|
||||
else
|
||||
addInstr(result, IRInstruction(Opcode.SETPARAM, paramDt, reg1 = tr.resultReg, immediate = index), null)
|
||||
}
|
||||
// for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
|
||||
// val paramDt = codeGen.irType(parameter.type)
|
||||
// val symbol = "${fcall.name}.${parameter.name}"
|
||||
// if(codeGen.isZero(arg)) {
|
||||
// addInstr(result, IRInstruction(Opcode.STOREZM, paramDt, labelSymbol = symbol), null)
|
||||
// } else {
|
||||
// if (paramDt == IRDataType.FLOAT) {
|
||||
// val tr = translateExpression(arg)
|
||||
// addToResult(result, tr, -1, tr.resultFpReg)
|
||||
// addInstr(result, IRInstruction(Opcode.STOREM, paramDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol), null)
|
||||
// } else {
|
||||
// val tr = translateExpression(arg)
|
||||
// addToResult(result, tr, tr.resultReg, -1)
|
||||
// addInstr(result, IRInstruction(Opcode.STOREM, paramDt, reg1 = tr.resultReg, labelSymbol = symbol), null)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
return if(fcall.void) {
|
||||
addInstr(result, IRInstruction(Opcode.CALL, labelSymbol = fcall.name), null)
|
||||
ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
||||
|
@ -197,7 +197,7 @@ sub str2uword(str string) -> uword {
|
||||
; (any non-digit character will terminate the number string that is parsed)
|
||||
%ir {{
|
||||
loadm.w r65535,conv.str2uword.string
|
||||
push.w r65535
|
||||
setparam.w r65535,0
|
||||
syscall 11
|
||||
pop.w r0
|
||||
returnr.w r0
|
||||
@ -210,7 +210,7 @@ sub str2word(str string) -> word {
|
||||
; (any non-digit character will terminate the number string that is parsed)
|
||||
%ir {{
|
||||
loadm.w r65535,conv.str2word.string
|
||||
push.w r65535
|
||||
setparam.w r65535,0
|
||||
syscall 12
|
||||
pop.w r0
|
||||
returnr.w r0
|
||||
|
@ -11,7 +11,7 @@ sub print_f(float value) {
|
||||
; ---- prints the floating point value (without a newline).
|
||||
%ir {{
|
||||
loadm.f fr65535,floats.print_f.value
|
||||
push.f fr65535
|
||||
setparam.f fr65535,0
|
||||
syscall 25
|
||||
return
|
||||
}}
|
||||
@ -136,7 +136,7 @@ sub rndf() -> float {
|
||||
sub rndseedf(float seed) {
|
||||
%ir {{
|
||||
loadm.f fr65535,floats.rndseedf.seed
|
||||
push.f fr65535
|
||||
setparam.f fr65535,0
|
||||
syscall 32
|
||||
}}
|
||||
}
|
||||
|
@ -179,9 +179,9 @@ math {
|
||||
; -- reset the pseudo RNG's seed values. Defaults are: $a55a, $7653.
|
||||
%ir {{
|
||||
loadm.w r65535,math.rndseed.seed1
|
||||
push.w r65535
|
||||
setparam.w r65535,0
|
||||
loadm.w r65535,math.rndseed.seed2
|
||||
push.w r65535
|
||||
setparam.w r65535,1
|
||||
syscall 31
|
||||
return
|
||||
}}
|
||||
|
@ -85,9 +85,9 @@ string {
|
||||
; comparison operators ==, < etcetera (it will use strcmp for you under water automatically).
|
||||
%ir {{
|
||||
loadm.w r65535,string.compare.st1
|
||||
push.w r65535
|
||||
setparam.w r65535,0
|
||||
loadm.w r65535,string.compare.st2
|
||||
push.w r65535
|
||||
setparam.w r65535,1
|
||||
syscall 29
|
||||
pop.b r0
|
||||
returnr.b r0
|
||||
|
@ -16,7 +16,7 @@ sys {
|
||||
; --- wait approximately the given number of jiffies (1/60th seconds)
|
||||
%ir {{
|
||||
loadm.w r65535,sys.wait.jiffies
|
||||
push.w r65535
|
||||
setparam.w r65535,0
|
||||
syscall 13
|
||||
}}
|
||||
}
|
||||
@ -64,7 +64,7 @@ sys {
|
||||
; -- immediately exit the program with a return code in the A register
|
||||
%ir {{
|
||||
loadm.b r65535,sys.exit.returnvalue
|
||||
push.b r65535
|
||||
setparam.b r65535,0
|
||||
syscall 1
|
||||
}}
|
||||
}
|
||||
@ -85,7 +85,7 @@ sys {
|
||||
sub gfx_enable(ubyte mode) {
|
||||
%ir {{
|
||||
loadm.b r65535,sys.gfx_enable.mode
|
||||
push.b r65535
|
||||
setparam.b r65535,0
|
||||
syscall 8
|
||||
}}
|
||||
}
|
||||
@ -93,7 +93,7 @@ sys {
|
||||
sub gfx_clear(ubyte color) {
|
||||
%ir {{
|
||||
loadm.b r65535,sys.gfx_clear.color
|
||||
push.b r65535
|
||||
setparam.b r65535,0
|
||||
syscall 9
|
||||
}}
|
||||
}
|
||||
@ -101,11 +101,11 @@ sys {
|
||||
sub gfx_plot(uword xx, uword yy, ubyte color) {
|
||||
%ir {{
|
||||
loadm.w r65535,sys.gfx_plot.xx
|
||||
push.w r65535
|
||||
setparam.w r65535,0
|
||||
loadm.w r65535,sys.gfx_plot.yy
|
||||
push.w r65535
|
||||
setparam.w r65535,1
|
||||
loadm.b r65535,sys.gfx_plot.color
|
||||
push.b r65535
|
||||
setparam.b r65535,2
|
||||
syscall 10
|
||||
}}
|
||||
}
|
||||
@ -113,9 +113,9 @@ sys {
|
||||
sub gfx_getpixel(uword xx, uword yy) -> ubyte {
|
||||
%ir {{
|
||||
loadm.w r65535,sys.gfx_getpixel.xx
|
||||
push.w r65535
|
||||
setparam.w r65535,0
|
||||
loadm.w r65535,sys.gfx_getpixel.yy
|
||||
push.w r65535
|
||||
setparam.w r65535,1
|
||||
syscall 30
|
||||
pop.b r0
|
||||
returnr.b r0
|
||||
|
@ -16,7 +16,7 @@ sub clear_screen() {
|
||||
str @shared sequence = "\x1b[2J\x1B[H"
|
||||
%ir {{
|
||||
load.w r65535,txt.clear_screen.sequence
|
||||
push.w r65535
|
||||
setparam.w r65535,0
|
||||
syscall 3
|
||||
}}
|
||||
}
|
||||
@ -40,7 +40,7 @@ sub uppercase() {
|
||||
sub chrout(ubyte char) {
|
||||
%ir {{
|
||||
loadm.b r65535,txt.chrout.char
|
||||
push.b r65535
|
||||
setparam.b r65535,0
|
||||
syscall 2
|
||||
}}
|
||||
}
|
||||
@ -48,7 +48,7 @@ sub chrout(ubyte char) {
|
||||
sub print (str text) {
|
||||
%ir {{
|
||||
loadm.w r65535,txt.print.text
|
||||
push.w r65535
|
||||
setparam.w r65535,0
|
||||
syscall 3
|
||||
}}
|
||||
}
|
||||
@ -126,9 +126,9 @@ sub input_chars (uword buffer) -> ubyte {
|
||||
; It assumes the keyboard is selected as I/O channel!
|
||||
%ir {{
|
||||
loadm.w r65535,txt.input_chars.buffer
|
||||
push.w r65535
|
||||
setparam.w r65535,0
|
||||
load.b r65535,80
|
||||
push.b r65535
|
||||
setparam.b r65535,1
|
||||
syscall 6
|
||||
pop.b r0
|
||||
returnr.b r0
|
||||
|
@ -47,9 +47,6 @@ Compiler:
|
||||
- ir: peephole opt: reuse registers in chunks (but keep result registers in mind that pass values out! and don't renumber registers above SyscallRegisterBase!)
|
||||
- ir: add more optimizations in IRPeepholeOptimizer
|
||||
- ir: for expressions with array indexes that occur multiple times, can we avoid loading them into new virtualregs everytime and just reuse a single virtualreg as indexer? (simple form of common subexpression elimination)
|
||||
- ir: write arguments for subroutine calls in IR differently?
|
||||
don't load them explicitly into the variables but use a new special instruction to do it transparently.
|
||||
(vm should take care of it based on the subroutine's parameter list)
|
||||
- PtAst/IR: more complex common subexpression eliminations
|
||||
- vm: somehow be able to load a label address as value? (VmProgramLoader) this may require storing the program as bytecodes in actual memory though...
|
||||
- 6502 codegen: see if we can let for loops skip the loop if startvar>endvar, without adding a lot of code size/duplicating the loop condition.
|
||||
|
@ -4,18 +4,24 @@
|
||||
%import string
|
||||
|
||||
main {
|
||||
ubyte a
|
||||
sub func1() {
|
||||
a++
|
||||
}
|
||||
|
||||
sub func2() -> ubyte {
|
||||
a++
|
||||
return a
|
||||
}
|
||||
|
||||
sub start() {
|
||||
str name = "irmen"
|
||||
reverse(name)
|
||||
txt.print(name)
|
||||
a=42
|
||||
func1()
|
||||
txt.print_ub(a)
|
||||
txt.nl()
|
||||
sort(name)
|
||||
txt.print(name)
|
||||
txt.nl()
|
||||
txt.print_ub('@' in name)
|
||||
txt.nl()
|
||||
txt.print_ub('i' in name)
|
||||
txt.print_ub(func2())
|
||||
txt.nl()
|
||||
floats.print_f(floats.PI)
|
||||
sys.wait(60)
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ CONTROL FLOW
|
||||
------------
|
||||
jump location - continue running at instruction number given by location
|
||||
jumpa address - continue running at memory address (note: only used to encode a physical cpu jump to fixed address instruction)
|
||||
setparam reg1, argpos - sets reg1 as the value for the parameter in the given position for an upcoming function call (call, callr, syscall, or even jump opcode).
|
||||
call location - save current instruction location+1, continue execution at instruction nr given by location. No return value is expected.
|
||||
callr reg1, location - like call but expects the routine to return a value with a returnr instruction, it then puts that in reg1
|
||||
syscall value - do a systemcall identified by call number, result value(s) are pushed on value stack so need to be POPped off (depends on syscall)
|
||||
@ -237,6 +238,7 @@ enum class Opcode {
|
||||
|
||||
JUMP,
|
||||
JUMPA,
|
||||
SETPARAM,
|
||||
CALL,
|
||||
CALLR,
|
||||
SYSCALL,
|
||||
@ -517,11 +519,12 @@ val instructionFormats = mutableMapOf(
|
||||
Opcode.STOREZX to InstructionFormat.from("BW,<r1,>a | F,<r1,>a"),
|
||||
Opcode.JUMP to InstructionFormat.from("N,<a"),
|
||||
Opcode.JUMPA to InstructionFormat.from("N,<a"),
|
||||
Opcode.SETPARAM to InstructionFormat.from("BW,<r1,<i | F,<fr1,<i"),
|
||||
Opcode.CALL to InstructionFormat.from("N,<a"),
|
||||
Opcode.CALLR to InstructionFormat.from("BW,>r1,<a | F,>fr1,<a"),
|
||||
Opcode.CALLR to InstructionFormat.from("BW,>r1,<a | F,>fr1,<a"),
|
||||
Opcode.SYSCALL to InstructionFormat.from("N,<i"),
|
||||
Opcode.RETURN to InstructionFormat.from("N"),
|
||||
Opcode.RETURNR to InstructionFormat.from("BW,>r1 | F,>fr1"),
|
||||
Opcode.RETURNR to InstructionFormat.from("BW,>r1 | F,>fr1"),
|
||||
Opcode.BSTCC to InstructionFormat.from("N,<a"),
|
||||
Opcode.BSTCS to InstructionFormat.from("N,<a"),
|
||||
Opcode.BSTEQ to InstructionFormat.from("N,<a"),
|
||||
@ -698,7 +701,12 @@ 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) {
|
||||
if(opcode!=Opcode.SETPARAM)
|
||||
require(immediateFp !=null) {"missing immediate fp value"}
|
||||
else
|
||||
require(immediateFp==null) {"setparam never has immediateFp only immediate"}
|
||||
}
|
||||
else require(immediate!=null || labelSymbol!=null) {"missing immediate value or labelsymbol"}
|
||||
}
|
||||
if(type!=IRDataType.FLOAT)
|
||||
|
@ -198,6 +198,10 @@ fun parseIRCodeLine(line: String, location: Pair<IRCodeChunk, Int>?, placeholder
|
||||
null -> {}
|
||||
}
|
||||
}
|
||||
if(format.immediate && opcode==Opcode.SETPARAM && immediateInt==null) {
|
||||
immediateInt = immediateFp!!.toInt()
|
||||
immediateFp = null
|
||||
}
|
||||
|
||||
if(format.address!=OperandDirection.UNUSED && address==null && labelSymbol==null)
|
||||
throw IRParseException("requires address or symbol for $line")
|
||||
|
@ -92,6 +92,7 @@ uword sys.wait.jiffies
|
||||
</PARAMS>
|
||||
<INLINEASM LABEL="sys.wait" IR="true" POS="[library:/prog8lib/virtual/syslib.p8: line 17 col 10-13]">
|
||||
loadm.w r0,sys.wait.jiffies
|
||||
setparam.w r0,0
|
||||
syscall 13
|
||||
</INLINEASM>
|
||||
<CODE>
|
||||
|
@ -80,7 +80,12 @@ enum class Syscall {
|
||||
RNDF,
|
||||
STRING_CONTAINS,
|
||||
BYTEARRAY_CONTAINS,
|
||||
WORDARRAY_CONTAINS
|
||||
WORDARRAY_CONTAINS;
|
||||
|
||||
companion object {
|
||||
private val VALUES = values()
|
||||
fun fromInt(value: Int) = VALUES[value]
|
||||
}
|
||||
}
|
||||
|
||||
object SysCalls {
|
||||
|
@ -176,6 +176,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
Opcode.STOREZI -> InsSTOREZI(ins)
|
||||
Opcode.JUMP -> InsJUMP(ins)
|
||||
Opcode.JUMPA -> throw IllegalArgumentException("vm program can't jump to system memory address (JUMPA)")
|
||||
Opcode.SETPARAM -> InsSETPARAM(ins)
|
||||
Opcode.CALL, Opcode.CALLR -> InsCALL(ins)
|
||||
Opcode.SYSCALL -> InsSYSCALL(ins)
|
||||
Opcode.RETURN -> InsRETURN()
|
||||
@ -351,8 +352,19 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
}
|
||||
|
||||
private fun InsSYSCALL(i: IRInstruction) {
|
||||
val call = Syscall.values()[i.immediate!!]
|
||||
SysCalls.call(call, this) // note: any result value(s) are pushed on the value stack
|
||||
// put the syscall's arguments that were prepared onto the stack
|
||||
for(value in syscallParams) {
|
||||
if(value.dt==null)
|
||||
break
|
||||
when(value.dt!!) {
|
||||
IRDataType.BYTE -> valueStack.push(value.value as UByte)
|
||||
IRDataType.WORD -> valueStack.pushw(value.value as UShort)
|
||||
IRDataType.FLOAT -> valueStack.pushf(value.value as Float)
|
||||
}
|
||||
value.dt=null
|
||||
}
|
||||
val call = Syscall.fromInt(i.immediate!!)
|
||||
SysCalls.call(call, this) // note: any result value(s) are pushed back on the value stack
|
||||
nextPc()
|
||||
}
|
||||
|
||||
@ -589,6 +601,31 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
branchTo(i)
|
||||
}
|
||||
|
||||
private class SyscallParamValue(var dt: IRDataType?, var value: Comparable<*>?)
|
||||
private val syscallParams = Array(100) { SyscallParamValue(null, null) }
|
||||
|
||||
private fun InsSETPARAM(i: IRInstruction) {
|
||||
// store the argument value into the retrieved subroutine's parameter variable (already cached in the instruction's address)
|
||||
// the reason this is a special instruction is to be flexible in implementing the call convention
|
||||
val address = i.address
|
||||
if(address==null) {
|
||||
// this param is for a SYSCALL (that has no param variable address, instead it goes via the stack)
|
||||
syscallParams[i.immediate!!].dt = i.type!!
|
||||
syscallParams[i.immediate!!].value = when(i.type!!) {
|
||||
IRDataType.BYTE -> registers.getUB(i.reg1!!)
|
||||
IRDataType.WORD -> registers.getUW(i.reg1!!)
|
||||
IRDataType.FLOAT -> registers.getFloat(i.fpReg1!!)
|
||||
}
|
||||
} else {
|
||||
when (i.type!!) {
|
||||
IRDataType.BYTE -> memory.setUB(address, registers.getUB(i.reg1!!))
|
||||
IRDataType.WORD -> memory.setUW(address, registers.getUW(i.reg1!!))
|
||||
IRDataType.FLOAT -> memory.setFloat(address, registers.getFloat(i.fpReg1!!))
|
||||
}
|
||||
}
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsCALL(i: IRInstruction) {
|
||||
callStack.push(CallSiteContext(pcChunk, pcIndex+1, i.reg1, i.fpReg1))
|
||||
branchTo(i)
|
||||
|
@ -7,10 +7,12 @@ import prog8.intermediate.*
|
||||
|
||||
class VmProgramLoader {
|
||||
private val placeholders = mutableMapOf<Pair<IRCodeChunk, Int>, String>() // program chunk+index to symbolname
|
||||
private val subroutines = mutableMapOf<String, IRSubroutine>() // label to subroutine node
|
||||
|
||||
fun load(irProgram: IRProgram, memory: Memory): List<IRCodeChunk> {
|
||||
placeholders.clear()
|
||||
irProgram.validate()
|
||||
placeholders.clear()
|
||||
subroutines.clear()
|
||||
val allocations = VmVariableAllocator(irProgram.st, irProgram.encoding, irProgram.options.compTarget)
|
||||
val variableAddresses = allocations.allocations.toMutableMap()
|
||||
val programChunks = mutableListOf<IRCodeChunk>()
|
||||
@ -48,6 +50,7 @@ class VmProgramLoader {
|
||||
}
|
||||
is IRInlineBinaryChunk -> throw IRParseException("inline binary data not yet supported in the VM") // TODO
|
||||
is IRSubroutine -> {
|
||||
subroutines[child.label] = child
|
||||
child.chunks.forEach { chunk ->
|
||||
when (chunk) {
|
||||
is IRInlineAsmChunk -> {
|
||||
@ -58,13 +61,14 @@ class VmProgramLoader {
|
||||
is IRCodeChunk -> programChunks += chunk
|
||||
else -> throw AssemblyError("weird chunk type")
|
||||
}
|
||||
} }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pass2translateSyscalls(programChunks)
|
||||
pass2replaceLabelsByProgIndex(programChunks, variableAddresses)
|
||||
pass2replaceLabelsByProgIndex(programChunks, variableAddresses, subroutines)
|
||||
phase2relinkReplacedChunks(chunkReplacements, programChunks)
|
||||
|
||||
programChunks.forEach {
|
||||
@ -137,7 +141,8 @@ class VmProgramLoader {
|
||||
|
||||
private fun pass2replaceLabelsByProgIndex(
|
||||
chunks: MutableList<IRCodeChunk>,
|
||||
variableAddresses: MutableMap<String, Int>
|
||||
variableAddresses: MutableMap<String, Int>,
|
||||
subroutines: MutableMap<String, IRSubroutine>
|
||||
) {
|
||||
for((ref, label) in placeholders) {
|
||||
val (chunk, line) = ref
|
||||
@ -168,6 +173,33 @@ class VmProgramLoader {
|
||||
chunk.instructions[line] = chunk.instructions[line].copy(address = replacement)
|
||||
}
|
||||
}
|
||||
|
||||
chunks.forEach {
|
||||
it.instructions.withIndex().forEach { (index, ins) ->
|
||||
if(ins.opcode==Opcode.SETPARAM && ins.address==null) {
|
||||
val call = findCall(it, index)
|
||||
if(call.opcode==Opcode.SYSCALL) {
|
||||
// there is no variable to set, SYSCALLs get their args from the stack.
|
||||
} else if(call.labelSymbol!=null) {
|
||||
// set the address in the instruction to the subroutine's parameter variable's address
|
||||
// this avoids having to look it up every time the SETPARAM instruction is encountered during execution
|
||||
val target = subroutines.getValue(call.labelSymbol!!)
|
||||
val paramVar = target.parameters[ins.immediate!!]
|
||||
val address = variableAddresses.getValue(paramVar.name)
|
||||
it.instructions[index] = ins.copy(address = address)
|
||||
} else
|
||||
throw IRParseException("weird call $call")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val functionCallOpcodes = setOf(Opcode.CALL, Opcode.CALLR, Opcode.SYSCALL, Opcode.JUMP, Opcode.JUMPA)
|
||||
private fun findCall(it: IRCodeChunk, startIndex: Int): IRInstruction {
|
||||
var idx = startIndex
|
||||
while(it.instructions[idx].opcode !in functionCallOpcodes)
|
||||
idx++
|
||||
return it.instructions[idx]
|
||||
}
|
||||
|
||||
private fun varsToMemory(
|
||||
|
Loading…
Reference in New Issue
Block a user