mirror of
https://github.com/irmen/prog8.git
synced 2026-04-19 20:16:51 +00:00
working on vm
This commit is contained in:
@@ -4,6 +4,7 @@ import prog8.code.core.CompilationOptions
|
||||
import prog8.code.core.IAssemblyProgram
|
||||
import prog8.vm.Instruction
|
||||
import prog8.vm.Opcode
|
||||
import prog8.vm.VmDataType
|
||||
import java.io.BufferedWriter
|
||||
import kotlin.io.path.bufferedWriter
|
||||
import kotlin.io.path.div
|
||||
@@ -51,7 +52,17 @@ internal class AssemblyProgram(override val name: String,
|
||||
|
||||
internal sealed class VmCodeLine
|
||||
|
||||
internal class VmCodeInstruction(val ins: Instruction): VmCodeLine()
|
||||
internal class VmCodeInstruction(
|
||||
opcode: Opcode,
|
||||
type: VmDataType?=null,
|
||||
reg1: Int?=null, // 0-$ffff
|
||||
reg2: Int?=null, // 0-$ffff
|
||||
reg3: Int?=null, // 0-$ffff
|
||||
value: Int?=null, // 0-$ffff
|
||||
symbol: List<String>?=null // alternative to value
|
||||
): VmCodeLine() {
|
||||
val ins = Instruction(opcode, type, reg1, reg2, reg3, value, symbol)
|
||||
}
|
||||
internal class VmCodeLabel(val name: List<String>): VmCodeLine()
|
||||
internal class VmCodeComment(val comment: String): VmCodeLine()
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ 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
|
||||
@@ -15,32 +14,32 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
when(call.name) {
|
||||
"syscall" -> {
|
||||
val vExpr = call.args.single() as PtNumber
|
||||
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=vExpr.number.toInt())
|
||||
}
|
||||
"syscall1" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
|
||||
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 0)
|
||||
val callNr = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], 0)
|
||||
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
|
||||
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
|
||||
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 0)
|
||||
}
|
||||
"syscall2" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
|
||||
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1))
|
||||
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 0)
|
||||
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(Instruction(Opcode.SYSCALL, value=callNr))
|
||||
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 1))
|
||||
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
|
||||
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1)
|
||||
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, 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))
|
||||
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 0)
|
||||
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1)
|
||||
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 2)
|
||||
while(codeGen.vmRegisters.peekNext()<3) {
|
||||
codeGen.vmRegisters.nextFree()
|
||||
}
|
||||
@@ -48,14 +47,14 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
code += exprGen.translateExpression(call.args[1], 0)
|
||||
code += exprGen.translateExpression(call.args[2], 1)
|
||||
code += exprGen.translateExpression(call.args[3], 2)
|
||||
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))
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
|
||||
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 2)
|
||||
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1)
|
||||
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 0)
|
||||
}
|
||||
"msb" -> {
|
||||
code += exprGen.translateExpression(call.args.single(), resultRegister)
|
||||
code += VmCodeInstruction(Instruction(Opcode.SWAP, VmDataType.BYTE, reg1 = resultRegister, reg2=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" -> {
|
||||
@@ -75,50 +74,50 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
}
|
||||
else
|
||||
existing.first
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, value=address.toInt()))
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, value=address.toInt())
|
||||
}
|
||||
"rnd" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value= Syscall.RND.ordinal))
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value= Syscall.RND.ordinal)
|
||||
if(resultRegister!=0)
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0))
|
||||
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
|
||||
}
|
||||
"peek" -> {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg)
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=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(Instruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg))
|
||||
code += VmCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg)
|
||||
}
|
||||
"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(Instruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg, reg3=lsbReg))
|
||||
code += VmCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg, reg3=lsbReg)
|
||||
}
|
||||
else -> {
|
||||
TODO("builtinfunc ${call.name}")
|
||||
// code += VmCodeInstruction(Instruction(Opcode.NOP))
|
||||
// code += VmCodeInstruction(Opcode.NOP))
|
||||
// for (arg in call.args) {
|
||||
// code += translateExpression(arg, resultRegister)
|
||||
// code += when(arg.type) {
|
||||
// in ByteDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1=resultRegister))
|
||||
// in WordDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1=resultRegister))
|
||||
// in ByteDatatypes -> VmCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=resultRegister))
|
||||
// in WordDatatypes -> VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1=resultRegister))
|
||||
// else -> throw AssemblyError("weird arg dt")
|
||||
// }
|
||||
// }
|
||||
// code += VmCodeInstruction(Instruction(Opcode.CALL), labelArg = listOf("_prog8_builtin", call.name))
|
||||
// code += VmCodeInstruction(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))
|
||||
// in ByteDatatypes -> VmCodeInstruction(Opcode.POP, VmDataType.BYTE, reg1=resultRegister))
|
||||
// in WordDatatypes -> VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1=resultRegister))
|
||||
// else -> throw AssemblyError("weird arg dt")
|
||||
// }
|
||||
// }
|
||||
// code += VmCodeInstruction(Instruction(Opcode.NOP))
|
||||
// code += VmCodeInstruction(Opcode.NOP))
|
||||
}
|
||||
}
|
||||
return code
|
||||
|
||||
@@ -4,10 +4,8 @@ import prog8.code.StStaticVariable
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.vm.Instruction
|
||||
import prog8.vm.Opcode
|
||||
import prog8.vm.VmDataType
|
||||
import java.lang.Math.pow
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
@@ -82,7 +80,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
is PtPostIncrDecr -> translate(node)
|
||||
is PtRepeatLoop -> translate(node)
|
||||
is PtLabel -> VmCodeChunk(VmCodeLabel(node.scopedName))
|
||||
is PtBreakpoint -> VmCodeChunk(VmCodeInstruction(Instruction(Opcode.BREAKPOINT)))
|
||||
is PtBreakpoint -> VmCodeChunk(VmCodeInstruction(Opcode.BREAKPOINT))
|
||||
is PtAddressOf,
|
||||
is PtContainmentCheck,
|
||||
is PtMemoryByte,
|
||||
@@ -129,14 +127,14 @@ class CodeGen(internal val program: PtProgram,
|
||||
val endLabel = createLabelName()
|
||||
if(iterableVar.dt==DataType.STR) {
|
||||
// iterate over a zero-terminated string
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0))
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += VmCodeLabel(loopLabel)
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOADX, VmDataType.BYTE, reg1=0, reg2=indexReg, value = arrayAddress))
|
||||
code += VmCodeInstruction(Instruction(Opcode.BZ, VmDataType.BYTE, reg1=0, symbol = endLabel))
|
||||
code += VmCodeInstruction(Instruction(Opcode.STOREM, VmDataType.BYTE, reg1=0, value = loopvarAddress))
|
||||
code += VmCodeInstruction(Opcode.LOADX, VmDataType.BYTE, reg1=0, reg2=indexReg, value = arrayAddress)
|
||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=0, symbol = endLabel)
|
||||
code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1=0, value = loopvarAddress)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += VmCodeInstruction(Instruction(Opcode.INC, VmDataType.BYTE, reg1=indexReg))
|
||||
code += VmCodeInstruction(Instruction(Opcode.JUMP, symbol = loopLabel))
|
||||
code += VmCodeInstruction(Opcode.INC, VmDataType.BYTE, reg1=indexReg)
|
||||
code += VmCodeInstruction(Opcode.JUMP, symbol = loopLabel)
|
||||
code += VmCodeLabel(endLabel)
|
||||
} else {
|
||||
// iterate over array
|
||||
@@ -154,15 +152,15 @@ class CodeGen(internal val program: PtProgram,
|
||||
goto _loop
|
||||
_end: ...
|
||||
*/
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0))
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.BYTE, reg1=lengthReg, value=lengthBytes))
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=lengthReg, value=lengthBytes)
|
||||
code += VmCodeLabel(loopLabel)
|
||||
code += VmCodeInstruction(Instruction(Opcode.BEQ, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, symbol = endLabel))
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOADX, vmType(elementDt), reg1=0, reg2=indexReg, value=arrayAddress))
|
||||
code += VmCodeInstruction(Instruction(Opcode.STOREM, vmType(elementDt), reg1=0, value = loopvarAddress))
|
||||
code += VmCodeInstruction(Opcode.BEQ, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, symbol = endLabel)
|
||||
code += VmCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=0, reg2=indexReg, value=arrayAddress)
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=0, value = loopvarAddress)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += addConst(VmDataType.BYTE, indexReg, elementSize)
|
||||
code += VmCodeInstruction(Instruction(Opcode.JUMP, symbol = loopLabel))
|
||||
code += VmCodeInstruction(Opcode.JUMP, symbol = loopLabel)
|
||||
code += VmCodeLabel(endLabel)
|
||||
}
|
||||
}
|
||||
@@ -176,12 +174,12 @@ class CodeGen(internal val program: PtProgram,
|
||||
when(value) {
|
||||
0u -> { /* do nothing */ }
|
||||
1u -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.INC, dt, reg1=reg))
|
||||
code += VmCodeInstruction(Opcode.INC, dt, reg1=reg)
|
||||
}
|
||||
else -> {
|
||||
val valueReg = vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOAD, dt, reg1=valueReg, value=value.toInt()))
|
||||
code += VmCodeInstruction(Instruction(Opcode.ADD, dt, reg1=reg, reg2=reg, reg3=valueReg))
|
||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=valueReg, value=value.toInt())
|
||||
code += VmCodeInstruction(Opcode.ADD, dt, reg1=reg, reg2=reg, reg3=valueReg)
|
||||
}
|
||||
}
|
||||
return code
|
||||
@@ -194,17 +192,17 @@ class CodeGen(internal val program: PtProgram,
|
||||
val pow2 = powersOfTwo.indexOf(factor.toInt())
|
||||
if(pow2>=1) {
|
||||
// just shift bits
|
||||
code += VmCodeInstruction(Instruction(Opcode.LSL, dt, reg1=reg, reg2=reg, reg3=pow2))
|
||||
code += VmCodeInstruction(Opcode.LSL, dt, reg1=reg, reg2=reg, reg3=pow2)
|
||||
} else {
|
||||
when(factor) {
|
||||
0u -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOAD, dt, reg1=reg, value=0))
|
||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0)
|
||||
}
|
||||
1u -> { /* do nothing */ }
|
||||
else -> {
|
||||
val factorReg = vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOAD, dt, reg1=factorReg, value=factor.toInt()))
|
||||
code += VmCodeInstruction(Instruction(Opcode.MUL, dt, reg1=reg, reg2=reg, reg3=factorReg))
|
||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value=factor.toInt())
|
||||
code += VmCodeInstruction(Opcode.MUL, dt, reg1=reg, reg2=reg, reg3=factorReg)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -236,16 +234,16 @@ class CodeGen(internal val program: PtProgram,
|
||||
// if and else parts
|
||||
val elseLabel = createLabelName()
|
||||
val afterIfLabel = createLabelName()
|
||||
code += VmCodeInstruction(Instruction(branch, vmDt, reg1=conditionReg, symbol = elseLabel))
|
||||
code += VmCodeInstruction(branch, vmDt, reg1=conditionReg, symbol = elseLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += VmCodeInstruction(Instruction(Opcode.JUMP, symbol = afterIfLabel))
|
||||
code += VmCodeInstruction(Opcode.JUMP, symbol = afterIfLabel)
|
||||
code += VmCodeLabel(elseLabel)
|
||||
code += translateNode(ifElse.elseScope)
|
||||
code += VmCodeLabel(afterIfLabel)
|
||||
} else {
|
||||
// only if part
|
||||
val afterIfLabel = createLabelName()
|
||||
code += VmCodeInstruction(Instruction(branch, vmDt, reg1=conditionReg, symbol = afterIfLabel))
|
||||
code += VmCodeInstruction(branch, vmDt, reg1=conditionReg, symbol = afterIfLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += VmCodeLabel(afterIfLabel)
|
||||
}
|
||||
@@ -266,15 +264,15 @@ class CodeGen(internal val program: PtProgram,
|
||||
val resultReg = vmRegisters.nextFree()
|
||||
if(ident!=null) {
|
||||
val address = allocations.get(ident.targetName)
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOADM, vmDt, reg1=resultReg, value = address))
|
||||
code += VmCodeInstruction(Instruction(operation, vmDt, reg1=resultReg))
|
||||
code += VmCodeInstruction(Instruction(Opcode.STOREM, vmDt, reg1=resultReg, value = address))
|
||||
code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1=resultReg, value = address)
|
||||
code += VmCodeInstruction(operation, vmDt, reg1=resultReg)
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultReg, value = address)
|
||||
} else if(memory!=null) {
|
||||
val addressReg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg)
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOADI, vmDt, reg1=resultReg, reg2=addressReg))
|
||||
code += VmCodeInstruction(Instruction(operation, vmDt, reg1=resultReg))
|
||||
code += VmCodeInstruction(Instruction(Opcode.STOREI, vmDt, reg1=resultReg, reg2=addressReg))
|
||||
code += VmCodeInstruction(Opcode.LOADI, vmDt, reg1=resultReg, reg2=addressReg)
|
||||
code += VmCodeInstruction(operation, vmDt, reg1=resultReg)
|
||||
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultReg, reg2=addressReg)
|
||||
} else if (array!=null) {
|
||||
TODO("postincrdecr array")
|
||||
} else
|
||||
@@ -300,8 +298,8 @@ class CodeGen(internal val program: PtProgram,
|
||||
val repeatLabel = createLabelName()
|
||||
code += VmCodeLabel(repeatLabel)
|
||||
code += translateNode(repeat.statements)
|
||||
code += VmCodeInstruction(Instruction(Opcode.DEC, vmDt, reg1=counterReg))
|
||||
code += VmCodeInstruction(Instruction(Opcode.BNZ, vmDt, reg1=counterReg, symbol = repeatLabel))
|
||||
code += VmCodeInstruction(Opcode.DEC, vmDt, reg1=counterReg)
|
||||
code += VmCodeInstruction(Opcode.BNZ, vmDt, reg1=counterReg, symbol = repeatLabel)
|
||||
return code
|
||||
}
|
||||
|
||||
@@ -310,9 +308,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, symbol = listOf(jump.generatedLabel!!)))
|
||||
VmCodeInstruction(Opcode.JUMP, symbol = listOf(jump.generatedLabel!!))
|
||||
else if(jump.identifier!=null)
|
||||
VmCodeInstruction(Instruction(Opcode.JUMP, symbol = jump.identifier!!.targetName))
|
||||
VmCodeInstruction(Opcode.JUMP, symbol = jump.identifier!!.targetName)
|
||||
else
|
||||
throw AssemblyError("weird jump")
|
||||
return code
|
||||
@@ -336,8 +334,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
val vmDt = vmType(assignment.value.type)
|
||||
if(ident!=null) {
|
||||
val address = allocations.get(ident.targetName)
|
||||
val ins = Instruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=address)
|
||||
code += VmCodeInstruction(ins)
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=address)
|
||||
}
|
||||
else if(array!=null) {
|
||||
val variable = array.variable.targetName
|
||||
@@ -347,23 +344,21 @@ class CodeGen(internal val program: PtProgram,
|
||||
val vmDtArrayIdx = vmType(array.type)
|
||||
if(fixedIndex!=null) {
|
||||
variableAddr += fixedIndex*itemsize
|
||||
code += VmCodeInstruction(Instruction(Opcode.STOREM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr))
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr)
|
||||
} else {
|
||||
val indexReg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(array.index, indexReg)
|
||||
code += VmCodeInstruction(Instruction(Opcode.STOREX, vmDtArrayIdx, reg1 = resultRegister, reg2=indexReg, value=variableAddr))
|
||||
code += VmCodeInstruction(Opcode.STOREX, vmDtArrayIdx, reg1 = resultRegister, reg2=indexReg, value=variableAddr)
|
||||
}
|
||||
}
|
||||
else if(memory!=null) {
|
||||
val ins =
|
||||
if(memory.address is PtNumber) {
|
||||
Instruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
|
||||
} else {
|
||||
val addressRegister = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(assignment.value, addressRegister)
|
||||
Instruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressRegister)
|
||||
}
|
||||
code += VmCodeInstruction(ins)
|
||||
if(memory.address is PtNumber) {
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
|
||||
} else {
|
||||
val addressRegister = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(assignment.value, addressRegister)
|
||||
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressRegister)
|
||||
}
|
||||
}
|
||||
else
|
||||
throw AssemblyError("weird assigntarget")
|
||||
@@ -377,7 +372,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
// Call Convention: return value is always returned in r0
|
||||
code += expressionEval.translateExpression(value, 0)
|
||||
}
|
||||
code += VmCodeInstruction(Instruction(Opcode.RETURN))
|
||||
code += VmCodeInstruction(Opcode.RETURN)
|
||||
return code
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ 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.VmDataType
|
||||
|
||||
@@ -21,20 +20,20 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
|
||||
when (expr) {
|
||||
is PtNumber -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt()))
|
||||
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt())
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
val mem = codeGen.allocations.get(expr.targetName)
|
||||
code += if(expr.type in PassByValueDatatypes) {
|
||||
VmCodeInstruction(Instruction(Opcode.LOADM, vmDt, reg1=resultRegister, value=mem))
|
||||
VmCodeInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, value=mem)
|
||||
} else {
|
||||
// for strings and arrays etc., load the *address* of the value instead
|
||||
VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem))
|
||||
VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem)
|
||||
}
|
||||
}
|
||||
is PtAddressOf -> {
|
||||
val mem = codeGen.allocations.get(expr.identifier.targetName)
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem))
|
||||
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem)
|
||||
}
|
||||
is PtMemoryByte -> {
|
||||
val addressRegister = codeGen.vmRegisters.nextFree()
|
||||
@@ -100,11 +99,11 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
code += translateExpression(arrayIx.index, idxReg)
|
||||
if(eltSize>1) {
|
||||
val factorReg = codeGen.vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.BYTE, reg1=factorReg, value=eltSize))
|
||||
code += VmCodeInstruction(Instruction(Opcode.MUL, VmDataType.BYTE, reg1=idxReg, reg2=factorReg))
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=factorReg, value=eltSize)
|
||||
code += VmCodeInstruction(Opcode.MUL, VmDataType.BYTE, reg1=idxReg, reg2=factorReg)
|
||||
}
|
||||
val arrayLocation = codeGen.allocations.get(arrayIx.variable.targetName)
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, value = arrayLocation))
|
||||
code += VmCodeInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, value = arrayLocation)
|
||||
return code
|
||||
}
|
||||
|
||||
@@ -115,22 +114,22 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
when(expr.operator) {
|
||||
"+" -> { }
|
||||
"-" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.NEG, vmDt, reg1=resultRegister))
|
||||
code += VmCodeInstruction(Opcode.NEG, vmDt, reg1=resultRegister)
|
||||
}
|
||||
"~" -> {
|
||||
val regMask = codeGen.vmRegisters.nextFree()
|
||||
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=regMask, value=mask))
|
||||
code += VmCodeInstruction(Instruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask))
|
||||
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=regMask, value=mask)
|
||||
code += VmCodeInstruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask)
|
||||
}
|
||||
"not" -> {
|
||||
val label = codeGen.createLabelName()
|
||||
code += VmCodeInstruction(Instruction(Opcode.BZ, vmDt, reg1=resultRegister, symbol = label))
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=1))
|
||||
code += VmCodeInstruction(Opcode.BZ, vmDt, reg1=resultRegister, symbol = label)
|
||||
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=1)
|
||||
code += VmCodeLabel(label)
|
||||
val regMask = codeGen.vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=regMask, value=1))
|
||||
code += VmCodeInstruction(Instruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask))
|
||||
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=regMask, value=1)
|
||||
code += VmCodeInstruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask)
|
||||
}
|
||||
else -> throw AssemblyError("weird prefix operator")
|
||||
}
|
||||
@@ -165,11 +164,11 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
when(cast.value.type) {
|
||||
DataType.BYTE -> {
|
||||
// byte -> uword: sign extend
|
||||
code += VmCodeInstruction(Instruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = resultRegister))
|
||||
code += VmCodeInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = resultRegister)
|
||||
}
|
||||
DataType.UBYTE -> {
|
||||
// ubyte -> uword: sign extend
|
||||
code += VmCodeInstruction(Instruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = resultRegister))
|
||||
code += VmCodeInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = resultRegister)
|
||||
}
|
||||
DataType.WORD -> { }
|
||||
DataType.FLOAT -> {
|
||||
@@ -182,11 +181,11 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
when(cast.value.type) {
|
||||
DataType.BYTE -> {
|
||||
// byte -> word: sign extend
|
||||
code += VmCodeInstruction(Instruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = resultRegister))
|
||||
code += VmCodeInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = resultRegister)
|
||||
}
|
||||
DataType.UBYTE -> {
|
||||
// byte -> word: sign extend
|
||||
code += VmCodeInstruction(Instruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = resultRegister))
|
||||
code += VmCodeInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = resultRegister)
|
||||
}
|
||||
DataType.UWORD -> { }
|
||||
DataType.FLOAT -> {
|
||||
@@ -228,57 +227,57 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val signed = binExpr.left.type in SignedDatatypes
|
||||
when(binExpr.operator) {
|
||||
"+" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.ADD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(Opcode.ADD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
"-" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.SUB, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(Opcode.SUB, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
"*" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.MUL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(Opcode.MUL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
"/" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.DIV, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(Opcode.DIV, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
"%" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.MOD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(Opcode.MOD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
"|", "or" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.OR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(Opcode.OR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
"&", "and" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.AND, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(Opcode.AND, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
"^", "xor" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
"<<" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.LSL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(Opcode.LSL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
">>" -> {
|
||||
val opc = if(signed) Opcode.ASR else Opcode.LSR
|
||||
code += VmCodeInstruction(Instruction(opc, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(opc, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
"==" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.SEQ, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(Opcode.SEQ, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
"!=" -> {
|
||||
code += VmCodeInstruction(Instruction(Opcode.SNE, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(Opcode.SNE, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
"<" -> {
|
||||
val ins = if(signed) Opcode.SLTS else Opcode.SLT
|
||||
code += VmCodeInstruction(Instruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
">" -> {
|
||||
val ins = if(signed) Opcode.SGTS else Opcode.SGT
|
||||
code += VmCodeInstruction(Instruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
"<=" -> {
|
||||
val ins = if(signed) Opcode.SLES else Opcode.SLE
|
||||
code += VmCodeInstruction(Instruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
">=" -> {
|
||||
val ins = if(signed) Opcode.SGES else Opcode.SGE
|
||||
code += VmCodeInstruction(Instruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
|
||||
code += VmCodeInstruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
else -> throw AssemblyError("weird operator ${binExpr.operator}")
|
||||
}
|
||||
@@ -293,12 +292,12 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
code += translateExpression(arg, argReg)
|
||||
val vmDt = codeGen.vmType(parameter.type)
|
||||
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
|
||||
code += VmCodeInstruction(Instruction(Opcode.STOREM, vmDt, reg1=argReg, value=mem))
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=argReg, value=mem)
|
||||
}
|
||||
code += VmCodeInstruction(Instruction(Opcode.CALL, symbol=fcall.functionName))
|
||||
code += VmCodeInstruction(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))
|
||||
code += VmCodeInstruction(Opcode.LOADR, codeGen.vmType(fcall.type), reg1=resultRegister, reg2=0)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user