source: rtems/c/src/lib/libcpu/m68k/m68040/fpsp/decbin.s @ f9b93da

4.104.114.84.95
Last change on this file since f9b93da was f9b93da, checked in by Joel Sherrill <joel.sherrill@…>, on 04/16/97 at 17:33:04

Added the MC68040 Floating Point Support Package. This was ported
to RTEMS by Eric Norum. It is freely distributable and was acquired
from the Motorola WWW site. More info is in the FPSP README.

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