162306a36Sopenharmony_ci|
262306a36Sopenharmony_ci|	x_store.sa 3.2 1/24/91
362306a36Sopenharmony_ci|
462306a36Sopenharmony_ci|	store --- store operand to memory or register
562306a36Sopenharmony_ci|
662306a36Sopenharmony_ci|	Used by underflow and overflow handlers.
762306a36Sopenharmony_ci|
862306a36Sopenharmony_ci|	a6 = points to fp value to be stored.
962306a36Sopenharmony_ci|
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci|		Copyright (C) Motorola, Inc. 1990
1262306a36Sopenharmony_ci|			All Rights Reserved
1362306a36Sopenharmony_ci|
1462306a36Sopenharmony_ci|       For details on the license for this file, please see the
1562306a36Sopenharmony_ci|       file, README, in this same directory.
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ciX_STORE:	|idnt    2,1 | Motorola 040 Floating Point Software Package
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	|section	8
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cifpreg_mask:
2262306a36Sopenharmony_ci	.byte	0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "fpsp.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	|xref	mem_write
2762306a36Sopenharmony_ci	|xref	get_fline
2862306a36Sopenharmony_ci	|xref	g_opcls
2962306a36Sopenharmony_ci	|xref	g_dfmtou
3062306a36Sopenharmony_ci	|xref	reg_dest
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	.global	dest_ext
3362306a36Sopenharmony_ci	.global	dest_dbl
3462306a36Sopenharmony_ci	.global	dest_sgl
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	.global	store
3762306a36Sopenharmony_cistore:
3862306a36Sopenharmony_ci	btstb	#E3,E_BYTE(%a6)
3962306a36Sopenharmony_ci	beqs	E1_sto
4062306a36Sopenharmony_ciE3_sto:
4162306a36Sopenharmony_ci	movel	CMDREG3B(%a6),%d0
4262306a36Sopenharmony_ci	bfextu	%d0{#6:#3},%d0		|isolate dest. reg from cmdreg3b
4362306a36Sopenharmony_cisto_fp:
4462306a36Sopenharmony_ci	lea	fpreg_mask,%a1
4562306a36Sopenharmony_ci	moveb	(%a1,%d0.w),%d0		|convert reg# to dynamic register mask
4662306a36Sopenharmony_ci	tstb	LOCAL_SGN(%a0)
4762306a36Sopenharmony_ci	beqs	is_pos
4862306a36Sopenharmony_ci	bsetb	#sign_bit,LOCAL_EX(%a0)
4962306a36Sopenharmony_ciis_pos:
5062306a36Sopenharmony_ci	fmovemx (%a0),%d0		|move to correct register
5162306a36Sopenharmony_ci|
5262306a36Sopenharmony_ci|	if fp0-fp3 is being modified, we must put a copy
5362306a36Sopenharmony_ci|	in the USER_FPn variable on the stack because all exception
5462306a36Sopenharmony_ci|	handlers restore fp0-fp3 from there.
5562306a36Sopenharmony_ci|
5662306a36Sopenharmony_ci	cmpb	#0x80,%d0
5762306a36Sopenharmony_ci	bnes	not_fp0
5862306a36Sopenharmony_ci	fmovemx %fp0-%fp0,USER_FP0(%a6)
5962306a36Sopenharmony_ci	rts
6062306a36Sopenharmony_cinot_fp0:
6162306a36Sopenharmony_ci	cmpb	#0x40,%d0
6262306a36Sopenharmony_ci	bnes	not_fp1
6362306a36Sopenharmony_ci	fmovemx %fp1-%fp1,USER_FP1(%a6)
6462306a36Sopenharmony_ci	rts
6562306a36Sopenharmony_cinot_fp1:
6662306a36Sopenharmony_ci	cmpb	#0x20,%d0
6762306a36Sopenharmony_ci	bnes	not_fp2
6862306a36Sopenharmony_ci	fmovemx %fp2-%fp2,USER_FP2(%a6)
6962306a36Sopenharmony_ci	rts
7062306a36Sopenharmony_cinot_fp2:
7162306a36Sopenharmony_ci	cmpb	#0x10,%d0
7262306a36Sopenharmony_ci	bnes	not_fp3
7362306a36Sopenharmony_ci	fmovemx %fp3-%fp3,USER_FP3(%a6)
7462306a36Sopenharmony_ci	rts
7562306a36Sopenharmony_cinot_fp3:
7662306a36Sopenharmony_ci	rts
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ciE1_sto:
7962306a36Sopenharmony_ci	bsrl	g_opcls		|returns opclass in d0
8062306a36Sopenharmony_ci	cmpib	#3,%d0
8162306a36Sopenharmony_ci	beq	opc011		|branch if opclass 3
8262306a36Sopenharmony_ci	movel	CMDREG1B(%a6),%d0
8362306a36Sopenharmony_ci	bfextu	%d0{#6:#3},%d0	|extract destination register
8462306a36Sopenharmony_ci	bras	sto_fp
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ciopc011:
8762306a36Sopenharmony_ci	bsrl	g_dfmtou	|returns dest format in d0
8862306a36Sopenharmony_ci|				;ext=00, sgl=01, dbl=10
8962306a36Sopenharmony_ci	movel	%a0,%a1		|save source addr in a1
9062306a36Sopenharmony_ci	movel	EXC_EA(%a6),%a0	|get the address
9162306a36Sopenharmony_ci	cmpil	#0,%d0		|if dest format is extended
9262306a36Sopenharmony_ci	beq	dest_ext	|then branch
9362306a36Sopenharmony_ci	cmpil	#1,%d0		|if dest format is single
9462306a36Sopenharmony_ci	beq	dest_sgl	|then branch
9562306a36Sopenharmony_ci|
9662306a36Sopenharmony_ci|	fall through to dest_dbl
9762306a36Sopenharmony_ci|
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci|
10062306a36Sopenharmony_ci|	dest_dbl --- write double precision value to user space
10162306a36Sopenharmony_ci|
10262306a36Sopenharmony_ci|Input
10362306a36Sopenharmony_ci|	a0 -> destination address
10462306a36Sopenharmony_ci|	a1 -> source in extended precision
10562306a36Sopenharmony_ci|Output
10662306a36Sopenharmony_ci|	a0 -> destroyed
10762306a36Sopenharmony_ci|	a1 -> destroyed
10862306a36Sopenharmony_ci|	d0 -> 0
10962306a36Sopenharmony_ci|
11062306a36Sopenharmony_ci|Changes extended precision to double precision.
11162306a36Sopenharmony_ci| Note: no attempt is made to round the extended value to double.
11262306a36Sopenharmony_ci|	dbl_sign = ext_sign
11362306a36Sopenharmony_ci|	dbl_exp = ext_exp - $3fff(ext bias) + $7ff(dbl bias)
11462306a36Sopenharmony_ci|	get rid of ext integer bit
11562306a36Sopenharmony_ci|	dbl_mant = ext_mant{62:12}
11662306a36Sopenharmony_ci|
11762306a36Sopenharmony_ci|		---------------   ---------------    ---------------
11862306a36Sopenharmony_ci|  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |
11962306a36Sopenharmony_ci|		---------------   ---------------    ---------------
12062306a36Sopenharmony_ci|		 95	    64    63 62	      32      31     11	  0
12162306a36Sopenharmony_ci|				     |			     |
12262306a36Sopenharmony_ci|				     |			     |
12362306a36Sopenharmony_ci|				     |			     |
12462306a36Sopenharmony_ci|			             v			     v
12562306a36Sopenharmony_ci|			      ---------------   ---------------
12662306a36Sopenharmony_ci|  double   ->		      |s|exp| mant  |   |  mant       |
12762306a36Sopenharmony_ci|			      ---------------   ---------------
12862306a36Sopenharmony_ci|			      63     51   32   31	       0
12962306a36Sopenharmony_ci|
13062306a36Sopenharmony_cidest_dbl:
13162306a36Sopenharmony_ci	clrl	%d0		|clear d0
13262306a36Sopenharmony_ci	movew	LOCAL_EX(%a1),%d0	|get exponent
13362306a36Sopenharmony_ci	subw	#0x3fff,%d0	|subtract extended precision bias
13462306a36Sopenharmony_ci	cmpw	#0x4000,%d0	|check if inf
13562306a36Sopenharmony_ci	beqs	inf		|if so, special case
13662306a36Sopenharmony_ci	addw	#0x3ff,%d0	|add double precision bias
13762306a36Sopenharmony_ci	swap	%d0		|d0 now in upper word
13862306a36Sopenharmony_ci	lsll	#4,%d0		|d0 now in proper place for dbl prec exp
13962306a36Sopenharmony_ci	tstb	LOCAL_SGN(%a1)
14062306a36Sopenharmony_ci	beqs	get_mant	|if positive, go process mantissa
14162306a36Sopenharmony_ci	bsetl	#31,%d0		|if negative, put in sign information
14262306a36Sopenharmony_ci|				; before continuing
14362306a36Sopenharmony_ci	bras	get_mant	|go process mantissa
14462306a36Sopenharmony_ciinf:
14562306a36Sopenharmony_ci	movel	#0x7ff00000,%d0	|load dbl inf exponent
14662306a36Sopenharmony_ci	clrl	LOCAL_HI(%a1)	|clear msb
14762306a36Sopenharmony_ci	tstb	LOCAL_SGN(%a1)
14862306a36Sopenharmony_ci	beqs	dbl_inf		|if positive, go ahead and write it
14962306a36Sopenharmony_ci	bsetl	#31,%d0		|if negative put in sign information
15062306a36Sopenharmony_cidbl_inf:
15162306a36Sopenharmony_ci	movel	%d0,LOCAL_EX(%a1)	|put the new exp back on the stack
15262306a36Sopenharmony_ci	bras	dbl_wrt
15362306a36Sopenharmony_ciget_mant:
15462306a36Sopenharmony_ci	movel	LOCAL_HI(%a1),%d1	|get ms mantissa
15562306a36Sopenharmony_ci	bfextu	%d1{#1:#20},%d1	|get upper 20 bits of ms
15662306a36Sopenharmony_ci	orl	%d1,%d0		|put these bits in ms word of double
15762306a36Sopenharmony_ci	movel	%d0,LOCAL_EX(%a1)	|put the new exp back on the stack
15862306a36Sopenharmony_ci	movel	LOCAL_HI(%a1),%d1	|get ms mantissa
15962306a36Sopenharmony_ci	movel	#21,%d0		|load shift count
16062306a36Sopenharmony_ci	lsll	%d0,%d1		|put lower 11 bits in upper bits
16162306a36Sopenharmony_ci	movel	%d1,LOCAL_HI(%a1)	|build lower lword in memory
16262306a36Sopenharmony_ci	movel	LOCAL_LO(%a1),%d1	|get ls mantissa
16362306a36Sopenharmony_ci	bfextu	%d1{#0:#21},%d0	|get ls 21 bits of double
16462306a36Sopenharmony_ci	orl	%d0,LOCAL_HI(%a1)	|put them in double result
16562306a36Sopenharmony_cidbl_wrt:
16662306a36Sopenharmony_ci	movel	#0x8,%d0		|byte count for double precision number
16762306a36Sopenharmony_ci	exg	%a0,%a1		|a0=supervisor source, a1=user dest
16862306a36Sopenharmony_ci	bsrl	mem_write	|move the number to the user's memory
16962306a36Sopenharmony_ci	rts
17062306a36Sopenharmony_ci|
17162306a36Sopenharmony_ci|	dest_sgl --- write single precision value to user space
17262306a36Sopenharmony_ci|
17362306a36Sopenharmony_ci|Input
17462306a36Sopenharmony_ci|	a0 -> destination address
17562306a36Sopenharmony_ci|	a1 -> source in extended precision
17662306a36Sopenharmony_ci|
17762306a36Sopenharmony_ci|Output
17862306a36Sopenharmony_ci|	a0 -> destroyed
17962306a36Sopenharmony_ci|	a1 -> destroyed
18062306a36Sopenharmony_ci|	d0 -> 0
18162306a36Sopenharmony_ci|
18262306a36Sopenharmony_ci|Changes extended precision to single precision.
18362306a36Sopenharmony_ci|	sgl_sign = ext_sign
18462306a36Sopenharmony_ci|	sgl_exp = ext_exp - $3fff(ext bias) + $7f(sgl bias)
18562306a36Sopenharmony_ci|	get rid of ext integer bit
18662306a36Sopenharmony_ci|	sgl_mant = ext_mant{62:12}
18762306a36Sopenharmony_ci|
18862306a36Sopenharmony_ci|		---------------   ---------------    ---------------
18962306a36Sopenharmony_ci|  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |
19062306a36Sopenharmony_ci|		---------------   ---------------    ---------------
19162306a36Sopenharmony_ci|		 95	    64    63 62	   40 32      31     12	  0
19262306a36Sopenharmony_ci|				     |	   |
19362306a36Sopenharmony_ci|				     |	   |
19462306a36Sopenharmony_ci|				     |	   |
19562306a36Sopenharmony_ci|			             v     v
19662306a36Sopenharmony_ci|			      ---------------
19762306a36Sopenharmony_ci|  single   ->		      |s|exp| mant  |
19862306a36Sopenharmony_ci|			      ---------------
19962306a36Sopenharmony_ci|			      31     22     0
20062306a36Sopenharmony_ci|
20162306a36Sopenharmony_cidest_sgl:
20262306a36Sopenharmony_ci	clrl	%d0
20362306a36Sopenharmony_ci	movew	LOCAL_EX(%a1),%d0	|get exponent
20462306a36Sopenharmony_ci	subw	#0x3fff,%d0	|subtract extended precision bias
20562306a36Sopenharmony_ci	cmpw	#0x4000,%d0	|check if inf
20662306a36Sopenharmony_ci	beqs	sinf		|if so, special case
20762306a36Sopenharmony_ci	addw	#0x7f,%d0		|add single precision bias
20862306a36Sopenharmony_ci	swap	%d0		|put exp in upper word of d0
20962306a36Sopenharmony_ci	lsll	#7,%d0		|shift it into single exp bits
21062306a36Sopenharmony_ci	tstb	LOCAL_SGN(%a1)
21162306a36Sopenharmony_ci	beqs	get_sman	|if positive, continue
21262306a36Sopenharmony_ci	bsetl	#31,%d0		|if negative, put in sign first
21362306a36Sopenharmony_ci	bras	get_sman	|get mantissa
21462306a36Sopenharmony_cisinf:
21562306a36Sopenharmony_ci	movel	#0x7f800000,%d0	|load single inf exp to d0
21662306a36Sopenharmony_ci	tstb	LOCAL_SGN(%a1)
21762306a36Sopenharmony_ci	beqs	sgl_wrt		|if positive, continue
21862306a36Sopenharmony_ci	bsetl	#31,%d0		|if negative, put in sign info
21962306a36Sopenharmony_ci	bras	sgl_wrt
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ciget_sman:
22262306a36Sopenharmony_ci	movel	LOCAL_HI(%a1),%d1	|get ms mantissa
22362306a36Sopenharmony_ci	bfextu	%d1{#1:#23},%d1	|get upper 23 bits of ms
22462306a36Sopenharmony_ci	orl	%d1,%d0		|put these bits in ms word of single
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cisgl_wrt:
22762306a36Sopenharmony_ci	movel	%d0,L_SCR1(%a6)	|put the new exp back on the stack
22862306a36Sopenharmony_ci	movel	#0x4,%d0		|byte count for single precision number
22962306a36Sopenharmony_ci	tstl	%a0		|users destination address
23062306a36Sopenharmony_ci	beqs	sgl_Dn		|destination is a data register
23162306a36Sopenharmony_ci	exg	%a0,%a1		|a0=supervisor source, a1=user dest
23262306a36Sopenharmony_ci	leal	L_SCR1(%a6),%a0	|point a0 to data
23362306a36Sopenharmony_ci	bsrl	mem_write	|move the number to the user's memory
23462306a36Sopenharmony_ci	rts
23562306a36Sopenharmony_cisgl_Dn:
23662306a36Sopenharmony_ci	bsrl	get_fline	|returns fline word in d0
23762306a36Sopenharmony_ci	andw	#0x7,%d0		|isolate register number
23862306a36Sopenharmony_ci	movel	%d0,%d1		|d1 has size:reg formatted for reg_dest
23962306a36Sopenharmony_ci	orl	#0x10,%d1		|reg_dest wants size added to reg#
24062306a36Sopenharmony_ci	bral	reg_dest	|size is X, rts in reg_dest will
24162306a36Sopenharmony_ci|				;return to caller of dest_sgl
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cidest_ext:
24462306a36Sopenharmony_ci	tstb	LOCAL_SGN(%a1)	|put back sign into exponent word
24562306a36Sopenharmony_ci	beqs	dstx_cont
24662306a36Sopenharmony_ci	bsetb	#sign_bit,LOCAL_EX(%a1)
24762306a36Sopenharmony_cidstx_cont:
24862306a36Sopenharmony_ci	clrb	LOCAL_SGN(%a1)	|clear out the sign byte
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	movel	#0x0c,%d0		|byte count for extended number
25162306a36Sopenharmony_ci	exg	%a0,%a1		|a0=supervisor source, a1=user dest
25262306a36Sopenharmony_ci	bsrl	mem_write	|move the number to the user's memory
25362306a36Sopenharmony_ci	rts
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	|end
256