mirror of
https://github.com/irmen/prog8.git
synced 2024-12-22 18:30:01 +00:00
vm: treat floats as 64 bits doubles. 0.0 printed as "0".
This commit is contained in:
parent
ab4bcdf12d
commit
af5ca2d0b8
@ -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(", ")
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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") {
|
||||
|
@ -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"
|
||||
}
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user