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