#
.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
