xref: /openbmc/linux/arch/m68k/fpsp040/res_func.S (revision e00d82d0)
11da177e4SLinus Torvalds|
21da177e4SLinus Torvalds|	res_func.sa 3.9 7/29/91
31da177e4SLinus Torvalds|
41da177e4SLinus Torvalds| Normalizes denormalized numbers if necessary and updates the
51da177e4SLinus Torvalds| stack frame.  The function is then restored back into the
61da177e4SLinus Torvalds| machine and the 040 completes the operation.  This routine
71da177e4SLinus Torvalds| is only used by the unsupported data type/format handler.
81da177e4SLinus Torvalds| (Exception vector 55).
91da177e4SLinus Torvalds|
101da177e4SLinus Torvalds| For packed move out (fmove.p fpm,<ea>) the operation is
111da177e4SLinus Torvalds| completed here; data is packed and moved to user memory.
121da177e4SLinus Torvalds| The stack is restored to the 040 only in the case of a
131da177e4SLinus Torvalds| reportable exception in the conversion.
141da177e4SLinus Torvalds|
151da177e4SLinus Torvalds|
161da177e4SLinus Torvalds|		Copyright (C) Motorola, Inc. 1990
171da177e4SLinus Torvalds|			All Rights Reserved
181da177e4SLinus Torvalds|
19e00d82d0SMatt Waddel|       For details on the license for this file, please see the
20e00d82d0SMatt Waddel|       file, README, in this same directory.
211da177e4SLinus Torvalds
221da177e4SLinus TorvaldsRES_FUNC:    |idnt    2,1 | Motorola 040 Floating Point Software Package
231da177e4SLinus Torvalds
241da177e4SLinus Torvalds	|section	8
251da177e4SLinus Torvalds
261da177e4SLinus Torvalds#include "fpsp.h"
271da177e4SLinus Torvalds
281da177e4SLinus Torvaldssp_bnds:	.short	0x3f81,0x407e
291da177e4SLinus Torvalds		.short	0x3f6a,0x0000
301da177e4SLinus Torvaldsdp_bnds:	.short	0x3c01,0x43fe
311da177e4SLinus Torvalds		.short	0x3bcd,0x0000
321da177e4SLinus Torvalds
331da177e4SLinus Torvalds	|xref	mem_write
341da177e4SLinus Torvalds	|xref	bindec
351da177e4SLinus Torvalds	|xref	get_fline
361da177e4SLinus Torvalds	|xref	round
371da177e4SLinus Torvalds	|xref	denorm
381da177e4SLinus Torvalds	|xref	dest_ext
391da177e4SLinus Torvalds	|xref	dest_dbl
401da177e4SLinus Torvalds	|xref	dest_sgl
411da177e4SLinus Torvalds	|xref	unf_sub
421da177e4SLinus Torvalds	|xref	nrm_set
431da177e4SLinus Torvalds	|xref	dnrm_lp
441da177e4SLinus Torvalds	|xref	ovf_res
451da177e4SLinus Torvalds	|xref	reg_dest
461da177e4SLinus Torvalds	|xref	t_ovfl
471da177e4SLinus Torvalds	|xref	t_unfl
481da177e4SLinus Torvalds
491da177e4SLinus Torvalds	.global	res_func
501da177e4SLinus Torvalds	.global	p_move
511da177e4SLinus Torvalds
521da177e4SLinus Torvaldsres_func:
531da177e4SLinus Torvalds	clrb	DNRM_FLG(%a6)
541da177e4SLinus Torvalds	clrb	RES_FLG(%a6)
551da177e4SLinus Torvalds	clrb	CU_ONLY(%a6)
561da177e4SLinus Torvalds	tstb	DY_MO_FLG(%a6)
571da177e4SLinus Torvalds	beqs	monadic
581da177e4SLinus Torvaldsdyadic:
591da177e4SLinus Torvalds	btstb	#7,DTAG(%a6)	|if dop = norm=000, zero=001,
601da177e4SLinus Torvalds|				;inf=010 or nan=011
611da177e4SLinus Torvalds	beqs	monadic		|then branch
621da177e4SLinus Torvalds|				;else denorm
631da177e4SLinus Torvalds| HANDLE DESTINATION DENORM HERE
641da177e4SLinus Torvalds|				;set dtag to norm
651da177e4SLinus Torvalds|				;write the tag & fpte15 to the fstack
661da177e4SLinus Torvalds	leal	FPTEMP(%a6),%a0
671da177e4SLinus Torvalds
681da177e4SLinus Torvalds	bclrb	#sign_bit,LOCAL_EX(%a0)
691da177e4SLinus Torvalds	sne	LOCAL_SGN(%a0)
701da177e4SLinus Torvalds
711da177e4SLinus Torvalds	bsr	nrm_set		|normalize number (exp will go negative)
721da177e4SLinus Torvalds	bclrb	#sign_bit,LOCAL_EX(%a0) |get rid of false sign
731da177e4SLinus Torvalds	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
741da177e4SLinus Torvalds	beqs	dpos
751da177e4SLinus Torvalds	bsetb	#sign_bit,LOCAL_EX(%a0)
761da177e4SLinus Torvaldsdpos:
771da177e4SLinus Torvalds	bfclr	DTAG(%a6){#0:#4}	|set tag to normalized, FPTE15 = 0
781da177e4SLinus Torvalds	bsetb	#4,DTAG(%a6)	|set FPTE15
791da177e4SLinus Torvalds	orb	#0x0f,DNRM_FLG(%a6)
801da177e4SLinus Torvaldsmonadic:
811da177e4SLinus Torvalds	leal	ETEMP(%a6),%a0
821da177e4SLinus Torvalds	btstb	#direction_bit,CMDREG1B(%a6)	|check direction
831da177e4SLinus Torvalds	bne	opclass3			|it is a mv out
841da177e4SLinus Torvalds|
851da177e4SLinus Torvalds| At this point, only opclass 0 and 2 possible
861da177e4SLinus Torvalds|
871da177e4SLinus Torvalds	btstb	#7,STAG(%a6)	|if sop = norm=000, zero=001,
881da177e4SLinus Torvalds|				;inf=010 or nan=011
891da177e4SLinus Torvalds	bne	mon_dnrm	|else denorm
901da177e4SLinus Torvalds	tstb	DY_MO_FLG(%a6)	|all cases of dyadic instructions would
911da177e4SLinus Torvalds	bne	normal		|require normalization of denorm
921da177e4SLinus Torvalds
931da177e4SLinus Torvalds| At this point:
941da177e4SLinus Torvalds|	monadic instructions:	fabs  = $18  fneg   = $1a  ftst   = $3a
951da177e4SLinus Torvalds|				fmove = $00  fsmove = $40  fdmove = $44
961da177e4SLinus Torvalds|				fsqrt = $05* fssqrt = $41  fdsqrt = $45
971da177e4SLinus Torvalds|				(*fsqrt reencoded to $05)
981da177e4SLinus Torvalds|
991da177e4SLinus Torvalds	movew	CMDREG1B(%a6),%d0	|get command register
1001da177e4SLinus Torvalds	andil	#0x7f,%d0			|strip to only command word
1011da177e4SLinus Torvalds|
1021da177e4SLinus Torvalds| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
1031da177e4SLinus Torvalds| fdsqrt are possible.
1041da177e4SLinus Torvalds| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
1051da177e4SLinus Torvalds| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
1061da177e4SLinus Torvalds|
1071da177e4SLinus Torvalds	btstl	#0,%d0
1081da177e4SLinus Torvalds	bne	normal			|weed out fsqrt instructions
1091da177e4SLinus Torvalds|
1101da177e4SLinus Torvalds| cu_norm handles fmove in instructions with normalized inputs.
1111da177e4SLinus Torvalds| The routine round is used to correctly round the input for the
1121da177e4SLinus Torvalds| destination precision and mode.
1131da177e4SLinus Torvalds|
1141da177e4SLinus Torvaldscu_norm:
1151da177e4SLinus Torvalds	st	CU_ONLY(%a6)		|set cu-only inst flag
1161da177e4SLinus Torvalds	movew	CMDREG1B(%a6),%d0
1171da177e4SLinus Torvalds	andib	#0x3b,%d0		|isolate bits to select inst
1181da177e4SLinus Torvalds	tstb	%d0
1191da177e4SLinus Torvalds	beql	cu_nmove	|if zero, it is an fmove
1201da177e4SLinus Torvalds	cmpib	#0x18,%d0
1211da177e4SLinus Torvalds	beql	cu_nabs		|if $18, it is fabs
1221da177e4SLinus Torvalds	cmpib	#0x1a,%d0
1231da177e4SLinus Torvalds	beql	cu_nneg		|if $1a, it is fneg
1241da177e4SLinus Torvalds|
1251da177e4SLinus Torvalds| Inst is ftst.  Check the source operand and set the cc's accordingly.
1261da177e4SLinus Torvalds| No write is done, so simply rts.
1271da177e4SLinus Torvalds|
1281da177e4SLinus Torvaldscu_ntst:
1291da177e4SLinus Torvalds	movew	LOCAL_EX(%a0),%d0
1301da177e4SLinus Torvalds	bclrl	#15,%d0
1311da177e4SLinus Torvalds	sne	LOCAL_SGN(%a0)
1321da177e4SLinus Torvalds	beqs	cu_ntpo
1331da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6) |set N
1341da177e4SLinus Torvaldscu_ntpo:
1351da177e4SLinus Torvalds	cmpiw	#0x7fff,%d0	|test for inf/nan
1361da177e4SLinus Torvalds	bnes	cu_ntcz
1371da177e4SLinus Torvalds	tstl	LOCAL_HI(%a0)
1381da177e4SLinus Torvalds	bnes	cu_ntn
1391da177e4SLinus Torvalds	tstl	LOCAL_LO(%a0)
1401da177e4SLinus Torvalds	bnes	cu_ntn
1411da177e4SLinus Torvalds	orl	#inf_mask,USER_FPSR(%a6)
1421da177e4SLinus Torvalds	rts
1431da177e4SLinus Torvaldscu_ntn:
1441da177e4SLinus Torvalds	orl	#nan_mask,USER_FPSR(%a6)
1451da177e4SLinus Torvalds	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
1461da177e4SLinus Torvalds|						;snan handler
1471da177e4SLinus Torvalds
1481da177e4SLinus Torvalds	rts
1491da177e4SLinus Torvaldscu_ntcz:
1501da177e4SLinus Torvalds	tstl	LOCAL_HI(%a0)
1511da177e4SLinus Torvalds	bnel	cu_ntsx
1521da177e4SLinus Torvalds	tstl	LOCAL_LO(%a0)
1531da177e4SLinus Torvalds	bnel	cu_ntsx
1541da177e4SLinus Torvalds	orl	#z_mask,USER_FPSR(%a6)
1551da177e4SLinus Torvaldscu_ntsx:
1561da177e4SLinus Torvalds	rts
1571da177e4SLinus Torvalds|
1581da177e4SLinus Torvalds| Inst is fabs.  Execute the absolute value function on the input.
1591da177e4SLinus Torvalds| Branch to the fmove code.  If the operand is NaN, do nothing.
1601da177e4SLinus Torvalds|
1611da177e4SLinus Torvaldscu_nabs:
1621da177e4SLinus Torvalds	moveb	STAG(%a6),%d0
1631da177e4SLinus Torvalds	btstl	#5,%d0			|test for NaN or zero
1641da177e4SLinus Torvalds	bne	wr_etemp		|if either, simply write it
1651da177e4SLinus Torvalds	bclrb	#7,LOCAL_EX(%a0)		|do abs
1661da177e4SLinus Torvalds	bras	cu_nmove		|fmove code will finish
1671da177e4SLinus Torvalds|
1681da177e4SLinus Torvalds| Inst is fneg.  Execute the negate value function on the input.
1691da177e4SLinus Torvalds| Fall though to the fmove code.  If the operand is NaN, do nothing.
1701da177e4SLinus Torvalds|
1711da177e4SLinus Torvaldscu_nneg:
1721da177e4SLinus Torvalds	moveb	STAG(%a6),%d0
1731da177e4SLinus Torvalds	btstl	#5,%d0			|test for NaN or zero
1741da177e4SLinus Torvalds	bne	wr_etemp		|if either, simply write it
1751da177e4SLinus Torvalds	bchgb	#7,LOCAL_EX(%a0)		|do neg
1761da177e4SLinus Torvalds|
1771da177e4SLinus Torvalds| Inst is fmove.  This code also handles all result writes.
1781da177e4SLinus Torvalds| If bit 2 is set, round is forced to double.  If it is clear,
1791da177e4SLinus Torvalds| and bit 6 is set, round is forced to single.  If both are clear,
1801da177e4SLinus Torvalds| the round precision is found in the fpcr.  If the rounding precision
1811da177e4SLinus Torvalds| is double or single, round the result before the write.
1821da177e4SLinus Torvalds|
1831da177e4SLinus Torvaldscu_nmove:
1841da177e4SLinus Torvalds	moveb	STAG(%a6),%d0
1851da177e4SLinus Torvalds	andib	#0xe0,%d0			|isolate stag bits
1861da177e4SLinus Torvalds	bne	wr_etemp		|if not norm, simply write it
1871da177e4SLinus Torvalds	btstb	#2,CMDREG1B+1(%a6)	|check for rd
1881da177e4SLinus Torvalds	bne	cu_nmrd
1891da177e4SLinus Torvalds	btstb	#6,CMDREG1B+1(%a6)	|check for rs
1901da177e4SLinus Torvalds	bne	cu_nmrs
1911da177e4SLinus Torvalds|
1921da177e4SLinus Torvalds| The move or operation is not with forced precision.  Test for
1931da177e4SLinus Torvalds| nan or inf as the input; if so, simply write it to FPn.  Use the
1941da177e4SLinus Torvalds| FPCR_MODE byte to get rounding on norms and zeros.
1951da177e4SLinus Torvalds|
1961da177e4SLinus Torvaldscu_nmnr:
1971da177e4SLinus Torvalds	bfextu	FPCR_MODE(%a6){#0:#2},%d0
1981da177e4SLinus Torvalds	tstb	%d0			|check for extended
1991da177e4SLinus Torvalds	beq	cu_wrexn		|if so, just write result
2001da177e4SLinus Torvalds	cmpib	#1,%d0			|check for single
2011da177e4SLinus Torvalds	beq	cu_nmrs			|fall through to double
2021da177e4SLinus Torvalds|
2031da177e4SLinus Torvalds| The move is fdmove or round precision is double.
2041da177e4SLinus Torvalds|
2051da177e4SLinus Torvaldscu_nmrd:
2061da177e4SLinus Torvalds	movel	#2,%d0			|set up the size for denorm
2071da177e4SLinus Torvalds	movew	LOCAL_EX(%a0),%d1		|compare exponent to double threshold
2081da177e4SLinus Torvalds	andw	#0x7fff,%d1
2091da177e4SLinus Torvalds	cmpw	#0x3c01,%d1
2101da177e4SLinus Torvalds	bls	cu_nunfl
2111da177e4SLinus Torvalds	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
2121da177e4SLinus Torvalds	orl	#0x00020000,%d1		|or in rprec (double)
2131da177e4SLinus Torvalds	clrl	%d0			|clear g,r,s for round
2141da177e4SLinus Torvalds	bclrb	#sign_bit,LOCAL_EX(%a0)	|convert to internal format
2151da177e4SLinus Torvalds	sne	LOCAL_SGN(%a0)
2161da177e4SLinus Torvalds	bsrl	round
2171da177e4SLinus Torvalds	bfclr	LOCAL_SGN(%a0){#0:#8}
2181da177e4SLinus Torvalds	beqs	cu_nmrdc
2191da177e4SLinus Torvalds	bsetb	#sign_bit,LOCAL_EX(%a0)
2201da177e4SLinus Torvaldscu_nmrdc:
2211da177e4SLinus Torvalds	movew	LOCAL_EX(%a0),%d1		|check for overflow
2221da177e4SLinus Torvalds	andw	#0x7fff,%d1
2231da177e4SLinus Torvalds	cmpw	#0x43ff,%d1
2241da177e4SLinus Torvalds	bge	cu_novfl		|take care of overflow case
2251da177e4SLinus Torvalds	bra	cu_wrexn
2261da177e4SLinus Torvalds|
2271da177e4SLinus Torvalds| The move is fsmove or round precision is single.
2281da177e4SLinus Torvalds|
2291da177e4SLinus Torvaldscu_nmrs:
2301da177e4SLinus Torvalds	movel	#1,%d0
2311da177e4SLinus Torvalds	movew	LOCAL_EX(%a0),%d1
2321da177e4SLinus Torvalds	andw	#0x7fff,%d1
2331da177e4SLinus Torvalds	cmpw	#0x3f81,%d1
2341da177e4SLinus Torvalds	bls	cu_nunfl
2351da177e4SLinus Torvalds	bfextu	FPCR_MODE(%a6){#2:#2},%d1
2361da177e4SLinus Torvalds	orl	#0x00010000,%d1
2371da177e4SLinus Torvalds	clrl	%d0
2381da177e4SLinus Torvalds	bclrb	#sign_bit,LOCAL_EX(%a0)
2391da177e4SLinus Torvalds	sne	LOCAL_SGN(%a0)
2401da177e4SLinus Torvalds	bsrl	round
2411da177e4SLinus Torvalds	bfclr	LOCAL_SGN(%a0){#0:#8}
2421da177e4SLinus Torvalds	beqs	cu_nmrsc
2431da177e4SLinus Torvalds	bsetb	#sign_bit,LOCAL_EX(%a0)
2441da177e4SLinus Torvaldscu_nmrsc:
2451da177e4SLinus Torvalds	movew	LOCAL_EX(%a0),%d1
2461da177e4SLinus Torvalds	andw	#0x7FFF,%d1
2471da177e4SLinus Torvalds	cmpw	#0x407f,%d1
2481da177e4SLinus Torvalds	blt	cu_wrexn
2491da177e4SLinus Torvalds|
2501da177e4SLinus Torvalds| The operand is above precision boundaries.  Use t_ovfl to
2511da177e4SLinus Torvalds| generate the correct value.
2521da177e4SLinus Torvalds|
2531da177e4SLinus Torvaldscu_novfl:
2541da177e4SLinus Torvalds	bsr	t_ovfl
2551da177e4SLinus Torvalds	bra	cu_wrexn
2561da177e4SLinus Torvalds|
2571da177e4SLinus Torvalds| The operand is below precision boundaries.  Use denorm to
2581da177e4SLinus Torvalds| generate the correct value.
2591da177e4SLinus Torvalds|
2601da177e4SLinus Torvaldscu_nunfl:
2611da177e4SLinus Torvalds	bclrb	#sign_bit,LOCAL_EX(%a0)
2621da177e4SLinus Torvalds	sne	LOCAL_SGN(%a0)
2631da177e4SLinus Torvalds	bsr	denorm
2641da177e4SLinus Torvalds	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
2651da177e4SLinus Torvalds	beqs	cu_nucont
2661da177e4SLinus Torvalds	bsetb	#sign_bit,LOCAL_EX(%a0)
2671da177e4SLinus Torvaldscu_nucont:
2681da177e4SLinus Torvalds	bfextu	FPCR_MODE(%a6){#2:#2},%d1
2691da177e4SLinus Torvalds	btstb	#2,CMDREG1B+1(%a6)	|check for rd
2701da177e4SLinus Torvalds	bne	inst_d
2711da177e4SLinus Torvalds	btstb	#6,CMDREG1B+1(%a6)	|check for rs
2721da177e4SLinus Torvalds	bne	inst_s
2731da177e4SLinus Torvalds	swap	%d1
2741da177e4SLinus Torvalds	moveb	FPCR_MODE(%a6),%d1
2751da177e4SLinus Torvalds	lsrb	#6,%d1
2761da177e4SLinus Torvalds	swap	%d1
2771da177e4SLinus Torvalds	bra	inst_sd
2781da177e4SLinus Torvaldsinst_d:
2791da177e4SLinus Torvalds	orl	#0x00020000,%d1
2801da177e4SLinus Torvalds	bra	inst_sd
2811da177e4SLinus Torvaldsinst_s:
2821da177e4SLinus Torvalds	orl	#0x00010000,%d1
2831da177e4SLinus Torvaldsinst_sd:
2841da177e4SLinus Torvalds	bclrb	#sign_bit,LOCAL_EX(%a0)
2851da177e4SLinus Torvalds	sne	LOCAL_SGN(%a0)
2861da177e4SLinus Torvalds	bsrl	round
2871da177e4SLinus Torvalds	bfclr	LOCAL_SGN(%a0){#0:#8}
2881da177e4SLinus Torvalds	beqs	cu_nuflp
2891da177e4SLinus Torvalds	bsetb	#sign_bit,LOCAL_EX(%a0)
2901da177e4SLinus Torvaldscu_nuflp:
2911da177e4SLinus Torvalds	btstb	#inex2_bit,FPSR_EXCEPT(%a6)
2921da177e4SLinus Torvalds	beqs	cu_nuninx
2931da177e4SLinus Torvalds	orl	#aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL
2941da177e4SLinus Torvaldscu_nuninx:
2951da177e4SLinus Torvalds	tstl	LOCAL_HI(%a0)		|test for zero
2961da177e4SLinus Torvalds	bnes	cu_nunzro
2971da177e4SLinus Torvalds	tstl	LOCAL_LO(%a0)
2981da177e4SLinus Torvalds	bnes	cu_nunzro
2991da177e4SLinus Torvalds|
3001da177e4SLinus Torvalds| The mantissa is zero from the denorm loop.  Check sign and rmode
3011da177e4SLinus Torvalds| to see if rounding should have occurred which would leave the lsb.
3021da177e4SLinus Torvalds|
3031da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d0
3041da177e4SLinus Torvalds	andil	#0x30,%d0		|isolate rmode
3051da177e4SLinus Torvalds	cmpil	#0x20,%d0
3061da177e4SLinus Torvalds	blts	cu_nzro
3071da177e4SLinus Torvalds	bnes	cu_nrp
3081da177e4SLinus Torvaldscu_nrm:
3091da177e4SLinus Torvalds	tstw	LOCAL_EX(%a0)	|if positive, set lsb
3101da177e4SLinus Torvalds	bges	cu_nzro
3111da177e4SLinus Torvalds	btstb	#7,FPCR_MODE(%a6) |check for double
3121da177e4SLinus Torvalds	beqs	cu_nincs
3131da177e4SLinus Torvalds	bras	cu_nincd
3141da177e4SLinus Torvaldscu_nrp:
3151da177e4SLinus Torvalds	tstw	LOCAL_EX(%a0)	|if positive, set lsb
3161da177e4SLinus Torvalds	blts	cu_nzro
3171da177e4SLinus Torvalds	btstb	#7,FPCR_MODE(%a6) |check for double
3181da177e4SLinus Torvalds	beqs	cu_nincs
3191da177e4SLinus Torvaldscu_nincd:
3201da177e4SLinus Torvalds	orl	#0x800,LOCAL_LO(%a0) |inc for double
3211da177e4SLinus Torvalds	bra	cu_nunzro
3221da177e4SLinus Torvaldscu_nincs:
3231da177e4SLinus Torvalds	orl	#0x100,LOCAL_HI(%a0) |inc for single
3241da177e4SLinus Torvalds	bra	cu_nunzro
3251da177e4SLinus Torvaldscu_nzro:
3261da177e4SLinus Torvalds	orl	#z_mask,USER_FPSR(%a6)
3271da177e4SLinus Torvalds	moveb	STAG(%a6),%d0
3281da177e4SLinus Torvalds	andib	#0xe0,%d0
3291da177e4SLinus Torvalds	cmpib	#0x40,%d0		|check if input was tagged zero
3301da177e4SLinus Torvalds	beqs	cu_numv
3311da177e4SLinus Torvaldscu_nunzro:
3321da177e4SLinus Torvalds	orl	#unfl_mask,USER_FPSR(%a6) |set unfl
3331da177e4SLinus Torvaldscu_numv:
3341da177e4SLinus Torvalds	movel	(%a0),ETEMP(%a6)
3351da177e4SLinus Torvalds	movel	4(%a0),ETEMP_HI(%a6)
3361da177e4SLinus Torvalds	movel	8(%a0),ETEMP_LO(%a6)
3371da177e4SLinus Torvalds|
3381da177e4SLinus Torvalds| Write the result to memory, setting the fpsr cc bits.  NaN and Inf
3391da177e4SLinus Torvalds| bypass cu_wrexn.
3401da177e4SLinus Torvalds|
3411da177e4SLinus Torvaldscu_wrexn:
3421da177e4SLinus Torvalds	tstw	LOCAL_EX(%a0)		|test for zero
3431da177e4SLinus Torvalds	beqs	cu_wrzero
3441da177e4SLinus Torvalds	cmpw	#0x8000,LOCAL_EX(%a0)	|test for zero
3451da177e4SLinus Torvalds	bnes	cu_wreon
3461da177e4SLinus Torvaldscu_wrzero:
3471da177e4SLinus Torvalds	orl	#z_mask,USER_FPSR(%a6)	|set Z bit
3481da177e4SLinus Torvaldscu_wreon:
3491da177e4SLinus Torvalds	tstw	LOCAL_EX(%a0)
3501da177e4SLinus Torvalds	bpl	wr_etemp
3511da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6)
3521da177e4SLinus Torvalds	bra	wr_etemp
3531da177e4SLinus Torvalds
3541da177e4SLinus Torvalds|
3551da177e4SLinus Torvalds| HANDLE SOURCE DENORM HERE
3561da177e4SLinus Torvalds|
3571da177e4SLinus Torvalds|				;clear denorm stag to norm
3581da177e4SLinus Torvalds|				;write the new tag & ete15 to the fstack
3591da177e4SLinus Torvaldsmon_dnrm:
3601da177e4SLinus Torvalds|
3611da177e4SLinus Torvalds| At this point, check for the cases in which normalizing the
3621da177e4SLinus Torvalds| denorm produces incorrect results.
3631da177e4SLinus Torvalds|
3641da177e4SLinus Torvalds	tstb	DY_MO_FLG(%a6)	|all cases of dyadic instructions would
3651da177e4SLinus Torvalds	bnes	nrm_src		|require normalization of denorm
3661da177e4SLinus Torvalds
3671da177e4SLinus Torvalds| At this point:
3681da177e4SLinus Torvalds|	monadic instructions:	fabs  = $18  fneg   = $1a  ftst   = $3a
3691da177e4SLinus Torvalds|				fmove = $00  fsmove = $40  fdmove = $44
3701da177e4SLinus Torvalds|				fsqrt = $05* fssqrt = $41  fdsqrt = $45
3711da177e4SLinus Torvalds|				(*fsqrt reencoded to $05)
3721da177e4SLinus Torvalds|
3731da177e4SLinus Torvalds	movew	CMDREG1B(%a6),%d0	|get command register
3741da177e4SLinus Torvalds	andil	#0x7f,%d0			|strip to only command word
3751da177e4SLinus Torvalds|
3761da177e4SLinus Torvalds| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
3771da177e4SLinus Torvalds| fdsqrt are possible.
3781da177e4SLinus Torvalds| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
3791da177e4SLinus Torvalds| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
3801da177e4SLinus Torvalds|
3811da177e4SLinus Torvalds	btstl	#0,%d0
3821da177e4SLinus Torvalds	bnes	nrm_src		|weed out fsqrt instructions
3831da177e4SLinus Torvalds	st	CU_ONLY(%a6)	|set cu-only inst flag
3841da177e4SLinus Torvalds	bra	cu_dnrm		|fmove, fabs, fneg, ftst
3851da177e4SLinus Torvalds|				;cases go to cu_dnrm
3861da177e4SLinus Torvaldsnrm_src:
3871da177e4SLinus Torvalds	bclrb	#sign_bit,LOCAL_EX(%a0)
3881da177e4SLinus Torvalds	sne	LOCAL_SGN(%a0)
3891da177e4SLinus Torvalds	bsr	nrm_set		|normalize number (exponent will go
3901da177e4SLinus Torvalds|				; negative)
3911da177e4SLinus Torvalds	bclrb	#sign_bit,LOCAL_EX(%a0) |get rid of false sign
3921da177e4SLinus Torvalds
3931da177e4SLinus Torvalds	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
3941da177e4SLinus Torvalds	beqs	spos
3951da177e4SLinus Torvalds	bsetb	#sign_bit,LOCAL_EX(%a0)
3961da177e4SLinus Torvaldsspos:
3971da177e4SLinus Torvalds	bfclr	STAG(%a6){#0:#4}	|set tag to normalized, FPTE15 = 0
3981da177e4SLinus Torvalds	bsetb	#4,STAG(%a6)	|set ETE15
3991da177e4SLinus Torvalds	orb	#0xf0,DNRM_FLG(%a6)
4001da177e4SLinus Torvaldsnormal:
4011da177e4SLinus Torvalds	tstb	DNRM_FLG(%a6)	|check if any of the ops were denorms
4021da177e4SLinus Torvalds	bne	ck_wrap		|if so, check if it is a potential
4031da177e4SLinus Torvalds|				;wrap-around case
4041da177e4SLinus Torvaldsfix_stk:
4051da177e4SLinus Torvalds	moveb	#0xfe,CU_SAVEPC(%a6)
4061da177e4SLinus Torvalds	bclrb	#E1,E_BYTE(%a6)
4071da177e4SLinus Torvalds
4081da177e4SLinus Torvalds	clrw	NMNEXC(%a6)
4091da177e4SLinus Torvalds
4101da177e4SLinus Torvalds	st	RES_FLG(%a6)	|indicate that a restore is needed
4111da177e4SLinus Torvalds	rts
4121da177e4SLinus Torvalds
4131da177e4SLinus Torvalds|
4141da177e4SLinus Torvalds| cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
4151da177e4SLinus Torvalds| ftst) completely in software without an frestore to the 040.
4161da177e4SLinus Torvalds|
4171da177e4SLinus Torvaldscu_dnrm:
4181da177e4SLinus Torvalds	st	CU_ONLY(%a6)
4191da177e4SLinus Torvalds	movew	CMDREG1B(%a6),%d0
4201da177e4SLinus Torvalds	andib	#0x3b,%d0		|isolate bits to select inst
4211da177e4SLinus Torvalds	tstb	%d0
4221da177e4SLinus Torvalds	beql	cu_dmove	|if zero, it is an fmove
4231da177e4SLinus Torvalds	cmpib	#0x18,%d0
4241da177e4SLinus Torvalds	beql	cu_dabs		|if $18, it is fabs
4251da177e4SLinus Torvalds	cmpib	#0x1a,%d0
4261da177e4SLinus Torvalds	beql	cu_dneg		|if $1a, it is fneg
4271da177e4SLinus Torvalds|
4281da177e4SLinus Torvalds| Inst is ftst.  Check the source operand and set the cc's accordingly.
4291da177e4SLinus Torvalds| No write is done, so simply rts.
4301da177e4SLinus Torvalds|
4311da177e4SLinus Torvaldscu_dtst:
4321da177e4SLinus Torvalds	movew	LOCAL_EX(%a0),%d0
4331da177e4SLinus Torvalds	bclrl	#15,%d0
4341da177e4SLinus Torvalds	sne	LOCAL_SGN(%a0)
4351da177e4SLinus Torvalds	beqs	cu_dtpo
4361da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6) |set N
4371da177e4SLinus Torvaldscu_dtpo:
4381da177e4SLinus Torvalds	cmpiw	#0x7fff,%d0	|test for inf/nan
4391da177e4SLinus Torvalds	bnes	cu_dtcz
4401da177e4SLinus Torvalds	tstl	LOCAL_HI(%a0)
4411da177e4SLinus Torvalds	bnes	cu_dtn
4421da177e4SLinus Torvalds	tstl	LOCAL_LO(%a0)
4431da177e4SLinus Torvalds	bnes	cu_dtn
4441da177e4SLinus Torvalds	orl	#inf_mask,USER_FPSR(%a6)
4451da177e4SLinus Torvalds	rts
4461da177e4SLinus Torvaldscu_dtn:
4471da177e4SLinus Torvalds	orl	#nan_mask,USER_FPSR(%a6)
4481da177e4SLinus Torvalds	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
4491da177e4SLinus Torvalds|						;snan handler
4501da177e4SLinus Torvalds	rts
4511da177e4SLinus Torvaldscu_dtcz:
4521da177e4SLinus Torvalds	tstl	LOCAL_HI(%a0)
4531da177e4SLinus Torvalds	bnel	cu_dtsx
4541da177e4SLinus Torvalds	tstl	LOCAL_LO(%a0)
4551da177e4SLinus Torvalds	bnel	cu_dtsx
4561da177e4SLinus Torvalds	orl	#z_mask,USER_FPSR(%a6)
4571da177e4SLinus Torvaldscu_dtsx:
4581da177e4SLinus Torvalds	rts
4591da177e4SLinus Torvalds|
4601da177e4SLinus Torvalds| Inst is fabs.  Execute the absolute value function on the input.
4611da177e4SLinus Torvalds| Branch to the fmove code.
4621da177e4SLinus Torvalds|
4631da177e4SLinus Torvaldscu_dabs:
4641da177e4SLinus Torvalds	bclrb	#7,LOCAL_EX(%a0)		|do abs
4651da177e4SLinus Torvalds	bras	cu_dmove		|fmove code will finish
4661da177e4SLinus Torvalds|
4671da177e4SLinus Torvalds| Inst is fneg.  Execute the negate value function on the input.
4681da177e4SLinus Torvalds| Fall though to the fmove code.
4691da177e4SLinus Torvalds|
4701da177e4SLinus Torvaldscu_dneg:
4711da177e4SLinus Torvalds	bchgb	#7,LOCAL_EX(%a0)		|do neg
4721da177e4SLinus Torvalds|
4731da177e4SLinus Torvalds| Inst is fmove.  This code also handles all result writes.
4741da177e4SLinus Torvalds| If bit 2 is set, round is forced to double.  If it is clear,
4751da177e4SLinus Torvalds| and bit 6 is set, round is forced to single.  If both are clear,
4761da177e4SLinus Torvalds| the round precision is found in the fpcr.  If the rounding precision
4771da177e4SLinus Torvalds| is double or single, the result is zero, and the mode is checked
4781da177e4SLinus Torvalds| to determine if the lsb of the result should be set.
4791da177e4SLinus Torvalds|
4801da177e4SLinus Torvaldscu_dmove:
4811da177e4SLinus Torvalds	btstb	#2,CMDREG1B+1(%a6)	|check for rd
4821da177e4SLinus Torvalds	bne	cu_dmrd
4831da177e4SLinus Torvalds	btstb	#6,CMDREG1B+1(%a6)	|check for rs
4841da177e4SLinus Torvalds	bne	cu_dmrs
4851da177e4SLinus Torvalds|
4861da177e4SLinus Torvalds| The move or operation is not with forced precision.  Use the
4871da177e4SLinus Torvalds| FPCR_MODE byte to get rounding.
4881da177e4SLinus Torvalds|
4891da177e4SLinus Torvaldscu_dmnr:
4901da177e4SLinus Torvalds	bfextu	FPCR_MODE(%a6){#0:#2},%d0
4911da177e4SLinus Torvalds	tstb	%d0			|check for extended
4921da177e4SLinus Torvalds	beq	cu_wrexd		|if so, just write result
4931da177e4SLinus Torvalds	cmpib	#1,%d0			|check for single
4941da177e4SLinus Torvalds	beq	cu_dmrs			|fall through to double
4951da177e4SLinus Torvalds|
4961da177e4SLinus Torvalds| The move is fdmove or round precision is double.  Result is zero.
4971da177e4SLinus Torvalds| Check rmode for rp or rm and set lsb accordingly.
4981da177e4SLinus Torvalds|
4991da177e4SLinus Torvaldscu_dmrd:
5001da177e4SLinus Torvalds	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
5011da177e4SLinus Torvalds	tstw	LOCAL_EX(%a0)		|check sign
5021da177e4SLinus Torvalds	blts	cu_dmdn
5031da177e4SLinus Torvalds	cmpib	#3,%d1			|check for rp
5041da177e4SLinus Torvalds	bne	cu_dpd			|load double pos zero
5051da177e4SLinus Torvalds	bra	cu_dpdr			|load double pos zero w/lsb
5061da177e4SLinus Torvaldscu_dmdn:
5071da177e4SLinus Torvalds	cmpib	#2,%d1			|check for rm
5081da177e4SLinus Torvalds	bne	cu_dnd			|load double neg zero
5091da177e4SLinus Torvalds	bra	cu_dndr			|load double neg zero w/lsb
5101da177e4SLinus Torvalds|
5111da177e4SLinus Torvalds| The move is fsmove or round precision is single.  Result is zero.
5121da177e4SLinus Torvalds| Check for rp or rm and set lsb accordingly.
5131da177e4SLinus Torvalds|
5141da177e4SLinus Torvaldscu_dmrs:
5151da177e4SLinus Torvalds	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
5161da177e4SLinus Torvalds	tstw	LOCAL_EX(%a0)		|check sign
5171da177e4SLinus Torvalds	blts	cu_dmsn
5181da177e4SLinus Torvalds	cmpib	#3,%d1			|check for rp
5191da177e4SLinus Torvalds	bne	cu_spd			|load single pos zero
5201da177e4SLinus Torvalds	bra	cu_spdr			|load single pos zero w/lsb
5211da177e4SLinus Torvaldscu_dmsn:
5221da177e4SLinus Torvalds	cmpib	#2,%d1			|check for rm
5231da177e4SLinus Torvalds	bne	cu_snd			|load single neg zero
5241da177e4SLinus Torvalds	bra	cu_sndr			|load single neg zero w/lsb
5251da177e4SLinus Torvalds|
5261da177e4SLinus Torvalds| The precision is extended, so the result in etemp is correct.
5271da177e4SLinus Torvalds| Simply set unfl (not inex2 or aunfl) and write the result to
5281da177e4SLinus Torvalds| the correct fp register.
5291da177e4SLinus Torvaldscu_wrexd:
5301da177e4SLinus Torvalds	orl	#unfl_mask,USER_FPSR(%a6)
5311da177e4SLinus Torvalds	tstw	LOCAL_EX(%a0)
5321da177e4SLinus Torvalds	beq	wr_etemp
5331da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6)
5341da177e4SLinus Torvalds	bra	wr_etemp
5351da177e4SLinus Torvalds|
5361da177e4SLinus Torvalds| These routines write +/- zero in double format.  The routines
5371da177e4SLinus Torvalds| cu_dpdr and cu_dndr set the double lsb.
5381da177e4SLinus Torvalds|
5391da177e4SLinus Torvaldscu_dpd:
5401da177e4SLinus Torvalds	movel	#0x3c010000,LOCAL_EX(%a0)	|force pos double zero
5411da177e4SLinus Torvalds	clrl	LOCAL_HI(%a0)
5421da177e4SLinus Torvalds	clrl	LOCAL_LO(%a0)
5431da177e4SLinus Torvalds	orl	#z_mask,USER_FPSR(%a6)
5441da177e4SLinus Torvalds	orl	#unfinx_mask,USER_FPSR(%a6)
5451da177e4SLinus Torvalds	bra	wr_etemp
5461da177e4SLinus Torvaldscu_dpdr:
5471da177e4SLinus Torvalds	movel	#0x3c010000,LOCAL_EX(%a0)	|force pos double zero
5481da177e4SLinus Torvalds	clrl	LOCAL_HI(%a0)
5491da177e4SLinus Torvalds	movel	#0x800,LOCAL_LO(%a0)	|with lsb set
5501da177e4SLinus Torvalds	orl	#unfinx_mask,USER_FPSR(%a6)
5511da177e4SLinus Torvalds	bra	wr_etemp
5521da177e4SLinus Torvaldscu_dnd:
5531da177e4SLinus Torvalds	movel	#0xbc010000,LOCAL_EX(%a0)	|force pos double zero
5541da177e4SLinus Torvalds	clrl	LOCAL_HI(%a0)
5551da177e4SLinus Torvalds	clrl	LOCAL_LO(%a0)
5561da177e4SLinus Torvalds	orl	#z_mask,USER_FPSR(%a6)
5571da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6)
5581da177e4SLinus Torvalds	orl	#unfinx_mask,USER_FPSR(%a6)
5591da177e4SLinus Torvalds	bra	wr_etemp
5601da177e4SLinus Torvaldscu_dndr:
5611da177e4SLinus Torvalds	movel	#0xbc010000,LOCAL_EX(%a0)	|force pos double zero
5621da177e4SLinus Torvalds	clrl	LOCAL_HI(%a0)
5631da177e4SLinus Torvalds	movel	#0x800,LOCAL_LO(%a0)	|with lsb set
5641da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6)
5651da177e4SLinus Torvalds	orl	#unfinx_mask,USER_FPSR(%a6)
5661da177e4SLinus Torvalds	bra	wr_etemp
5671da177e4SLinus Torvalds|
5681da177e4SLinus Torvalds| These routines write +/- zero in single format.  The routines
5691da177e4SLinus Torvalds| cu_dpdr and cu_dndr set the single lsb.
5701da177e4SLinus Torvalds|
5711da177e4SLinus Torvaldscu_spd:
5721da177e4SLinus Torvalds	movel	#0x3f810000,LOCAL_EX(%a0)	|force pos single zero
5731da177e4SLinus Torvalds	clrl	LOCAL_HI(%a0)
5741da177e4SLinus Torvalds	clrl	LOCAL_LO(%a0)
5751da177e4SLinus Torvalds	orl	#z_mask,USER_FPSR(%a6)
5761da177e4SLinus Torvalds	orl	#unfinx_mask,USER_FPSR(%a6)
5771da177e4SLinus Torvalds	bra	wr_etemp
5781da177e4SLinus Torvaldscu_spdr:
5791da177e4SLinus Torvalds	movel	#0x3f810000,LOCAL_EX(%a0)	|force pos single zero
5801da177e4SLinus Torvalds	movel	#0x100,LOCAL_HI(%a0)	|with lsb set
5811da177e4SLinus Torvalds	clrl	LOCAL_LO(%a0)
5821da177e4SLinus Torvalds	orl	#unfinx_mask,USER_FPSR(%a6)
5831da177e4SLinus Torvalds	bra	wr_etemp
5841da177e4SLinus Torvaldscu_snd:
5851da177e4SLinus Torvalds	movel	#0xbf810000,LOCAL_EX(%a0)	|force pos single zero
5861da177e4SLinus Torvalds	clrl	LOCAL_HI(%a0)
5871da177e4SLinus Torvalds	clrl	LOCAL_LO(%a0)
5881da177e4SLinus Torvalds	orl	#z_mask,USER_FPSR(%a6)
5891da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6)
5901da177e4SLinus Torvalds	orl	#unfinx_mask,USER_FPSR(%a6)
5911da177e4SLinus Torvalds	bra	wr_etemp
5921da177e4SLinus Torvaldscu_sndr:
5931da177e4SLinus Torvalds	movel	#0xbf810000,LOCAL_EX(%a0)	|force pos single zero
5941da177e4SLinus Torvalds	movel	#0x100,LOCAL_HI(%a0)	|with lsb set
5951da177e4SLinus Torvalds	clrl	LOCAL_LO(%a0)
5961da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6)
5971da177e4SLinus Torvalds	orl	#unfinx_mask,USER_FPSR(%a6)
5981da177e4SLinus Torvalds	bra	wr_etemp
5991da177e4SLinus Torvalds
6001da177e4SLinus Torvalds|
6011da177e4SLinus Torvalds| This code checks for 16-bit overflow conditions on dyadic
6021da177e4SLinus Torvalds| operations which are not restorable into the floating-point
6031da177e4SLinus Torvalds| unit and must be completed in software.  Basically, this
6041da177e4SLinus Torvalds| condition exists with a very large norm and a denorm.  One
6051da177e4SLinus Torvalds| of the operands must be denormalized to enter this code.
6061da177e4SLinus Torvalds|
6071da177e4SLinus Torvalds| Flags used:
6081da177e4SLinus Torvalds|	DY_MO_FLG contains 0 for monadic op, $ff for dyadic
6091da177e4SLinus Torvalds|	DNRM_FLG contains $00 for neither op denormalized
6101da177e4SLinus Torvalds|	                  $0f for the destination op denormalized
6111da177e4SLinus Torvalds|	                  $f0 for the source op denormalized
6121da177e4SLinus Torvalds|	                  $ff for both ops denormalized
6131da177e4SLinus Torvalds|
6141da177e4SLinus Torvalds| The wrap-around condition occurs for add, sub, div, and cmp
6151da177e4SLinus Torvalds| when
6161da177e4SLinus Torvalds|
6171da177e4SLinus Torvalds|	abs(dest_exp - src_exp) >= $8000
6181da177e4SLinus Torvalds|
6191da177e4SLinus Torvalds| and for mul when
6201da177e4SLinus Torvalds|
6211da177e4SLinus Torvalds|	(dest_exp + src_exp) < $0
6221da177e4SLinus Torvalds|
6231da177e4SLinus Torvalds| we must process the operation here if this case is true.
6241da177e4SLinus Torvalds|
6251da177e4SLinus Torvalds| The rts following the frcfpn routine is the exit from res_func
6261da177e4SLinus Torvalds| for this condition.  The restore flag (RES_FLG) is left clear.
6271da177e4SLinus Torvalds| No frestore is done unless an exception is to be reported.
6281da177e4SLinus Torvalds|
6291da177e4SLinus Torvalds| For fadd:
6301da177e4SLinus Torvalds|	if(sign_of(dest) != sign_of(src))
6311da177e4SLinus Torvalds|		replace exponent of src with $3fff (keep sign)
6321da177e4SLinus Torvalds|		use fpu to perform dest+new_src (user's rmode and X)
6331da177e4SLinus Torvalds|		clr sticky
6341da177e4SLinus Torvalds|	else
6351da177e4SLinus Torvalds|		set sticky
6361da177e4SLinus Torvalds|	call round with user's precision and mode
6371da177e4SLinus Torvalds|	move result to fpn and wbtemp
6381da177e4SLinus Torvalds|
6391da177e4SLinus Torvalds| For fsub:
6401da177e4SLinus Torvalds|	if(sign_of(dest) == sign_of(src))
6411da177e4SLinus Torvalds|		replace exponent of src with $3fff (keep sign)
6421da177e4SLinus Torvalds|		use fpu to perform dest+new_src (user's rmode and X)
6431da177e4SLinus Torvalds|		clr sticky
6441da177e4SLinus Torvalds|	else
6451da177e4SLinus Torvalds|		set sticky
6461da177e4SLinus Torvalds|	call round with user's precision and mode
6471da177e4SLinus Torvalds|	move result to fpn and wbtemp
6481da177e4SLinus Torvalds|
6491da177e4SLinus Torvalds| For fdiv/fsgldiv:
6501da177e4SLinus Torvalds|	if(both operands are denorm)
6511da177e4SLinus Torvalds|		restore_to_fpu;
6521da177e4SLinus Torvalds|	if(dest is norm)
6531da177e4SLinus Torvalds|		force_ovf;
6541da177e4SLinus Torvalds|	else(dest is denorm)
6551da177e4SLinus Torvalds|		force_unf:
6561da177e4SLinus Torvalds|
6571da177e4SLinus Torvalds| For fcmp:
6581da177e4SLinus Torvalds|	if(dest is norm)
6591da177e4SLinus Torvalds|		N = sign_of(dest);
6601da177e4SLinus Torvalds|	else(dest is denorm)
6611da177e4SLinus Torvalds|		N = sign_of(src);
6621da177e4SLinus Torvalds|
6631da177e4SLinus Torvalds| For fmul:
6641da177e4SLinus Torvalds|	if(both operands are denorm)
6651da177e4SLinus Torvalds|		force_unf;
6661da177e4SLinus Torvalds|	if((dest_exp + src_exp) < 0)
6671da177e4SLinus Torvalds|		force_unf:
6681da177e4SLinus Torvalds|	else
6691da177e4SLinus Torvalds|		restore_to_fpu;
6701da177e4SLinus Torvalds|
6711da177e4SLinus Torvalds| local equates:
6721da177e4SLinus Torvalds	.set	addcode,0x22
6731da177e4SLinus Torvalds	.set	subcode,0x28
6741da177e4SLinus Torvalds	.set	mulcode,0x23
6751da177e4SLinus Torvalds	.set	divcode,0x20
6761da177e4SLinus Torvalds	.set	cmpcode,0x38
6771da177e4SLinus Torvaldsck_wrap:
6781da177e4SLinus Torvalds	| tstb	DY_MO_FLG(%a6)	;check for fsqrt
6791da177e4SLinus Torvalds	beq	fix_stk		|if zero, it is fsqrt
6801da177e4SLinus Torvalds	movew	CMDREG1B(%a6),%d0
6811da177e4SLinus Torvalds	andiw	#0x3b,%d0		|strip to command bits
6821da177e4SLinus Torvalds	cmpiw	#addcode,%d0
6831da177e4SLinus Torvalds	beq	wrap_add
6841da177e4SLinus Torvalds	cmpiw	#subcode,%d0
6851da177e4SLinus Torvalds	beq	wrap_sub
6861da177e4SLinus Torvalds	cmpiw	#mulcode,%d0
6871da177e4SLinus Torvalds	beq	wrap_mul
6881da177e4SLinus Torvalds	cmpiw	#cmpcode,%d0
6891da177e4SLinus Torvalds	beq	wrap_cmp
6901da177e4SLinus Torvalds|
6911da177e4SLinus Torvalds| Inst is fdiv.
6921da177e4SLinus Torvalds|
6931da177e4SLinus Torvaldswrap_div:
6941da177e4SLinus Torvalds	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
6951da177e4SLinus Torvalds	beq	fix_stk		 |restore to fpu
6961da177e4SLinus Torvalds|
6971da177e4SLinus Torvalds| One of the ops is denormalized.  Test for wrap condition
6981da177e4SLinus Torvalds| and force the result.
6991da177e4SLinus Torvalds|
7001da177e4SLinus Torvalds	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
7011da177e4SLinus Torvalds	bnes	div_srcd
7021da177e4SLinus Torvaldsdiv_destd:
7031da177e4SLinus Torvalds	bsrl	ckinf_ns
7041da177e4SLinus Torvalds	bne	fix_stk
7051da177e4SLinus Torvalds	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
7061da177e4SLinus Torvalds	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
7071da177e4SLinus Torvalds	subl	%d1,%d0			|subtract dest from src
7081da177e4SLinus Torvalds	cmpl	#0x7fff,%d0
7091da177e4SLinus Torvalds	blt	fix_stk			|if less, not wrap case
7101da177e4SLinus Torvalds	clrb	WBTEMP_SGN(%a6)
7111da177e4SLinus Torvalds	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
7121da177e4SLinus Torvalds	movew	FPTEMP_EX(%a6),%d1
7131da177e4SLinus Torvalds	eorw	%d1,%d0
7141da177e4SLinus Torvalds	andiw	#0x8000,%d0
7151da177e4SLinus Torvalds	beq	force_unf
7161da177e4SLinus Torvalds	st	WBTEMP_SGN(%a6)
7171da177e4SLinus Torvalds	bra	force_unf
7181da177e4SLinus Torvalds
7191da177e4SLinus Torvaldsckinf_ns:
7201da177e4SLinus Torvalds	moveb	STAG(%a6),%d0		|check source tag for inf or nan
7211da177e4SLinus Torvalds	bra	ck_in_com
7221da177e4SLinus Torvaldsckinf_nd:
7231da177e4SLinus Torvalds	moveb	DTAG(%a6),%d0		|check destination tag for inf or nan
7241da177e4SLinus Torvaldsck_in_com:
7251da177e4SLinus Torvalds	andib	#0x60,%d0			|isolate tag bits
7261da177e4SLinus Torvalds	cmpb	#0x40,%d0			|is it inf?
7271da177e4SLinus Torvalds	beq	nan_or_inf		|not wrap case
7281da177e4SLinus Torvalds	cmpb	#0x60,%d0			|is it nan?
7291da177e4SLinus Torvalds	beq	nan_or_inf		|yes, not wrap case?
7301da177e4SLinus Torvalds	cmpb	#0x20,%d0			|is it a zero?
7311da177e4SLinus Torvalds	beq	nan_or_inf		|yes
7321da177e4SLinus Torvalds	clrl	%d0
7331da177e4SLinus Torvalds	rts				|then ; it is either a zero of norm,
7341da177e4SLinus Torvalds|					;check wrap case
7351da177e4SLinus Torvaldsnan_or_inf:
7361da177e4SLinus Torvalds	moveql	#-1,%d0
7371da177e4SLinus Torvalds	rts
7381da177e4SLinus Torvalds
7391da177e4SLinus Torvalds
7401da177e4SLinus Torvalds
7411da177e4SLinus Torvaldsdiv_srcd:
7421da177e4SLinus Torvalds	bsrl	ckinf_nd
7431da177e4SLinus Torvalds	bne	fix_stk
7441da177e4SLinus Torvalds	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
7451da177e4SLinus Torvalds	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
7461da177e4SLinus Torvalds	subl	%d1,%d0			|subtract src from dest
7471da177e4SLinus Torvalds	cmpl	#0x8000,%d0
7481da177e4SLinus Torvalds	blt	fix_stk			|if less, not wrap case
7491da177e4SLinus Torvalds	clrb	WBTEMP_SGN(%a6)
7501da177e4SLinus Torvalds	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
7511da177e4SLinus Torvalds	movew	FPTEMP_EX(%a6),%d1
7521da177e4SLinus Torvalds	eorw	%d1,%d0
7531da177e4SLinus Torvalds	andiw	#0x8000,%d0
7541da177e4SLinus Torvalds	beqs	force_ovf
7551da177e4SLinus Torvalds	st	WBTEMP_SGN(%a6)
7561da177e4SLinus Torvalds|
7571da177e4SLinus Torvalds| This code handles the case of the instruction resulting in
7581da177e4SLinus Torvalds| an overflow condition.
7591da177e4SLinus Torvalds|
7601da177e4SLinus Torvaldsforce_ovf:
7611da177e4SLinus Torvalds	bclrb	#E1,E_BYTE(%a6)
7621da177e4SLinus Torvalds	orl	#ovfl_inx_mask,USER_FPSR(%a6)
7631da177e4SLinus Torvalds	clrw	NMNEXC(%a6)
7641da177e4SLinus Torvalds	leal	WBTEMP(%a6),%a0		|point a0 to memory location
7651da177e4SLinus Torvalds	movew	CMDREG1B(%a6),%d0
7661da177e4SLinus Torvalds	btstl	#6,%d0			|test for forced precision
7671da177e4SLinus Torvalds	beqs	frcovf_fpcr
7681da177e4SLinus Torvalds	btstl	#2,%d0			|check for double
7691da177e4SLinus Torvalds	bnes	frcovf_dbl
7701da177e4SLinus Torvalds	movel	#0x1,%d0			|inst is forced single
7711da177e4SLinus Torvalds	bras	frcovf_rnd
7721da177e4SLinus Torvaldsfrcovf_dbl:
7731da177e4SLinus Torvalds	movel	#0x2,%d0			|inst is forced double
7741da177e4SLinus Torvalds	bras	frcovf_rnd
7751da177e4SLinus Torvaldsfrcovf_fpcr:
7761da177e4SLinus Torvalds	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
7771da177e4SLinus Torvaldsfrcovf_rnd:
7781da177e4SLinus Torvalds
7791da177e4SLinus Torvalds| The 881/882 does not set inex2 for the following case, so the
7801da177e4SLinus Torvalds| line is commented out to be compatible with 881/882
7811da177e4SLinus Torvalds|	tst.b	%d0
7821da177e4SLinus Torvalds|	beq.b	frcovf_x
7831da177e4SLinus Torvalds|	or.l	#inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
7841da177e4SLinus Torvalds
7851da177e4SLinus Torvalds|frcovf_x:
7861da177e4SLinus Torvalds	bsrl	ovf_res			|get correct result based on
7871da177e4SLinus Torvalds|					;round precision/mode.  This
7881da177e4SLinus Torvalds|					;sets FPSR_CC correctly
7891da177e4SLinus Torvalds|					;returns in external format
7901da177e4SLinus Torvalds	bfclr	WBTEMP_SGN(%a6){#0:#8}
7911da177e4SLinus Torvalds	beq	frcfpn
7921da177e4SLinus Torvalds	bsetb	#sign_bit,WBTEMP_EX(%a6)
7931da177e4SLinus Torvalds	bra	frcfpn
7941da177e4SLinus Torvalds|
7951da177e4SLinus Torvalds| Inst is fadd.
7961da177e4SLinus Torvalds|
7971da177e4SLinus Torvaldswrap_add:
7981da177e4SLinus Torvalds	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
7991da177e4SLinus Torvalds	beq	fix_stk		 |restore to fpu
8001da177e4SLinus Torvalds|
8011da177e4SLinus Torvalds| One of the ops is denormalized.  Test for wrap condition
8021da177e4SLinus Torvalds| and complete the instruction.
8031da177e4SLinus Torvalds|
8041da177e4SLinus Torvalds	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
8051da177e4SLinus Torvalds	bnes	add_srcd
8061da177e4SLinus Torvaldsadd_destd:
8071da177e4SLinus Torvalds	bsrl	ckinf_ns
8081da177e4SLinus Torvalds	bne	fix_stk
8091da177e4SLinus Torvalds	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
8101da177e4SLinus Torvalds	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
8111da177e4SLinus Torvalds	subl	%d1,%d0			|subtract dest from src
8121da177e4SLinus Torvalds	cmpl	#0x8000,%d0
8131da177e4SLinus Torvalds	blt	fix_stk			|if less, not wrap case
8141da177e4SLinus Torvalds	bra	add_wrap
8151da177e4SLinus Torvaldsadd_srcd:
8161da177e4SLinus Torvalds	bsrl	ckinf_nd
8171da177e4SLinus Torvalds	bne	fix_stk
8181da177e4SLinus Torvalds	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
8191da177e4SLinus Torvalds	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
8201da177e4SLinus Torvalds	subl	%d1,%d0			|subtract src from dest
8211da177e4SLinus Torvalds	cmpl	#0x8000,%d0
8221da177e4SLinus Torvalds	blt	fix_stk			|if less, not wrap case
8231da177e4SLinus Torvalds|
8241da177e4SLinus Torvalds| Check the signs of the operands.  If they are unlike, the fpu
8251da177e4SLinus Torvalds| can be used to add the norm and 1.0 with the sign of the
8261da177e4SLinus Torvalds| denorm and it will correctly generate the result in extended
8271da177e4SLinus Torvalds| precision.  We can then call round with no sticky and the result
8281da177e4SLinus Torvalds| will be correct for the user's rounding mode and precision.  If
8291da177e4SLinus Torvalds| the signs are the same, we call round with the sticky bit set
8301da177e4SLinus Torvalds| and the result will be correct for the user's rounding mode and
8311da177e4SLinus Torvalds| precision.
8321da177e4SLinus Torvalds|
8331da177e4SLinus Torvaldsadd_wrap:
8341da177e4SLinus Torvalds	movew	ETEMP_EX(%a6),%d0
8351da177e4SLinus Torvalds	movew	FPTEMP_EX(%a6),%d1
8361da177e4SLinus Torvalds	eorw	%d1,%d0
8371da177e4SLinus Torvalds	andiw	#0x8000,%d0
8381da177e4SLinus Torvalds	beq	add_same
8391da177e4SLinus Torvalds|
8401da177e4SLinus Torvalds| The signs are unlike.
8411da177e4SLinus Torvalds|
8421da177e4SLinus Torvalds	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
8431da177e4SLinus Torvalds	bnes	add_u_srcd
8441da177e4SLinus Torvalds	movew	FPTEMP_EX(%a6),%d0
8451da177e4SLinus Torvalds	andiw	#0x8000,%d0
8461da177e4SLinus Torvalds	orw	#0x3fff,%d0	|force the exponent to +/- 1
8471da177e4SLinus Torvalds	movew	%d0,FPTEMP_EX(%a6) |in the denorm
8481da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d0
8491da177e4SLinus Torvalds	andil	#0x30,%d0
8501da177e4SLinus Torvalds	fmovel	%d0,%fpcr		|set up users rmode and X
8511da177e4SLinus Torvalds	fmovex	ETEMP(%a6),%fp0
8521da177e4SLinus Torvalds	faddx	FPTEMP(%a6),%fp0
8531da177e4SLinus Torvalds	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
8541da177e4SLinus Torvalds	fmovel	%fpsr,%d1
8551da177e4SLinus Torvalds	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
8561da177e4SLinus Torvalds	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
8571da177e4SLinus Torvalds	lsrl	#4,%d0		|put rmode in lower 2 bits
8581da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d1
8591da177e4SLinus Torvalds	andil	#0xc0,%d1
8601da177e4SLinus Torvalds	lsrl	#6,%d1		|put precision in upper word
8611da177e4SLinus Torvalds	swap	%d1
8621da177e4SLinus Torvalds	orl	%d0,%d1		|set up for round call
8631da177e4SLinus Torvalds	clrl	%d0		|force sticky to zero
8641da177e4SLinus Torvalds	bclrb	#sign_bit,WBTEMP_EX(%a6)
8651da177e4SLinus Torvalds	sne	WBTEMP_SGN(%a6)
8661da177e4SLinus Torvalds	bsrl	round		|round result to users rmode & prec
8671da177e4SLinus Torvalds	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
8681da177e4SLinus Torvalds	beq	frcfpnr
8691da177e4SLinus Torvalds	bsetb	#sign_bit,WBTEMP_EX(%a6)
8701da177e4SLinus Torvalds	bra	frcfpnr
8711da177e4SLinus Torvaldsadd_u_srcd:
8721da177e4SLinus Torvalds	movew	ETEMP_EX(%a6),%d0
8731da177e4SLinus Torvalds	andiw	#0x8000,%d0
8741da177e4SLinus Torvalds	orw	#0x3fff,%d0	|force the exponent to +/- 1
8751da177e4SLinus Torvalds	movew	%d0,ETEMP_EX(%a6) |in the denorm
8761da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d0
8771da177e4SLinus Torvalds	andil	#0x30,%d0
8781da177e4SLinus Torvalds	fmovel	%d0,%fpcr		|set up users rmode and X
8791da177e4SLinus Torvalds	fmovex	ETEMP(%a6),%fp0
8801da177e4SLinus Torvalds	faddx	FPTEMP(%a6),%fp0
8811da177e4SLinus Torvalds	fmovel	%fpsr,%d1
8821da177e4SLinus Torvalds	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
8831da177e4SLinus Torvalds	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
8841da177e4SLinus Torvalds	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
8851da177e4SLinus Torvalds	lsrl	#4,%d0		|put rmode in lower 2 bits
8861da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d1
8871da177e4SLinus Torvalds	andil	#0xc0,%d1
8881da177e4SLinus Torvalds	lsrl	#6,%d1		|put precision in upper word
8891da177e4SLinus Torvalds	swap	%d1
8901da177e4SLinus Torvalds	orl	%d0,%d1		|set up for round call
8911da177e4SLinus Torvalds	clrl	%d0		|force sticky to zero
8921da177e4SLinus Torvalds	bclrb	#sign_bit,WBTEMP_EX(%a6)
8931da177e4SLinus Torvalds	sne	WBTEMP_SGN(%a6)	|use internal format for round
8941da177e4SLinus Torvalds	bsrl	round		|round result to users rmode & prec
8951da177e4SLinus Torvalds	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
8961da177e4SLinus Torvalds	beq	frcfpnr
8971da177e4SLinus Torvalds	bsetb	#sign_bit,WBTEMP_EX(%a6)
8981da177e4SLinus Torvalds	bra	frcfpnr
8991da177e4SLinus Torvalds|
9001da177e4SLinus Torvalds| Signs are alike:
9011da177e4SLinus Torvalds|
9021da177e4SLinus Torvaldsadd_same:
9031da177e4SLinus Torvalds	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
9041da177e4SLinus Torvalds	bnes	add_s_srcd
9051da177e4SLinus Torvaldsadd_s_destd:
9061da177e4SLinus Torvalds	leal	ETEMP(%a6),%a0
9071da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d0
9081da177e4SLinus Torvalds	andil	#0x30,%d0
9091da177e4SLinus Torvalds	lsrl	#4,%d0		|put rmode in lower 2 bits
9101da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d1
9111da177e4SLinus Torvalds	andil	#0xc0,%d1
9121da177e4SLinus Torvalds	lsrl	#6,%d1		|put precision in upper word
9131da177e4SLinus Torvalds	swap	%d1
9141da177e4SLinus Torvalds	orl	%d0,%d1		|set up for round call
9151da177e4SLinus Torvalds	movel	#0x20000000,%d0	|set sticky for round
9161da177e4SLinus Torvalds	bclrb	#sign_bit,ETEMP_EX(%a6)
9171da177e4SLinus Torvalds	sne	ETEMP_SGN(%a6)
9181da177e4SLinus Torvalds	bsrl	round		|round result to users rmode & prec
9191da177e4SLinus Torvalds	bfclr	ETEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
9201da177e4SLinus Torvalds	beqs	add_s_dclr
9211da177e4SLinus Torvalds	bsetb	#sign_bit,ETEMP_EX(%a6)
9221da177e4SLinus Torvaldsadd_s_dclr:
9231da177e4SLinus Torvalds	leal	WBTEMP(%a6),%a0
9241da177e4SLinus Torvalds	movel	ETEMP(%a6),(%a0)	|write result to wbtemp
9251da177e4SLinus Torvalds	movel	ETEMP_HI(%a6),4(%a0)
9261da177e4SLinus Torvalds	movel	ETEMP_LO(%a6),8(%a0)
9271da177e4SLinus Torvalds	tstw	ETEMP_EX(%a6)
9281da177e4SLinus Torvalds	bgt	add_ckovf
9291da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6)
9301da177e4SLinus Torvalds	bra	add_ckovf
9311da177e4SLinus Torvaldsadd_s_srcd:
9321da177e4SLinus Torvalds	leal	FPTEMP(%a6),%a0
9331da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d0
9341da177e4SLinus Torvalds	andil	#0x30,%d0
9351da177e4SLinus Torvalds	lsrl	#4,%d0		|put rmode in lower 2 bits
9361da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d1
9371da177e4SLinus Torvalds	andil	#0xc0,%d1
9381da177e4SLinus Torvalds	lsrl	#6,%d1		|put precision in upper word
9391da177e4SLinus Torvalds	swap	%d1
9401da177e4SLinus Torvalds	orl	%d0,%d1		|set up for round call
9411da177e4SLinus Torvalds	movel	#0x20000000,%d0	|set sticky for round
9421da177e4SLinus Torvalds	bclrb	#sign_bit,FPTEMP_EX(%a6)
9431da177e4SLinus Torvalds	sne	FPTEMP_SGN(%a6)
9441da177e4SLinus Torvalds	bsrl	round		|round result to users rmode & prec
9451da177e4SLinus Torvalds	bfclr	FPTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
9461da177e4SLinus Torvalds	beqs	add_s_sclr
9471da177e4SLinus Torvalds	bsetb	#sign_bit,FPTEMP_EX(%a6)
9481da177e4SLinus Torvaldsadd_s_sclr:
9491da177e4SLinus Torvalds	leal	WBTEMP(%a6),%a0
9501da177e4SLinus Torvalds	movel	FPTEMP(%a6),(%a0)	|write result to wbtemp
9511da177e4SLinus Torvalds	movel	FPTEMP_HI(%a6),4(%a0)
9521da177e4SLinus Torvalds	movel	FPTEMP_LO(%a6),8(%a0)
9531da177e4SLinus Torvalds	tstw	FPTEMP_EX(%a6)
9541da177e4SLinus Torvalds	bgt	add_ckovf
9551da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6)
9561da177e4SLinus Torvaldsadd_ckovf:
9571da177e4SLinus Torvalds	movew	WBTEMP_EX(%a6),%d0
9581da177e4SLinus Torvalds	andiw	#0x7fff,%d0
9591da177e4SLinus Torvalds	cmpiw	#0x7fff,%d0
9601da177e4SLinus Torvalds	bne	frcfpnr
9611da177e4SLinus Torvalds|
9621da177e4SLinus Torvalds| The result has overflowed to $7fff exponent.  Set I, ovfl,
9631da177e4SLinus Torvalds| and aovfl, and clr the mantissa (incorrectly set by the
9641da177e4SLinus Torvalds| round routine.)
9651da177e4SLinus Torvalds|
9661da177e4SLinus Torvalds	orl	#inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
9671da177e4SLinus Torvalds	clrl	4(%a0)
9681da177e4SLinus Torvalds	bra	frcfpnr
9691da177e4SLinus Torvalds|
9701da177e4SLinus Torvalds| Inst is fsub.
9711da177e4SLinus Torvalds|
9721da177e4SLinus Torvaldswrap_sub:
9731da177e4SLinus Torvalds	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
9741da177e4SLinus Torvalds	beq	fix_stk		 |restore to fpu
9751da177e4SLinus Torvalds|
9761da177e4SLinus Torvalds| One of the ops is denormalized.  Test for wrap condition
9771da177e4SLinus Torvalds| and complete the instruction.
9781da177e4SLinus Torvalds|
9791da177e4SLinus Torvalds	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
9801da177e4SLinus Torvalds	bnes	sub_srcd
9811da177e4SLinus Torvaldssub_destd:
9821da177e4SLinus Torvalds	bsrl	ckinf_ns
9831da177e4SLinus Torvalds	bne	fix_stk
9841da177e4SLinus Torvalds	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
9851da177e4SLinus Torvalds	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
9861da177e4SLinus Torvalds	subl	%d1,%d0			|subtract src from dest
9871da177e4SLinus Torvalds	cmpl	#0x8000,%d0
9881da177e4SLinus Torvalds	blt	fix_stk			|if less, not wrap case
9891da177e4SLinus Torvalds	bra	sub_wrap
9901da177e4SLinus Torvaldssub_srcd:
9911da177e4SLinus Torvalds	bsrl	ckinf_nd
9921da177e4SLinus Torvalds	bne	fix_stk
9931da177e4SLinus Torvalds	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
9941da177e4SLinus Torvalds	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
9951da177e4SLinus Torvalds	subl	%d1,%d0			|subtract dest from src
9961da177e4SLinus Torvalds	cmpl	#0x8000,%d0
9971da177e4SLinus Torvalds	blt	fix_stk			|if less, not wrap case
9981da177e4SLinus Torvalds|
9991da177e4SLinus Torvalds| Check the signs of the operands.  If they are alike, the fpu
10001da177e4SLinus Torvalds| can be used to subtract from the norm 1.0 with the sign of the
10011da177e4SLinus Torvalds| denorm and it will correctly generate the result in extended
10021da177e4SLinus Torvalds| precision.  We can then call round with no sticky and the result
10031da177e4SLinus Torvalds| will be correct for the user's rounding mode and precision.  If
10041da177e4SLinus Torvalds| the signs are unlike, we call round with the sticky bit set
10051da177e4SLinus Torvalds| and the result will be correct for the user's rounding mode and
10061da177e4SLinus Torvalds| precision.
10071da177e4SLinus Torvalds|
10081da177e4SLinus Torvaldssub_wrap:
10091da177e4SLinus Torvalds	movew	ETEMP_EX(%a6),%d0
10101da177e4SLinus Torvalds	movew	FPTEMP_EX(%a6),%d1
10111da177e4SLinus Torvalds	eorw	%d1,%d0
10121da177e4SLinus Torvalds	andiw	#0x8000,%d0
10131da177e4SLinus Torvalds	bne	sub_diff
10141da177e4SLinus Torvalds|
10151da177e4SLinus Torvalds| The signs are alike.
10161da177e4SLinus Torvalds|
10171da177e4SLinus Torvalds	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
10181da177e4SLinus Torvalds	bnes	sub_u_srcd
10191da177e4SLinus Torvalds	movew	FPTEMP_EX(%a6),%d0
10201da177e4SLinus Torvalds	andiw	#0x8000,%d0
10211da177e4SLinus Torvalds	orw	#0x3fff,%d0	|force the exponent to +/- 1
10221da177e4SLinus Torvalds	movew	%d0,FPTEMP_EX(%a6) |in the denorm
10231da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d0
10241da177e4SLinus Torvalds	andil	#0x30,%d0
10251da177e4SLinus Torvalds	fmovel	%d0,%fpcr		|set up users rmode and X
10261da177e4SLinus Torvalds	fmovex	FPTEMP(%a6),%fp0
10271da177e4SLinus Torvalds	fsubx	ETEMP(%a6),%fp0
10281da177e4SLinus Torvalds	fmovel	%fpsr,%d1
10291da177e4SLinus Torvalds	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
10301da177e4SLinus Torvalds	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
10311da177e4SLinus Torvalds	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
10321da177e4SLinus Torvalds	lsrl	#4,%d0		|put rmode in lower 2 bits
10331da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d1
10341da177e4SLinus Torvalds	andil	#0xc0,%d1
10351da177e4SLinus Torvalds	lsrl	#6,%d1		|put precision in upper word
10361da177e4SLinus Torvalds	swap	%d1
10371da177e4SLinus Torvalds	orl	%d0,%d1		|set up for round call
10381da177e4SLinus Torvalds	clrl	%d0		|force sticky to zero
10391da177e4SLinus Torvalds	bclrb	#sign_bit,WBTEMP_EX(%a6)
10401da177e4SLinus Torvalds	sne	WBTEMP_SGN(%a6)
10411da177e4SLinus Torvalds	bsrl	round		|round result to users rmode & prec
10421da177e4SLinus Torvalds	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
10431da177e4SLinus Torvalds	beq	frcfpnr
10441da177e4SLinus Torvalds	bsetb	#sign_bit,WBTEMP_EX(%a6)
10451da177e4SLinus Torvalds	bra	frcfpnr
10461da177e4SLinus Torvaldssub_u_srcd:
10471da177e4SLinus Torvalds	movew	ETEMP_EX(%a6),%d0
10481da177e4SLinus Torvalds	andiw	#0x8000,%d0
10491da177e4SLinus Torvalds	orw	#0x3fff,%d0	|force the exponent to +/- 1
10501da177e4SLinus Torvalds	movew	%d0,ETEMP_EX(%a6) |in the denorm
10511da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d0
10521da177e4SLinus Torvalds	andil	#0x30,%d0
10531da177e4SLinus Torvalds	fmovel	%d0,%fpcr		|set up users rmode and X
10541da177e4SLinus Torvalds	fmovex	FPTEMP(%a6),%fp0
10551da177e4SLinus Torvalds	fsubx	ETEMP(%a6),%fp0
10561da177e4SLinus Torvalds	fmovel	%fpsr,%d1
10571da177e4SLinus Torvalds	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
10581da177e4SLinus Torvalds	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
10591da177e4SLinus Torvalds	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
10601da177e4SLinus Torvalds	lsrl	#4,%d0		|put rmode in lower 2 bits
10611da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d1
10621da177e4SLinus Torvalds	andil	#0xc0,%d1
10631da177e4SLinus Torvalds	lsrl	#6,%d1		|put precision in upper word
10641da177e4SLinus Torvalds	swap	%d1
10651da177e4SLinus Torvalds	orl	%d0,%d1		|set up for round call
10661da177e4SLinus Torvalds	clrl	%d0		|force sticky to zero
10671da177e4SLinus Torvalds	bclrb	#sign_bit,WBTEMP_EX(%a6)
10681da177e4SLinus Torvalds	sne	WBTEMP_SGN(%a6)
10691da177e4SLinus Torvalds	bsrl	round		|round result to users rmode & prec
10701da177e4SLinus Torvalds	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
10711da177e4SLinus Torvalds	beq	frcfpnr
10721da177e4SLinus Torvalds	bsetb	#sign_bit,WBTEMP_EX(%a6)
10731da177e4SLinus Torvalds	bra	frcfpnr
10741da177e4SLinus Torvalds|
10751da177e4SLinus Torvalds| Signs are unlike:
10761da177e4SLinus Torvalds|
10771da177e4SLinus Torvaldssub_diff:
10781da177e4SLinus Torvalds	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
10791da177e4SLinus Torvalds	bnes	sub_s_srcd
10801da177e4SLinus Torvaldssub_s_destd:
10811da177e4SLinus Torvalds	leal	ETEMP(%a6),%a0
10821da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d0
10831da177e4SLinus Torvalds	andil	#0x30,%d0
10841da177e4SLinus Torvalds	lsrl	#4,%d0		|put rmode in lower 2 bits
10851da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d1
10861da177e4SLinus Torvalds	andil	#0xc0,%d1
10871da177e4SLinus Torvalds	lsrl	#6,%d1		|put precision in upper word
10881da177e4SLinus Torvalds	swap	%d1
10891da177e4SLinus Torvalds	orl	%d0,%d1		|set up for round call
10901da177e4SLinus Torvalds	movel	#0x20000000,%d0	|set sticky for round
10911da177e4SLinus Torvalds|
10921da177e4SLinus Torvalds| Since the dest is the denorm, the sign is the opposite of the
10931da177e4SLinus Torvalds| norm sign.
10941da177e4SLinus Torvalds|
10951da177e4SLinus Torvalds	eoriw	#0x8000,ETEMP_EX(%a6)	|flip sign on result
10961da177e4SLinus Torvalds	tstw	ETEMP_EX(%a6)
10971da177e4SLinus Torvalds	bgts	sub_s_dwr
10981da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6)
10991da177e4SLinus Torvaldssub_s_dwr:
11001da177e4SLinus Torvalds	bclrb	#sign_bit,ETEMP_EX(%a6)
11011da177e4SLinus Torvalds	sne	ETEMP_SGN(%a6)
11021da177e4SLinus Torvalds	bsrl	round		|round result to users rmode & prec
11031da177e4SLinus Torvalds	bfclr	ETEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
11041da177e4SLinus Torvalds	beqs	sub_s_dclr
11051da177e4SLinus Torvalds	bsetb	#sign_bit,ETEMP_EX(%a6)
11061da177e4SLinus Torvaldssub_s_dclr:
11071da177e4SLinus Torvalds	leal	WBTEMP(%a6),%a0
11081da177e4SLinus Torvalds	movel	ETEMP(%a6),(%a0)	|write result to wbtemp
11091da177e4SLinus Torvalds	movel	ETEMP_HI(%a6),4(%a0)
11101da177e4SLinus Torvalds	movel	ETEMP_LO(%a6),8(%a0)
11111da177e4SLinus Torvalds	bra	sub_ckovf
11121da177e4SLinus Torvaldssub_s_srcd:
11131da177e4SLinus Torvalds	leal	FPTEMP(%a6),%a0
11141da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d0
11151da177e4SLinus Torvalds	andil	#0x30,%d0
11161da177e4SLinus Torvalds	lsrl	#4,%d0		|put rmode in lower 2 bits
11171da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d1
11181da177e4SLinus Torvalds	andil	#0xc0,%d1
11191da177e4SLinus Torvalds	lsrl	#6,%d1		|put precision in upper word
11201da177e4SLinus Torvalds	swap	%d1
11211da177e4SLinus Torvalds	orl	%d0,%d1		|set up for round call
11221da177e4SLinus Torvalds	movel	#0x20000000,%d0	|set sticky for round
11231da177e4SLinus Torvalds	bclrb	#sign_bit,FPTEMP_EX(%a6)
11241da177e4SLinus Torvalds	sne	FPTEMP_SGN(%a6)
11251da177e4SLinus Torvalds	bsrl	round		|round result to users rmode & prec
11261da177e4SLinus Torvalds	bfclr	FPTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
11271da177e4SLinus Torvalds	beqs	sub_s_sclr
11281da177e4SLinus Torvalds	bsetb	#sign_bit,FPTEMP_EX(%a6)
11291da177e4SLinus Torvaldssub_s_sclr:
11301da177e4SLinus Torvalds	leal	WBTEMP(%a6),%a0
11311da177e4SLinus Torvalds	movel	FPTEMP(%a6),(%a0)	|write result to wbtemp
11321da177e4SLinus Torvalds	movel	FPTEMP_HI(%a6),4(%a0)
11331da177e4SLinus Torvalds	movel	FPTEMP_LO(%a6),8(%a0)
11341da177e4SLinus Torvalds	tstw	FPTEMP_EX(%a6)
11351da177e4SLinus Torvalds	bgt	sub_ckovf
11361da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6)
11371da177e4SLinus Torvaldssub_ckovf:
11381da177e4SLinus Torvalds	movew	WBTEMP_EX(%a6),%d0
11391da177e4SLinus Torvalds	andiw	#0x7fff,%d0
11401da177e4SLinus Torvalds	cmpiw	#0x7fff,%d0
11411da177e4SLinus Torvalds	bne	frcfpnr
11421da177e4SLinus Torvalds|
11431da177e4SLinus Torvalds| The result has overflowed to $7fff exponent.  Set I, ovfl,
11441da177e4SLinus Torvalds| and aovfl, and clr the mantissa (incorrectly set by the
11451da177e4SLinus Torvalds| round routine.)
11461da177e4SLinus Torvalds|
11471da177e4SLinus Torvalds	orl	#inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
11481da177e4SLinus Torvalds	clrl	4(%a0)
11491da177e4SLinus Torvalds	bra	frcfpnr
11501da177e4SLinus Torvalds|
11511da177e4SLinus Torvalds| Inst is fcmp.
11521da177e4SLinus Torvalds|
11531da177e4SLinus Torvaldswrap_cmp:
11541da177e4SLinus Torvalds	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
11551da177e4SLinus Torvalds	beq	fix_stk		 |restore to fpu
11561da177e4SLinus Torvalds|
11571da177e4SLinus Torvalds| One of the ops is denormalized.  Test for wrap condition
11581da177e4SLinus Torvalds| and complete the instruction.
11591da177e4SLinus Torvalds|
11601da177e4SLinus Torvalds	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
11611da177e4SLinus Torvalds	bnes	cmp_srcd
11621da177e4SLinus Torvaldscmp_destd:
11631da177e4SLinus Torvalds	bsrl	ckinf_ns
11641da177e4SLinus Torvalds	bne	fix_stk
11651da177e4SLinus Torvalds	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
11661da177e4SLinus Torvalds	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
11671da177e4SLinus Torvalds	subl	%d1,%d0			|subtract dest from src
11681da177e4SLinus Torvalds	cmpl	#0x8000,%d0
11691da177e4SLinus Torvalds	blt	fix_stk			|if less, not wrap case
11701da177e4SLinus Torvalds	tstw	ETEMP_EX(%a6)		|set N to ~sign_of(src)
11711da177e4SLinus Torvalds	bge	cmp_setn
11721da177e4SLinus Torvalds	rts
11731da177e4SLinus Torvaldscmp_srcd:
11741da177e4SLinus Torvalds	bsrl	ckinf_nd
11751da177e4SLinus Torvalds	bne	fix_stk
11761da177e4SLinus Torvalds	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
11771da177e4SLinus Torvalds	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
11781da177e4SLinus Torvalds	subl	%d1,%d0			|subtract src from dest
11791da177e4SLinus Torvalds	cmpl	#0x8000,%d0
11801da177e4SLinus Torvalds	blt	fix_stk			|if less, not wrap case
11811da177e4SLinus Torvalds	tstw	FPTEMP_EX(%a6)		|set N to sign_of(dest)
11821da177e4SLinus Torvalds	blt	cmp_setn
11831da177e4SLinus Torvalds	rts
11841da177e4SLinus Torvaldscmp_setn:
11851da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6)
11861da177e4SLinus Torvalds	rts
11871da177e4SLinus Torvalds
11881da177e4SLinus Torvalds|
11891da177e4SLinus Torvalds| Inst is fmul.
11901da177e4SLinus Torvalds|
11911da177e4SLinus Torvaldswrap_mul:
11921da177e4SLinus Torvalds	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
11931da177e4SLinus Torvalds	beq	force_unf	|force an underflow (really!)
11941da177e4SLinus Torvalds|
11951da177e4SLinus Torvalds| One of the ops is denormalized.  Test for wrap condition
11961da177e4SLinus Torvalds| and complete the instruction.
11971da177e4SLinus Torvalds|
11981da177e4SLinus Torvalds	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
11991da177e4SLinus Torvalds	bnes	mul_srcd
12001da177e4SLinus Torvaldsmul_destd:
12011da177e4SLinus Torvalds	bsrl	ckinf_ns
12021da177e4SLinus Torvalds	bne	fix_stk
12031da177e4SLinus Torvalds	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
12041da177e4SLinus Torvalds	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
12051da177e4SLinus Torvalds	addl	%d1,%d0			|subtract dest from src
12061da177e4SLinus Torvalds	bgt	fix_stk
12071da177e4SLinus Torvalds	bra	force_unf
12081da177e4SLinus Torvaldsmul_srcd:
12091da177e4SLinus Torvalds	bsrl	ckinf_nd
12101da177e4SLinus Torvalds	bne	fix_stk
12111da177e4SLinus Torvalds	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
12121da177e4SLinus Torvalds	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
12131da177e4SLinus Torvalds	addl	%d1,%d0			|subtract src from dest
12141da177e4SLinus Torvalds	bgt	fix_stk
12151da177e4SLinus Torvalds
12161da177e4SLinus Torvalds|
12171da177e4SLinus Torvalds| This code handles the case of the instruction resulting in
12181da177e4SLinus Torvalds| an underflow condition.
12191da177e4SLinus Torvalds|
12201da177e4SLinus Torvaldsforce_unf:
12211da177e4SLinus Torvalds	bclrb	#E1,E_BYTE(%a6)
12221da177e4SLinus Torvalds	orl	#unfinx_mask,USER_FPSR(%a6)
12231da177e4SLinus Torvalds	clrw	NMNEXC(%a6)
12241da177e4SLinus Torvalds	clrb	WBTEMP_SGN(%a6)
12251da177e4SLinus Torvalds	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
12261da177e4SLinus Torvalds	movew	FPTEMP_EX(%a6),%d1
12271da177e4SLinus Torvalds	eorw	%d1,%d0
12281da177e4SLinus Torvalds	andiw	#0x8000,%d0
12291da177e4SLinus Torvalds	beqs	frcunfcont
12301da177e4SLinus Torvalds	st	WBTEMP_SGN(%a6)
12311da177e4SLinus Torvaldsfrcunfcont:
12321da177e4SLinus Torvalds	lea	WBTEMP(%a6),%a0		|point a0 to memory location
12331da177e4SLinus Torvalds	movew	CMDREG1B(%a6),%d0
12341da177e4SLinus Torvalds	btstl	#6,%d0			|test for forced precision
12351da177e4SLinus Torvalds	beqs	frcunf_fpcr
12361da177e4SLinus Torvalds	btstl	#2,%d0			|check for double
12371da177e4SLinus Torvalds	bnes	frcunf_dbl
12381da177e4SLinus Torvalds	movel	#0x1,%d0			|inst is forced single
12391da177e4SLinus Torvalds	bras	frcunf_rnd
12401da177e4SLinus Torvaldsfrcunf_dbl:
12411da177e4SLinus Torvalds	movel	#0x2,%d0			|inst is forced double
12421da177e4SLinus Torvalds	bras	frcunf_rnd
12431da177e4SLinus Torvaldsfrcunf_fpcr:
12441da177e4SLinus Torvalds	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
12451da177e4SLinus Torvaldsfrcunf_rnd:
12461da177e4SLinus Torvalds	bsrl	unf_sub			|get correct result based on
12471da177e4SLinus Torvalds|					;round precision/mode.  This
12481da177e4SLinus Torvalds|					;sets FPSR_CC correctly
12491da177e4SLinus Torvalds	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
12501da177e4SLinus Torvalds	beqs	frcfpn
12511da177e4SLinus Torvalds	bsetb	#sign_bit,WBTEMP_EX(%a6)
12521da177e4SLinus Torvalds	bra	frcfpn
12531da177e4SLinus Torvalds
12541da177e4SLinus Torvalds|
12551da177e4SLinus Torvalds| Write the result to the user's fpn.  All results must be HUGE to be
12561da177e4SLinus Torvalds| written; otherwise the results would have overflowed or underflowed.
12571da177e4SLinus Torvalds| If the rounding precision is single or double, the ovf_res routine
12581da177e4SLinus Torvalds| is needed to correctly supply the max value.
12591da177e4SLinus Torvalds|
12601da177e4SLinus Torvaldsfrcfpnr:
12611da177e4SLinus Torvalds	movew	CMDREG1B(%a6),%d0
12621da177e4SLinus Torvalds	btstl	#6,%d0			|test for forced precision
12631da177e4SLinus Torvalds	beqs	frcfpn_fpcr
12641da177e4SLinus Torvalds	btstl	#2,%d0			|check for double
12651da177e4SLinus Torvalds	bnes	frcfpn_dbl
12661da177e4SLinus Torvalds	movel	#0x1,%d0			|inst is forced single
12671da177e4SLinus Torvalds	bras	frcfpn_rnd
12681da177e4SLinus Torvaldsfrcfpn_dbl:
12691da177e4SLinus Torvalds	movel	#0x2,%d0			|inst is forced double
12701da177e4SLinus Torvalds	bras	frcfpn_rnd
12711da177e4SLinus Torvaldsfrcfpn_fpcr:
12721da177e4SLinus Torvalds	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
12731da177e4SLinus Torvalds	tstb	%d0
12741da177e4SLinus Torvalds	beqs	frcfpn			|if extended, write what you got
12751da177e4SLinus Torvaldsfrcfpn_rnd:
12761da177e4SLinus Torvalds	bclrb	#sign_bit,WBTEMP_EX(%a6)
12771da177e4SLinus Torvalds	sne	WBTEMP_SGN(%a6)
12781da177e4SLinus Torvalds	bsrl	ovf_res			|get correct result based on
12791da177e4SLinus Torvalds|					;round precision/mode.  This
12801da177e4SLinus Torvalds|					;sets FPSR_CC correctly
12811da177e4SLinus Torvalds	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
12821da177e4SLinus Torvalds	beqs	frcfpn_clr
12831da177e4SLinus Torvalds	bsetb	#sign_bit,WBTEMP_EX(%a6)
12841da177e4SLinus Torvaldsfrcfpn_clr:
12851da177e4SLinus Torvalds	orl	#ovfinx_mask,USER_FPSR(%a6)
12861da177e4SLinus Torvalds|
12871da177e4SLinus Torvalds| Perform the write.
12881da177e4SLinus Torvalds|
12891da177e4SLinus Torvaldsfrcfpn:
12901da177e4SLinus Torvalds	bfextu	CMDREG1B(%a6){#6:#3},%d0	|extract fp destination register
12911da177e4SLinus Torvalds	cmpib	#3,%d0
12921da177e4SLinus Torvalds	bles	frc0123			|check if dest is fp0-fp3
12931da177e4SLinus Torvalds	movel	#7,%d1
12941da177e4SLinus Torvalds	subl	%d0,%d1
12951da177e4SLinus Torvalds	clrl	%d0
12961da177e4SLinus Torvalds	bsetl	%d1,%d0
12971da177e4SLinus Torvalds	fmovemx WBTEMP(%a6),%d0
12981da177e4SLinus Torvalds	rts
12991da177e4SLinus Torvaldsfrc0123:
13001da177e4SLinus Torvalds	cmpib	#0,%d0
13011da177e4SLinus Torvalds	beqs	frc0_dst
13021da177e4SLinus Torvalds	cmpib	#1,%d0
13031da177e4SLinus Torvalds	beqs	frc1_dst
13041da177e4SLinus Torvalds	cmpib	#2,%d0
13051da177e4SLinus Torvalds	beqs	frc2_dst
13061da177e4SLinus Torvaldsfrc3_dst:
13071da177e4SLinus Torvalds	movel	WBTEMP_EX(%a6),USER_FP3(%a6)
13081da177e4SLinus Torvalds	movel	WBTEMP_HI(%a6),USER_FP3+4(%a6)
13091da177e4SLinus Torvalds	movel	WBTEMP_LO(%a6),USER_FP3+8(%a6)
13101da177e4SLinus Torvalds	rts
13111da177e4SLinus Torvaldsfrc2_dst:
13121da177e4SLinus Torvalds	movel	WBTEMP_EX(%a6),USER_FP2(%a6)
13131da177e4SLinus Torvalds	movel	WBTEMP_HI(%a6),USER_FP2+4(%a6)
13141da177e4SLinus Torvalds	movel	WBTEMP_LO(%a6),USER_FP2+8(%a6)
13151da177e4SLinus Torvalds	rts
13161da177e4SLinus Torvaldsfrc1_dst:
13171da177e4SLinus Torvalds	movel	WBTEMP_EX(%a6),USER_FP1(%a6)
13181da177e4SLinus Torvalds	movel	WBTEMP_HI(%a6),USER_FP1+4(%a6)
13191da177e4SLinus Torvalds	movel	WBTEMP_LO(%a6),USER_FP1+8(%a6)
13201da177e4SLinus Torvalds	rts
13211da177e4SLinus Torvaldsfrc0_dst:
13221da177e4SLinus Torvalds	movel	WBTEMP_EX(%a6),USER_FP0(%a6)
13231da177e4SLinus Torvalds	movel	WBTEMP_HI(%a6),USER_FP0+4(%a6)
13241da177e4SLinus Torvalds	movel	WBTEMP_LO(%a6),USER_FP0+8(%a6)
13251da177e4SLinus Torvalds	rts
13261da177e4SLinus Torvalds
13271da177e4SLinus Torvalds|
13281da177e4SLinus Torvalds| Write etemp to fpn.
13291da177e4SLinus Torvalds| A check is made on enabled and signalled snan exceptions,
13301da177e4SLinus Torvalds| and the destination is not overwritten if this condition exists.
13311da177e4SLinus Torvalds| This code is designed to make fmoveins of unsupported data types
13321da177e4SLinus Torvalds| faster.
13331da177e4SLinus Torvalds|
13341da177e4SLinus Torvaldswr_etemp:
13351da177e4SLinus Torvalds	btstb	#snan_bit,FPSR_EXCEPT(%a6)	|if snan is set, and
13361da177e4SLinus Torvalds	beqs	fmoveinc		|enabled, force restore
13371da177e4SLinus Torvalds	btstb	#snan_bit,FPCR_ENABLE(%a6) |and don't overwrite
13381da177e4SLinus Torvalds	beqs	fmoveinc		|the dest
13391da177e4SLinus Torvalds	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
13401da177e4SLinus Torvalds|						;snan handler
13411da177e4SLinus Torvalds	tstb	ETEMP(%a6)		|check for negative
13421da177e4SLinus Torvalds	blts	snan_neg
13431da177e4SLinus Torvalds	rts
13441da177e4SLinus Torvaldssnan_neg:
13451da177e4SLinus Torvalds	orl	#neg_bit,USER_FPSR(%a6)	|snan is negative; set N
13461da177e4SLinus Torvalds	rts
13471da177e4SLinus Torvaldsfmoveinc:
13481da177e4SLinus Torvalds	clrw	NMNEXC(%a6)
13491da177e4SLinus Torvalds	bclrb	#E1,E_BYTE(%a6)
13501da177e4SLinus Torvalds	moveb	STAG(%a6),%d0		|check if stag is inf
13511da177e4SLinus Torvalds	andib	#0xe0,%d0
13521da177e4SLinus Torvalds	cmpib	#0x40,%d0
13531da177e4SLinus Torvalds	bnes	fminc_cnan
13541da177e4SLinus Torvalds	orl	#inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I
13551da177e4SLinus Torvalds	tstw	LOCAL_EX(%a0)		|check sign
13561da177e4SLinus Torvalds	bges	fminc_con
13571da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6)
13581da177e4SLinus Torvalds	bra	fminc_con
13591da177e4SLinus Torvaldsfminc_cnan:
13601da177e4SLinus Torvalds	cmpib	#0x60,%d0			|check if stag is NaN
13611da177e4SLinus Torvalds	bnes	fminc_czero
13621da177e4SLinus Torvalds	orl	#nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaN
13631da177e4SLinus Torvalds	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
13641da177e4SLinus Torvalds|						;snan handler
13651da177e4SLinus Torvalds	tstw	LOCAL_EX(%a0)		|check sign
13661da177e4SLinus Torvalds	bges	fminc_con
13671da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6)
13681da177e4SLinus Torvalds	bra	fminc_con
13691da177e4SLinus Torvaldsfminc_czero:
13701da177e4SLinus Torvalds	cmpib	#0x20,%d0			|check if zero
13711da177e4SLinus Torvalds	bnes	fminc_con
13721da177e4SLinus Torvalds	orl	#z_mask,USER_FPSR(%a6)	|if zero, set Z
13731da177e4SLinus Torvalds	tstw	LOCAL_EX(%a0)		|check sign
13741da177e4SLinus Torvalds	bges	fminc_con
13751da177e4SLinus Torvalds	orl	#neg_mask,USER_FPSR(%a6)
13761da177e4SLinus Torvaldsfminc_con:
13771da177e4SLinus Torvalds	bfextu	CMDREG1B(%a6){#6:#3},%d0	|extract fp destination register
13781da177e4SLinus Torvalds	cmpib	#3,%d0
13791da177e4SLinus Torvalds	bles	fp0123			|check if dest is fp0-fp3
13801da177e4SLinus Torvalds	movel	#7,%d1
13811da177e4SLinus Torvalds	subl	%d0,%d1
13821da177e4SLinus Torvalds	clrl	%d0
13831da177e4SLinus Torvalds	bsetl	%d1,%d0
13841da177e4SLinus Torvalds	fmovemx ETEMP(%a6),%d0
13851da177e4SLinus Torvalds	rts
13861da177e4SLinus Torvalds
13871da177e4SLinus Torvaldsfp0123:
13881da177e4SLinus Torvalds	cmpib	#0,%d0
13891da177e4SLinus Torvalds	beqs	fp0_dst
13901da177e4SLinus Torvalds	cmpib	#1,%d0
13911da177e4SLinus Torvalds	beqs	fp1_dst
13921da177e4SLinus Torvalds	cmpib	#2,%d0
13931da177e4SLinus Torvalds	beqs	fp2_dst
13941da177e4SLinus Torvaldsfp3_dst:
13951da177e4SLinus Torvalds	movel	ETEMP_EX(%a6),USER_FP3(%a6)
13961da177e4SLinus Torvalds	movel	ETEMP_HI(%a6),USER_FP3+4(%a6)
13971da177e4SLinus Torvalds	movel	ETEMP_LO(%a6),USER_FP3+8(%a6)
13981da177e4SLinus Torvalds	rts
13991da177e4SLinus Torvaldsfp2_dst:
14001da177e4SLinus Torvalds	movel	ETEMP_EX(%a6),USER_FP2(%a6)
14011da177e4SLinus Torvalds	movel	ETEMP_HI(%a6),USER_FP2+4(%a6)
14021da177e4SLinus Torvalds	movel	ETEMP_LO(%a6),USER_FP2+8(%a6)
14031da177e4SLinus Torvalds	rts
14041da177e4SLinus Torvaldsfp1_dst:
14051da177e4SLinus Torvalds	movel	ETEMP_EX(%a6),USER_FP1(%a6)
14061da177e4SLinus Torvalds	movel	ETEMP_HI(%a6),USER_FP1+4(%a6)
14071da177e4SLinus Torvalds	movel	ETEMP_LO(%a6),USER_FP1+8(%a6)
14081da177e4SLinus Torvalds	rts
14091da177e4SLinus Torvaldsfp0_dst:
14101da177e4SLinus Torvalds	movel	ETEMP_EX(%a6),USER_FP0(%a6)
14111da177e4SLinus Torvalds	movel	ETEMP_HI(%a6),USER_FP0+4(%a6)
14121da177e4SLinus Torvalds	movel	ETEMP_LO(%a6),USER_FP0+8(%a6)
14131da177e4SLinus Torvalds	rts
14141da177e4SLinus Torvalds
14151da177e4SLinus Torvaldsopclass3:
14161da177e4SLinus Torvalds	st	CU_ONLY(%a6)
14171da177e4SLinus Torvalds	movew	CMDREG1B(%a6),%d0	|check if packed moveout
14181da177e4SLinus Torvalds	andiw	#0x0c00,%d0	|isolate last 2 bits of size field
14191da177e4SLinus Torvalds	cmpiw	#0x0c00,%d0	|if size is 011 or 111, it is packed
14201da177e4SLinus Torvalds	beq	pack_out	|else it is norm or denorm
14211da177e4SLinus Torvalds	bra	mv_out
14221da177e4SLinus Torvalds
14231da177e4SLinus Torvalds
14241da177e4SLinus Torvalds|
14251da177e4SLinus Torvalds|	MOVE OUT
14261da177e4SLinus Torvalds|
14271da177e4SLinus Torvalds
14281da177e4SLinus Torvaldsmv_tbl:
14291da177e4SLinus Torvalds	.long	li
14301da177e4SLinus Torvalds	.long	sgp
14311da177e4SLinus Torvalds	.long	xp
14321da177e4SLinus Torvalds	.long	mvout_end	|should never be taken
14331da177e4SLinus Torvalds	.long	wi
14341da177e4SLinus Torvalds	.long	dp
14351da177e4SLinus Torvalds	.long	bi
14361da177e4SLinus Torvalds	.long	mvout_end	|should never be taken
14371da177e4SLinus Torvaldsmv_out:
14381da177e4SLinus Torvalds	bfextu	CMDREG1B(%a6){#3:#3},%d1	|put source specifier in d1
14391da177e4SLinus Torvalds	leal	mv_tbl,%a0
14401da177e4SLinus Torvalds	movel	%a0@(%d1:l:4),%a0
14411da177e4SLinus Torvalds	jmp	(%a0)
14421da177e4SLinus Torvalds
14431da177e4SLinus Torvalds|
14441da177e4SLinus Torvalds| This exit is for move-out to memory.  The aunfl bit is
14451da177e4SLinus Torvalds| set if the result is inex and unfl is signalled.
14461da177e4SLinus Torvalds|
14471da177e4SLinus Torvaldsmvout_end:
14481da177e4SLinus Torvalds	btstb	#inex2_bit,FPSR_EXCEPT(%a6)
14491da177e4SLinus Torvalds	beqs	no_aufl
14501da177e4SLinus Torvalds	btstb	#unfl_bit,FPSR_EXCEPT(%a6)
14511da177e4SLinus Torvalds	beqs	no_aufl
14521da177e4SLinus Torvalds	bsetb	#aunfl_bit,FPSR_AEXCEPT(%a6)
14531da177e4SLinus Torvaldsno_aufl:
14541da177e4SLinus Torvalds	clrw	NMNEXC(%a6)
14551da177e4SLinus Torvalds	bclrb	#E1,E_BYTE(%a6)
14561da177e4SLinus Torvalds	fmovel	#0,%FPSR			|clear any cc bits from res_func
14571da177e4SLinus Torvalds|
14581da177e4SLinus Torvalds| Return ETEMP to extended format from internal extended format so
14591da177e4SLinus Torvalds| that gen_except will have a correctly signed value for ovfl/unfl
14601da177e4SLinus Torvalds| handlers.
14611da177e4SLinus Torvalds|
14621da177e4SLinus Torvalds	bfclr	ETEMP_SGN(%a6){#0:#8}
14631da177e4SLinus Torvalds	beqs	mvout_con
14641da177e4SLinus Torvalds	bsetb	#sign_bit,ETEMP_EX(%a6)
14651da177e4SLinus Torvaldsmvout_con:
14661da177e4SLinus Torvalds	rts
14671da177e4SLinus Torvalds|
14681da177e4SLinus Torvalds| This exit is for move-out to int register.  The aunfl bit is
14691da177e4SLinus Torvalds| not set in any case for this move.
14701da177e4SLinus Torvalds|
14711da177e4SLinus Torvaldsmvouti_end:
14721da177e4SLinus Torvalds	clrw	NMNEXC(%a6)
14731da177e4SLinus Torvalds	bclrb	#E1,E_BYTE(%a6)
14741da177e4SLinus Torvalds	fmovel	#0,%FPSR			|clear any cc bits from res_func
14751da177e4SLinus Torvalds|
14761da177e4SLinus Torvalds| Return ETEMP to extended format from internal extended format so
14771da177e4SLinus Torvalds| that gen_except will have a correctly signed value for ovfl/unfl
14781da177e4SLinus Torvalds| handlers.
14791da177e4SLinus Torvalds|
14801da177e4SLinus Torvalds	bfclr	ETEMP_SGN(%a6){#0:#8}
14811da177e4SLinus Torvalds	beqs	mvouti_con
14821da177e4SLinus Torvalds	bsetb	#sign_bit,ETEMP_EX(%a6)
14831da177e4SLinus Torvaldsmvouti_con:
14841da177e4SLinus Torvalds	rts
14851da177e4SLinus Torvalds|
14861da177e4SLinus Torvalds| li is used to handle a long integer source specifier
14871da177e4SLinus Torvalds|
14881da177e4SLinus Torvalds
14891da177e4SLinus Torvaldsli:
14901da177e4SLinus Torvalds	moveql	#4,%d0		|set byte count
14911da177e4SLinus Torvalds
14921da177e4SLinus Torvalds	btstb	#7,STAG(%a6)	|check for extended denorm
14931da177e4SLinus Torvalds	bne	int_dnrm	|if so, branch
14941da177e4SLinus Torvalds
14951da177e4SLinus Torvalds	fmovemx ETEMP(%a6),%fp0-%fp0
14961da177e4SLinus Torvalds	fcmpd	#0x41dfffffffc00000,%fp0
14971da177e4SLinus Torvalds| 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
14981da177e4SLinus Torvalds	fbge	lo_plrg
14991da177e4SLinus Torvalds	fcmpd	#0xc1e0000000000000,%fp0
15001da177e4SLinus Torvalds| c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
15011da177e4SLinus Torvalds	fble	lo_nlrg
15021da177e4SLinus Torvalds|
15031da177e4SLinus Torvalds| at this point, the answer is between the largest pos and neg values
15041da177e4SLinus Torvalds|
15051da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
15061da177e4SLinus Torvalds	andil	#0x30,%d1
15071da177e4SLinus Torvalds	fmovel	%d1,%fpcr
15081da177e4SLinus Torvalds	fmovel	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
15091da177e4SLinus Torvalds	fmovel %fpsr,%d1
15101da177e4SLinus Torvalds	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
15111da177e4SLinus Torvalds	bra	int_wrt
15121da177e4SLinus Torvalds
15131da177e4SLinus Torvalds
15141da177e4SLinus Torvaldslo_plrg:
15151da177e4SLinus Torvalds	movel	#0x7fffffff,L_SCR1(%a6)	|answer is largest positive int
15161da177e4SLinus Torvalds	fbeq	int_wrt			|exact answer
15171da177e4SLinus Torvalds	fcmpd	#0x41dfffffffe00000,%fp0
15181da177e4SLinus Torvalds| 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
15191da177e4SLinus Torvalds	fbge	int_operr		|set operr
15201da177e4SLinus Torvalds	bra	int_inx			|set inexact
15211da177e4SLinus Torvalds
15221da177e4SLinus Torvaldslo_nlrg:
15231da177e4SLinus Torvalds	movel	#0x80000000,L_SCR1(%a6)
15241da177e4SLinus Torvalds	fbeq	int_wrt			|exact answer
15251da177e4SLinus Torvalds	fcmpd	#0xc1e0000000100000,%fp0
15261da177e4SLinus Torvalds| c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
15271da177e4SLinus Torvalds	fblt	int_operr		|set operr
15281da177e4SLinus Torvalds	bra	int_inx			|set inexact
15291da177e4SLinus Torvalds
15301da177e4SLinus Torvalds|
15311da177e4SLinus Torvalds| wi is used to handle a word integer source specifier
15321da177e4SLinus Torvalds|
15331da177e4SLinus Torvalds
15341da177e4SLinus Torvaldswi:
15351da177e4SLinus Torvalds	moveql	#2,%d0		|set byte count
15361da177e4SLinus Torvalds
15371da177e4SLinus Torvalds	btstb	#7,STAG(%a6)	|check for extended denorm
15381da177e4SLinus Torvalds	bne	int_dnrm	|branch if so
15391da177e4SLinus Torvalds
15401da177e4SLinus Torvalds	fmovemx ETEMP(%a6),%fp0-%fp0
15411da177e4SLinus Torvalds	fcmps	#0x46fffe00,%fp0
15421da177e4SLinus Torvalds| 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
15431da177e4SLinus Torvalds	fbge	wo_plrg
15441da177e4SLinus Torvalds	fcmps	#0xc7000000,%fp0
15451da177e4SLinus Torvalds| c7000000 in sgl prec = c00e00008000000000000000 in ext prec
15461da177e4SLinus Torvalds	fble	wo_nlrg
15471da177e4SLinus Torvalds
15481da177e4SLinus Torvalds|
15491da177e4SLinus Torvalds| at this point, the answer is between the largest pos and neg values
15501da177e4SLinus Torvalds|
15511da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
15521da177e4SLinus Torvalds	andil	#0x30,%d1
15531da177e4SLinus Torvalds	fmovel	%d1,%fpcr
15541da177e4SLinus Torvalds	fmovew	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
15551da177e4SLinus Torvalds	fmovel %fpsr,%d1
15561da177e4SLinus Torvalds	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
15571da177e4SLinus Torvalds	bra	int_wrt
15581da177e4SLinus Torvalds
15591da177e4SLinus Torvaldswo_plrg:
15601da177e4SLinus Torvalds	movew	#0x7fff,L_SCR1(%a6)	|answer is largest positive int
15611da177e4SLinus Torvalds	fbeq	int_wrt			|exact answer
15621da177e4SLinus Torvalds	fcmps	#0x46ffff00,%fp0
15631da177e4SLinus Torvalds| 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
15641da177e4SLinus Torvalds	fbge	int_operr		|set operr
15651da177e4SLinus Torvalds	bra	int_inx			|set inexact
15661da177e4SLinus Torvalds
15671da177e4SLinus Torvaldswo_nlrg:
15681da177e4SLinus Torvalds	movew	#0x8000,L_SCR1(%a6)
15691da177e4SLinus Torvalds	fbeq	int_wrt			|exact answer
15701da177e4SLinus Torvalds	fcmps	#0xc7000080,%fp0
15711da177e4SLinus Torvalds| c7000080 in sgl prec = c00e00008000800000000000 in ext prec
15721da177e4SLinus Torvalds	fblt	int_operr		|set operr
15731da177e4SLinus Torvalds	bra	int_inx			|set inexact
15741da177e4SLinus Torvalds
15751da177e4SLinus Torvalds|
15761da177e4SLinus Torvalds| bi is used to handle a byte integer source specifier
15771da177e4SLinus Torvalds|
15781da177e4SLinus Torvalds
15791da177e4SLinus Torvaldsbi:
15801da177e4SLinus Torvalds	moveql	#1,%d0		|set byte count
15811da177e4SLinus Torvalds
15821da177e4SLinus Torvalds	btstb	#7,STAG(%a6)	|check for extended denorm
15831da177e4SLinus Torvalds	bne	int_dnrm	|branch if so
15841da177e4SLinus Torvalds
15851da177e4SLinus Torvalds	fmovemx ETEMP(%a6),%fp0-%fp0
15861da177e4SLinus Torvalds	fcmps	#0x42fe0000,%fp0
15871da177e4SLinus Torvalds| 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
15881da177e4SLinus Torvalds	fbge	by_plrg
15891da177e4SLinus Torvalds	fcmps	#0xc3000000,%fp0
15901da177e4SLinus Torvalds| c3000000 in sgl prec = c00600008000000000000000 in ext prec
15911da177e4SLinus Torvalds	fble	by_nlrg
15921da177e4SLinus Torvalds
15931da177e4SLinus Torvalds|
15941da177e4SLinus Torvalds| at this point, the answer is between the largest pos and neg values
15951da177e4SLinus Torvalds|
15961da177e4SLinus Torvalds	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
15971da177e4SLinus Torvalds	andil	#0x30,%d1
15981da177e4SLinus Torvalds	fmovel	%d1,%fpcr
15991da177e4SLinus Torvalds	fmoveb	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
16001da177e4SLinus Torvalds	fmovel %fpsr,%d1
16011da177e4SLinus Torvalds	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
16021da177e4SLinus Torvalds	bra	int_wrt
16031da177e4SLinus Torvalds
16041da177e4SLinus Torvaldsby_plrg:
16051da177e4SLinus Torvalds	moveb	#0x7f,L_SCR1(%a6)		|answer is largest positive int
16061da177e4SLinus Torvalds	fbeq	int_wrt			|exact answer
16071da177e4SLinus Torvalds	fcmps	#0x42ff0000,%fp0
16081da177e4SLinus Torvalds| 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
16091da177e4SLinus Torvalds	fbge	int_operr		|set operr
16101da177e4SLinus Torvalds	bra	int_inx			|set inexact
16111da177e4SLinus Torvalds
16121da177e4SLinus Torvaldsby_nlrg:
16131da177e4SLinus Torvalds	moveb	#0x80,L_SCR1(%a6)
16141da177e4SLinus Torvalds	fbeq	int_wrt			|exact answer
16151da177e4SLinus Torvalds	fcmps	#0xc3008000,%fp0
16161da177e4SLinus Torvalds| c3008000 in sgl prec = c00600008080000000000000 in ext prec
16171da177e4SLinus Torvalds	fblt	int_operr		|set operr
16181da177e4SLinus Torvalds	bra	int_inx			|set inexact
16191da177e4SLinus Torvalds
16201da177e4SLinus Torvalds|
16211da177e4SLinus Torvalds| Common integer routines
16221da177e4SLinus Torvalds|
16231da177e4SLinus Torvalds| int_drnrm---account for possible nonzero result for round up with positive
16241da177e4SLinus Torvalds| operand and round down for negative answer.  In the first case (result = 1)
16251da177e4SLinus Torvalds| byte-width (store in d0) of result must be honored.  In the second case,
16261da177e4SLinus Torvalds| -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).
16271da177e4SLinus Torvalds
16281da177e4SLinus Torvaldsint_dnrm:
16291da177e4SLinus Torvalds	movel	#0,L_SCR1(%a6)	| initialize result to 0
16301da177e4SLinus Torvalds	bfextu	FPCR_MODE(%a6){#2:#2},%d1	| d1 is the rounding mode
16311da177e4SLinus Torvalds	cmpb	#2,%d1
16321da177e4SLinus Torvalds	bmis	int_inx		| if RN or RZ, done
16331da177e4SLinus Torvalds	bnes	int_rp		| if RP, continue below
16341da177e4SLinus Torvalds	tstw	ETEMP(%a6)	| RM: store -1 in L_SCR1 if src is negative
16351da177e4SLinus Torvalds	bpls	int_inx		| otherwise result is 0
16361da177e4SLinus Torvalds	movel	#-1,L_SCR1(%a6)
16371da177e4SLinus Torvalds	bras	int_inx
16381da177e4SLinus Torvaldsint_rp:
16391da177e4SLinus Torvalds	tstw	ETEMP(%a6)	| RP: store +1 of proper width in L_SCR1 if
16401da177e4SLinus Torvalds|				; source is greater than 0
16411da177e4SLinus Torvalds	bmis	int_inx		| otherwise, result is 0
16421da177e4SLinus Torvalds	lea	L_SCR1(%a6),%a1	| a1 is address of L_SCR1
16431da177e4SLinus Torvalds	addal	%d0,%a1		| offset by destination width -1
16441da177e4SLinus Torvalds	subal	#1,%a1
16451da177e4SLinus Torvalds	bsetb	#0,(%a1)		| set low bit at a1 address
16461da177e4SLinus Torvaldsint_inx:
16471da177e4SLinus Torvalds	oril	#inx2a_mask,USER_FPSR(%a6)
16481da177e4SLinus Torvalds	bras	int_wrt
16491da177e4SLinus Torvaldsint_operr:
16501da177e4SLinus Torvalds	fmovemx %fp0-%fp0,FPTEMP(%a6)	|FPTEMP must contain the extended
16511da177e4SLinus Torvalds|				;precision source that needs to be
16521da177e4SLinus Torvalds|				;converted to integer this is required
16531da177e4SLinus Torvalds|				;if the operr exception is enabled.
16541da177e4SLinus Torvalds|				;set operr/aiop (no inex2 on int ovfl)
16551da177e4SLinus Torvalds
16561da177e4SLinus Torvalds	oril	#opaop_mask,USER_FPSR(%a6)
16571da177e4SLinus Torvalds|				;fall through to perform int_wrt
16581da177e4SLinus Torvaldsint_wrt:
16591da177e4SLinus Torvalds	movel	EXC_EA(%a6),%a1	|load destination address
16601da177e4SLinus Torvalds	tstl	%a1		|check to see if it is a dest register
16611da177e4SLinus Torvalds	beqs	wrt_dn		|write data register
16621da177e4SLinus Torvalds	lea	L_SCR1(%a6),%a0	|point to supervisor source address
16631da177e4SLinus Torvalds	bsrl	mem_write
16641da177e4SLinus Torvalds	bra	mvouti_end
16651da177e4SLinus Torvalds
16661da177e4SLinus Torvaldswrt_dn:
16671da177e4SLinus Torvalds	movel	%d0,-(%sp)	|d0 currently contains the size to write
16681da177e4SLinus Torvalds	bsrl	get_fline	|get_fline returns Dn in d0
16691da177e4SLinus Torvalds	andiw	#0x7,%d0		|isolate register
16701da177e4SLinus Torvalds	movel	(%sp)+,%d1	|get size
16711da177e4SLinus Torvalds	cmpil	#4,%d1		|most frequent case
16721da177e4SLinus Torvalds	beqs	sz_long
16731da177e4SLinus Torvalds	cmpil	#2,%d1
16741da177e4SLinus Torvalds	bnes	sz_con
16751da177e4SLinus Torvalds	orl	#8,%d0		|add 'word' size to register#
16761da177e4SLinus Torvalds	bras	sz_con
16771da177e4SLinus Torvaldssz_long:
16781da177e4SLinus Torvalds	orl	#0x10,%d0		|add 'long' size to register#
16791da177e4SLinus Torvaldssz_con:
16801da177e4SLinus Torvalds	movel	%d0,%d1		|reg_dest expects size:reg in d1
16811da177e4SLinus Torvalds	bsrl	reg_dest	|load proper data register
16821da177e4SLinus Torvalds	bra	mvouti_end
16831da177e4SLinus Torvaldsxp:
16841da177e4SLinus Torvalds	lea	ETEMP(%a6),%a0
16851da177e4SLinus Torvalds	bclrb	#sign_bit,LOCAL_EX(%a0)
16861da177e4SLinus Torvalds	sne	LOCAL_SGN(%a0)
16871da177e4SLinus Torvalds	btstb	#7,STAG(%a6)	|check for extended denorm
16881da177e4SLinus Torvalds	bne	xdnrm
16891da177e4SLinus Torvalds	clrl	%d0
16901da177e4SLinus Torvalds	bras	do_fp		|do normal case
16911da177e4SLinus Torvaldssgp:
16921da177e4SLinus Torvalds	lea	ETEMP(%a6),%a0
16931da177e4SLinus Torvalds	bclrb	#sign_bit,LOCAL_EX(%a0)
16941da177e4SLinus Torvalds	sne	LOCAL_SGN(%a0)
16951da177e4SLinus Torvalds	btstb	#7,STAG(%a6)	|check for extended denorm
16961da177e4SLinus Torvalds	bne	sp_catas	|branch if so
16971da177e4SLinus Torvalds	movew	LOCAL_EX(%a0),%d0
16981da177e4SLinus Torvalds	lea	sp_bnds,%a1
16991da177e4SLinus Torvalds	cmpw	(%a1),%d0
17001da177e4SLinus Torvalds	blt	sp_under
17011da177e4SLinus Torvalds	cmpw	2(%a1),%d0
17021da177e4SLinus Torvalds	bgt	sp_over
17031da177e4SLinus Torvalds	movel	#1,%d0		|set destination format to single
17041da177e4SLinus Torvalds	bras	do_fp		|do normal case
17051da177e4SLinus Torvaldsdp:
17061da177e4SLinus Torvalds	lea	ETEMP(%a6),%a0
17071da177e4SLinus Torvalds	bclrb	#sign_bit,LOCAL_EX(%a0)
17081da177e4SLinus Torvalds	sne	LOCAL_SGN(%a0)
17091da177e4SLinus Torvalds
17101da177e4SLinus Torvalds	btstb	#7,STAG(%a6)	|check for extended denorm
17111da177e4SLinus Torvalds	bne	dp_catas	|branch if so
17121da177e4SLinus Torvalds
17131da177e4SLinus Torvalds	movew	LOCAL_EX(%a0),%d0
17141da177e4SLinus Torvalds	lea	dp_bnds,%a1
17151da177e4SLinus Torvalds
17161da177e4SLinus Torvalds	cmpw	(%a1),%d0
17171da177e4SLinus Torvalds	blt	dp_under
17181da177e4SLinus Torvalds	cmpw	2(%a1),%d0
17191da177e4SLinus Torvalds	bgt	dp_over
17201da177e4SLinus Torvalds
17211da177e4SLinus Torvalds	movel	#2,%d0		|set destination format to double
17221da177e4SLinus Torvalds|				;fall through to do_fp
17231da177e4SLinus Torvalds|
17241da177e4SLinus Torvaldsdo_fp:
17251da177e4SLinus Torvalds	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|rnd mode in d1
17261da177e4SLinus Torvalds	swap	%d0			|rnd prec in upper word
17271da177e4SLinus Torvalds	addl	%d0,%d1			|d1 has PREC/MODE info
17281da177e4SLinus Torvalds
17291da177e4SLinus Torvalds	clrl	%d0			|clear g,r,s
17301da177e4SLinus Torvalds
17311da177e4SLinus Torvalds	bsrl	round			|round
17321da177e4SLinus Torvalds
17331da177e4SLinus Torvalds	movel	%a0,%a1
17341da177e4SLinus Torvalds	movel	EXC_EA(%a6),%a0
17351da177e4SLinus Torvalds
17361da177e4SLinus Torvalds	bfextu	CMDREG1B(%a6){#3:#3},%d1	|extract destination format
17371da177e4SLinus Torvalds|					;at this point only the dest
17381da177e4SLinus Torvalds|					;formats sgl, dbl, ext are
17391da177e4SLinus Torvalds|					;possible
17401da177e4SLinus Torvalds	cmpb	#2,%d1
17411da177e4SLinus Torvalds	bgts	ddbl			|double=5, extended=2, single=1
17421da177e4SLinus Torvalds	bnes	dsgl
17431da177e4SLinus Torvalds|					;fall through to dext
17441da177e4SLinus Torvaldsdext:
17451da177e4SLinus Torvalds	bsrl	dest_ext
17461da177e4SLinus Torvalds	bra	mvout_end
17471da177e4SLinus Torvaldsdsgl:
17481da177e4SLinus Torvalds	bsrl	dest_sgl
17491da177e4SLinus Torvalds	bra	mvout_end
17501da177e4SLinus Torvaldsddbl:
17511da177e4SLinus Torvalds	bsrl	dest_dbl
17521da177e4SLinus Torvalds	bra	mvout_end
17531da177e4SLinus Torvalds
17541da177e4SLinus Torvalds|
17551da177e4SLinus Torvalds| Handle possible denorm or catastrophic underflow cases here
17561da177e4SLinus Torvalds|
17571da177e4SLinus Torvaldsxdnrm:
17581da177e4SLinus Torvalds	bsr	set_xop		|initialize WBTEMP
17591da177e4SLinus Torvalds	bsetb	#wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15
17601da177e4SLinus Torvalds
17611da177e4SLinus Torvalds	movel	%a0,%a1
17621da177e4SLinus Torvalds	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
17631da177e4SLinus Torvalds	bsrl	dest_ext	|store to memory
17641da177e4SLinus Torvalds	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
17651da177e4SLinus Torvalds	bra	mvout_end
17661da177e4SLinus Torvalds
17671da177e4SLinus Torvaldssp_under:
17681da177e4SLinus Torvalds	bsetb	#etemp15_bit,STAG(%a6)
17691da177e4SLinus Torvalds
17701da177e4SLinus Torvalds	cmpw	4(%a1),%d0
17711da177e4SLinus Torvalds	blts	sp_catas	|catastrophic underflow case
17721da177e4SLinus Torvalds
17731da177e4SLinus Torvalds	movel	#1,%d0		|load in round precision
17741da177e4SLinus Torvalds	movel	#sgl_thresh,%d1	|load in single denorm threshold
17751da177e4SLinus Torvalds	bsrl	dpspdnrm	|expects d1 to have the proper
17761da177e4SLinus Torvalds|				;denorm threshold
17771da177e4SLinus Torvalds	bsrl	dest_sgl	|stores value to destination
17781da177e4SLinus Torvalds	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
17791da177e4SLinus Torvalds	bra	mvout_end	|exit
17801da177e4SLinus Torvalds
17811da177e4SLinus Torvaldsdp_under:
17821da177e4SLinus Torvalds	bsetb	#etemp15_bit,STAG(%a6)
17831da177e4SLinus Torvalds
17841da177e4SLinus Torvalds	cmpw	4(%a1),%d0
17851da177e4SLinus Torvalds	blts	dp_catas	|catastrophic underflow case
17861da177e4SLinus Torvalds
17871da177e4SLinus Torvalds	movel	#dbl_thresh,%d1	|load in double precision threshold
17881da177e4SLinus Torvalds	movel	#2,%d0
17891da177e4SLinus Torvalds	bsrl	dpspdnrm	|expects d1 to have proper
17901da177e4SLinus Torvalds|				;denorm threshold
17911da177e4SLinus Torvalds|				;expects d0 to have round precision
17921da177e4SLinus Torvalds	bsrl	dest_dbl	|store value to destination
17931da177e4SLinus Torvalds	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
17941da177e4SLinus Torvalds	bra	mvout_end	|exit
17951da177e4SLinus Torvalds
17961da177e4SLinus Torvalds|
17971da177e4SLinus Torvalds| Handle catastrophic underflow cases here
17981da177e4SLinus Torvalds|
17991da177e4SLinus Torvaldssp_catas:
18001da177e4SLinus Torvalds| Temp fix for z bit set in unf_sub
18011da177e4SLinus Torvalds	movel	USER_FPSR(%a6),-(%a7)
18021da177e4SLinus Torvalds
18031da177e4SLinus Torvalds	movel	#1,%d0		|set round precision to sgl
18041da177e4SLinus Torvalds
18051da177e4SLinus Torvalds	bsrl	unf_sub		|a0 points to result
18061da177e4SLinus Torvalds
18071da177e4SLinus Torvalds	movel	(%a7)+,USER_FPSR(%a6)
18081da177e4SLinus Torvalds
18091da177e4SLinus Torvalds	movel	#1,%d0
18101da177e4SLinus Torvalds	subw	%d0,LOCAL_EX(%a0) |account for difference between
18111da177e4SLinus Torvalds|				;denorm/norm bias
18121da177e4SLinus Torvalds
18131da177e4SLinus Torvalds	movel	%a0,%a1		|a1 has the operand input
18141da177e4SLinus Torvalds	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
18151da177e4SLinus Torvalds
18161da177e4SLinus Torvalds	bsrl	dest_sgl	|store the result
18171da177e4SLinus Torvalds	oril	#unfinx_mask,USER_FPSR(%a6)
18181da177e4SLinus Torvalds	bra	mvout_end
18191da177e4SLinus Torvalds
18201da177e4SLinus Torvaldsdp_catas:
18211da177e4SLinus Torvalds| Temp fix for z bit set in unf_sub
18221da177e4SLinus Torvalds	movel	USER_FPSR(%a6),-(%a7)
18231da177e4SLinus Torvalds
18241da177e4SLinus Torvalds	movel	#2,%d0		|set round precision to dbl
18251da177e4SLinus Torvalds	bsrl	unf_sub		|a0 points to result
18261da177e4SLinus Torvalds
18271da177e4SLinus Torvalds	movel	(%a7)+,USER_FPSR(%a6)
18281da177e4SLinus Torvalds
18291da177e4SLinus Torvalds	movel	#1,%d0
18301da177e4SLinus Torvalds	subw	%d0,LOCAL_EX(%a0) |account for difference between
18311da177e4SLinus Torvalds|				;denorm/norm bias
18321da177e4SLinus Torvalds
18331da177e4SLinus Torvalds	movel	%a0,%a1		|a1 has the operand input
18341da177e4SLinus Torvalds	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
18351da177e4SLinus Torvalds
18361da177e4SLinus Torvalds	bsrl	dest_dbl	|store the result
18371da177e4SLinus Torvalds	oril	#unfinx_mask,USER_FPSR(%a6)
18381da177e4SLinus Torvalds	bra	mvout_end
18391da177e4SLinus Torvalds
18401da177e4SLinus Torvalds|
18411da177e4SLinus Torvalds| Handle catastrophic overflow cases here
18421da177e4SLinus Torvalds|
18431da177e4SLinus Torvaldssp_over:
18441da177e4SLinus Torvalds| Temp fix for z bit set in unf_sub
18451da177e4SLinus Torvalds	movel	USER_FPSR(%a6),-(%a7)
18461da177e4SLinus Torvalds
18471da177e4SLinus Torvalds	movel	#1,%d0
18481da177e4SLinus Torvalds	leal	FP_SCR1(%a6),%a0	|use FP_SCR1 for creating result
18491da177e4SLinus Torvalds	movel	ETEMP_EX(%a6),(%a0)
18501da177e4SLinus Torvalds	movel	ETEMP_HI(%a6),4(%a0)
18511da177e4SLinus Torvalds	movel	ETEMP_LO(%a6),8(%a0)
18521da177e4SLinus Torvalds	bsrl	ovf_res
18531da177e4SLinus Torvalds
18541da177e4SLinus Torvalds	movel	(%a7)+,USER_FPSR(%a6)
18551da177e4SLinus Torvalds
18561da177e4SLinus Torvalds	movel	%a0,%a1
18571da177e4SLinus Torvalds	movel	EXC_EA(%a6),%a0
18581da177e4SLinus Torvalds	bsrl	dest_sgl
18591da177e4SLinus Torvalds	orl	#ovfinx_mask,USER_FPSR(%a6)
18601da177e4SLinus Torvalds	bra	mvout_end
18611da177e4SLinus Torvalds
18621da177e4SLinus Torvaldsdp_over:
18631da177e4SLinus Torvalds| Temp fix for z bit set in ovf_res
18641da177e4SLinus Torvalds	movel	USER_FPSR(%a6),-(%a7)
18651da177e4SLinus Torvalds
18661da177e4SLinus Torvalds	movel	#2,%d0
18671da177e4SLinus Torvalds	leal	FP_SCR1(%a6),%a0	|use FP_SCR1 for creating result
18681da177e4SLinus Torvalds	movel	ETEMP_EX(%a6),(%a0)
18691da177e4SLinus Torvalds	movel	ETEMP_HI(%a6),4(%a0)
18701da177e4SLinus Torvalds	movel	ETEMP_LO(%a6),8(%a0)
18711da177e4SLinus Torvalds	bsrl	ovf_res
18721da177e4SLinus Torvalds
18731da177e4SLinus Torvalds	movel	(%a7)+,USER_FPSR(%a6)
18741da177e4SLinus Torvalds
18751da177e4SLinus Torvalds	movel	%a0,%a1
18761da177e4SLinus Torvalds	movel	EXC_EA(%a6),%a0
18771da177e4SLinus Torvalds	bsrl	dest_dbl
18781da177e4SLinus Torvalds	orl	#ovfinx_mask,USER_FPSR(%a6)
18791da177e4SLinus Torvalds	bra	mvout_end
18801da177e4SLinus Torvalds
18811da177e4SLinus Torvalds|
18821da177e4SLinus Torvalds|	DPSPDNRM
18831da177e4SLinus Torvalds|
18841da177e4SLinus Torvalds| This subroutine takes an extended normalized number and denormalizes
18851da177e4SLinus Torvalds| it to the given round precision. This subroutine also decrements
18861da177e4SLinus Torvalds| the input operand's exponent by 1 to account for the fact that
18871da177e4SLinus Torvalds| dest_sgl or dest_dbl expects a normalized number's bias.
18881da177e4SLinus Torvalds|
18891da177e4SLinus Torvalds| Input: a0  points to a normalized number in internal extended format
18901da177e4SLinus Torvalds|	 d0  is the round precision (=1 for sgl; =2 for dbl)
18911da177e4SLinus Torvalds|	 d1  is the single precision or double precision
18921da177e4SLinus Torvalds|	     denorm threshold
18931da177e4SLinus Torvalds|
18941da177e4SLinus Torvalds| Output: (In the format for dest_sgl or dest_dbl)
18951da177e4SLinus Torvalds|	 a0   points to the destination
18961da177e4SLinus Torvalds|	 a1   points to the operand
18971da177e4SLinus Torvalds|
18981da177e4SLinus Torvalds| Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
18991da177e4SLinus Torvalds|
19001da177e4SLinus Torvaldsdpspdnrm:
19011da177e4SLinus Torvalds	movel	%d0,-(%a7)	|save round precision
19021da177e4SLinus Torvalds	clrl	%d0		|clear initial g,r,s
19031da177e4SLinus Torvalds	bsrl	dnrm_lp		|careful with d0, it's needed by round
19041da177e4SLinus Torvalds
19051da177e4SLinus Torvalds	bfextu	FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode
19061da177e4SLinus Torvalds	swap	%d1
19071da177e4SLinus Torvalds	movew	2(%a7),%d1	|set rounding precision
19081da177e4SLinus Torvalds	swap	%d1		|at this point d1 has PREC/MODE info
19091da177e4SLinus Torvalds	bsrl	round		|round result, sets the inex bit in
19101da177e4SLinus Torvalds|				;USER_FPSR if needed
19111da177e4SLinus Torvalds
19121da177e4SLinus Torvalds	movew	#1,%d0
19131da177e4SLinus Torvalds	subw	%d0,LOCAL_EX(%a0) |account for difference in denorm
19141da177e4SLinus Torvalds|				;vs norm bias
19151da177e4SLinus Torvalds
19161da177e4SLinus Torvalds	movel	%a0,%a1		|a1 has the operand input
19171da177e4SLinus Torvalds	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
19181da177e4SLinus Torvalds	addw	#4,%a7		|pop stack
19191da177e4SLinus Torvalds	rts
19201da177e4SLinus Torvalds|
19211da177e4SLinus Torvalds| SET_XOP initialized WBTEMP with the value pointed to by a0
19221da177e4SLinus Torvalds| input: a0 points to input operand in the internal extended format
19231da177e4SLinus Torvalds|
19241da177e4SLinus Torvaldsset_xop:
19251da177e4SLinus Torvalds	movel	LOCAL_EX(%a0),WBTEMP_EX(%a6)
19261da177e4SLinus Torvalds	movel	LOCAL_HI(%a0),WBTEMP_HI(%a6)
19271da177e4SLinus Torvalds	movel	LOCAL_LO(%a0),WBTEMP_LO(%a6)
19281da177e4SLinus Torvalds	bfclr	WBTEMP_SGN(%a6){#0:#8}
19291da177e4SLinus Torvalds	beqs	sxop
19301da177e4SLinus Torvalds	bsetb	#sign_bit,WBTEMP_EX(%a6)
19311da177e4SLinus Torvaldssxop:
19321da177e4SLinus Torvalds	bfclr	STAG(%a6){#5:#4}	|clear wbtm66,wbtm1,wbtm0,sbit
19331da177e4SLinus Torvalds	rts
19341da177e4SLinus Torvalds|
19351da177e4SLinus Torvalds|	P_MOVE
19361da177e4SLinus Torvalds|
19371da177e4SLinus Torvaldsp_movet:
19381da177e4SLinus Torvalds	.long	p_move
19391da177e4SLinus Torvalds	.long	p_movez
19401da177e4SLinus Torvalds	.long	p_movei
19411da177e4SLinus Torvalds	.long	p_moven
19421da177e4SLinus Torvalds	.long	p_move
19431da177e4SLinus Torvaldsp_regd:
19441da177e4SLinus Torvalds	.long	p_dyd0
19451da177e4SLinus Torvalds	.long	p_dyd1
19461da177e4SLinus Torvalds	.long	p_dyd2
19471da177e4SLinus Torvalds	.long	p_dyd3
19481da177e4SLinus Torvalds	.long	p_dyd4
19491da177e4SLinus Torvalds	.long	p_dyd5
19501da177e4SLinus Torvalds	.long	p_dyd6
19511da177e4SLinus Torvalds	.long	p_dyd7
19521da177e4SLinus Torvalds
19531da177e4SLinus Torvaldspack_out:
19541da177e4SLinus Torvalds	leal	p_movet,%a0	|load jmp table address
19551da177e4SLinus Torvalds	movew	STAG(%a6),%d0	|get source tag
19561da177e4SLinus Torvalds	bfextu	%d0{#16:#3},%d0	|isolate source bits
19571da177e4SLinus Torvalds	movel	(%a0,%d0.w*4),%a0	|load a0 with routine label for tag
19581da177e4SLinus Torvalds	jmp	(%a0)		|go to the routine
19591da177e4SLinus Torvalds
19601da177e4SLinus Torvaldsp_write:
19611da177e4SLinus Torvalds	movel	#0x0c,%d0	|get byte count
19621da177e4SLinus Torvalds	movel	EXC_EA(%a6),%a1	|get the destination address
19631da177e4SLinus Torvalds	bsr	mem_write	|write the user's destination
19641da177e4SLinus Torvalds	moveb	#0,CU_SAVEPC(%a6) |set the cu save pc to all 0's
19651da177e4SLinus Torvalds
19661da177e4SLinus Torvalds|
19671da177e4SLinus Torvalds| Also note that the dtag must be set to norm here - this is because
19681da177e4SLinus Torvalds| the 040 uses the dtag to execute the correct microcode.
19691da177e4SLinus Torvalds|
19701da177e4SLinus Torvalds        bfclr    DTAG(%a6){#0:#3}  |set dtag to norm
19711da177e4SLinus Torvalds
19721da177e4SLinus Torvalds	rts
19731da177e4SLinus Torvalds
19741da177e4SLinus Torvalds| Notes on handling of special case (zero, inf, and nan) inputs:
19751da177e4SLinus Torvalds|	1. Operr is not signalled if the k-factor is greater than 18.
19761da177e4SLinus Torvalds|	2. Per the manual, status bits are not set.
19771da177e4SLinus Torvalds|
19781da177e4SLinus Torvalds
19791da177e4SLinus Torvaldsp_move:
19801da177e4SLinus Torvalds	movew	CMDREG1B(%a6),%d0
19811da177e4SLinus Torvalds	btstl	#kfact_bit,%d0	|test for dynamic k-factor
19821da177e4SLinus Torvalds	beqs	statick		|if clear, k-factor is static
19831da177e4SLinus Torvaldsdynamick:
19841da177e4SLinus Torvalds	bfextu	%d0{#25:#3},%d0	|isolate register for dynamic k-factor
19851da177e4SLinus Torvalds	lea	p_regd,%a0
19861da177e4SLinus Torvalds	movel	%a0@(%d0:l:4),%a0
19871da177e4SLinus Torvalds	jmp	(%a0)
19881da177e4SLinus Torvaldsstatick:
19891da177e4SLinus Torvalds	andiw	#0x007f,%d0	|get k-factor
19901da177e4SLinus Torvalds	bfexts	%d0{#25:#7},%d0	|sign extend d0 for bindec
19911da177e4SLinus Torvalds	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
19921da177e4SLinus Torvalds	bsrl	bindec		|perform the convert; data at a6
19931da177e4SLinus Torvalds	leal	FP_SCR1(%a6),%a0	|load a0 with result address
19941da177e4SLinus Torvalds	bral	p_write
19951da177e4SLinus Torvaldsp_movez:
19961da177e4SLinus Torvalds	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
19971da177e4SLinus Torvalds	clrw	2(%a0)		|clear lower word of exp
19981da177e4SLinus Torvalds	clrl	4(%a0)		|load second lword of ZERO
19991da177e4SLinus Torvalds	clrl	8(%a0)		|load third lword of ZERO
20001da177e4SLinus Torvalds	bra	p_write		|go write results
20011da177e4SLinus Torvaldsp_movei:
20021da177e4SLinus Torvalds	fmovel	#0,%FPSR		|clear aiop
20031da177e4SLinus Torvalds	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
20041da177e4SLinus Torvalds	clrw	2(%a0)		|clear lower word of exp
20051da177e4SLinus Torvalds	bra	p_write		|go write the result
20061da177e4SLinus Torvaldsp_moven:
20071da177e4SLinus Torvalds	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
20081da177e4SLinus Torvalds	clrw	2(%a0)		|clear lower word of exp
20091da177e4SLinus Torvalds	bra	p_write		|go write the result
20101da177e4SLinus Torvalds
20111da177e4SLinus Torvalds|
20121da177e4SLinus Torvalds| Routines to read the dynamic k-factor from Dn.
20131da177e4SLinus Torvalds|
20141da177e4SLinus Torvaldsp_dyd0:
20151da177e4SLinus Torvalds	movel	USER_D0(%a6),%d0
20161da177e4SLinus Torvalds	bras	statick
20171da177e4SLinus Torvaldsp_dyd1:
20181da177e4SLinus Torvalds	movel	USER_D1(%a6),%d0
20191da177e4SLinus Torvalds	bras	statick
20201da177e4SLinus Torvaldsp_dyd2:
20211da177e4SLinus Torvalds	movel	%d2,%d0
20221da177e4SLinus Torvalds	bras	statick
20231da177e4SLinus Torvaldsp_dyd3:
20241da177e4SLinus Torvalds	movel	%d3,%d0
20251da177e4SLinus Torvalds	bras	statick
20261da177e4SLinus Torvaldsp_dyd4:
20271da177e4SLinus Torvalds	movel	%d4,%d0
20281da177e4SLinus Torvalds	bras	statick
20291da177e4SLinus Torvaldsp_dyd5:
20301da177e4SLinus Torvalds	movel	%d5,%d0
20311da177e4SLinus Torvalds	bras	statick
20321da177e4SLinus Torvaldsp_dyd6:
20331da177e4SLinus Torvalds	movel	%d6,%d0
20341da177e4SLinus Torvalds	bra	statick
20351da177e4SLinus Torvaldsp_dyd7:
20361da177e4SLinus Torvalds	movel	%d7,%d0
20371da177e4SLinus Torvalds	bra	statick
20381da177e4SLinus Torvalds
20391da177e4SLinus Torvalds	|end
2040