; SF format is:
;
; [sign] 1.[23bits] E[8bits(n-127)]
;
; SEEEEEEE Emmmmmmm mmmmmmmm mmmmmmmm
;
; [A+0] mmmmmmmm
; [A+1] mmmmmmmm
; [A+2] Emmmmmmm
; [A+3] SEEEEEEE
;
; Special values (xxx != 0):
;
;  r11      r10      r9       r8
;  [HL+3]   [HL+2]   [HL+1]   [HL+0]   
;  s1111111 10000000 00000000 00000000	infinity
;  s1111111 1xxxxxxx xxxxxxxx xxxxxxxx	NaN
;  s0000000 00000000 00000000 00000000	zero
;  s0000000 0xxxxxxx xxxxxxxx xxxxxxxx	denormals
;
; Note that CMPtype is "signed char" for rl78
;
	
#include "vregs.h"

#define Z	PSW.6

; External Functions:
;
;  __int_isnan  [HL] -> Z if NaN
;  __int_iszero  [HL] -> Z if zero

START_FUNC	__int_isinf
	;; [HL] points to value, returns Z if it's #Inf

	mov	a, [hl+2]
	and	a, #0x80
	mov	x, a
	mov	a, [hl+3]
	and	a, #0x7f
	cmpw	ax, #0x7f80
	skz
	ret			; return NZ if not NaN
	mov	a, [hl+2]
	and	a, #0x7f
	or	a, [hl+1]
	or	a, [hl]
	ret

END_FUNC	__int_isinf

#define A_SIGN		[hl+0]	/* byte */
#define A_EXP		[hl+2]	/* word */
#define A_FRAC_L	[hl+4]	/* word */
#define A_FRAC_LH	[hl+5]	/* byte */
#define A_FRAC_H	[hl+6]	/* word or byte */
#define A_FRAC_HH	[hl+7]	/* byte */

#define B_SIGN		[hl+8]
#define B_EXP		[hl+10]
#define B_FRAC_L	[hl+12]
#define B_FRAC_LH	[hl+13]
#define B_FRAC_H	[hl+14]
#define B_FRAC_HH	[hl+15]

START_FUNC	_int_unpack_sf
	;; convert 32-bit SFmode [DE] to 6-byte struct [HL] ("A")

	mov	a, [de+3]
	sar	a, 7
	mov	A_SIGN, a

	movw	ax, [de+2]
	and	a, #0x7f
	shrw	ax, 7
	movw	bc, ax		; remember if the exponent is all zeros
	subw	ax, #127	; exponent is now non-biased
	movw	A_EXP, ax

	movw	ax, [de]
	movw	A_FRAC_L, ax

	mov	a, [de+2]
	and	a, #0x7f
	cmp0	c		; if the exp is all zeros, it's denormal
	skz
	or	a, #0x80
	mov	A_FRAC_H, a

	mov	a, #0
	mov	A_FRAC_HH, a

	;; rounding-bit-shift
	movw	ax, A_FRAC_L
	shlw	ax, 1
	movw	A_FRAC_L, ax
	mov	a, A_FRAC_H
	rolc	a, 1
	mov	A_FRAC_H, a
	mov	a, A_FRAC_HH
	rolc	a, 1
	mov	A_FRAC_HH, a

	ret

END_FUNC	_int_unpack_sf

;	func(SF a,SF b)
;	[SP+4..7]	a
;	[SP+8..11]	b

START_FUNC		___subsf3

	;; a - b => a + (-b)

	;; Note - we cannot just change the sign of B on the stack and
	;; then fall through into __addsf3.  The stack'ed value may be
	;; used again (it was created by our caller after all).  Instead
	;; we have to allocate some stack space of our own, copy A and B,
	;; change the sign of B, call __addsf3, release the allocated stack
	;; and then return.

	subw	sp, #8
	movw	ax, [sp+4+8]
	movw	[sp], ax
	movw	ax, [sp+4+2+8]
	movw	[sp+2], ax
	movw	ax, [sp+4+4+8]
	movw	[sp+4], ax
	mov 	a, [sp+4+6+8]
	mov	[sp+6], a
	mov	a, [sp+4+7+8]
	xor	a, #0x80
	mov	[sp+7], a
	call	$!___addsf3
	addw	sp, #8
	ret
END_FUNC	___subsf3

START_FUNC	___addsf3

	;; if (isnan(a)) return a
	movw	ax, sp
	addw	ax, #4
	movw	hl, ax
	call	!!__int_isnan
	bnz	$1f
ret_a:
	movw	ax, [sp+4]
	movw	r8, ax
	movw	ax, [sp+6]
	movw	r10, ax
	ret

1:	;; if (isnan (b)) return b;
	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	call	!!__int_isnan
	bnz	$2f
ret_b:
	movw	ax, [sp+8]
	movw	r8, ax
	movw	ax, [sp+10]
	movw	r10, ax
	ret

2:	;; if (isinf (a))
	movw	ax, sp
	addw	ax, #4
	movw	hl, ax
	call	$!__int_isinf
	bnz	$3f

	;;   if (isinf (b) && a->sign != b->sign) return NaN
	
	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	call	$!__int_isinf
	bnz	$ret_a

	mov	a, [sp+7]
	mov	h, a
	mov	a, [sp+11]
	xor	a, h
	bf	a.7, $ret_a

	movw	r8,  #0x0001
	movw	r10, #0x7f80
	ret

3:	;; if (isinf (b)) return b;
	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	call	$!__int_isinf
	bz	$ret_b

	;; if (iszero (b))
	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	call	!!__int_iszero
	bnz	$4f

	;;   if (iszero (a))
	movw	ax, sp
	addw	ax, #4
	movw	hl, ax
	call	!!__int_iszero
	bnz	$ret_a

	movw	ax, [sp+4]
	movw	r8, ax
	mov	a, [sp+7]
	mov	h, a
	movw	ax, [sp+10]
	and	a, h
	movw	r10, ax
	ret

4:	;; if (iszero (a)) return b;
	movw	ax, sp
	addw	ax, #4
	movw	hl, ax
	call	!!__int_iszero
	bz	$ret_b

; Normalize the two numbers relative to each other.  At this point,
; we need the numbers converted to their "unpacked" format.

	subw	sp, #16		; Save room for two unpacked values.

	movw	ax, sp
	movw	hl, ax
	addw	ax, #16+4
	movw	de, ax
	call	$!_int_unpack_sf

	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	addw	ax, #16+8-8
	movw	de, ax
	call	$!_int_unpack_sf

	movw	ax, sp
	movw	hl, ax

	;; diff = a.exponent - b.exponent
	movw	ax, B_EXP	; sign/exponent word
	movw	bc, ax
	movw	ax, A_EXP	; sign/exponent word
	
	subw	ax, bc		; a = a.exp - b.exp
	movw	de, ax		; d = sdiff

	;;  if (diff < 0) diff = -diff
	bf	a.7, $1f
	xor	a, #0xff
	xor	r_0, #0xff	; x
	incw	ax		; a = diff
1:	
	;; if (diff >= 23) zero the smaller one
	cmpw	ax, #24
	bc	$.L661		; if a < 23 goto 661

	;; zero out the smaller one

	movw	ax, de
	bt	a.7, $1f	; if sdiff < 0 (a_exp < b_exp) goto 1f
	;; "zero out" b
	movw	ax, A_EXP
	movw	B_EXP, ax
	movw	ax, #0
	movw	B_FRAC_L, ax
	movw	B_FRAC_H, ax
	br	$5f
1:	
	;; "zero out" a
	movw	ax, B_EXP
	movw	A_EXP, ax
	movw	ax, #0
	movw	A_FRAC_L, ax
	movw	A_FRAC_H, ax

	br	$5f
.L661:
	;; shift the smaller one so they have the same exponents
1:	
	movw	ax, de
	bt	a.7, $1f
	cmpw	ax, #0		; sdiff > 0
	bnh	$1f		; if (sdiff <= 0) goto 1f

	decw	de
	incw	B_EXP		; because it's [HL+byte]

	movw	ax, B_FRAC_H
	shrw	ax, 1
	movw	B_FRAC_H, ax
	mov	a, B_FRAC_LH
	rorc	a, 1
	mov	B_FRAC_LH, a
	mov	a, B_FRAC_L
	rorc	a, 1
	mov	B_FRAC_L, a
	
	br	$1b
1:	
	movw	ax, de
	bf	a.7, $1f

	incw	de
	incw	A_EXP		; because it's [HL+byte]

	movw	ax, A_FRAC_H
	shrw	ax, 1
	movw	A_FRAC_H, ax
	mov	a, A_FRAC_LH
	rorc	a, 1
	mov	A_FRAC_LH, a
	mov	a, A_FRAC_L
	rorc	a, 1
	mov	A_FRAC_L, a
	
	br	$1b
1:	

5:	;; At this point, A and B have the same exponent.

	mov	a, A_SIGN
	cmp	a, B_SIGN
	bnz	$1f

	;; Same sign, just add.
	movw	ax, A_FRAC_L
	addw	ax, B_FRAC_L
	movw	A_FRAC_L, ax
	mov	a, A_FRAC_H
	addc	a, B_FRAC_H
	mov	A_FRAC_H, a
	mov	a, A_FRAC_HH
	addc	a, B_FRAC_HH
	mov	A_FRAC_HH, a

	br	$.L728

1:	;; Signs differ - A has A_SIGN still.
	bf	a.7, $.L696

	;; A is negative, do B-A
	movw	ax, B_FRAC_L
	subw	ax, A_FRAC_L
	movw	A_FRAC_L, ax
	mov	a, B_FRAC_H
	subc	a, A_FRAC_H
	mov	A_FRAC_H, a
	mov	a, B_FRAC_HH
	subc	a, A_FRAC_HH
	mov	A_FRAC_HH, a

	br	$.L698
.L696:
	;; B is negative, do A-B
	movw	ax, A_FRAC_L
	subw	ax, B_FRAC_L
	movw	A_FRAC_L, ax
	mov	a, A_FRAC_H
	subc	a, B_FRAC_H
	mov	A_FRAC_H, a
	mov	a, A_FRAC_HH
	subc	a, B_FRAC_HH
	mov	A_FRAC_HH, a

.L698:	
	;; A is still A_FRAC_HH
	bt	a.7, $.L706
	
	;; subtraction was positive
	mov	a, #0
	mov	A_SIGN, a
	br	$.L712

.L706:
	;; subtraction was negative
	mov	a, #0xff
	mov	A_SIGN, a

	;; This negates A_FRAC
	mov	a, A_FRAC_L
	xor	a, #0xff		; XOR doesn't mess with carry
	add	a, #1			; INC doesn't set the carry
	mov	A_FRAC_L, a
	mov	a, A_FRAC_LH
	xor	a, #0xff
	addc	a, #0
	mov	A_FRAC_LH, a
	mov	a, A_FRAC_H
	xor	a, #0xff
	addc	a, #0
	mov	A_FRAC_H, a
	mov	a, A_FRAC_HH
	xor	a, #0xff
	addc	a, #0
	mov	A_FRAC_HH, a

.L712:
	;; Renormalize the subtraction

	mov	a, A_FRAC_L
	or	a, A_FRAC_LH
	or	a, A_FRAC_H
	or	a, A_FRAC_HH
	bz	$.L728

	;; Mantissa is not zero, left shift until the MSB is in the
	;; right place
1:
	movw	ax, A_FRAC_H
	cmpw	ax, #0x0200
	bnc	$.L728

	decw	A_EXP

	movw	ax, A_FRAC_L
	shlw	ax, 1
	movw	A_FRAC_L, ax
	movw	ax, A_FRAC_H
	rolwc	ax, 1
	movw	A_FRAC_H, ax
	br	$1b

.L728:
	;; normalize A and pack it

	movw	ax, A_FRAC_H
	cmpw	ax, #0x01ff
	bnh	$1f
	;; overflow in the mantissa; adjust
	movw	ax, A_FRAC_H
	shrw	ax, 1
	movw	A_FRAC_H, ax
	mov	a, A_FRAC_LH
	rorc	a, 1
	mov	A_FRAC_LH, a
	mov	a, A_FRAC_L
	rorc	a, 1
	mov	A_FRAC_L, a
	incw	A_EXP
1:	

	call	$!__rl78_int_pack_a_r8
	addw	sp, #16
	ret

END_FUNC	___addsf3

START_FUNC	__rl78_int_pack_a_r8
	;; pack A to R8
	movw	ax, A_EXP
	addw	ax, #126	; not 127, we want the "bt/bf" test to check for denormals

	bf	a.7, $1f
	;; make a denormal
2:
	movw	bc, ax
	movw	ax, A_FRAC_H
	shrw	ax, 1
	movw	A_FRAC_H, ax
	mov	a, A_FRAC_LH
	rorc	a, 1
	mov	A_FRAC_LH, a
	mov	a, A_FRAC_L
	rorc	a, 1
	mov	A_FRAC_L, a
	movw	ax, bc
	incw	ax
	bt	a.7, $2b
	decw	ax
1:	
	incw	ax		; now it's as if we added 127
	movw	A_EXP, ax

	cmpw	ax, #0xfe
	bnh	$1f
	;; store #Inf instead
	mov	a, A_SIGN
	or	a, #0x7f
	mov	x, #0x80
	movw	r10, ax
	movw	r8, #0
	ret

1:
	bf	a.7, $1f	; note AX has EXP at top of loop
	;; underflow, denormal?
	movw	ax, A_FRAC_H
	shrw	ax, 1
	movw	A_FRAC_H, ax
	mov	a, A_FRAC_LH
	rorc	a, 1
	movw	A_FRAC_LH, ax
	mov	a, A_FRAC_L
	rorc	a, 1
	movw	A_FRAC_L, ax
	incw	A_EXP
	movw	ax, A_EXP
	br	$1b

1:
	;; undo the rounding-bit-shift
	mov	a, A_FRAC_L
	bf	a.0, $1f
	;; round up
	movw	ax, A_FRAC_L
	addw	ax, #1
	movw	A_FRAC_L, ax
	bnc	$1f
	incw	A_FRAC_H

	;; If the rounding set the bit beyond the end of the fraction, increment the exponent.
	mov	a, A_FRAC_HH
	bf	a.1, $1f
	incw	A_EXP
	
1:	
	movw	ax, A_FRAC_H
	shrw	ax, 1
	movw	A_FRAC_H, ax
	mov	a, A_FRAC_LH
	rorc	a, 1
	mov	A_FRAC_LH, a
	mov	a, A_FRAC_L
	rorc	a, 1
	mov	A_FRAC_L, a

	movw	ax, A_FRAC_L
	movw	r8, ax

	or	a, x
	or	a, A_FRAC_H
	or	a, A_FRAC_HH
	bnz	$1f
	movw	ax, #0
	movw	A_EXP, ax
1:	
	mov	a, A_FRAC_H
	and	a, #0x7f
	mov	b, a
	mov	a, A_EXP
	shl	a, 7
	or	a, b
	mov	r10, a

	mov	a, A_SIGN
	and	a, #0x80
	mov	b, a
	mov	a, A_EXP
	shr	a, 1
	or	a, b
	mov	r11, a

	ret
END_FUNC	__rl78_int_pack_a_r8

START_FUNC	___mulsf3

	;; if (isnan(a)) return a
	movw	ax, sp
	addw	ax, #4
	movw	hl, ax
	call	!!__int_isnan
	bnz	$1f
mret_a:
	movw	ax, [sp+4]
	movw	r8, ax
	mov	a, [sp+11]
	and	a, #0x80
	mov	b, a
	movw	ax, [sp+6]
	xor	a, b		; sign is always a ^ b
	movw	r10, ax
	ret
1:	
	;; if (isnan (b)) return b;
	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	call	!!__int_isnan
	bnz	$1f
mret_b:
	movw	ax, [sp+8]
	movw	r8, ax
	mov	a, [sp+7]
	and	a, #0x80
	mov	b, a
	movw	ax, [sp+10]
	xor	a, b		; sign is always a ^ b
	movw	r10, ax
	ret
1:	
	;; if (isinf (a)) return (b==0) ? nan : a
	movw	ax, sp
	addw	ax, #4
	movw	hl, ax
	call	$!__int_isinf
	bnz	$.L805

	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	call	!!__int_iszero
	bnz	$mret_a

	movw	r8,  #0x0001	; return NaN
	movw	r10, #0x7f80
	ret

.L805:	
	;; if (isinf (b)) return (a==0) ? nan : b
	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	call	$!__int_isinf
	bnz	$.L814

	movw	ax, sp
	addw	ax, #4
	movw	hl, ax
	call	!!__int_iszero
	bnz	$mret_b

	movw	r8,  #0x0001	; return NaN
	movw	r10, #0x7f80
	ret

.L814:
	movw	ax, sp
	addw	ax, #4
	movw	hl, ax
	call	!!__int_iszero
	bz	$mret_a
	
	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	call	!!__int_iszero
	bz	$mret_b

	;; at this point, we're doing the multiplication.

	subw	sp, #16	; save room for two unpacked values

	movw	ax, sp
	movw	hl, ax
	addw	ax, #16+4
	movw	de, ax
	call	$!_int_unpack_sf

	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	addw	ax, #16+8-8
	movw	de, ax
	call	$!_int_unpack_sf

	movw	ax, sp
	movw	hl, ax

	;; multiply SI a.FRAC * SI b.FRAC to DI r8

	subw	sp, #16
	movw	ax, A_FRAC_L
	movw	[sp+0], ax
	movw	ax, A_FRAC_H
	movw	[sp+2], ax

	movw	ax, B_FRAC_L
	movw	[sp+8], ax
	movw	ax, B_FRAC_H
	movw	[sp+10], ax

	movw	ax, #0
	movw	[sp+4], ax
	movw	[sp+6], ax
	movw	[sp+12], ax
	movw	[sp+14], ax

	call	!!___muldi3	; MTMPa * MTMPb -> R8..R15
	addw	sp, #16

	movw	ax, sp
	movw	hl, ax

	;;  add the exponents together
	movw	ax, A_EXP
	addw	ax, B_EXP
	movw	bc, ax		; exponent in BC

	;; now, re-normalize the DI value in R8..R15 to have the
	;; MSB in the "right" place, adjusting BC as we shift it.

	;; The value will normally be in this range:
	;; R15              R8
	;; 0001_0000_0000_0000
	;; 0003_ffff_fc00_0001

	;; so to speed it up, we normalize to:
	;; 0001_xxxx_xxxx_xxxx
	;; then extract the bytes we want (r11-r14)

1:
	mov	a, r15
	cmp0	a
	bnz	$2f
	mov	a, r14
	and	a, #0xfe
	bz	$1f
2:	
	;; shift right, inc exponent
	movw	ax, r14
	shrw	ax, 1
	movw	r14, ax
	mov	a, r13
	rorc	a, 1
	mov	r13, a
	mov	a, r12
	rorc	a, 1
	mov	r12, a
	mov	a, r11
	rorc	a, 1
	mov	r11, a
	;; we don't care about r8/r9/r10 if we're shifting this way
	incw	bc
	br	$1b
1:	
	mov	a, r15
	or	a, r14
	bnz	$1f
	;; shift left, dec exponent
	movw	ax, r8
	shlw	ax, 1
	movw	r8, ax
	movw	ax, r10
	rolwc	ax, 1
	movw	r10, ax
	movw	ax, r12
	rolwc	ax, 1
	movw	r12, ax
	movw	ax, r14
	rolwc	ax, 1
	movw	r14, ax
	decw	bc
	br	$1b
1:
	;; at this point, FRAC is in R11..R14 and EXP is in BC
	movw	ax, bc
	movw	A_EXP, ax

	mov	a, r11
	mov	A_FRAC_L, a
	mov	a, r12
	mov	A_FRAC_LH, a
	mov	a, r13
	mov	A_FRAC_H, a
	mov	a, r14
	mov	A_FRAC_HH, a

	mov	a, A_SIGN
	xor	a, B_SIGN
	mov	A_SIGN, a

	call	$!__rl78_int_pack_a_r8

	addw	sp, #16
	ret

END_FUNC		___mulsf3
	
START_FUNC		___divsf3

	;; if (isnan(a)) return a
	movw	ax, sp
	addw	ax, #4
	movw	hl, ax
	call	!!__int_isnan
	bnz	$1f
dret_a:
	movw	ax, [sp+4]
	movw	r8, ax
	mov	a, [sp+11]
	and	a, #0x80
	mov	b, a
	movw	ax, [sp+6]
	xor	a, b		; sign is always a ^ b
	movw	r10, ax
	ret
1:	
	;; if (isnan (b)) return b;
	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	call	!!__int_isnan
	bnz	$1f
dret_b:
	movw	ax, [sp+8]
	movw	r8, ax
	mov	a, [sp+7]
	and	a, #0x80
	mov	b, a
	movw	ax, [sp+10]
	xor	a, b		; sign is always a ^ b
	movw	r10, ax
	ret
1:	

	;; if (isinf (a)) return isinf(b) ? nan : a

	movw	ax, sp
	addw	ax, #4
	movw	hl, ax
	call	$!__int_isinf
	bnz	$1f
	
	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	call	$!__int_isinf
	bnz	$dret_a
dret_nan:	
	movw	r8,  #0x0001	; return NaN
	movw	r10, #0x7f80
	ret
	
1:	

	;; if (iszero (a)) return iszero(b) ? nan : a

	movw	ax, sp
	addw	ax, #4
	movw	hl, ax
	call	!!__int_iszero
	bnz	$1f
	
	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	call	!!__int_iszero
	bnz	$dret_a
	br	$dret_nan
	
1:	
	;; if (isinf (b)) return 0

	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	call	$!__int_isinf
	bnz	$1f
	
	mov	a, [sp+7]
	mov	b, a
	mov	a, [sp+11]
	xor	a, b
	and	a, #0x80
	mov	r11, a
	movw	r8, #0
	mov	r10, #0
	ret
	
1:	
	;; if (iszero (b)) return Inf

	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	call	!!__int_iszero
	bnz	$1f

	mov	a, [sp+7]
	mov	b, a
	mov	a, [sp+11]
	xor	a, b
	or	a, #0x7f
	mov	r11, a
	movw	r8, #0
	mov	r10, #0x80
	ret
1:	

	;; at this point, we're doing the division.  Normalized
	;; mantissas look like:
	;; 01.xx.xx.xx
	;; so we divide:
	;; 01.xx.xx.xx.00.00.00.00
	;; by          01.xx.xx.xx
	;; to get approx 00.80.00.00.00 to 01.ff.ff.ff.00


	subw	sp, #16	; save room for two unpacked values

	movw	ax, sp
	movw	hl, ax
	addw	ax, #16+4
	movw	de, ax
	call	$!_int_unpack_sf

	movw	ax, sp
	addw	ax, #8
	movw	hl, ax
	addw	ax, #16+8-8
	movw	de, ax
	call	$!_int_unpack_sf

	movw	ax, sp
	movw	hl, ax

	;; divide DI a.FRAC / SI b.FRAC to DI r8

	subw	sp, #16
	movw	ax, A_FRAC_L
	movw	[sp+4], ax
	movw	ax, A_FRAC_H
	movw	[sp+6], ax

	movw	ax, B_FRAC_L
	movw	[sp+8], ax
	movw	ax, B_FRAC_H
	movw	[sp+10], ax

	movw	ax, #0
	movw	[sp+0], ax
	movw	[sp+2], ax
	movw	[sp+12], ax
	movw	[sp+14], ax

	call	!!___divdi3	; MTMPa / MTMPb -> R8..R15
	addw	sp, #16

	movw	ax, sp
	movw	hl, ax

	;;  subtract the exponents A - B
	movw	ax, A_EXP
	subw	ax, B_EXP
	movw	bc, ax		; exponent in BC

	;; now, re-normalize the DI value in R8..R15 to have the
	;; MSB in the "right" place, adjusting BC as we shift it.

	;; The value will normally be in this range:
	;; R15              R8
	;; 0000_0000_8000_0000
	;; 0000_0001_ffff_ff00

	;; so to speed it up, we normalize to:
	;; 0000_0001_xxxx_xxxx
	;; then extract the bytes we want (r9-r12)

1:
	movw	ax, r14
	cmpw	ax, #0
	bnz	$2f
	movw	ax, r12
	cmpw	ax, #1
	bnh	$1f
2:	
	;; shift right, inc exponent
	movw	ax, r14
	shrw	ax, 1
	movw	r14, ax
	mov	a, r13
	rorc	a, 1
	mov	r13, a
	mov	a, r12
	rorc	a, 1
	mov	r12, a
	mov	a, r11
	rorc	a, 1
	mov	r11, a
	mov	a, r10
	rorc	a, 1
	mov	r10, a
	mov	a, r9
	rorc	a, 1
	mov	r9, a
	mov	a, r8
	rorc	a, 1
	mov	r8, a

	incw	bc
	br	$1b
1:	
	;; the previous loop leaves r15.r13 zero
	mov	a, r12
	cmp0	a
	bnz	$1f
	;; shift left, dec exponent
	movw	ax, r8
	shlw	ax, 1
	movw	r8, ax
	movw	ax, r10
	rolwc	ax, 1
	movw	r10, ax
	movw	ax, r12
	rolwc	ax, 1
	movw	r12, ax
	;; don't need to do r14
	decw	bc
	br	$1b
1:
	;; at this point, FRAC is in R8..R11 and EXP is in BC
	movw	ax, bc
	movw	A_EXP, ax

	mov	a, r9
	mov	A_FRAC_L, a
	mov	a, r10
	mov	A_FRAC_LH, a
	mov	a, r11
	mov	A_FRAC_H, a
	mov	a, r12
	mov	A_FRAC_HH, a

	mov	a, A_SIGN
	xor	a, B_SIGN
	mov	A_SIGN, a

	call	$!__rl78_int_pack_a_r8

	addw	sp, #16
	ret
	
END_FUNC	___divsf3