vm: some preparations for floating point

This commit is contained in:
Irmen de Jong 2022-04-25 00:10:12 +02:00
parent 6471c0c536
commit 625d5b2313
13 changed files with 497 additions and 310 deletions

View File

@ -14,7 +14,7 @@ class VirtualMachineDefinition: IMachineDefinition {
override val FLOAT_MAX_POSITIVE = Float.MAX_VALUE.toDouble() override val FLOAT_MAX_POSITIVE = Float.MAX_VALUE.toDouble()
override val FLOAT_MAX_NEGATIVE = -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 PROGRAM_LOAD_ADDRESS = 0u // not actually used
override val ESTACK_LO = 0u // not actually used override val ESTACK_LO = 0u // not actually used

View File

@ -61,10 +61,14 @@ internal class VmCodeInstruction(
reg1: Int?=null, // 0-$ffff reg1: Int?=null, // 0-$ffff
reg2: Int?=null, // 0-$ffff reg2: Int?=null, // 0-$ffff
reg3: 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 value: Int?=null, // 0-$ffff
fpValue: Float?=null,
symbol: List<String>?=null // alternative to value symbol: List<String>?=null // alternative to value
): VmCodeLine() { ): 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 { init {
if(value!=null && opcode !in OpcodesWithAddress) { if(value!=null && opcode !in OpcodesWithAddress) {
@ -77,11 +81,12 @@ internal class VmCodeInstruction(
if (value < -32768 || value > 65535) if (value < -32768 || value > 65535)
throw IllegalArgumentException("value out of range for word: $value") throw IllegalArgumentException("value out of range for word: $value")
} }
null -> {} VmDataType.FLOAT, null -> {}
} }
} }
} }
} }
internal class VmCodeLabel(val name: List<String>): VmCodeLine() internal class VmCodeLabel(val name: List<String>): VmCodeLine()
internal class VmCodeComment(val comment: String): VmCodeLine() internal class VmCodeComment(val comment: String): VmCodeLine()

View File

@ -5,6 +5,7 @@ import prog8.code.ast.*
import prog8.code.core.ArrayToElementTypes 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.code.core.WordDatatypes
import prog8.vm.Opcode import prog8.vm.Opcode
import prog8.vm.Syscall import prog8.vm.Syscall
import prog8.vm.VmDataType import prog8.vm.VmDataType
@ -59,8 +60,8 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
val code = VmCodeChunk() val code = VmCodeChunk()
val leftRegister = codeGen.vmRegisters.nextFree() val leftRegister = codeGen.vmRegisters.nextFree()
val rightRegister = codeGen.vmRegisters.nextFree() val rightRegister = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], leftRegister) code += exprGen.translateExpression(call.args[0], leftRegister, 99999)
code += exprGen.translateExpression(call.args[1], rightRegister) code += exprGen.translateExpression(call.args[1], rightRegister, 99999)
code += VmCodeInstruction(Opcode.CMP, codeGen.vmType(call.args[0].type), reg1=leftRegister, reg2=rightRegister) code += VmCodeInstruction(Opcode.CMP, codeGen.vmType(call.args[0].type), reg1=leftRegister, reg2=rightRegister)
return code return code
} }
@ -79,7 +80,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
else -> throw IllegalArgumentException("weird type") else -> throw IllegalArgumentException("weird type")
} }
val code = VmCodeChunk() 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.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal) code += VmCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal)
if(resultRegister!=0) if(resultRegister!=0)
@ -101,7 +102,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
else -> throw IllegalArgumentException("weird type") else -> throw IllegalArgumentException("weird type")
} }
val code = VmCodeChunk() 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.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal) code += VmCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal)
if(resultRegister!=0) if(resultRegister!=0)
@ -113,7 +114,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
val code = VmCodeChunk() val code = VmCodeChunk()
val sourceDt = call.args.single().type val sourceDt = call.args.single().type
if(sourceDt!=DataType.UWORD) { if(sourceDt!=DataType.UWORD) {
code += exprGen.translateExpression(call.args[0], resultRegister) code += exprGen.translateExpression(call.args[0], resultRegister, 99999)
when (sourceDt) { when (sourceDt) {
DataType.UBYTE -> { DataType.UBYTE -> {
code += VmCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister) 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 { private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = 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) code += VmCodeInstruction(Opcode.SGN, codeGen.vmType(call.type), reg1=resultRegister, reg2=0)
return code return code
} }
private fun funcSqrt16(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { private fun funcSqrt16(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = 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) code += VmCodeInstruction(Opcode.SQRT, VmDataType.WORD, reg1=resultRegister, reg2=0)
return code return code
} }
@ -173,14 +174,14 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
private fun funcPush(call: PtBuiltinFunctionCall): VmCodeChunk { private fun funcPush(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = 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) code += VmCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=0)
return code return code
} }
private fun funcPushw(call: PtBuiltinFunctionCall): VmCodeChunk { private fun funcPushw(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = 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) code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1=0)
return code return code
} }
@ -191,8 +192,8 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
val leftReg = codeGen.vmRegisters.nextFree() val leftReg = codeGen.vmRegisters.nextFree()
val rightReg = codeGen.vmRegisters.nextFree() val rightReg = codeGen.vmRegisters.nextFree()
val code = VmCodeChunk() val code = VmCodeChunk()
code += exprGen.translateExpression(left, leftReg) code += exprGen.translateExpression(left, leftReg, 99999)
code += exprGen.translateExpression(right, rightReg) code += exprGen.translateExpression(right, rightReg, 99999)
code += assignRegisterTo(left, rightReg) code += assignRegisterTo(left, rightReg)
code += assignRegisterTo(right, leftReg) code += assignRegisterTo(right, leftReg)
return code return code
@ -209,7 +210,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
else -> throw IllegalArgumentException("weird type to reverse") else -> throw IllegalArgumentException("weird type to reverse")
} }
val code = VmCodeChunk() 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.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal) code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
return code return code
@ -229,7 +230,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
else -> throw IllegalArgumentException("weird type to sort") else -> throw IllegalArgumentException("weird type to sort")
} }
val code = VmCodeChunk() 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.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal) code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
return code return code
@ -239,8 +240,8 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
val msbReg = codeGen.vmRegisters.nextFree() val msbReg = codeGen.vmRegisters.nextFree()
val lsbReg = codeGen.vmRegisters.nextFree() val lsbReg = codeGen.vmRegisters.nextFree()
val code = VmCodeChunk() val code = VmCodeChunk()
code += exprGen.translateExpression(call.args[0], msbReg) code += exprGen.translateExpression(call.args[0], msbReg, 99999)
code += exprGen.translateExpression(call.args[1], lsbReg) code += exprGen.translateExpression(call.args[1], lsbReg, 99999)
code += VmCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg, reg3=lsbReg) code += VmCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg, reg3=lsbReg)
return code return code
} }
@ -250,12 +251,12 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
val valueReg = codeGen.vmRegisters.nextFree() val valueReg = codeGen.vmRegisters.nextFree()
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) code += exprGen.translateExpression(call.args[1], valueReg, 99999)
code += VmCodeInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value=address) code += VmCodeInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value=address)
} else { } else {
val addressReg = codeGen.vmRegisters.nextFree() val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], addressReg) code += exprGen.translateExpression(call.args[0], addressReg, 99999)
code += exprGen.translateExpression(call.args[1], valueReg) code += exprGen.translateExpression(call.args[1], valueReg, 99999)
code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2 = addressReg) code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2 = addressReg)
} }
return code return code
@ -266,12 +267,12 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
val valueReg = codeGen.vmRegisters.nextFree() val valueReg = codeGen.vmRegisters.nextFree()
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) code += exprGen.translateExpression(call.args[1], valueReg, 99999)
code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value=address) code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value=address)
} else { } else {
val addressReg = codeGen.vmRegisters.nextFree() val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], addressReg) code += exprGen.translateExpression(call.args[0], addressReg, 99999)
code += exprGen.translateExpression(call.args[1], valueReg) code += exprGen.translateExpression(call.args[1], valueReg, 99999)
code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2 = addressReg) code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
} }
return code 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) code += VmCodeInstruction(Opcode.LOADM, VmDataType.WORD, reg1 = resultRegister, value = address)
} else { } else {
val addressReg = codeGen.vmRegisters.nextFree() 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) code += VmCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2 = addressReg)
} }
return code 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) code += VmCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1 = resultRegister, value = address)
} else { } else {
val addressReg = codeGen.vmRegisters.nextFree() 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) code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2 = addressReg)
} }
return code return code
@ -305,17 +306,13 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
private fun funcRnd(resultRegister: Int): VmCodeChunk { private fun funcRnd(resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
code += VmCodeInstruction(Opcode.SYSCALL, value= Syscall.RND.ordinal) code += VmCodeInstruction(Opcode.RND, VmDataType.BYTE, reg1=resultRegister)
if(resultRegister!=0)
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
return code return code
} }
private fun funcRndw(resultRegister: Int): VmCodeChunk { private fun funcRndw(resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
code += VmCodeInstruction(Opcode.SYSCALL, value= Syscall.RNDW.ordinal) code += VmCodeInstruction(Opcode.RND, VmDataType.WORD, reg1=resultRegister)
if(resultRegister!=0)
code += VmCodeInstruction(Opcode.LOADR, VmDataType.WORD, reg1=resultRegister, reg2=0)
return code return code
} }
@ -339,14 +336,14 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = 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. // 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 return code
} }
private fun funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { private fun funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = 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) 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. // 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 return code
@ -362,7 +359,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
private fun funcSyscall1(call: PtBuiltinFunctionCall): VmCodeChunk { private fun funcSyscall1(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
val callNr = (call.args[0] as PtNumber).number.toInt() 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) code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
return code return code
} }
@ -374,8 +371,8 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
codeGen.vmRegisters.nextFree() codeGen.vmRegisters.nextFree()
} }
val callNr = (call.args[0] as PtNumber).number.toInt() 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 += exprGen.translateExpression(call.args[2], 1) code += exprGen.translateExpression(call.args[2], 1, 99999)
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr) code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1) code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1)
return code return code
@ -389,9 +386,9 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
codeGen.vmRegisters.nextFree() codeGen.vmRegisters.nextFree()
} }
val callNr = (call.args[0] as PtNumber).number.toInt() 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 += exprGen.translateExpression(call.args[2], 1) code += exprGen.translateExpression(call.args[2], 1, 99999)
code += exprGen.translateExpression(call.args[3], 2) code += exprGen.translateExpression(call.args[3], 2, 99999)
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr) code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 2) code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 2)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1) 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 { private fun funcRolRor2(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val vmDt = codeGen.vmType(call.args[0].type) val vmDt = codeGen.vmType(call.args[0].type)
val code = VmCodeChunk() 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 += VmCodeInstruction(opcode, vmDt, reg1=resultRegister)
code += assignRegisterTo(call.args[0], resultRegister) code += assignRegisterTo(call.args[0], resultRegister)
return code return code

View File

@ -10,15 +10,25 @@ import kotlin.math.pow
internal class VmRegisterPool { 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 peekNext() = firstFree
fun peekNextFloat() = firstFreeFloat
fun nextFree(): Int { fun nextFree(): Int {
val result = firstFree val result = firstFree
firstFree++ firstFree++
if(firstFree>65535) 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 return result
} }
} }
@ -141,7 +151,7 @@ class CodeGen(internal val program: PtProgram,
val valueReg = vmRegisters.nextFree() val valueReg = vmRegisters.nextFree()
val choiceReg = vmRegisters.nextFree() val choiceReg = vmRegisters.nextFree()
val valueDt = vmType(whenStmt.value.type) 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 choices = whenStmt.choices.children.map {it as PtWhenChoice }
val endLabel = createLabelName() val endLabel = createLabelName()
for (choice in choices) { for (choice in choices) {
@ -239,8 +249,8 @@ class CodeGen(internal val program: PtProgram,
val loopLabel = createLabelName() val loopLabel = createLabelName()
val code = VmCodeChunk() val code = VmCodeChunk()
code += expressionEval.translateExpression(iterable.to, endvalueReg) code += expressionEval.translateExpression(iterable.to, endvalueReg, 99999)
code += expressionEval.translateExpression(iterable.from, indexReg) code += expressionEval.translateExpression(iterable.from, indexReg, 99999)
code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, value=loopvarAddress) code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, value=loopvarAddress)
code += VmCodeLabel(loopLabel) code += VmCodeLabel(loopLabel)
code += translateNode(forLoop.statements) code += translateNode(forLoop.statements)
@ -448,7 +458,7 @@ class CodeGen(internal val program: PtProgram,
val conditionReg = vmRegisters.nextFree() val conditionReg = vmRegisters.nextFree()
val vmDt = vmType(condition.type) val vmDt = vmType(condition.type)
val code = VmCodeChunk() val code = VmCodeChunk()
code += expressionEval.translateExpression(condition, conditionReg) code += expressionEval.translateExpression(condition, conditionReg, 99999)
if(ifElse.elseScope.children.isNotEmpty()) { if(ifElse.elseScope.children.isNotEmpty()) {
// if and else parts // if and else parts
val elseLabel = createLabelName() val elseLabel = createLabelName()
@ -494,7 +504,7 @@ class CodeGen(internal val program: PtProgram,
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, value=address) code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, value=address)
} else { } else {
val addressReg = vmRegisters.nextFree() 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(Opcode.LOADI, vmDt, reg1 = resultReg, reg2 = addressReg)
code += VmCodeInstruction(operation, vmDt, reg1 = resultReg) code += VmCodeInstruction(operation, vmDt, reg1 = resultReg)
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1 = resultReg, reg2 = addressReg) 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) code += VmCodeInstruction(memOp, vmDt, value=variableAddr)
} else { } else {
val indexReg = vmRegisters.nextFree() 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(Opcode.LOADX, vmDt, reg1=resultReg, reg2=indexReg, value=variableAddr)
code += VmCodeInstruction(operation, vmDt, reg1=resultReg) code += VmCodeInstruction(operation, vmDt, reg1=resultReg)
code += VmCodeInstruction(Opcode.STOREX, vmDt, reg1=resultReg, reg2=indexReg, value=variableAddr) 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 code = VmCodeChunk()
val counterReg = vmRegisters.nextFree() val counterReg = vmRegisters.nextFree()
val vmDt = vmType(repeat.count.type) val vmDt = vmType(repeat.count.type)
code += expressionEval.translateExpression(repeat.count, counterReg) code += expressionEval.translateExpression(repeat.count, counterReg, 99999)
val repeatLabel = createLabelName() val repeatLabel = createLabelName()
code += VmCodeLabel(repeatLabel) code += VmCodeLabel(repeatLabel)
code += translateNode(repeat.statements) code += translateNode(repeat.statements)
@ -576,7 +586,7 @@ class CodeGen(internal val program: PtProgram,
(assignment.value as PtMachineRegister).register (assignment.value as PtMachineRegister).register
} else { } else {
val reg = vmRegisters.nextFree() val reg = vmRegisters.nextFree()
code += expressionEval.translateExpression(assignment.value, reg) code += expressionEval.translateExpression(assignment.value, reg, 99999)
reg reg
} }
val ident = assignment.target.identifier val ident = assignment.target.identifier
@ -598,7 +608,7 @@ class CodeGen(internal val program: PtProgram,
code += VmCodeInstruction(Opcode.STOREM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr) code += VmCodeInstruction(Opcode.STOREM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr)
} else { } else {
val indexReg = vmRegisters.nextFree() 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) 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()) code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
} else { } else {
val addressReg = vmRegisters.nextFree() 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) code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
} }
} }
@ -622,7 +632,7 @@ class CodeGen(internal val program: PtProgram,
val value = ret.value val value = ret.value
if(value!=null) { if(value!=null) {
// Call Convention: return value is always returned in r0 // Call Convention: return value is always returned in r0
code += expressionEval.translateExpression(value, 0) code += expressionEval.translateExpression(value, 0, 99999)
} }
code += VmCodeInstruction(Opcode.RETURN) code += VmCodeInstruction(Opcode.RETURN)
return code return code
@ -658,6 +668,7 @@ class CodeGen(internal val program: PtProgram,
DataType.BYTE -> VmDataType.BYTE DataType.BYTE -> VmDataType.BYTE
DataType.UWORD, DataType.UWORD,
DataType.WORD -> VmDataType.WORD DataType.WORD -> VmDataType.WORD
DataType.FLOAT -> VmDataType.FLOAT
in PassByReferenceDatatypes -> VmDataType.WORD in PassByReferenceDatatypes -> VmDataType.WORD
else -> throw AssemblyError("no vm datatype for $type") else -> throw AssemblyError("no vm datatype for $type")
} }

View File

@ -12,7 +12,7 @@ import prog8.vm.VmDataType
internal class ExpressionGen(private val codeGen: CodeGen) { 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) require(codeGen.vmRegisters.peekNext() > resultRegister)
val code = VmCodeChunk() val code = VmCodeChunk()
@ -49,7 +49,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
code += VmCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1=resultRegister, value = address) code += VmCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1=resultRegister, value = address)
} else { } else {
val addressRegister = codeGen.vmRegisters.nextFree() 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) code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1=resultRegister, reg2=addressRegister)
} }
} }
@ -91,7 +91,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
} }
val code = VmCodeChunk() val code = VmCodeChunk()
code += translateExpression(segments[0], valueReg) code += translateExpression(segments[0], valueReg, 99999)
for (segment in segments.subList(1, segments.size-1)) { for (segment in segments.subList(1, segments.size-1)) {
val sourceReg = valueReg val sourceReg = valueReg
val sourceDt = valueDt val sourceDt = valueDt
@ -100,16 +100,16 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
valueReg = codeGen.vmRegisters.nextFree() valueReg = codeGen.vmRegisters.nextFree()
} }
val segmentWithImplicitArgument = addImplicitArgToSegment(segment, sourceReg, sourceDt) val segmentWithImplicitArgument = addImplicitArgToSegment(segment, sourceReg, sourceDt)
code += translateExpression(segmentWithImplicitArgument, valueReg) code += translateExpression(segmentWithImplicitArgument, valueReg, 99999)
} }
val segWithArg = addImplicitArgToSegment(segments.last(), valueReg, valueDt) val segWithArg = addImplicitArgToSegment(segments.last(), valueReg, valueDt)
code += translateExpression(segWithArg, resultRegister) code += translateExpression(segWithArg, resultRegister, 99999)
return code return code
} }
private fun translate(check: PtContainmentCheck, resultRegister: Int): VmCodeChunk { private fun translate(check: PtContainmentCheck, resultRegister: Int): VmCodeChunk {
val code = 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 val iterable = codeGen.symbolTable.flat.getValue(check.iterable.targetName) as StStaticVariable
when(iterable.dt) { when(iterable.dt) {
DataType.STR -> { DataType.STR -> {
@ -149,7 +149,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val memOffset = (arrayIx.index as PtNumber).number.toInt() * eltSize val memOffset = (arrayIx.index as PtNumber).number.toInt() * eltSize
code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, value=arrayLocation+memOffset) code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, value=arrayLocation+memOffset)
} else { } else {
code += translateExpression(arrayIx.index, idxReg) code += translateExpression(arrayIx.index, idxReg, 99999)
if(eltSize>1) if(eltSize>1)
code += codeGen.multiplyByConst(VmDataType.BYTE, idxReg, eltSize) code += codeGen.multiplyByConst(VmDataType.BYTE, idxReg, eltSize)
code += VmCodeInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, value = arrayLocation) 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 { private fun translate(expr: PtPrefix, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
code += translateExpression(expr.value, resultRegister) code += translateExpression(expr.value, resultRegister, 99999)
val vmDt = codeGen.vmType(expr.type) val vmDt = codeGen.vmType(expr.type)
when(expr.operator) { when(expr.operator) {
"+" -> { } "+" -> { }
@ -190,7 +190,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val code = VmCodeChunk() val code = VmCodeChunk()
if(cast.type==cast.value.type) if(cast.type==cast.value.type)
return code return code
code += translateExpression(cast.value, resultRegister) code += translateExpression(cast.value, resultRegister, 99999)
when(cast.type) { when(cast.type) {
DataType.UBYTE -> { DataType.UBYTE -> {
when(cast.value.type) { when(cast.value.type) {
@ -297,8 +297,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val code = VmCodeChunk() val code = VmCodeChunk()
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) code += translateExpression(binExpr.left, leftResultReg, 99999)
code += translateExpression(binExpr.right, rightResultReg) code += translateExpression(binExpr.right, rightResultReg, 99999)
val ins = if(signed) { val ins = if(signed) {
if(greaterEquals) Opcode.SGES else Opcode.SGTS if(greaterEquals) Opcode.SGES else Opcode.SGTS
} else { } else {
@ -318,8 +318,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val code = VmCodeChunk() val code = VmCodeChunk()
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) code += translateExpression(binExpr.left, leftResultReg, 99999)
code += translateExpression(binExpr.right, rightResultReg) code += translateExpression(binExpr.right, rightResultReg, 99999)
val ins = if(signed) { val ins = if(signed) {
if(lessEquals) Opcode.SLES else Opcode.SLTS if(lessEquals) Opcode.SLES else Opcode.SLTS
} else { } else {
@ -333,8 +333,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val code = VmCodeChunk() val code = VmCodeChunk()
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) code += translateExpression(binExpr.left, leftResultReg, 99999)
code += translateExpression(binExpr.right, rightResultReg) code += translateExpression(binExpr.right, rightResultReg, 99999)
val opcode = if(notEquals) Opcode.SNE else Opcode.SEQ val opcode = if(notEquals) Opcode.SNE else Opcode.SEQ
code += VmCodeInstruction(opcode, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg) code += VmCodeInstruction(opcode, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
return code return code
@ -344,8 +344,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val code = VmCodeChunk() val code = VmCodeChunk()
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) code += translateExpression(binExpr.left, leftResultReg, 99999)
code += translateExpression(binExpr.right, rightResultReg) code += translateExpression(binExpr.right, rightResultReg, 99999)
val opc = if(signed) Opcode.ASRX else Opcode.LSRX val opc = if(signed) Opcode.ASRX else Opcode.LSRX
code += VmCodeInstruction(opc, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg) code += VmCodeInstruction(opc, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
return code return code
@ -355,8 +355,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val code = VmCodeChunk() val code = VmCodeChunk()
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) code += translateExpression(binExpr.left, leftResultReg, 99999)
code += translateExpression(binExpr.right, rightResultReg) code += translateExpression(binExpr.right, rightResultReg, 99999)
code += VmCodeInstruction(Opcode.LSLX, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg) code += VmCodeInstruction(Opcode.LSLX, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
return code return code
} }
@ -365,8 +365,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val code = VmCodeChunk() val code = VmCodeChunk()
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) code += translateExpression(binExpr.left, leftResultReg, 99999)
code += translateExpression(binExpr.right, rightResultReg) code += translateExpression(binExpr.right, rightResultReg, 99999)
code += VmCodeInstruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg) code += VmCodeInstruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
return code return code
} }
@ -375,8 +375,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val code = VmCodeChunk() val code = VmCodeChunk()
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) code += translateExpression(binExpr.left, leftResultReg, 99999)
code += translateExpression(binExpr.right, rightResultReg) code += translateExpression(binExpr.right, rightResultReg, 99999)
code += VmCodeInstruction(Opcode.AND, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg) code += VmCodeInstruction(Opcode.AND, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
return code return code
} }
@ -385,8 +385,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val code = VmCodeChunk() val code = VmCodeChunk()
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) code += translateExpression(binExpr.left, leftResultReg, 99999)
code += translateExpression(binExpr.right, rightResultReg) code += translateExpression(binExpr.right, rightResultReg, 99999)
code += VmCodeInstruction(Opcode.OR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg) code += VmCodeInstruction(Opcode.OR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
return code return code
} }
@ -395,8 +395,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val code = VmCodeChunk() val code = VmCodeChunk()
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) code += translateExpression(binExpr.left, leftResultReg, 99999)
code += translateExpression(binExpr.right, rightResultReg) code += translateExpression(binExpr.right, rightResultReg, 99999)
code += VmCodeInstruction(Opcode.MOD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg) code += VmCodeInstruction(Opcode.MOD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
return code return code
} }
@ -405,14 +405,14 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val code = VmCodeChunk() val code = VmCodeChunk()
val constFactorRight = binExpr.right as? PtNumber val constFactorRight = binExpr.right as? PtNumber
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
code += translateExpression(binExpr.left, resultRegister) code += translateExpression(binExpr.left, resultRegister, 99999)
val factor = constFactorRight.number.toInt() val factor = constFactorRight.number.toInt()
code += codeGen.divideByConst(vmDt, resultRegister, factor) code += codeGen.divideByConst(vmDt, resultRegister, factor)
} else { } else {
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) code += translateExpression(binExpr.left, leftResultReg, 99999)
code += translateExpression(binExpr.right, rightResultReg) code += translateExpression(binExpr.right, rightResultReg, 99999)
code += VmCodeInstruction(Opcode.DIV, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg) code += VmCodeInstruction(Opcode.DIV, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
} }
return code return code
@ -423,18 +423,18 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val constFactorLeft = binExpr.left as? PtNumber val constFactorLeft = binExpr.left as? PtNumber
val constFactorRight = binExpr.right as? PtNumber val constFactorRight = binExpr.right as? PtNumber
if(constFactorLeft!=null && constFactorLeft.type!=DataType.FLOAT) { if(constFactorLeft!=null && constFactorLeft.type!=DataType.FLOAT) {
code += translateExpression(binExpr.right, resultRegister) code += translateExpression(binExpr.right, resultRegister, 99999)
val factor = constFactorLeft.number.toInt() val factor = constFactorLeft.number.toInt()
code += codeGen.multiplyByConst(vmDt, resultRegister, factor) code += codeGen.multiplyByConst(vmDt, resultRegister, factor)
} else if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { } else if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
code += translateExpression(binExpr.left, resultRegister) code += translateExpression(binExpr.left, resultRegister, 99999)
val factor = constFactorRight.number.toInt() val factor = constFactorRight.number.toInt()
code += codeGen.multiplyByConst(vmDt, resultRegister, factor) code += codeGen.multiplyByConst(vmDt, resultRegister, factor)
} else { } else {
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) code += translateExpression(binExpr.left, leftResultReg, 99999)
code += translateExpression(binExpr.right, rightResultReg) code += translateExpression(binExpr.right, rightResultReg, 99999)
code += VmCodeInstruction(Opcode.MUL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg) code += VmCodeInstruction(Opcode.MUL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
} }
return code return code
@ -443,14 +443,14 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk { private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
if((binExpr.right as? PtNumber)?.number==1.0) { 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) code += VmCodeInstruction(Opcode.DEC, vmDt, reg1=resultRegister)
} }
else { else {
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) code += translateExpression(binExpr.left, leftResultReg, 99999)
code += translateExpression(binExpr.right, rightResultReg) code += translateExpression(binExpr.right, rightResultReg, 99999)
code += VmCodeInstruction(Opcode.SUB, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg) code += VmCodeInstruction(Opcode.SUB, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
} }
return code return code
@ -459,18 +459,18 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
private fun operatorPlus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk { private fun operatorPlus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
if((binExpr.left as? PtNumber)?.number==1.0) { 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) code += VmCodeInstruction(Opcode.INC, vmDt, reg1=resultRegister)
} }
else if((binExpr.right as? PtNumber)?.number==1.0) { 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) code += VmCodeInstruction(Opcode.INC, vmDt, reg1=resultRegister)
} }
else { else {
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) code += translateExpression(binExpr.left, leftResultReg, 99999)
code += translateExpression(binExpr.right, rightResultReg) code += translateExpression(binExpr.right, rightResultReg, 99999)
code += VmCodeInstruction(Opcode.ADD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg) code += VmCodeInstruction(Opcode.ADD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
} }
return code return code
@ -481,7 +481,7 @@ 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 argReg = codeGen.vmRegisters.nextFree() val argReg = codeGen.vmRegisters.nextFree()
code += translateExpression(arg, argReg) code += translateExpression(arg, argReg, 99999)
val vmDt = codeGen.vmType(parameter.type) val vmDt = codeGen.vmType(parameter.type)
val mem = codeGen.allocations.get(fcall.functionName + parameter.name) val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=argReg, value=mem) code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=argReg, value=mem)

View File

@ -1,5 +1,5 @@
%import textio %import textio
; %import floats ;%import floats
%import conv %import conv
%zeropage dontuse %zeropage dontuse
@ -7,39 +7,34 @@
; 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 {
sub newstring() -> str {
return "new"
}
sub start() { sub start() {
str name = "irmen\n" uword uw = 15555
txt.print(name) uword squw = sqrt16(uw)
name = "pipo\n" txt.print_uw(squw)
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()
}
txt.nl() txt.nl()
txt.print_ub0(99) squw = rndw()
txt.print_uw(squw)
txt.spc() txt.spc()
txt.print_ub(99) squw = rndw()
txt.print_uw(squw)
txt.nl() txt.nl()
txt.print_uw0(9988)
squw = rnd()
txt.print_uw(squw)
txt.spc() txt.spc()
txt.print_uw(9988) squw = rnd()
txt.print_uw(squw)
txt.nl() 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 ; float f1 = 1.555
; floats.print_f(floats.sin(f1)) ; floats.print_f(floats.sin(f1))
; txt.nl() ; txt.nl()
@ -71,24 +66,24 @@ main {
; "ln", "log2", "sqrt", "rad", ; "ln", "log2", "sqrt", "rad",
; "deg", "round", "floor", "ceil", "rndf" ; "deg", "round", "floor", "ceil", "rndf"
; ; a "pixelshader": ; a "pixelshader":
; void syscall1(8, 0) ; enable lo res creen void syscall1(8, 0) ; enable lo res creen
; ubyte shifter ubyte shifter
;
; ; pokemon(1,0) ; pokemon(1,0)
;
; repeat { repeat {
; uword xx uword xx
; uword yy = 0 uword yy = 0
; repeat 240 { repeat 240 {
; xx = 0 xx = 0
; repeat 320 { repeat 320 {
; syscall3(10, xx, yy, xx*yy + shifter) ; plot pixel syscall3(10, xx, yy, xx*yy + shifter) ; plot pixel
; xx++ xx++
; } }
; yy++ yy++
; } }
; shifter+=4 shifter+=4
; } }
} }
} }

View File

@ -45,6 +45,13 @@ class Assembler {
address += 2 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") else -> throw IllegalArgumentException("mem instr $what")
} }
} }
@ -113,10 +120,18 @@ class Assembler {
} }
} }
} }
val format = instructionFormats.getValue(opcode) val formats = instructionFormats.getValue(opcode)
if(type==null && format.datatypes.isNotEmpty()) val format: InstructionFormat
type= VmDataType.BYTE if(type !in formats) {
if(type!=null && type !in format.datatypes) 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") throw IllegalArgumentException("invalid type code for $line")
if(format.reg1 && reg1==null) if(format.reg1 && reg1==null)
throw IllegalArgumentException("needs reg1 for $line") throw IllegalArgumentException("needs reg1 for $line")
@ -144,10 +159,13 @@ class Assembler {
if (value < -32768 || value > 65535) if (value < -32768 || value > 65535)
throw IllegalArgumentException("value out of range for word: $value") throw IllegalArgumentException("value out of range for word: $value")
} }
VmDataType.FLOAT -> {
throw IllegalArgumentException("can't use float here")
}
null -> {} null -> {}
} }
} }
program.add(Instruction(opcode, type, reg1, reg2, reg3, value)) program.add(Instruction(opcode, type, reg1, reg2, reg3, value=value))
} }
} }

View File

@ -5,42 +5,37 @@ package prog8.vm
Virtual machine: Virtual machine:
65536 virtual registers, 16 bits wide, can also be used as 8 bits. r0-r65535 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. 65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
Value stack, max 128 entries of 1 byte each. Value stack, max 128 entries of 1 byte each.
Status registers: Carry. Status registers: Carry, Zero, Negative.
Most instructions have an associated data type 'b','w','f'. (omitting it means 'b'/byte).
Instruction serialization format possibility: Currently NO support for 24 or 32 bits integers.
Floating point operations are just 'f' typed regular instructions, and additionally there are
OPCODE: 1 byte a few fp conversion instructions to
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.
*only* LOAD AND STORE instructions have a possible memory operand, all other instructions use only registers or immediate value. *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 LOAD/STORE
---------- ----------
All have type b or w. All have type b or w or f.
load reg1, value - load immediate value into register load reg1, value - load immediate value into register
loadm reg1, address - load reg1 with value in memory address loadm reg1, address - load reg1 with value at memory address
loadi reg1, reg2 - load reg1 with value in memory indirect, memory pointed to by reg2 loadi reg1, reg2 - load reg1 with value at memory indirect, memory pointed to by reg2
loadx reg1, reg2, address - load reg1 with value in memory address, indexed by value in reg2 loadx reg1, reg2, address - load reg1 with value at memory address, indexed by value in reg2
loadr reg1, reg2 - load reg1 with value in register reg2 loadr reg1, reg2 - load reg1 with value at register reg2
storem reg1, address - store reg1 in memory address storem reg1, address - store reg1 at memory address
storei reg1, reg2 - store reg1 in 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 in 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 in memory address storez address - store zero at memory address
storezi reg1 - store zero in memory pointed to by reg1 storezi reg1 - store zero at memory pointed to by reg1
storezx reg1, address - store zero in memory address, indexed by value in reg storezx reg1, address - store zero at memory address, indexed by value in reg
CONTROL FLOW 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 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 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
ARITHMETIC
INTEGER 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. 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) (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) 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! 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 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 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) 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) 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. 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,20 +130,32 @@ rol reg1 - rotate reg1 left by 1bits, not us
roxl reg1 - rotate reg1 left by 1bits, using carry, + set Carry to shifted bit 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 MISC
---- ----
clc - clear Carry status bit 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 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 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 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
*/ */
@ -217,6 +222,7 @@ enum class Opcode {
SQRT, SQRT,
SGN, SGN,
CMP, CMP,
RND,
EXT, EXT,
EXTS, EXTS,
@ -234,6 +240,15 @@ enum class Opcode {
ROL, ROL,
ROXL, ROXL,
FFROMUB,
FFROMSB,
FFROMUW,
FFROMSW,
FTOUB,
FTOSB,
FTOUW,
FTOSW,
CLC, CLC,
SEC, SEC,
PUSH, PUSH,
@ -256,7 +271,8 @@ val OpcodesWithAddress = setOf(
enum class VmDataType { enum class VmDataType {
BYTE, BYTE,
WORD WORD,
FLOAT
// TODO add INT (32-bit)? INT24 (24-bit)? // TODO add INT (32-bit)? INT24 (24-bit)?
} }
@ -266,14 +282,19 @@ data class Instruction(
val reg1: Int?=null, // 0-$ffff val reg1: Int?=null, // 0-$ffff
val reg2: Int?=null, // 0-$ffff val reg2: Int?=null, // 0-$ffff
val reg3: 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 value: Int?=null, // 0-$ffff
val fpValue: Float?=null,
val symbol: List<String>?=null // alternative to value val symbol: List<String>?=null // alternative to value
) { ) {
init { init {
val format = instructionFormats.getValue(opcode) val formats = instructionFormats.getValue(opcode)
if(format.datatypes.isNotEmpty() && type==null) if(type==null && !formats.containsKey(null))
throw IllegalArgumentException("missing type") throw IllegalArgumentException("missing type")
val format = formats.getValue(type)
if(format.reg1 && reg1==null || if(format.reg1 && reg1==null ||
format.reg2 && reg2==null || format.reg2 && reg2==null ||
format.reg3 && reg3==null) format.reg3 && reg3==null)
@ -284,8 +305,18 @@ data class Instruction(
!format.reg3 && reg3!=null) !format.reg3 && reg3!=null)
throw IllegalArgumentException("too many registers") throw IllegalArgumentException("too many registers")
if(format.value && (value==null && symbol==null))
throw IllegalArgumentException("missing a value or symbol") 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("$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 { override fun toString(): String {
@ -308,10 +339,26 @@ data class Instruction(
result.add("r$it") result.add("r$it")
result.add(",") 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 { value?.let {
result.add(it.toString()) result.add(it.toString())
result.add(",") result.add(",")
} }
fpValue?.let {
result.add(it.toString())
result.add(",")
}
symbol?.let { symbol?.let {
result.add("_" + it.joinToString(".")) 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") @Suppress("BooleanLiteralArgument")
val instructionFormats = mutableMapOf( val instructionFormats = mutableMapOf(
Opcode.NOP to InstructionFormat(NN, false, false, false, false), Opcode.NOP to InstructionFormat.from("N"),
Opcode.LOAD to InstructionFormat(BW, true, false, false, true ), Opcode.LOAD to InstructionFormat.from("BW,r1,v | F,fr1,fv"),
Opcode.LOADM to InstructionFormat(BW, true, false, false, true ), Opcode.LOADM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
Opcode.LOADI to InstructionFormat(BW, true, true, false, false), Opcode.LOADI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
Opcode.LOADX to InstructionFormat(BW, true, true, false, true ), Opcode.LOADX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
Opcode.LOADR to InstructionFormat(BW, true, true, false, false), Opcode.LOADR to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.SWAPREG to InstructionFormat(BW, true, true, false, false), Opcode.SWAPREG to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.STOREM to InstructionFormat(BW, true, false, false, true ), Opcode.STOREM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
Opcode.STOREI to InstructionFormat(BW, true, true, false, false), Opcode.STOREI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
Opcode.STOREX to InstructionFormat(BW, true, true, false, true ), Opcode.STOREX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
Opcode.STOREZ to InstructionFormat(BW, false, false, false, true ), Opcode.STOREZ to InstructionFormat.from("BW,v | F,v"),
Opcode.STOREZI to InstructionFormat(BW, true, false, false, false), Opcode.STOREZI to InstructionFormat.from("BW,r1 | F,r1"),
Opcode.STOREZX to InstructionFormat(BW, true, false, false, true ), 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.FFROMUB to InstructionFormat.from("F,fr1,r1"),
Opcode.JUMPI to InstructionFormat(NN, true, false, false, false), Opcode.FFROMSB to InstructionFormat.from("F,fr1,r1"),
Opcode.CALL to InstructionFormat(NN, false, false, false, true ), Opcode.FFROMUW to InstructionFormat.from("F,fr1,r1"),
Opcode.CALLI to InstructionFormat(NN, true, false, false, false), Opcode.FFROMSW to InstructionFormat.from("F,fr1,r1"),
Opcode.SYSCALL to InstructionFormat(NN, false, false, false, true ), Opcode.FTOUB to InstructionFormat.from("F,r1,fr1"),
Opcode.RETURN to InstructionFormat(NN, false, false, false, false), 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.MSIG to InstructionFormat.from("BW,r1,r2"),
Opcode.BSTCS to InstructionFormat(NN, false, false,false, true ), Opcode.PUSH to InstructionFormat.from("BW,r1"),
Opcode.BSTEQ to InstructionFormat(NN, false, false,false, true ), Opcode.POP to InstructionFormat.from("BW,r1"),
Opcode.BSTNE to InstructionFormat(NN, false, false,false, true ), Opcode.CONCAT to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.BSTNEG to InstructionFormat(NN, false, false,false, true ), Opcode.CLC to InstructionFormat.from("N"),
Opcode.BSTPOS to InstructionFormat(NN, false, false,false, true ), Opcode.SEC to InstructionFormat.from("N"),
Opcode.BZ to InstructionFormat(BW, true, false, false, true ), Opcode.BREAKPOINT to InstructionFormat.from("N"),
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)
) )

View File

@ -27,11 +27,11 @@ class Memory {
} }
fun getUW(address: Int): UShort { 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 { 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) { fun setUW(address: Int, value: UShort) {
@ -45,6 +45,22 @@ class Memory {
mem[address] = uv.toUByte() 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. // for now, no LONG 32-bits and no FLOAT support.
// fun getL(address: Int): UInt { // fun getL(address: Int): UInt {
// return mem[address+3] + 256u*mem[address+2] + 65536u*mem[address+1] + 16777216u*mem[address] // return mem[address+3] + 256u*mem[address+2] + 65536u*mem[address+1] + 16777216u*mem[address]

View File

@ -1,13 +1,16 @@
package prog8.vm 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 { class Registers {
private val registers = Array<UShort>(65536) { 0u } private val registers = Array<UShort>(65536) { 0u }
private val floatRegisters = Array<Float>(65535) { 0f }
fun reset() { fun reset() {
registers.fill(0u) registers.fill(0u)
floatRegisters.fill(0f)
} }
fun setUB(reg: Int, value: UByte) { fun setUB(reg: Int, value: UByte) {
@ -33,4 +36,10 @@ class Registers {
fun getUW(reg: Int) = registers[reg] fun getUW(reg: Int) = registers[reg]
fun getSW(reg: Int) = registers[reg].toShort() fun getSW(reg: Int) = registers[reg].toShort()
fun getFloat(reg:Int) = floatRegisters[reg]
fun setFloat(reg:Int, value: Float) {
floatRegisters[reg] = value
}
} }

View File

@ -1,7 +1,6 @@
package prog8.vm package prog8.vm
import kotlin.math.* import kotlin.math.*
import kotlin.random.Random
/* /*
SYSCALLS: SYSCALLS:
@ -17,8 +16,8 @@ SYSCALLS:
8 = gfx_enable ; enable graphics window r0.b = 0 -> lores 320x240, r0.b = 1 -> hires 640x480 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 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 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 11 = set_carry status flag
12 = rndw ; random WORD 12 = clear_carry status flag
13 = wait ; wait certain amount of jiffies (1/60 sec) 13 = wait ; wait certain amount of jiffies (1/60 sec)
14 = waitvsync ; wait on vsync 14 = waitvsync ; wait on vsync
15 = sort_ubyte array 15 = sort_ubyte array
@ -41,8 +40,6 @@ SYSCALLS:
32 = all_word array 32 = all_word array
33 = reverse_bytes array 33 = reverse_bytes array
34 = reverse_words array 34 = reverse_words array
35 = set_carry status flag
36 = clear_carry status flag
*/ */
enum class Syscall { enum class Syscall {
@ -57,8 +54,8 @@ enum class Syscall {
GFX_ENABLE, GFX_ENABLE,
GFX_CLEAR, GFX_CLEAR,
GFX_PLOT, GFX_PLOT,
RND, SET_CARRY,
RNDW, CLEAR_CARRY,
WAIT, WAIT,
WAITVSYNC, WAITVSYNC,
SORT_UBYTE, SORT_UBYTE,
@ -80,9 +77,7 @@ enum class Syscall {
ALL_BYTE, ALL_BYTE,
ALL_WORD, ALL_WORD,
REVERSE_BYTES, REVERSE_BYTES,
REVERSE_WORDS, REVERSE_WORDS
SET_CARRY,
CLEAR_CARRY
} }
object SysCalls { object SysCalls {
@ -129,12 +124,6 @@ object SysCalls {
Syscall.GFX_ENABLE -> vm.gfx_enable() Syscall.GFX_ENABLE -> vm.gfx_enable()
Syscall.GFX_CLEAR -> vm.gfx_clear() Syscall.GFX_CLEAR -> vm.gfx_clear()
Syscall.GFX_PLOT -> vm.gfx_plot() 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 -> { Syscall.WAIT -> {
val millis = vm.registers.getUW(0).toLong() * 1000/60 val millis = vm.registers.getUW(0).toLong() * 1000/60
Thread.sleep(millis) Thread.sleep(millis)

View File

@ -6,6 +6,7 @@ import java.util.*
import kotlin.math.roundToInt import kotlin.math.roundToInt
import kotlin.math.sign import kotlin.math.sign
import kotlin.math.sqrt import kotlin.math.sqrt
import kotlin.random.Random
class ProgramExitException(val status: Int): Exception() class ProgramExitException(val status: Int): Exception()
@ -143,9 +144,10 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
Opcode.MUL -> InsMUL(ins) Opcode.MUL -> InsMUL(ins)
Opcode.DIV -> InsDIV(ins) Opcode.DIV -> InsDIV(ins)
Opcode.MOD -> InsMOD(ins) Opcode.MOD -> InsMOD(ins)
Opcode.SQRT -> InsSQRT(ins)
Opcode.SGN -> InsSGN(ins) Opcode.SGN -> InsSGN(ins)
Opcode.CMP -> InsCMP(ins) Opcode.CMP -> InsCMP(ins)
Opcode.RND -> InsRND(ins)
Opcode.SQRT -> InsSQRT(ins)
Opcode.EXT -> InsEXT(ins) Opcode.EXT -> InsEXT(ins)
Opcode.EXTS -> InsEXTS(ins) Opcode.EXTS -> InsEXTS(ins)
Opcode.AND -> InsAND(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 and 255u).toUByte())
valueStack.push((value.toInt() ushr 8).toUByte()) valueStack.push((value.toInt() ushr 8).toUByte())
} }
VmDataType.FLOAT -> {
throw IllegalArgumentException("can't PUSH a float")
}
} }
pc++ pc++
} }
@ -205,6 +210,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
val lsb = valueStack.pop() val lsb = valueStack.pop()
(msb.toInt() shl 8) + lsb.toInt() (msb.toInt() shl 8) + lsb.toInt()
} }
VmDataType.FLOAT -> {
throw IllegalArgumentException("can't POP a float")
}
} }
setResultReg(i.reg1!!, value, i.type) setResultReg(i.reg1!!, value, i.type)
pc++ pc++
@ -649,14 +657,6 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
pc++ 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) { private fun InsSGN(i: Instruction) {
when(i.type!!) { when(i.type!!) {
VmDataType.BYTE -> registers.setSB(i.reg1!!, registers.getSB(i.reg2!!).toInt().sign.toByte()) 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++ 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) { private fun InsCMP(i: Instruction) {
val comparison: Int val comparison: Int
when(i.type!!) { when(i.type!!) {
@ -680,6 +698,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
comparison = reg1.toInt() - reg2.toInt() comparison = reg1.toInt() - reg2.toInt()
statusNegative = (comparison and 0x8000)==0x8000 statusNegative = (comparison and 0x8000)==0x8000
} }
VmDataType.FLOAT -> {
TODO("CMP float")
}
} }
if(comparison==0){ if(comparison==0){
statusZero = true statusZero = true
@ -891,6 +912,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
orig.rotateRight(1) orig.rotateRight(1)
registers.setUW(i.reg1, rotated) registers.setUW(i.reg1, rotated)
} }
VmDataType.FLOAT -> {
throw IllegalArgumentException("can't ROR a float")
}
} }
pc++ pc++
statusCarry = newStatusCarry statusCarry = newStatusCarry
@ -919,6 +943,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
orig.rotateLeft(1) orig.rotateLeft(1)
registers.setUW(i.reg1, rotated) registers.setUW(i.reg1, rotated)
} }
VmDataType.FLOAT -> {
throw IllegalArgumentException("can't ROL a float")
}
} }
pc++ pc++
statusCarry = newStatusCarry statusCarry = newStatusCarry
@ -952,6 +979,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
return when(i.type) { return when(i.type) {
VmDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), registers.getSB(i.reg2!!).toInt()) 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.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") null -> throw IllegalArgumentException("need type for branch instruction")
} }
} }
@ -960,6 +990,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
return when(i.type) { return when(i.type) {
VmDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), registers.getUB(i.reg2!!).toUInt()) 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.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") null -> throw IllegalArgumentException("need type for branch instruction")
} }
} }
@ -968,6 +1001,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
return when(i.type) { return when(i.type) {
VmDataType.BYTE -> Pair(registers.getUB(i.reg2!!).toUInt(), registers.getUB(i.reg3!!).toUInt()) 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.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") null -> throw IllegalArgumentException("need type for logical instruction")
} }
} }
@ -976,6 +1012,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
return when(i.type) { return when(i.type) {
VmDataType.BYTE -> Pair(registers.getSB(i.reg2!!).toInt(), registers.getSB(i.reg3!!).toInt()) 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.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") null -> throw IllegalArgumentException("need type for logical instruction")
} }
} }
@ -985,6 +1024,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
return when(ins.type) { return when(ins.type) {
VmDataType.BYTE -> Triple(ins.reg1!!, registers.getSB(ins.reg2!!).toInt(), registers.getSB(ins.reg3!!).toInt()) 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.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") null -> throw IllegalArgumentException("need type for branch instruction")
} }
} }
@ -993,6 +1035,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
return when(ins.type) { return when(ins.type) {
VmDataType.BYTE -> Triple(ins.reg1!!, registers.getUB(ins.reg2!!).toUInt(), registers.getUB(ins.reg3!!).toUInt()) 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.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") null -> throw IllegalArgumentException("need type for branch instruction")
} }
} }

View File

@ -44,6 +44,13 @@ class TestMemory: FunSpec({
mem.getUB(1001) shouldBe 0xeau 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") { test("setstring and getstring") {
val mem = Memory() val mem = Memory()
mem.setString(1000, "******************", false) mem.setString(1000, "******************", false)