1 * $NetBSD: bindec.sa,v 1.4 2001/09/16 16:34:32 wiz Exp $
3 * MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
4 * M68000 Hi-Performance Microprocessor Division
5 * M68040 Software Package
7 * M68040 Software Package Copyright (c) 1993, 1994 Motorola Inc.
10 * THE SOFTWARE is provided on an "AS IS" basis and without warranty.
11 * To the maximum extent permitted by applicable law,
12 * MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
13 * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
14 * PARTICULAR PURPOSE and any warranty against infringement with
15 * regard to the SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF)
16 * and any accompanying written materials.
18 * To the maximum extent permitted by applicable law,
19 * IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
20 * (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS
21 * PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR
22 * OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE
23 * SOFTWARE. Motorola assumes no responsibility for the maintenance
24 * and support of the SOFTWARE.
26 * You are hereby granted a copyright license to use, modify, and
27 * distribute the SOFTWARE so long as this entire notice is retained
28 * without alteration in any modified and/or redistributed versions,
29 * and that such modified versions are clearly identified as such.
30 * No licenses are granted by implication, estoppel or otherwise
31 * under any patents or trademarks of Motorola, Inc.
34 * bindec.sa 3.4 1/3/91
39 * Converts an input in extended precision format
43 * a0 points to the input extended precision value
44 * value in memory; d0 contains the k-factor sign-extended
45 * to 32-bits. The input may be either normalized,
46 * unnormalized, or denormalized.
48 * Output: result in the FP_SCR1 space on the stack.
50 * Saves and Modifies: D2-D7,A2,FP2
54 * A1. Set RM and size ext; Set SIGMA = sign of input.
55 * The k-factor is saved for use in d7. Clear the
56 * BINDEC_FLG for separating normalized/denormalized
57 * input. If input is unnormalized or denormalized,
60 * A2. Set X = abs(input).
63 * ILOG is the log base 10 of the input value. It is
64 * approximated by adding e + 0.f when the original
65 * value is viewed as 2^^e * 1.f in extended precision.
66 * This value is stored in d6.
69 * The operation in A3 above may have set INEX2.
72 * ICTR is a flag used in A13. It must be set before the
76 * LEN is the number of digits to be displayed. The
77 * k-factor can dictate either the total number of digits,
78 * if it is a positive number, or the number of digits
79 * after the decimal point which are to be included as
80 * significant. See the 68882 manual for examples.
81 * If LEN is computed to be greater than 17, set OPERR in
82 * USER_FPSR. LEN is stored in d4.
84 * A7. Calculate SCALE.
85 * SCALE is equal to 10^ISCALE, where ISCALE is the number
86 * of decimal places needed to insure LEN integer digits
87 * in the output before conversion to bcd. LAMBDA is the
88 * sign of ISCALE, used in A9. Fp1 contains
89 * 10^^(abs(ISCALE)) using a rounding mode which is a
90 * function of the original rounding mode and the signs
91 * of ISCALE and X. A table is given in the code.
93 * A8. Clr INEX; Force RZ.
94 * The operation in A3 above may have set INEX2.
95 * RZ mode is forced for the scaling operation to insure
96 * only one rounding error. The grs bits are collected in
97 * the INEX flag for use in A10.
100 * The mantissa is scaled to the desired number of
101 * significant digits. The excess digits are collected
105 * If INEX is set, round error occurred. This is
106 * compensated for by 'or-ing' in the INEX2 flag to
109 * A11. Restore original FPCR; set size ext.
110 * Perform FINT operation in the user's rounding mode.
111 * Keep the size to extended.
113 * A12. Calculate YINT = FINT(Y) according to user's rounding
114 * mode. The FPSP routine sintd0 is used. The output
117 * A13. Check for LEN digits.
118 * If the int operation results in more than LEN digits,
119 * or less than LEN -1 digits, adjust ILOG and repeat from
120 * A6. This test occurs only on the first pass. If the
121 * result is exactly 10^LEN, decrement ILOG and divide
122 * the mantissa by 10.
124 * A14. Convert the mantissa to bcd.
125 * The binstr routine is used to convert the LEN digit
126 * mantissa to bcd in memory. The input to binstr is
127 * to be a fraction; i.e. (mantissa)/10^LEN and adjusted
128 * such that the decimal point is to the left of bit 63.
129 * The bcd digits are stored in the correct position in
130 * the final string area in memory.
132 * A15. Convert the exponent to bcd.
133 * As in A14 above, the exp is converted to bcd and the
134 * digits are stored in the final string.
135 * Test the length of the final exponent string. If the
136 * length is 4, set operr.
138 * A16. Write sign bits to final string.
140 * Implementation Notes:
142 * The registers are used as follows:
144 * d0: scratch; LEN input to binstr
146 * d2: upper 32-bits of mantissa for binstr
147 * d3: scratch;lower 32-bits of mantissa for binstr
152 * a0: ptr for original operand/final result
153 * a1: scratch pointer
154 * a2: pointer to FP_X; abs(original value) in ext
164 BINDEC IDNT 2,1 Motorola 040 Floating Point Software Package
170 * Constants in extended precision
171 LOG2 dc.l $3FFD0000,$9A209A84,$FBCFF798,$00000000
172 LOG2UP1 dc.l $3FFD0000,$9A209A84,$FBCFF799,$00000000
174 * Constants in single precision
175 FONE dc.l $3F800000,$00000000,$00000000,$00000000
176 FTWO dc.l $40000000,$00000000,$00000000,$00000000
177 FTEN dc.l $41200000,$00000000,$00000000,$00000000
178 F4933 dc.l $459A2800,$00000000,$00000000,$00000000
187 xref ptenrn,ptenrm,ptenrp
192 movem.l d2-d7/a2,-(a7)
193 fmovem.x fp0-fp2,-(a7)
195 * A1. Set RM and size ext. Set SIGMA = sign input;
196 * The k-factor is saved for use in d7. Clear BINDEC_FLG for
197 * separating normalized/denormalized input. If the input
198 * is a denormalized number, set the BINDEC_FLG memory word
199 * to signal denorm. If the input is unnormalized, normalize
200 * the input and test for denormalized result.
202 fmove.l #rm_mode,FPCR ;set RM and ext
203 move.l (a0),L_SCR2(a6) ;save exponent for sign check
204 move.l d0,d7 ;move k-factor to d7
205 clr.b BINDEC_FLG(a6) ;clr norm/denorm flag
206 move.w STAG(a6),d0 ;get stag
207 andi.w #$e000,d0 ;isolate stag bits
208 beq A2_str ;if zero, input is norm
210 * Normalize the denorm
214 andi.w #$7fff,d0 ;strip sign of normalized exp
224 * Test if the normalized input is denormalized
227 bgt.b pos_exp ;if greater than zero, it is a norm
228 st BINDEC_FLG(a6) ;set flag for denorm
230 andi.w #$7fff,d0 ;strip sign of normalized exp
235 * A2. Set X = abs(input).
238 move.l (a0),FP_SCR2(a6) ; move input to work space
239 move.l 4(a0),FP_SCR2+4(a6) ; move input to work space
240 move.l 8(a0),FP_SCR2+8(a6) ; move input to work space
241 andi.l #$7fffffff,FP_SCR2(a6) ;create abs(X)
244 * ILOG is the log base 10 of the input value. It is approx-
245 * imated by adding e + 0.f when the original value is viewed
246 * as 2^^e * 1.f in extended precision. This value is stored
251 * d0: k-factor/exponent
257 * d7: k-factor/Unchanged
258 * a0: ptr for original operand/final result
265 * F_SCR2:Abs(X)/Abs(X) with $3fff exponent
267 * L_SCR2:first word of X packed/Unchanged
269 tst.b BINDEC_FLG(a6) ;check for denorm
270 beq.b A3_cont ;if clr, continue with norm
271 move.l #-4933,d6 ;force ILOG = -4933
274 move.w FP_SCR2(a6),d0 ;move exp to d0
275 move.w #$3fff,FP_SCR2(a6) ;replace exponent with 0x3fff
276 fmove.x FP_SCR2(a6),fp0 ;now fp0 has 1.f
277 sub.w #$3fff,d0 ;strip off bias
278 fadd.w d0,fp0 ;add in exp
279 fsub.s FONE,fp0 ;subtract off 1.0
280 fbge.w pos_res ;if pos, branch
281 fmul.x LOG2UP1,fp0 ;if neg, mul by LOG2UP1
282 fmove.l fp0,d6 ;put ILOG in d6 as a lword
283 bra.b A4_str ;go move out ILOG
285 fmul.x LOG2,fp0 ;if pos, mul by LOG2
286 fmove.l fp0,d6 ;put ILOG in d6 as a lword
290 * The operation in A3 above may have set INEX2.
293 fmove.l #0,FPSR ;zero all of fpsr - nothing needed
297 * ICTR is a flag used in A13. It must be set before the
298 * loop entry A6. The lower word of d5 is used for ICTR.
304 * LEN is the number of digits to be displayed. The k-factor
305 * can dictate either the total number of digits, if it is
306 * a positive number, or the number of digits after the
307 * original decimal point which are to be included as
308 * significant. See the 68882 manual for examples.
309 * If LEN is computed to be greater than 17, set OPERR in
310 * USER_FPSR. LEN is stored in d4.
314 * d0: exponent/Unchanged
317 * d4: exc picture/LEN
320 * d7: k-factor/Unchanged
321 * a0: ptr for original operand/final result
324 * fp0: float(ILOG)/Unchanged
328 * F_SCR2:Abs(X) with $3fff exponent/Unchanged
330 * L_SCR2:first word of X packed/Unchanged
333 tst.l d7 ;branch on sign of k
334 ble.b k_neg ;if k <= 0, LEN = ILOG + 1 - k
335 move.l d7,d4 ;if k > 0, LEN = k
336 bra.b len_ck ;skip to LEN check
338 move.l d6,d4 ;first load ILOG to d4
339 sub.l d7,d4 ;subtract off k
340 addq.l #1,d4 ;add in the 1
342 tst.l d4 ;LEN check: branch on sign of LEN
343 ble.b LEN_ng ;if neg, set LEN = 1
344 cmp.l #17,d4 ;test if LEN > 17
345 ble.b A7_str ;if not, forget it
346 move.l #17,d4 ;set max LEN = 17
347 tst.l d7 ;if negative, never set OPERR
348 ble.b A7_str ;if positive, continue
349 or.l #opaop_mask,USER_FPSR(a6) ;set OPERR & AIOP in USER_FPSR
350 bra.b A7_str ;finished here
352 moveq.l #1,d4 ;min LEN is 1
355 * A7. Calculate SCALE.
356 * SCALE is equal to 10^ISCALE, where ISCALE is the number
357 * of decimal places needed to insure LEN integer digits
358 * in the output before conversion to bcd. LAMBDA is the sign
359 * of ISCALE, used in A9. Fp1 contains 10^^(abs(ISCALE)) using
360 * the rounding mode as given in the following table (see
361 * Coonen, p. 7.23 as ref.; however, the SCALE variable is
362 * of opposite sign in bindec.sa from Coonen).
365 * FPCR[6:5] LAMBDA SIGN(X) FPCR[6:5]
366 * ----------------------------------------------
386 * d0: exponent/scratch - final is 0
387 * d2: x/0 or 24 for A9
388 * d3: x/scratch - offset ptr into PTENRM array
391 * d6: ILOG/ILOG or k if ((k<=0)&(ILOG<k))
392 * d7: k-factor/Unchanged
393 * a0: ptr for original operand/final result
394 * a1: x/ptr to PTENRM array
396 * fp0: float(ILOG)/Unchanged
400 * F_SCR2:Abs(X) with $3fff exponent/Unchanged
402 * L_SCR2:first word of X packed/Unchanged
405 tst.l d7 ;test sign of k
406 bgt.b k_pos ;if pos and > 0, skip this
407 cmp.l d6,d7 ;test k - ILOG
408 blt.b k_pos ;if ILOG >= k, skip this
409 move.l d7,d6 ;if ((k<0) & (ILOG < k)) ILOG = k
411 move.l d6,d0 ;calc ILOG + 1 - LEN in d0
412 addq.l #1,d0 ;add the 1
413 sub.l d4,d0 ;sub off LEN
414 swap d5 ;use upper word of d5 for LAMBDA
415 clr.w d5 ;set it zero initially
416 clr.w d2 ;set up d2 for very small case
417 tst.l d0 ;test sign of ISCALE
418 bge.b iscale ;if pos, skip next inst
419 addq.w #1,d5 ;if neg, set LAMBDA true
420 cmp.l #$ffffecd4,d0 ;test iscale <= -4908
421 bgt.b no_inf ;if false, skip rest
422 addi.l #24,d0 ;add in 24 to iscale
423 move.l #24,d2 ;put 24 in d2 for A9
425 neg.l d0 ;and take abs of ISCALE
427 fmove.s FONE,fp1 ;init fp1 to 1
428 bfextu USER_FPCR(a6){26:2},d1 ;get initial rmode bits
429 add.w d1,d1 ;put them in bits 2:1
430 add.w d5,d1 ;add in LAMBDA
431 add.w d1,d1 ;put them in bits 3:1
432 tst.l L_SCR2(a6) ;test sign of original x
433 bge.b x_pos ;if pos, don't set bit 0
434 addq.l #1,d1 ;if neg, set bit 0
436 lea.l RBDTBL,a2 ;load rbdtbl base
437 move.b (a2,d1),d3 ;load d3 with new rmode
438 lsl.l #4,d3 ;put bits in proper position
439 fmove.l d3,fpcr ;load bits into fpu
440 lsr.l #4,d3 ;put bits in proper position
441 tst.b d3 ;decode new rmode for pten table
442 bne.b not_rn ;if zero, it is RN
443 lea.l PTENRN,a1 ;load a1 with RN table base
444 bra.b rmode ;exit decode
446 lsr.b #1,d3 ;get lsb in carry
447 bcc.b not_rp ;if carry clear, it is RM
448 lea.l PTENRP,a1 ;load a1 with RP table base
449 bra.b rmode ;exit decode
451 lea.l PTENRM,a1 ;load a1 with RM table base
453 clr.l d3 ;clr table index
455 lsr.l #1,d0 ;shift next bit into carry
456 bcc.b e_next ;if zero, skip the mul
457 fmul.x (a1,d3),fp1 ;mul by 10**(d3_bit_no)
459 add.l #12,d3 ;inc d3 to next pwrten table entry
460 tst.l d0 ;test if ISCALE is zero
461 bne.b e_loop ;if not, loop
464 * A8. Clr INEX; Force RZ.
465 * The operation in A3 above may have set INEX2.
466 * RZ mode is forced for the scaling operation to insure
467 * only one rounding error. The grs bits are collected in
468 * the INEX flag for use in A10.
473 fmove.l #0,FPSR ;clr INEX
474 fmove.l #rz_mode,FPCR ;set RZ rounding mode
478 * The mantissa is scaled to the desired number of significant
479 * digits. The excess digits are collected in INEX2. If mul,
480 * Check d2 for excess 10 exponential value. If not zero,
481 * the iscale value would have caused the pwrten calculation
482 * to overflow. Only a negative iscale can cause this, so
483 * multiply by 10^(d2), which is now only allowed to be 24,
484 * with a multiply by 10^8 and 10^16, which is exact since
485 * 10^24 is exact. If the input was denormalized, we must
486 * create a busy stack frame with the mul command and the
487 * two operands, and allow the fpu to complete the multiply.
491 * d0: FPCR with RZ mode/Unchanged
492 * d2: 0 or 24/unchanged
497 * d7: k-factor/Unchanged
498 * a0: ptr for original operand/final result
499 * a1: ptr to PTENRM array/Unchanged
501 * fp0: float(ILOG)/X adjusted for SCALE (Y)
502 * fp1: 10^ISCALE/Unchanged
505 * F_SCR2:Abs(X) with $3fff exponent/Unchanged
507 * L_SCR2:first word of X packed/Unchanged
510 fmove.x (a0),fp0 ;load X from memory
511 fabs.x fp0 ;use abs(X)
512 tst.w d5 ;LAMBDA is in lower word of d5
513 bne.b short_sc_mul ;if neg (LAMBDA = 1), scale by mul
514 fdiv.x fp1,fp0 ;calculate X / SCALE -> Y to fp0
515 bra.b A10_st ;branch to A10
519 tst.b BINDEC_FLG(a6) ;check for denorm
520 beq.b A9_norm ;if norm, continue with mul
521 fmovem.x fp1,-(a7) ;load ETEMP with 10^ISCALE
522 move.l 8(a0),-(a7) ;load FPTEMP with input arg
525 move.l #18,d3 ;load count for busy stack
527 clr.l -(a7) ;clear lword on stack
529 move.b VER_TMP(a6),(a7) ;write current version number
530 move.b #BUSY_SIZE-4,1(a7) ;write current busy size
531 move.b #$10,$44(a7) ;set fcefpte[15] bit
532 move.w #$0023,$40(a7) ;load cmdreg1b with mul command
533 move.b #$fe,$8(a7) ;load all 1s to cu savepc
534 frestore (a7)+ ;restore frame to fpu for completion
535 fmul.x 36(a1),fp0 ;multiply fp0 by 10^8
536 fmul.x 48(a1),fp0 ;multiply fp0 by 10^16
539 tst.w d2 ;test for small exp case
540 beq.b A9_con ;if zero, continue as normal
541 fmul.x 36(a1),fp0 ;multiply fp0 by 10^8
542 fmul.x 48(a1),fp0 ;multiply fp0 by 10^16
544 fmul.x fp1,fp0 ;calculate X * SCALE -> Y to fp0
548 * If INEX is set, round error occurred. This is compensated
549 * for by 'or-ing' in the INEX2 flag to the lsb of Y.
553 * d0: FPCR with RZ mode/FPSR with INEX2 isolated
559 * d7: k-factor/Unchanged
560 * a0: ptr for original operand/final result
561 * a1: ptr to PTENxx array/Unchanged
562 * a2: x/ptr to FP_SCR2(a6)
563 * fp0: Y/Y with lsb adjusted
564 * fp1: 10^ISCALE/Unchanged
568 fmove.l FPSR,d0 ;get FPSR
569 fmove.x fp0,FP_SCR2(a6) ;move Y to memory
570 lea.l FP_SCR2(a6),a2 ;load a2 with ptr to FP_SCR2
571 btst.l #9,d0 ;check if INEX2 set
572 beq.b A11_st ;if clear, skip rest
573 ori.l #1,8(a2) ;or in 1 to lsb of mantissa
574 fmove.x FP_SCR2(a6),fp0 ;write adjusted Y back to fpu
577 * A11. Restore original FPCR; set size ext.
578 * Perform FINT operation in the user's rounding mode. Keep
579 * the size to extended. The sintdo entry point in the sint
580 * routine expects the FPCR value to be in USER_FPCR for
581 * mode and precision. The original FPCR is saved in L_SCR1.
584 move.l USER_FPCR(a6),L_SCR1(a6) ;save it for later
585 andi.l #$00000030,USER_FPCR(a6) ;set size to ext,
589 * A12. Calculate YINT = FINT(Y) according to user's rounding mode.
590 * The FPSP routine sintd0 is used. The output is in fp0.
594 * d0: FPSR with AINEX cleared/FPCR with size set to ext
598 * d5: ICTR:LAMBDA/Unchanged
600 * d7: k-factor/Unchanged
601 * a0: ptr for original operand/src ptr for sintdo
602 * a1: ptr to PTENxx array/Unchanged
603 * a2: ptr to FP_SCR2(a6)/Unchanged
604 * a6: temp pointer to FP_SCR2(a6) - orig value saved and restored
606 * fp1: 10^ISCALE/Unchanged
609 * F_SCR2:Y adjusted for inex/Y with original exponent
610 * L_SCR1:x/original USER_FPCR
611 * L_SCR2:first word of X packed/Unchanged
614 movem.l d0-d1/a0-a1,-(a7) ;save regs used by sintd0
615 move.l L_SCR1(a6),-(a7)
616 move.l L_SCR2(a6),-(a7)
617 lea.l FP_SCR2(a6),a0 ;a0 is ptr to F_SCR2(a6)
618 fmove.x fp0,(a0) ;move Y to memory at FP_SCR2(a6)
619 tst.l L_SCR2(a6) ;test sign of original operand
620 bge.b do_fint ;if pos, use Y
621 or.l #$80000000,(a0) ;if neg, use -Y
623 move.l USER_FPSR(a6),-(a7)
624 bsr sintdo ;sint routine returns int in fp0
625 move.b (a7),USER_FPSR(a6)
627 move.l (a7)+,L_SCR2(a6)
628 move.l (a7)+,L_SCR1(a6)
629 movem.l (a7)+,d0-d1/a0-a1 ;restore regs used by sint
630 move.l L_SCR2(a6),FP_SCR2(a6) ;restore original exponent
631 move.l L_SCR1(a6),USER_FPCR(a6) ;restore user's FPCR
634 * A13. Check for LEN digits.
635 * If the int operation results in more than LEN digits,
636 * or less than LEN -1 digits, adjust ILOG and repeat from
637 * A6. This test occurs only on the first pass. If the
638 * result is exactly 10^LEN, decrement ILOG and divide
639 * the mantissa by 10. The calculation of 10^LEN cannot
640 * be inexact, since all powers of ten upto 10^27 are exact
641 * in extended precision, so the use of a previous power-of-ten
642 * table will introduce no error.
647 * d0: FPCR with size set to ext/scratch final = 0
649 * d3: x/scratch final = x
650 * d4: LEN/LEN adjusted
651 * d5: ICTR:LAMBDA/LAMBDA:ICTR
652 * d6: ILOG/ILOG adjusted
653 * d7: k-factor/Unchanged
654 * a0: pointer into memory for packed bcd string formation
655 * a1: ptr to PTENxx array/Unchanged
656 * a2: ptr to FP_SCR2(a6)/Unchanged
657 * fp0: int portion of Y/abs(YINT) adjusted
658 * fp1: 10^ISCALE/Unchanged
661 * F_SCR2:Y with original exponent/Unchanged
662 * L_SCR1:original USER_FPCR/Unchanged
663 * L_SCR2:first word of X packed/Unchanged
666 swap d5 ;put ICTR in lower word of d5
667 tst.w d5 ;check if ICTR = 0
668 bne not_zr ;if non-zero, go to second test
672 fmove.s FONE,fp2 ;init fp2 to 1.0
673 move.l d4,d0 ;put LEN in d0
674 subq.l #1,d0 ;d0 = LEN -1
675 clr.l d3 ;clr table index
677 lsr.l #1,d0 ;shift next bit into carry
678 bcc.b l_next ;if zero, skip the mul
679 fmul.x (a1,d3),fp2 ;mul by 10**(d3_bit_no)
681 add.l #12,d3 ;inc d3 to next pwrten table entry
682 tst.l d0 ;test if LEN is zero
683 bne.b l_loop ;if not, loop
685 * 10^LEN-1 is computed for this test and A14. If the input was
686 * denormalized, check only the case in which YINT > 10^LEN.
688 tst.b BINDEC_FLG(a6) ;check if input was norm
689 beq.b A13_con ;if norm, continue with checking
690 fabs.x fp0 ;take abs of YINT
693 * Compare abs(YINT) to 10^(LEN-1) and 10^LEN
696 fabs.x fp0 ;take abs of YINT
697 fcmp.x fp2,fp0 ;compare abs(YINT) with 10^(LEN-1)
698 fbge.w test_2 ;if greater, do next test
699 subq.l #1,d6 ;subtract 1 from ILOG
700 move.w #1,d5 ;set ICTR
701 fmove.l #rm_mode,FPCR ;set rmode to RM
702 fmul.s FTEN,fp2 ;compute 10^LEN
703 bra.w A6_str ;return to A6 and recompute YINT
705 fmul.s FTEN,fp2 ;compute 10^LEN
706 fcmp.x fp2,fp0 ;compare abs(YINT) with 10^LEN
707 fblt.w A14_st ;if less, all is ok, go to A14
708 fbgt.w fix_ex ;if greater, fix and redo
709 fdiv.s FTEN,fp0 ;if equal, divide by 10
710 addq.l #1,d6 ; and inc ILOG
711 bra.b A14_st ; and continue elsewhere
713 addq.l #1,d6 ;increment ILOG by 1
714 move.w #1,d5 ;set ICTR
715 fmove.l #rm_mode,FPCR ;set rmode to RM
716 bra.w A6_str ;return to A6 and recompute YINT
718 * Since ICTR <> 0, we have already been through one adjustment,
719 * and shouldn't have another; this is to check if abs(YINT) = 10^LEN
720 * 10^LEN is again computed using whatever table is in a1 since the
721 * value calculated cannot be inexact.
724 fmove.s FONE,fp2 ;init fp2 to 1.0
725 move.l d4,d0 ;put LEN in d0
726 clr.l d3 ;clr table index
728 lsr.l #1,d0 ;shift next bit into carry
729 bcc.b z_next ;if zero, skip the mul
730 fmul.x (a1,d3),fp2 ;mul by 10**(d3_bit_no)
732 add.l #12,d3 ;inc d3 to next pwrten table entry
733 tst.l d0 ;test if LEN is zero
734 bne.b z_loop ;if not, loop
735 fabs.x fp0 ;get abs(YINT)
736 fcmp.x fp2,fp0 ;check if abs(YINT) = 10^LEN
737 fbne.w A14_st ;if not, skip this
738 fdiv.s FTEN,fp0 ;divide abs(YINT) by 10
739 addq.l #1,d6 ;and inc ILOG by 1
740 addq.l #1,d4 ; and inc LEN
741 fmul.s FTEN,fp2 ; if LEN++, the get 10^^LEN
744 * A14. Convert the mantissa to bcd.
745 * The binstr routine is used to convert the LEN digit
746 * mantissa to bcd in memory. The input to binstr is
747 * to be a fraction; i.e. (mantissa)/10^LEN and adjusted
748 * such that the decimal point is to the left of bit 63.
749 * The bcd digits are stored in the correct position in
750 * the final string area in memory.
755 * d0: x/LEN call to binstr - final is 0
757 * d2: x/ms 32-bits of mant of abs(YINT)
758 * d3: x/ls 32-bits of mant of abs(YINT)
760 * d5: ICTR:LAMBDA/LAMBDA:ICTR
762 * d7: k-factor/Unchanged
763 * a0: pointer into memory for packed bcd string formation
764 * /ptr to first mantissa byte in result string
765 * a1: ptr to PTENxx array/Unchanged
766 * a2: ptr to FP_SCR2(a6)/Unchanged
767 * fp0: int portion of Y/abs(YINT) adjusted
768 * fp1: 10^ISCALE/Unchanged
769 * fp2: 10^LEN/Unchanged
770 * F_SCR1:x/Work area for final result
771 * F_SCR2:Y with original exponent/Unchanged
772 * L_SCR1:original USER_FPCR/Unchanged
773 * L_SCR2:first word of X packed/Unchanged
776 fmove.l #rz_mode,FPCR ;force rz for conversion
777 fdiv.x fp2,fp0 ;divide abs(YINT) by 10^LEN
779 fmove.x fp0,(a0) ;move abs(YINT)/10^LEN to memory
780 move.l 4(a0),d2 ;move 2nd word of FP_RES to d2
781 move.l 8(a0),d3 ;move 3rd word of FP_RES to d3
782 clr.l 4(a0) ;zero word 2 of FP_RES
783 clr.l 8(a0) ;zero word 3 of FP_RES
784 move.l (a0),d0 ;move exponent to d0
785 swap d0 ;put exponent in lower word
786 beq.b no_sft ;if zero, don't shift
787 subi.l #$3ffd,d0 ;sub bias less 2 to make fract
788 tst.l d0 ;check if > 1
789 bgt.b no_sft ;if so, don't shift
790 neg.l d0 ;make exp positive
792 lsr.l #1,d2 ;shift d2:d3 right, add 0s
793 roxr.l #1,d3 ;the number of places
794 dbf.w d0,m_loop ;given in d0
796 tst.l d2 ;check for mantissa of zero
797 bne.b no_zr ;if not, go on
798 tst.l d3 ;continue zero check
799 beq.b zer_m ;if zero, go directly to binstr
801 clr.l d1 ;put zero in d1 for addx
802 addi.l #$00000080,d3 ;inc at bit 7
803 addx.l d1,d2 ;continue inc
804 andi.l #$ffffff80,d3 ;strip off lsb not used by 882
806 move.l d4,d0 ;put LEN in d0 for binstr call
807 addq.l #3,a0 ;a0 points to M16 byte in result
808 bsr binstr ;call binstr to convert mant
811 * A15. Convert the exponent to bcd.
812 * As in A14 above, the exp is converted to bcd and the
813 * digits are stored in the final string.
815 * Digits are stored in L_SCR1(a6) on return from BINDEC as:
818 * -----------------------------------------
819 * | 0 | e3 | e2 | e1 | e4 | X | X | X |
820 * -----------------------------------------
822 * And are moved into their proper places in FP_SCR1. If digit e4
823 * is non-zero, OPERR is signaled. In all cases, all 4 digits are
824 * written as specified in the 881/882 manual for packed decimal.
828 * d0: x/LEN call to binstr - final is 0
829 * d1: x/scratch (0);shift count for final exponent packing
830 * d2: x/ms 32-bits of exp fraction/scratch
831 * d3: x/ls 32-bits of exp fraction
833 * d5: ICTR:LAMBDA/LAMBDA:ICTR
835 * d7: k-factor/Unchanged
836 * a0: ptr to result string/ptr to L_SCR1(a6)
837 * a1: ptr to PTENxx array/Unchanged
838 * a2: ptr to FP_SCR2(a6)/Unchanged
839 * fp0: abs(YINT) adjusted/float(ILOG)
840 * fp1: 10^ISCALE/Unchanged
841 * fp2: 10^LEN/Unchanged
842 * F_SCR1:Work area for final result/BCD result
843 * F_SCR2:Y with original exponent/ILOG/10^4
844 * L_SCR1:original USER_FPCR/Exponent digits on return from binstr
845 * L_SCR2:first word of X packed/Unchanged
848 tst.b BINDEC_FLG(a6) ;check for denorm
850 ftst.x fp0 ;test for zero
851 fbeq.w den_zero ;if zero, use k-factor or 4933
852 fmove.l d6,fp0 ;float ILOG
853 fabs.x fp0 ;get abs of ILOG
856 tst.l d7 ;check sign of the k-factor
857 blt.b use_ilog ;if negative, use ILOG
858 fmove.s F4933,fp0 ;force exponent to 4933
861 fmove.l d6,fp0 ;float ILOG
862 fabs.x fp0 ;get abs of ILOG
865 ftst.x fp0 ;test for zero
866 fbne.w not_zero ;if zero, force exponent
867 fmove.s FONE,fp0 ;force exponent to 1
870 fmove.l d6,fp0 ;float ILOG
871 fabs.x fp0 ;get abs of ILOG
873 fdiv.x 24(a1),fp0 ;compute ILOG/10^4
874 fmove.x fp0,FP_SCR2(a6) ;store fp0 in memory
875 move.l 4(a2),d2 ;move word 2 to d2
876 move.l 8(a2),d3 ;move word 3 to d3
877 move.w (a2),d0 ;move exp to d0
878 beq.b x_loop_fin ;if zero, skip the shift
879 subi.w #$3ffd,d0 ;subtract off bias
880 neg.w d0 ;make exp positive
882 lsr.l #1,d2 ;shift d2:d3 right
883 roxr.l #1,d3 ;the number of places
884 dbf.w d0,x_loop ;given in d0
886 clr.l d1 ;put zero in d1 for addx
887 addi.l #$00000080,d3 ;inc at bit 6
888 addx.l d1,d2 ;continue inc
889 andi.l #$ffffff80,d3 ;strip off lsb not used by 882
890 move.l #4,d0 ;put 4 in d0 for binstr call
891 lea.l L_SCR1(a6),a0 ;a0 is ptr to L_SCR1 for exp digits
892 bsr binstr ;call binstr to convert exp
893 move.l L_SCR1(a6),d0 ;load L_SCR1 lword to d0
894 move.l #12,d1 ;use d1 for shift count
895 lsr.l d1,d0 ;shift d0 right by 12
896 bfins d0,FP_SCR1(a6){4:12} ;put e3:e2:e1 in FP_SCR1
897 lsr.l d1,d0 ;shift d0 right by 12
898 bfins d0,FP_SCR1(a6){16:4} ;put e4 in FP_SCR1
899 tst.b d0 ;check if e4 is zero
900 beq.b A16_st ;if zero, skip rest
901 or.l #opaop_mask,USER_FPSR(a6) ;set OPERR & AIOP in USER_FPSR
904 * A16. Write sign bits to final string.
905 * Sigma is bit 31 of initial value; RHO is bit 31 of d6 (ILOG).
909 * d0: x/scratch - final is x
913 * d5: ICTR:LAMBDA/LAMBDA:ICTR
914 * d6: ILOG/ILOG adjusted
915 * d7: k-factor/Unchanged
916 * a0: ptr to L_SCR1(a6)/Unchanged
917 * a1: ptr to PTENxx array/Unchanged
918 * a2: ptr to FP_SCR2(a6)/Unchanged
919 * fp0: float(ILOG)/Unchanged
920 * fp1: 10^ISCALE/Unchanged
921 * fp2: 10^LEN/Unchanged
922 * F_SCR1:BCD result with correct signs
924 * L_SCR1:Exponent digits on return from binstr
925 * L_SCR2:first word of X packed/Unchanged
928 clr.l d0 ;clr d0 for collection of signs
929 andi.b #$0f,FP_SCR1(a6) ;clear first nibble of FP_SCR1
930 tst.l L_SCR2(a6) ;check sign of original mantissa
931 bge.b mant_p ;if pos, don't set SM
932 moveq.l #2,d0 ;move 2 in to d0 for SM
934 tst.l d6 ;check sign of ILOG
935 bge.b wr_sgn ;if pos, don't set SE
936 addq.l #1,d0 ;set bit 0 in d0 for SE
938 bfins d0,FP_SCR1(a6){0:2} ;insert SM and SE into FP_SCR1
940 * Clean up and restore all registers used.
942 fmove.l #0,FPSR ;clear possible inex2/ainex bits
943 fmovem.x (a7)+,fp0-fp2
944 movem.l (a7)+,d2-d7/a2