1; SF format is:
2;
3; [sign] 1.[23bits] E[8bits(n-127)]
4;
5; SEEEEEEE Emmmmmmm mmmmmmmm mmmmmmmm
6;
7; [A+0] mmmmmmmm
8; [A+1] mmmmmmmm
9; [A+2] Emmmmmmm
10; [A+3] SEEEEEEE
11;
12; Special values (xxx != 0):
13;
14;  r11      r10      r9       r8
15;  [HL+3]   [HL+2]   [HL+1]   [HL+0]
16;  s1111111 10000000 00000000 00000000	infinity
17;  s1111111 1xxxxxxx xxxxxxxx xxxxxxxx	NaN
18;  s0000000 00000000 00000000 00000000	zero
19;  s0000000 0xxxxxxx xxxxxxxx xxxxxxxx	denormals
20;
21; Note that CMPtype is "signed char" for rl78
22;
23
24#include "vregs.h"
25
26#define Z	PSW.6
27
28; External Functions:
29;
30;  __int_isnan  [HL] -> Z if NaN
31;  __int_iszero  [HL] -> Z if zero
32
33START_FUNC	__int_isinf
34	;; [HL] points to value, returns Z if it's #Inf
35
36	mov	a, [hl+2]
37	and	a, #0x80
38	mov	x, a
39	mov	a, [hl+3]
40	and	a, #0x7f
41	cmpw	ax, #0x7f80
42	skz
43	ret			; return NZ if not NaN
44	mov	a, [hl+2]
45	and	a, #0x7f
46	or	a, [hl+1]
47	or	a, [hl]
48	ret
49
50END_FUNC	__int_isinf
51
52#define A_SIGN		[hl+0]	/* byte */
53#define A_EXP		[hl+2]	/* word */
54#define A_FRAC_L	[hl+4]	/* word */
55#define A_FRAC_LH	[hl+5]	/* byte */
56#define A_FRAC_H	[hl+6]	/* word or byte */
57#define A_FRAC_HH	[hl+7]	/* byte */
58
59#define B_SIGN		[hl+8]
60#define B_EXP		[hl+10]
61#define B_FRAC_L	[hl+12]
62#define B_FRAC_LH	[hl+13]
63#define B_FRAC_H	[hl+14]
64#define B_FRAC_HH	[hl+15]
65
66START_FUNC	_int_unpack_sf
67	;; convert 32-bit SFmode [DE] to 6-byte struct [HL] ("A")
68
69	mov	a, [de+3]
70	sar	a, 7
71	mov	A_SIGN, a
72
73	movw	ax, [de+2]
74	and	a, #0x7f
75	shrw	ax, 7
76	movw	bc, ax		; remember if the exponent is all zeros
77	subw	ax, #127	; exponent is now non-biased
78	movw	A_EXP, ax
79
80	movw	ax, [de]
81	movw	A_FRAC_L, ax
82
83	mov	a, [de+2]
84	and	a, #0x7f
85	cmp0	c		; if the exp is all zeros, it's denormal
86	skz
87	or	a, #0x80
88	mov	A_FRAC_H, a
89
90	mov	a, #0
91	mov	A_FRAC_HH, a
92
93	;; rounding-bit-shift
94	movw	ax, A_FRAC_L
95	shlw	ax, 1
96	movw	A_FRAC_L, ax
97	mov	a, A_FRAC_H
98	rolc	a, 1
99	mov	A_FRAC_H, a
100	mov	a, A_FRAC_HH
101	rolc	a, 1
102	mov	A_FRAC_HH, a
103
104	ret
105
106END_FUNC	_int_unpack_sf
107
108;	func(SF a,SF b)
109;	[SP+4..7]	a
110;	[SP+8..11]	b
111
112START_FUNC		___subsf3
113
114	;; a - b => a + (-b)
115
116	;; Note - we cannot just change the sign of B on the stack and
117	;; then fall through into __addsf3.  The stack'ed value may be
118	;; used again (it was created by our caller after all).  Instead
119	;; we have to allocate some stack space of our own, copy A and B,
120	;; change the sign of B, call __addsf3, release the allocated stack
121	;; and then return.
122
123	subw	sp, #8
124	movw	ax, [sp+4+8]
125	movw	[sp], ax
126	movw	ax, [sp+4+2+8]
127	movw	[sp+2], ax
128	movw	ax, [sp+4+4+8]
129	movw	[sp+4], ax
130	mov 	a, [sp+4+6+8]
131	mov	[sp+6], a
132	mov	a, [sp+4+7+8]
133	xor	a, #0x80
134	mov	[sp+7], a
135	call	$!___addsf3
136	addw	sp, #8
137	ret
138END_FUNC	___subsf3
139
140START_FUNC	___addsf3
141
142	;; if (isnan(a)) return a
143	movw	ax, sp
144	addw	ax, #4
145	movw	hl, ax
146	call	!!__int_isnan
147	bnz	$1f
148ret_a:
149	movw	ax, [sp+4]
150	movw	r8, ax
151	movw	ax, [sp+6]
152	movw	r10, ax
153	ret
154
1551:	;; if (isnan (b)) return b;
156	movw	ax, sp
157	addw	ax, #8
158	movw	hl, ax
159	call	!!__int_isnan
160	bnz	$2f
161ret_b:
162	movw	ax, [sp+8]
163	movw	r8, ax
164	movw	ax, [sp+10]
165	movw	r10, ax
166	ret
167
1682:	;; if (isinf (a))
169	movw	ax, sp
170	addw	ax, #4
171	movw	hl, ax
172	call	$!__int_isinf
173	bnz	$3f
174
175	;;   if (isinf (b) && a->sign != b->sign) return NaN
176
177	movw	ax, sp
178	addw	ax, #8
179	movw	hl, ax
180	call	$!__int_isinf
181	bnz	$ret_a
182
183	mov	a, [sp+7]
184	mov	h, a
185	mov	a, [sp+11]
186	xor	a, h
187	bf	a.7, $ret_a
188
189	movw	r8,  #0x0001
190	movw	r10, #0x7f80
191	ret
192
1933:	;; if (isinf (b)) return b;
194	movw	ax, sp
195	addw	ax, #8
196	movw	hl, ax
197	call	$!__int_isinf
198	bz	$ret_b
199
200	;; if (iszero (b))
201	movw	ax, sp
202	addw	ax, #8
203	movw	hl, ax
204	call	!!__int_iszero
205	bnz	$4f
206
207	;;   if (iszero (a))
208	movw	ax, sp
209	addw	ax, #4
210	movw	hl, ax
211	call	!!__int_iszero
212	bnz	$ret_a
213
214	movw	ax, [sp+4]
215	movw	r8, ax
216	mov	a, [sp+7]
217	mov	h, a
218	movw	ax, [sp+10]
219	and	a, h
220	movw	r10, ax
221	ret
222
2234:	;; if (iszero (a)) return b;
224	movw	ax, sp
225	addw	ax, #4
226	movw	hl, ax
227	call	!!__int_iszero
228	bz	$ret_b
229
230; Normalize the two numbers relative to each other.  At this point,
231; we need the numbers converted to their "unpacked" format.
232
233	subw	sp, #16		; Save room for two unpacked values.
234
235	movw	ax, sp
236	movw	hl, ax
237	addw	ax, #16+4
238	movw	de, ax
239	call	$!_int_unpack_sf
240
241	movw	ax, sp
242	addw	ax, #8
243	movw	hl, ax
244	addw	ax, #16+8-8
245	movw	de, ax
246	call	$!_int_unpack_sf
247
248	movw	ax, sp
249	movw	hl, ax
250
251	;; diff = a.exponent - b.exponent
252	movw	ax, B_EXP	; sign/exponent word
253	movw	bc, ax
254	movw	ax, A_EXP	; sign/exponent word
255
256	subw	ax, bc		; a = a.exp - b.exp
257	movw	de, ax		; d = sdiff
258
259	;;  if (diff < 0) diff = -diff
260	bf	a.7, $1f
261	xor	a, #0xff
262	xor	r_0, #0xff	; x
263	incw	ax		; a = diff
2641:
265	;; if (diff >= 23) zero the smaller one
266	cmpw	ax, #24
267	bc	$.L661		; if a < 23 goto 661
268
269	;; zero out the smaller one
270
271	movw	ax, de
272	bt	a.7, $1f	; if sdiff < 0 (a_exp < b_exp) goto 1f
273	;; "zero out" b
274	movw	ax, A_EXP
275	movw	B_EXP, ax
276	movw	ax, #0
277	movw	B_FRAC_L, ax
278	movw	B_FRAC_H, ax
279	br	$5f
2801:
281	;; "zero out" a
282	movw	ax, B_EXP
283	movw	A_EXP, ax
284	movw	ax, #0
285	movw	A_FRAC_L, ax
286	movw	A_FRAC_H, ax
287
288	br	$5f
289.L661:
290	;; shift the smaller one so they have the same exponents
2911:
292	movw	ax, de
293	bt	a.7, $1f
294	cmpw	ax, #0		; sdiff > 0
295	bnh	$1f		; if (sdiff <= 0) goto 1f
296
297	decw	de
298	incw	B_EXP		; because it's [HL+byte]
299
300	movw	ax, B_FRAC_H
301	shrw	ax, 1
302	movw	B_FRAC_H, ax
303	mov	a, B_FRAC_LH
304	rorc	a, 1
305	mov	B_FRAC_LH, a
306	mov	a, B_FRAC_L
307	rorc	a, 1
308	mov	B_FRAC_L, a
309
310	br	$1b
3111:
312	movw	ax, de
313	bf	a.7, $1f
314
315	incw	de
316	incw	A_EXP		; because it's [HL+byte]
317
318	movw	ax, A_FRAC_H
319	shrw	ax, 1
320	movw	A_FRAC_H, ax
321	mov	a, A_FRAC_LH
322	rorc	a, 1
323	mov	A_FRAC_LH, a
324	mov	a, A_FRAC_L
325	rorc	a, 1
326	mov	A_FRAC_L, a
327
328	br	$1b
3291:
330
3315:	;; At this point, A and B have the same exponent.
332
333	mov	a, A_SIGN
334	cmp	a, B_SIGN
335	bnz	$1f
336
337	;; Same sign, just add.
338	movw	ax, A_FRAC_L
339	addw	ax, B_FRAC_L
340	movw	A_FRAC_L, ax
341	mov	a, A_FRAC_H
342	addc	a, B_FRAC_H
343	mov	A_FRAC_H, a
344	mov	a, A_FRAC_HH
345	addc	a, B_FRAC_HH
346	mov	A_FRAC_HH, a
347
348	br	$.L728
349
3501:	;; Signs differ - A has A_SIGN still.
351	bf	a.7, $.L696
352
353	;; A is negative, do B-A
354	movw	ax, B_FRAC_L
355	subw	ax, A_FRAC_L
356	movw	A_FRAC_L, ax
357	mov	a, B_FRAC_H
358	subc	a, A_FRAC_H
359	mov	A_FRAC_H, a
360	mov	a, B_FRAC_HH
361	subc	a, A_FRAC_HH
362	mov	A_FRAC_HH, a
363
364	br	$.L698
365.L696:
366	;; B is negative, do A-B
367	movw	ax, A_FRAC_L
368	subw	ax, B_FRAC_L
369	movw	A_FRAC_L, ax
370	mov	a, A_FRAC_H
371	subc	a, B_FRAC_H
372	mov	A_FRAC_H, a
373	mov	a, A_FRAC_HH
374	subc	a, B_FRAC_HH
375	mov	A_FRAC_HH, a
376
377.L698:
378	;; A is still A_FRAC_HH
379	bt	a.7, $.L706
380
381	;; subtraction was positive
382	mov	a, #0
383	mov	A_SIGN, a
384	br	$.L712
385
386.L706:
387	;; subtraction was negative
388	mov	a, #0xff
389	mov	A_SIGN, a
390
391	;; This negates A_FRAC
392	mov	a, A_FRAC_L
393	xor	a, #0xff		; XOR doesn't mess with carry
394	add	a, #1			; INC doesn't set the carry
395	mov	A_FRAC_L, a
396	mov	a, A_FRAC_LH
397	xor	a, #0xff
398	addc	a, #0
399	mov	A_FRAC_LH, a
400	mov	a, A_FRAC_H
401	xor	a, #0xff
402	addc	a, #0
403	mov	A_FRAC_H, a
404	mov	a, A_FRAC_HH
405	xor	a, #0xff
406	addc	a, #0
407	mov	A_FRAC_HH, a
408
409.L712:
410	;; Renormalize the subtraction
411
412	mov	a, A_FRAC_L
413	or	a, A_FRAC_LH
414	or	a, A_FRAC_H
415	or	a, A_FRAC_HH
416	bz	$.L728
417
418	;; Mantissa is not zero, left shift until the MSB is in the
419	;; right place
4201:
421	movw	ax, A_FRAC_H
422	cmpw	ax, #0x0200
423	bnc	$.L728
424
425	decw	A_EXP
426
427	movw	ax, A_FRAC_L
428	shlw	ax, 1
429	movw	A_FRAC_L, ax
430	movw	ax, A_FRAC_H
431	rolwc	ax, 1
432	movw	A_FRAC_H, ax
433	br	$1b
434
435.L728:
436	;; normalize A and pack it
437
438	movw	ax, A_FRAC_H
439	cmpw	ax, #0x01ff
440	bnh	$1f
441	;; overflow in the mantissa; adjust
442	movw	ax, A_FRAC_H
443	shrw	ax, 1
444	movw	A_FRAC_H, ax
445	mov	a, A_FRAC_LH
446	rorc	a, 1
447	mov	A_FRAC_LH, a
448	mov	a, A_FRAC_L
449	rorc	a, 1
450	mov	A_FRAC_L, a
451	incw	A_EXP
4521:
453
454	call	$!__rl78_int_pack_a_r8
455	addw	sp, #16
456	ret
457
458END_FUNC	___addsf3
459
460START_FUNC	__rl78_int_pack_a_r8
461	;; pack A to R8
462	movw	ax, A_EXP
463	addw	ax, #126	; not 127, we want the "bt/bf" test to check for denormals
464
465	bf	a.7, $1f
466	;; make a denormal
4672:
468	movw	bc, ax
469	movw	ax, A_FRAC_H
470	shrw	ax, 1
471	movw	A_FRAC_H, ax
472	mov	a, A_FRAC_LH
473	rorc	a, 1
474	mov	A_FRAC_LH, a
475	mov	a, A_FRAC_L
476	rorc	a, 1
477	mov	A_FRAC_L, a
478	movw	ax, bc
479	incw	ax
480	bt	a.7, $2b
481	decw	ax
4821:
483	incw	ax		; now it's as if we added 127
484	movw	A_EXP, ax
485
486	cmpw	ax, #0xfe
487	bnh	$1f
488	;; store #Inf instead
489	mov	a, A_SIGN
490	or	a, #0x7f
491	mov	x, #0x80
492	movw	r10, ax
493	movw	r8, #0
494	ret
495
4961:
497	bf	a.7, $1f	; note AX has EXP at top of loop
498	;; underflow, denormal?
499	movw	ax, A_FRAC_H
500	shrw	ax, 1
501	movw	A_FRAC_H, ax
502	mov	a, A_FRAC_LH
503	rorc	a, 1
504	movw	A_FRAC_LH, ax
505	mov	a, A_FRAC_L
506	rorc	a, 1
507	movw	A_FRAC_L, ax
508	incw	A_EXP
509	movw	ax, A_EXP
510	br	$1b
511
5121:
513	;; undo the rounding-bit-shift
514	mov	a, A_FRAC_L
515	bf	a.0, $1f
516	;; round up
517	movw	ax, A_FRAC_L
518	addw	ax, #1
519	movw	A_FRAC_L, ax
520	bnc	$1f
521	incw	A_FRAC_H
522
523	;; If the rounding set the bit beyond the end of the fraction, increment the exponent.
524	mov	a, A_FRAC_HH
525	bf	a.1, $1f
526	incw	A_EXP
527
5281:
529	movw	ax, A_FRAC_H
530	shrw	ax, 1
531	movw	A_FRAC_H, ax
532	mov	a, A_FRAC_LH
533	rorc	a, 1
534	mov	A_FRAC_LH, a
535	mov	a, A_FRAC_L
536	rorc	a, 1
537	mov	A_FRAC_L, a
538
539	movw	ax, A_FRAC_L
540	movw	r8, ax
541
542	or	a, x
543	or	a, A_FRAC_H
544	or	a, A_FRAC_HH
545	bnz	$1f
546	movw	ax, #0
547	movw	A_EXP, ax
5481:
549	mov	a, A_FRAC_H
550	and	a, #0x7f
551	mov	b, a
552	mov	a, A_EXP
553	shl	a, 7
554	or	a, b
555	mov	r10, a
556
557	mov	a, A_SIGN
558	and	a, #0x80
559	mov	b, a
560	mov	a, A_EXP
561	shr	a, 1
562	or	a, b
563	mov	r11, a
564
565	ret
566END_FUNC	__rl78_int_pack_a_r8
567
568START_FUNC	___mulsf3
569
570	;; if (isnan(a)) return a
571	movw	ax, sp
572	addw	ax, #4
573	movw	hl, ax
574	call	!!__int_isnan
575	bnz	$1f
576mret_a:
577	movw	ax, [sp+4]
578	movw	r8, ax
579	mov	a, [sp+11]
580	and	a, #0x80
581	mov	b, a
582	movw	ax, [sp+6]
583	xor	a, b		; sign is always a ^ b
584	movw	r10, ax
585	ret
5861:
587	;; if (isnan (b)) return b;
588	movw	ax, sp
589	addw	ax, #8
590	movw	hl, ax
591	call	!!__int_isnan
592	bnz	$1f
593mret_b:
594	movw	ax, [sp+8]
595	movw	r8, ax
596	mov	a, [sp+7]
597	and	a, #0x80
598	mov	b, a
599	movw	ax, [sp+10]
600	xor	a, b		; sign is always a ^ b
601	movw	r10, ax
602	ret
6031:
604	;; if (isinf (a)) return (b==0) ? nan : a
605	movw	ax, sp
606	addw	ax, #4
607	movw	hl, ax
608	call	$!__int_isinf
609	bnz	$.L805
610
611	movw	ax, sp
612	addw	ax, #8
613	movw	hl, ax
614	call	!!__int_iszero
615	bnz	$mret_a
616
617	movw	r8,  #0x0001	; return NaN
618	movw	r10, #0x7f80
619	ret
620
621.L805:
622	;; if (isinf (b)) return (a==0) ? nan : b
623	movw	ax, sp
624	addw	ax, #8
625	movw	hl, ax
626	call	$!__int_isinf
627	bnz	$.L814
628
629	movw	ax, sp
630	addw	ax, #4
631	movw	hl, ax
632	call	!!__int_iszero
633	bnz	$mret_b
634
635	movw	r8,  #0x0001	; return NaN
636	movw	r10, #0x7f80
637	ret
638
639.L814:
640	movw	ax, sp
641	addw	ax, #4
642	movw	hl, ax
643	call	!!__int_iszero
644	bz	$mret_a
645
646	movw	ax, sp
647	addw	ax, #8
648	movw	hl, ax
649	call	!!__int_iszero
650	bz	$mret_b
651
652	;; at this point, we're doing the multiplication.
653
654	subw	sp, #16	; save room for two unpacked values
655
656	movw	ax, sp
657	movw	hl, ax
658	addw	ax, #16+4
659	movw	de, ax
660	call	$!_int_unpack_sf
661
662	movw	ax, sp
663	addw	ax, #8
664	movw	hl, ax
665	addw	ax, #16+8-8
666	movw	de, ax
667	call	$!_int_unpack_sf
668
669	movw	ax, sp
670	movw	hl, ax
671
672	;; multiply SI a.FRAC * SI b.FRAC to DI r8
673
674	subw	sp, #16
675	movw	ax, A_FRAC_L
676	movw	[sp+0], ax
677	movw	ax, A_FRAC_H
678	movw	[sp+2], ax
679
680	movw	ax, B_FRAC_L
681	movw	[sp+8], ax
682	movw	ax, B_FRAC_H
683	movw	[sp+10], ax
684
685	movw	ax, #0
686	movw	[sp+4], ax
687	movw	[sp+6], ax
688	movw	[sp+12], ax
689	movw	[sp+14], ax
690
691	call	!!___muldi3	; MTMPa * MTMPb -> R8..R15
692	addw	sp, #16
693
694	movw	ax, sp
695	movw	hl, ax
696
697	;;  add the exponents together
698	movw	ax, A_EXP
699	addw	ax, B_EXP
700	movw	bc, ax		; exponent in BC
701
702	;; now, re-normalize the DI value in R8..R15 to have the
703	;; MSB in the "right" place, adjusting BC as we shift it.
704
705	;; The value will normally be in this range:
706	;; R15              R8
707	;; 0001_0000_0000_0000
708	;; 0003_ffff_fc00_0001
709
710	;; so to speed it up, we normalize to:
711	;; 0001_xxxx_xxxx_xxxx
712	;; then extract the bytes we want (r11-r14)
713
7141:
715	mov	a, r15
716	cmp0	a
717	bnz	$2f
718	mov	a, r14
719	and	a, #0xfe
720	bz	$1f
7212:
722	;; shift right, inc exponent
723	movw	ax, r14
724	shrw	ax, 1
725	movw	r14, ax
726	mov	a, r13
727	rorc	a, 1
728	mov	r13, a
729	mov	a, r12
730	rorc	a, 1
731	mov	r12, a
732	mov	a, r11
733	rorc	a, 1
734	mov	r11, a
735	;; we don't care about r8/r9/r10 if we're shifting this way
736	incw	bc
737	br	$1b
7381:
739	mov	a, r15
740	or	a, r14
741	bnz	$1f
742	;; shift left, dec exponent
743	movw	ax, r8
744	shlw	ax, 1
745	movw	r8, ax
746	movw	ax, r10
747	rolwc	ax, 1
748	movw	r10, ax
749	movw	ax, r12
750	rolwc	ax, 1
751	movw	r12, ax
752	movw	ax, r14
753	rolwc	ax, 1
754	movw	r14, ax
755	decw	bc
756	br	$1b
7571:
758	;; at this point, FRAC is in R11..R14 and EXP is in BC
759	movw	ax, bc
760	movw	A_EXP, ax
761
762	mov	a, r11
763	mov	A_FRAC_L, a
764	mov	a, r12
765	mov	A_FRAC_LH, a
766	mov	a, r13
767	mov	A_FRAC_H, a
768	mov	a, r14
769	mov	A_FRAC_HH, a
770
771	mov	a, A_SIGN
772	xor	a, B_SIGN
773	mov	A_SIGN, a
774
775	call	$!__rl78_int_pack_a_r8
776
777	addw	sp, #16
778	ret
779
780END_FUNC		___mulsf3
781
782START_FUNC		___divsf3
783
784	;; if (isnan(a)) return a
785	movw	ax, sp
786	addw	ax, #4
787	movw	hl, ax
788	call	!!__int_isnan
789	bnz	$1f
790dret_a:
791	movw	ax, [sp+4]
792	movw	r8, ax
793	mov	a, [sp+11]
794	and	a, #0x80
795	mov	b, a
796	movw	ax, [sp+6]
797	xor	a, b		; sign is always a ^ b
798	movw	r10, ax
799	ret
8001:
801	;; if (isnan (b)) return b;
802	movw	ax, sp
803	addw	ax, #8
804	movw	hl, ax
805	call	!!__int_isnan
806	bnz	$1f
807dret_b:
808	movw	ax, [sp+8]
809	movw	r8, ax
810	mov	a, [sp+7]
811	and	a, #0x80
812	mov	b, a
813	movw	ax, [sp+10]
814	xor	a, b		; sign is always a ^ b
815	movw	r10, ax
816	ret
8171:
818
819	;; if (isinf (a)) return isinf(b) ? nan : a
820
821	movw	ax, sp
822	addw	ax, #4
823	movw	hl, ax
824	call	$!__int_isinf
825	bnz	$1f
826
827	movw	ax, sp
828	addw	ax, #8
829	movw	hl, ax
830	call	$!__int_isinf
831	bnz	$dret_a
832dret_nan:
833	movw	r8,  #0x0001	; return NaN
834	movw	r10, #0x7f80
835	ret
836
8371:
838
839	;; if (iszero (a)) return iszero(b) ? nan : a
840
841	movw	ax, sp
842	addw	ax, #4
843	movw	hl, ax
844	call	!!__int_iszero
845	bnz	$1f
846
847	movw	ax, sp
848	addw	ax, #8
849	movw	hl, ax
850	call	!!__int_iszero
851	bnz	$dret_a
852	br	$dret_nan
853
8541:
855	;; if (isinf (b)) return 0
856
857	movw	ax, sp
858	addw	ax, #8
859	movw	hl, ax
860	call	$!__int_isinf
861	bnz	$1f
862
863	mov	a, [sp+7]
864	mov	b, a
865	mov	a, [sp+11]
866	xor	a, b
867	and	a, #0x80
868	mov	r11, a
869	movw	r8, #0
870	mov	r10, #0
871	ret
872
8731:
874	;; if (iszero (b)) return Inf
875
876	movw	ax, sp
877	addw	ax, #8
878	movw	hl, ax
879	call	!!__int_iszero
880	bnz	$1f
881
882	mov	a, [sp+7]
883	mov	b, a
884	mov	a, [sp+11]
885	xor	a, b
886	or	a, #0x7f
887	mov	r11, a
888	movw	r8, #0
889	mov	r10, #0x80
890	ret
8911:
892
893	;; at this point, we're doing the division.  Normalized
894	;; mantissas look like:
895	;; 01.xx.xx.xx
896	;; so we divide:
897	;; 01.xx.xx.xx.00.00.00.00
898	;; by          01.xx.xx.xx
899	;; to get approx 00.80.00.00.00 to 01.ff.ff.ff.00
900
901
902	subw	sp, #16	; save room for two unpacked values
903
904	movw	ax, sp
905	movw	hl, ax
906	addw	ax, #16+4
907	movw	de, ax
908	call	$!_int_unpack_sf
909
910	movw	ax, sp
911	addw	ax, #8
912	movw	hl, ax
913	addw	ax, #16+8-8
914	movw	de, ax
915	call	$!_int_unpack_sf
916
917	movw	ax, sp
918	movw	hl, ax
919
920	;; divide DI a.FRAC / SI b.FRAC to DI r8
921
922	subw	sp, #16
923	movw	ax, A_FRAC_L
924	movw	[sp+4], ax
925	movw	ax, A_FRAC_H
926	movw	[sp+6], ax
927
928	movw	ax, B_FRAC_L
929	movw	[sp+8], ax
930	movw	ax, B_FRAC_H
931	movw	[sp+10], ax
932
933	movw	ax, #0
934	movw	[sp+0], ax
935	movw	[sp+2], ax
936	movw	[sp+12], ax
937	movw	[sp+14], ax
938
939	call	!!___divdi3	; MTMPa / MTMPb -> R8..R15
940	addw	sp, #16
941
942	movw	ax, sp
943	movw	hl, ax
944
945	;;  subtract the exponents A - B
946	movw	ax, A_EXP
947	subw	ax, B_EXP
948	movw	bc, ax		; exponent in BC
949
950	;; now, re-normalize the DI value in R8..R15 to have the
951	;; MSB in the "right" place, adjusting BC as we shift it.
952
953	;; The value will normally be in this range:
954	;; R15              R8
955	;; 0000_0000_8000_0000
956	;; 0000_0001_ffff_ff00
957
958	;; so to speed it up, we normalize to:
959	;; 0000_0001_xxxx_xxxx
960	;; then extract the bytes we want (r9-r12)
961
9621:
963	movw	ax, r14
964	cmpw	ax, #0
965	bnz	$2f
966	movw	ax, r12
967	cmpw	ax, #1
968	bnh	$1f
9692:
970	;; shift right, inc exponent
971	movw	ax, r14
972	shrw	ax, 1
973	movw	r14, ax
974	mov	a, r13
975	rorc	a, 1
976	mov	r13, a
977	mov	a, r12
978	rorc	a, 1
979	mov	r12, a
980	mov	a, r11
981	rorc	a, 1
982	mov	r11, a
983	mov	a, r10
984	rorc	a, 1
985	mov	r10, a
986	mov	a, r9
987	rorc	a, 1
988	mov	r9, a
989	mov	a, r8
990	rorc	a, 1
991	mov	r8, a
992
993	incw	bc
994	br	$1b
9951:
996	;; the previous loop leaves r15.r13 zero
997	mov	a, r12
998	cmp0	a
999	bnz	$1f
1000	;; shift left, dec exponent
1001	movw	ax, r8
1002	shlw	ax, 1
1003	movw	r8, ax
1004	movw	ax, r10
1005	rolwc	ax, 1
1006	movw	r10, ax
1007	movw	ax, r12
1008	rolwc	ax, 1
1009	movw	r12, ax
1010	;; don't need to do r14
1011	decw	bc
1012	br	$1b
10131:
1014	;; at this point, FRAC is in R8..R11 and EXP is in BC
1015	movw	ax, bc
1016	movw	A_EXP, ax
1017
1018	mov	a, r9
1019	mov	A_FRAC_L, a
1020	mov	a, r10
1021	mov	A_FRAC_LH, a
1022	mov	a, r11
1023	mov	A_FRAC_H, a
1024	mov	a, r12
1025	mov	A_FRAC_HH, a
1026
1027	mov	a, A_SIGN
1028	xor	a, B_SIGN
1029	mov	A_SIGN, a
1030
1031	call	$!__rl78_int_pack_a_r8
1032
1033	addw	sp, #16
1034	ret
1035
1036END_FUNC	___divsf3
1037