more readable

This commit is contained in:
Irmen de Jong 2022-04-10 22:31:37 +02:00
parent c25d07259a
commit 890b1c2d52
3 changed files with 219 additions and 150 deletions

View File

@ -10,151 +10,29 @@ import prog8.vm.VmDataType
internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: ExpressionGen) {
fun translate(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
when(call.name) {
"syscall" -> {
val vExpr = call.args.single() as PtNumber
code += VmCodeInstruction(Opcode.SYSCALL, value=vExpr.number.toInt())
}
"syscall1" -> {
val callNr = (call.args[0] as PtNumber).number.toInt()
code += exprGen.translateExpression(call.args[1], 0)
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
}
"syscall2" -> {
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1)
while(codeGen.vmRegisters.peekNext()<2) {
codeGen.vmRegisters.nextFree()
}
val callNr = (call.args[0] as PtNumber).number.toInt()
code += exprGen.translateExpression(call.args[1], 0)
code += exprGen.translateExpression(call.args[2], 1)
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1)
}
"syscall3" -> {
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1)
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 2)
while(codeGen.vmRegisters.peekNext()<3) {
codeGen.vmRegisters.nextFree()
}
val callNr = (call.args[0] as PtNumber).number.toInt()
code += exprGen.translateExpression(call.args[1], 0)
code += exprGen.translateExpression(call.args[2], 1)
code += exprGen.translateExpression(call.args[3], 2)
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 2)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1)
}
"msb" -> {
code += exprGen.translateExpression(call.args.single(), resultRegister)
code += VmCodeInstruction(Opcode.SWAP, VmDataType.BYTE, reg1 = resultRegister)
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
}
"lsb" -> {
code += exprGen.translateExpression(call.args.single(), resultRegister)
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
}
"memory" -> {
val name = (call.args[0] as PtString).value
val size = (call.args[1] as PtNumber).number.toUInt()
val align = (call.args[2] as PtNumber).number.toUInt()
val existing = codeGen.allocations.getMemorySlab(name)
val address = if(existing==null)
codeGen.allocations.allocateMemorySlab(name, size, align)
else if(existing.second!=size || existing.third!=align) {
codeGen.errors.err("memory slab '$name' already exists with a different size or alignment", call.position)
return VmCodeChunk()
}
else
existing.first
code += VmCodeInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, value=address.toInt())
}
"rnd" -> {
code += VmCodeInstruction(Opcode.SYSCALL, value= Syscall.RND.ordinal)
if(resultRegister!=0)
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
}
"peek" -> {
// should just be a memory read
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), addressReg)
code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=addressReg)
}
"peekw" -> {
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), addressReg)
code += VmCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg)
}
"poke" -> {
// should just be a memory write
val addressReg = codeGen.vmRegisters.nextFree()
val valueReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], addressReg)
code += exprGen.translateExpression(call.args[1], valueReg)
code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = addressReg, reg2=valueReg)
}
"pokew" -> {
val addressReg = codeGen.vmRegisters.nextFree()
val valueReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], addressReg)
code += exprGen.translateExpression(call.args[1], valueReg)
code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = addressReg, reg2=valueReg)
}
"mkword" -> {
val msbReg = codeGen.vmRegisters.nextFree()
val lsbReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], msbReg)
code += exprGen.translateExpression(call.args[1], lsbReg)
code += VmCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg, reg3=lsbReg)
}
"sin8u" -> {
code += exprGen.translateExpression(call.args[0], 0)
code += VmCodeInstruction(Opcode.SYSCALL, value=Syscall.SIN8U.ordinal)
if(resultRegister!=0)
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
}
"cos8u" -> {
code += exprGen.translateExpression(call.args[0], 0)
code += VmCodeInstruction(Opcode.SYSCALL, value=Syscall.COS8U.ordinal)
if(resultRegister!=0)
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
}
"sort" -> {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
val sortSyscall =
when(array.dt) {
DataType.ARRAY_UB -> Syscall.SORT_UBYTE
DataType.ARRAY_B -> Syscall.SORT_BYTE
DataType.ARRAY_UW -> Syscall.SORT_UWORD
DataType.ARRAY_W -> Syscall.SORT_WORD
DataType.FLOAT -> TODO("float sort")
DataType.STR -> Syscall.SORT_UBYTE
else -> throw IllegalArgumentException("weird type to sort")
}
code += exprGen.translateExpression(call.args[0], 0)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
}
"reverse" -> {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
val sortSyscall =
when(array.dt) {
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.STR -> Syscall.REVERSE_BYTES
DataType.ARRAY_UW, DataType.ARRAY_W -> Syscall.REVERSE_WORDS
DataType.FLOAT -> TODO("reverse floats")
else -> throw IllegalArgumentException("weird type to reverse")
}
code += exprGen.translateExpression(call.args[0], 0)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
}
"rol" -> RolRor2(Opcode.ROXL, call, resultRegister, code)
"ror" -> RolRor2(Opcode.ROXR, call, resultRegister, code)
"rol2" -> RolRor2(Opcode.ROL, call, resultRegister, code)
"ror2" -> RolRor2(Opcode.ROR, call, resultRegister, code)
return when(call.name) {
"syscall" -> funcSyscall(call)
"syscall1" -> funcSyscall1(call)
"syscall2" -> funcSyscall2(call)
"syscall3" -> funcSyscall3(call)
"msb" -> funcMsb(call, resultRegister)
"lsb" -> funcLsb(call, resultRegister)
"memory" -> funcMemory(call, resultRegister)
"rnd" -> funcRnd(call, resultRegister)
"peek" -> funcPeek(call, resultRegister)
"peekw" -> funcPeekW(call, resultRegister)
"poke" -> funcPoke(call, resultRegister)
"pokew" -> funcPokeW(call, resultRegister)
"pokemon" -> VmCodeChunk()
"mkword" -> funcMkword(call, resultRegister)
"sin8u" -> funcSin8u(call, resultRegister)
"cos8u" -> funcCos8u(call, resultRegister)
"sort" -> funcSort(call)
"reverse" -> funcReverse(call)
"rol" -> funcRolRor2(Opcode.ROXL, call, resultRegister)
"ror" -> funcRolRor2(Opcode.ROXR, call, resultRegister)
"rol2" -> funcRolRor2(Opcode.ROL, call, resultRegister)
"ror2" -> funcRolRor2(Opcode.ROR, call, resultRegister)
else -> {
TODO("builtinfunc ${call.name}")
// code += VmCodeInstruction(Opcode.NOP))
@ -177,12 +55,202 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
// code += VmCodeInstruction(Opcode.NOP))
}
}
}
private fun funcReverse(call: PtBuiltinFunctionCall): VmCodeChunk {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
val sortSyscall =
when(array.dt) {
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.STR -> Syscall.REVERSE_BYTES
DataType.ARRAY_UW, DataType.ARRAY_W -> Syscall.REVERSE_WORDS
DataType.FLOAT -> TODO("reverse floats")
else -> throw IllegalArgumentException("weird type to reverse")
}
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args[0], 0)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
return code
}
private fun RolRor2(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int, code: VmCodeChunk) {
private fun funcSort(call: PtBuiltinFunctionCall): VmCodeChunk {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
val sortSyscall =
when(array.dt) {
DataType.ARRAY_UB -> Syscall.SORT_UBYTE
DataType.ARRAY_B -> Syscall.SORT_BYTE
DataType.ARRAY_UW -> Syscall.SORT_UWORD
DataType.ARRAY_W -> Syscall.SORT_WORD
DataType.FLOAT -> TODO("float sort")
DataType.STR -> Syscall.SORT_UBYTE
else -> throw IllegalArgumentException("weird type to sort")
}
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args[0], 0)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
return code
}
private fun funcCos8u(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args[0], 0)
code += VmCodeInstruction(Opcode.SYSCALL, value=Syscall.COS8U.ordinal)
if(resultRegister!=0)
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
return code
}
private fun funcSin8u(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args[0], 0)
code += VmCodeInstruction(Opcode.SYSCALL, value=Syscall.SIN8U.ordinal)
if(resultRegister!=0)
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
return code
}
private fun funcMkword(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val msbReg = codeGen.vmRegisters.nextFree()
val lsbReg = codeGen.vmRegisters.nextFree()
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args[0], msbReg)
code += exprGen.translateExpression(call.args[1], lsbReg)
code += VmCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg, reg3=lsbReg)
return code
}
private fun funcPokeW(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val addressReg = codeGen.vmRegisters.nextFree()
val valueReg = codeGen.vmRegisters.nextFree()
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args[0], addressReg)
code += exprGen.translateExpression(call.args[1], valueReg)
code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = addressReg, reg2=valueReg)
return code
}
private fun funcPoke(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
// should just be a memory write
val addressReg = codeGen.vmRegisters.nextFree()
val valueReg = codeGen.vmRegisters.nextFree()
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args[0], addressReg)
code += exprGen.translateExpression(call.args[1], valueReg)
code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = addressReg, reg2=valueReg)
return code
}
private fun funcPeekW(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val addressReg = codeGen.vmRegisters.nextFree()
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args.single(), addressReg)
code += VmCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg)
return code
}
private fun funcPeek(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
// should just be a memory read
val code = VmCodeChunk()
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), addressReg)
code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=addressReg)
return code
}
private fun funcRnd(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
code += VmCodeInstruction(Opcode.SYSCALL, value= Syscall.RND.ordinal)
if(resultRegister!=0)
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
return code
}
private fun funcMemory(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val name = (call.args[0] as PtString).value
val size = (call.args[1] as PtNumber).number.toUInt()
val align = (call.args[2] as PtNumber).number.toUInt()
val existing = codeGen.allocations.getMemorySlab(name)
val address = if(existing==null)
codeGen.allocations.allocateMemorySlab(name, size, align)
else if(existing.second!=size || existing.third!=align) {
codeGen.errors.err("memory slab '$name' already exists with a different size or alignment", call.position)
return VmCodeChunk()
}
else
existing.first
val code = VmCodeChunk()
code += VmCodeInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, value=address.toInt())
return code
}
private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args.single(), resultRegister)
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
return code
}
private fun funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args.single(), resultRegister)
code += VmCodeInstruction(Opcode.SWAP, VmDataType.BYTE, reg1 = resultRegister)
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
return code
}
private fun funcSyscall(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
val vExpr = call.args.single() as PtNumber
code += VmCodeInstruction(Opcode.SYSCALL, value=vExpr.number.toInt())
return code
}
private fun funcSyscall1(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
val callNr = (call.args[0] as PtNumber).number.toInt()
code += exprGen.translateExpression(call.args[1], 0)
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
return code
}
private fun funcSyscall2(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1)
while(codeGen.vmRegisters.peekNext()<2) {
codeGen.vmRegisters.nextFree()
}
val callNr = (call.args[0] as PtNumber).number.toInt()
code += exprGen.translateExpression(call.args[1], 0)
code += exprGen.translateExpression(call.args[2], 1)
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1)
return code
}
private fun funcSyscall3(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1)
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 2)
while(codeGen.vmRegisters.peekNext()<3) {
codeGen.vmRegisters.nextFree()
}
val callNr = (call.args[0] as PtNumber).number.toInt()
code += exprGen.translateExpression(call.args[1], 0)
code += exprGen.translateExpression(call.args[2], 1)
code += exprGen.translateExpression(call.args[3], 2)
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 2)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1)
return code
}
private fun funcRolRor2(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
// bit rotate left without carry, in-place
val vmDt = codeGen.vmType(call.args[0].type)
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args[0], resultRegister)
code += VmCodeInstruction(opcode, vmDt, reg1=resultRegister)
val assignment = PtAssignment(call.position)
@ -191,6 +259,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
assignment.children.add(target)
assignment.children.add(PtIdentifier(listOf(":vmreg-$resultRegister"), listOf(":vmreg-$resultRegister"), call.args[0].type, call.position))
code += codeGen.translateNode(assignment)
return code
}
}

View File

@ -3,6 +3,7 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- vm: add support for all builtin functions
- pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls.
- createAssemblyAndAssemble(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there.
- allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type

View File

@ -5,16 +5,15 @@
; NOTE: meant to test to virtual machine output target (use -target vitual)
main {
%option align_word
%option force_output
sub start() {
pokemon(1,0)
; a "pixelshader":
void syscall1(8, 0) ; enable lo res creen
ubyte shifter
shifter >>= 1
; pokemon(1,0)
repeat {
uword xx