ack/mach/mips/libem/fif8.s

70 lines
1.6 KiB
ArmAsm
Raw Permalink Normal View History

#
.sect .text; .sect .rom; .sect .data; .sect .bss
/* Multiplies two double-precision floats, then splits the product into
* fraction and integer, both as floats, like modf(3) in C,
* http://en.cppreference.com/w/c/numeric/math/modf
*
* Stack: ( a b -- fraction integer )
*/
.sect .text
.define .fif8
.fif8:
ldc1 f0, 8(sp) ! f0 = a
ldc1 f2, 0(sp) ! f2 = b
mul.d f0, f0, f2 ! f0 = a * b
abs.d f2, f0 ! f2 = abs(f0)
lui at, ha16[max_power_of_two]
ldc1 f4, lo16[max_power_of_two] (at) ! f4 = max power of two
mov.d f6, f2 ! we're going to assemble the integer part in f6
c.lt.d 0, f4, f2 ! if absolute value too big, it must be integral
bc1t 0, return
nop
! Crudely strip off the fractional part.
add.d f6, f2, f4 ! f6 = absolute value + max power of two
sub.d f6, f6, f4 ! f6 -= max_power_of_two
! The above might round, so correct that.
lui at, ha16[one]
ldc1 f8, lo16[one] (at) ! f8 = 1.0
1:
c.le.d 0, f6, f2 ! if result <= absolute value, stop
bc1t 0, 2f
nop
sub.d f6, f6, f8 ! result -= 1.0
b 1b
nop
2:
! Correct the sign of the result.
mtc1 zero, f8
mthc1 zero, f8 ! f8 = 0.0
c.lt.d 0, f0, f8 ! if original value was negative
bc1f 0, 1f
nop
neg.d f6, f6 ! negate the result
1:
return:
sdc1 f6, 0(sp) ! store integer part
sub.d f6, f0, f6 ! calculate fractional part
sdc1 f6, 8(sp) ! store fractional part
jr ra
nop
! doubles >= MAXPOWTWO are already integers
.sect .rom
max_power_of_two:
.dataf8 4.503599627370496000E+15
one:
.dataf8 1.0