mirror of
https://github.com/irmen/prog8.git
synced 2026-04-20 11:17:01 +00:00
workin on vm issues
This commit is contained in:
@@ -39,15 +39,7 @@ internal class AssemblyProgram(override val name: String,
|
||||
when(line) {
|
||||
is VmCodeComment -> write("; ${line.comment}\n")
|
||||
is VmCodeInstruction -> {
|
||||
write(line.ins.toString())
|
||||
if(line.labelArg!=null) {
|
||||
if (line.ins.reg1 != null || line.ins.reg2 != null || line.ins.reg3 != null || line.ins.value != null)
|
||||
write(",")
|
||||
else
|
||||
write(" ")
|
||||
write("_" + line.labelArg.joinToString("."))
|
||||
}
|
||||
write("\n")
|
||||
write(line.ins.toString() + "\n")
|
||||
}
|
||||
is VmCodeLabel -> write("_" + line.name.joinToString(".") + ":\n")
|
||||
}
|
||||
@@ -59,7 +51,7 @@ internal class AssemblyProgram(override val name: String,
|
||||
|
||||
internal sealed class VmCodeLine
|
||||
|
||||
internal class VmCodeInstruction(val ins: Instruction, val labelArg: List<String>?=null): VmCodeLine()
|
||||
internal class VmCodeInstruction(val ins: Instruction): VmCodeLine()
|
||||
internal class VmCodeLabel(val name: List<String>): VmCodeLine()
|
||||
internal class VmCodeComment(val comment: String): VmCodeLine()
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
package prog8.codegen.virtual
|
||||
|
||||
import prog8.code.ast.PtBuiltinFunctionCall
|
||||
import prog8.code.ast.PtNumber
|
||||
import prog8.code.ast.PtString
|
||||
import prog8.vm.Instruction
|
||||
import prog8.vm.Opcode
|
||||
import prog8.vm.Syscall
|
||||
import prog8.vm.VmDataType
|
||||
|
||||
internal class BuiltinFuncGen(val codeGen: CodeGen, val exprGen: ExpressionGen) {
|
||||
|
||||
fun translate(call: PtBuiltinFunctionCall, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
when(call.name) {
|
||||
"syscall" -> {
|
||||
val vExpr = call.args.single() as PtNumber
|
||||
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
|
||||
}
|
||||
"syscall1" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
|
||||
val callNr = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], 0, regUsage)
|
||||
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
|
||||
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
|
||||
}
|
||||
"syscall2" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
|
||||
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1))
|
||||
while(regUsage.firstFree<2) {
|
||||
regUsage.nextFree()
|
||||
}
|
||||
val callNr = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], 0, regUsage)
|
||||
code += exprGen.translateExpression(call.args[2], 1, regUsage)
|
||||
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
|
||||
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 1))
|
||||
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
|
||||
}
|
||||
"syscall3" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
|
||||
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1))
|
||||
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 2))
|
||||
while(regUsage.firstFree<3) {
|
||||
regUsage.nextFree()
|
||||
}
|
||||
val callNr = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], 0, regUsage)
|
||||
code += exprGen.translateExpression(call.args[2], 1, regUsage)
|
||||
code += exprGen.translateExpression(call.args[3], 2, regUsage)
|
||||
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
|
||||
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 2))
|
||||
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 1))
|
||||
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
|
||||
}
|
||||
"msb" -> {
|
||||
code += exprGen.translateExpression(call.args.single(), resultRegister, regUsage)
|
||||
code += VmCodeInstruction(Instruction(Opcode.SWAP, VmDataType.BYTE, reg1 = resultRegister, reg2=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, regUsage)
|
||||
// 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(Instruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, value=address.toInt()))
|
||||
}
|
||||
"rnd" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value= Syscall.RND.ordinal))
|
||||
if(resultRegister!=0)
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0))
|
||||
}
|
||||
"peek" -> {
|
||||
val addressReg = regUsage.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg, regUsage)
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=addressReg))
|
||||
}
|
||||
"peekw" -> {
|
||||
val addressReg = regUsage.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg, regUsage)
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg))
|
||||
}
|
||||
else -> {
|
||||
TODO("builtinfunc ${call.name}")
|
||||
// code += VmCodeInstruction(Instruction(Opcode.NOP))
|
||||
// for (arg in call.args) {
|
||||
// code += translateExpression(arg, resultRegister, regUsage)
|
||||
// code += when(arg.type) {
|
||||
// in ByteDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1=resultRegister))
|
||||
// in WordDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1=resultRegister))
|
||||
// else -> throw AssemblyError("weird arg dt")
|
||||
// }
|
||||
// }
|
||||
// code += VmCodeInstruction(Instruction(Opcode.CALL), labelArg = listOf("_prog8_builtin", call.name))
|
||||
// for (arg in call.args) {
|
||||
// code += when(arg.type) {
|
||||
// in ByteDatatypes -> VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1=resultRegister))
|
||||
// in WordDatatypes -> VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1=resultRegister))
|
||||
// else -> throw AssemblyError("weird arg dt")
|
||||
// }
|
||||
// }
|
||||
// code += VmCodeInstruction(Instruction(Opcode.NOP))
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
|
||||
internal val allocations = VariableAllocator(symbolTable, program, errors)
|
||||
private val expressionEval = ExpressionGen(this)
|
||||
private val builtinFuncGen = BuiltinFuncGen(this, expressionEval)
|
||||
|
||||
init {
|
||||
if(options.dontReinitGlobals)
|
||||
@@ -52,7 +53,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
is PtConstant -> VmCodeChunk() // constants have all been folded into the code
|
||||
is PtAssignment -> translate(node, regUsage)
|
||||
is PtNodeGroup -> translateGroup(node.children, regUsage)
|
||||
is PtBuiltinFunctionCall -> expressionEval.translate(node, regUsage.nextFree(), regUsage)
|
||||
is PtBuiltinFunctionCall -> translateBuiltinFunc(node, regUsage.nextFree(), regUsage)
|
||||
is PtFunctionCall -> expressionEval.translate(node, regUsage.nextFree(), regUsage)
|
||||
is PtNop -> VmCodeChunk()
|
||||
is PtReturn -> translate(node)
|
||||
@@ -140,16 +141,16 @@ class CodeGen(internal val program: PtProgram,
|
||||
// if and else parts
|
||||
val elseLabel = createLabelName()
|
||||
val afterIfLabel = createLabelName()
|
||||
code += VmCodeInstruction(Instruction(branch, vmDt, reg1=conditionReg), labelArg = elseLabel)
|
||||
code += VmCodeInstruction(Instruction(branch, vmDt, reg1=conditionReg, symbol = elseLabel))
|
||||
code += translateNode(ifElse.ifScope, regUsage)
|
||||
code += VmCodeInstruction(Instruction(Opcode.JUMP), labelArg = afterIfLabel)
|
||||
code += VmCodeInstruction(Instruction(Opcode.JUMP, symbol = afterIfLabel))
|
||||
code += VmCodeLabel(elseLabel)
|
||||
code += translateNode(ifElse.elseScope, regUsage)
|
||||
code += VmCodeLabel(afterIfLabel)
|
||||
} else {
|
||||
// only if part
|
||||
val afterIfLabel = createLabelName()
|
||||
code += VmCodeInstruction(Instruction(branch, vmDt, reg1=conditionReg), labelArg = afterIfLabel)
|
||||
code += VmCodeInstruction(Instruction(branch, vmDt, reg1=conditionReg, symbol = afterIfLabel))
|
||||
code += translateNode(ifElse.ifScope, regUsage)
|
||||
code += VmCodeLabel(afterIfLabel)
|
||||
}
|
||||
@@ -205,7 +206,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
code += VmCodeLabel(repeatLabel)
|
||||
code += translateNode(repeat.statements, regUsage)
|
||||
code += VmCodeInstruction(Instruction(Opcode.DEC, vmDt, reg1=counterReg))
|
||||
code += VmCodeInstruction(Instruction(Opcode.BNZ, vmDt, reg1=counterReg), labelArg = repeatLabel)
|
||||
code += VmCodeInstruction(Instruction(Opcode.BNZ, vmDt, reg1=counterReg, symbol = repeatLabel))
|
||||
return code
|
||||
}
|
||||
|
||||
@@ -214,9 +215,9 @@ class CodeGen(internal val program: PtProgram,
|
||||
if(jump.address!=null)
|
||||
throw AssemblyError("cannot jump to memory location in the vm target")
|
||||
code += if(jump.generatedLabel!=null)
|
||||
VmCodeInstruction(Instruction(Opcode.JUMP), labelArg = listOf(jump.generatedLabel!!))
|
||||
VmCodeInstruction(Instruction(Opcode.JUMP, symbol = listOf(jump.generatedLabel!!)))
|
||||
else if(jump.identifier!=null)
|
||||
VmCodeInstruction(Instruction(Opcode.JUMP), labelArg = jump.identifier!!.targetName)
|
||||
VmCodeInstruction(Instruction(Opcode.JUMP, symbol = jump.identifier!!.targetName))
|
||||
else
|
||||
throw AssemblyError("weird jump")
|
||||
return code
|
||||
@@ -325,4 +326,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
labelSequenceNumber++
|
||||
return listOf("generated$labelSequenceNumber")
|
||||
}
|
||||
|
||||
internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk =
|
||||
builtinFuncGen.translate(call, resultRegister, regUsage)
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@ package prog8.codegen.virtual
|
||||
import prog8.code.StStaticVariable
|
||||
import prog8.code.StSub
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.code.core.AssemblyError
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.PassByValueDatatypes
|
||||
import prog8.code.core.SignedDatatypes
|
||||
import prog8.vm.Instruction
|
||||
import prog8.vm.Opcode
|
||||
import prog8.vm.Syscall
|
||||
import prog8.vm.VmDataType
|
||||
|
||||
|
||||
@@ -52,7 +54,7 @@ internal class ExpressionGen(val codeGen: CodeGen) {
|
||||
is PtPrefix -> code += translate(expr, resultRegister, regUsage)
|
||||
is PtArrayIndexer -> code += translate(expr, resultRegister, regUsage)
|
||||
is PtBinaryExpression -> code += translate(expr, resultRegister, regUsage)
|
||||
is PtBuiltinFunctionCall -> code += translate(expr, resultRegister, regUsage)
|
||||
is PtBuiltinFunctionCall -> code += codeGen.translateBuiltinFunc(expr, resultRegister, regUsage)
|
||||
is PtFunctionCall -> code += translate(expr, resultRegister, regUsage)
|
||||
is PtContainmentCheck -> code += translate(expr, resultRegister, regUsage)
|
||||
is PtPipe -> code += translate(expr, resultRegister, regUsage)
|
||||
@@ -132,7 +134,7 @@ internal class ExpressionGen(val codeGen: CodeGen) {
|
||||
}
|
||||
"not" -> {
|
||||
val label = codeGen.createLabelName()
|
||||
code += VmCodeInstruction(Instruction(Opcode.BZ, vmDt, reg1=resultRegister), labelArg = label)
|
||||
code += VmCodeInstruction(Instruction(Opcode.BZ, vmDt, reg1=resultRegister, symbol = label))
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=1))
|
||||
code += VmCodeLabel(label)
|
||||
val regMask = regUsage.nextFree()
|
||||
@@ -300,7 +302,7 @@ internal class ExpressionGen(val codeGen: CodeGen) {
|
||||
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
|
||||
code += VmCodeInstruction(Instruction(Opcode.STOREM, vmDt, reg1=argReg, value=mem))
|
||||
}
|
||||
code += VmCodeInstruction(Instruction(Opcode.CALL), labelArg=fcall.functionName)
|
||||
code += VmCodeInstruction(Instruction(Opcode.CALL, symbol=fcall.functionName))
|
||||
if(!fcall.void && resultRegister!=0) {
|
||||
// Call convention: result value is in r0, so put it in the required register instead. TODO does this work correctly?
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOADR, codeGen.vmType(fcall.type), reg1=resultRegister, reg2=0))
|
||||
@@ -308,111 +310,4 @@ internal class ExpressionGen(val codeGen: CodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
fun translate(call: PtBuiltinFunctionCall, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
when(call.name) {
|
||||
"syscall" -> {
|
||||
val vExpr = call.args.single() as PtNumber
|
||||
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
|
||||
}
|
||||
"syscall1" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
|
||||
val callNr = (call.args[0] as PtNumber).number.toInt()
|
||||
code += translateExpression(call.args[1], 0, regUsage)
|
||||
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
|
||||
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
|
||||
}
|
||||
"syscall2" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
|
||||
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1))
|
||||
while(regUsage.firstFree<2) {
|
||||
regUsage.nextFree()
|
||||
}
|
||||
val callNr = (call.args[0] as PtNumber).number.toInt()
|
||||
code += translateExpression(call.args[1], 0, regUsage)
|
||||
code += translateExpression(call.args[2], 1, regUsage)
|
||||
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
|
||||
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 1))
|
||||
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
|
||||
}
|
||||
"syscall3" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
|
||||
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1))
|
||||
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 2))
|
||||
while(regUsage.firstFree<3) {
|
||||
regUsage.nextFree()
|
||||
}
|
||||
val callNr = (call.args[0] as PtNumber).number.toInt()
|
||||
code += translateExpression(call.args[1], 0, regUsage)
|
||||
code += translateExpression(call.args[2], 1, regUsage)
|
||||
code += translateExpression(call.args[3], 2, regUsage)
|
||||
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
|
||||
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 2))
|
||||
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 1))
|
||||
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
|
||||
}
|
||||
"msb" -> {
|
||||
code += translateExpression(call.args.single(), resultRegister, regUsage)
|
||||
code += VmCodeInstruction(Instruction(Opcode.SWAP, VmDataType.BYTE, reg1 = resultRegister, reg2=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 += translateExpression(call.args.single(), resultRegister, regUsage)
|
||||
// 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(Instruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, value=address.toInt()))
|
||||
}
|
||||
"rnd" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=Syscall.RND.ordinal))
|
||||
if(resultRegister!=0)
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0))
|
||||
}
|
||||
"peek" -> {
|
||||
val addressReg = regUsage.nextFree()
|
||||
code += translateExpression(call.args.single(), addressReg, regUsage)
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=addressReg))
|
||||
}
|
||||
"peekw" -> {
|
||||
val addressReg = regUsage.nextFree()
|
||||
code += translateExpression(call.args.single(), addressReg, regUsage)
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg))
|
||||
}
|
||||
else -> {
|
||||
TODO("builtinfunc ${call.name}")
|
||||
// code += VmCodeInstruction(Instruction(Opcode.NOP))
|
||||
// for (arg in call.args) {
|
||||
// code += translateExpression(arg, resultRegister, regUsage)
|
||||
// code += when(arg.type) {
|
||||
// in ByteDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1=resultRegister))
|
||||
// in WordDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1=resultRegister))
|
||||
// else -> throw AssemblyError("weird arg dt")
|
||||
// }
|
||||
// }
|
||||
// code += VmCodeInstruction(Instruction(Opcode.CALL), labelArg = listOf("_prog8_builtin", call.name))
|
||||
// for (arg in call.args) {
|
||||
// code += when(arg.type) {
|
||||
// in ByteDatatypes -> VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1=resultRegister))
|
||||
// in WordDatatypes -> VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1=resultRegister))
|
||||
// else -> throw AssemblyError("weird arg dt")
|
||||
// }
|
||||
// }
|
||||
// code += VmCodeInstruction(Instruction(Opcode.NOP))
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user