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