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