Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:48

0001 #include "fpsp-namespace.h"
0002 //
0003 //
0004 //  bindec.sa 3.4 1/3/91
0005 //
0006 //  bindec
0007 //
0008 //  Description:
0009 //      Converts an input in extended precision format
0010 //      to bcd format.
0011 //
0012 //  Input:
0013 //      a0 points to the input extended precision value
0014 //      value in memory; d0 contains the k-factor sign-extended
0015 //      to 32-bits.  The input may be either normalized,
0016 //      unnormalized, or denormalized.
0017 //
0018 //  Output: result in the FP_SCR1 space on the stack.
0019 //
0020 //  Saves and Modifies: D2-D7,A2,FP2
0021 //
0022 //  Algorithm:
0023 //
0024 //  A1. Set RM and size ext;  Set SIGMA = sign of input.
0025 //      The k-factor is saved for use in d7. Clear the
0026 //      BINDEC_FLG for separating normalized/denormalized
0027 //      input.  If input is unnormalized or denormalized,
0028 //      normalize it.
0029 //
0030 //  A2. Set X = abs(input).
0031 //
0032 //  A3. Compute ILOG.
0033 //      ILOG is the log base 10 of the input value.  It is
0034 //      approximated by adding e + 0.f when the original
0035 //      value is viewed as 2^^e * 1.f in extended precision.
0036 //      This value is stored in d6.
0037 //
0038 //  A4. Clr INEX bit.
0039 //      The operation in A3 above may have set INEX2.
0040 //
0041 //  A5. Set ICTR = 0;
0042 //      ICTR is a flag used in A13.  It must be set before the
0043 //      loop entry A6.
0044 //
0045 //  A6. Calculate LEN.
0046 //      LEN is the number of digits to be displayed.  The
0047 //      k-factor can dictate either the total number of digits,
0048 //      if it is a positive number, or the number of digits
0049 //      after the decimal point which are to be included as
0050 //      significant.  See the 68882 manual for examples.
0051 //      If LEN is computed to be greater than 17, set OPERR in
0052 //      USER_FPSR.  LEN is stored in d4.
0053 //
0054 //  A7. Calculate SCALE.
0055 //      SCALE is equal to 10^ISCALE, where ISCALE is the number
0056 //      of decimal places needed to insure LEN integer digits
0057 //      in the output before conversion to bcd. LAMBDA is the
0058 //      sign of ISCALE, used in A9. Fp1 contains
0059 //      10^^(abs(ISCALE)) using a rounding mode which is a
0060 //      function of the original rounding mode and the signs
0061 //      of ISCALE and X.  A table is given in the code.
0062 //
0063 //  A8. Clr INEX; Force RZ.
0064 //      The operation in A3 above may have set INEX2.
0065 //      RZ mode is forced for the scaling operation to insure
0066 //      only one rounding error.  The grs bits are collected in
0067 //      the INEX flag for use in A10.
0068 //
0069 //  A9. Scale X -> Y.
0070 //      The mantissa is scaled to the desired number of
0071 //      significant digits.  The excess digits are collected
0072 //      in INEX2.
0073 //
0074 //  A10.    Or in INEX.
0075 //      If INEX is set, round error occurred.  This is
0076 //      compensated for by 'or-ing' in the INEX2 flag to
0077 //      the lsb of Y.
0078 //
0079 //  A11.    Restore original FPCR; set size ext.
0080 //      Perform FINT operation in the user's rounding mode.
0081 //      Keep the size to extended.
0082 //
0083 //  A12.    Calculate YINT = FINT(Y) according to user's rounding
0084 //      mode.  The FPSP routine sintd0 is used.  The output
0085 //      is in fp0.
0086 //
0087 //  A13.    Check for LEN digits.
0088 //      If the int operation results in more than LEN digits,
0089 //      or less than LEN -1 digits, adjust ILOG and repeat from
0090 //      A6.  This test occurs only on the first pass.  If the
0091 //      result is exactly 10^LEN, decrement ILOG and divide
0092 //      the mantissa by 10.
0093 //
0094 //  A14.    Convert the mantissa to bcd.
0095 //      The binstr routine is used to convert the LEN digit
0096 //      mantissa to bcd in memory.  The input to binstr is
0097 //      to be a fraction; i.e. (mantissa)/10^LEN and adjusted
0098 //      such that the decimal point is to the left of bit 63.
0099 //      The bcd digits are stored in the correct position in
0100 //      the final string area in memory.
0101 //
0102 //  A15.    Convert the exponent to bcd.
0103 //      As in A14 above, the exp is converted to bcd and the
0104 //      digits are stored in the final string.
0105 //      Test the length of the final exponent string.  If the
0106 //      length is 4, set operr.
0107 //
0108 //  A16.    Write sign bits to final string.
0109 //
0110 //  Implementation Notes:
0111 //
0112 //  The registers are used as follows:
0113 //
0114 //      d0: scratch; LEN input to binstr
0115 //      d1: scratch
0116 //      d2: upper 32-bits of mantissa for binstr
0117 //      d3: scratch;lower 32-bits of mantissa for binstr
0118 //      d4: LEN
0119 //              d5: LAMBDA/ICTR
0120 //      d6: ILOG
0121 //      d7: k-factor
0122 //      a0: ptr for original operand/final result
0123 //      a1: scratch pointer
0124 //      a2: pointer to FP_X; abs(original value) in ext
0125 //      fp0: scratch
0126 //      fp1: scratch
0127 //      fp2: scratch
0128 //      F_SCR1:
0129 //      F_SCR2:
0130 //      L_SCR1:
0131 //      L_SCR2:
0132 
0133 //      Copyright (C) Motorola, Inc. 1990
0134 //          All Rights Reserved
0135 //
0136 //  THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
0137 //  The copyright notice above does not evidence any
0138 //  actual or intended publication of such source code.
0139 
0140 //BINDEC    idnt    2,1 | Motorola 040 Floating Point Software Package
0141 
0142 #include "fpsp.defs"
0143 
0144     |section    8
0145 
0146 // Constants in extended precision
0147 LOG2:   .long   0x3FFD0000,0x9A209A84,0xFBCFF798,0x00000000
0148 LOG2UP1:    .long   0x3FFD0000,0x9A209A84,0xFBCFF799,0x00000000
0149 
0150 // Constants in single precision
0151 FONE:   .long   0x3F800000,0x00000000,0x00000000,0x00000000
0152 FTWO:   .long   0x40000000,0x00000000,0x00000000,0x00000000
0153 FTEN:   .long   0x41200000,0x00000000,0x00000000,0x00000000
0154 F4933:  .long   0x459A2800,0x00000000,0x00000000,0x00000000
0155 
0156 RBDTBL:     .byte   0,0,0,0
0157     .byte   3,3,2,2
0158     .byte   3,2,2,3
0159     .byte   2,3,3,2
0160 
0161     |xref   binstr
0162     |xref   sintdo
0163     |xref   ptenrn,ptenrm,ptenrp
0164 
0165     .global bindec
0166     .global sc_mul
0167 bindec:
0168     moveml  %d2-%d7/%a2,-(%a7)
0169     fmovemx %fp0-%fp2,-(%a7)
0170 
0171 // A1. Set RM and size ext. Set SIGMA = sign input;
0172 //     The k-factor is saved for use in d7.  Clear BINDEC_FLG for
0173 //     separating  normalized/denormalized input.  If the input
0174 //     is a denormalized number, set the BINDEC_FLG memory word
0175 //     to signal denorm.  If the input is unnormalized, normalize
0176 //     the input and test for denormalized result.
0177 //
0178     fmovel  #rm_mode,%FPCR  //set RM and ext
0179     movel   (%a0),L_SCR2(%a6)   //save exponent for sign check
0180     movel   %d0,%d7     //move k-factor to d7
0181     clrb    BINDEC_FLG(%a6) //clr norm/denorm flag
0182     movew   STAG(%a6),%d0   //get stag
0183     andiw   #0xe000,%d0 //isolate stag bits
0184     beq A2_str      //if zero, input is norm
0185 //
0186 // Normalize the denorm
0187 //
0188 un_de_norm:
0189     movew   (%a0),%d0
0190     andiw   #0x7fff,%d0 //strip sign of normalized exp
0191     movel   4(%a0),%d1
0192     movel   8(%a0),%d2
0193 norm_loop:
0194     subw    #1,%d0
0195     lsll    #1,%d2
0196     roxll   #1,%d1
0197     tstl    %d1
0198     bges    norm_loop
0199 //
0200 // Test if the normalized input is denormalized
0201 //
0202     tstw    %d0
0203     bgts    pos_exp     //if greater than zero, it is a norm
0204     st  BINDEC_FLG(%a6) //set flag for denorm
0205 pos_exp:
0206     andiw   #0x7fff,%d0 //strip sign of normalized exp
0207     movew   %d0,(%a0)
0208     movel   %d1,4(%a0)
0209     movel   %d2,8(%a0)
0210 
0211 // A2. Set X = abs(input).
0212 //
0213 A2_str:
0214     movel   (%a0),FP_SCR2(%a6) // move input to work space
0215     movel   4(%a0),FP_SCR2+4(%a6) // move input to work space
0216     movel   8(%a0),FP_SCR2+8(%a6) // move input to work space
0217     andil   #0x7fffffff,FP_SCR2(%a6) //create abs(X)
0218 
0219 // A3. Compute ILOG.
0220 //     ILOG is the log base 10 of the input value.  It is approx-
0221 //     imated by adding e + 0.f when the original value is viewed
0222 //     as 2^^e * 1.f in extended precision.  This value is stored
0223 //     in d6.
0224 //
0225 // Register usage:
0226 //  Input/Output
0227 //  d0: k-factor/exponent
0228 //  d2: x/x
0229 //  d3: x/x
0230 //  d4: x/x
0231 //  d5: x/x
0232 //  d6: x/ILOG
0233 //  d7: k-factor/Unchanged
0234 //  a0: ptr for original operand/final result
0235 //  a1: x/x
0236 //  a2: x/x
0237 //  fp0: x/float(ILOG)
0238 //  fp1: x/x
0239 //  fp2: x/x
0240 //  F_SCR1:x/x
0241 //  F_SCR2:Abs(X)/Abs(X) with $3fff exponent
0242 //  L_SCR1:x/x
0243 //  L_SCR2:first word of X packed/Unchanged
0244 
0245     tstb    BINDEC_FLG(%a6) //check for denorm
0246     beqs    A3_cont     //if clr, continue with norm
0247     movel   #-4933,%d6  //force ILOG = -4933
0248     bras    A4_str
0249 A3_cont:
0250     movew   FP_SCR2(%a6),%d0    //move exp to d0
0251     movew   #0x3fff,FP_SCR2(%a6) //replace exponent with 0x3fff
0252     fmovex  FP_SCR2(%a6),%fp0   //now fp0 has 1.f
0253     subw    #0x3fff,%d0 //strip off bias
0254     faddw   %d0,%fp0        //add in exp
0255     fsubs   FONE,%fp0   //subtract off 1.0
0256     fbge    pos_res     //if pos, branch
0257     fmulx   LOG2UP1,%fp0    //if neg, mul by LOG2UP1
0258     fmovel  %fp0,%d6        //put ILOG in d6 as a lword
0259     bras    A4_str      //go move out ILOG
0260 pos_res:
0261     fmulx   LOG2,%fp0   //if pos, mul by LOG2
0262     fmovel  %fp0,%d6        //put ILOG in d6 as a lword
0263 
0264 
0265 // A4. Clr INEX bit.
0266 //     The operation in A3 above may have set INEX2.
0267 
0268 A4_str:
0269     fmovel  #0,%FPSR        //zero all of fpsr - nothing needed
0270 
0271 
0272 // A5. Set ICTR = 0;
0273 //     ICTR is a flag used in A13.  It must be set before the
0274 //     loop entry A6. The lower word of d5 is used for ICTR.
0275 
0276     clrw    %d5     //clear ICTR
0277 
0278 
0279 // A6. Calculate LEN.
0280 //     LEN is the number of digits to be displayed.  The k-factor
0281 //     can dictate either the total number of digits, if it is
0282 //     a positive number, or the number of digits after the
0283 //     original decimal point which are to be included as
0284 //     significant.  See the 68882 manual for examples.
0285 //     If LEN is computed to be greater than 17, set OPERR in
0286 //     USER_FPSR.  LEN is stored in d4.
0287 //
0288 // Register usage:
0289 //  Input/Output
0290 //  d0: exponent/Unchanged
0291 //  d2: x/x/scratch
0292 //  d3: x/x
0293 //  d4: exc picture/LEN
0294 //  d5: ICTR/Unchanged
0295 //  d6: ILOG/Unchanged
0296 //  d7: k-factor/Unchanged
0297 //  a0: ptr for original operand/final result
0298 //  a1: x/x
0299 //  a2: x/x
0300 //  fp0: float(ILOG)/Unchanged
0301 //  fp1: x/x
0302 //  fp2: x/x
0303 //  F_SCR1:x/x
0304 //  F_SCR2:Abs(X) with $3fff exponent/Unchanged
0305 //  L_SCR1:x/x
0306 //  L_SCR2:first word of X packed/Unchanged
0307 
0308 A6_str:
0309     tstl    %d7     //branch on sign of k
0310     bles    k_neg       //if k <= 0, LEN = ILOG + 1 - k
0311     movel   %d7,%d4     //if k > 0, LEN = k
0312     bras    len_ck      //skip to LEN check
0313 k_neg:
0314     movel   %d6,%d4     //first load ILOG to d4
0315     subl    %d7,%d4     //subtract off k
0316     addql   #1,%d4      //add in the 1
0317 len_ck:
0318     tstl    %d4     //LEN check: branch on sign of LEN
0319     bles    LEN_ng      //if neg, set LEN = 1
0320     cmpl    #17,%d4     //test if LEN > 17
0321     bles    A7_str      //if not, forget it
0322     movel   #17,%d4     //set max LEN = 17
0323     tstl    %d7     //if negative, never set OPERR
0324     bles    A7_str      //if positive, continue
0325     orl #opaop_mask,USER_FPSR(%a6) //set OPERR & AIOP in USER_FPSR
0326     bras    A7_str      //finished here
0327 LEN_ng:
0328     moveql  #1,%d4      //min LEN is 1
0329 
0330 
0331 // A7. Calculate SCALE.
0332 //     SCALE is equal to 10^ISCALE, where ISCALE is the number
0333 //     of decimal places needed to insure LEN integer digits
0334 //     in the output before conversion to bcd. LAMBDA is the sign
0335 //     of ISCALE, used in A9.  Fp1 contains 10^^(abs(ISCALE)) using
0336 //     the rounding mode as given in the following table (see
0337 //     Coonen, p. 7.23 as ref.; however, the SCALE variable is
0338 //     of opposite sign in bindec.sa from Coonen).
0339 //
0340 //  Initial                 USE
0341 //  FPCR[6:5]   LAMBDA  SIGN(X)     FPCR[6:5]
0342 //  ----------------------------------------------
0343 //   RN 00     0       0        00/0    RN
0344 //   RN 00     0       1        00/0    RN
0345 //   RN 00     1       0        00/0    RN
0346 //   RN 00     1       1        00/0    RN
0347 //   RZ 01     0       0        11/3    RP
0348 //   RZ 01     0       1        11/3    RP
0349 //   RZ 01     1       0        10/2    RM
0350 //   RZ 01     1       1        10/2    RM
0351 //   RM 10     0       0        11/3    RP
0352 //   RM 10     0       1        10/2    RM
0353 //   RM 10     1       0        10/2    RM
0354 //   RM 10     1       1        11/3    RP
0355 //   RP 11     0       0        10/2    RM
0356 //   RP 11     0       1        11/3    RP
0357 //   RP 11     1       0        11/3    RP
0358 //   RP 11     1       1        10/2    RM
0359 //
0360 // Register usage:
0361 //  Input/Output
0362 //  d0: exponent/scratch - final is 0
0363 //  d2: x/0 or 24 for A9
0364 //  d3: x/scratch - offset ptr into PTENRM array
0365 //  d4: LEN/Unchanged
0366 //  d5: 0/ICTR:LAMBDA
0367 //  d6: ILOG/ILOG or k if ((k<=0)&(ILOG<k))
0368 //  d7: k-factor/Unchanged
0369 //  a0: ptr for original operand/final result
0370 //  a1: x/ptr to PTENRM array
0371 //  a2: x/x
0372 //  fp0: float(ILOG)/Unchanged
0373 //  fp1: x/10^ISCALE
0374 //  fp2: x/x
0375 //  F_SCR1:x/x
0376 //  F_SCR2:Abs(X) with $3fff exponent/Unchanged
0377 //  L_SCR1:x/x
0378 //  L_SCR2:first word of X packed/Unchanged
0379 
0380 A7_str:
0381     tstl    %d7     //test sign of k
0382     bgts    k_pos       //if pos and > 0, skip this
0383     cmpl    %d6,%d7     //test k - ILOG
0384     blts    k_pos       //if ILOG >= k, skip this
0385     movel   %d7,%d6     //if ((k<0) & (ILOG < k)) ILOG = k
0386 k_pos:
0387     movel   %d6,%d0     //calc ILOG + 1 - LEN in d0
0388     addql   #1,%d0      //add the 1
0389     subl    %d4,%d0     //sub off LEN
0390     swap    %d5     //use upper word of d5 for LAMBDA
0391     clrw    %d5     //set it zero initially
0392     clrw    %d2     //set up d2 for very small case
0393     tstl    %d0     //test sign of ISCALE
0394     bges    iscale      //if pos, skip next inst
0395     addqw   #1,%d5      //if neg, set LAMBDA true
0396     cmpl    #0xffffecd4,%d0 //test iscale <= -4908
0397     bgts    no_inf      //if false, skip rest
0398     addil   #24,%d0     //add in 24 to iscale
0399     movel   #24,%d2     //put 24 in d2 for A9
0400 no_inf:
0401     negl    %d0     //and take abs of ISCALE
0402 iscale:
0403     fmoves  FONE,%fp1   //init fp1 to 1
0404     bfextu  USER_FPCR(%a6){#26:#2},%d1 //get initial rmode bits
0405     lslw    #1,%d1      //put them in bits 2:1
0406     addw    %d5,%d1     //add in LAMBDA
0407     lslw    #1,%d1      //put them in bits 3:1
0408     tstl    L_SCR2(%a6) //test sign of original x
0409     bges    x_pos       //if pos, don't set bit 0
0410     addql   #1,%d1      //if neg, set bit 0
0411 x_pos:
0412     leal    RBDTBL,%a2  //load rbdtbl base
0413     moveb   (%a2,%d1),%d3   //load d3 with new rmode
0414     lsll    #4,%d3      //put bits in proper position
0415     fmovel  %d3,%fpcr       //load bits into fpu
0416     lsrl    #4,%d3      //put bits in proper position
0417     tstb    %d3     //decode new rmode for pten table
0418     bnes    not_rn      //if zero, it is RN
0419     leal    PTENRN,%a1  //load a1 with RN table base
0420     bras    rmode       //exit decode
0421 not_rn:
0422     lsrb    #1,%d3      //get lsb in carry
0423     bccs    not_rp      //if carry clear, it is RM
0424     leal    PTENRP,%a1  //load a1 with RP table base
0425     bras    rmode       //exit decode
0426 not_rp:
0427     leal    PTENRM,%a1  //load a1 with RM table base
0428 rmode:
0429     clrl    %d3     //clr table index
0430 e_loop:
0431     lsrl    #1,%d0      //shift next bit into carry
0432     bccs    e_next      //if zero, skip the mul
0433     fmulx   (%a1,%d3),%fp1  //mul by 10**(d3_bit_no)
0434 e_next:
0435     addl    #12,%d3     //inc d3 to next pwrten table entry
0436     tstl    %d0     //test if ISCALE is zero
0437     bnes    e_loop      //if not, loop
0438 
0439 
0440 // A8. Clr INEX; Force RZ.
0441 //     The operation in A3 above may have set INEX2.
0442 //     RZ mode is forced for the scaling operation to insure
0443 //     only one rounding error.  The grs bits are collected in
0444 //     the INEX flag for use in A10.
0445 //
0446 // Register usage:
0447 //  Input/Output
0448 
0449     fmovel  #0,%FPSR        //clr INEX
0450     fmovel  #rz_mode,%FPCR  //set RZ rounding mode
0451 
0452 
0453 // A9. Scale X -> Y.
0454 //     The mantissa is scaled to the desired number of significant
0455 //     digits.  The excess digits are collected in INEX2. If mul,
0456 //     Check d2 for excess 10 exponential value.  If not zero,
0457 //     the iscale value would have caused the pwrten calculation
0458 //     to overflow.  Only a negative iscale can cause this, so
0459 //     multiply by 10^(d2), which is now only allowed to be 24,
0460 //     with a multiply by 10^8 and 10^16, which is exact since
0461 //     10^24 is exact.  If the input was denormalized, we must
0462 //     create a busy stack frame with the mul command and the
0463 //     two operands, and allow the fpu to complete the multiply.
0464 //
0465 // Register usage:
0466 //  Input/Output
0467 //  d0: FPCR with RZ mode/Unchanged
0468 //  d2: 0 or 24/unchanged
0469 //  d3: x/x
0470 //  d4: LEN/Unchanged
0471 //  d5: ICTR:LAMBDA
0472 //  d6: ILOG/Unchanged
0473 //  d7: k-factor/Unchanged
0474 //  a0: ptr for original operand/final result
0475 //  a1: ptr to PTENRM array/Unchanged
0476 //  a2: x/x
0477 //  fp0: float(ILOG)/X adjusted for SCALE (Y)
0478 //  fp1: 10^ISCALE/Unchanged
0479 //  fp2: x/x
0480 //  F_SCR1:x/x
0481 //  F_SCR2:Abs(X) with $3fff exponent/Unchanged
0482 //  L_SCR1:x/x
0483 //  L_SCR2:first word of X packed/Unchanged
0484 
0485 A9_str:
0486     fmovex  (%a0),%fp0  //load X from memory
0487     fabsx   %fp0        //use abs(X)
0488     tstw    %d5     //LAMBDA is in lower word of d5
0489     bne     sc_mul      //if neg (LAMBDA = 1), scale by mul
0490     fdivx   %fp1,%fp0       //calculate X / SCALE -> Y to fp0
0491     bras    A10_st      //branch to A10
0492 
0493 sc_mul:
0494     tstb    BINDEC_FLG(%a6) //check for denorm
0495     beqs    A9_norm     //if norm, continue with mul
0496     fmovemx %fp1-%fp1,-(%a7)    //load ETEMP with 10^ISCALE
0497     movel   8(%a0),-(%a7)   //load FPTEMP with input arg
0498     movel   4(%a0),-(%a7)
0499     movel   (%a0),-(%a7)
0500     movel   #18,%d3     //load count for busy stack
0501 A9_loop:
0502     clrl    -(%a7)      //clear lword on stack
0503     dbf %d3,A9_loop
0504     moveb   VER_TMP(%a6),(%a7) //write current version number
0505     moveb   #BUSY_SIZE-4,1(%a7) //write current busy size
0506     moveb   #0x10,0x44(%a7) //set fcefpte[15] bit
0507     movew   #0x0023,0x40(%a7)   //load cmdreg1b with mul command
0508     moveb   #0xfe,0x8(%a7)  //load all 1s to cu savepc
0509     frestore (%a7)+     //restore frame to fpu for completion
0510     fmulx   36(%a1),%fp0    //multiply fp0 by 10^8
0511     fmulx   48(%a1),%fp0    //multiply fp0 by 10^16
0512     bras    A10_st
0513 A9_norm:
0514     tstw    %d2     //test for small exp case
0515     beqs    A9_con      //if zero, continue as normal
0516     fmulx   36(%a1),%fp0    //multiply fp0 by 10^8
0517     fmulx   48(%a1),%fp0    //multiply fp0 by 10^16
0518 A9_con:
0519     fmulx   %fp1,%fp0       //calculate X * SCALE -> Y to fp0
0520 
0521 
0522 // A10. Or in INEX.
0523 //      If INEX is set, round error occurred.  This is compensated
0524 //      for by 'or-ing' in the INEX2 flag to the lsb of Y.
0525 //
0526 // Register usage:
0527 //  Input/Output
0528 //  d0: FPCR with RZ mode/FPSR with INEX2 isolated
0529 //  d2: x/x
0530 //  d3: x/x
0531 //  d4: LEN/Unchanged
0532 //  d5: ICTR:LAMBDA
0533 //  d6: ILOG/Unchanged
0534 //  d7: k-factor/Unchanged
0535 //  a0: ptr for original operand/final result
0536 //  a1: ptr to PTENxx array/Unchanged
0537 //  a2: x/ptr to FP_SCR2(a6)
0538 //  fp0: Y/Y with lsb adjusted
0539 //  fp1: 10^ISCALE/Unchanged
0540 //  fp2: x/x
0541 
0542 A10_st:
0543     fmovel  %FPSR,%d0       //get FPSR
0544     fmovex  %fp0,FP_SCR2(%a6)   //move Y to memory
0545     leal    FP_SCR2(%a6),%a2    //load a2 with ptr to FP_SCR2
0546     btstl   #9,%d0      //check if INEX2 set
0547     beqs    A11_st      //if clear, skip rest
0548     oril    #1,8(%a2)   //or in 1 to lsb of mantissa
0549     fmovex  FP_SCR2(%a6),%fp0   //write adjusted Y back to fpu
0550 
0551 
0552 // A11. Restore original FPCR; set size ext.
0553 //      Perform FINT operation in the user's rounding mode.  Keep
0554 //      the size to extended.  The sintdo entry point in the sint
0555 //      routine expects the FPCR value to be in USER_FPCR for
0556 //      mode and precision.  The original FPCR is saved in L_SCR1.
0557 
0558 A11_st:
0559     movel   USER_FPCR(%a6),L_SCR1(%a6) //save it for later
0560     andil   #0x00000030,USER_FPCR(%a6) //set size to ext,
0561 //                  ;block exceptions
0562 
0563 
0564 // A12. Calculate YINT = FINT(Y) according to user's rounding mode.
0565 //      The FPSP routine sintd0 is used.  The output is in fp0.
0566 //
0567 // Register usage:
0568 //  Input/Output
0569 //  d0: FPSR with AINEX cleared/FPCR with size set to ext
0570 //  d2: x/x/scratch
0571 //  d3: x/x
0572 //  d4: LEN/Unchanged
0573 //  d5: ICTR:LAMBDA/Unchanged
0574 //  d6: ILOG/Unchanged
0575 //  d7: k-factor/Unchanged
0576 //  a0: ptr for original operand/src ptr for sintdo
0577 //  a1: ptr to PTENxx array/Unchanged
0578 //  a2: ptr to FP_SCR2(a6)/Unchanged
0579 //  a6: temp pointer to FP_SCR2(a6) - orig value saved and restored
0580 //  fp0: Y/YINT
0581 //  fp1: 10^ISCALE/Unchanged
0582 //  fp2: x/x
0583 //  F_SCR1:x/x
0584 //  F_SCR2:Y adjusted for inex/Y with original exponent
0585 //  L_SCR1:x/original USER_FPCR
0586 //  L_SCR2:first word of X packed/Unchanged
0587 
0588 A12_st:
0589     moveml  %d0-%d1/%a0-%a1,-(%a7)  //save regs used by sintd0
0590     movel   L_SCR1(%a6),-(%a7)
0591     movel   L_SCR2(%a6),-(%a7)
0592     leal    FP_SCR2(%a6),%a0        //a0 is ptr to F_SCR2(a6)
0593     fmovex  %fp0,(%a0)      //move Y to memory at FP_SCR2(a6)
0594     tstl    L_SCR2(%a6)     //test sign of original operand
0595     bges    do_fint         //if pos, use Y
0596     orl #0x80000000,(%a0)       //if neg, use -Y
0597 do_fint:
0598     movel   USER_FPSR(%a6),-(%a7)
0599     bsr sintdo          //sint routine returns int in fp0
0600     moveb   (%a7),USER_FPSR(%a6)
0601     addl    #4,%a7
0602     movel   (%a7)+,L_SCR2(%a6)
0603     movel   (%a7)+,L_SCR1(%a6)
0604     moveml  (%a7)+,%d0-%d1/%a0-%a1  //restore regs used by sint
0605     movel   L_SCR2(%a6),FP_SCR2(%a6)    //restore original exponent
0606     movel   L_SCR1(%a6),USER_FPCR(%a6) //restore user's FPCR
0607 
0608 
0609 // A13. Check for LEN digits.
0610 //      If the int operation results in more than LEN digits,
0611 //      or less than LEN -1 digits, adjust ILOG and repeat from
0612 //      A6.  This test occurs only on the first pass.  If the
0613 //      result is exactly 10^LEN, decrement ILOG and divide
0614 //      the mantissa by 10.  The calculation of 10^LEN cannot
0615 //      be inexact, since all powers of ten upto 10^27 are exact
0616 //      in extended precision, so the use of a previous power-of-ten
0617 //      table will introduce no error.
0618 //
0619 //
0620 // Register usage:
0621 //  Input/Output
0622 //  d0: FPCR with size set to ext/scratch final = 0
0623 //  d2: x/x
0624 //  d3: x/scratch final = x
0625 //  d4: LEN/LEN adjusted
0626 //  d5: ICTR:LAMBDA/LAMBDA:ICTR
0627 //  d6: ILOG/ILOG adjusted
0628 //  d7: k-factor/Unchanged
0629 //  a0: pointer into memory for packed bcd string formation
0630 //  a1: ptr to PTENxx array/Unchanged
0631 //  a2: ptr to FP_SCR2(a6)/Unchanged
0632 //  fp0: int portion of Y/abs(YINT) adjusted
0633 //  fp1: 10^ISCALE/Unchanged
0634 //  fp2: x/10^LEN
0635 //  F_SCR1:x/x
0636 //  F_SCR2:Y with original exponent/Unchanged
0637 //  L_SCR1:original USER_FPCR/Unchanged
0638 //  L_SCR2:first word of X packed/Unchanged
0639 
0640 A13_st:
0641     swap    %d5     //put ICTR in lower word of d5
0642     tstw    %d5     //check if ICTR = 0
0643     bne not_zr      //if non-zero, go to second test
0644 //
0645 // Compute 10^(LEN-1)
0646 //
0647     fmoves  FONE,%fp2   //init fp2 to 1.0
0648     movel   %d4,%d0     //put LEN in d0
0649     subql   #1,%d0      //d0 = LEN -1
0650     clrl    %d3     //clr table index
0651 l_loop:
0652     lsrl    #1,%d0      //shift next bit into carry
0653     bccs    l_next      //if zero, skip the mul
0654     fmulx   (%a1,%d3),%fp2  //mul by 10**(d3_bit_no)
0655 l_next:
0656     addl    #12,%d3     //inc d3 to next pwrten table entry
0657     tstl    %d0     //test if LEN is zero
0658     bnes    l_loop      //if not, loop
0659 //
0660 // 10^LEN-1 is computed for this test and A14.  If the input was
0661 // denormalized, check only the case in which YINT > 10^LEN.
0662 //
0663     tstb    BINDEC_FLG(%a6) //check if input was norm
0664     beqs    A13_con     //if norm, continue with checking
0665     fabsx   %fp0        //take abs of YINT
0666     bra test_2
0667 //
0668 // Compare abs(YINT) to 10^(LEN-1) and 10^LEN
0669 //
0670 A13_con:
0671     fabsx   %fp0        //take abs of YINT
0672     fcmpx   %fp2,%fp0       //compare abs(YINT) with 10^(LEN-1)
0673     fbge    test_2      //if greater, do next test
0674     subql   #1,%d6      //subtract 1 from ILOG
0675     movew   #1,%d5      //set ICTR
0676     fmovel  #rm_mode,%FPCR  //set rmode to RM
0677     fmuls   FTEN,%fp2   //compute 10^LEN
0678     bra A6_str      //return to A6 and recompute YINT
0679 test_2:
0680     fmuls   FTEN,%fp2   //compute 10^LEN
0681     fcmpx   %fp2,%fp0       //compare abs(YINT) with 10^LEN
0682     fblt    A14_st      //if less, all is ok, go to A14
0683     fbgt    fix_ex      //if greater, fix and redo
0684     fdivs   FTEN,%fp0   //if equal, divide by 10
0685     addql   #1,%d6      // and inc ILOG
0686     bras    A14_st      // and continue elsewhere
0687 fix_ex:
0688     addql   #1,%d6      //increment ILOG by 1
0689     movew   #1,%d5      //set ICTR
0690     fmovel  #rm_mode,%FPCR  //set rmode to RM
0691     bra A6_str      //return to A6 and recompute YINT
0692 //
0693 // Since ICTR <> 0, we have already been through one adjustment,
0694 // and shouldn't have another; this is to check if abs(YINT) = 10^LEN
0695 // 10^LEN is again computed using whatever table is in a1 since the
0696 // value calculated cannot be inexact.
0697 //
0698 not_zr:
0699     fmoves  FONE,%fp2   //init fp2 to 1.0
0700     movel   %d4,%d0     //put LEN in d0
0701     clrl    %d3     //clr table index
0702 z_loop:
0703     lsrl    #1,%d0      //shift next bit into carry
0704     bccs    z_next      //if zero, skip the mul
0705     fmulx   (%a1,%d3),%fp2  //mul by 10**(d3_bit_no)
0706 z_next:
0707     addl    #12,%d3     //inc d3 to next pwrten table entry
0708     tstl    %d0     //test if LEN is zero
0709     bnes    z_loop      //if not, loop
0710     fabsx   %fp0        //get abs(YINT)
0711     fcmpx   %fp2,%fp0       //check if abs(YINT) = 10^LEN
0712     fbne    A14_st      //if not, skip this
0713     fdivs   FTEN,%fp0   //divide abs(YINT) by 10
0714     addql   #1,%d6      //and inc ILOG by 1
0715     addql   #1,%d4      // and inc LEN
0716     fmuls   FTEN,%fp2   // if LEN++, the get 10^^LEN
0717 
0718 
0719 // A14. Convert the mantissa to bcd.
0720 //      The binstr routine is used to convert the LEN digit
0721 //      mantissa to bcd in memory.  The input to binstr is
0722 //      to be a fraction; i.e. (mantissa)/10^LEN and adjusted
0723 //      such that the decimal point is to the left of bit 63.
0724 //      The bcd digits are stored in the correct position in
0725 //      the final string area in memory.
0726 //
0727 //
0728 // Register usage:
0729 //  Input/Output
0730 //  d0: x/LEN call to binstr - final is 0
0731 //  d1: x/0
0732 //  d2: x/ms 32-bits of mant of abs(YINT)
0733 //  d3: x/ls 32-bits of mant of abs(YINT)
0734 //  d4: LEN/Unchanged
0735 //  d5: ICTR:LAMBDA/LAMBDA:ICTR
0736 //  d6: ILOG
0737 //  d7: k-factor/Unchanged
0738 //  a0: pointer into memory for packed bcd string formation
0739 //      /ptr to first mantissa byte in result string
0740 //  a1: ptr to PTENxx array/Unchanged
0741 //  a2: ptr to FP_SCR2(a6)/Unchanged
0742 //  fp0: int portion of Y/abs(YINT) adjusted
0743 //  fp1: 10^ISCALE/Unchanged
0744 //  fp2: 10^LEN/Unchanged
0745 //  F_SCR1:x/Work area for final result
0746 //  F_SCR2:Y with original exponent/Unchanged
0747 //  L_SCR1:original USER_FPCR/Unchanged
0748 //  L_SCR2:first word of X packed/Unchanged
0749 
0750 A14_st:
0751     fmovel  #rz_mode,%FPCR  //force rz for conversion
0752     fdivx   %fp2,%fp0       //divide abs(YINT) by 10^LEN
0753     leal    FP_SCR1(%a6),%a0
0754     fmovex  %fp0,(%a0)  //move abs(YINT)/10^LEN to memory
0755     movel   4(%a0),%d2  //move 2nd word of FP_RES to d2
0756     movel   8(%a0),%d3  //move 3rd word of FP_RES to d3
0757     clrl    4(%a0)      //zero word 2 of FP_RES
0758     clrl    8(%a0)      //zero word 3 of FP_RES
0759     movel   (%a0),%d0       //move exponent to d0
0760     swap    %d0     //put exponent in lower word
0761     beqs    no_sft      //if zero, don't shift
0762     subil   #0x3ffd,%d0 //sub bias less 2 to make fract
0763     tstl    %d0     //check if > 1
0764     bgts    no_sft      //if so, don't shift
0765     negl    %d0     //make exp positive
0766 m_loop:
0767     lsrl    #1,%d2      //shift d2:d3 right, add 0s
0768     roxrl   #1,%d3      //the number of places
0769     dbf %d0,m_loop  //given in d0
0770 no_sft:
0771     tstl    %d2     //check for mantissa of zero
0772     bnes    no_zr       //if not, go on
0773     tstl    %d3     //continue zero check
0774     beqs    zer_m       //if zero, go directly to binstr
0775 no_zr:
0776     clrl    %d1     //put zero in d1 for addx
0777     addil   #0x00000080,%d3 //inc at bit 7
0778     addxl   %d1,%d2     //continue inc
0779     andil   #0xffffff80,%d3 //strip off lsb not used by 882
0780 zer_m:
0781     movel   %d4,%d0     //put LEN in d0 for binstr call
0782     addql   #3,%a0      //a0 points to M16 byte in result
0783     bsr binstr      //call binstr to convert mant
0784 
0785 
0786 // A15. Convert the exponent to bcd.
0787 //      As in A14 above, the exp is converted to bcd and the
0788 //      digits are stored in the final string.
0789 //
0790 //      Digits are stored in L_SCR1(a6) on return from BINDEC as:
0791 //
0792 //       32               16 15                0
0793 //  -----------------------------------------
0794 //      |  0 | e3 | e2 | e1 | e4 |  X |  X |  X |
0795 //  -----------------------------------------
0796 //
0797 // And are moved into their proper places in FP_SCR1.  If digit e4
0798 // is non-zero, OPERR is signaled.  In all cases, all 4 digits are
0799 // written as specified in the 881/882 manual for packed decimal.
0800 //
0801 // Register usage:
0802 //  Input/Output
0803 //  d0: x/LEN call to binstr - final is 0
0804 //  d1: x/scratch (0);shift count for final exponent packing
0805 //  d2: x/ms 32-bits of exp fraction/scratch
0806 //  d3: x/ls 32-bits of exp fraction
0807 //  d4: LEN/Unchanged
0808 //  d5: ICTR:LAMBDA/LAMBDA:ICTR
0809 //  d6: ILOG
0810 //  d7: k-factor/Unchanged
0811 //  a0: ptr to result string/ptr to L_SCR1(a6)
0812 //  a1: ptr to PTENxx array/Unchanged
0813 //  a2: ptr to FP_SCR2(a6)/Unchanged
0814 //  fp0: abs(YINT) adjusted/float(ILOG)
0815 //  fp1: 10^ISCALE/Unchanged
0816 //  fp2: 10^LEN/Unchanged
0817 //  F_SCR1:Work area for final result/BCD result
0818 //  F_SCR2:Y with original exponent/ILOG/10^4
0819 //  L_SCR1:original USER_FPCR/Exponent digits on return from binstr
0820 //  L_SCR2:first word of X packed/Unchanged
0821 
0822 A15_st:
0823     tstb    BINDEC_FLG(%a6) //check for denorm
0824     beqs    not_denorm
0825     ftstx   %fp0        //test for zero
0826     fbeq    den_zero    //if zero, use k-factor or 4933
0827     fmovel  %d6,%fp0        //float ILOG
0828     fabsx   %fp0        //get abs of ILOG
0829     bras    convrt
0830 den_zero:
0831     tstl    %d7     //check sign of the k-factor
0832     blts    use_ilog    //if negative, use ILOG
0833     fmoves  F4933,%fp0  //force exponent to 4933
0834     bras    convrt      //do it
0835 use_ilog:
0836     fmovel  %d6,%fp0        //float ILOG
0837     fabsx   %fp0        //get abs of ILOG
0838     bras    convrt
0839 not_denorm:
0840     ftstx   %fp0        //test for zero
0841     fbne    not_zero    //if zero, force exponent
0842     fmoves  FONE,%fp0   //force exponent to 1
0843     bras    convrt      //do it
0844 not_zero:
0845     fmovel  %d6,%fp0        //float ILOG
0846     fabsx   %fp0        //get abs of ILOG
0847 convrt:
0848     fdivx   24(%a1),%fp0    //compute ILOG/10^4
0849     fmovex  %fp0,FP_SCR2(%a6)   //store fp0 in memory
0850     movel   4(%a2),%d2  //move word 2 to d2
0851     movel   8(%a2),%d3  //move word 3 to d3
0852     movew   (%a2),%d0       //move exp to d0
0853     beqs    x_loop_fin  //if zero, skip the shift
0854     subiw   #0x3ffd,%d0 //subtract off bias
0855     negw    %d0     //make exp positive
0856 x_loop:
0857     lsrl    #1,%d2      //shift d2:d3 right
0858     roxrl   #1,%d3      //the number of places
0859     dbf %d0,x_loop  //given in d0
0860 x_loop_fin:
0861     clrl    %d1     //put zero in d1 for addx
0862     addil   #0x00000080,%d3 //inc at bit 6
0863     addxl   %d1,%d2     //continue inc
0864     andil   #0xffffff80,%d3 //strip off lsb not used by 882
0865     movel   #4,%d0      //put 4 in d0 for binstr call
0866     leal    L_SCR1(%a6),%a0 //a0 is ptr to L_SCR1 for exp digits
0867     bsr binstr      //call binstr to convert exp
0868     movel   L_SCR1(%a6),%d0 //load L_SCR1 lword to d0
0869     movel   #12,%d1     //use d1 for shift count
0870     lsrl    %d1,%d0     //shift d0 right by 12
0871     bfins   %d0,FP_SCR1(%a6){#4:#12} //put e3:e2:e1 in FP_SCR1
0872     lsrl    %d1,%d0     //shift d0 right by 12
0873     bfins   %d0,FP_SCR1(%a6){#16:#4} //put e4 in FP_SCR1
0874     tstb    %d0     //check if e4 is zero
0875     beqs    A16_st      //if zero, skip rest
0876     orl #opaop_mask,USER_FPSR(%a6) //set OPERR & AIOP in USER_FPSR
0877 
0878 
0879 // A16. Write sign bits to final string.
0880 //     Sigma is bit 31 of initial value; RHO is bit 31 of d6 (ILOG).
0881 //
0882 // Register usage:
0883 //  Input/Output
0884 //  d0: x/scratch - final is x
0885 //  d2: x/x
0886 //  d3: x/x
0887 //  d4: LEN/Unchanged
0888 //  d5: ICTR:LAMBDA/LAMBDA:ICTR
0889 //  d6: ILOG/ILOG adjusted
0890 //  d7: k-factor/Unchanged
0891 //  a0: ptr to L_SCR1(a6)/Unchanged
0892 //  a1: ptr to PTENxx array/Unchanged
0893 //  a2: ptr to FP_SCR2(a6)/Unchanged
0894 //  fp0: float(ILOG)/Unchanged
0895 //  fp1: 10^ISCALE/Unchanged
0896 //  fp2: 10^LEN/Unchanged
0897 //  F_SCR1:BCD result with correct signs
0898 //  F_SCR2:ILOG/10^4
0899 //  L_SCR1:Exponent digits on return from binstr
0900 //  L_SCR2:first word of X packed/Unchanged
0901 
0902 A16_st:
0903     clrl    %d0     //clr d0 for collection of signs
0904     andib   #0x0f,FP_SCR1(%a6) //clear first nibble of FP_SCR1
0905     tstl    L_SCR2(%a6) //check sign of original mantissa
0906     bges    mant_p      //if pos, don't set SM
0907     moveql  #2,%d0      //move 2 in to d0 for SM
0908 mant_p:
0909     tstl    %d6     //check sign of ILOG
0910     bges    wr_sgn      //if pos, don't set SE
0911     addql   #1,%d0      //set bit 0 in d0 for SE
0912 wr_sgn:
0913     bfins   %d0,FP_SCR1(%a6){#0:#2} //insert SM and SE into FP_SCR1
0914 
0915 // Clean up and restore all registers used.
0916 
0917     fmovel  #0,%FPSR        //clear possible inex2/ainex bits
0918     fmovemx (%a7)+,%fp0-%fp2
0919     moveml  (%a7)+,%d2-%d7/%a2
0920     rts
0921 
0922     |end