fpmath-sf.S revision 1.1.1.1 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
33 START_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
50 END_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
66 START_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
106 END_FUNC _int_unpack_sf
107
108 ; func(SF a,SF b)
109 ; [SP+4..7] a
110 ; [SP+8..11] b
111
112 START_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
138 END_FUNC ___subsf3
139
140 START_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
148 ret_a:
149 movw ax, [sp+4]
150 movw r8, ax
151 movw ax, [sp+6]
152 movw r10, ax
153 ret
154
155 1: ;; if (isnan (b)) return b;
156 movw ax, sp
157 addw ax, #8
158 movw hl, ax
159 call !!__int_isnan
160 bnz $2f
161 ret_b:
162 movw ax, [sp+8]
163 movw r8, ax
164 movw ax, [sp+10]
165 movw r10, ax
166 ret
167
168 2: ;; 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
193 3: ;; 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
223 4: ;; 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
264 1:
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
280 1:
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
291 1:
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
311 1:
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
329 1:
330
331 5: ;; 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
350 1: ;; 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
420 1:
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
452 1:
453
454 call $!__rl78_int_pack_a_r8
455 addw sp, #16
456 ret
457
458 END_FUNC ___addsf3
459
460 START_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
467 2:
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
482 1:
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
496 1:
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
512 1:
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
528 1:
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
548 1:
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
566 END_FUNC __rl78_int_pack_a_r8
567
568 START_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
576 mret_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
586 1:
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
593 mret_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
603 1:
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
714 1:
715 mov a, r15
716 cmp0 a
717 bnz $2f
718 mov a, r14
719 and a, #0xfe
720 bz $1f
721 2:
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
738 1:
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
757 1:
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
780 END_FUNC ___mulsf3
781
782 START_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
790 dret_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
800 1:
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
807 dret_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
817 1:
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
832 dret_nan:
833 movw r8, #0x0001 ; return NaN
834 movw r10, #0x7f80
835 ret
836
837 1:
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
854 1:
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
873 1:
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
891 1:
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
962 1:
963 movw ax, r14
964 cmpw ax, #0
965 bnz $2f
966 movw ax, r12
967 cmpw ax, #1
968 bnh $1f
969 2:
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
995 1:
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
1013 1:
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
1036 END_FUNC ___divsf3
1037