xref: /openbmc/linux/arch/m68k/fpsp040/x_store.S (revision e00d82d0)
11da177e4SLinus Torvalds|
21da177e4SLinus Torvalds|	x_store.sa 3.2 1/24/91
31da177e4SLinus Torvalds|
41da177e4SLinus Torvalds|	store --- store operand to memory or register
51da177e4SLinus Torvalds|
61da177e4SLinus Torvalds|	Used by underflow and overflow handlers.
71da177e4SLinus Torvalds|
81da177e4SLinus Torvalds|	a6 = points to fp value to be stored.
91da177e4SLinus Torvalds|
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds|		Copyright (C) Motorola, Inc. 1990
121da177e4SLinus Torvalds|			All Rights Reserved
131da177e4SLinus Torvalds|
14e00d82d0SMatt Waddel|       For details on the license for this file, please see the
15e00d82d0SMatt Waddel|       file, README, in this same directory.
161da177e4SLinus Torvalds
171da177e4SLinus TorvaldsX_STORE:	|idnt    2,1 | Motorola 040 Floating Point Software Package
181da177e4SLinus Torvalds
191da177e4SLinus Torvalds	|section	8
201da177e4SLinus Torvalds
211da177e4SLinus Torvaldsfpreg_mask:
221da177e4SLinus Torvalds	.byte	0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01
231da177e4SLinus Torvalds
241da177e4SLinus Torvalds#include "fpsp.h"
251da177e4SLinus Torvalds
261da177e4SLinus Torvalds	|xref	mem_write
271da177e4SLinus Torvalds	|xref	get_fline
281da177e4SLinus Torvalds	|xref	g_opcls
291da177e4SLinus Torvalds	|xref	g_dfmtou
301da177e4SLinus Torvalds	|xref	reg_dest
311da177e4SLinus Torvalds
321da177e4SLinus Torvalds	.global	dest_ext
331da177e4SLinus Torvalds	.global	dest_dbl
341da177e4SLinus Torvalds	.global	dest_sgl
351da177e4SLinus Torvalds
361da177e4SLinus Torvalds	.global	store
371da177e4SLinus Torvaldsstore:
381da177e4SLinus Torvalds	btstb	#E3,E_BYTE(%a6)
391da177e4SLinus Torvalds	beqs	E1_sto
401da177e4SLinus TorvaldsE3_sto:
411da177e4SLinus Torvalds	movel	CMDREG3B(%a6),%d0
421da177e4SLinus Torvalds	bfextu	%d0{#6:#3},%d0		|isolate dest. reg from cmdreg3b
431da177e4SLinus Torvaldssto_fp:
441da177e4SLinus Torvalds	lea	fpreg_mask,%a1
451da177e4SLinus Torvalds	moveb	(%a1,%d0.w),%d0		|convert reg# to dynamic register mask
461da177e4SLinus Torvalds	tstb	LOCAL_SGN(%a0)
471da177e4SLinus Torvalds	beqs	is_pos
481da177e4SLinus Torvalds	bsetb	#sign_bit,LOCAL_EX(%a0)
491da177e4SLinus Torvaldsis_pos:
501da177e4SLinus Torvalds	fmovemx (%a0),%d0		|move to correct register
511da177e4SLinus Torvalds|
521da177e4SLinus Torvalds|	if fp0-fp3 is being modified, we must put a copy
531da177e4SLinus Torvalds|	in the USER_FPn variable on the stack because all exception
541da177e4SLinus Torvalds|	handlers restore fp0-fp3 from there.
551da177e4SLinus Torvalds|
561da177e4SLinus Torvalds	cmpb	#0x80,%d0
571da177e4SLinus Torvalds	bnes	not_fp0
581da177e4SLinus Torvalds	fmovemx %fp0-%fp0,USER_FP0(%a6)
591da177e4SLinus Torvalds	rts
601da177e4SLinus Torvaldsnot_fp0:
611da177e4SLinus Torvalds	cmpb	#0x40,%d0
621da177e4SLinus Torvalds	bnes	not_fp1
631da177e4SLinus Torvalds	fmovemx %fp1-%fp1,USER_FP1(%a6)
641da177e4SLinus Torvalds	rts
651da177e4SLinus Torvaldsnot_fp1:
661da177e4SLinus Torvalds	cmpb	#0x20,%d0
671da177e4SLinus Torvalds	bnes	not_fp2
681da177e4SLinus Torvalds	fmovemx %fp2-%fp2,USER_FP2(%a6)
691da177e4SLinus Torvalds	rts
701da177e4SLinus Torvaldsnot_fp2:
711da177e4SLinus Torvalds	cmpb	#0x10,%d0
721da177e4SLinus Torvalds	bnes	not_fp3
731da177e4SLinus Torvalds	fmovemx %fp3-%fp3,USER_FP3(%a6)
741da177e4SLinus Torvalds	rts
751da177e4SLinus Torvaldsnot_fp3:
761da177e4SLinus Torvalds	rts
771da177e4SLinus Torvalds
781da177e4SLinus TorvaldsE1_sto:
791da177e4SLinus Torvalds	bsrl	g_opcls		|returns opclass in d0
801da177e4SLinus Torvalds	cmpib	#3,%d0
811da177e4SLinus Torvalds	beq	opc011		|branch if opclass 3
821da177e4SLinus Torvalds	movel	CMDREG1B(%a6),%d0
831da177e4SLinus Torvalds	bfextu	%d0{#6:#3},%d0	|extract destination register
841da177e4SLinus Torvalds	bras	sto_fp
851da177e4SLinus Torvalds
861da177e4SLinus Torvaldsopc011:
871da177e4SLinus Torvalds	bsrl	g_dfmtou	|returns dest format in d0
881da177e4SLinus Torvalds|				;ext=00, sgl=01, dbl=10
891da177e4SLinus Torvalds	movel	%a0,%a1		|save source addr in a1
901da177e4SLinus Torvalds	movel	EXC_EA(%a6),%a0	|get the address
911da177e4SLinus Torvalds	cmpil	#0,%d0		|if dest format is extended
921da177e4SLinus Torvalds	beq	dest_ext	|then branch
931da177e4SLinus Torvalds	cmpil	#1,%d0		|if dest format is single
941da177e4SLinus Torvalds	beq	dest_sgl	|then branch
951da177e4SLinus Torvalds|
961da177e4SLinus Torvalds|	fall through to dest_dbl
971da177e4SLinus Torvalds|
981da177e4SLinus Torvalds
991da177e4SLinus Torvalds|
1001da177e4SLinus Torvalds|	dest_dbl --- write double precision value to user space
1011da177e4SLinus Torvalds|
1021da177e4SLinus Torvalds|Input
1031da177e4SLinus Torvalds|	a0 -> destination address
1041da177e4SLinus Torvalds|	a1 -> source in extended precision
1051da177e4SLinus Torvalds|Output
1061da177e4SLinus Torvalds|	a0 -> destroyed
1071da177e4SLinus Torvalds|	a1 -> destroyed
1081da177e4SLinus Torvalds|	d0 -> 0
1091da177e4SLinus Torvalds|
1101da177e4SLinus Torvalds|Changes extended precision to double precision.
1111da177e4SLinus Torvalds| Note: no attempt is made to round the extended value to double.
1121da177e4SLinus Torvalds|	dbl_sign = ext_sign
1131da177e4SLinus Torvalds|	dbl_exp = ext_exp - $3fff(ext bias) + $7ff(dbl bias)
1141da177e4SLinus Torvalds|	get rid of ext integer bit
1151da177e4SLinus Torvalds|	dbl_mant = ext_mant{62:12}
1161da177e4SLinus Torvalds|
1171da177e4SLinus Torvalds|		---------------   ---------------    ---------------
1181da177e4SLinus Torvalds|  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |
1191da177e4SLinus Torvalds|		---------------   ---------------    ---------------
1201da177e4SLinus Torvalds|		 95	    64    63 62	      32      31     11	  0
1211da177e4SLinus Torvalds|				     |			     |
1221da177e4SLinus Torvalds|				     |			     |
1231da177e4SLinus Torvalds|				     |			     |
1241da177e4SLinus Torvalds|			             v			     v
1251da177e4SLinus Torvalds|			      ---------------   ---------------
1261da177e4SLinus Torvalds|  double   ->		      |s|exp| mant  |   |  mant       |
1271da177e4SLinus Torvalds|			      ---------------   ---------------
1281da177e4SLinus Torvalds|			      63     51   32   31	       0
1291da177e4SLinus Torvalds|
1301da177e4SLinus Torvaldsdest_dbl:
1311da177e4SLinus Torvalds	clrl	%d0		|clear d0
1321da177e4SLinus Torvalds	movew	LOCAL_EX(%a1),%d0	|get exponent
1331da177e4SLinus Torvalds	subw	#0x3fff,%d0	|subtract extended precision bias
1341da177e4SLinus Torvalds	cmpw	#0x4000,%d0	|check if inf
1351da177e4SLinus Torvalds	beqs	inf		|if so, special case
1361da177e4SLinus Torvalds	addw	#0x3ff,%d0	|add double precision bias
1371da177e4SLinus Torvalds	swap	%d0		|d0 now in upper word
1381da177e4SLinus Torvalds	lsll	#4,%d0		|d0 now in proper place for dbl prec exp
1391da177e4SLinus Torvalds	tstb	LOCAL_SGN(%a1)
1401da177e4SLinus Torvalds	beqs	get_mant	|if positive, go process mantissa
1411da177e4SLinus Torvalds	bsetl	#31,%d0		|if negative, put in sign information
1421da177e4SLinus Torvalds|				; before continuing
1431da177e4SLinus Torvalds	bras	get_mant	|go process mantissa
1441da177e4SLinus Torvaldsinf:
1451da177e4SLinus Torvalds	movel	#0x7ff00000,%d0	|load dbl inf exponent
1461da177e4SLinus Torvalds	clrl	LOCAL_HI(%a1)	|clear msb
1471da177e4SLinus Torvalds	tstb	LOCAL_SGN(%a1)
1481da177e4SLinus Torvalds	beqs	dbl_inf		|if positive, go ahead and write it
1491da177e4SLinus Torvalds	bsetl	#31,%d0		|if negative put in sign information
1501da177e4SLinus Torvaldsdbl_inf:
1511da177e4SLinus Torvalds	movel	%d0,LOCAL_EX(%a1)	|put the new exp back on the stack
1521da177e4SLinus Torvalds	bras	dbl_wrt
1531da177e4SLinus Torvaldsget_mant:
1541da177e4SLinus Torvalds	movel	LOCAL_HI(%a1),%d1	|get ms mantissa
1551da177e4SLinus Torvalds	bfextu	%d1{#1:#20},%d1	|get upper 20 bits of ms
1561da177e4SLinus Torvalds	orl	%d1,%d0		|put these bits in ms word of double
1571da177e4SLinus Torvalds	movel	%d0,LOCAL_EX(%a1)	|put the new exp back on the stack
1581da177e4SLinus Torvalds	movel	LOCAL_HI(%a1),%d1	|get ms mantissa
1591da177e4SLinus Torvalds	movel	#21,%d0		|load shift count
1601da177e4SLinus Torvalds	lsll	%d0,%d1		|put lower 11 bits in upper bits
1611da177e4SLinus Torvalds	movel	%d1,LOCAL_HI(%a1)	|build lower lword in memory
1621da177e4SLinus Torvalds	movel	LOCAL_LO(%a1),%d1	|get ls mantissa
1631da177e4SLinus Torvalds	bfextu	%d1{#0:#21},%d0	|get ls 21 bits of double
1641da177e4SLinus Torvalds	orl	%d0,LOCAL_HI(%a1)	|put them in double result
1651da177e4SLinus Torvaldsdbl_wrt:
1661da177e4SLinus Torvalds	movel	#0x8,%d0		|byte count for double precision number
1671da177e4SLinus Torvalds	exg	%a0,%a1		|a0=supervisor source, a1=user dest
1681da177e4SLinus Torvalds	bsrl	mem_write	|move the number to the user's memory
1691da177e4SLinus Torvalds	rts
1701da177e4SLinus Torvalds|
1711da177e4SLinus Torvalds|	dest_sgl --- write single precision value to user space
1721da177e4SLinus Torvalds|
1731da177e4SLinus Torvalds|Input
1741da177e4SLinus Torvalds|	a0 -> destination address
1751da177e4SLinus Torvalds|	a1 -> source in extended precision
1761da177e4SLinus Torvalds|
1771da177e4SLinus Torvalds|Output
1781da177e4SLinus Torvalds|	a0 -> destroyed
1791da177e4SLinus Torvalds|	a1 -> destroyed
1801da177e4SLinus Torvalds|	d0 -> 0
1811da177e4SLinus Torvalds|
1821da177e4SLinus Torvalds|Changes extended precision to single precision.
1831da177e4SLinus Torvalds|	sgl_sign = ext_sign
1841da177e4SLinus Torvalds|	sgl_exp = ext_exp - $3fff(ext bias) + $7f(sgl bias)
1851da177e4SLinus Torvalds|	get rid of ext integer bit
1861da177e4SLinus Torvalds|	sgl_mant = ext_mant{62:12}
1871da177e4SLinus Torvalds|
1881da177e4SLinus Torvalds|		---------------   ---------------    ---------------
1891da177e4SLinus Torvalds|  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |
1901da177e4SLinus Torvalds|		---------------   ---------------    ---------------
1911da177e4SLinus Torvalds|		 95	    64    63 62	   40 32      31     12	  0
1921da177e4SLinus Torvalds|				     |	   |
1931da177e4SLinus Torvalds|				     |	   |
1941da177e4SLinus Torvalds|				     |	   |
1951da177e4SLinus Torvalds|			             v     v
1961da177e4SLinus Torvalds|			      ---------------
1971da177e4SLinus Torvalds|  single   ->		      |s|exp| mant  |
1981da177e4SLinus Torvalds|			      ---------------
1991da177e4SLinus Torvalds|			      31     22     0
2001da177e4SLinus Torvalds|
2011da177e4SLinus Torvaldsdest_sgl:
2021da177e4SLinus Torvalds	clrl	%d0
2031da177e4SLinus Torvalds	movew	LOCAL_EX(%a1),%d0	|get exponent
2041da177e4SLinus Torvalds	subw	#0x3fff,%d0	|subtract extended precision bias
2051da177e4SLinus Torvalds	cmpw	#0x4000,%d0	|check if inf
2061da177e4SLinus Torvalds	beqs	sinf		|if so, special case
2071da177e4SLinus Torvalds	addw	#0x7f,%d0		|add single precision bias
2081da177e4SLinus Torvalds	swap	%d0		|put exp in upper word of d0
2091da177e4SLinus Torvalds	lsll	#7,%d0		|shift it into single exp bits
2101da177e4SLinus Torvalds	tstb	LOCAL_SGN(%a1)
2111da177e4SLinus Torvalds	beqs	get_sman	|if positive, continue
2121da177e4SLinus Torvalds	bsetl	#31,%d0		|if negative, put in sign first
2131da177e4SLinus Torvalds	bras	get_sman	|get mantissa
2141da177e4SLinus Torvaldssinf:
2151da177e4SLinus Torvalds	movel	#0x7f800000,%d0	|load single inf exp to d0
2161da177e4SLinus Torvalds	tstb	LOCAL_SGN(%a1)
2171da177e4SLinus Torvalds	beqs	sgl_wrt		|if positive, continue
2181da177e4SLinus Torvalds	bsetl	#31,%d0		|if negative, put in sign info
2191da177e4SLinus Torvalds	bras	sgl_wrt
2201da177e4SLinus Torvalds
2211da177e4SLinus Torvaldsget_sman:
2221da177e4SLinus Torvalds	movel	LOCAL_HI(%a1),%d1	|get ms mantissa
2231da177e4SLinus Torvalds	bfextu	%d1{#1:#23},%d1	|get upper 23 bits of ms
2241da177e4SLinus Torvalds	orl	%d1,%d0		|put these bits in ms word of single
2251da177e4SLinus Torvalds
2261da177e4SLinus Torvaldssgl_wrt:
2271da177e4SLinus Torvalds	movel	%d0,L_SCR1(%a6)	|put the new exp back on the stack
2281da177e4SLinus Torvalds	movel	#0x4,%d0		|byte count for single precision number
2291da177e4SLinus Torvalds	tstl	%a0		|users destination address
2301da177e4SLinus Torvalds	beqs	sgl_Dn		|destination is a data register
2311da177e4SLinus Torvalds	exg	%a0,%a1		|a0=supervisor source, a1=user dest
2321da177e4SLinus Torvalds	leal	L_SCR1(%a6),%a0	|point a0 to data
2331da177e4SLinus Torvalds	bsrl	mem_write	|move the number to the user's memory
2341da177e4SLinus Torvalds	rts
2351da177e4SLinus Torvaldssgl_Dn:
2361da177e4SLinus Torvalds	bsrl	get_fline	|returns fline word in d0
2371da177e4SLinus Torvalds	andw	#0x7,%d0		|isolate register number
2381da177e4SLinus Torvalds	movel	%d0,%d1		|d1 has size:reg formatted for reg_dest
2391da177e4SLinus Torvalds	orl	#0x10,%d1		|reg_dest wants size added to reg#
2401da177e4SLinus Torvalds	bral	reg_dest	|size is X, rts in reg_dest will
2411da177e4SLinus Torvalds|				;return to caller of dest_sgl
2421da177e4SLinus Torvalds
2431da177e4SLinus Torvaldsdest_ext:
2441da177e4SLinus Torvalds	tstb	LOCAL_SGN(%a1)	|put back sign into exponent word
2451da177e4SLinus Torvalds	beqs	dstx_cont
2461da177e4SLinus Torvalds	bsetb	#sign_bit,LOCAL_EX(%a1)
2471da177e4SLinus Torvaldsdstx_cont:
2481da177e4SLinus Torvalds	clrb	LOCAL_SGN(%a1)	|clear out the sign byte
2491da177e4SLinus Torvalds
2501da177e4SLinus Torvalds	movel	#0x0c,%d0		|byte count for extended number
2511da177e4SLinus Torvalds	exg	%a0,%a1		|a0=supervisor source, a1=user dest
2521da177e4SLinus Torvalds	bsrl	mem_write	|move the number to the user's memory
2531da177e4SLinus Torvalds	rts
2541da177e4SLinus Torvalds
2551da177e4SLinus Torvalds	|end
256