source: rtems/c/src/lib/libcpu/m68k/m68040/fpsp/decbin.S @ 9b4422a2

4.115
Last change on this file since 9b4422a2 was 9b4422a2, checked in by Joel Sherrill <joel.sherrill@…>, on 05/03/12 at 15:09:24

Remove All CVS Id Strings Possible Using a Script

Script does what is expected and tries to do it as
smartly as possible.

+ remove occurrences of two blank comment lines

next to each other after Id string line removed.

+ remove entire comment blocks which only exited to

contain CVS Ids

+ If the processing left a blank line at the top of

a file, it was removed.

  • Property mode set to 100644
File size: 15.8 KB
Line 
1//
2//
3//      decbin.sa 3.3 12/19/90
4//
5//      Description: Converts normalized packed bcd value pointed to by
6//      register A6 to extended-precision value in FP0.
7//
8//      Input: Normalized packed bcd value in ETEMP(a6).
9//
10//      Output: Exact floating-point representation of the packed bcd value.
11//
12//      Saves and Modifies: D2-D5
13//
14//      Speed: The program decbin takes ??? cycles to execute.
15//
16//      Object Size:
17//
18//      External Reference(s): None.
19//
20//      Algorithm:
21//      Expected is a normal bcd (i.e. non-exceptional; all inf, zero,
22//      and NaN operands are dispatched without entering this routine)
23//      value in 68881/882 format at location ETEMP(A6).
24//
25//      A1.     Convert the bcd exponent to binary by successive adds and muls.
26//      Set the sign according to SE. Subtract 16 to compensate
27//      for the mantissa which is to be interpreted as 17 integer
28//      digits, rather than 1 integer and 16 fraction digits.
29//      Note: this operation can never overflow.
30//
31//      A2. Convert the bcd mantissa to binary by successive
32//      adds and muls in FP0. Set the sign according to SM.
33//      The mantissa digits will be converted with the decimal point
34//      assumed following the least-significant digit.
35//      Note: this operation can never overflow.
36//
37//      A3. Count the number of leading/trailing zeros in the
38//      bcd string.  If SE is positive, count the leading zeros;
39//      if negative, count the trailing zeros.  Set the adjusted
40//      exponent equal to the exponent from A1 and the zero count
41//      added if SM = 1 and subtracted if SM = 0.  Scale the
42//      mantissa the equivalent of forcing in the bcd value:
43//
44//      SM = 0  a non-zero digit in the integer position
45//      SM = 1  a non-zero digit in Mant0, lsd of the fraction
46//
47//      this will insure that any value, regardless of its
48//      representation (ex. 0.1E2, 1E1, 10E0, 100E-1), is converted
49//      consistently.
50//
51//      A4. Calculate the factor 10^exp in FP1 using a table of
52//      10^(2^n) values.  To reduce the error in forming factors
53//      greater than 10^27, a directed rounding scheme is used with
54//      tables rounded to RN, RM, and RP, according to the table
55//      in the comments of the pwrten section.
56//
57//      A5. Form the final binary number by scaling the mantissa by
58//      the exponent factor.  This is done by multiplying the
59//      mantissa in FP0 by the factor in FP1 if the adjusted
60//      exponent sign is positive, and dividing FP0 by FP1 if
61//      it is negative.
62//
63//      Clean up and return.  Check if the final mul or div resulted
64//      in an inex2 exception.  If so, set inex1 in the fpsr and
65//      check if the inex1 exception is enabled.  If so, set d7 upper
66//      word to $0100.  This will signal unimp.sa that an enabled inex1
67//      exception occurred.  Unimp will fix the stack.
68//
69
70//              Copyright (C) Motorola, Inc. 1990
71//                      All Rights Reserved
72//
73//      THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
74//      The copyright notice above does not evidence any
75//      actual or intended publication of such source code.
76
77//DECBIN    idnt    2,1 | Motorola 040 Floating Point Software Package
78
79        |section        8
80
81#include "fpsp.defs"
82
83//
84//      PTENRN, PTENRM, and PTENRP are arrays of powers of 10 rounded
85//      to nearest, minus, and plus, respectively.  The tables include
86//      10**{1,2,4,8,16,32,64,128,256,512,1024,2048,4096}.  No rounding
87//      is required until the power is greater than 27, however, all
88//      tables include the first 5 for ease of indexing.
89//
90        |xref   PTENRN
91        |xref   PTENRM
92        |xref   PTENRP
93
94RTABLE: .byte   0,0,0,0
95        .byte   2,3,2,3
96        .byte   2,3,3,2
97        .byte   3,2,2,3
98
99        .global decbin
100        .global calc_e
101        .global pwrten
102        .global calc_m
103        .global norm
104        .global ap_st_z
105        .global ap_st_n
106//
107        .set    FNIBS,7
108        .set    FSTRT,0
109//
110        .set    ESTRT,4
111        .set    EDIGITS,2       //
112//
113// Constants in single precision
114FZERO:  .long   0x00000000
115FONE:   .long   0x3F800000
116FTEN:   .long   0x41200000
117
118        .set    TEN,10
119
120//
121decbin:
122        | fmovel        #0,FPCR         ;clr real fpcr
123        moveml  %d2-%d5,-(%a7)
124//
125// Calculate exponent:
126//  1. Copy bcd value in memory for use as a working copy.
127//  2. Calculate absolute value of exponent in d1 by mul and add.
128//  3. Correct for exponent sign.
129//  4. Subtract 16 to compensate for interpreting the mant as all integer digits.
130//     (i.e., all digits assumed left of the decimal point.)
131//
132// Register usage:
133//
134//  calc_e:
135//      (*)  d0: temp digit storage
136//      (*)  d1: accumulator for binary exponent
137//      (*)  d2: digit count
138//      (*)  d3: offset pointer
139//      ( )  d4: first word of bcd
140//      ( )  a0: pointer to working bcd value
141//      ( )  a6: pointer to original bcd value
142//      (*)  FP_SCR1: working copy of original bcd value
143//      (*)  L_SCR1: copy of original exponent word
144//
145calc_e:
146        movel   #EDIGITS,%d2    //# of nibbles (digits) in fraction part
147        moveql  #ESTRT,%d3      //counter to pick up digits
148        leal    FP_SCR1(%a6),%a0        //load tmp bcd storage address
149        movel   ETEMP(%a6),(%a0)        //save input bcd value
150        movel   ETEMP_HI(%a6),4(%a0) //save words 2 and 3
151        movel   ETEMP_LO(%a6),8(%a0) //and work with these
152        movel   (%a0),%d4       //get first word of bcd
153        clrl    %d1             //zero d1 for accumulator
154e_gd:
155        mulul   #TEN,%d1        //mul partial product by one digit place
156        bfextu  %d4{%d3:#4},%d0 //get the digit and zero extend into d0
157        addl    %d0,%d1         //d1 = d1 + d0
158        addqb   #4,%d3          //advance d3 to the next digit
159        dbf     %d2,e_gd        //if we have used all 3 digits, exit loop
160        btst    #30,%d4         //get SE
161        beqs    e_pos           //don't negate if pos
162        negl    %d1             //negate before subtracting
163e_pos:
164        subl    #16,%d1         //sub to compensate for shift of mant
165        bges    e_save          //if still pos, do not neg
166        negl    %d1             //now negative, make pos and set SE
167        orl     #0x40000000,%d4 //set SE in d4,
168        orl     #0x40000000,(%a0)       //and in working bcd
169e_save:
170        movel   %d1,L_SCR1(%a6) //save exp in memory
171//
172//
173// Calculate mantissa:
174//  1. Calculate absolute value of mantissa in fp0 by mul and add.
175//  2. Correct for mantissa sign.
176//     (i.e., all digits assumed left of the decimal point.)
177//
178// Register usage:
179//
180//  calc_m:
181//      (*)  d0: temp digit storage
182//      (*)  d1: lword counter
183//      (*)  d2: digit count
184//      (*)  d3: offset pointer
185//      ( )  d4: words 2 and 3 of bcd
186//      ( )  a0: pointer to working bcd value
187//      ( )  a6: pointer to original bcd value
188//      (*) fp0: mantissa accumulator
189//      ( )  FP_SCR1: working copy of original bcd value
190//      ( )  L_SCR1: copy of original exponent word
191//
192calc_m:
193        moveql  #1,%d1          //word counter, init to 1
194        fmoves  FZERO,%fp0      //accumulator
195//
196//
197//  Since the packed number has a long word between the first & second parts,
198//  get the integer digit then skip down & get the rest of the
199//  mantissa.  We will unroll the loop once.
200//
201        bfextu  (%a0){#28:#4},%d0       //integer part is ls digit in long word
202        faddb   %d0,%fp0                //add digit to sum in fp0
203//
204//
205//  Get the rest of the mantissa.
206//
207loadlw:
208        movel   (%a0,%d1.L*4),%d4       //load mantissa longword into d4
209        moveql  #FSTRT,%d3      //counter to pick up digits
210        moveql  #FNIBS,%d2      //reset number of digits per a0 ptr
211md2b:
212        fmuls   FTEN,%fp0       //fp0 = fp0 * 10
213        bfextu  %d4{%d3:#4},%d0 //get the digit and zero extend
214        faddb   %d0,%fp0        //fp0 = fp0 + digit
215//
216//
217//  If all the digits (8) in that long word have been converted (d2=0),
218//  then inc d1 (=2) to point to the next long word and reset d3 to 0
219//  to initialize the digit offset, and set d2 to 7 for the digit count;
220//  else continue with this long word.
221//
222        addqb   #4,%d3          //advance d3 to the next digit
223        dbf     %d2,md2b                //check for last digit in this lw
224nextlw:
225        addql   #1,%d1          //inc lw pointer in mantissa
226        cmpl    #2,%d1          //test for last lw
227        ble     loadlw          //if not, get last one
228
229//
230//  Check the sign of the mant and make the value in fp0 the same sign.
231//
232m_sign:
233        btst    #31,(%a0)       //test sign of the mantissa
234        beq     ap_st_z         //if clear, go to append/strip zeros
235        fnegx   %fp0            //if set, negate fp0
236
237//
238// Append/strip zeros:
239//
240//  For adjusted exponents which have an absolute value greater than 27*,
241//  this routine calculates the amount needed to normalize the mantissa
242//  for the adjusted exponent.  That number is subtracted from the exp
243//  if the exp was positive, and added if it was negative.  The purpose
244//  of this is to reduce the value of the exponent and the possibility
245//  of error in calculation of pwrten.
246//
247//  1. Branch on the sign of the adjusted exponent.
248//  2p.(positive exp)
249//   2. Check M16 and the digits in lwords 2 and 3 in descending order.
250//   3. Add one for each zero encountered until a non-zero digit.
251//   4. Subtract the count from the exp.
252//   5. Check if the exp has crossed zero in #3 above; make the exp abs
253//         and set SE.
254//      6. Multiply the mantissa by 10**count.
255//  2n.(negative exp)
256//   2. Check the digits in lwords 3 and 2 in descending order.
257//   3. Add one for each zero encountered until a non-zero digit.
258//   4. Add the count to the exp.
259//   5. Check if the exp has crossed zero in #3 above; clear SE.
260//   6. Divide the mantissa by 10**count.
261//
262//  *Why 27?  If the adjusted exponent is within -28 < expA < 28, than
263//   any adjustment due to append/strip zeros will drive the resultant
264//   exponent towards zero.  Since all pwrten constants with a power
265//   of 27 or less are exact, there is no need to use this routine to
266//   attempt to lessen the resultant exponent.
267//
268// Register usage:
269//
270//  ap_st_z:
271//      (*)  d0: temp digit storage
272//      (*)  d1: zero count
273//      (*)  d2: digit count
274//      (*)  d3: offset pointer
275//      ( )  d4: first word of bcd
276//      (*)  d5: lword counter
277//      ( )  a0: pointer to working bcd value
278//      ( )  FP_SCR1: working copy of original bcd value
279//      ( )  L_SCR1: copy of original exponent word
280//
281//
282// First check the absolute value of the exponent to see if this
283// routine is necessary.  If so, then check the sign of the exponent
284// and do append (+) or strip (-) zeros accordingly.
285// This section handles a positive adjusted exponent.
286//
287ap_st_z:
288        movel   L_SCR1(%a6),%d1 //load expA for range test
289        cmpl    #27,%d1         //test is with 27
290        ble     pwrten          //if abs(expA) <28, skip ap/st zeros
291        btst    #30,(%a0)       //check sign of exp
292        bne     ap_st_n         //if neg, go to neg side
293        clrl    %d1             //zero count reg
294        movel   (%a0),%d4               //load lword 1 to d4
295        bfextu  %d4{#28:#4},%d0 //get M16 in d0
296        bnes    ap_p_fx         //if M16 is non-zero, go fix exp
297        addql   #1,%d1          //inc zero count
298        moveql  #1,%d5          //init lword counter
299        movel   (%a0,%d5.L*4),%d4       //get lword 2 to d4
300        bnes    ap_p_cl         //if lw 2 is zero, skip it
301        addql   #8,%d1          //and inc count by 8
302        addql   #1,%d5          //inc lword counter
303        movel   (%a0,%d5.L*4),%d4       //get lword 3 to d4
304ap_p_cl:
305        clrl    %d3             //init offset reg
306        moveql  #7,%d2          //init digit counter
307ap_p_gd:
308        bfextu  %d4{%d3:#4},%d0 //get digit
309        bnes    ap_p_fx         //if non-zero, go to fix exp
310        addql   #4,%d3          //point to next digit
311        addql   #1,%d1          //inc digit counter
312        dbf     %d2,ap_p_gd     //get next digit
313ap_p_fx:
314        movel   %d1,%d0         //copy counter to d2
315        movel   L_SCR1(%a6),%d1 //get adjusted exp from memory
316        subl    %d0,%d1         //subtract count from exp
317        bges    ap_p_fm         //if still pos, go to pwrten
318        negl    %d1             //now its neg; get abs
319        movel   (%a0),%d4               //load lword 1 to d4
320        orl     #0x40000000,%d4 // and set SE in d4
321        orl     #0x40000000,(%a0)       // and in memory
322//
323// Calculate the mantissa multiplier to compensate for the striping of
324// zeros from the mantissa.
325//
326ap_p_fm:
327        movel   #PTENRN,%a1     //get address of power-of-ten table
328        clrl    %d3             //init table index
329        fmoves  FONE,%fp1       //init fp1 to 1
330        moveql  #3,%d2          //init d2 to count bits in counter
331ap_p_el:
332        asrl    #1,%d0          //shift lsb into carry
333        bccs    ap_p_en         //if 1, mul fp1 by pwrten factor
334        fmulx   (%a1,%d3),%fp1  //mul by 10**(d3_bit_no)
335ap_p_en:
336        addl    #12,%d3         //inc d3 to next rtable entry
337        tstl    %d0             //check if d0 is zero
338        bnes    ap_p_el         //if not, get next bit
339        fmulx   %fp1,%fp0               //mul mantissa by 10**(no_bits_shifted)
340        bra     pwrten          //go calc pwrten
341//
342// This section handles a negative adjusted exponent.
343//
344ap_st_n:
345        clrl    %d1             //clr counter
346        moveql  #2,%d5          //set up d5 to point to lword 3
347        movel   (%a0,%d5.L*4),%d4       //get lword 3
348        bnes    ap_n_cl         //if not zero, check digits
349        subl    #1,%d5          //dec d5 to point to lword 2
350        addql   #8,%d1          //inc counter by 8
351        movel   (%a0,%d5.L*4),%d4       //get lword 2
352ap_n_cl:
353        movel   #28,%d3         //point to last digit
354        moveql  #7,%d2          //init digit counter
355ap_n_gd:
356        bfextu  %d4{%d3:#4},%d0 //get digit
357        bnes    ap_n_fx         //if non-zero, go to exp fix
358        subql   #4,%d3          //point to previous digit
359        addql   #1,%d1          //inc digit counter
360        dbf     %d2,ap_n_gd     //get next digit
361ap_n_fx:
362        movel   %d1,%d0         //copy counter to d0
363        movel   L_SCR1(%a6),%d1 //get adjusted exp from memory
364        subl    %d0,%d1         //subtract count from exp
365        bgts    ap_n_fm         //if still pos, go fix mantissa
366        negl    %d1             //take abs of exp and clr SE
367        movel   (%a0),%d4               //load lword 1 to d4
368        andl    #0xbfffffff,%d4 // and clr SE in d4
369        andl    #0xbfffffff,(%a0)       // and in memory
370//
371// Calculate the mantissa multiplier to compensate for the appending of
372// zeros to the mantissa.
373//
374ap_n_fm:
375        movel   #PTENRN,%a1     //get address of power-of-ten table
376        clrl    %d3             //init table index
377        fmoves  FONE,%fp1       //init fp1 to 1
378        moveql  #3,%d2          //init d2 to count bits in counter
379ap_n_el:
380        asrl    #1,%d0          //shift lsb into carry
381        bccs    ap_n_en         //if 1, mul fp1 by pwrten factor
382        fmulx   (%a1,%d3),%fp1  //mul by 10**(d3_bit_no)
383ap_n_en:
384        addl    #12,%d3         //inc d3 to next rtable entry
385        tstl    %d0             //check if d0 is zero
386        bnes    ap_n_el         //if not, get next bit
387        fdivx   %fp1,%fp0               //div mantissa by 10**(no_bits_shifted)
388//
389//
390// Calculate power-of-ten factor from adjusted and shifted exponent.
391//
392// Register usage:
393//
394//  pwrten:
395//      (*)  d0: temp
396//      ( )  d1: exponent
397//      (*)  d2: {FPCR[6:5],SM,SE} as index in RTABLE; temp
398//      (*)  d3: FPCR work copy
399//      ( )  d4: first word of bcd
400//      (*)  a1: RTABLE pointer
401//  calc_p:
402//      (*)  d0: temp
403//      ( )  d1: exponent
404//      (*)  d3: PWRTxx table index
405//      ( )  a0: pointer to working copy of bcd
406//      (*)  a1: PWRTxx pointer
407//      (*) fp1: power-of-ten accumulator
408//
409// Pwrten calculates the exponent factor in the selected rounding mode
410// according to the following table:
411//
412//      Sign of Mant  Sign of Exp  Rounding Mode  PWRTEN Rounding Mode
413//
414//      ANY       ANY   RN      RN
415//
416//       +         +    RP      RP
417//       -         +    RP      RM
418//       +         -    RP      RM
419//       -         -    RP      RP
420//
421//       +         +    RM      RM
422//       -         +    RM      RP
423//       +         -    RM      RP
424//       -         -    RM      RM
425//
426//       +         +    RZ      RM
427//       -         +    RZ      RM
428//       +         -    RZ      RP
429//       -         -    RZ      RP
430//
431//
432pwrten:
433        movel   USER_FPCR(%a6),%d3 //get user's FPCR
434        bfextu  %d3{#26:#2},%d2 //isolate rounding mode bits
435        movel   (%a0),%d4               //reload 1st bcd word to d4
436        asll    #2,%d2          //format d2 to be
437        bfextu  %d4{#0:#2},%d0  // {FPCR[6],FPCR[5],SM,SE}
438        addl    %d0,%d2         //in d2 as index into RTABLE
439        leal    RTABLE,%a1      //load rtable base
440        moveb   (%a1,%d2),%d0   //load new rounding bits from table
441        clrl    %d3                     //clear d3 to force no exc and extended
442        bfins   %d0,%d3{#26:#2} //stuff new rounding bits in FPCR
443        fmovel  %d3,%FPCR               //write new FPCR
444        asrl    #1,%d0          //write correct PTENxx table
445        bccs    not_rp          //to a1
446        leal    PTENRP,%a1      //it is RP
447        bras    calc_p          //go to init section
448not_rp:
449        asrl    #1,%d0          //keep checking
450        bccs    not_rm
451        leal    PTENRM,%a1      //it is RM
452        bras    calc_p          //go to init section
453not_rm:
454        leal    PTENRN,%a1      //it is RN
455calc_p:
456        movel   %d1,%d0         //copy exp to d0;use d0
457        bpls    no_neg          //if exp is negative,
458        negl    %d0             //invert it
459        orl     #0x40000000,(%a0)       //and set SE bit
460no_neg:
461        clrl    %d3             //table index
462        fmoves  FONE,%fp1       //init fp1 to 1
463e_loop:
464        asrl    #1,%d0          //shift next bit into carry
465        bccs    e_next          //if zero, skip the mul
466        fmulx   (%a1,%d3),%fp1  //mul by 10**(d3_bit_no)
467e_next:
468        addl    #12,%d3         //inc d3 to next rtable entry
469        tstl    %d0             //check if d0 is zero
470        bnes    e_loop          //not zero, continue shifting
471//
472//
473//  Check the sign of the adjusted exp and make the value in fp0 the
474//  same sign. If the exp was pos then multiply fp1*fp0;
475//  else divide fp0/fp1.
476//
477// Register Usage:
478//  norm:
479//      ( )  a0: pointer to working bcd value
480//      (*) fp0: mantissa accumulator
481//      ( ) fp1: scaling factor - 10**(abs(exp))
482//
483norm:
484        btst    #30,(%a0)       //test the sign of the exponent
485        beqs    mul             //if clear, go to multiply
486div:
487        fdivx   %fp1,%fp0               //exp is negative, so divide mant by exp
488        bras    end_dec
489mul:
490        fmulx   %fp1,%fp0               //exp is positive, so multiply by exp
491//
492//
493// Clean up and return with result in fp0.
494//
495// If the final mul/div in decbin incurred an inex exception,
496// it will be inex2, but will be reported as inex1 by get_op.
497//
498end_dec:
499        fmovel  %FPSR,%d0               //get status register
500        bclrl   #inex2_bit+8,%d0        //test for inex2 and clear it
501        fmovel  %d0,%FPSR               //return status reg w/o inex2
502        beqs    no_exc          //skip this if no exc
503        orl     #inx1a_mask,USER_FPSR(%a6) //set inex1/ainex
504no_exc:
505        moveml  (%a7)+,%d2-%d5
506        rts
507        |end
Note: See TracBrowser for help on using the repository browser.