mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
vm: some preparations for floating point
This commit is contained in:
parent
6471c0c536
commit
625d5b2313
@ -14,7 +14,7 @@ class VirtualMachineDefinition: IMachineDefinition {
|
||||
|
||||
override val FLOAT_MAX_POSITIVE = Float.MAX_VALUE.toDouble()
|
||||
override val FLOAT_MAX_NEGATIVE = -Float.MAX_VALUE.toDouble()
|
||||
override val FLOAT_MEM_SIZE = 4
|
||||
override val FLOAT_MEM_SIZE = 4 // 32-bits floating point
|
||||
override val PROGRAM_LOAD_ADDRESS = 0u // not actually used
|
||||
|
||||
override val ESTACK_LO = 0u // not actually used
|
||||
|
@ -61,10 +61,14 @@ internal class VmCodeInstruction(
|
||||
reg1: Int?=null, // 0-$ffff
|
||||
reg2: Int?=null, // 0-$ffff
|
||||
reg3: Int?=null, // 0-$ffff
|
||||
fpReg1: Int?=null, // 0-$ffff
|
||||
fpReg2: Int?=null, // 0-$ffff
|
||||
fpReg3: Int?=null, // 0-$ffff
|
||||
value: Int?=null, // 0-$ffff
|
||||
fpValue: Float?=null,
|
||||
symbol: List<String>?=null // alternative to value
|
||||
): VmCodeLine() {
|
||||
val ins = Instruction(opcode, type, reg1, reg2, reg3, value, symbol)
|
||||
val ins = Instruction(opcode, type, reg1, reg2, reg3, fpReg1, fpReg2, fpReg3, value, fpValue, symbol)
|
||||
|
||||
init {
|
||||
if(value!=null && opcode !in OpcodesWithAddress) {
|
||||
@ -77,11 +81,12 @@ internal class VmCodeInstruction(
|
||||
if (value < -32768 || value > 65535)
|
||||
throw IllegalArgumentException("value out of range for word: $value")
|
||||
}
|
||||
null -> {}
|
||||
VmDataType.FLOAT, null -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class VmCodeLabel(val name: List<String>): VmCodeLine()
|
||||
internal class VmCodeComment(val comment: String): VmCodeLine()
|
||||
|
||||
|
@ -5,6 +5,7 @@ import prog8.code.ast.*
|
||||
import prog8.code.core.ArrayToElementTypes
|
||||
import prog8.code.core.AssemblyError
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.WordDatatypes
|
||||
import prog8.vm.Opcode
|
||||
import prog8.vm.Syscall
|
||||
import prog8.vm.VmDataType
|
||||
@ -59,8 +60,8 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
val code = VmCodeChunk()
|
||||
val leftRegister = codeGen.vmRegisters.nextFree()
|
||||
val rightRegister = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], leftRegister)
|
||||
code += exprGen.translateExpression(call.args[1], rightRegister)
|
||||
code += exprGen.translateExpression(call.args[0], leftRegister, 99999)
|
||||
code += exprGen.translateExpression(call.args[1], rightRegister, 99999)
|
||||
code += VmCodeInstruction(Opcode.CMP, codeGen.vmType(call.args[0].type), reg1=leftRegister, reg2=rightRegister)
|
||||
return code
|
||||
}
|
||||
@ -79,7 +80,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
else -> throw IllegalArgumentException("weird type")
|
||||
}
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args[0], 0)
|
||||
code += exprGen.translateExpression(call.args[0], 0, 99999)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
if(resultRegister!=0)
|
||||
@ -101,7 +102,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
else -> throw IllegalArgumentException("weird type")
|
||||
}
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args[0], 0)
|
||||
code += exprGen.translateExpression(call.args[0], 0, 99999)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
if(resultRegister!=0)
|
||||
@ -113,7 +114,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
val code = VmCodeChunk()
|
||||
val sourceDt = call.args.single().type
|
||||
if(sourceDt!=DataType.UWORD) {
|
||||
code += exprGen.translateExpression(call.args[0], resultRegister)
|
||||
code += exprGen.translateExpression(call.args[0], resultRegister, 99999)
|
||||
when (sourceDt) {
|
||||
DataType.UBYTE -> {
|
||||
code += VmCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
||||
@ -145,14 +146,14 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
|
||||
private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args.single(), 0)
|
||||
code += exprGen.translateExpression(call.args.single(), 0, 99999)
|
||||
code += VmCodeInstruction(Opcode.SGN, codeGen.vmType(call.type), reg1=resultRegister, reg2=0)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcSqrt16(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args.single(), 0)
|
||||
code += exprGen.translateExpression(call.args.single(), 0, 99999)
|
||||
code += VmCodeInstruction(Opcode.SQRT, VmDataType.WORD, reg1=resultRegister, reg2=0)
|
||||
return code
|
||||
}
|
||||
@ -173,14 +174,14 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
|
||||
private fun funcPush(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args.single(), 0)
|
||||
code += exprGen.translateExpression(call.args.single(), 0, 99999)
|
||||
code += VmCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=0)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPushw(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args.single(), 0)
|
||||
code += exprGen.translateExpression(call.args.single(), 0, 99999)
|
||||
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1=0)
|
||||
return code
|
||||
}
|
||||
@ -191,8 +192,8 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
val leftReg = codeGen.vmRegisters.nextFree()
|
||||
val rightReg = codeGen.vmRegisters.nextFree()
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(left, leftReg)
|
||||
code += exprGen.translateExpression(right, rightReg)
|
||||
code += exprGen.translateExpression(left, leftReg, 99999)
|
||||
code += exprGen.translateExpression(right, rightReg, 99999)
|
||||
code += assignRegisterTo(left, rightReg)
|
||||
code += assignRegisterTo(right, leftReg)
|
||||
return code
|
||||
@ -209,7 +210,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
else -> throw IllegalArgumentException("weird type to reverse")
|
||||
}
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args[0], 0)
|
||||
code += exprGen.translateExpression(call.args[0], 0, 99999)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
|
||||
return code
|
||||
@ -229,7 +230,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
else -> throw IllegalArgumentException("weird type to sort")
|
||||
}
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args[0], 0)
|
||||
code += exprGen.translateExpression(call.args[0], 0, 99999)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
|
||||
return code
|
||||
@ -239,8 +240,8 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
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 += exprGen.translateExpression(call.args[0], msbReg, 99999)
|
||||
code += exprGen.translateExpression(call.args[1], lsbReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg, reg3=lsbReg)
|
||||
return code
|
||||
}
|
||||
@ -250,12 +251,12 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
val valueReg = codeGen.vmRegisters.nextFree()
|
||||
if(call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], valueReg)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value=address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg)
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, 99999)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2 = addressReg)
|
||||
}
|
||||
return code
|
||||
@ -266,12 +267,12 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
val valueReg = codeGen.vmRegisters.nextFree()
|
||||
if(call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], valueReg)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value=address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg)
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, 99999)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
|
||||
}
|
||||
return code
|
||||
@ -284,7 +285,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
code += VmCodeInstruction(Opcode.LOADM, VmDataType.WORD, reg1 = resultRegister, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg)
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2 = addressReg)
|
||||
}
|
||||
return code
|
||||
@ -297,7 +298,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
code += VmCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1 = resultRegister, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg)
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2 = addressReg)
|
||||
}
|
||||
return code
|
||||
@ -305,17 +306,13 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
|
||||
private fun funcRnd(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)
|
||||
code += VmCodeInstruction(Opcode.RND, VmDataType.BYTE, reg1=resultRegister)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcRndw(resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value= Syscall.RNDW.ordinal)
|
||||
if(resultRegister!=0)
|
||||
code += VmCodeInstruction(Opcode.LOADR, VmDataType.WORD, reg1=resultRegister, reg2=0)
|
||||
code += VmCodeInstruction(Opcode.RND, VmDataType.WORD, reg1=resultRegister)
|
||||
return code
|
||||
}
|
||||
|
||||
@ -339,14 +336,14 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
|
||||
private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args.single(), resultRegister)
|
||||
code += exprGen.translateExpression(call.args.single(), resultRegister, 99999)
|
||||
// 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 += exprGen.translateExpression(call.args.single(), resultRegister, 99999)
|
||||
code += VmCodeInstruction(Opcode.MSIG, 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.
|
||||
return code
|
||||
@ -362,7 +359,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
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 += exprGen.translateExpression(call.args[1], 0, 99999)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
|
||||
return code
|
||||
}
|
||||
@ -374,8 +371,8 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
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[1], 0, 99999)
|
||||
code += exprGen.translateExpression(call.args[2], 1, 99999)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
|
||||
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1)
|
||||
return code
|
||||
@ -389,9 +386,9 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
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 += exprGen.translateExpression(call.args[1], 0, 99999)
|
||||
code += exprGen.translateExpression(call.args[2], 1, 99999)
|
||||
code += exprGen.translateExpression(call.args[3], 2, 99999)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
|
||||
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 2)
|
||||
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1)
|
||||
@ -401,7 +398,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
private fun funcRolRor2(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val vmDt = codeGen.vmType(call.args[0].type)
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args[0], resultRegister)
|
||||
code += exprGen.translateExpression(call.args[0], resultRegister, 99999)
|
||||
code += VmCodeInstruction(opcode, vmDt, reg1=resultRegister)
|
||||
code += assignRegisterTo(call.args[0], resultRegister)
|
||||
return code
|
||||
|
@ -10,15 +10,25 @@ import kotlin.math.pow
|
||||
|
||||
|
||||
internal class VmRegisterPool {
|
||||
private var firstFree: Int=3 // registers 0,1,2 are reserved
|
||||
private var firstFree: Int=3 // integer registers 0,1,2 are reserved
|
||||
private var firstFreeFloat: Int=0
|
||||
|
||||
fun peekNext() = firstFree
|
||||
fun peekNextFloat() = firstFreeFloat
|
||||
|
||||
fun nextFree(): Int {
|
||||
val result = firstFree
|
||||
firstFree++
|
||||
if(firstFree>65535)
|
||||
throw AssemblyError("out of virtual registers")
|
||||
throw AssemblyError("out of virtual registers (int)")
|
||||
return result
|
||||
}
|
||||
|
||||
fun nextFreeFloat(): Int {
|
||||
val result = firstFreeFloat
|
||||
firstFreeFloat++
|
||||
if(firstFreeFloat>65535)
|
||||
throw AssemblyError("out of virtual registers (fp)")
|
||||
return result
|
||||
}
|
||||
}
|
||||
@ -141,7 +151,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
val valueReg = vmRegisters.nextFree()
|
||||
val choiceReg = vmRegisters.nextFree()
|
||||
val valueDt = vmType(whenStmt.value.type)
|
||||
code += expressionEval.translateExpression(whenStmt.value, valueReg)
|
||||
code += expressionEval.translateExpression(whenStmt.value, valueReg, 99999)
|
||||
val choices = whenStmt.choices.children.map {it as PtWhenChoice }
|
||||
val endLabel = createLabelName()
|
||||
for (choice in choices) {
|
||||
@ -239,8 +249,8 @@ class CodeGen(internal val program: PtProgram,
|
||||
val loopLabel = createLabelName()
|
||||
val code = VmCodeChunk()
|
||||
|
||||
code += expressionEval.translateExpression(iterable.to, endvalueReg)
|
||||
code += expressionEval.translateExpression(iterable.from, indexReg)
|
||||
code += expressionEval.translateExpression(iterable.to, endvalueReg, 99999)
|
||||
code += expressionEval.translateExpression(iterable.from, indexReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, value=loopvarAddress)
|
||||
code += VmCodeLabel(loopLabel)
|
||||
code += translateNode(forLoop.statements)
|
||||
@ -448,7 +458,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
val conditionReg = vmRegisters.nextFree()
|
||||
val vmDt = vmType(condition.type)
|
||||
val code = VmCodeChunk()
|
||||
code += expressionEval.translateExpression(condition, conditionReg)
|
||||
code += expressionEval.translateExpression(condition, conditionReg, 99999)
|
||||
if(ifElse.elseScope.children.isNotEmpty()) {
|
||||
// if and else parts
|
||||
val elseLabel = createLabelName()
|
||||
@ -494,7 +504,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, value=address)
|
||||
} else {
|
||||
val addressReg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg)
|
||||
code += expressionEval.translateExpression(memory.address, addressReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.LOADI, vmDt, reg1 = resultReg, reg2 = addressReg)
|
||||
code += VmCodeInstruction(operation, vmDt, reg1 = resultReg)
|
||||
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1 = resultReg, reg2 = addressReg)
|
||||
@ -514,7 +524,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
code += VmCodeInstruction(memOp, vmDt, value=variableAddr)
|
||||
} else {
|
||||
val indexReg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(array.index, indexReg)
|
||||
code += expressionEval.translateExpression(array.index, indexReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.LOADX, vmDt, reg1=resultReg, reg2=indexReg, value=variableAddr)
|
||||
code += VmCodeInstruction(operation, vmDt, reg1=resultReg)
|
||||
code += VmCodeInstruction(Opcode.STOREX, vmDt, reg1=resultReg, reg2=indexReg, value=variableAddr)
|
||||
@ -538,7 +548,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
val code = VmCodeChunk()
|
||||
val counterReg = vmRegisters.nextFree()
|
||||
val vmDt = vmType(repeat.count.type)
|
||||
code += expressionEval.translateExpression(repeat.count, counterReg)
|
||||
code += expressionEval.translateExpression(repeat.count, counterReg, 99999)
|
||||
val repeatLabel = createLabelName()
|
||||
code += VmCodeLabel(repeatLabel)
|
||||
code += translateNode(repeat.statements)
|
||||
@ -576,7 +586,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
(assignment.value as PtMachineRegister).register
|
||||
} else {
|
||||
val reg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(assignment.value, reg)
|
||||
code += expressionEval.translateExpression(assignment.value, reg, 99999)
|
||||
reg
|
||||
}
|
||||
val ident = assignment.target.identifier
|
||||
@ -598,7 +608,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr)
|
||||
} else {
|
||||
val indexReg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(array.index, indexReg)
|
||||
code += expressionEval.translateExpression(array.index, indexReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.STOREX, vmDtArrayIdx, reg1 = resultRegister, reg2=indexReg, value=variableAddr)
|
||||
}
|
||||
}
|
||||
@ -608,7 +618,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
|
||||
} else {
|
||||
val addressReg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg)
|
||||
code += expressionEval.translateExpression(memory.address, addressReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
|
||||
}
|
||||
}
|
||||
@ -622,7 +632,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
val value = ret.value
|
||||
if(value!=null) {
|
||||
// Call Convention: return value is always returned in r0
|
||||
code += expressionEval.translateExpression(value, 0)
|
||||
code += expressionEval.translateExpression(value, 0, 99999)
|
||||
}
|
||||
code += VmCodeInstruction(Opcode.RETURN)
|
||||
return code
|
||||
@ -658,6 +668,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
DataType.BYTE -> VmDataType.BYTE
|
||||
DataType.UWORD,
|
||||
DataType.WORD -> VmDataType.WORD
|
||||
DataType.FLOAT -> VmDataType.FLOAT
|
||||
in PassByReferenceDatatypes -> VmDataType.WORD
|
||||
else -> throw AssemblyError("no vm datatype for $type")
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import prog8.vm.VmDataType
|
||||
|
||||
|
||||
internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
fun translateExpression(expr: PtExpression, resultRegister: Int): VmCodeChunk {
|
||||
fun translateExpression(expr: PtExpression, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
|
||||
require(codeGen.vmRegisters.peekNext() > resultRegister)
|
||||
|
||||
val code = VmCodeChunk()
|
||||
@ -49,7 +49,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
code += VmCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1=resultRegister, value = address)
|
||||
} else {
|
||||
val addressRegister = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(expr.address, addressRegister)
|
||||
code += translateExpression(expr.address, addressRegister, 99999)
|
||||
code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1=resultRegister, reg2=addressRegister)
|
||||
}
|
||||
}
|
||||
@ -91,7 +91,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
}
|
||||
|
||||
val code = VmCodeChunk()
|
||||
code += translateExpression(segments[0], valueReg)
|
||||
code += translateExpression(segments[0], valueReg, 99999)
|
||||
for (segment in segments.subList(1, segments.size-1)) {
|
||||
val sourceReg = valueReg
|
||||
val sourceDt = valueDt
|
||||
@ -100,16 +100,16 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
valueReg = codeGen.vmRegisters.nextFree()
|
||||
}
|
||||
val segmentWithImplicitArgument = addImplicitArgToSegment(segment, sourceReg, sourceDt)
|
||||
code += translateExpression(segmentWithImplicitArgument, valueReg)
|
||||
code += translateExpression(segmentWithImplicitArgument, valueReg, 99999)
|
||||
}
|
||||
val segWithArg = addImplicitArgToSegment(segments.last(), valueReg, valueDt)
|
||||
code += translateExpression(segWithArg, resultRegister)
|
||||
code += translateExpression(segWithArg, resultRegister, 99999)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(check: PtContainmentCheck, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
code += translateExpression(check.element, resultRegister) // load the element to check in resultRegister
|
||||
code += translateExpression(check.element, resultRegister, 99999) // load the element to check in resultRegister
|
||||
val iterable = codeGen.symbolTable.flat.getValue(check.iterable.targetName) as StStaticVariable
|
||||
when(iterable.dt) {
|
||||
DataType.STR -> {
|
||||
@ -149,7 +149,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val memOffset = (arrayIx.index as PtNumber).number.toInt() * eltSize
|
||||
code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, value=arrayLocation+memOffset)
|
||||
} else {
|
||||
code += translateExpression(arrayIx.index, idxReg)
|
||||
code += translateExpression(arrayIx.index, idxReg, 99999)
|
||||
if(eltSize>1)
|
||||
code += codeGen.multiplyByConst(VmDataType.BYTE, idxReg, eltSize)
|
||||
code += VmCodeInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, value = arrayLocation)
|
||||
@ -159,7 +159,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
|
||||
private fun translate(expr: PtPrefix, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
code += translateExpression(expr.value, resultRegister)
|
||||
code += translateExpression(expr.value, resultRegister, 99999)
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
when(expr.operator) {
|
||||
"+" -> { }
|
||||
@ -190,7 +190,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val code = VmCodeChunk()
|
||||
if(cast.type==cast.value.type)
|
||||
return code
|
||||
code += translateExpression(cast.value, resultRegister)
|
||||
code += translateExpression(cast.value, resultRegister, 99999)
|
||||
when(cast.type) {
|
||||
DataType.UBYTE -> {
|
||||
when(cast.value.type) {
|
||||
@ -297,8 +297,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val code = VmCodeChunk()
|
||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, leftResultReg)
|
||||
code += translateExpression(binExpr.right, rightResultReg)
|
||||
code += translateExpression(binExpr.left, leftResultReg, 99999)
|
||||
code += translateExpression(binExpr.right, rightResultReg, 99999)
|
||||
val ins = if(signed) {
|
||||
if(greaterEquals) Opcode.SGES else Opcode.SGTS
|
||||
} else {
|
||||
@ -318,8 +318,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val code = VmCodeChunk()
|
||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, leftResultReg)
|
||||
code += translateExpression(binExpr.right, rightResultReg)
|
||||
code += translateExpression(binExpr.left, leftResultReg, 99999)
|
||||
code += translateExpression(binExpr.right, rightResultReg, 99999)
|
||||
val ins = if(signed) {
|
||||
if(lessEquals) Opcode.SLES else Opcode.SLTS
|
||||
} else {
|
||||
@ -333,8 +333,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val code = VmCodeChunk()
|
||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, leftResultReg)
|
||||
code += translateExpression(binExpr.right, rightResultReg)
|
||||
code += translateExpression(binExpr.left, leftResultReg, 99999)
|
||||
code += translateExpression(binExpr.right, rightResultReg, 99999)
|
||||
val opcode = if(notEquals) Opcode.SNE else Opcode.SEQ
|
||||
code += VmCodeInstruction(opcode, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
return code
|
||||
@ -344,8 +344,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val code = VmCodeChunk()
|
||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, leftResultReg)
|
||||
code += translateExpression(binExpr.right, rightResultReg)
|
||||
code += translateExpression(binExpr.left, leftResultReg, 99999)
|
||||
code += translateExpression(binExpr.right, rightResultReg, 99999)
|
||||
val opc = if(signed) Opcode.ASRX else Opcode.LSRX
|
||||
code += VmCodeInstruction(opc, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
return code
|
||||
@ -355,8 +355,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val code = VmCodeChunk()
|
||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, leftResultReg)
|
||||
code += translateExpression(binExpr.right, rightResultReg)
|
||||
code += translateExpression(binExpr.left, leftResultReg, 99999)
|
||||
code += translateExpression(binExpr.right, rightResultReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.LSLX, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
return code
|
||||
}
|
||||
@ -365,8 +365,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val code = VmCodeChunk()
|
||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, leftResultReg)
|
||||
code += translateExpression(binExpr.right, rightResultReg)
|
||||
code += translateExpression(binExpr.left, leftResultReg, 99999)
|
||||
code += translateExpression(binExpr.right, rightResultReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
return code
|
||||
}
|
||||
@ -375,8 +375,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val code = VmCodeChunk()
|
||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, leftResultReg)
|
||||
code += translateExpression(binExpr.right, rightResultReg)
|
||||
code += translateExpression(binExpr.left, leftResultReg, 99999)
|
||||
code += translateExpression(binExpr.right, rightResultReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.AND, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
return code
|
||||
}
|
||||
@ -385,8 +385,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val code = VmCodeChunk()
|
||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, leftResultReg)
|
||||
code += translateExpression(binExpr.right, rightResultReg)
|
||||
code += translateExpression(binExpr.left, leftResultReg, 99999)
|
||||
code += translateExpression(binExpr.right, rightResultReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.OR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
return code
|
||||
}
|
||||
@ -395,8 +395,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val code = VmCodeChunk()
|
||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, leftResultReg)
|
||||
code += translateExpression(binExpr.right, rightResultReg)
|
||||
code += translateExpression(binExpr.left, leftResultReg, 99999)
|
||||
code += translateExpression(binExpr.right, rightResultReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.MOD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
return code
|
||||
}
|
||||
@ -405,14 +405,14 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val code = VmCodeChunk()
|
||||
val constFactorRight = binExpr.right as? PtNumber
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
code += translateExpression(binExpr.left, resultRegister)
|
||||
code += translateExpression(binExpr.left, resultRegister, 99999)
|
||||
val factor = constFactorRight.number.toInt()
|
||||
code += codeGen.divideByConst(vmDt, resultRegister, factor)
|
||||
} else {
|
||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, leftResultReg)
|
||||
code += translateExpression(binExpr.right, rightResultReg)
|
||||
code += translateExpression(binExpr.left, leftResultReg, 99999)
|
||||
code += translateExpression(binExpr.right, rightResultReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.DIV, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
return code
|
||||
@ -423,18 +423,18 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val constFactorLeft = binExpr.left as? PtNumber
|
||||
val constFactorRight = binExpr.right as? PtNumber
|
||||
if(constFactorLeft!=null && constFactorLeft.type!=DataType.FLOAT) {
|
||||
code += translateExpression(binExpr.right, resultRegister)
|
||||
code += translateExpression(binExpr.right, resultRegister, 99999)
|
||||
val factor = constFactorLeft.number.toInt()
|
||||
code += codeGen.multiplyByConst(vmDt, resultRegister, factor)
|
||||
} else if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
code += translateExpression(binExpr.left, resultRegister)
|
||||
code += translateExpression(binExpr.left, resultRegister, 99999)
|
||||
val factor = constFactorRight.number.toInt()
|
||||
code += codeGen.multiplyByConst(vmDt, resultRegister, factor)
|
||||
} else {
|
||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, leftResultReg)
|
||||
code += translateExpression(binExpr.right, rightResultReg)
|
||||
code += translateExpression(binExpr.left, leftResultReg, 99999)
|
||||
code += translateExpression(binExpr.right, rightResultReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.MUL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
return code
|
||||
@ -443,14 +443,14 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if((binExpr.right as? PtNumber)?.number==1.0) {
|
||||
code += translateExpression(binExpr.left, resultRegister)
|
||||
code += translateExpression(binExpr.left, resultRegister, 99999)
|
||||
code += VmCodeInstruction(Opcode.DEC, vmDt, reg1=resultRegister)
|
||||
}
|
||||
else {
|
||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, leftResultReg)
|
||||
code += translateExpression(binExpr.right, rightResultReg)
|
||||
code += translateExpression(binExpr.left, leftResultReg, 99999)
|
||||
code += translateExpression(binExpr.right, rightResultReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.SUB, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
return code
|
||||
@ -459,18 +459,18 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
private fun operatorPlus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if((binExpr.left as? PtNumber)?.number==1.0) {
|
||||
code += translateExpression(binExpr.right, resultRegister)
|
||||
code += translateExpression(binExpr.right, resultRegister, 99999)
|
||||
code += VmCodeInstruction(Opcode.INC, vmDt, reg1=resultRegister)
|
||||
}
|
||||
else if((binExpr.right as? PtNumber)?.number==1.0) {
|
||||
code += translateExpression(binExpr.left, resultRegister)
|
||||
code += translateExpression(binExpr.left, resultRegister, 99999)
|
||||
code += VmCodeInstruction(Opcode.INC, vmDt, reg1=resultRegister)
|
||||
}
|
||||
else {
|
||||
val leftResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, leftResultReg)
|
||||
code += translateExpression(binExpr.right, rightResultReg)
|
||||
code += translateExpression(binExpr.left, leftResultReg, 99999)
|
||||
code += translateExpression(binExpr.right, rightResultReg, 99999)
|
||||
code += VmCodeInstruction(Opcode.ADD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
|
||||
}
|
||||
return code
|
||||
@ -481,7 +481,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val code = VmCodeChunk()
|
||||
for ((arg, parameter) in fcall.args.zip(subroutine.parameters)) {
|
||||
val argReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(arg, argReg)
|
||||
code += translateExpression(arg, argReg, 99999)
|
||||
val vmDt = codeGen.vmType(parameter.type)
|
||||
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=argReg, value=mem)
|
||||
|
@ -1,5 +1,5 @@
|
||||
%import textio
|
||||
; %import floats
|
||||
;%import floats
|
||||
%import conv
|
||||
%zeropage dontuse
|
||||
|
||||
@ -7,39 +7,34 @@
|
||||
; NOTE: meant to test to virtual machine output target (use -target vitual)
|
||||
|
||||
main {
|
||||
sub newstring() -> str {
|
||||
return "new"
|
||||
}
|
||||
|
||||
sub start() {
|
||||
str name = "irmen\n"
|
||||
txt.print(name)
|
||||
name = "pipo\n"
|
||||
txt.print(name)
|
||||
|
||||
ubyte cc
|
||||
ubyte[] array = [11,22,33,44]
|
||||
for cc in array {
|
||||
txt.print_ub(cc)
|
||||
txt.spc()
|
||||
}
|
||||
txt.nl()
|
||||
array = [99,88,77,66]
|
||||
for cc in array {
|
||||
txt.print_ub(cc)
|
||||
txt.spc()
|
||||
}
|
||||
uword uw = 15555
|
||||
uword squw = sqrt16(uw)
|
||||
txt.print_uw(squw)
|
||||
txt.nl()
|
||||
|
||||
txt.print_ub0(99)
|
||||
squw = rndw()
|
||||
txt.print_uw(squw)
|
||||
txt.spc()
|
||||
txt.print_ub(99)
|
||||
squw = rndw()
|
||||
txt.print_uw(squw)
|
||||
txt.nl()
|
||||
txt.print_uw0(9988)
|
||||
|
||||
squw = rnd()
|
||||
txt.print_uw(squw)
|
||||
txt.spc()
|
||||
txt.print_uw(9988)
|
||||
squw = rnd()
|
||||
txt.print_uw(squw)
|
||||
txt.nl()
|
||||
|
||||
; float f1 = 1.2345
|
||||
; float f2 = -9.99
|
||||
; float f3 = f1 % f2
|
||||
; floats.print_f(f3)
|
||||
; f3 = floats.sin(f3)
|
||||
; floats.print_f(f3)
|
||||
; txt.nl()
|
||||
|
||||
; float f1 = 1.555
|
||||
; floats.print_f(floats.sin(f1))
|
||||
; txt.nl()
|
||||
@ -71,24 +66,24 @@ main {
|
||||
; "ln", "log2", "sqrt", "rad",
|
||||
; "deg", "round", "floor", "ceil", "rndf"
|
||||
|
||||
; ; a "pixelshader":
|
||||
; void syscall1(8, 0) ; enable lo res creen
|
||||
; ubyte shifter
|
||||
;
|
||||
; ; pokemon(1,0)
|
||||
;
|
||||
; repeat {
|
||||
; uword xx
|
||||
; uword yy = 0
|
||||
; repeat 240 {
|
||||
; xx = 0
|
||||
; repeat 320 {
|
||||
; syscall3(10, xx, yy, xx*yy + shifter) ; plot pixel
|
||||
; xx++
|
||||
; }
|
||||
; yy++
|
||||
; }
|
||||
; shifter+=4
|
||||
; }
|
||||
; a "pixelshader":
|
||||
void syscall1(8, 0) ; enable lo res creen
|
||||
ubyte shifter
|
||||
|
||||
; pokemon(1,0)
|
||||
|
||||
repeat {
|
||||
uword xx
|
||||
uword yy = 0
|
||||
repeat 240 {
|
||||
xx = 0
|
||||
repeat 320 {
|
||||
syscall3(10, xx, yy, xx*yy + shifter) ; plot pixel
|
||||
xx++
|
||||
}
|
||||
yy++
|
||||
}
|
||||
shifter+=4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,13 @@ class Assembler {
|
||||
address += 2
|
||||
}
|
||||
}
|
||||
"float" -> {
|
||||
val array = values.split(',').map { it.toFloat() }
|
||||
for (value in array) {
|
||||
memory.setFloat(address, value)
|
||||
address += 4 // 32-bits floats
|
||||
}
|
||||
}
|
||||
else -> throw IllegalArgumentException("mem instr $what")
|
||||
}
|
||||
}
|
||||
@ -113,10 +120,18 @@ class Assembler {
|
||||
}
|
||||
}
|
||||
}
|
||||
val format = instructionFormats.getValue(opcode)
|
||||
if(type==null && format.datatypes.isNotEmpty())
|
||||
type= VmDataType.BYTE
|
||||
if(type!=null && type !in format.datatypes)
|
||||
val formats = instructionFormats.getValue(opcode)
|
||||
val format: InstructionFormat
|
||||
if(type !in formats) {
|
||||
type = VmDataType.BYTE
|
||||
format = if(type !in formats)
|
||||
formats.getValue(null)
|
||||
else
|
||||
formats.getValue(type)
|
||||
} else {
|
||||
format = formats.getValue(type)
|
||||
}
|
||||
if(type!=null && type !in formats)
|
||||
throw IllegalArgumentException("invalid type code for $line")
|
||||
if(format.reg1 && reg1==null)
|
||||
throw IllegalArgumentException("needs reg1 for $line")
|
||||
@ -144,10 +159,13 @@ class Assembler {
|
||||
if (value < -32768 || value > 65535)
|
||||
throw IllegalArgumentException("value out of range for word: $value")
|
||||
}
|
||||
VmDataType.FLOAT -> {
|
||||
throw IllegalArgumentException("can't use float here")
|
||||
}
|
||||
null -> {}
|
||||
}
|
||||
}
|
||||
program.add(Instruction(opcode, type, reg1, reg2, reg3, value))
|
||||
program.add(Instruction(opcode, type, reg1, reg2, reg3, value=value))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,42 +5,37 @@ package prog8.vm
|
||||
Virtual machine:
|
||||
|
||||
65536 virtual registers, 16 bits wide, can also be used as 8 bits. r0-r65535
|
||||
65536 virtual floating point registers (32 bits single precision floats) fr0-fr65535
|
||||
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
|
||||
Value stack, max 128 entries of 1 byte each.
|
||||
Status registers: Carry.
|
||||
Status registers: Carry, Zero, Negative.
|
||||
|
||||
|
||||
Instruction serialization format possibility:
|
||||
|
||||
OPCODE: 1 byte
|
||||
TYPECODE: 1 byte
|
||||
REGISTER 1: 2 bytes
|
||||
REGISTER 2: 2 bytes
|
||||
REG3/MEMORY/VALUE: 2 bytes
|
||||
|
||||
Instructions with Type come in variants 'b' and 'w' (omitting it in the instruction means 'b' by default)
|
||||
Currently NO support for 24 or 32 bits, and FLOATING POINT is not implemented yet either. FP would be
|
||||
a separate set of registers and instructions/routines anyway.
|
||||
Most instructions have an associated data type 'b','w','f'. (omitting it means 'b'/byte).
|
||||
Currently NO support for 24 or 32 bits integers.
|
||||
Floating point operations are just 'f' typed regular instructions, and additionally there are
|
||||
a few fp conversion instructions to
|
||||
|
||||
*only* LOAD AND STORE instructions have a possible memory operand, all other instructions use only registers or immediate value.
|
||||
|
||||
|
||||
TODO all floating point arithmethic functions as fp-instructions.
|
||||
|
||||
LOAD/STORE
|
||||
----------
|
||||
All have type b or w.
|
||||
All have type b or w or f.
|
||||
|
||||
load reg1, value - load immediate value into register
|
||||
loadm reg1, address - load reg1 with value in memory address
|
||||
loadi reg1, reg2 - load reg1 with value in memory indirect, memory pointed to by reg2
|
||||
loadx reg1, reg2, address - load reg1 with value in memory address, indexed by value in reg2
|
||||
loadr reg1, reg2 - load reg1 with value in register reg2
|
||||
loadm reg1, address - load reg1 with value at memory address
|
||||
loadi reg1, reg2 - load reg1 with value at memory indirect, memory pointed to by reg2
|
||||
loadx reg1, reg2, address - load reg1 with value at memory address, indexed by value in reg2
|
||||
loadr reg1, reg2 - load reg1 with value at register reg2
|
||||
|
||||
storem reg1, address - store reg1 in memory address
|
||||
storei reg1, reg2 - store reg1 in memory indirect, memory pointed to by reg2
|
||||
storex reg1, reg2, address - store reg1 in memory address, indexed by value in reg2
|
||||
storez address - store zero in memory address
|
||||
storezi reg1 - store zero in memory pointed to by reg1
|
||||
storezx reg1, address - store zero in memory address, indexed by value in reg
|
||||
storem reg1, address - store reg1 at memory address
|
||||
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
|
||||
storez address - store zero at memory address
|
||||
storezi reg1 - store zero at memory pointed to by reg1
|
||||
storezx reg1, address - store zero at memory address, indexed by value in reg
|
||||
|
||||
|
||||
CONTROL FLOW
|
||||
@ -91,13 +86,10 @@ sgts reg1, reg2, reg3 - set reg=1 if reg2 > reg3 (signed), ot
|
||||
sge reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (unsigned), otherwise set reg1=0
|
||||
sges reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (signed), otherwise set reg1=0
|
||||
|
||||
TODO: support for the other prog8 special branching instructions if_XX (bpl, bmi etc.)
|
||||
but we don't have any 'processor flags' whatsoever in the vm so it's a bit weird
|
||||
|
||||
|
||||
INTEGER ARITHMETIC
|
||||
------------------
|
||||
All have type b or w. Note: result types are the same as operand types! E.g. byte*byte->byte.
|
||||
ARITHMETIC
|
||||
----------
|
||||
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)
|
||||
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)
|
||||
@ -111,9 +103,10 @@ sub reg1, reg2, reg3 - reg1 = reg2-reg3 (unsigned + signe
|
||||
mul reg1, reg2, reg3 - unsigned multiply reg1=reg2*reg3 note: byte*byte->byte, no type extension to word!
|
||||
div reg1, reg2, reg3 - unsigned division reg1=reg2/reg3 note: division by zero yields max signed int $ff/$ffff
|
||||
mod reg1, reg2, reg3 - remainder (modulo) of unsigned division reg1=reg2%reg3 note: division by zero yields max signed int $ff/$ffff
|
||||
sqrt reg1, reg2 - reg1 is the square root of reg2 (for .w and .b both , the result is a byte)
|
||||
sqrt reg1, reg2 - reg1 is the square root of reg2
|
||||
sgn reg1, reg2 - reg1 is the sign of reg2 (0, 1 or -1)
|
||||
cmp reg1, reg2 - set processor status bits C, N, Z according to comparison of reg1 with reg2. (semantics taken from 6502/68000 CMP instruction)
|
||||
rnd reg1 - get a random number (byte, word or float)
|
||||
|
||||
NOTE: because mul/div are constrained (truncated) to remain in 8 or 16 bits, there is NO NEED for separate signed/unsigned mul and div instructions. The result is identical.
|
||||
|
||||
@ -137,6 +130,18 @@ rol reg1 - rotate reg1 left by 1bits, not us
|
||||
roxl reg1 - rotate reg1 left by 1bits, using carry, + set Carry to shifted bit
|
||||
|
||||
|
||||
FLOATING POINT CONVERSIONS
|
||||
--------------------------
|
||||
ffromub fpreg1, reg1 - fpreg1 = reg1 from usigned byte
|
||||
ffromsb fpreg1, reg1 - fpreg1 = reg1 from signed byte
|
||||
ffromuw fpreg1, reg1 - fpreg1 = reg1 from unsigned word
|
||||
ffromsw fpreg1, reg1 - fpreg1 = reg1 from signed word
|
||||
ftoub reg1, fpreg1 - reg1 = fpreg1 as unsigned byte
|
||||
ftosb reg1, fpreg1 - reg1 = fpreg1 as signed byte
|
||||
ftouw reg1, fpreg1 - reg1 = fpreg1 as unsigned word
|
||||
ftosw reg1, fpreg1 - reg1 = fpreg1 as signed word
|
||||
|
||||
|
||||
MISC
|
||||
----
|
||||
|
||||
@ -217,6 +222,7 @@ enum class Opcode {
|
||||
SQRT,
|
||||
SGN,
|
||||
CMP,
|
||||
RND,
|
||||
EXT,
|
||||
EXTS,
|
||||
|
||||
@ -234,6 +240,15 @@ enum class Opcode {
|
||||
ROL,
|
||||
ROXL,
|
||||
|
||||
FFROMUB,
|
||||
FFROMSB,
|
||||
FFROMUW,
|
||||
FFROMSW,
|
||||
FTOUB,
|
||||
FTOSB,
|
||||
FTOUW,
|
||||
FTOSW,
|
||||
|
||||
CLC,
|
||||
SEC,
|
||||
PUSH,
|
||||
@ -256,7 +271,8 @@ val OpcodesWithAddress = setOf(
|
||||
|
||||
enum class VmDataType {
|
||||
BYTE,
|
||||
WORD
|
||||
WORD,
|
||||
FLOAT
|
||||
// TODO add INT (32-bit)? INT24 (24-bit)?
|
||||
}
|
||||
|
||||
@ -266,14 +282,19 @@ data class Instruction(
|
||||
val reg1: Int?=null, // 0-$ffff
|
||||
val reg2: Int?=null, // 0-$ffff
|
||||
val reg3: Int?=null, // 0-$ffff
|
||||
val fpReg1: Int?=null, // 0-$ffff
|
||||
val fpReg2: Int?=null, // 0-$ffff
|
||||
val fpReg3: Int?=null, // 0-$ffff
|
||||
val value: Int?=null, // 0-$ffff
|
||||
val fpValue: Float?=null,
|
||||
val symbol: List<String>?=null // alternative to value
|
||||
) {
|
||||
init {
|
||||
val format = instructionFormats.getValue(opcode)
|
||||
if(format.datatypes.isNotEmpty() && type==null)
|
||||
val formats = instructionFormats.getValue(opcode)
|
||||
if(type==null && !formats.containsKey(null))
|
||||
throw IllegalArgumentException("missing type")
|
||||
|
||||
val format = formats.getValue(type)
|
||||
if(format.reg1 && reg1==null ||
|
||||
format.reg2 && reg2==null ||
|
||||
format.reg3 && reg3==null)
|
||||
@ -284,8 +305,18 @@ data class Instruction(
|
||||
!format.reg3 && reg3!=null)
|
||||
throw IllegalArgumentException("too many registers")
|
||||
|
||||
|
||||
if (type==VmDataType.FLOAT) {
|
||||
if(format.value && (fpValue==null && symbol==null))
|
||||
throw IllegalArgumentException("$opcode: missing a fp-value or symbol")
|
||||
if (reg1 != null || reg2 != null || reg3 != null)
|
||||
throw java.lang.IllegalArgumentException("$opcode: floating point instruction can't use integer registers")
|
||||
} else {
|
||||
if(format.value && (value==null && symbol==null))
|
||||
throw IllegalArgumentException("missing a value or symbol")
|
||||
throw IllegalArgumentException("$opcode: missing a value or symbol")
|
||||
if (fpReg1 != null || fpReg2 != null || fpReg3 != null)
|
||||
throw java.lang.IllegalArgumentException("$opcode: integer point instruction can't use floating point registers")
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
@ -308,10 +339,26 @@ data class Instruction(
|
||||
result.add("r$it")
|
||||
result.add(",")
|
||||
}
|
||||
fpReg1?.let {
|
||||
result.add("fr$it")
|
||||
result.add(",")
|
||||
}
|
||||
fpReg2?.let {
|
||||
result.add("fr$it")
|
||||
result.add(",")
|
||||
}
|
||||
fpReg3?.let {
|
||||
result.add("fr$it")
|
||||
result.add(",")
|
||||
}
|
||||
value?.let {
|
||||
result.add(it.toString())
|
||||
result.add(",")
|
||||
}
|
||||
fpValue?.let {
|
||||
result.add(it.toString())
|
||||
result.add(",")
|
||||
}
|
||||
symbol?.let {
|
||||
result.add("_" + it.joinToString("."))
|
||||
}
|
||||
@ -321,98 +368,146 @@ data class Instruction(
|
||||
}
|
||||
}
|
||||
|
||||
data class InstructionFormat(val datatypes: Set<VmDataType>, val reg1: Boolean, val reg2: Boolean, val reg3: Boolean, val value: Boolean)
|
||||
data class InstructionFormat(val datatype: VmDataType?,
|
||||
val reg1: Boolean, val reg2: Boolean, val reg3: Boolean,
|
||||
val fpReg1: Boolean, val fpReg2: Boolean, val fpReg3: Boolean,
|
||||
val value: Boolean,
|
||||
val fpValue: Boolean) {
|
||||
companion object {
|
||||
fun from(spec: String): Map<VmDataType?, InstructionFormat> {
|
||||
val result = mutableMapOf<VmDataType?, InstructionFormat>()
|
||||
var reg1 = false
|
||||
var reg2 = false
|
||||
var reg3 = false
|
||||
var fpreg1 = false
|
||||
var fpreg2 = false
|
||||
var fpreg3 = false
|
||||
var value = false
|
||||
var fpvalue = false
|
||||
for(part in spec.split('|').map{ it.trim() }) {
|
||||
val splits = part.splitToSequence(',').iterator()
|
||||
val typespec = splits.next()
|
||||
while(splits.hasNext()) {
|
||||
when(splits.next()) {
|
||||
"r1" -> reg1=true
|
||||
"r2" -> reg2=true
|
||||
"r3" -> reg3=true
|
||||
"fr1" -> fpreg1=true
|
||||
"fr2" -> fpreg2=true
|
||||
"fr3" -> fpreg3=true
|
||||
"v" -> value = true
|
||||
"fv" -> fpvalue = true
|
||||
else -> throw IllegalArgumentException(spec)
|
||||
}
|
||||
}
|
||||
if(typespec=="N")
|
||||
result[null] = InstructionFormat(null, reg1=reg1, reg2=reg2, reg3=reg3, fpReg1=fpreg1, fpReg2=fpreg2, fpReg3=fpreg3, value=value, fpValue=fpvalue)
|
||||
if('B' in typespec)
|
||||
result[VmDataType.BYTE] = InstructionFormat(VmDataType.BYTE, reg1=reg1, reg2=reg2, reg3=reg3, fpReg1=fpreg1, fpReg2=fpreg2, fpReg3=fpreg3, value=value, fpValue=fpvalue)
|
||||
if('W' in typespec)
|
||||
result[VmDataType.WORD] = InstructionFormat(VmDataType.WORD, reg1=reg1, reg2=reg2, reg3=reg3, fpReg1=fpreg1, fpReg2=fpreg2, fpReg3=fpreg3, value=value, fpValue=fpvalue)
|
||||
if('F' in typespec)
|
||||
result[VmDataType.FLOAT] = InstructionFormat(VmDataType.FLOAT, reg1=reg1, reg2=reg2, reg3=reg3, fpReg1=fpreg1, fpReg2=fpreg2, fpReg3=fpreg3, value=value, fpValue=fpvalue)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val NN = emptySet<VmDataType>()
|
||||
private val BW = setOf(VmDataType.BYTE, VmDataType.WORD)
|
||||
|
||||
@Suppress("BooleanLiteralArgument")
|
||||
val instructionFormats = mutableMapOf(
|
||||
Opcode.NOP to InstructionFormat(NN, false, false, false, false),
|
||||
Opcode.LOAD to InstructionFormat(BW, true, false, false, true ),
|
||||
Opcode.LOADM to InstructionFormat(BW, true, false, false, true ),
|
||||
Opcode.LOADI to InstructionFormat(BW, true, true, false, false),
|
||||
Opcode.LOADX to InstructionFormat(BW, true, true, false, true ),
|
||||
Opcode.LOADR to InstructionFormat(BW, true, true, false, false),
|
||||
Opcode.SWAPREG to InstructionFormat(BW, true, true, false, false),
|
||||
Opcode.STOREM to InstructionFormat(BW, true, false, false, true ),
|
||||
Opcode.STOREI to InstructionFormat(BW, true, true, false, false),
|
||||
Opcode.STOREX to InstructionFormat(BW, true, true, false, true ),
|
||||
Opcode.STOREZ to InstructionFormat(BW, false, false, false, true ),
|
||||
Opcode.STOREZI to InstructionFormat(BW, true, false, false, false),
|
||||
Opcode.STOREZX to InstructionFormat(BW, true, false, false, true ),
|
||||
Opcode.NOP to InstructionFormat.from("N"),
|
||||
Opcode.LOAD to InstructionFormat.from("BW,r1,v | F,fr1,fv"),
|
||||
Opcode.LOADM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
|
||||
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.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.STOREI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
|
||||
Opcode.STOREX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
|
||||
Opcode.STOREZ to InstructionFormat.from("BW,v | F,v"),
|
||||
Opcode.STOREZI to InstructionFormat.from("BW,r1 | F,r1"),
|
||||
Opcode.STOREZX to InstructionFormat.from("BW,r1,v | F,r1,v"),
|
||||
Opcode.JUMP to InstructionFormat.from("N,v"),
|
||||
Opcode.JUMPI to InstructionFormat.from("N,r1"),
|
||||
Opcode.CALL to InstructionFormat.from("N,v"),
|
||||
Opcode.CALLI to InstructionFormat.from("N,r1"),
|
||||
Opcode.SYSCALL to InstructionFormat.from("N,v"),
|
||||
Opcode.RETURN to InstructionFormat.from("N"),
|
||||
Opcode.BSTCC to InstructionFormat.from("N,v"),
|
||||
Opcode.BSTCS to InstructionFormat.from("N,v"),
|
||||
Opcode.BSTEQ to InstructionFormat.from("N,v"),
|
||||
Opcode.BSTNE to InstructionFormat.from("N,v"),
|
||||
Opcode.BSTNEG to InstructionFormat.from("N,v"),
|
||||
Opcode.BSTPOS to InstructionFormat.from("N,v"),
|
||||
Opcode.BZ to InstructionFormat.from("BW,r1,v"),
|
||||
Opcode.BNZ to InstructionFormat.from("BW,r1,v"),
|
||||
Opcode.BEQ to InstructionFormat.from("BW,r1,r2,v"),
|
||||
Opcode.BNE to InstructionFormat.from("BW,r1,r2,v"),
|
||||
Opcode.BLT to InstructionFormat.from("BW,r1,r2,v"),
|
||||
Opcode.BLTS to InstructionFormat.from("BW,r1,r2,v"),
|
||||
Opcode.BGT to InstructionFormat.from("BW,r1,r2,v"),
|
||||
Opcode.BGTS to InstructionFormat.from("BW,r1,r2,v"),
|
||||
Opcode.BLE to InstructionFormat.from("BW,r1,r2,v"),
|
||||
Opcode.BLES to InstructionFormat.from("BW,r1,r2,v"),
|
||||
Opcode.BGE to InstructionFormat.from("BW,r1,r2,v"),
|
||||
Opcode.BGES to InstructionFormat.from("BW,r1,r2,v"),
|
||||
Opcode.SEQ to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.SNE to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.SLT to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.SLTS to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.SGT to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.SGTS to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.SLE to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.SLES to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.SGE to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.SGES to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.INC to InstructionFormat.from("BW,r1"),
|
||||
Opcode.INCM to InstructionFormat.from("BW,v"),
|
||||
Opcode.DEC to InstructionFormat.from("BW,r1"),
|
||||
Opcode.DECM to InstructionFormat.from("BW,v"),
|
||||
Opcode.NEG to InstructionFormat.from("BW,r1 | F,fr1"),
|
||||
Opcode.ADD to InstructionFormat.from("BW,r1,r2,r3 | F,fr1,fr2,fr3"),
|
||||
Opcode.SUB to InstructionFormat.from("BW,r1,r2,r3 | F,fr1,fr2,fr3"),
|
||||
Opcode.MUL to InstructionFormat.from("BW,r1,r2,r3 | F,fr1,fr2,fr3"),
|
||||
Opcode.DIV to InstructionFormat.from("BW,r1,r2,r3 | F,fr1,fr2,fr3"),
|
||||
Opcode.SQRT to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
||||
Opcode.SGN to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
||||
Opcode.RND to InstructionFormat.from("BW,r1 | F,fr1"),
|
||||
Opcode.MOD to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.CMP to InstructionFormat.from("BW,r1,r2"),
|
||||
Opcode.EXT to InstructionFormat.from("BW,r1"),
|
||||
Opcode.EXTS to InstructionFormat.from("BW,r1"),
|
||||
Opcode.AND 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.ASRX to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.LSRX to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.LSLX to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.ASR to InstructionFormat.from("BW,r1"),
|
||||
Opcode.LSR to InstructionFormat.from("BW,r1"),
|
||||
Opcode.LSL to InstructionFormat.from("BW,r1"),
|
||||
Opcode.ROR to InstructionFormat.from("BW,r1"),
|
||||
Opcode.ROXR to InstructionFormat.from("BW,r1"),
|
||||
Opcode.ROL to InstructionFormat.from("BW,r1"),
|
||||
Opcode.ROXL to InstructionFormat.from("BW,r1"),
|
||||
|
||||
Opcode.JUMP to InstructionFormat(NN, false, false, false, true ),
|
||||
Opcode.JUMPI to InstructionFormat(NN, true, false, false, false),
|
||||
Opcode.CALL to InstructionFormat(NN, false, false, false, true ),
|
||||
Opcode.CALLI to InstructionFormat(NN, true, false, false, false),
|
||||
Opcode.SYSCALL to InstructionFormat(NN, false, false, false, true ),
|
||||
Opcode.RETURN to InstructionFormat(NN, false, false, false, false),
|
||||
Opcode.FFROMUB to InstructionFormat.from("F,fr1,r1"),
|
||||
Opcode.FFROMSB to InstructionFormat.from("F,fr1,r1"),
|
||||
Opcode.FFROMUW to InstructionFormat.from("F,fr1,r1"),
|
||||
Opcode.FFROMSW to InstructionFormat.from("F,fr1,r1"),
|
||||
Opcode.FTOUB to InstructionFormat.from("F,r1,fr1"),
|
||||
Opcode.FTOSB to InstructionFormat.from("F,r1,fr1"),
|
||||
Opcode.FTOUW to InstructionFormat.from("F,r1,fr1"),
|
||||
Opcode.FTOSW to InstructionFormat.from("F,r1,fr1"),
|
||||
|
||||
Opcode.BSTCC to InstructionFormat(NN, false, false,false, true ),
|
||||
Opcode.BSTCS to InstructionFormat(NN, false, false,false, true ),
|
||||
Opcode.BSTEQ to InstructionFormat(NN, false, false,false, true ),
|
||||
Opcode.BSTNE to InstructionFormat(NN, false, false,false, true ),
|
||||
Opcode.BSTNEG to InstructionFormat(NN, false, false,false, true ),
|
||||
Opcode.BSTPOS to InstructionFormat(NN, false, false,false, true ),
|
||||
Opcode.BZ to InstructionFormat(BW, true, false, false, true ),
|
||||
Opcode.BNZ to InstructionFormat(BW, true, false, false, true ),
|
||||
Opcode.BEQ to InstructionFormat(BW, true, true, false, true ),
|
||||
Opcode.BNE to InstructionFormat(BW, true, true, false, true ),
|
||||
Opcode.BLT to InstructionFormat(BW, true, true, false, true ),
|
||||
Opcode.BLTS to InstructionFormat(BW, true, true, false, true ),
|
||||
Opcode.BGT to InstructionFormat(BW, true, true, false, true ),
|
||||
Opcode.BGTS to InstructionFormat(BW, true, true, false, true ),
|
||||
Opcode.BLE to InstructionFormat(BW, true, true, false, true ),
|
||||
Opcode.BLES to InstructionFormat(BW, true, true, false, true ),
|
||||
Opcode.BGE to InstructionFormat(BW, true, true, false, true ),
|
||||
Opcode.BGES to InstructionFormat(BW, true, true, false, true ),
|
||||
Opcode.SEQ to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.SNE to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.SLT to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.SLTS to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.SGT to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.SGTS to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.SLE to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.SLES to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.SGE to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.SGES to InstructionFormat(BW, true, true, true, false),
|
||||
|
||||
Opcode.INC to InstructionFormat(BW, true, false, false, false),
|
||||
Opcode.INCM to InstructionFormat(BW, false, false, false, true ),
|
||||
Opcode.DEC to InstructionFormat(BW, true, false, false, false),
|
||||
Opcode.DECM to InstructionFormat(BW, false, false, false, true ),
|
||||
Opcode.NEG to InstructionFormat(BW, true, false, false, false),
|
||||
Opcode.ADD to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.SUB to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.MUL to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.DIV to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.MOD to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.SQRT to InstructionFormat(BW, true, true, false, false),
|
||||
Opcode.SGN to InstructionFormat(BW, true, true, false, false),
|
||||
Opcode.CMP to InstructionFormat(BW, true, true, false, false),
|
||||
Opcode.EXT to InstructionFormat(BW, true, false, false, false),
|
||||
Opcode.EXTS to InstructionFormat(BW, true, false, false, false),
|
||||
|
||||
Opcode.AND to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.OR to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.XOR to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.ASRX to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.LSRX to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.LSLX to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.ASR to InstructionFormat(BW, true, false, false, false),
|
||||
Opcode.LSR to InstructionFormat(BW, true, false, false, false),
|
||||
Opcode.LSL to InstructionFormat(BW, true, false, false, false),
|
||||
Opcode.ROR to InstructionFormat(BW, true, false, false, false),
|
||||
Opcode.ROXR to InstructionFormat(BW, true, false, false, false),
|
||||
Opcode.ROL to InstructionFormat(BW, true, false, false, false),
|
||||
Opcode.ROXL to InstructionFormat(BW, true, false, false, false),
|
||||
|
||||
Opcode.MSIG to InstructionFormat(BW, true, true, false, false),
|
||||
Opcode.PUSH to InstructionFormat(BW, true, false, false, false),
|
||||
Opcode.POP to InstructionFormat(BW, true, false, false, false),
|
||||
Opcode.CONCAT to InstructionFormat(BW, true, true, true, false),
|
||||
Opcode.CLC to InstructionFormat(NN, false, false, false, false),
|
||||
Opcode.SEC to InstructionFormat(NN, false, false, false, false),
|
||||
Opcode.BREAKPOINT to InstructionFormat(NN, false, false, false, false)
|
||||
Opcode.MSIG to InstructionFormat.from("BW,r1,r2"),
|
||||
Opcode.PUSH to InstructionFormat.from("BW,r1"),
|
||||
Opcode.POP to InstructionFormat.from("BW,r1"),
|
||||
Opcode.CONCAT to InstructionFormat.from("BW,r1,r2,r3"),
|
||||
Opcode.CLC to InstructionFormat.from("N"),
|
||||
Opcode.SEC to InstructionFormat.from("N"),
|
||||
Opcode.BREAKPOINT to InstructionFormat.from("N"),
|
||||
)
|
||||
|
@ -27,11 +27,11 @@ class Memory {
|
||||
}
|
||||
|
||||
fun getUW(address: Int): UShort {
|
||||
return (256u*mem[address+1] + mem[address]).toUShort()
|
||||
return (mem[address] + 256u*mem[address+1]).toUShort()
|
||||
}
|
||||
|
||||
fun getSW(address: Int): Short {
|
||||
return (mem[address+1].toInt()*256 + mem[address].toInt()).toShort()
|
||||
return (mem[address].toInt() + mem[address+1].toInt()*256).toShort()
|
||||
}
|
||||
|
||||
fun setUW(address: Int, value: UShort) {
|
||||
@ -45,6 +45,22 @@ class Memory {
|
||||
mem[address] = uv.toUByte()
|
||||
}
|
||||
|
||||
fun setFloat(address: Int, value: Float) {
|
||||
var bits = value.toBits()
|
||||
mem[address] = bits.toUByte()
|
||||
bits = bits ushr 8
|
||||
mem[address+1] = bits.toUByte()
|
||||
bits = bits ushr 8
|
||||
mem[address+2] = bits.toUByte()
|
||||
bits = bits ushr 8
|
||||
mem[address+3] = bits.toUByte()
|
||||
}
|
||||
|
||||
fun getFloat(address: Int): Float {
|
||||
val bits = mem[address] + 256u*mem[address+1] + 65536u*mem[address+2] + 16777216u*mem[address+3]
|
||||
return Float.fromBits(bits.toInt())
|
||||
}
|
||||
|
||||
// for now, no LONG 32-bits and no FLOAT support.
|
||||
// fun getL(address: Int): UInt {
|
||||
// return mem[address+3] + 256u*mem[address+2] + 65536u*mem[address+1] + 16777216u*mem[address]
|
||||
|
@ -1,13 +1,16 @@
|
||||
package prog8.vm
|
||||
|
||||
/**
|
||||
* 65536 virtual registers of 16 bits wide.
|
||||
* 65536 virtual integer registers of 16 bits wide.
|
||||
* 65536 virtual float registers of 32 bits wide.
|
||||
*/
|
||||
class Registers {
|
||||
private val registers = Array<UShort>(65536) { 0u }
|
||||
private val floatRegisters = Array<Float>(65535) { 0f }
|
||||
|
||||
fun reset() {
|
||||
registers.fill(0u)
|
||||
floatRegisters.fill(0f)
|
||||
}
|
||||
|
||||
fun setUB(reg: Int, value: UByte) {
|
||||
@ -33,4 +36,10 @@ class Registers {
|
||||
fun getUW(reg: Int) = registers[reg]
|
||||
|
||||
fun getSW(reg: Int) = registers[reg].toShort()
|
||||
|
||||
fun getFloat(reg:Int) = floatRegisters[reg]
|
||||
|
||||
fun setFloat(reg:Int, value: Float) {
|
||||
floatRegisters[reg] = value
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package prog8.vm
|
||||
|
||||
import kotlin.math.*
|
||||
import kotlin.random.Random
|
||||
|
||||
/*
|
||||
SYSCALLS:
|
||||
@ -17,8 +16,8 @@ SYSCALLS:
|
||||
8 = gfx_enable ; enable graphics window r0.b = 0 -> lores 320x240, r0.b = 1 -> hires 640x480
|
||||
9 = gfx_clear ; clear graphics window with shade in r0.b
|
||||
10 = gfx_plot ; plot pixel in graphics window, r0.w/r1.w contain X and Y coordinates, r2.b contains brightness
|
||||
11 = rnd ; random BYTE
|
||||
12 = rndw ; random WORD
|
||||
11 = set_carry status flag
|
||||
12 = clear_carry status flag
|
||||
13 = wait ; wait certain amount of jiffies (1/60 sec)
|
||||
14 = waitvsync ; wait on vsync
|
||||
15 = sort_ubyte array
|
||||
@ -41,8 +40,6 @@ SYSCALLS:
|
||||
32 = all_word array
|
||||
33 = reverse_bytes array
|
||||
34 = reverse_words array
|
||||
35 = set_carry status flag
|
||||
36 = clear_carry status flag
|
||||
*/
|
||||
|
||||
enum class Syscall {
|
||||
@ -57,8 +54,8 @@ enum class Syscall {
|
||||
GFX_ENABLE,
|
||||
GFX_CLEAR,
|
||||
GFX_PLOT,
|
||||
RND,
|
||||
RNDW,
|
||||
SET_CARRY,
|
||||
CLEAR_CARRY,
|
||||
WAIT,
|
||||
WAITVSYNC,
|
||||
SORT_UBYTE,
|
||||
@ -80,9 +77,7 @@ enum class Syscall {
|
||||
ALL_BYTE,
|
||||
ALL_WORD,
|
||||
REVERSE_BYTES,
|
||||
REVERSE_WORDS,
|
||||
SET_CARRY,
|
||||
CLEAR_CARRY
|
||||
REVERSE_WORDS
|
||||
}
|
||||
|
||||
object SysCalls {
|
||||
@ -129,12 +124,6 @@ object SysCalls {
|
||||
Syscall.GFX_ENABLE -> vm.gfx_enable()
|
||||
Syscall.GFX_CLEAR -> vm.gfx_clear()
|
||||
Syscall.GFX_PLOT -> vm.gfx_plot()
|
||||
Syscall.RND -> {
|
||||
vm.registers.setUB(0, Random.nextInt().toUByte())
|
||||
}
|
||||
Syscall.RNDW -> {
|
||||
vm.registers.setUW(0, Random.nextInt().toUShort())
|
||||
}
|
||||
Syscall.WAIT -> {
|
||||
val millis = vm.registers.getUW(0).toLong() * 1000/60
|
||||
Thread.sleep(millis)
|
||||
|
@ -6,6 +6,7 @@ import java.util.*
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.math.sign
|
||||
import kotlin.math.sqrt
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
class ProgramExitException(val status: Int): Exception()
|
||||
@ -143,9 +144,10 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
Opcode.MUL -> InsMUL(ins)
|
||||
Opcode.DIV -> InsDIV(ins)
|
||||
Opcode.MOD -> InsMOD(ins)
|
||||
Opcode.SQRT -> InsSQRT(ins)
|
||||
Opcode.SGN -> InsSGN(ins)
|
||||
Opcode.CMP -> InsCMP(ins)
|
||||
Opcode.RND -> InsRND(ins)
|
||||
Opcode.SQRT -> InsSQRT(ins)
|
||||
Opcode.EXT -> InsEXT(ins)
|
||||
Opcode.EXTS -> InsEXTS(ins)
|
||||
Opcode.AND -> InsAND(ins)
|
||||
@ -191,6 +193,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
valueStack.push((value and 255u).toUByte())
|
||||
valueStack.push((value.toInt() ushr 8).toUByte())
|
||||
}
|
||||
VmDataType.FLOAT -> {
|
||||
throw IllegalArgumentException("can't PUSH a float")
|
||||
}
|
||||
}
|
||||
pc++
|
||||
}
|
||||
@ -205,6 +210,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
val lsb = valueStack.pop()
|
||||
(msb.toInt() shl 8) + lsb.toInt()
|
||||
}
|
||||
VmDataType.FLOAT -> {
|
||||
throw IllegalArgumentException("can't POP a float")
|
||||
}
|
||||
}
|
||||
setResultReg(i.reg1!!, value, i.type)
|
||||
pc++
|
||||
@ -649,14 +657,6 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
pc++
|
||||
}
|
||||
|
||||
private fun InsSQRT(i: Instruction) {
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, sqrt(registers.getUB(i.reg2!!).toDouble()).toInt().toUByte())
|
||||
VmDataType.WORD -> registers.setUB(i.reg1!!, sqrt(registers.getUW(i.reg2!!).toDouble()).toInt().toUByte())
|
||||
}
|
||||
pc++
|
||||
}
|
||||
|
||||
private fun InsSGN(i: Instruction) {
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> registers.setSB(i.reg1!!, registers.getSB(i.reg2!!).toInt().sign.toByte())
|
||||
@ -665,6 +665,24 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
pc++
|
||||
}
|
||||
|
||||
private fun InsSQRT(i: Instruction) {
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, sqrt(registers.getUB(i.reg2!!).toDouble()).toInt().toUByte())
|
||||
VmDataType.WORD -> registers.setUB(i.reg1!!, sqrt(registers.getUW(i.reg2!!).toDouble()).toInt().toUByte())
|
||||
VmDataType.FLOAT -> registers.setFloat(i.fpReg1!!, sqrt(registers.getFloat(i.fpReg2!!)))
|
||||
}
|
||||
pc++
|
||||
}
|
||||
|
||||
private fun InsRND(i: Instruction) {
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, Random.nextInt().toUByte())
|
||||
VmDataType.WORD -> registers.setUW(i.reg1!!, Random.nextInt().toUShort())
|
||||
VmDataType.FLOAT -> registers.setFloat(i.fpReg1!!, Random.nextFloat())
|
||||
}
|
||||
pc++
|
||||
}
|
||||
|
||||
private fun InsCMP(i: Instruction) {
|
||||
val comparison: Int
|
||||
when(i.type!!) {
|
||||
@ -680,6 +698,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
comparison = reg1.toInt() - reg2.toInt()
|
||||
statusNegative = (comparison and 0x8000)==0x8000
|
||||
}
|
||||
VmDataType.FLOAT -> {
|
||||
TODO("CMP float")
|
||||
}
|
||||
}
|
||||
if(comparison==0){
|
||||
statusZero = true
|
||||
@ -891,6 +912,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
orig.rotateRight(1)
|
||||
registers.setUW(i.reg1, rotated)
|
||||
}
|
||||
VmDataType.FLOAT -> {
|
||||
throw IllegalArgumentException("can't ROR a float")
|
||||
}
|
||||
}
|
||||
pc++
|
||||
statusCarry = newStatusCarry
|
||||
@ -919,6 +943,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
orig.rotateLeft(1)
|
||||
registers.setUW(i.reg1, rotated)
|
||||
}
|
||||
VmDataType.FLOAT -> {
|
||||
throw IllegalArgumentException("can't ROL a float")
|
||||
}
|
||||
}
|
||||
pc++
|
||||
statusCarry = newStatusCarry
|
||||
@ -952,6 +979,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
return when(i.type) {
|
||||
VmDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), registers.getSB(i.reg2!!).toInt())
|
||||
VmDataType.WORD -> Pair(registers.getSW(i.reg1!!).toInt(), registers.getSW(i.reg2!!).toInt())
|
||||
VmDataType.FLOAT -> {
|
||||
throw IllegalArgumentException("can't use float here")
|
||||
}
|
||||
null -> throw IllegalArgumentException("need type for branch instruction")
|
||||
}
|
||||
}
|
||||
@ -960,6 +990,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
return when(i.type) {
|
||||
VmDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), registers.getUB(i.reg2!!).toUInt())
|
||||
VmDataType.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), registers.getUW(i.reg2!!).toUInt())
|
||||
VmDataType.FLOAT -> {
|
||||
throw IllegalArgumentException("can't use float here")
|
||||
}
|
||||
null -> throw IllegalArgumentException("need type for branch instruction")
|
||||
}
|
||||
}
|
||||
@ -968,6 +1001,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
return when(i.type) {
|
||||
VmDataType.BYTE -> Pair(registers.getUB(i.reg2!!).toUInt(), registers.getUB(i.reg3!!).toUInt())
|
||||
VmDataType.WORD -> Pair(registers.getUW(i.reg2!!).toUInt(), registers.getUW(i.reg3!!).toUInt())
|
||||
VmDataType.FLOAT -> {
|
||||
throw IllegalArgumentException("can't use float here")
|
||||
}
|
||||
null -> throw IllegalArgumentException("need type for logical instruction")
|
||||
}
|
||||
}
|
||||
@ -976,6 +1012,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
return when(i.type) {
|
||||
VmDataType.BYTE -> Pair(registers.getSB(i.reg2!!).toInt(), registers.getSB(i.reg3!!).toInt())
|
||||
VmDataType.WORD -> Pair(registers.getSW(i.reg2!!).toInt(), registers.getSW(i.reg3!!).toInt())
|
||||
VmDataType.FLOAT -> {
|
||||
throw IllegalArgumentException("can't use float here")
|
||||
}
|
||||
null -> throw IllegalArgumentException("need type for logical instruction")
|
||||
}
|
||||
}
|
||||
@ -985,6 +1024,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
return when(ins.type) {
|
||||
VmDataType.BYTE -> Triple(ins.reg1!!, registers.getSB(ins.reg2!!).toInt(), registers.getSB(ins.reg3!!).toInt())
|
||||
VmDataType.WORD -> Triple(ins.reg1!!, registers.getSW(ins.reg2!!).toInt(), registers.getSW(ins.reg3!!).toInt())
|
||||
VmDataType.FLOAT -> {
|
||||
throw IllegalArgumentException("can't use float here")
|
||||
}
|
||||
null -> throw IllegalArgumentException("need type for branch instruction")
|
||||
}
|
||||
}
|
||||
@ -993,6 +1035,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
return when(ins.type) {
|
||||
VmDataType.BYTE -> Triple(ins.reg1!!, registers.getUB(ins.reg2!!).toUInt(), registers.getUB(ins.reg3!!).toUInt())
|
||||
VmDataType.WORD -> Triple(ins.reg1!!, registers.getUW(ins.reg2!!).toUInt(), registers.getUW(ins.reg3!!).toUInt())
|
||||
VmDataType.FLOAT -> {
|
||||
throw IllegalArgumentException("can't use float here")
|
||||
}
|
||||
null -> throw IllegalArgumentException("need type for branch instruction")
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,13 @@ class TestMemory: FunSpec({
|
||||
mem.getUB(1001) shouldBe 0xeau
|
||||
}
|
||||
|
||||
test("32 bits float access") {
|
||||
val mem = Memory()
|
||||
mem.getFloat(1000) shouldBe 0.0
|
||||
mem.setFloat(1000, -9.876543f)
|
||||
mem.getFloat(1000) shouldBe -9.876543f
|
||||
}
|
||||
|
||||
test("setstring and getstring") {
|
||||
val mem = Memory()
|
||||
mem.setString(1000, "******************", false)
|
||||
|
Loading…
Reference in New Issue
Block a user