aboutsummaryrefslogtreecommitdiff
path: root/arch/m68k/fpsp040/x_store.S
blob: 402dc0c0ebc04d814b69f55636ae1320bf24b747 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
|
|	x_store.sa 3.2 1/24/91
|
|	store --- store operand to memory or register
|
|	Used by underflow and overflow handlers.
|
|	a6 = points to fp value to be stored.
|

|		Copyright (C) Motorola, Inc. 1990
|			All Rights Reserved
|
|       For details on the license for this file, please see the
|       file, README, in this same directory.

X_STORE:	|idnt    2,1 | Motorola 040 Floating Point Software Package

	|section	8

fpreg_mask:
	.byte	0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01

#include "fpsp.h"

	|xref	mem_write
	|xref	get_fline
	|xref	g_opcls
	|xref	g_dfmtou
	|xref	reg_dest

	.global	dest_ext
	.global	dest_dbl
	.global	dest_sgl

	.global	store
store:
	btstb	#E3,E_BYTE(%a6)
	beqs	E1_sto
E3_sto:
	movel	CMDREG3B(%a6),%d0
	bfextu	%d0{#6:#3},%d0		|isolate dest. reg from cmdreg3b
sto_fp:
	lea	fpreg_mask,%a1
	moveb	(%a1,%d0.w),%d0		|convert reg# to dynamic register mask
	tstb	LOCAL_SGN(%a0)
	beqs	is_pos
	bsetb	#sign_bit,LOCAL_EX(%a0)
is_pos:
	fmovemx (%a0),%d0		|move to correct register
|
|	if fp0-fp3 is being modified, we must put a copy
|	in the USER_FPn variable on the stack because all exception
|	handlers restore fp0-fp3 from there.
|
	cmpb	#0x80,%d0
	bnes	not_fp0
	fmovemx %fp0-%fp0,USER_FP0(%a6)
	rts
not_fp0:
	cmpb	#0x40,%d0
	bnes	not_fp1
	fmovemx %fp1-%fp1,USER_FP1(%a6)
	rts
not_fp1:
	cmpb	#0x20,%d0
	bnes	not_fp2
	fmovemx %fp2-%fp2,USER_FP2(%a6)
	rts
not_fp2:
	cmpb	#0x10,%d0
	bnes	not_fp3
	fmovemx %fp3-%fp3,USER_FP3(%a6)
	rts
not_fp3:
	rts

E1_sto:
	bsrl	g_opcls		|returns opclass in d0
	cmpib	#3,%d0
	beq	opc011		|branch if opclass 3
	movel	CMDREG1B(%a6),%d0
	bfextu	%d0{#6:#3},%d0	|extract destination register
	bras	sto_fp

opc011:
	bsrl	g_dfmtou	|returns dest format in d0
|				;ext=00, sgl=01, dbl=10
	movel	%a0,%a1		|save source addr in a1
	movel	EXC_EA(%a6),%a0	|get the address
	cmpil	#0,%d0		|if dest format is extended
	beq	dest_ext	|then branch
	cmpil	#1,%d0		|if dest format is single
	beq	dest_sgl	|then branch
|
|	fall through to dest_dbl
|

|
|	dest_dbl --- write double precision value to user space
|
|Input
|	a0 -> destination address
|	a1 -> source in extended precision
|Output
|	a0 -> destroyed
|	a1 -> destroyed
|	d0 -> 0
|
|Changes extended precision to double precision.
| Note: no attempt is made to round the extended value to double.
|	dbl_sign = ext_sign
|	dbl_exp = ext_exp - $3fff(ext bias) + $7ff(dbl bias)
|	get rid of ext integer bit
|	dbl_mant = ext_mant{62:12}
|
|		---------------   ---------------    ---------------
|  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |
|		---------------   ---------------    ---------------
|		 95	    64    63 62	      32      31     11	  0
|				     |			     |
|				     |			     |
|				     |			     |
|			             v			     v
|			      ---------------   ---------------
|  double   ->		      |s|exp| mant  |   |  mant       |
|			      ---------------   ---------------
|			      63     51   32   31	       0
|
dest_dbl:
	clrl	%d0		|clear d0
	movew	LOCAL_EX(%a1),%d0	|get exponent
	subw	#0x3fff,%d0	|subtract extended precision bias
	cmpw	#0x4000,%d0	|check if inf
	beqs	inf		|if so, special case
	addw	#0x3ff,%d0	|add double precision bias
	swap	%d0		|d0 now in upper word
	lsll	#4,%d0		|d0 now in proper place for dbl prec exp
	tstb	LOCAL_SGN(%a1)
	beqs	get_mant	|if positive, go process mantissa
	bsetl	#31,%d0		|if negative, put in sign information
|				; before continuing
	bras	get_mant	|go process mantissa
inf:
	movel	#0x7ff00000,%d0	|load dbl inf exponent
	clrl	LOCAL_HI(%a1)	|clear msb
	tstb	LOCAL_SGN(%a1)
	beqs	dbl_inf		|if positive, go ahead and write it
	bsetl	#31,%d0		|if negative put in sign information
dbl_inf:
	movel	%d0,LOCAL_EX(%a1)	|put the new exp back on the stack
	bras	dbl_wrt
get_mant:
	movel	LOCAL_HI(%a1),%d1	|get ms mantissa
	bfextu	%d1{#1:#20},%d1	|get upper 20 bits of ms
	orl	%d1,%d0		|put these bits in ms word of double
	movel	%d0,LOCAL_EX(%a1)	|put the new exp back on the stack
	movel	LOCAL_HI(%a1),%d1	|get ms mantissa
	movel	#21,%d0		|load shift count
	lsll	%d0,%d1		|put lower 11 bits in upper bits
	movel	%d1,LOCAL_HI(%a1)	|build lower lword in memory
	movel	LOCAL_LO(%a1),%d1	|get ls mantissa
	bfextu	%d1{#0:#21},%d0	|get ls 21 bits of double
	orl	%d0,LOCAL_HI(%a1)	|put them in double result
dbl_wrt:
	movel	#0x8,%d0		|byte count for double precision number
	exg	%a0,%a1		|a0=supervisor source, a1=user dest
	bsrl	mem_write	|move the number to the user's memory
	rts
|
|	dest_sgl --- write single precision value to user space
|
|Input
|	a0 -> destination address
|	a1 -> source in extended precision
|
|Output
|	a0 -> destroyed
|	a1 -> destroyed
|	d0 -> 0
|
|Changes extended precision to single precision.
|	sgl_sign = ext_sign
|	sgl_exp = ext_exp - $3fff(ext bias) + $7f(sgl bias)
|	get rid of ext integer bit
|	sgl_mant = ext_mant{62:12}
|
|		---------------   ---------------    ---------------
|  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |
|		---------------   ---------------    ---------------
|		 95	    64    63 62	   40 32      31     12	  0
|				     |	   |
|				     |	   |
|				     |	   |
|			             v     v
|			      ---------------
|  single   ->		      |s|exp| mant  |
|			      ---------------
|			      31     22     0
|
dest_sgl:
	clrl	%d0
	movew	LOCAL_EX(%a1),%d0	|get exponent
	subw	#0x3fff,%d0	|subtract extended precision bias
	cmpw	#0x4000,%d0	|check if inf
	beqs	sinf		|if so, special case
	addw	#0x7f,%d0		|add single precision bias
	swap	%d0		|put exp in upper word of d0
	lsll	#7,%d0		|shift it into single exp bits
	tstb	LOCAL_SGN(%a1)
	beqs	get_sman	|if positive, continue
	bsetl	#31,%d0		|if negative, put in sign first
	bras	get_sman	|get mantissa
sinf:
	movel	#0x7f800000,%d0	|load single inf exp to d0
	tstb	LOCAL_SGN(%a1)
	beqs	sgl_wrt		|if positive, continue
	bsetl	#31,%d0		|if negative, put in sign info
	bras	sgl_wrt

get_sman:
	movel	LOCAL_HI(%a1),%d1	|get ms mantissa
	bfextu	%d1{#1:#23},%d1	|get upper 23 bits of ms
	orl	%d1,%d0		|put these bits in ms word of single

sgl_wrt:
	movel	%d0,L_SCR1(%a6)	|put the new exp back on the stack
	movel	#0x4,%d0		|byte count for single precision number
	tstl	%a0		|users destination address
	beqs	sgl_Dn		|destination is a data register
	exg	%a0,%a1		|a0=supervisor source, a1=user dest
	leal	L_SCR1(%a6),%a0	|point a0 to data
	bsrl	mem_write	|move the number to the user's memory
	rts
sgl_Dn:
	bsrl	get_fline	|returns fline word in d0
	andw	#0x7,%d0		|isolate register number
	movel	%d0,%d1		|d1 has size:reg formatted for reg_dest
	orl	#0x10,%d1		|reg_dest wants size added to reg#
	bral	reg_dest	|size is X, rts in reg_dest will
|				;return to caller of dest_sgl

dest_ext:
	tstb	LOCAL_SGN(%a1)	|put back sign into exponent word
	beqs	dstx_cont
	bsetb	#sign_bit,LOCAL_EX(%a1)
dstx_cont:
	clrb	LOCAL_SGN(%a1)	|clear out the sign byte

	movel	#0x0c,%d0		|byte count for extended number
	exg	%a0,%a1		|a0=supervisor source, a1=user dest
	bsrl	mem_write	|move the number to the user's memory
	rts

	|end