xref: /OK3568_Linux_fs/kernel/arch/m68k/fpsp040/do_func.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun|
2*4882a593Smuzhiyun|	do_func.sa 3.4 2/18/91
3*4882a593Smuzhiyun|
4*4882a593Smuzhiyun| Do_func performs the unimplemented operation.  The operation
5*4882a593Smuzhiyun| to be performed is determined from the lower 7 bits of the
6*4882a593Smuzhiyun| extension word (except in the case of fmovecr and fsincos).
7*4882a593Smuzhiyun| The opcode and tag bits form an index into a jump table in
8*4882a593Smuzhiyun| tbldo.sa.  Cases of zero, infinity and NaN are handled in
9*4882a593Smuzhiyun| do_func by forcing the default result.  Normalized and
10*4882a593Smuzhiyun| denormalized (there are no unnormalized numbers at this
11*4882a593Smuzhiyun| point) are passed onto the emulation code.
12*4882a593Smuzhiyun|
13*4882a593Smuzhiyun| CMDREG1B and STAG are extracted from the fsave frame
14*4882a593Smuzhiyun| and combined to form the table index.  The function called
15*4882a593Smuzhiyun| will start with a0 pointing to the ETEMP operand.  Dyadic
16*4882a593Smuzhiyun| functions can find FPTEMP at -12(a0).
17*4882a593Smuzhiyun|
18*4882a593Smuzhiyun| Called functions return their result in fp0.  Sincos returns
19*4882a593Smuzhiyun| sin(x) in fp0 and cos(x) in fp1.
20*4882a593Smuzhiyun|
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun|		Copyright (C) Motorola, Inc. 1990
23*4882a593Smuzhiyun|			All Rights Reserved
24*4882a593Smuzhiyun|
25*4882a593Smuzhiyun|       For details on the license for this file, please see the
26*4882a593Smuzhiyun|       file, README, in this same directory.
27*4882a593Smuzhiyun
28*4882a593SmuzhiyunDO_FUNC:	|idnt    2,1 | Motorola 040 Floating Point Software Package
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun	|section	8
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun#include "fpsp.h"
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun	|xref	t_dz2
35*4882a593Smuzhiyun	|xref	t_operr
36*4882a593Smuzhiyun	|xref	t_inx2
37*4882a593Smuzhiyun	|xref	t_resdnrm
38*4882a593Smuzhiyun	|xref	dst_nan
39*4882a593Smuzhiyun	|xref	src_nan
40*4882a593Smuzhiyun	|xref	nrm_set
41*4882a593Smuzhiyun	|xref	sto_cos
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun	|xref	tblpre
44*4882a593Smuzhiyun	|xref	slognp1,slogn,slog10,slog2
45*4882a593Smuzhiyun	|xref	slognd,slog10d,slog2d
46*4882a593Smuzhiyun	|xref	smod,srem
47*4882a593Smuzhiyun	|xref	sscale
48*4882a593Smuzhiyun	|xref	smovcr
49*4882a593Smuzhiyun
50*4882a593SmuzhiyunPONE:	.long	0x3fff0000,0x80000000,0x00000000	|+1
51*4882a593SmuzhiyunMONE:	.long	0xbfff0000,0x80000000,0x00000000	|-1
52*4882a593SmuzhiyunPZERO:	.long	0x00000000,0x00000000,0x00000000	|+0
53*4882a593SmuzhiyunMZERO:	.long	0x80000000,0x00000000,0x00000000	|-0
54*4882a593SmuzhiyunPINF:	.long	0x7fff0000,0x00000000,0x00000000	|+inf
55*4882a593SmuzhiyunMINF:	.long	0xffff0000,0x00000000,0x00000000	|-inf
56*4882a593SmuzhiyunQNAN:	.long	0x7fff0000,0xffffffff,0xffffffff	|non-signaling nan
57*4882a593SmuzhiyunPPIBY2:  .long	0x3FFF0000,0xC90FDAA2,0x2168C235	|+PI/2
58*4882a593SmuzhiyunMPIBY2:  .long	0xbFFF0000,0xC90FDAA2,0x2168C235	|-PI/2
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun	.global	do_func
61*4882a593Smuzhiyundo_func:
62*4882a593Smuzhiyun	clrb	CU_ONLY(%a6)
63*4882a593Smuzhiyun|
64*4882a593Smuzhiyun| Check for fmovecr.  It does not follow the format of fp gen
65*4882a593Smuzhiyun| unimplemented instructions.  The test is on the upper 6 bits;
66*4882a593Smuzhiyun| if they are $17, the inst is fmovecr.  Call entry smovcr
67*4882a593Smuzhiyun| directly.
68*4882a593Smuzhiyun|
69*4882a593Smuzhiyun	bfextu	CMDREG1B(%a6){#0:#6},%d0 |get opclass and src fields
70*4882a593Smuzhiyun	cmpil	#0x17,%d0		|if op class and size fields are $17,
71*4882a593Smuzhiyun|				;it is FMOVECR; if not, continue
72*4882a593Smuzhiyun	bnes	not_fmovecr
73*4882a593Smuzhiyun	jmp	smovcr		|fmovecr; jmp directly to emulation
74*4882a593Smuzhiyun
75*4882a593Smuzhiyunnot_fmovecr:
76*4882a593Smuzhiyun	movew	CMDREG1B(%a6),%d0
77*4882a593Smuzhiyun	andl	#0x7F,%d0
78*4882a593Smuzhiyun	cmpil	#0x38,%d0		|if the extension is >= $38,
79*4882a593Smuzhiyun	bge	serror		|it is illegal
80*4882a593Smuzhiyun	bfextu	STAG(%a6){#0:#3},%d1
81*4882a593Smuzhiyun	lsll	#3,%d0		|make room for STAG
82*4882a593Smuzhiyun	addl	%d1,%d0		|combine for final index into table
83*4882a593Smuzhiyun	leal	tblpre,%a1	|start of monster jump table
84*4882a593Smuzhiyun	movel	(%a1,%d0.w*4),%a1	|real target address
85*4882a593Smuzhiyun	leal	ETEMP(%a6),%a0	|a0 is pointer to src op
86*4882a593Smuzhiyun	movel	USER_FPCR(%a6),%d1
87*4882a593Smuzhiyun	andl	#0xFF,%d1		| discard all but rounding mode/prec
88*4882a593Smuzhiyun	fmovel	#0,%fpcr
89*4882a593Smuzhiyun	jmp	(%a1)
90*4882a593Smuzhiyun|
91*4882a593Smuzhiyun|	ERROR
92*4882a593Smuzhiyun|
93*4882a593Smuzhiyun	.global	serror
94*4882a593Smuzhiyunserror:
95*4882a593Smuzhiyun	st	STORE_FLG(%a6)
96*4882a593Smuzhiyun	rts
97*4882a593Smuzhiyun|
98*4882a593Smuzhiyun| These routines load forced values into fp0.  They are called
99*4882a593Smuzhiyun| by index into tbldo.
100*4882a593Smuzhiyun|
101*4882a593Smuzhiyun| Load a signed zero to fp0 and set inex2/ainex
102*4882a593Smuzhiyun|
103*4882a593Smuzhiyun	.global	snzrinx
104*4882a593Smuzhiyunsnzrinx:
105*4882a593Smuzhiyun	btstb	#sign_bit,LOCAL_EX(%a0)	|get sign of source operand
106*4882a593Smuzhiyun	bnes	ld_mzinx	|if negative, branch
107*4882a593Smuzhiyun	bsr	ld_pzero	|bsr so we can return and set inx
108*4882a593Smuzhiyun	bra	t_inx2		|now, set the inx for the next inst
109*4882a593Smuzhiyunld_mzinx:
110*4882a593Smuzhiyun	bsr	ld_mzero	|if neg, load neg zero, return here
111*4882a593Smuzhiyun	bra	t_inx2		|now, set the inx for the next inst
112*4882a593Smuzhiyun|
113*4882a593Smuzhiyun| Load a signed zero to fp0; do not set inex2/ainex
114*4882a593Smuzhiyun|
115*4882a593Smuzhiyun	.global	szero
116*4882a593Smuzhiyunszero:
117*4882a593Smuzhiyun	btstb	#sign_bit,LOCAL_EX(%a0) |get sign of source operand
118*4882a593Smuzhiyun	bne	ld_mzero	|if neg, load neg zero
119*4882a593Smuzhiyun	bra	ld_pzero	|load positive zero
120*4882a593Smuzhiyun|
121*4882a593Smuzhiyun| Load a signed infinity to fp0; do not set inex2/ainex
122*4882a593Smuzhiyun|
123*4882a593Smuzhiyun	.global	sinf
124*4882a593Smuzhiyunsinf:
125*4882a593Smuzhiyun	btstb	#sign_bit,LOCAL_EX(%a0)	|get sign of source operand
126*4882a593Smuzhiyun	bne	ld_minf			|if negative branch
127*4882a593Smuzhiyun	bra	ld_pinf
128*4882a593Smuzhiyun|
129*4882a593Smuzhiyun| Load a signed one to fp0; do not set inex2/ainex
130*4882a593Smuzhiyun|
131*4882a593Smuzhiyun	.global	sone
132*4882a593Smuzhiyunsone:
133*4882a593Smuzhiyun	btstb	#sign_bit,LOCAL_EX(%a0)	|check sign of source
134*4882a593Smuzhiyun	bne	ld_mone
135*4882a593Smuzhiyun	bra	ld_pone
136*4882a593Smuzhiyun|
137*4882a593Smuzhiyun| Load a signed pi/2 to fp0; do not set inex2/ainex
138*4882a593Smuzhiyun|
139*4882a593Smuzhiyun	.global	spi_2
140*4882a593Smuzhiyunspi_2:
141*4882a593Smuzhiyun	btstb	#sign_bit,LOCAL_EX(%a0)	|check sign of source
142*4882a593Smuzhiyun	bne	ld_mpi2
143*4882a593Smuzhiyun	bra	ld_ppi2
144*4882a593Smuzhiyun|
145*4882a593Smuzhiyun| Load either a +0 or +inf for plus/minus operand
146*4882a593Smuzhiyun|
147*4882a593Smuzhiyun	.global	szr_inf
148*4882a593Smuzhiyunszr_inf:
149*4882a593Smuzhiyun	btstb	#sign_bit,LOCAL_EX(%a0)	|check sign of source
150*4882a593Smuzhiyun	bne	ld_pzero
151*4882a593Smuzhiyun	bra	ld_pinf
152*4882a593Smuzhiyun|
153*4882a593Smuzhiyun| Result is either an operr or +inf for plus/minus operand
154*4882a593Smuzhiyun| [Used by slogn, slognp1, slog10, and slog2]
155*4882a593Smuzhiyun|
156*4882a593Smuzhiyun	.global	sopr_inf
157*4882a593Smuzhiyunsopr_inf:
158*4882a593Smuzhiyun	btstb	#sign_bit,LOCAL_EX(%a0)	|check sign of source
159*4882a593Smuzhiyun	bne	t_operr
160*4882a593Smuzhiyun	bra	ld_pinf
161*4882a593Smuzhiyun|
162*4882a593Smuzhiyun|	FLOGNP1
163*4882a593Smuzhiyun|
164*4882a593Smuzhiyun	.global	sslognp1
165*4882a593Smuzhiyunsslognp1:
166*4882a593Smuzhiyun	fmovemx (%a0),%fp0-%fp0
167*4882a593Smuzhiyun	fcmpb	#-1,%fp0
168*4882a593Smuzhiyun	fbgt	slognp1
169*4882a593Smuzhiyun	fbeq	t_dz2		|if = -1, divide by zero exception
170*4882a593Smuzhiyun	fmovel	#0,%FPSR		|clr N flag
171*4882a593Smuzhiyun	bra	t_operr		|take care of operands < -1
172*4882a593Smuzhiyun|
173*4882a593Smuzhiyun|	FETOXM1
174*4882a593Smuzhiyun|
175*4882a593Smuzhiyun	.global	setoxm1i
176*4882a593Smuzhiyunsetoxm1i:
177*4882a593Smuzhiyun	btstb	#sign_bit,LOCAL_EX(%a0)	|check sign of source
178*4882a593Smuzhiyun	bne	ld_mone
179*4882a593Smuzhiyun	bra	ld_pinf
180*4882a593Smuzhiyun|
181*4882a593Smuzhiyun|	FLOGN
182*4882a593Smuzhiyun|
183*4882a593Smuzhiyun| Test for 1.0 as an input argument, returning +zero.  Also check
184*4882a593Smuzhiyun| the sign and return operr if negative.
185*4882a593Smuzhiyun|
186*4882a593Smuzhiyun	.global	sslogn
187*4882a593Smuzhiyunsslogn:
188*4882a593Smuzhiyun	btstb	#sign_bit,LOCAL_EX(%a0)
189*4882a593Smuzhiyun	bne	t_operr		|take care of operands < 0
190*4882a593Smuzhiyun	cmpiw	#0x3fff,LOCAL_EX(%a0) |test for 1.0 input
191*4882a593Smuzhiyun	bne	slogn
192*4882a593Smuzhiyun	cmpil	#0x80000000,LOCAL_HI(%a0)
193*4882a593Smuzhiyun	bne	slogn
194*4882a593Smuzhiyun	tstl	LOCAL_LO(%a0)
195*4882a593Smuzhiyun	bne	slogn
196*4882a593Smuzhiyun	fmovex	PZERO,%fp0
197*4882a593Smuzhiyun	rts
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun	.global	sslognd
200*4882a593Smuzhiyunsslognd:
201*4882a593Smuzhiyun	btstb	#sign_bit,LOCAL_EX(%a0)
202*4882a593Smuzhiyun	beq	slognd
203*4882a593Smuzhiyun	bra	t_operr		|take care of operands < 0
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun|
206*4882a593Smuzhiyun|	FLOG10
207*4882a593Smuzhiyun|
208*4882a593Smuzhiyun	.global	sslog10
209*4882a593Smuzhiyunsslog10:
210*4882a593Smuzhiyun	btstb	#sign_bit,LOCAL_EX(%a0)
211*4882a593Smuzhiyun	bne	t_operr		|take care of operands < 0
212*4882a593Smuzhiyun	cmpiw	#0x3fff,LOCAL_EX(%a0) |test for 1.0 input
213*4882a593Smuzhiyun	bne	slog10
214*4882a593Smuzhiyun	cmpil	#0x80000000,LOCAL_HI(%a0)
215*4882a593Smuzhiyun	bne	slog10
216*4882a593Smuzhiyun	tstl	LOCAL_LO(%a0)
217*4882a593Smuzhiyun	bne	slog10
218*4882a593Smuzhiyun	fmovex	PZERO,%fp0
219*4882a593Smuzhiyun	rts
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun	.global	sslog10d
222*4882a593Smuzhiyunsslog10d:
223*4882a593Smuzhiyun	btstb	#sign_bit,LOCAL_EX(%a0)
224*4882a593Smuzhiyun	beq	slog10d
225*4882a593Smuzhiyun	bra	t_operr		|take care of operands < 0
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun|
228*4882a593Smuzhiyun|	FLOG2
229*4882a593Smuzhiyun|
230*4882a593Smuzhiyun	.global	sslog2
231*4882a593Smuzhiyunsslog2:
232*4882a593Smuzhiyun	btstb	#sign_bit,LOCAL_EX(%a0)
233*4882a593Smuzhiyun	bne	t_operr		|take care of operands < 0
234*4882a593Smuzhiyun	cmpiw	#0x3fff,LOCAL_EX(%a0) |test for 1.0 input
235*4882a593Smuzhiyun	bne	slog2
236*4882a593Smuzhiyun	cmpil	#0x80000000,LOCAL_HI(%a0)
237*4882a593Smuzhiyun	bne	slog2
238*4882a593Smuzhiyun	tstl	LOCAL_LO(%a0)
239*4882a593Smuzhiyun	bne	slog2
240*4882a593Smuzhiyun	fmovex	PZERO,%fp0
241*4882a593Smuzhiyun	rts
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun	.global	sslog2d
244*4882a593Smuzhiyunsslog2d:
245*4882a593Smuzhiyun	btstb	#sign_bit,LOCAL_EX(%a0)
246*4882a593Smuzhiyun	beq	slog2d
247*4882a593Smuzhiyun	bra	t_operr		|take care of operands < 0
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun|
250*4882a593Smuzhiyun|	FMOD
251*4882a593Smuzhiyun|
252*4882a593Smuzhiyunpmodt:
253*4882a593Smuzhiyun|				;$21 fmod
254*4882a593Smuzhiyun|				;dtag,stag
255*4882a593Smuzhiyun	.long	smod		|  00,00  norm,norm = normal
256*4882a593Smuzhiyun	.long	smod_oper	|  00,01  norm,zero = nan with operr
257*4882a593Smuzhiyun	.long	smod_fpn	|  00,10  norm,inf  = fpn
258*4882a593Smuzhiyun	.long	smod_snan	|  00,11  norm,nan  = nan
259*4882a593Smuzhiyun	.long	smod_zro	|  01,00  zero,norm = +-zero
260*4882a593Smuzhiyun	.long	smod_oper	|  01,01  zero,zero = nan with operr
261*4882a593Smuzhiyun	.long	smod_zro	|  01,10  zero,inf  = +-zero
262*4882a593Smuzhiyun	.long	smod_snan	|  01,11  zero,nan  = nan
263*4882a593Smuzhiyun	.long	smod_oper	|  10,00  inf,norm  = nan with operr
264*4882a593Smuzhiyun	.long	smod_oper	|  10,01  inf,zero  = nan with operr
265*4882a593Smuzhiyun	.long	smod_oper	|  10,10  inf,inf   = nan with operr
266*4882a593Smuzhiyun	.long	smod_snan	|  10,11  inf,nan   = nan
267*4882a593Smuzhiyun	.long	smod_dnan	|  11,00  nan,norm  = nan
268*4882a593Smuzhiyun	.long	smod_dnan	|  11,01  nan,zero  = nan
269*4882a593Smuzhiyun	.long	smod_dnan	|  11,10  nan,inf   = nan
270*4882a593Smuzhiyun	.long	smod_dnan	|  11,11  nan,nan   = nan
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun	.global	pmod
273*4882a593Smuzhiyunpmod:
274*4882a593Smuzhiyun	clrb	FPSR_QBYTE(%a6) | clear quotient field
275*4882a593Smuzhiyun	bfextu	STAG(%a6){#0:#3},%d0 |stag = d0
276*4882a593Smuzhiyun	bfextu	DTAG(%a6){#0:#3},%d1 |dtag = d1
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun|
279*4882a593Smuzhiyun| Alias extended denorms to norms for the jump table.
280*4882a593Smuzhiyun|
281*4882a593Smuzhiyun	bclrl	#2,%d0
282*4882a593Smuzhiyun	bclrl	#2,%d1
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun	lslb	#2,%d1
285*4882a593Smuzhiyun	orb	%d0,%d1		|d1{3:2} = dtag, d1{1:0} = stag
286*4882a593Smuzhiyun|				;Tag values:
287*4882a593Smuzhiyun|				;00 = norm or denorm
288*4882a593Smuzhiyun|				;01 = zero
289*4882a593Smuzhiyun|				;10 = inf
290*4882a593Smuzhiyun|				;11 = nan
291*4882a593Smuzhiyun	lea	pmodt,%a1
292*4882a593Smuzhiyun	movel	(%a1,%d1.w*4),%a1
293*4882a593Smuzhiyun	jmp	(%a1)
294*4882a593Smuzhiyun
295*4882a593Smuzhiyunsmod_snan:
296*4882a593Smuzhiyun	bra	src_nan
297*4882a593Smuzhiyunsmod_dnan:
298*4882a593Smuzhiyun	bra	dst_nan
299*4882a593Smuzhiyunsmod_oper:
300*4882a593Smuzhiyun	bra	t_operr
301*4882a593Smuzhiyunsmod_zro:
302*4882a593Smuzhiyun	moveb	ETEMP(%a6),%d1	|get sign of src op
303*4882a593Smuzhiyun	moveb	FPTEMP(%a6),%d0	|get sign of dst op
304*4882a593Smuzhiyun	eorb	%d0,%d1		|get exor of sign bits
305*4882a593Smuzhiyun	btstl	#7,%d1		|test for sign
306*4882a593Smuzhiyun	beqs	smod_zsn	|if clr, do not set sign big
307*4882a593Smuzhiyun	bsetb	#q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit
308*4882a593Smuzhiyunsmod_zsn:
309*4882a593Smuzhiyun	btstl	#7,%d0		|test if + or -
310*4882a593Smuzhiyun	beq	ld_pzero	|if pos then load +0
311*4882a593Smuzhiyun	bra	ld_mzero	|else neg load -0
312*4882a593Smuzhiyun
313*4882a593Smuzhiyunsmod_fpn:
314*4882a593Smuzhiyun	moveb	ETEMP(%a6),%d1	|get sign of src op
315*4882a593Smuzhiyun	moveb	FPTEMP(%a6),%d0	|get sign of dst op
316*4882a593Smuzhiyun	eorb	%d0,%d1		|get exor of sign bits
317*4882a593Smuzhiyun	btstl	#7,%d1		|test for sign
318*4882a593Smuzhiyun	beqs	smod_fsn	|if clr, do not set sign big
319*4882a593Smuzhiyun	bsetb	#q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit
320*4882a593Smuzhiyunsmod_fsn:
321*4882a593Smuzhiyun	tstb	DTAG(%a6)	|filter out denormal destination case
322*4882a593Smuzhiyun	bpls	smod_nrm	|
323*4882a593Smuzhiyun	leal	FPTEMP(%a6),%a0	|a0<- addr(FPTEMP)
324*4882a593Smuzhiyun	bra	t_resdnrm	|force UNFL(but exact) result
325*4882a593Smuzhiyunsmod_nrm:
326*4882a593Smuzhiyun	fmovel USER_FPCR(%a6),%fpcr |use user's rmode and precision
327*4882a593Smuzhiyun	fmovex FPTEMP(%a6),%fp0	|return dest to fp0
328*4882a593Smuzhiyun	rts
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun|
331*4882a593Smuzhiyun|	FREM
332*4882a593Smuzhiyun|
333*4882a593Smuzhiyunpremt:
334*4882a593Smuzhiyun|				;$25 frem
335*4882a593Smuzhiyun|				;dtag,stag
336*4882a593Smuzhiyun	.long	srem		|  00,00  norm,norm = normal
337*4882a593Smuzhiyun	.long	srem_oper	|  00,01  norm,zero = nan with operr
338*4882a593Smuzhiyun	.long	srem_fpn	|  00,10  norm,inf  = fpn
339*4882a593Smuzhiyun	.long	srem_snan	|  00,11  norm,nan  = nan
340*4882a593Smuzhiyun	.long	srem_zro	|  01,00  zero,norm = +-zero
341*4882a593Smuzhiyun	.long	srem_oper	|  01,01  zero,zero = nan with operr
342*4882a593Smuzhiyun	.long	srem_zro	|  01,10  zero,inf  = +-zero
343*4882a593Smuzhiyun	.long	srem_snan	|  01,11  zero,nan  = nan
344*4882a593Smuzhiyun	.long	srem_oper	|  10,00  inf,norm  = nan with operr
345*4882a593Smuzhiyun	.long	srem_oper	|  10,01  inf,zero  = nan with operr
346*4882a593Smuzhiyun	.long	srem_oper	|  10,10  inf,inf   = nan with operr
347*4882a593Smuzhiyun	.long	srem_snan	|  10,11  inf,nan   = nan
348*4882a593Smuzhiyun	.long	srem_dnan	|  11,00  nan,norm  = nan
349*4882a593Smuzhiyun	.long	srem_dnan	|  11,01  nan,zero  = nan
350*4882a593Smuzhiyun	.long	srem_dnan	|  11,10  nan,inf   = nan
351*4882a593Smuzhiyun	.long	srem_dnan	|  11,11  nan,nan   = nan
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun	.global	prem
354*4882a593Smuzhiyunprem:
355*4882a593Smuzhiyun	clrb	FPSR_QBYTE(%a6)   |clear quotient field
356*4882a593Smuzhiyun	bfextu	STAG(%a6){#0:#3},%d0 |stag = d0
357*4882a593Smuzhiyun	bfextu	DTAG(%a6){#0:#3},%d1 |dtag = d1
358*4882a593Smuzhiyun|
359*4882a593Smuzhiyun| Alias extended denorms to norms for the jump table.
360*4882a593Smuzhiyun|
361*4882a593Smuzhiyun	bclr	#2,%d0
362*4882a593Smuzhiyun	bclr	#2,%d1
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun	lslb	#2,%d1
365*4882a593Smuzhiyun	orb	%d0,%d1		|d1{3:2} = dtag, d1{1:0} = stag
366*4882a593Smuzhiyun|				;Tag values:
367*4882a593Smuzhiyun|				;00 = norm or denorm
368*4882a593Smuzhiyun|				;01 = zero
369*4882a593Smuzhiyun|				;10 = inf
370*4882a593Smuzhiyun|				;11 = nan
371*4882a593Smuzhiyun	lea	premt,%a1
372*4882a593Smuzhiyun	movel	(%a1,%d1.w*4),%a1
373*4882a593Smuzhiyun	jmp	(%a1)
374*4882a593Smuzhiyun
375*4882a593Smuzhiyunsrem_snan:
376*4882a593Smuzhiyun	bra	src_nan
377*4882a593Smuzhiyunsrem_dnan:
378*4882a593Smuzhiyun	bra	dst_nan
379*4882a593Smuzhiyunsrem_oper:
380*4882a593Smuzhiyun	bra	t_operr
381*4882a593Smuzhiyunsrem_zro:
382*4882a593Smuzhiyun	moveb	ETEMP(%a6),%d1	|get sign of src op
383*4882a593Smuzhiyun	moveb	FPTEMP(%a6),%d0	|get sign of dst op
384*4882a593Smuzhiyun	eorb	%d0,%d1		|get exor of sign bits
385*4882a593Smuzhiyun	btstl	#7,%d1		|test for sign
386*4882a593Smuzhiyun	beqs	srem_zsn	|if clr, do not set sign big
387*4882a593Smuzhiyun	bsetb	#q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit
388*4882a593Smuzhiyunsrem_zsn:
389*4882a593Smuzhiyun	btstl	#7,%d0		|test if + or -
390*4882a593Smuzhiyun	beq	ld_pzero	|if pos then load +0
391*4882a593Smuzhiyun	bra	ld_mzero	|else neg load -0
392*4882a593Smuzhiyun
393*4882a593Smuzhiyunsrem_fpn:
394*4882a593Smuzhiyun	moveb	ETEMP(%a6),%d1	|get sign of src op
395*4882a593Smuzhiyun	moveb	FPTEMP(%a6),%d0	|get sign of dst op
396*4882a593Smuzhiyun	eorb	%d0,%d1		|get exor of sign bits
397*4882a593Smuzhiyun	btstl	#7,%d1		|test for sign
398*4882a593Smuzhiyun	beqs	srem_fsn	|if clr, do not set sign big
399*4882a593Smuzhiyun	bsetb	#q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit
400*4882a593Smuzhiyunsrem_fsn:
401*4882a593Smuzhiyun	tstb	DTAG(%a6)	|filter out denormal destination case
402*4882a593Smuzhiyun	bpls	srem_nrm	|
403*4882a593Smuzhiyun	leal	FPTEMP(%a6),%a0	|a0<- addr(FPTEMP)
404*4882a593Smuzhiyun	bra	t_resdnrm	|force UNFL(but exact) result
405*4882a593Smuzhiyunsrem_nrm:
406*4882a593Smuzhiyun	fmovel USER_FPCR(%a6),%fpcr |use user's rmode and precision
407*4882a593Smuzhiyun	fmovex FPTEMP(%a6),%fp0	|return dest to fp0
408*4882a593Smuzhiyun	rts
409*4882a593Smuzhiyun|
410*4882a593Smuzhiyun|	FSCALE
411*4882a593Smuzhiyun|
412*4882a593Smuzhiyunpscalet:
413*4882a593Smuzhiyun|				;$26 fscale
414*4882a593Smuzhiyun|				;dtag,stag
415*4882a593Smuzhiyun	.long	sscale		|  00,00  norm,norm = result
416*4882a593Smuzhiyun	.long	sscale		|  00,01  norm,zero = fpn
417*4882a593Smuzhiyun	.long	scl_opr		|  00,10  norm,inf  = nan with operr
418*4882a593Smuzhiyun	.long	scl_snan	|  00,11  norm,nan  = nan
419*4882a593Smuzhiyun	.long	scl_zro		|  01,00  zero,norm = +-zero
420*4882a593Smuzhiyun	.long	scl_zro		|  01,01  zero,zero = +-zero
421*4882a593Smuzhiyun	.long	scl_opr		|  01,10  zero,inf  = nan with operr
422*4882a593Smuzhiyun	.long	scl_snan	|  01,11  zero,nan  = nan
423*4882a593Smuzhiyun	.long	scl_inf		|  10,00  inf,norm  = +-inf
424*4882a593Smuzhiyun	.long	scl_inf		|  10,01  inf,zero  = +-inf
425*4882a593Smuzhiyun	.long	scl_opr		|  10,10  inf,inf   = nan with operr
426*4882a593Smuzhiyun	.long	scl_snan	|  10,11  inf,nan   = nan
427*4882a593Smuzhiyun	.long	scl_dnan	|  11,00  nan,norm  = nan
428*4882a593Smuzhiyun	.long	scl_dnan	|  11,01  nan,zero  = nan
429*4882a593Smuzhiyun	.long	scl_dnan	|  11,10  nan,inf   = nan
430*4882a593Smuzhiyun	.long	scl_dnan	|  11,11  nan,nan   = nan
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun	.global	pscale
433*4882a593Smuzhiyunpscale:
434*4882a593Smuzhiyun	bfextu	STAG(%a6){#0:#3},%d0 |stag in d0
435*4882a593Smuzhiyun	bfextu	DTAG(%a6){#0:#3},%d1 |dtag in d1
436*4882a593Smuzhiyun	bclrl	#2,%d0		|alias  denorm into norm
437*4882a593Smuzhiyun	bclrl	#2,%d1		|alias  denorm into norm
438*4882a593Smuzhiyun	lslb	#2,%d1
439*4882a593Smuzhiyun	orb	%d0,%d1		|d1{4:2} = dtag, d1{1:0} = stag
440*4882a593Smuzhiyun|				;dtag values     stag values:
441*4882a593Smuzhiyun|				;000 = norm      00 = norm
442*4882a593Smuzhiyun|				;001 = zero	 01 = zero
443*4882a593Smuzhiyun|				;010 = inf	 10 = inf
444*4882a593Smuzhiyun|				;011 = nan	 11 = nan
445*4882a593Smuzhiyun|				;100 = dnrm
446*4882a593Smuzhiyun|
447*4882a593Smuzhiyun|
448*4882a593Smuzhiyun	leal	pscalet,%a1	|load start of jump table
449*4882a593Smuzhiyun	movel	(%a1,%d1.w*4),%a1	|load a1 with label depending on tag
450*4882a593Smuzhiyun	jmp	(%a1)		|go to the routine
451*4882a593Smuzhiyun
452*4882a593Smuzhiyunscl_opr:
453*4882a593Smuzhiyun	bra	t_operr
454*4882a593Smuzhiyun
455*4882a593Smuzhiyunscl_dnan:
456*4882a593Smuzhiyun	bra	dst_nan
457*4882a593Smuzhiyun
458*4882a593Smuzhiyunscl_zro:
459*4882a593Smuzhiyun	btstb	#sign_bit,FPTEMP_EX(%a6)	|test if + or -
460*4882a593Smuzhiyun	beq	ld_pzero		|if pos then load +0
461*4882a593Smuzhiyun	bra	ld_mzero		|if neg then load -0
462*4882a593Smuzhiyunscl_inf:
463*4882a593Smuzhiyun	btstb	#sign_bit,FPTEMP_EX(%a6)	|test if + or -
464*4882a593Smuzhiyun	beq	ld_pinf			|if pos then load +inf
465*4882a593Smuzhiyun	bra	ld_minf			|else neg load -inf
466*4882a593Smuzhiyunscl_snan:
467*4882a593Smuzhiyun	bra	src_nan
468*4882a593Smuzhiyun|
469*4882a593Smuzhiyun|	FSINCOS
470*4882a593Smuzhiyun|
471*4882a593Smuzhiyun	.global	ssincosz
472*4882a593Smuzhiyunssincosz:
473*4882a593Smuzhiyun	btstb	#sign_bit,ETEMP(%a6)	|get sign
474*4882a593Smuzhiyun	beqs	sincosp
475*4882a593Smuzhiyun	fmovex	MZERO,%fp0
476*4882a593Smuzhiyun	bras	sincoscom
477*4882a593Smuzhiyunsincosp:
478*4882a593Smuzhiyun	fmovex PZERO,%fp0
479*4882a593Smuzhiyunsincoscom:
480*4882a593Smuzhiyun	fmovemx PONE,%fp1-%fp1	|do not allow FPSR to be affected
481*4882a593Smuzhiyun	bra	sto_cos		|store cosine result
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun	.global	ssincosi
484*4882a593Smuzhiyunssincosi:
485*4882a593Smuzhiyun	fmovex QNAN,%fp1	|load NAN
486*4882a593Smuzhiyun	bsr	sto_cos		|store cosine result
487*4882a593Smuzhiyun	fmovex QNAN,%fp0	|load NAN
488*4882a593Smuzhiyun	bra	t_operr
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun	.global	ssincosnan
491*4882a593Smuzhiyunssincosnan:
492*4882a593Smuzhiyun	movel	ETEMP_EX(%a6),FP_SCR1(%a6)
493*4882a593Smuzhiyun	movel	ETEMP_HI(%a6),FP_SCR1+4(%a6)
494*4882a593Smuzhiyun	movel	ETEMP_LO(%a6),FP_SCR1+8(%a6)
495*4882a593Smuzhiyun	bsetb	#signan_bit,FP_SCR1+4(%a6)
496*4882a593Smuzhiyun	fmovemx FP_SCR1(%a6),%fp1-%fp1
497*4882a593Smuzhiyun	bsr	sto_cos
498*4882a593Smuzhiyun	bra	src_nan
499*4882a593Smuzhiyun|
500*4882a593Smuzhiyun| This code forces default values for the zero, inf, and nan cases
501*4882a593Smuzhiyun| in the transcendentals code.  The CC bits must be set in the
502*4882a593Smuzhiyun| stacked FPSR to be correctly reported.
503*4882a593Smuzhiyun|
504*4882a593Smuzhiyun|**Returns +PI/2
505*4882a593Smuzhiyun	.global	ld_ppi2
506*4882a593Smuzhiyunld_ppi2:
507*4882a593Smuzhiyun	fmovex PPIBY2,%fp0		|load +pi/2
508*4882a593Smuzhiyun	bra	t_inx2			|set inex2 exc
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun|**Returns -PI/2
511*4882a593Smuzhiyun	.global	ld_mpi2
512*4882a593Smuzhiyunld_mpi2:
513*4882a593Smuzhiyun	fmovex MPIBY2,%fp0		|load -pi/2
514*4882a593Smuzhiyun	orl	#neg_mask,USER_FPSR(%a6)	|set N bit
515*4882a593Smuzhiyun	bra	t_inx2			|set inex2 exc
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun|**Returns +inf
518*4882a593Smuzhiyun	.global	ld_pinf
519*4882a593Smuzhiyunld_pinf:
520*4882a593Smuzhiyun	fmovex PINF,%fp0		|load +inf
521*4882a593Smuzhiyun	orl	#inf_mask,USER_FPSR(%a6)	|set I bit
522*4882a593Smuzhiyun	rts
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun|**Returns -inf
525*4882a593Smuzhiyun	.global	ld_minf
526*4882a593Smuzhiyunld_minf:
527*4882a593Smuzhiyun	fmovex MINF,%fp0		|load -inf
528*4882a593Smuzhiyun	orl	#neg_mask+inf_mask,USER_FPSR(%a6)	|set N and I bits
529*4882a593Smuzhiyun	rts
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun|**Returns +1
532*4882a593Smuzhiyun	.global	ld_pone
533*4882a593Smuzhiyunld_pone:
534*4882a593Smuzhiyun	fmovex PONE,%fp0		|load +1
535*4882a593Smuzhiyun	rts
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun|**Returns -1
538*4882a593Smuzhiyun	.global	ld_mone
539*4882a593Smuzhiyunld_mone:
540*4882a593Smuzhiyun	fmovex MONE,%fp0		|load -1
541*4882a593Smuzhiyun	orl	#neg_mask,USER_FPSR(%a6)	|set N bit
542*4882a593Smuzhiyun	rts
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun|**Returns +0
545*4882a593Smuzhiyun	.global	ld_pzero
546*4882a593Smuzhiyunld_pzero:
547*4882a593Smuzhiyun	fmovex PZERO,%fp0		|load +0
548*4882a593Smuzhiyun	orl	#z_mask,USER_FPSR(%a6)	|set Z bit
549*4882a593Smuzhiyun	rts
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun|**Returns -0
552*4882a593Smuzhiyun	.global	ld_mzero
553*4882a593Smuzhiyunld_mzero:
554*4882a593Smuzhiyun	fmovex MZERO,%fp0		|load -0
555*4882a593Smuzhiyun	orl	#neg_mask+z_mask,USER_FPSR(%a6)	|set N and Z bits
556*4882a593Smuzhiyun	rts
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun	|end
559