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_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

View File

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

View File

@ -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

View File

@ -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")
}

View File

@ -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)

View File

@ -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
}
}
}

View File

@ -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))
}
}

View File

@ -5,42 +5,37 @@ package prog8.vm
Virtual machine:
65536 virtual registers, 16 bits wide, can also be used as 8 bits. r0-r65535
65536 virtual floating point registers (32 bits single precision floats) fr0-fr65535
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
Value stack, max 128 entries of 1 byte each.
Status registers: Carry.
Status registers: Carry, Zero, Negative.
Instruction serialization format possibility:
OPCODE: 1 byte
TYPECODE: 1 byte
REGISTER 1: 2 bytes
REGISTER 2: 2 bytes
REG3/MEMORY/VALUE: 2 bytes
Instructions with Type come in variants 'b' and 'w' (omitting it in the instruction means 'b' by default)
Currently NO support for 24 or 32 bits, and FLOATING POINT is not implemented yet either. FP would be
a separate set of registers and instructions/routines anyway.
Most instructions have an associated data type 'b','w','f'. (omitting it means 'b'/byte).
Currently NO support for 24 or 32 bits integers.
Floating point operations are just 'f' typed regular instructions, and additionally there are
a few fp conversion instructions to
*only* LOAD AND STORE instructions have a possible memory operand, all other instructions use only registers or immediate value.
TODO all floating point arithmethic functions as fp-instructions.
LOAD/STORE
----------
All have type b or w.
All have type b or w or f.
load reg1, value - load immediate value into register
loadm reg1, address - load reg1 with value in memory address
loadi reg1, reg2 - load reg1 with value in memory indirect, memory pointed to by reg2
loadx reg1, reg2, address - load reg1 with value in memory address, indexed by value in reg2
loadr reg1, reg2 - load reg1 with value in register reg2
loadm reg1, address - load reg1 with value at memory address
loadi reg1, reg2 - load reg1 with value at memory indirect, memory pointed to by reg2
loadx reg1, reg2, address - load reg1 with value at memory address, indexed by value in reg2
loadr reg1, reg2 - load reg1 with value at register reg2
storem reg1, address - store reg1 in memory address
storei reg1, reg2 - store reg1 in memory indirect, memory pointed to by reg2
storex reg1, reg2, address - store reg1 in memory address, indexed by value in reg2
storez address - store zero in memory address
storezi reg1 - store zero in memory pointed to by reg1
storezx reg1, address - store zero in memory address, indexed by value in reg
storem reg1, address - store reg1 at memory address
storei reg1, reg2 - store reg1 at memory indirect, memory pointed to by reg2
storex reg1, reg2, address - store reg1 at memory address, indexed by value in reg2
storez address - store zero at memory address
storezi reg1 - store zero at memory pointed to by reg1
storezx reg1, address - store zero at memory address, indexed by value in reg
CONTROL FLOW
@ -91,13 +86,10 @@ sgts reg1, reg2, reg3 - set reg=1 if reg2 > reg3 (signed), ot
sge reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (unsigned), otherwise set reg1=0
sges reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (signed), otherwise set reg1=0
TODO: support for the other prog8 special branching instructions if_XX (bpl, bmi etc.)
but we don't have any 'processor flags' whatsoever in the vm so it's a bit weird
INTEGER ARITHMETIC
------------------
All have type b or w. Note: result types are the same as operand types! E.g. byte*byte->byte.
ARITHMETIC
----------
All have type b or w or f. Note: result types are the same as operand types! E.g. byte*byte->byte.
ext reg1 - reg1 = unsigned extension of reg1 (which in practice just means clearing the MSB / MSW) (latter not yet implemented as we don't have longs yet)
exts reg1 - reg1 = signed extension of reg1 (byte to word, or word to long) (note: latter ext.w, not yet implemented as we don't have longs yet)
@ -111,9 +103,10 @@ sub reg1, reg2, reg3 - reg1 = reg2-reg3 (unsigned + signe
mul reg1, reg2, reg3 - unsigned multiply reg1=reg2*reg3 note: byte*byte->byte, no type extension to word!
div reg1, reg2, reg3 - unsigned division reg1=reg2/reg3 note: division by zero yields max signed int $ff/$ffff
mod reg1, reg2, reg3 - remainder (modulo) of unsigned division reg1=reg2%reg3 note: division by zero yields max signed int $ff/$ffff
sqrt reg1, reg2 - reg1 is the square root of reg2 (for .w and .b both , the result is a byte)
sqrt reg1, reg2 - reg1 is the square root of reg2
sgn reg1, reg2 - reg1 is the sign of reg2 (0, 1 or -1)
cmp reg1, reg2 - set processor status bits C, N, Z according to comparison of reg1 with reg2. (semantics taken from 6502/68000 CMP instruction)
rnd reg1 - get a random number (byte, word or float)
NOTE: because mul/div are constrained (truncated) to remain in 8 or 16 bits, there is NO NEED for separate signed/unsigned mul and div instructions. The result is identical.
@ -137,6 +130,18 @@ rol reg1 - rotate reg1 left by 1bits, not us
roxl reg1 - rotate reg1 left by 1bits, using carry, + set Carry to shifted bit
FLOATING POINT CONVERSIONS
--------------------------
ffromub fpreg1, reg1 - fpreg1 = reg1 from usigned byte
ffromsb fpreg1, reg1 - fpreg1 = reg1 from signed byte
ffromuw fpreg1, reg1 - fpreg1 = reg1 from unsigned word
ffromsw fpreg1, reg1 - fpreg1 = reg1 from signed word
ftoub reg1, fpreg1 - reg1 = fpreg1 as unsigned byte
ftosb reg1, fpreg1 - reg1 = fpreg1 as signed byte
ftouw reg1, fpreg1 - reg1 = fpreg1 as unsigned word
ftosw reg1, fpreg1 - reg1 = fpreg1 as signed word
MISC
----
@ -217,6 +222,7 @@ enum class Opcode {
SQRT,
SGN,
CMP,
RND,
EXT,
EXTS,
@ -234,6 +240,15 @@ enum class Opcode {
ROL,
ROXL,
FFROMUB,
FFROMSB,
FFROMUW,
FFROMSW,
FTOUB,
FTOSB,
FTOUW,
FTOSW,
CLC,
SEC,
PUSH,
@ -256,7 +271,8 @@ val OpcodesWithAddress = setOf(
enum class VmDataType {
BYTE,
WORD
WORD,
FLOAT
// TODO add INT (32-bit)? INT24 (24-bit)?
}
@ -266,14 +282,19 @@ data class Instruction(
val reg1: Int?=null, // 0-$ffff
val reg2: Int?=null, // 0-$ffff
val reg3: Int?=null, // 0-$ffff
val fpReg1: Int?=null, // 0-$ffff
val fpReg2: Int?=null, // 0-$ffff
val fpReg3: Int?=null, // 0-$ffff
val value: Int?=null, // 0-$ffff
val fpValue: Float?=null,
val symbol: List<String>?=null // alternative to value
) {
init {
val format = instructionFormats.getValue(opcode)
if(format.datatypes.isNotEmpty() && type==null)
val formats = instructionFormats.getValue(opcode)
if(type==null && !formats.containsKey(null))
throw IllegalArgumentException("missing type")
val format = formats.getValue(type)
if(format.reg1 && reg1==null ||
format.reg2 && reg2==null ||
format.reg3 && reg3==null)
@ -284,8 +305,18 @@ data class Instruction(
!format.reg3 && reg3!=null)
throw IllegalArgumentException("too many registers")
if (type==VmDataType.FLOAT) {
if(format.value && (fpValue==null && symbol==null))
throw IllegalArgumentException("$opcode: missing a fp-value or symbol")
if (reg1 != null || reg2 != null || reg3 != null)
throw java.lang.IllegalArgumentException("$opcode: floating point instruction can't use integer registers")
} else {
if(format.value && (value==null && symbol==null))
throw IllegalArgumentException("missing a value or symbol")
throw IllegalArgumentException("$opcode: missing a value or symbol")
if (fpReg1 != null || fpReg2 != null || fpReg3 != null)
throw java.lang.IllegalArgumentException("$opcode: integer point instruction can't use floating point registers")
}
}
override fun toString(): String {
@ -308,10 +339,26 @@ data class Instruction(
result.add("r$it")
result.add(",")
}
fpReg1?.let {
result.add("fr$it")
result.add(",")
}
fpReg2?.let {
result.add("fr$it")
result.add(",")
}
fpReg3?.let {
result.add("fr$it")
result.add(",")
}
value?.let {
result.add(it.toString())
result.add(",")
}
fpValue?.let {
result.add(it.toString())
result.add(",")
}
symbol?.let {
result.add("_" + it.joinToString("."))
}
@ -321,98 +368,146 @@ data class Instruction(
}
}
data class InstructionFormat(val datatypes: Set<VmDataType>, val reg1: Boolean, val reg2: Boolean, val reg3: Boolean, val value: Boolean)
data class InstructionFormat(val datatype: VmDataType?,
val reg1: Boolean, val reg2: Boolean, val reg3: Boolean,
val fpReg1: Boolean, val fpReg2: Boolean, val fpReg3: Boolean,
val value: Boolean,
val fpValue: Boolean) {
companion object {
fun from(spec: String): Map<VmDataType?, InstructionFormat> {
val result = mutableMapOf<VmDataType?, InstructionFormat>()
var reg1 = false
var reg2 = false
var reg3 = false
var fpreg1 = false
var fpreg2 = false
var fpreg3 = false
var value = false
var fpvalue = false
for(part in spec.split('|').map{ it.trim() }) {
val splits = part.splitToSequence(',').iterator()
val typespec = splits.next()
while(splits.hasNext()) {
when(splits.next()) {
"r1" -> reg1=true
"r2" -> reg2=true
"r3" -> reg3=true
"fr1" -> fpreg1=true
"fr2" -> fpreg2=true
"fr3" -> fpreg3=true
"v" -> value = true
"fv" -> fpvalue = true
else -> throw IllegalArgumentException(spec)
}
}
if(typespec=="N")
result[null] = InstructionFormat(null, reg1=reg1, reg2=reg2, reg3=reg3, fpReg1=fpreg1, fpReg2=fpreg2, fpReg3=fpreg3, value=value, fpValue=fpvalue)
if('B' in typespec)
result[VmDataType.BYTE] = InstructionFormat(VmDataType.BYTE, reg1=reg1, reg2=reg2, reg3=reg3, fpReg1=fpreg1, fpReg2=fpreg2, fpReg3=fpreg3, value=value, fpValue=fpvalue)
if('W' in typespec)
result[VmDataType.WORD] = InstructionFormat(VmDataType.WORD, reg1=reg1, reg2=reg2, reg3=reg3, fpReg1=fpreg1, fpReg2=fpreg2, fpReg3=fpreg3, value=value, fpValue=fpvalue)
if('F' in typespec)
result[VmDataType.FLOAT] = InstructionFormat(VmDataType.FLOAT, reg1=reg1, reg2=reg2, reg3=reg3, fpReg1=fpreg1, fpReg2=fpreg2, fpReg3=fpreg3, value=value, fpValue=fpvalue)
}
return result
}
}
}
private val NN = emptySet<VmDataType>()
private val BW = setOf(VmDataType.BYTE, VmDataType.WORD)
@Suppress("BooleanLiteralArgument")
val instructionFormats = mutableMapOf(
Opcode.NOP to InstructionFormat(NN, false, false, false, false),
Opcode.LOAD to InstructionFormat(BW, true, false, false, true ),
Opcode.LOADM to InstructionFormat(BW, true, false, false, true ),
Opcode.LOADI to InstructionFormat(BW, true, true, false, false),
Opcode.LOADX to InstructionFormat(BW, true, true, false, true ),
Opcode.LOADR to InstructionFormat(BW, true, true, false, false),
Opcode.SWAPREG to InstructionFormat(BW, true, true, false, false),
Opcode.STOREM to InstructionFormat(BW, true, false, false, true ),
Opcode.STOREI to InstructionFormat(BW, true, true, false, false),
Opcode.STOREX to InstructionFormat(BW, true, true, false, true ),
Opcode.STOREZ to InstructionFormat(BW, false, false, false, true ),
Opcode.STOREZI to InstructionFormat(BW, true, false, false, false),
Opcode.STOREZX to InstructionFormat(BW, true, false, false, true ),
Opcode.NOP to InstructionFormat.from("N"),
Opcode.LOAD to InstructionFormat.from("BW,r1,v | F,fr1,fv"),
Opcode.LOADM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
Opcode.LOADI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
Opcode.LOADX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
Opcode.LOADR to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.SWAPREG to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.STOREM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
Opcode.STOREI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
Opcode.STOREX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
Opcode.STOREZ to InstructionFormat.from("BW,v | F,v"),
Opcode.STOREZI to InstructionFormat.from("BW,r1 | F,r1"),
Opcode.STOREZX to InstructionFormat.from("BW,r1,v | F,r1,v"),
Opcode.JUMP to InstructionFormat.from("N,v"),
Opcode.JUMPI to InstructionFormat.from("N,r1"),
Opcode.CALL to InstructionFormat.from("N,v"),
Opcode.CALLI to InstructionFormat.from("N,r1"),
Opcode.SYSCALL to InstructionFormat.from("N,v"),
Opcode.RETURN to InstructionFormat.from("N"),
Opcode.BSTCC to InstructionFormat.from("N,v"),
Opcode.BSTCS to InstructionFormat.from("N,v"),
Opcode.BSTEQ to InstructionFormat.from("N,v"),
Opcode.BSTNE to InstructionFormat.from("N,v"),
Opcode.BSTNEG to InstructionFormat.from("N,v"),
Opcode.BSTPOS to InstructionFormat.from("N,v"),
Opcode.BZ to InstructionFormat.from("BW,r1,v"),
Opcode.BNZ to InstructionFormat.from("BW,r1,v"),
Opcode.BEQ to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BNE to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BLT to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BLTS to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BGT to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BGTS to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BLE to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BLES to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BGE to InstructionFormat.from("BW,r1,r2,v"),
Opcode.BGES to InstructionFormat.from("BW,r1,r2,v"),
Opcode.SEQ to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.SNE to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.SLT to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.SLTS to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.SGT to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.SGTS to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.SLE to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.SLES to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.SGE to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.SGES to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.INC to InstructionFormat.from("BW,r1"),
Opcode.INCM to InstructionFormat.from("BW,v"),
Opcode.DEC to InstructionFormat.from("BW,r1"),
Opcode.DECM to InstructionFormat.from("BW,v"),
Opcode.NEG to InstructionFormat.from("BW,r1 | F,fr1"),
Opcode.ADD to InstructionFormat.from("BW,r1,r2,r3 | F,fr1,fr2,fr3"),
Opcode.SUB to InstructionFormat.from("BW,r1,r2,r3 | F,fr1,fr2,fr3"),
Opcode.MUL to InstructionFormat.from("BW,r1,r2,r3 | F,fr1,fr2,fr3"),
Opcode.DIV to InstructionFormat.from("BW,r1,r2,r3 | F,fr1,fr2,fr3"),
Opcode.SQRT to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.SGN to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.RND to InstructionFormat.from("BW,r1 | F,fr1"),
Opcode.MOD to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.CMP to InstructionFormat.from("BW,r1,r2"),
Opcode.EXT to InstructionFormat.from("BW,r1"),
Opcode.EXTS to InstructionFormat.from("BW,r1"),
Opcode.AND to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.OR to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.XOR to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.ASRX to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.LSRX to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.LSLX to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.ASR to InstructionFormat.from("BW,r1"),
Opcode.LSR to InstructionFormat.from("BW,r1"),
Opcode.LSL to InstructionFormat.from("BW,r1"),
Opcode.ROR to InstructionFormat.from("BW,r1"),
Opcode.ROXR to InstructionFormat.from("BW,r1"),
Opcode.ROL to InstructionFormat.from("BW,r1"),
Opcode.ROXL to InstructionFormat.from("BW,r1"),
Opcode.JUMP to InstructionFormat(NN, false, false, false, true ),
Opcode.JUMPI to InstructionFormat(NN, true, false, false, false),
Opcode.CALL to InstructionFormat(NN, false, false, false, true ),
Opcode.CALLI to InstructionFormat(NN, true, false, false, false),
Opcode.SYSCALL to InstructionFormat(NN, false, false, false, true ),
Opcode.RETURN to InstructionFormat(NN, false, false, false, false),
Opcode.FFROMUB to InstructionFormat.from("F,fr1,r1"),
Opcode.FFROMSB to InstructionFormat.from("F,fr1,r1"),
Opcode.FFROMUW to InstructionFormat.from("F,fr1,r1"),
Opcode.FFROMSW to InstructionFormat.from("F,fr1,r1"),
Opcode.FTOUB to InstructionFormat.from("F,r1,fr1"),
Opcode.FTOSB to InstructionFormat.from("F,r1,fr1"),
Opcode.FTOUW to InstructionFormat.from("F,r1,fr1"),
Opcode.FTOSW to InstructionFormat.from("F,r1,fr1"),
Opcode.BSTCC to InstructionFormat(NN, false, false,false, true ),
Opcode.BSTCS to InstructionFormat(NN, false, false,false, true ),
Opcode.BSTEQ to InstructionFormat(NN, false, false,false, true ),
Opcode.BSTNE to InstructionFormat(NN, false, false,false, true ),
Opcode.BSTNEG to InstructionFormat(NN, false, false,false, true ),
Opcode.BSTPOS to InstructionFormat(NN, false, false,false, true ),
Opcode.BZ to InstructionFormat(BW, true, false, false, true ),
Opcode.BNZ to InstructionFormat(BW, true, false, false, true ),
Opcode.BEQ to InstructionFormat(BW, true, true, false, true ),
Opcode.BNE to InstructionFormat(BW, true, true, false, true ),
Opcode.BLT to InstructionFormat(BW, true, true, false, true ),
Opcode.BLTS to InstructionFormat(BW, true, true, false, true ),
Opcode.BGT to InstructionFormat(BW, true, true, false, true ),
Opcode.BGTS to InstructionFormat(BW, true, true, false, true ),
Opcode.BLE to InstructionFormat(BW, true, true, false, true ),
Opcode.BLES to InstructionFormat(BW, true, true, false, true ),
Opcode.BGE to InstructionFormat(BW, true, true, false, true ),
Opcode.BGES to InstructionFormat(BW, true, true, false, true ),
Opcode.SEQ to InstructionFormat(BW, true, true, true, false),
Opcode.SNE to InstructionFormat(BW, true, true, true, false),
Opcode.SLT to InstructionFormat(BW, true, true, true, false),
Opcode.SLTS to InstructionFormat(BW, true, true, true, false),
Opcode.SGT to InstructionFormat(BW, true, true, true, false),
Opcode.SGTS to InstructionFormat(BW, true, true, true, false),
Opcode.SLE to InstructionFormat(BW, true, true, true, false),
Opcode.SLES to InstructionFormat(BW, true, true, true, false),
Opcode.SGE to InstructionFormat(BW, true, true, true, false),
Opcode.SGES to InstructionFormat(BW, true, true, true, false),
Opcode.INC to InstructionFormat(BW, true, false, false, false),
Opcode.INCM to InstructionFormat(BW, false, false, false, true ),
Opcode.DEC to InstructionFormat(BW, true, false, false, false),
Opcode.DECM to InstructionFormat(BW, false, false, false, true ),
Opcode.NEG to InstructionFormat(BW, true, false, false, false),
Opcode.ADD to InstructionFormat(BW, true, true, true, false),
Opcode.SUB to InstructionFormat(BW, true, true, true, false),
Opcode.MUL to InstructionFormat(BW, true, true, true, false),
Opcode.DIV to InstructionFormat(BW, true, true, true, false),
Opcode.MOD to InstructionFormat(BW, true, true, true, false),
Opcode.SQRT to InstructionFormat(BW, true, true, false, false),
Opcode.SGN to InstructionFormat(BW, true, true, false, false),
Opcode.CMP to InstructionFormat(BW, true, true, false, false),
Opcode.EXT to InstructionFormat(BW, true, false, false, false),
Opcode.EXTS to InstructionFormat(BW, true, false, false, false),
Opcode.AND to InstructionFormat(BW, true, true, true, false),
Opcode.OR to InstructionFormat(BW, true, true, true, false),
Opcode.XOR to InstructionFormat(BW, true, true, true, false),
Opcode.ASRX to InstructionFormat(BW, true, true, true, false),
Opcode.LSRX to InstructionFormat(BW, true, true, true, false),
Opcode.LSLX to InstructionFormat(BW, true, true, true, false),
Opcode.ASR to InstructionFormat(BW, true, false, false, false),
Opcode.LSR to InstructionFormat(BW, true, false, false, false),
Opcode.LSL to InstructionFormat(BW, true, false, false, false),
Opcode.ROR to InstructionFormat(BW, true, false, false, false),
Opcode.ROXR to InstructionFormat(BW, true, false, false, false),
Opcode.ROL to InstructionFormat(BW, true, false, false, false),
Opcode.ROXL to InstructionFormat(BW, true, false, false, false),
Opcode.MSIG to InstructionFormat(BW, true, true, false, false),
Opcode.PUSH to InstructionFormat(BW, true, false, false, false),
Opcode.POP to InstructionFormat(BW, true, false, false, false),
Opcode.CONCAT to InstructionFormat(BW, true, true, true, false),
Opcode.CLC to InstructionFormat(NN, false, false, false, false),
Opcode.SEC to InstructionFormat(NN, false, false, false, false),
Opcode.BREAKPOINT to InstructionFormat(NN, false, false, false, false)
Opcode.MSIG to InstructionFormat.from("BW,r1,r2"),
Opcode.PUSH to InstructionFormat.from("BW,r1"),
Opcode.POP to InstructionFormat.from("BW,r1"),
Opcode.CONCAT to InstructionFormat.from("BW,r1,r2,r3"),
Opcode.CLC to InstructionFormat.from("N"),
Opcode.SEC to InstructionFormat.from("N"),
Opcode.BREAKPOINT to InstructionFormat.from("N"),
)

View File

@ -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]

View File

@ -1,13 +1,16 @@
package prog8.vm
/**
* 65536 virtual registers of 16 bits wide.
* 65536 virtual integer registers of 16 bits wide.
* 65536 virtual float registers of 32 bits wide.
*/
class Registers {
private val registers = Array<UShort>(65536) { 0u }
private val floatRegisters = Array<Float>(65535) { 0f }
fun reset() {
registers.fill(0u)
floatRegisters.fill(0f)
}
fun setUB(reg: Int, value: UByte) {
@ -33,4 +36,10 @@ class Registers {
fun getUW(reg: Int) = registers[reg]
fun getSW(reg: Int) = registers[reg].toShort()
fun getFloat(reg:Int) = floatRegisters[reg]
fun setFloat(reg:Int, value: Float) {
floatRegisters[reg] = value
}
}

View File

@ -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)

View File

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

View File

@ -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)