vm: treat floats as 64 bits doubles. 0.0 printed as "0".

This commit is contained in:
Irmen de Jong 2023-11-20 23:19:08 +01:00
parent ab4bcdf12d
commit af5ca2d0b8
14 changed files with 139 additions and 98 deletions

View File

@ -12,7 +12,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 // 32-bits floating point
override val FLOAT_MEM_SIZE = 8 // 64-bits double
override val PROGRAM_LOAD_ADDRESS = 0u // not actually used
override val BSSHIGHRAM_START = 0u // not actually used
@ -22,8 +22,8 @@ class VirtualMachineDefinition: IMachineDefinition {
override fun getFloatAsmBytes(num: Number): String {
// little endian binary representation
val bits = num.toFloat().toBits().toUInt()
val hexStr = bits.toString(16).padStart(8, '0')
val bits = num.toDouble().toBits().toULong()
val hexStr = bits.toString(16).padStart(16, '0')
val parts = hexStr.chunked(2).map { "\$" + it }
return parts.joinToString(", ")
}

View File

@ -33,7 +33,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val code = IRCodeChunk(null, null)
if(vmDt==IRDataType.FLOAT) {
val resultFpRegister = codeGen.registers.nextFreeFloat()
code += IRInstruction(Opcode.LOAD, vmDt, fpReg1 = resultFpRegister, immediateFp = expr.number.toFloat())
code += IRInstruction(Opcode.LOAD, vmDt, fpReg1 = resultFpRegister, immediateFp = expr.number)
ExpressionCodeResult(code, vmDt,-1, resultFpRegister)
}
else {
@ -713,7 +713,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
val tr = translateExpression(binExpr.left)
addToResult(result, tr, -1, tr.resultFpReg)
val factor = constFactorRight.number.toFloat()
val factor = constFactorRight.number
result += codeGen.divideByConstFloat(tr.resultFpReg, factor)
return ExpressionCodeResult(result, vmDt, -1, tr.resultFpReg)
} else {
@ -769,13 +769,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
return if(constFactorLeft!=null) {
val tr = translateExpression(binExpr.right)
addToResult(result, tr, -1, tr.resultFpReg)
val factor = constFactorLeft.number.toFloat()
val factor = constFactorLeft.number
result += codeGen.multiplyByConstFloat(tr.resultFpReg, factor)
ExpressionCodeResult(result, vmDt, -1, tr.resultFpReg)
} else if(constFactorRight!=null) {
val tr = translateExpression(binExpr.left)
addToResult(result, tr, -1, tr.resultFpReg)
val factor = constFactorRight.number.toFloat()
val factor = constFactorRight.number
result += codeGen.multiplyByConstFloat(tr.resultFpReg, factor)
ExpressionCodeResult(result, vmDt, -1, tr.resultFpReg)
} else {
@ -823,7 +823,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
return if(binExpr.right is PtNumber) {
val tr = translateExpression(binExpr.left)
addToResult(result, tr, -1, tr.resultFpReg)
addInstr(result, IRInstruction(Opcode.SUB, vmDt, fpReg1 = tr.resultFpReg, immediateFp = (binExpr.right as PtNumber).number.toFloat()), null)
addInstr(result, IRInstruction(Opcode.SUB, vmDt, fpReg1 = tr.resultFpReg, immediateFp = (binExpr.right as PtNumber).number), null)
ExpressionCodeResult(result, vmDt, -1, tr.resultFpReg)
} else {
val leftTr = translateExpression(binExpr.left)
@ -878,7 +878,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
return if(binExpr.right is PtNumber) {
val tr = translateExpression(binExpr.left)
addToResult(result, tr, -1, tr.resultFpReg)
addInstr(result, IRInstruction(Opcode.ADD, vmDt, fpReg1 = tr.resultFpReg, immediateFp = (binExpr.right as PtNumber).number.toFloat()), null)
addInstr(result, IRInstruction(Opcode.ADD, vmDt, fpReg1 = tr.resultFpReg, immediateFp = (binExpr.right as PtNumber).number), null)
ExpressionCodeResult(result, vmDt, -1, tr.resultFpReg)
} else {
val leftTr = translateExpression(binExpr.left)
@ -950,7 +950,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val constFactorRight = operand as? PtNumber
if(vmDt==IRDataType.FLOAT) {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
val factor = constFactorRight.number.toFloat()
val factor = constFactorRight.number
result += codeGen.divideByConstFloatInplace(knownAddress, symbol, factor)
} else {
val tr = translateExpression(operand)
@ -999,7 +999,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val constFactorRight = operand as? PtNumber
if(vmDt==IRDataType.FLOAT) {
if(constFactorRight!=null) {
val factor = constFactorRight.number.toFloat()
val factor = constFactorRight.number
result += codeGen.multiplyByConstFloatInplace(knownAddress, symbol, factor)
} else {
val tr = translateExpression(operand)
@ -1324,7 +1324,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
// in-place modify a memory location
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, address = knownAddress)
it += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = numberReg, immediateFp = operand.number.toFloat())
it += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = numberReg, immediateFp = operand.number)
it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = numberReg)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, immediate = 0)
it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpResultReg, reg2=cmpReg, reg3=zeroReg)
@ -1335,7 +1335,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
// in-place modify a symbol (variable)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, labelSymbol = symbol)
it += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = numberReg, immediateFp = operand.number.toFloat())
it += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = numberReg, immediateFp = operand.number)
it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = numberReg)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, immediate = 0)
it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpResultReg, reg2=cmpReg, reg3=zeroReg)

View File

@ -710,23 +710,23 @@ class IRCodeGen(
return code
}
internal fun multiplyByConstFloat(fpReg: Int, factor: Float): IRCodeChunk {
internal fun multiplyByConstFloat(fpReg: Int, factor: Double): IRCodeChunk {
val code = IRCodeChunk(null, null)
if(factor==1f)
if(factor==1.0)
return code
code += if(factor==0f) {
IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = fpReg, immediateFp = 0f)
code += if(factor==0.0) {
IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = fpReg, immediateFp = 0.0)
} else {
IRInstruction(Opcode.MUL, IRDataType.FLOAT, fpReg1 = fpReg, immediateFp = factor)
}
return code
}
internal fun multiplyByConstFloatInplace(knownAddress: Int?, symbol: String?, factor: Float): IRCodeChunk {
internal fun multiplyByConstFloatInplace(knownAddress: Int?, symbol: String?, factor: Double): IRCodeChunk {
val code = IRCodeChunk(null, null)
if(factor==1f)
if(factor==1.0)
return code
if(factor==0f) {
if(factor==0.0) {
code += if(knownAddress!=null)
IRInstruction(Opcode.STOREZM, IRDataType.FLOAT, address = knownAddress)
else
@ -807,25 +807,25 @@ class IRCodeGen(
return code
}
internal fun divideByConstFloat(fpReg: Int, factor: Float): IRCodeChunk {
internal fun divideByConstFloat(fpReg: Int, factor: Double): IRCodeChunk {
val code = IRCodeChunk(null, null)
if(factor==1f)
if(factor==1.0)
return code
code += if(factor==0f) {
IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = fpReg, immediateFp = Float.MAX_VALUE)
code += if(factor==0.0) {
IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = fpReg, immediateFp = Double.MAX_VALUE)
} else {
IRInstruction(Opcode.DIVS, IRDataType.FLOAT, fpReg1 = fpReg, immediateFp = factor)
}
return code
}
internal fun divideByConstFloatInplace(knownAddress: Int?, symbol: String?, factor: Float): IRCodeChunk {
internal fun divideByConstFloatInplace(knownAddress: Int?, symbol: String?, factor: Double): IRCodeChunk {
val code = IRCodeChunk(null, null)
if(factor==1f)
if(factor==1.0)
return code
if(factor==0f) {
if(factor==0.0) {
val maxvalueReg = registers.nextFreeFloat()
code += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = maxvalueReg, immediateFp = Float.MAX_VALUE)
code += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = maxvalueReg, immediateFp = Double.MAX_VALUE)
code += if(knownAddress!=null)
IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = maxvalueReg, address = knownAddress)
else
@ -1189,7 +1189,7 @@ class IRCodeGen(
addToResult(result, leftTr, -1, leftTr.resultFpReg)
result += IRCodeChunk(null, null).also {
val rightFpReg = registers.nextFreeFloat()
it += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = rightFpReg, immediateFp = 0f)
it += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = rightFpReg, immediateFp = 0.0)
it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=compResultReg, fpReg1 = leftTr.resultFpReg, fpReg2 = rightFpReg)
}
when (condition.operator) {

View File

@ -23,8 +23,7 @@ Future Things and Ideas
Compiler:
- Currently "320*240/8/8" gives integer overflow, so: allow constant integer subexpressions to contain out of range integers (>65535 etc) as long as the final constant value is within byte/word range.
- allow 'chained' array indexing for expressions: value = ptrarray[0][0]
- allow 'chained' array indexing for assign targets: ptrarray[0][0] = 42 this is just evaluating the lhs as a uword pointer expression
- Multidimensional arrays and chained indexing, purely as syntactic sugar over regular arrays.
- fix the other cases of "TODO index could also be a binexpr" (in AssignmentAsmGen), but these are for float arrays so rarely used.
- [much work:] more support for (64tass) SEGMENTS ?
@ -68,6 +67,7 @@ Libraries:
Optimizations:
- give a warning for variables that could be a const - or even make them a const (if not @shared)?
- treat every scalar variable decl with initialization value, as const by default, unless the variable gets assigned to somewhere (or has its address taken, or is @shared)
- VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served?
for instance, vars used inside loops first, then loopvars, then uwords used as pointers, then the rest

View File

@ -1,11 +1,14 @@
%import textio
%import floats
%zeropage basicsafe
main {
sub start() {
str key = "test"
txt.print(":")
if key != ":" {
cx16.r0++
}
float fl1 = 999.8877
float fl2 = sqrt(fl1) * fl1 + fl1*33.44
floats.print_f(fl2)
txt.nl()
fl1=0
floats.print_f(fl1)
}
}

View File

@ -11,7 +11,7 @@ Intermediate Representation instructions for the IR Virtual machine.
Specs of the virtual machine this will run on:
Program to execute is not stored in the system memory, it's just a separate list of instructions.
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 virtual floating point registers (64 bits double precision) 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 flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC!!!
@ -21,7 +21,7 @@ Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by t
Instruction set is mostly a load/store architecture, there are few instructions operating on memory directly.
Value types: integers (.b=byte=8 bits, .w=word=16 bits) and float (.f=32 bits). Omitting it defaults to b if the instruction requires a type.
Value types: integers (.b=byte=8 bits, .w=word=16 bits) and float (.f=64 bits). Omitting it defaults to b if the instruction requires a type.
Currently ther is NO support for 24 or 32 bits integers.
There is no distinction between signed and unsigned integers.
Instead, a different instruction is used if a distinction should be made (for example div and divs).
@ -691,7 +691,7 @@ data class IRInstruction(
val fpReg1: Int?=null, // 0-$ffff
val fpReg2: Int?=null, // 0-$ffff
val immediate: Int?=null, // 0-$ff or $ffff if word
val immediateFp: Float?=null,
val immediateFp: Double?=null,
val address: Int?=null, // 0-$ffff
val labelSymbol: String?=null, // symbolic label name as alternative to address (so only for Branch/jump/call Instructions!)
var branchTarget: IRCodeChunkBase? = null, // Will be linked after loading in IRProgram.linkChunks()! This is the chunk that the branch labelSymbol points to.

View File

@ -62,15 +62,15 @@ fun convertIRType(typestr: String): IRDataType? {
}
}
fun parseIRValue(value: String): Float {
fun parseIRValue(value: String): Double {
return if(value.startsWith("-"))
-parseIRValue(value.substring(1))
else if(value.startsWith('$'))
value.substring(1).toInt(16).toFloat()
value.substring(1).toInt(16).toDouble()
else if(value.startsWith('%'))
value.substring(1).toInt(2).toFloat()
value.substring(1).toInt(2).toDouble()
else if(value.startsWith("0x"))
value.substring(2).toInt(16).toFloat()
value.substring(2).toInt(16).toDouble()
else if(value.startsWith('_'))
throw IRParseException("attempt to parse a label as numeric value")
else if(value.startsWith('&'))
@ -78,7 +78,7 @@ fun parseIRValue(value: String): Float {
else if(value.startsWith('@'))
throw IRParseException("address-of @ should have been handled earlier")
else
return value.toFloat()
return value.toDouble()
}
@ -119,11 +119,11 @@ fun parseIRCodeLine(line: String): Either<IRInstruction, String> {
var fpReg1: Int? = null
var fpReg2: Int? = null
var immediateInt: Int? = null
var immediateFp: Float? = null
var immediateFp: Double? = null
var address: Int? = null
var labelSymbol: String? = null
fun parseValueOrPlaceholder(operand: String): Float? {
fun parseValueOrPlaceholder(operand: String): Double? {
return if(operand[0].isLetter()) {
null
} else {

View File

@ -47,7 +47,7 @@ class Memory {
mem[address] = uv.toUByte()
}
fun setFloat(address: Int, value: Float) {
fun setFloat(address: Int, value: Double) {
var bits = value.toBits()
mem[address] = bits.toUByte()
bits = bits ushr 8
@ -56,11 +56,26 @@ class Memory {
mem[address+2] = bits.toUByte()
bits = bits ushr 8
mem[address+3] = bits.toUByte()
bits = bits ushr 8
mem[address+4] = bits.toUByte()
bits = bits ushr 8
mem[address+5] = bits.toUByte()
bits = bits ushr 8
mem[address+6] = bits.toUByte()
bits = bits ushr 8
mem[address+7] = 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())
fun getFloat(address: Int): Double {
val bits = mem[address].toLong() +
(1L shl 8)*mem[address+1].toLong() +
(1L shl 16)*mem[address+2].toLong() +
(1L shl 24)*mem[address+3].toLong() +
(1L shl 32)*mem[address+4].toLong() +
(1L shl 40)*mem[address+5].toLong() +
(1L shl 48)*mem[address+6].toLong() +
(1L shl 56)*mem[address+7].toLong()
return Double.fromBits(bits)
}
// for now, no LONG 32-bits and no FLOAT support.

View File

@ -7,14 +7,14 @@ package prog8.vm
*/
class Registers {
private val registers = Array<UShort>(65536) { 0u }
private val floatRegisters = Array(65536) { 0f }
private val floatRegisters = Array(65536) { 0.0 }
var cpuA: UByte = 0u
var cpuX: UByte = 0u
var cpuY: UByte = 0u
fun reset() {
registers.fill(0u)
floatRegisters.fill(0f)
floatRegisters.fill(0.0)
cpuA = 0u
cpuX = 0u
cpuY = 0u
@ -46,7 +46,7 @@ class Registers {
fun getFloat(reg:Int) = floatRegisters[reg]
fun setFloat(reg:Int, value: Float) {
fun setFloat(reg:Int, value: Double) {
floatRegisters[reg] = value
}
}

View File

@ -124,15 +124,16 @@ object SysCalls {
}
private fun returnValue(returns: FunctionCallArgs.RegSpec, value: Comparable<Nothing>, vm: VirtualMachine) {
val vv: Float = when(value) {
is UByte -> value.toFloat()
is UShort -> value.toFloat()
is UInt -> value.toFloat()
is Byte -> value.toFloat()
is Short -> value.toFloat()
is Int -> value.toFloat()
is Float -> value
else -> (value as Number).toFloat()
val vv: Double = when(value) {
is UByte -> value.toDouble()
is UShort -> value.toDouble()
is UInt -> value.toDouble()
is Byte -> value.toDouble()
is Short -> value.toDouble()
is Int -> value.toDouble()
is Float -> value.toDouble()
is Double -> value
else -> (value as Number).toDouble()
}
when(returns.dt) {
IRDataType.BYTE -> vm.registers.setUB(returns.registerNum, vv.toInt().toUByte())
@ -346,8 +347,11 @@ object SysCalls {
returnValue(callspec.returns!!, 0, vm)
}
Syscall.PRINT_F -> {
val value = getArgValues(callspec.arguments, vm).single() as Float
print(value)
val value = getArgValues(callspec.arguments, vm).single() as Double
if(value==0.0)
print("0")
else
print(value)
}
Syscall.STR_TO_UWORD -> {
val stringAddr = getArgValues(callspec.arguments, vm).single() as UShort
@ -373,7 +377,7 @@ object SysCalls {
Syscall.STR_TO_FLOAT -> {
val stringAddr = getArgValues(callspec.arguments, vm).single() as UShort
val memstring = vm.memory.getString(stringAddr.toInt())
returnValue(callspec.returns!!, memstring.toFloat(), vm)
returnValue(callspec.returns!!, memstring.toDouble(), vm)
}
Syscall.COMPARE_STRINGS -> {
val (firstV, secondV) = getArgValues(callspec.arguments, vm)
@ -390,7 +394,7 @@ object SysCalls {
returnValue(callspec.returns!!, 1, vm)
}
Syscall.RNDFSEED -> {
val seed = getArgValues(callspec.arguments, vm).single() as Float
val seed = getArgValues(callspec.arguments, vm).single() as Double
if(seed>0) // always use negative seed, this mimics the behavior on CBM machines
vm.randomSeedFloat(-seed)
else
@ -474,9 +478,9 @@ object SysCalls {
}
Syscall.CLAMP_FLOAT -> {
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
val value = valueU as Float
val minimum = minimumU as Float
val maximum = maximumU as Float
val value = valueU as Double
val minimum = minimumU as Double
val maximum = maximumU as Double
val result = min(max(value, minimum), maximum)
returnValue(callspec.returns!!, result, vm)
}

View File

@ -357,7 +357,7 @@ class VirtualMachine(irProgram: IRProgram) {
when(value.dt!!) {
IRDataType.BYTE -> valueStack.push(value.value as UByte)
IRDataType.WORD -> valueStack.pushw(value.value as UShort)
IRDataType.FLOAT -> valueStack.pushf(value.value as Float)
IRDataType.FLOAT -> valueStack.pushf(value.value as Double)
}
value.dt=null
}
@ -531,7 +531,7 @@ class VirtualMachine(irProgram: IRProgram) {
when(i.type!!) {
IRDataType.BYTE -> memory.setUB(i.address!!, 0u)
IRDataType.WORD -> memory.setUW(i.address!!, 0u)
IRDataType.FLOAT -> memory.setFloat(i.address!!, 0f)
IRDataType.FLOAT -> memory.setFloat(i.address!!, 0.0)
}
nextPc()
}
@ -540,7 +540,7 @@ class VirtualMachine(irProgram: IRProgram) {
when (i.type!!) {
IRDataType.BYTE -> memory.setUB(registers.getUW(i.reg1!!).toInt(), 0u)
IRDataType.WORD -> memory.setUW(registers.getUW(i.reg1!!).toInt(), 0u)
IRDataType.FLOAT -> memory.setFloat(registers.getUW(i.reg1!!).toInt(), 0f)
IRDataType.FLOAT -> memory.setFloat(registers.getUW(i.reg1!!).toInt(), 0.0)
}
nextPc()
}
@ -549,7 +549,7 @@ class VirtualMachine(irProgram: IRProgram) {
when (i.type!!) {
IRDataType.BYTE -> memory.setUB(i.address!! + registers.getUB(i.reg1!!).toInt(), 0u)
IRDataType.WORD -> memory.setUW(i.address!! + registers.getUB(i.reg1!!).toInt(), 0u)
IRDataType.FLOAT -> memory.setFloat(i.address!! + registers.getUB(i.reg1!!).toInt(), 0f)
IRDataType.FLOAT -> memory.setFloat(i.address!! + registers.getUB(i.reg1!!).toInt(), 0.0)
}
nextPc()
}
@ -1592,16 +1592,16 @@ class VirtualMachine(irProgram: IRProgram) {
memory.setSW(address, result.toShort())
}
private fun arithFloat(left: Float, operator: String, right: Float): Float = when(operator) {
private fun arithFloat(left: Double, operator: String, right: Double): Double = when(operator) {
"+" -> left + right
"-" -> left - right
"*" -> left * right
"/" -> {
if(right==0f) Float.MAX_VALUE
if(right==0.0) Double.MAX_VALUE
else left / right
}
"%" -> {
if(right==0f) Float.MAX_VALUE
if(right==0.0) Double.MAX_VALUE
else left % right
}
else -> throw IllegalArgumentException("operator word $operator")
@ -2108,22 +2108,22 @@ class VirtualMachine(irProgram: IRProgram) {
}
private fun InsFFROMUB(i: IRInstruction) {
registers.setFloat(i.fpReg1!!, registers.getUB(i.reg1!!).toFloat())
registers.setFloat(i.fpReg1!!, registers.getUB(i.reg1!!).toDouble())
nextPc()
}
private fun InsFFROMSB(i: IRInstruction) {
registers.setFloat(i.fpReg1!!, registers.getSB(i.reg1!!).toFloat())
registers.setFloat(i.fpReg1!!, registers.getSB(i.reg1!!).toDouble())
nextPc()
}
private fun InsFFROMUW(i: IRInstruction) {
registers.setFloat(i.fpReg1!!, registers.getUW(i.reg1!!).toFloat())
registers.setFloat(i.fpReg1!!, registers.getUW(i.reg1!!).toDouble())
nextPc()
}
private fun InsFFROMSW(i: IRInstruction) {
registers.setFloat(i.fpReg1!!, registers.getSW(i.reg1!!).toFloat())
registers.setFloat(i.fpReg1!!, registers.getSW(i.reg1!!).toDouble())
nextPc()
}
@ -2356,7 +2356,7 @@ class VirtualMachine(irProgram: IRProgram) {
randomGenerator = Random(((seed1.toUInt() shl 16) or seed2.toUInt()).toInt())
}
fun randomSeedFloat(seed: Float) {
fun randomSeedFloat(seed: Double) {
randomGeneratorFloats = Random(seed.toBits())
}
}
@ -2366,7 +2366,7 @@ internal fun Stack<UByte>.pushw(value: UShort) {
push((value.toInt() ushr 8).toUByte())
}
internal fun Stack<UByte>.pushf(value: Float) {
internal fun Stack<UByte>.pushf(value: Double) {
// push float; lsb first, msb last
var bits = value.toBits()
push(bits.toUByte())
@ -2376,6 +2376,14 @@ internal fun Stack<UByte>.pushf(value: Float) {
push(bits.toUByte())
bits = bits ushr 8
push(bits.toUByte())
bits = bits ushr 8
push(bits.toUByte())
bits = bits ushr 8
push(bits.toUByte())
bits = bits ushr 8
push(bits.toUByte())
bits = bits ushr 8
push(bits.toUByte())
}
internal fun Stack<UByte>.popw(): UShort {
@ -2384,14 +2392,25 @@ internal fun Stack<UByte>.popw(): UShort {
return ((msb.toInt() shl 8) + lsb.toInt()).toUShort()
}
internal fun Stack<UByte>.popf(): Float {
internal fun Stack<UByte>.popf(): Double {
// pop float; lsb is on bottom, msb on top
val b0 = pop()
val b1 = pop()
val b2 = pop()
val b3 = pop()
val bits = b3 + 256u*b2 + 65536u*b1 + 16777216u*b0
return Float.fromBits(bits.toInt())
val b0 = pop().toLong()
val b1 = pop().toLong()
val b2 = pop().toLong()
val b3 = pop().toLong()
val b4 = pop().toLong()
val b5 = pop().toLong()
val b6 = pop().toLong()
val b7 = pop().toLong()
val bits = b7 +
(1L shl 8)*b6 +
(1L shl 16)*b5 +
(1L shl 24)*b4
(1L shl 32)*b3
(1L shl 40)*b2
(1L shl 48)*b1
(1L shl 56)*b0
return Double.fromBits(bits)
}
// probably called via reflection

View File

@ -217,7 +217,7 @@ class VmProgramLoader {
addr += 2
}
DataType.ARRAY_F -> {
memory.setFloat(addr, 0.0f)
memory.setFloat(addr, 0.0)
addr += program.options.compTarget.machine.FLOAT_MEM_SIZE
}
in SplitWordArrayTypes -> {
@ -238,7 +238,7 @@ class VmProgramLoader {
DataType.BYTE -> memory.setSB(addr, it.toInt().toByte())
DataType.UWORD -> memory.setUW(addr, it.toInt().toUShort())
DataType.WORD -> memory.setSW(addr, it.toInt().toShort())
DataType.FLOAT -> memory.setFloat(addr, it.toFloat())
DataType.FLOAT -> memory.setFloat(addr, it)
else -> throw IRParseException("invalid dt")
}
}
@ -314,7 +314,7 @@ class VmProgramLoader {
DataType.ARRAY_F -> {
for (elt in iElts) {
val value = getInitializerValue(variable.dt, elt, symbolAddresses).toFloat()
val value = getInitializerValue(variable.dt, elt, symbolAddresses).toDouble()
memory.setFloat(address, value)
address += program.options.compTarget.machine.FLOAT_MEM_SIZE
}
@ -378,7 +378,7 @@ class VmProgramLoader {
}
DataType.ARRAY_F -> {
val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toFloat()
val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toDouble()
repeat(variable.length!!) {
memory.setFloat(address, value)
address += program.options.compTarget.machine.FLOAT_MEM_SIZE

View File

@ -48,10 +48,10 @@ class TestMemory: FunSpec({
test("32 bits float access") {
val mem = Memory()
mem.getFloat(1000) shouldNotBe 0.0
mem.setFloat(1000, 0.0f)
mem.getFloat(1000) shouldBe 0.0f
mem.setFloat(1000, -9.876543f)
mem.getFloat(1000) shouldBe -9.876543f
mem.setFloat(1000, 0.0)
mem.getFloat(1000) shouldBe 0.0
mem.setFloat(1000, -9.876543)
mem.getFloat(1000) shouldBe -9.876543
}
test("setstring and getstring") {

View File

@ -128,6 +128,6 @@ class TestVm: FunSpec( {
c64machine.getFloatAsmBytes(Math.PI) shouldBe "\$82, \$49, \$0f, \$da, \$a2"
val vm = VirtualMachineDefinition()
vm.getFloatAsmBytes(Math.PI) shouldBe "\$40, \$49, \$0f, \$db"
vm.getFloatAsmBytes(Math.PI) shouldBe "\$40, \$09, \$21, \$fb, \$54, \$44, \$2d, \$18"
}
})