vm: implement float type casts to integer types

This commit is contained in:
Irmen de Jong 2022-05-02 23:38:32 +02:00
parent 10c8cc35c5
commit 0869789214
6 changed files with 92 additions and 40 deletions

View File

@ -9,6 +9,7 @@ import prog8.code.core.PassByValueDatatypes
import prog8.code.core.SignedDatatypes
import prog8.vm.Opcode
import prog8.vm.VmDataType
import java.nio.channels.FileLock
internal class ExpressionGen(private val codeGen: CodeGen) {
@ -59,7 +60,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1=resultRegister, reg2=addressRegister)
}
}
is PtTypeCast -> code += translate(expr, resultRegister)
is PtTypeCast -> code += translate(expr, resultRegister, resultFpRegister)
is PtPrefix -> code += translate(expr, resultRegister)
is PtArrayIndexer -> code += translate(expr, resultRegister)
is PtBinaryExpression -> code += translate(expr, resultRegister, resultFpRegister)
@ -192,27 +193,29 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
return code
}
private fun translate(cast: PtTypeCast, resultRegister: Int): VmCodeChunk {
private fun translate(cast: PtTypeCast, resultRegister: Int, predefinedResultFpRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
if(cast.type==cast.value.type)
return code
code += translateExpression(cast.value, resultRegister, -1)
val actualResultFpReg = if(predefinedResultFpRegister>=0) predefinedResultFpRegister else codeGen.vmRegisters.nextFreeFloat()
if(cast.value.type==DataType.FLOAT) {
// a cast from float to integer, so evaluate the value into a float register first
code += translateExpression(cast.value, -1, actualResultFpReg)
}
else
code += translateExpression(cast.value, resultRegister, -1)
when(cast.type) {
DataType.UBYTE -> {
when(cast.value.type) {
DataType.BYTE, DataType.UWORD, DataType.WORD -> { /* just keep the LSB as it is */ }
DataType.FLOAT -> {
TODO("float -> ubyte") // float not yet supported
}
DataType.FLOAT -> code += VmCodeInstruction(Opcode.FTOUB, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = actualResultFpReg)
else -> throw AssemblyError("weird cast value type")
}
}
DataType.BYTE -> {
when(cast.value.type) {
DataType.UBYTE, DataType.UWORD, DataType.WORD -> { /* just keep the LSB as it is */ }
DataType.FLOAT -> {
TODO("float -> byte") // float not yet supported
}
DataType.FLOAT -> code += VmCodeInstruction(Opcode.FTOSB, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = actualResultFpReg)
else -> throw AssemblyError("weird cast value type")
}
}
@ -228,7 +231,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
DataType.WORD -> { }
DataType.FLOAT -> {
TODO("float -> uword") // float not yet supported
code += VmCodeInstruction(Opcode.FTOUW, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = actualResultFpReg)
}
else -> throw AssemblyError("weird cast value type")
}
@ -245,13 +248,13 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
DataType.UWORD -> { }
DataType.FLOAT -> {
TODO("float -> word") // float not yet supported
code += VmCodeInstruction(Opcode.FTOSW, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = actualResultFpReg)
}
else -> throw AssemblyError("weird cast value type")
}
}
DataType.FLOAT -> {
TODO("floating point not yet supported")
TODO("floating point to integer cast not yet supported")
// when(cast.value.type) {
// DataType.BYTE -> {
// }

View File

@ -3,7 +3,7 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- vm: implement float type casts to integer types
- compiler: fix crash when print_ub(float as ubyte)
- vm: implement float any, all, reverse, sort
- vm: fix test fp calc result being 0
- vm: get rid of intermediate floats.xxx() functions somehow, instead generate the float instructions directly?

View File

@ -8,22 +8,19 @@
main {
sub start() {
float fl1 = 500.0
float fzero = 0.0
floats.print_f(fl1 / fzero)
float fl = -4.567
float fl2 = fl / 1.0
floats.print_f(fl2)
txt.nl()
txt.print_ub(fl2 as ubyte) ; TODO fix crash source dt size must be less or equal to target dt size
txt.nl()
txt.print_b(fl2 as byte) ; TODO fix crash
txt.nl()
txt.print_uw(fl2 as uword) ; TODO fix crash
txt.nl()
txt.print_w(fl2 as word) ; TODO fix crash
txt.nl()
ubyte ub1 = 50
ubyte ubzero = 0
txt.print_ub(ub1/ubzero)
txt.nl()
uword uw1 = 5000
uword uwzero = 0
txt.print_uw(uw1/uwzero)
txt.nl()
; float fl = 500.0
; txt.print("rad 180 = ")
; floats.print_f(floats.rad(180.0))
; txt.print("rad 360 = ")

View File

@ -82,6 +82,18 @@ class Assembler {
val (_, instr, typestr, rest) = match.groupValues
val opcode = Opcode.valueOf(instr.uppercase())
var type: VmDataType? = convertType(typestr)
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)
}
// parse the operands
val operands = rest.lowercase().split(",").toMutableList()
var reg1: Int? = null
var reg2: Int? = null
@ -129,17 +141,19 @@ class Assembler {
}
}
}
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)
// shift the operands back into place
while(reg1==null && reg2!=null) {
reg1 = reg2
reg2 = reg3
reg3 = null
}
while(fpReg1==null && fpReg2!=null) {
fpReg1 = fpReg2
fpReg2 = fpReg3
fpReg3 = null
}
if(type!=null && type !in formats)
throw IllegalArgumentException("invalid type code for $line")
if(format.reg1 && reg1==null)

View File

@ -330,8 +330,6 @@ data class Instruction(
if (type==VmDataType.FLOAT) {
if(format.fpValue && (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")

View File

@ -172,6 +172,27 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
Opcode.BREAKPOINT -> InsBREAKPOINT()
Opcode.CLC -> { statusCarry = false; pc++ }
Opcode.SEC -> { statusCarry = true; pc++ }
Opcode.FFROMUB -> TODO()
Opcode.FFROMSB -> TODO()
Opcode.FFROMUW -> TODO()
Opcode.FFROMSW -> TODO()
Opcode.FTOUB -> InsFTOUB(ins)
Opcode.FTOSB -> InsFTOSB(ins)
Opcode.FTOUW -> InsFTOUW(ins)
Opcode.FTOSW -> InsFTOSW(ins)
Opcode.FPOW -> TODO()
Opcode.FABS -> TODO()
Opcode.FSIN -> TODO()
Opcode.FCOS -> TODO()
Opcode.FTAN -> TODO()
Opcode.FATAN -> TODO()
Opcode.FLN -> TODO()
Opcode.FLOG -> TODO()
Opcode.FSQRT -> TODO()
Opcode.FROUND -> TODO()
Opcode.FFLOOR -> TODO()
Opcode.FCEIL -> TODO()
else -> throw IllegalArgumentException("invalid opcode ${ins.opcode}")
}
}
@ -1041,6 +1062,26 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
pc++
}
private fun InsFTOUB(i: Instruction) {
registers.setUB(i.reg1!!, registers.getFloat(i.fpReg1!!).toInt().toUByte())
pc++
}
private fun InsFTOUW(i: Instruction) {
registers.setUW(i.reg1!!, registers.getFloat(i.fpReg1!!).toInt().toUShort())
pc++
}
private fun InsFTOSB(i: Instruction) {
registers.setSB(i.reg1!!, registers.getFloat(i.fpReg1!!).toInt().toByte())
pc++
}
private fun InsFTOSW(i: Instruction) {
registers.setSW(i.reg1!!, registers.getFloat(i.fpReg1!!).toInt().toShort())
pc++
}
private fun getBranchOperands(i: Instruction): Pair<Int, Int> {
return when(i.type) {
VmDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), registers.getSB(i.reg2!!).toInt())
@ -1085,7 +1126,6 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
}
}
private fun getSetOnConditionOperands(ins: Instruction): Triple<Int, Int, Int> {
return when(ins.type) {
VmDataType.BYTE -> Triple(ins.reg1!!, registers.getSB(ins.reg2!!).toInt(), registers.getSB(ins.reg3!!).toInt())