mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
vm: actually use the store-zero instructions in codegen
This commit is contained in:
parent
627aa61184
commit
d43ad849d1
@ -2,7 +2,6 @@ package prog8.codegen.virtual
|
|||||||
|
|
||||||
import prog8.code.StStaticVariable
|
import prog8.code.StStaticVariable
|
||||||
import prog8.code.ast.*
|
import prog8.code.ast.*
|
||||||
import prog8.code.core.ArrayToElementTypes
|
|
||||||
import prog8.code.core.AssemblyError
|
import prog8.code.core.AssemblyError
|
||||||
import prog8.code.core.DataType
|
import prog8.code.core.DataType
|
||||||
import prog8.vm.Opcode
|
import prog8.vm.Opcode
|
||||||
@ -241,32 +240,54 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
|||||||
|
|
||||||
private fun funcPokeW(call: PtBuiltinFunctionCall): VmCodeChunk {
|
private fun funcPokeW(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||||
val code = VmCodeChunk()
|
val code = VmCodeChunk()
|
||||||
val valueReg = codeGen.vmRegisters.nextFree()
|
if(codeGen.isZero(call.args[1])) {
|
||||||
if(call.args[0] is PtNumber) {
|
if (call.args[0] is PtNumber) {
|
||||||
val address = (call.args[0] as PtNumber).number.toInt()
|
val address = (call.args[0] as PtNumber).number.toInt()
|
||||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
code += VmCodeInstruction(Opcode.STOREZM, VmDataType.WORD, value = address)
|
||||||
code += VmCodeInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value=address)
|
} else {
|
||||||
|
val addressReg = codeGen.vmRegisters.nextFree()
|
||||||
|
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREZI, VmDataType.WORD, reg2 = addressReg)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
val addressReg = codeGen.vmRegisters.nextFree()
|
val valueReg = codeGen.vmRegisters.nextFree()
|
||||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
if (call.args[0] is PtNumber) {
|
||||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
val address = (call.args[0] as PtNumber).number.toInt()
|
||||||
code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2 = addressReg)
|
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value = address)
|
||||||
|
} else {
|
||||||
|
val addressReg = codeGen.vmRegisters.nextFree()
|
||||||
|
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||||
|
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2 = addressReg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcPoke(call: PtBuiltinFunctionCall): VmCodeChunk {
|
private fun funcPoke(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||||
val code = VmCodeChunk()
|
val code = VmCodeChunk()
|
||||||
val valueReg = codeGen.vmRegisters.nextFree()
|
if(codeGen.isZero(call.args[1])) {
|
||||||
if(call.args[0] is PtNumber) {
|
if (call.args[0] is PtNumber) {
|
||||||
val address = (call.args[0] as PtNumber).number.toInt()
|
val address = (call.args[0] as PtNumber).number.toInt()
|
||||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
code += VmCodeInstruction(Opcode.STOREZM, VmDataType.BYTE, value = address)
|
||||||
code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value=address)
|
} else {
|
||||||
|
val addressReg = codeGen.vmRegisters.nextFree()
|
||||||
|
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREZI, VmDataType.BYTE, reg2 = addressReg)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
val addressReg = codeGen.vmRegisters.nextFree()
|
val valueReg = codeGen.vmRegisters.nextFree()
|
||||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
if (call.args[0] is PtNumber) {
|
||||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
val address = (call.args[0] as PtNumber).number.toInt()
|
||||||
code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
|
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value = address)
|
||||||
|
} else {
|
||||||
|
val addressReg = codeGen.vmRegisters.nextFree()
|
||||||
|
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||||
|
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -361,5 +382,4 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
|||||||
code += codeGen.translateNode(assignment)
|
code += codeGen.translateNode(assignment)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import prog8.code.ast.*
|
|||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
import prog8.vm.Opcode
|
import prog8.vm.Opcode
|
||||||
import prog8.vm.VmDataType
|
import prog8.vm.VmDataType
|
||||||
import java.nio.file.Path
|
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
|
||||||
@ -410,7 +409,7 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
// just shift multiple bits
|
// just shift multiple bits
|
||||||
val pow2reg = vmRegisters.nextFree()
|
val pow2reg = vmRegisters.nextFree()
|
||||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
||||||
code += VmCodeInstruction(Opcode.LSLX, dt, reg1=reg, reg2=reg, reg3=pow2reg)
|
code += VmCodeInstruction(Opcode.LSLN, dt, reg1=reg, reg2=reg, reg3=pow2reg)
|
||||||
} else {
|
} else {
|
||||||
if (factor == 0) {
|
if (factor == 0) {
|
||||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0)
|
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0)
|
||||||
@ -451,7 +450,7 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
// just shift multiple bits
|
// just shift multiple bits
|
||||||
val pow2reg = vmRegisters.nextFree()
|
val pow2reg = vmRegisters.nextFree()
|
||||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
||||||
code += VmCodeInstruction(Opcode.LSRX, dt, reg1=reg, reg2=reg, reg3=pow2reg)
|
code += VmCodeInstruction(Opcode.LSRN, dt, reg1=reg, reg2=reg, reg3=pow2reg)
|
||||||
} else {
|
} else {
|
||||||
if (factor == 0) {
|
if (factor == 0) {
|
||||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
|
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
|
||||||
@ -615,24 +614,32 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
val vmDt = vmType(assignment.value.type)
|
val vmDt = vmType(assignment.value.type)
|
||||||
var resultRegister = -1
|
var resultRegister = -1
|
||||||
var resultFpRegister = -1
|
var resultFpRegister = -1
|
||||||
if(vmDt==VmDataType.FLOAT) {
|
val zero = isZero(assignment.value)
|
||||||
resultFpRegister = vmRegisters.nextFreeFloat()
|
if(!zero) {
|
||||||
code += expressionEval.translateExpression(assignment.value, -1, resultFpRegister)
|
// calculate the assignment value
|
||||||
} else {
|
if (vmDt == VmDataType.FLOAT) {
|
||||||
resultRegister = if (assignment.value is PtMachineRegister) {
|
resultFpRegister = vmRegisters.nextFreeFloat()
|
||||||
(assignment.value as PtMachineRegister).register
|
code += expressionEval.translateExpression(assignment.value, -1, resultFpRegister)
|
||||||
} else {
|
} else {
|
||||||
val reg = vmRegisters.nextFree()
|
resultRegister = if (assignment.value is PtMachineRegister) {
|
||||||
code += expressionEval.translateExpression(assignment.value, reg, -1)
|
(assignment.value as PtMachineRegister).register
|
||||||
reg
|
} else {
|
||||||
|
val reg = vmRegisters.nextFree()
|
||||||
|
code += expressionEval.translateExpression(assignment.value, reg, -1)
|
||||||
|
reg
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(ident!=null) {
|
if(ident!=null) {
|
||||||
val address = allocations.get(ident.targetName)
|
val address = allocations.get(ident.targetName)
|
||||||
code += if(vmDt==VmDataType.FLOAT)
|
code += if(zero) {
|
||||||
VmCodeInstruction(Opcode.STOREM, vmDt, fpReg1=resultFpRegister, value=address)
|
VmCodeInstruction(Opcode.STOREZM, vmDt, value = address)
|
||||||
else
|
} else {
|
||||||
VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=address)
|
if (vmDt == VmDataType.FLOAT)
|
||||||
|
VmCodeInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, value = address)
|
||||||
|
else
|
||||||
|
VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, value = address)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(array!=null) {
|
else if(array!=null) {
|
||||||
val variable = array.variable.targetName
|
val variable = array.variable.targetName
|
||||||
@ -640,23 +647,45 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
val itemsize = program.memsizer.memorySize(array.type)
|
val itemsize = program.memsizer.memorySize(array.type)
|
||||||
val fixedIndex = constIntValue(array.index)
|
val fixedIndex = constIntValue(array.index)
|
||||||
val vmDtArrayIdx = vmType(array.type)
|
val vmDtArrayIdx = vmType(array.type)
|
||||||
if(fixedIndex!=null) {
|
// TODO floating point array incorrect?
|
||||||
variableAddr += fixedIndex*itemsize
|
if(zero) {
|
||||||
code += VmCodeInstruction(Opcode.STOREM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr)
|
if(fixedIndex!=null) {
|
||||||
|
variableAddr += fixedIndex*itemsize
|
||||||
|
code += VmCodeInstruction(Opcode.STOREZM, vmDtArrayIdx, value=variableAddr)
|
||||||
|
} else {
|
||||||
|
val indexReg = vmRegisters.nextFree()
|
||||||
|
code += expressionEval.translateExpression(array.index, indexReg, -1)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREZX, vmDtArrayIdx, reg1=indexReg, value=variableAddr)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
val indexReg = vmRegisters.nextFree()
|
if(fixedIndex!=null) {
|
||||||
code += expressionEval.translateExpression(array.index, indexReg, -1)
|
variableAddr += fixedIndex*itemsize
|
||||||
code += VmCodeInstruction(Opcode.STOREX, vmDtArrayIdx, reg1 = resultRegister, reg2=indexReg, value=variableAddr)
|
code += VmCodeInstruction(Opcode.STOREM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr)
|
||||||
|
} else {
|
||||||
|
val indexReg = vmRegisters.nextFree()
|
||||||
|
code += expressionEval.translateExpression(array.index, indexReg, -1)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREX, vmDtArrayIdx, reg1 = resultRegister, reg2=indexReg, value=variableAddr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(memory!=null) {
|
else if(memory!=null) {
|
||||||
require(vmDt==VmDataType.BYTE)
|
require(vmDt==VmDataType.BYTE)
|
||||||
if(memory.address is PtNumber) {
|
if(zero) {
|
||||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
|
if(memory.address is PtNumber) {
|
||||||
|
code += VmCodeInstruction(Opcode.STOREZM, vmDt, value=(memory.address as PtNumber).number.toInt())
|
||||||
|
} else {
|
||||||
|
val addressReg = vmRegisters.nextFree()
|
||||||
|
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREZI, vmDt, reg1=addressReg)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
val addressReg = vmRegisters.nextFree()
|
if(memory.address is PtNumber) {
|
||||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
|
||||||
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
|
} else {
|
||||||
|
val addressReg = vmRegisters.nextFree()
|
||||||
|
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -722,4 +751,6 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
|
|
||||||
internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk =
|
internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk =
|
||||||
builtinFuncGen.translate(call, resultRegister)
|
builtinFuncGen.translate(call, resultRegister)
|
||||||
|
|
||||||
|
internal fun isZero(expression: PtExpression): Boolean = expression is PtNumber && expression.number==0.0
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import prog8.code.core.PassByValueDatatypes
|
|||||||
import prog8.code.core.SignedDatatypes
|
import prog8.code.core.SignedDatatypes
|
||||||
import prog8.vm.Opcode
|
import prog8.vm.Opcode
|
||||||
import prog8.vm.VmDataType
|
import prog8.vm.VmDataType
|
||||||
import java.nio.channels.FileLock
|
|
||||||
|
|
||||||
|
|
||||||
internal class ExpressionGen(private val codeGen: CodeGen) {
|
internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||||
@ -174,6 +173,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
|||||||
|
|
||||||
private fun translate(expr: PtPrefix, resultRegister: Int): VmCodeChunk {
|
private fun translate(expr: PtPrefix, resultRegister: Int): VmCodeChunk {
|
||||||
val code = VmCodeChunk()
|
val code = VmCodeChunk()
|
||||||
|
// TODO if the value is a variable or memory read, use memory-versions of the opcodes instead of using intermediary register
|
||||||
code += translateExpression(expr.value, resultRegister, -1)
|
code += translateExpression(expr.value, resultRegister, -1)
|
||||||
val vmDt = codeGen.vmType(expr.type)
|
val vmDt = codeGen.vmType(expr.type)
|
||||||
when(expr.operator) {
|
when(expr.operator) {
|
||||||
@ -363,22 +363,24 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
|||||||
|
|
||||||
private fun operatorShiftRight(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, signed: Boolean): VmCodeChunk {
|
private fun operatorShiftRight(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, signed: Boolean): VmCodeChunk {
|
||||||
val code = VmCodeChunk()
|
val code = VmCodeChunk()
|
||||||
|
// TODO if shift is 1, use ASR/LSR instruction instead of multishift
|
||||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(binExpr.left, leftResultReg, -1)
|
code += translateExpression(binExpr.left, leftResultReg, -1)
|
||||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||||
val opc = if(signed) Opcode.ASRX else Opcode.LSRX
|
val opc = if(signed) Opcode.ASRN else Opcode.LSRN
|
||||||
code += VmCodeInstruction(opc, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
code += VmCodeInstruction(opc, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun operatorShiftLeft(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
|
private fun operatorShiftLeft(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
|
||||||
val code = VmCodeChunk()
|
val code = VmCodeChunk()
|
||||||
|
// TODO if shift is 1, use LSL instruction instead of multishift
|
||||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(binExpr.left, leftResultReg, -1)
|
code += translateExpression(binExpr.left, leftResultReg, -1)
|
||||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||||
code += VmCodeInstruction(Opcode.LSLX, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
code += VmCodeInstruction(Opcode.LSLN, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,16 +570,26 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
|||||||
val code = VmCodeChunk()
|
val code = VmCodeChunk()
|
||||||
for ((arg, parameter) in fcall.args.zip(subroutine.parameters)) {
|
for ((arg, parameter) in fcall.args.zip(subroutine.parameters)) {
|
||||||
val paramDt = codeGen.vmType(parameter.type)
|
val paramDt = codeGen.vmType(parameter.type)
|
||||||
if(paramDt==VmDataType.FLOAT) {
|
if(codeGen.isZero(arg)) {
|
||||||
val argFpReg = codeGen.vmRegisters.nextFreeFloat()
|
if (paramDt == VmDataType.FLOAT) {
|
||||||
code += translateExpression(arg, -1, argFpReg)
|
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
|
||||||
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
|
code += VmCodeInstruction(Opcode.STOREZM, paramDt, value = mem)
|
||||||
code += VmCodeInstruction(Opcode.STOREM, paramDt, fpReg1 = argFpReg, value = mem)
|
} else {
|
||||||
|
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREZM, paramDt, value = mem)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
val argReg = codeGen.vmRegisters.nextFree()
|
if (paramDt == VmDataType.FLOAT) {
|
||||||
code += translateExpression(arg, argReg, -1)
|
val argFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||||
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
|
code += translateExpression(arg, -1, argFpReg)
|
||||||
code += VmCodeInstruction(Opcode.STOREM, paramDt, reg1 = argReg, value = mem)
|
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREM, paramDt, fpReg1 = argFpReg, value = mem)
|
||||||
|
} else {
|
||||||
|
val argReg = codeGen.vmRegisters.nextFree()
|
||||||
|
code += translateExpression(arg, argReg, -1)
|
||||||
|
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREM, paramDt, reg1 = argReg, value = mem)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
code += VmCodeInstruction(Opcode.CALL, symbol=fcall.functionName)
|
code += VmCodeInstruction(Opcode.CALL, symbol=fcall.functionName)
|
||||||
|
@ -3,7 +3,11 @@ TODO
|
|||||||
|
|
||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- vm: add way more instructions operating directly on memory instead of only registers
|
- vm: assignment to float array is not correct? also zero?
|
||||||
|
- vm: use more instructions in codegen: shift one
|
||||||
|
- vm: use more instructions in codegen: branching
|
||||||
|
- vm: add more instructions operating directly on memory instead of only registers?
|
||||||
|
- in-place modifiying functions (rol, ror, ..) don't accept a memory address but require a memory-read expression. that is weird.
|
||||||
- complete the Inliner
|
- complete the Inliner
|
||||||
- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value?
|
- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value?
|
||||||
|
|
||||||
|
@ -6,21 +6,57 @@
|
|||||||
; NOTE: meant to test to virtual machine output target (use -target vitual)
|
; NOTE: meant to test to virtual machine output target (use -target vitual)
|
||||||
|
|
||||||
main {
|
main {
|
||||||
ubyte value = 42
|
; ubyte value = 42
|
||||||
|
;
|
||||||
|
; sub inline_candidate() -> ubyte {
|
||||||
|
; return math.sin8u(value)
|
||||||
|
; }
|
||||||
|
;
|
||||||
|
; sub add(ubyte first, ubyte second) -> ubyte {
|
||||||
|
; return first + second
|
||||||
|
; }
|
||||||
|
;
|
||||||
|
; sub mul(ubyte first, ubyte second) -> ubyte {
|
||||||
|
; return first * second
|
||||||
|
; }
|
||||||
|
|
||||||
sub derp() -> ubyte {
|
sub ding(uword arg) {
|
||||||
return math.sin8u(value)
|
arg++
|
||||||
|
txt.print_uw(arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
ubyte value = derp()
|
ding(0)
|
||||||
txt.print_ub(value)
|
|
||||||
txt.nl()
|
txt.nl()
|
||||||
txt.print_ub(derp())
|
ding(2)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
; TODO: test with builtin function using multiple args (such as mkword)
|
; ubyte value = inline_candidate()
|
||||||
; ubyte value = add(3,4) |> add(10) |> mul(2) |> math.sin8u() ; TODO should not work yet on vm codegen, but it compiles.... :/
|
; byte svalue = 99
|
||||||
|
; svalue = -svalue
|
||||||
|
; @($5000) = not @($5000)
|
||||||
|
; rol(value)
|
||||||
|
; rol(@($5000))
|
||||||
|
; ror(value)
|
||||||
|
; ror(@($5000))
|
||||||
|
; rol2(value)
|
||||||
|
; rol2(@($5000))
|
||||||
|
; ror2(value)
|
||||||
|
; ror2(@($5000))
|
||||||
|
; @($5000) <<= 1
|
||||||
|
; @($5000) >>= 1
|
||||||
|
; value <<= 1
|
||||||
|
; value >>= 1
|
||||||
|
; @($5000) <<= 3
|
||||||
|
; @($5000) >>= 3
|
||||||
|
; value <<= 3
|
||||||
|
; value >>= 3
|
||||||
|
; txt.print_ub(value)
|
||||||
|
; txt.nl()
|
||||||
|
; txt.print_ub(inline_candidate())
|
||||||
|
; txt.nl()
|
||||||
|
|
||||||
|
; ubyte value = add(3,4) |> add(10) |> mul(2) |> math.sin8u()
|
||||||
; txt.print_ub(value)
|
; txt.print_ub(value)
|
||||||
; txt.nl()
|
; txt.nl()
|
||||||
; uword wvalue = add(3,4) |> add($30) |> mkword($ea)
|
; uword wvalue = add(3,4) |> add($30) |> mkword($ea)
|
||||||
|
@ -31,7 +31,7 @@ loadr reg1, reg2 - load reg1 with value at register reg2
|
|||||||
storem reg1, address - store reg1 at memory address
|
storem reg1, address - store reg1 at memory address
|
||||||
storei reg1, reg2 - store reg1 at memory indirect, memory pointed to by reg2
|
storei reg1, reg2 - store reg1 at memory indirect, memory pointed to by reg2
|
||||||
storex reg1, reg2, address - store reg1 at memory address, indexed by value in reg2
|
storex reg1, reg2, address - store reg1 at memory address, indexed by value in reg2
|
||||||
storez address - store zero at memory address
|
storezm address - store zero at memory address
|
||||||
storezi reg1 - store zero at memory pointed to by reg1
|
storezi reg1 - store zero at memory pointed to by reg1
|
||||||
storezx reg1, address - store zero at memory address, indexed by value in reg
|
storezx reg1, address - store zero at memory address, indexed by value in reg
|
||||||
|
|
||||||
@ -89,8 +89,8 @@ ARITHMETIC
|
|||||||
----------
|
----------
|
||||||
All have type b or w or f. Note: result types are the same as operand types! E.g. byte*byte->byte.
|
All have type b or w or f. Note: result types are the same as operand types! E.g. byte*byte->byte.
|
||||||
|
|
||||||
ext reg1 - reg1 = unsigned extension of reg1 (which in practice just means clearing the MSB / MSW) (latter not yet implemented as we don't have longs yet)
|
ext reg1 - reg1 = unsigned extension of reg1 (which in practice just means clearing the MSB / MSW) (ext.w not yet implemented as we don't have longs yet)
|
||||||
exts reg1 - reg1 = signed extension of reg1 (byte to word, or word to long) (note: latter ext.w, not yet implemented as we don't have longs yet)
|
exts reg1 - reg1 = signed extension of reg1 (byte to word, or word to long) (note: ext.w is not yet implemented as we don't have longs yet)
|
||||||
inc reg1 - reg1 = reg1+1
|
inc reg1 - reg1 = reg1+1
|
||||||
incm address - memory at address += 1
|
incm address - memory at address += 1
|
||||||
dec reg1 - reg1 = reg1-1
|
dec reg1 - reg1 = reg1-1
|
||||||
@ -116,9 +116,9 @@ All have type b or w.
|
|||||||
and reg1, reg2, reg3 - reg1 = reg2 bitwise and reg3
|
and reg1, reg2, reg3 - reg1 = reg2 bitwise and reg3
|
||||||
or reg1, reg2, reg3 - reg1 = reg2 bitwise or reg3
|
or reg1, reg2, reg3 - reg1 = reg2 bitwise or reg3
|
||||||
xor reg1, reg2, reg3 - reg1 = reg2 bitwise xor reg3
|
xor reg1, reg2, reg3 - reg1 = reg2 bitwise xor reg3
|
||||||
lsrx reg1, reg2, reg3 - reg1 = multi-shift reg2 right by reg3 bits + set Carry to shifted bit
|
lsrn reg1, reg2, reg3 - reg1 = multi-shift reg2 right by reg3 bits + set Carry to shifted bit
|
||||||
asrx reg1, reg2, reg3 - reg1 = multi-shift reg2 right by reg3 bits (signed) + set Carry to shifted bit
|
asrn reg1, reg2, reg3 - reg1 = multi-shift reg2 right by reg3 bits (signed) + set Carry to shifted bit
|
||||||
lslx reg1, reg2, reg3 - reg1 = multi-shift reg2 left by reg3 bits + set Carry to shifted bit
|
lsln reg1, reg2, reg3 - reg1 = multi-shift reg2 left by reg3 bits + set Carry to shifted bit
|
||||||
lsr reg1 - shift reg1 right by 1 bits + set Carry to shifted bit
|
lsr reg1 - shift reg1 right by 1 bits + set Carry to shifted bit
|
||||||
asr reg1 - shift reg1 right by 1 bits (signed) + set Carry to shifted bit
|
asr reg1 - shift reg1 right by 1 bits (signed) + set Carry to shifted bit
|
||||||
lsl reg1 - shift reg1 left by 1 bits + set Carry to shifted bit
|
lsl reg1 - shift reg1 left by 1 bits + set Carry to shifted bit
|
||||||
@ -149,10 +149,7 @@ clc - clear Carry status bit
|
|||||||
sec - set Carry status bit
|
sec - set Carry status bit
|
||||||
nop - do nothing
|
nop - do nothing
|
||||||
breakpoint - trigger a breakpoint
|
breakpoint - trigger a breakpoint
|
||||||
copy reg1, reg2, length - copy memory from ptrs in reg1 to reg3, length bytes
|
|
||||||
copyz reg1, reg2 - copy memory from ptrs in reg1 to reg3, stop after first 0-byte
|
|
||||||
msig [b, w] reg1, reg2 - reg1 becomes the most significant byte (or word) of the word (or int) in reg2 (.w not yet implemented; requires 32 bits regs)
|
msig [b, w] reg1, reg2 - reg1 becomes the most significant byte (or word) of the word (or int) in reg2 (.w not yet implemented; requires 32 bits regs)
|
||||||
swapreg reg1, reg2 - swap values in reg1 and reg2
|
|
||||||
concat [b, w] reg1, reg2, reg3 - reg1 = concatenated lsb/lsw of reg2 and lsb/lsw of reg3 into new word or int (int not yet implemented; requires 32bits regs)
|
concat [b, w] reg1, reg2, reg3 - reg1 = concatenated lsb/lsw of reg2 and lsb/lsw of reg3 into new word or int (int not yet implemented; requires 32bits regs)
|
||||||
push [b, w] reg1 - push value in reg1 on the stack
|
push [b, w] reg1 - push value in reg1 on the stack
|
||||||
pop [b, w] reg1 - pop value from stack into reg1
|
pop [b, w] reg1 - pop value from stack into reg1
|
||||||
@ -169,14 +166,12 @@ enum class Opcode {
|
|||||||
STOREM,
|
STOREM,
|
||||||
STOREI,
|
STOREI,
|
||||||
STOREX,
|
STOREX,
|
||||||
STOREZ,
|
STOREZM,
|
||||||
STOREZI,
|
STOREZI,
|
||||||
STOREZX,
|
STOREZX,
|
||||||
|
|
||||||
JUMP,
|
JUMP,
|
||||||
JUMPI,
|
|
||||||
CALL,
|
CALL,
|
||||||
CALLI,
|
|
||||||
SYSCALL,
|
SYSCALL,
|
||||||
RETURN,
|
RETURN,
|
||||||
|
|
||||||
@ -190,14 +185,14 @@ enum class Opcode {
|
|||||||
BNZ,
|
BNZ,
|
||||||
BEQ,
|
BEQ,
|
||||||
BNE,
|
BNE,
|
||||||
BLT,
|
BLT, // TODO not used in codegen??? <
|
||||||
BLTS,
|
BLTS, // TODO not used in codegen??? <
|
||||||
BGT,
|
BGT, // TODO not used in codegen??? >
|
||||||
BGTS,
|
BGTS, // TODO not used in codegen??? >
|
||||||
BLE,
|
BLE, // TODO should be used in codegen conditional branch too
|
||||||
BLES,
|
BLES, // TODO should be used in codegen conditional branch too
|
||||||
BGE,
|
BGE, // TODO not used in codegen??? >=
|
||||||
BGES,
|
BGES, // TODO not used in codegen??? >=
|
||||||
SEQ,
|
SEQ,
|
||||||
SNE,
|
SNE,
|
||||||
SLT,
|
SLT,
|
||||||
@ -229,12 +224,12 @@ enum class Opcode {
|
|||||||
AND,
|
AND,
|
||||||
OR,
|
OR,
|
||||||
XOR,
|
XOR,
|
||||||
ASRX,
|
ASRN,
|
||||||
LSRX,
|
LSRN,
|
||||||
LSLX,
|
LSLN,
|
||||||
ASR,
|
ASR, // TODO not used in codegen of shift 1
|
||||||
LSR,
|
LSR, // TODO not used in codegen of shift 1
|
||||||
LSL,
|
LSL, // TODO not used in codegen of shift 1
|
||||||
ROR,
|
ROR,
|
||||||
ROXR,
|
ROXR,
|
||||||
ROL,
|
ROL,
|
||||||
@ -266,7 +261,6 @@ enum class Opcode {
|
|||||||
PUSH,
|
PUSH,
|
||||||
POP,
|
POP,
|
||||||
MSIG,
|
MSIG,
|
||||||
SWAPREG,
|
|
||||||
CONCAT,
|
CONCAT,
|
||||||
BREAKPOINT
|
BREAKPOINT
|
||||||
}
|
}
|
||||||
@ -276,7 +270,7 @@ val OpcodesWithAddress = setOf(
|
|||||||
Opcode.LOADX,
|
Opcode.LOADX,
|
||||||
Opcode.STOREM,
|
Opcode.STOREM,
|
||||||
Opcode.STOREX,
|
Opcode.STOREX,
|
||||||
Opcode.STOREZ,
|
Opcode.STOREZM,
|
||||||
Opcode.STOREZX
|
Opcode.STOREZX
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -443,17 +437,14 @@ val instructionFormats = mutableMapOf(
|
|||||||
Opcode.LOADI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
|
Opcode.LOADI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
|
||||||
Opcode.LOADX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
|
Opcode.LOADX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
|
||||||
Opcode.LOADR to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
Opcode.LOADR to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
||||||
Opcode.SWAPREG to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
|
||||||
Opcode.STOREM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
|
Opcode.STOREM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
|
||||||
Opcode.STOREI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
|
Opcode.STOREI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
|
||||||
Opcode.STOREX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
|
Opcode.STOREX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
|
||||||
Opcode.STOREZ to InstructionFormat.from("BW,v | F,v"),
|
Opcode.STOREZM to InstructionFormat.from("BW,v | F,v"),
|
||||||
Opcode.STOREZI to InstructionFormat.from("BW,r1 | F,r1"),
|
Opcode.STOREZI to InstructionFormat.from("BW,r1 | F,r1"),
|
||||||
Opcode.STOREZX to InstructionFormat.from("BW,r1,v | F,r1,v"),
|
Opcode.STOREZX to InstructionFormat.from("BW,r1,v | F,r1,v"),
|
||||||
Opcode.JUMP to InstructionFormat.from("N,v"),
|
Opcode.JUMP to InstructionFormat.from("N,v"),
|
||||||
Opcode.JUMPI to InstructionFormat.from("N,r1"),
|
|
||||||
Opcode.CALL to InstructionFormat.from("N,v"),
|
Opcode.CALL to InstructionFormat.from("N,v"),
|
||||||
Opcode.CALLI to InstructionFormat.from("N,r1"),
|
|
||||||
Opcode.SYSCALL to InstructionFormat.from("N,v"),
|
Opcode.SYSCALL to InstructionFormat.from("N,v"),
|
||||||
Opcode.RETURN to InstructionFormat.from("N"),
|
Opcode.RETURN to InstructionFormat.from("N"),
|
||||||
Opcode.BSTCC to InstructionFormat.from("N,v"),
|
Opcode.BSTCC to InstructionFormat.from("N,v"),
|
||||||
@ -503,9 +494,9 @@ val instructionFormats = mutableMapOf(
|
|||||||
Opcode.AND to InstructionFormat.from("BW,r1,r2,r3"),
|
Opcode.AND to InstructionFormat.from("BW,r1,r2,r3"),
|
||||||
Opcode.OR to InstructionFormat.from("BW,r1,r2,r3"),
|
Opcode.OR to InstructionFormat.from("BW,r1,r2,r3"),
|
||||||
Opcode.XOR to InstructionFormat.from("BW,r1,r2,r3"),
|
Opcode.XOR to InstructionFormat.from("BW,r1,r2,r3"),
|
||||||
Opcode.ASRX to InstructionFormat.from("BW,r1,r2,r3"),
|
Opcode.ASRN to InstructionFormat.from("BW,r1,r2,r3"),
|
||||||
Opcode.LSRX to InstructionFormat.from("BW,r1,r2,r3"),
|
Opcode.LSRN to InstructionFormat.from("BW,r1,r2,r3"),
|
||||||
Opcode.LSLX to InstructionFormat.from("BW,r1,r2,r3"),
|
Opcode.LSLN to InstructionFormat.from("BW,r1,r2,r3"),
|
||||||
Opcode.ASR to InstructionFormat.from("BW,r1"),
|
Opcode.ASR to InstructionFormat.from("BW,r1"),
|
||||||
Opcode.LSR to InstructionFormat.from("BW,r1"),
|
Opcode.LSR to InstructionFormat.from("BW,r1"),
|
||||||
Opcode.LSL to InstructionFormat.from("BW,r1"),
|
Opcode.LSL to InstructionFormat.from("BW,r1"),
|
||||||
|
@ -92,17 +92,14 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
Opcode.LOADX -> InsLOADX(ins)
|
Opcode.LOADX -> InsLOADX(ins)
|
||||||
Opcode.LOADI -> InsLOADI(ins)
|
Opcode.LOADI -> InsLOADI(ins)
|
||||||
Opcode.LOADR -> InsLOADR(ins)
|
Opcode.LOADR -> InsLOADR(ins)
|
||||||
Opcode.SWAPREG -> InsSWAPREG(ins)
|
|
||||||
Opcode.STOREM -> InsSTOREM(ins)
|
Opcode.STOREM -> InsSTOREM(ins)
|
||||||
Opcode.STOREX -> InsSTOREX(ins)
|
Opcode.STOREX -> InsSTOREX(ins)
|
||||||
Opcode.STOREI -> InsSTOREI(ins)
|
Opcode.STOREI -> InsSTOREI(ins)
|
||||||
Opcode.STOREZ -> InsSTOREZ(ins)
|
Opcode.STOREZM -> InsSTOREZ(ins)
|
||||||
Opcode.STOREZX -> InsSTOREZX(ins)
|
Opcode.STOREZX -> InsSTOREZX(ins)
|
||||||
Opcode.STOREZI -> InsSTOREZI(ins)
|
Opcode.STOREZI -> InsSTOREZI(ins)
|
||||||
Opcode.JUMP -> InsJUMP(ins)
|
Opcode.JUMP -> InsJUMP(ins)
|
||||||
Opcode.JUMPI -> InsJUMPI(ins)
|
|
||||||
Opcode.CALL -> InsCALL(ins)
|
Opcode.CALL -> InsCALL(ins)
|
||||||
Opcode.CALLI -> InsCALLI(ins)
|
|
||||||
Opcode.SYSCALL -> InsSYSCALL(ins)
|
Opcode.SYSCALL -> InsSYSCALL(ins)
|
||||||
Opcode.RETURN -> InsRETURN()
|
Opcode.RETURN -> InsRETURN()
|
||||||
Opcode.BSTCC -> InsBSTCC(ins)
|
Opcode.BSTCC -> InsBSTCC(ins)
|
||||||
@ -153,9 +150,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
Opcode.AND -> InsAND(ins)
|
Opcode.AND -> InsAND(ins)
|
||||||
Opcode.OR -> InsOR(ins)
|
Opcode.OR -> InsOR(ins)
|
||||||
Opcode.XOR -> InsXOR(ins)
|
Opcode.XOR -> InsXOR(ins)
|
||||||
Opcode.ASRX -> InsASRM(ins)
|
Opcode.ASRN -> InsASRM(ins)
|
||||||
Opcode.LSRX -> InsLSRM(ins)
|
Opcode.LSRN -> InsLSRM(ins)
|
||||||
Opcode.LSLX -> InsLSLM(ins)
|
Opcode.LSLN -> InsLSLM(ins)
|
||||||
Opcode.ASR -> InsASR(ins)
|
Opcode.ASR -> InsASR(ins)
|
||||||
Opcode.LSR -> InsLSR(ins)
|
Opcode.LSR -> InsLSR(ins)
|
||||||
Opcode.LSL -> InsLSL(ins)
|
Opcode.LSL -> InsLSL(ins)
|
||||||
@ -297,27 +294,6 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
pc++
|
pc++
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun InsSWAPREG(i: Instruction) {
|
|
||||||
when(i.type!!) {
|
|
||||||
VmDataType.BYTE -> {
|
|
||||||
val oldR2 = registers.getUB(i.reg2!!)
|
|
||||||
registers.setUB(i.reg2, registers.getUB(i.reg1!!))
|
|
||||||
registers.setUB(i.reg1, oldR2)
|
|
||||||
}
|
|
||||||
VmDataType.WORD -> {
|
|
||||||
val oldR2 = registers.getUW(i.reg2!!)
|
|
||||||
registers.setUW(i.reg2, registers.getUW(i.reg1!!))
|
|
||||||
registers.setUW(i.reg1, oldR2)
|
|
||||||
}
|
|
||||||
VmDataType.FLOAT -> {
|
|
||||||
val oldR2 = registers.getFloat(i.fpReg2!!)
|
|
||||||
registers.setFloat(i.fpReg2, registers.getFloat(i.fpReg1!!))
|
|
||||||
registers.setFloat(i.fpReg1, oldR2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pc++
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun InsSTOREM(i: Instruction) {
|
private fun InsSTOREM(i: Instruction) {
|
||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
VmDataType.BYTE -> memory.setUB(i.value!!, registers.getUB(i.reg1!!))
|
VmDataType.BYTE -> memory.setUB(i.value!!, registers.getUB(i.reg1!!))
|
||||||
@ -351,6 +327,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
VmDataType.WORD -> memory.setUW(i.value!!, 0u)
|
VmDataType.WORD -> memory.setUW(i.value!!, 0u)
|
||||||
VmDataType.FLOAT -> memory.setFloat(i.value!!, 0f)
|
VmDataType.FLOAT -> memory.setFloat(i.value!!, 0f)
|
||||||
}
|
}
|
||||||
|
pc++
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun InsSTOREZI(i: Instruction) {
|
private fun InsSTOREZI(i: Instruction) {
|
||||||
@ -375,20 +352,11 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
pc = i.value!!
|
pc = i.value!!
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun InsJUMPI(i: Instruction) {
|
|
||||||
pc = registers.getUW(i.reg1!!).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun InsCALL(i: Instruction) {
|
private fun InsCALL(i: Instruction) {
|
||||||
callStack.push(pc+1)
|
callStack.push(pc+1)
|
||||||
pc = i.value!!
|
pc = i.value!!
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun InsCALLI(i: Instruction) {
|
|
||||||
callStack.push(pc+1)
|
|
||||||
pc = registers.getUW(i.reg1!!).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun InsRETURN() {
|
private fun InsRETURN() {
|
||||||
if(callStack.isEmpty())
|
if(callStack.isEmpty())
|
||||||
exit()
|
exit()
|
||||||
|
Loading…
Reference in New Issue
Block a user