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