From 625d5b231376b97febcff9dddfcf840e048495af Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 25 Apr 2022 00:10:12 +0200 Subject: [PATCH] vm: some preparations for floating point --- .../virtual/VirtualMachineDefinition.kt | 2 +- .../prog8/codegen/virtual/AssemblyProgram.kt | 9 +- .../prog8/codegen/virtual/BuiltinFuncGen.kt | 73 ++-- .../src/prog8/codegen/virtual/CodeGen.kt | 39 +- .../prog8/codegen/virtual/ExpressionGen.kt | 84 ++-- examples/test.p8 | 85 ++-- virtualmachine/src/prog8/vm/Assembler.kt | 28 +- virtualmachine/src/prog8/vm/Instructions.kt | 365 +++++++++++------- virtualmachine/src/prog8/vm/Memory.kt | 20 +- virtualmachine/src/prog8/vm/Registers.kt | 11 +- virtualmachine/src/prog8/vm/SysCalls.kt | 21 +- virtualmachine/src/prog8/vm/VirtualMachine.kt | 63 ++- virtualmachine/test/TestMemory.kt | 7 + 13 files changed, 497 insertions(+), 310 deletions(-) diff --git a/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt b/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt index 28aca4118..8436fc1dc 100644 --- a/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt +++ b/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt @@ -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 diff --git a/codeGenVirtual/src/prog8/codegen/virtual/AssemblyProgram.kt b/codeGenVirtual/src/prog8/codegen/virtual/AssemblyProgram.kt index b32d7e47c..72584b42d 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/AssemblyProgram.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/AssemblyProgram.kt @@ -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?=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): VmCodeLine() internal class VmCodeComment(val comment: String): VmCodeLine() diff --git a/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt index b8806d92a..4db8a6bef 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt @@ -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 diff --git a/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt index 563ca6b3a..e26fbab30 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt @@ -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") } diff --git a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt index 4a077cd92..6d505f66c 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt @@ -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) diff --git a/examples/test.p8 b/examples/test.p8 index a434ff761..eed7de156 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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 + } } } diff --git a/virtualmachine/src/prog8/vm/Assembler.kt b/virtualmachine/src/prog8/vm/Assembler.kt index 4eecbbbdf..88446af57 100644 --- a/virtualmachine/src/prog8/vm/Assembler.kt +++ b/virtualmachine/src/prog8/vm/Assembler.kt @@ -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)) } } diff --git a/virtualmachine/src/prog8/vm/Instructions.kt b/virtualmachine/src/prog8/vm/Instructions.kt index 158af74be..6a046227d 100644 --- a/virtualmachine/src/prog8/vm/Instructions.kt +++ b/virtualmachine/src/prog8/vm/Instructions.kt @@ -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,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 +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 ---- -clc - clear Carry status bit -sec - set Carry status bit -nop - do nothing -breakpoint - trigger a breakpoint -copy reg1, reg2, length - copy memory from ptrs in reg1 to reg3, length bytes -copyz reg1, reg2 - copy memory from ptrs in reg1 to reg3, stop after first 0-byte -msig [b, w] reg1, reg2 - reg1 becomes the most significant byte (or word) of the word (or int) in reg2 (.w not yet implemented; requires 32 bits regs) -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) -push [b, w] reg1 - push value in reg1 on the stack -pop [b, w] reg1 - pop value from stack into reg1 +clc - clear Carry status bit +sec - set Carry status bit +nop - do nothing +breakpoint - trigger a breakpoint +copy reg1, reg2, length - copy memory from ptrs in reg1 to reg3, length bytes +copyz reg1, reg2 - copy memory from ptrs in reg1 to reg3, stop after first 0-byte +msig [b, w] reg1, reg2 - reg1 becomes the most significant byte (or word) of the word (or int) in reg2 (.w not yet implemented; requires 32 bits regs) +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) +push [b, w] reg1 - push value in reg1 on the stack +pop [b, w] reg1 - pop value from stack into reg1 */ @@ -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?=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(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 { @@ -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, 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 { + val result = mutableMapOf() + 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() -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"), ) diff --git a/virtualmachine/src/prog8/vm/Memory.kt b/virtualmachine/src/prog8/vm/Memory.kt index 8c356458e..74f7b4a89 100644 --- a/virtualmachine/src/prog8/vm/Memory.kt +++ b/virtualmachine/src/prog8/vm/Memory.kt @@ -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] diff --git a/virtualmachine/src/prog8/vm/Registers.kt b/virtualmachine/src/prog8/vm/Registers.kt index c99e3ae28..055c95311 100644 --- a/virtualmachine/src/prog8/vm/Registers.kt +++ b/virtualmachine/src/prog8/vm/Registers.kt @@ -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(65536) { 0u } + private val floatRegisters = Array(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 + } } diff --git a/virtualmachine/src/prog8/vm/SysCalls.kt b/virtualmachine/src/prog8/vm/SysCalls.kt index 4cac559b3..0af9f55c4 100644 --- a/virtualmachine/src/prog8/vm/SysCalls.kt +++ b/virtualmachine/src/prog8/vm/SysCalls.kt @@ -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) diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 1b6c9e42d..5c36ea3a5 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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") } } diff --git a/virtualmachine/test/TestMemory.kt b/virtualmachine/test/TestMemory.kt index 47edd5cba..2f85a6b11 100644 --- a/virtualmachine/test/TestMemory.kt +++ b/virtualmachine/test/TestMemory.kt @@ -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)