xref: /openbmc/linux/arch/m68k/fpsp040/x_operr.S (revision 2a598d0b)
1|
2|	x_operr.sa 3.5 7/1/91
3|
4|	fpsp_operr --- FPSP handler for operand error exception
5|
6|	See 68040 User's Manual pp. 9-44f
7|
8| Note 1: For trap disabled 040 does the following:
9| If the dest is a fp reg, then an extended precision non_signaling
10| NAN is stored in the dest reg.  If the dest format is b, w, or l and
11| the source op is a NAN, then garbage is stored as the result (actually
12| the upper 32 bits of the mantissa are sent to the integer unit). If
13| the dest format is integer (b, w, l) and the operr is caused by
14| integer overflow, or the source op is inf, then the result stored is
15| garbage.
16| There are three cases in which operr is incorrectly signaled on the
17| 040.  This occurs for move_out of format b, w, or l for the largest
18| negative integer (-2^7 for b, -2^15 for w, -2^31 for l).
19|
20|	  On opclass = 011 fmove.(b,w,l) that causes a conversion
21|	  overflow -> OPERR, the exponent in wbte (and fpte) is:
22|		byte    56 - (62 - exp)
23|		word    48 - (62 - exp)
24|		long    32 - (62 - exp)
25|
26|			where exp = (true exp) - 1
27|
28|  So, wbtemp and fptemp will contain the following on erroneously
29|	  signalled operr:
30|			fpts = 1
31|			fpte = $4000  (15 bit externally)
32|		byte	fptm = $ffffffff ffffff80
33|		word	fptm = $ffffffff ffff8000
34|		long	fptm = $ffffffff 80000000
35|
36| Note 2: For trap enabled 040 does the following:
37| If the inst is move_out, then same as Note 1.
38| If the inst is not move_out, the dest is not modified.
39| The exceptional operand is not defined for integer overflow
40| during a move_out.
41|
42
43|		Copyright (C) Motorola, Inc. 1990
44|			All Rights Reserved
45|
46|       For details on the license for this file, please see the
47|       file, README, in this same directory.
48
49X_OPERR:	|idnt    2,1 | Motorola 040 Floating Point Software Package
50
51	|section	8
52
53#include "fpsp.h"
54
55	|xref	mem_write
56	|xref	real_operr
57	|xref	real_inex
58	|xref	get_fline
59	|xref	fpsp_done
60	|xref	reg_dest
61
62	.global	fpsp_operr
63fpsp_operr:
64|
65	link		%a6,#-LOCAL_SIZE
66	fsave		-(%a7)
67	moveml		%d0-%d1/%a0-%a1,USER_DA(%a6)
68	fmovemx	%fp0-%fp3,USER_FP0(%a6)
69	fmoveml	%fpcr/%fpsr/%fpiar,USER_FPCR(%a6)
70
71|
72| Check if this is an opclass 3 instruction.
73|  If so, fall through, else branch to operr_end
74|
75	btstb	#TFLAG,T_BYTE(%a6)
76	beqs	operr_end
77
78|
79| If the destination size is B,W,or L, the operr must be
80| handled here.
81|
82	movel	CMDREG1B(%a6),%d0
83	bfextu	%d0{#3:#3},%d0	|0=long, 4=word, 6=byte
84	cmpib	#0,%d0		|determine size; check long
85	beq	operr_long
86	cmpib	#4,%d0		|check word
87	beq	operr_word
88	cmpib	#6,%d0		|check byte
89	beq	operr_byte
90
91|
92| The size is not B,W,or L, so the operr is handled by the
93| kernel handler.  Set the operr bits and clean up, leaving
94| only the integer exception frame on the stack, and the
95| fpu in the original exceptional state.
96|
97operr_end:
98	bsetb		#operr_bit,FPSR_EXCEPT(%a6)
99	bsetb		#aiop_bit,FPSR_AEXCEPT(%a6)
100
101	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
102	fmovemx	USER_FP0(%a6),%fp0-%fp3
103	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
104	frestore	(%a7)+
105	unlk		%a6
106	bral		real_operr
107
108operr_long:
109	moveql	#4,%d1		|write size to d1
110	moveb	STAG(%a6),%d0	|test stag for nan
111	andib	#0xe0,%d0		|clr all but tag
112	cmpib	#0x60,%d0		|check for nan
113	beq	operr_nan
114	cmpil	#0x80000000,FPTEMP_LO(%a6) |test if ls lword is special
115	bnes	chklerr		|if not equal, check for incorrect operr
116	bsr	check_upper	|check if exp and ms mant are special
117	tstl	%d0
118	bnes	chklerr		|if d0 is true, check for incorrect operr
119	movel	#0x80000000,%d0	|store special case result
120	bsr	operr_store
121	bra	not_enabled	|clean and exit
122|
123|	CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE
124|
125chklerr:
126	movew	FPTEMP_EX(%a6),%d0
127	andw	#0x7FFF,%d0	|ignore sign bit
128	cmpw	#0x3FFE,%d0	|this is the only possible exponent value
129	bnes	chklerr2
130fixlong:
131	movel	FPTEMP_LO(%a6),%d0
132	bsr	operr_store
133	bra	not_enabled
134chklerr2:
135	movew	FPTEMP_EX(%a6),%d0
136	andw	#0x7FFF,%d0	|ignore sign bit
137	cmpw	#0x4000,%d0
138	bcc	store_max	|exponent out of range
139
140	movel	FPTEMP_LO(%a6),%d0
141	andl	#0x7FFF0000,%d0	|look for all 1's on bits 30-16
142	cmpl	#0x7FFF0000,%d0
143	beqs	fixlong
144
145	tstl	FPTEMP_LO(%a6)
146	bpls	chklepos
147	cmpl	#0xFFFFFFFF,FPTEMP_HI(%a6)
148	beqs	fixlong
149	bra	store_max
150chklepos:
151	tstl	FPTEMP_HI(%a6)
152	beqs	fixlong
153	bra	store_max
154
155operr_word:
156	moveql	#2,%d1		|write size to d1
157	moveb	STAG(%a6),%d0	|test stag for nan
158	andib	#0xe0,%d0		|clr all but tag
159	cmpib	#0x60,%d0		|check for nan
160	beq	operr_nan
161	cmpil	#0xffff8000,FPTEMP_LO(%a6) |test if ls lword is special
162	bnes	chkwerr		|if not equal, check for incorrect operr
163	bsr	check_upper	|check if exp and ms mant are special
164	tstl	%d0
165	bnes	chkwerr		|if d0 is true, check for incorrect operr
166	movel	#0x80000000,%d0	|store special case result
167	bsr	operr_store
168	bra	not_enabled	|clean and exit
169|
170|	CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE
171|
172chkwerr:
173	movew	FPTEMP_EX(%a6),%d0
174	andw	#0x7FFF,%d0	|ignore sign bit
175	cmpw	#0x3FFE,%d0	|this is the only possible exponent value
176	bnes	store_max
177	movel	FPTEMP_LO(%a6),%d0
178	swap	%d0
179	bsr	operr_store
180	bra	not_enabled
181
182operr_byte:
183	moveql	#1,%d1		|write size to d1
184	moveb	STAG(%a6),%d0	|test stag for nan
185	andib	#0xe0,%d0		|clr all but tag
186	cmpib	#0x60,%d0		|check for nan
187	beqs	operr_nan
188	cmpil	#0xffffff80,FPTEMP_LO(%a6) |test if ls lword is special
189	bnes	chkberr		|if not equal, check for incorrect operr
190	bsr	check_upper	|check if exp and ms mant are special
191	tstl	%d0
192	bnes	chkberr		|if d0 is true, check for incorrect operr
193	movel	#0x80000000,%d0	|store special case result
194	bsr	operr_store
195	bra	not_enabled	|clean and exit
196|
197|	CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE
198|
199chkberr:
200	movew	FPTEMP_EX(%a6),%d0
201	andw	#0x7FFF,%d0	|ignore sign bit
202	cmpw	#0x3FFE,%d0	|this is the only possible exponent value
203	bnes	store_max
204	movel	FPTEMP_LO(%a6),%d0
205	asll	#8,%d0
206	swap	%d0
207	bsr	operr_store
208	bra	not_enabled
209
210|
211| This operr condition is not of the special case.  Set operr
212| and aiop and write the portion of the nan to memory for the
213| given size.
214|
215operr_nan:
216	orl	#opaop_mask,USER_FPSR(%a6) |set operr & aiop
217
218	movel	ETEMP_HI(%a6),%d0	|output will be from upper 32 bits
219	bsr	operr_store
220	bra	end_operr
221|
222| Store_max loads the max pos or negative for the size, sets
223| the operr and aiop bits, and clears inex and ainex, incorrectly
224| set by the 040.
225|
226store_max:
227	orl	#opaop_mask,USER_FPSR(%a6) |set operr & aiop
228	bclrb	#inex2_bit,FPSR_EXCEPT(%a6)
229	bclrb	#ainex_bit,FPSR_AEXCEPT(%a6)
230	fmovel	#0,%FPSR
231
232	tstw	FPTEMP_EX(%a6)	|check sign
233	blts	load_neg
234	movel	#0x7fffffff,%d0
235	bsr	operr_store
236	bra	end_operr
237load_neg:
238	movel	#0x80000000,%d0
239	bsr	operr_store
240	bra	end_operr
241
242|
243| This routine stores the data in d0, for the given size in d1,
244| to memory or data register as required.  A read of the fline
245| is required to determine the destination.
246|
247operr_store:
248	movel	%d0,L_SCR1(%a6)	|move write data to L_SCR1
249	movel	%d1,-(%a7)	|save register size
250	bsrl	get_fline	|fline returned in d0
251	movel	(%a7)+,%d1
252	bftst	%d0{#26:#3}		|if mode is zero, dest is Dn
253	bnes	dest_mem
254|
255| Destination is Dn.  Get register number from d0. Data is on
256| the stack at (a7). D1 has size: 1=byte,2=word,4=long/single
257|
258	andil	#7,%d0		|isolate register number
259	cmpil	#4,%d1
260	beqs	op_long		|the most frequent case
261	cmpil	#2,%d1
262	bnes	op_con
263	orl	#8,%d0
264	bras	op_con
265op_long:
266	orl	#0x10,%d0
267op_con:
268	movel	%d0,%d1		|format size:reg for reg_dest
269	bral	reg_dest	|call to reg_dest returns to caller
270|				;of operr_store
271|
272| Destination is memory.  Get <ea> from integer exception frame
273| and call mem_write.
274|
275dest_mem:
276	leal	L_SCR1(%a6),%a0	|put ptr to write data in a0
277	movel	EXC_EA(%a6),%a1	|put user destination address in a1
278	movel	%d1,%d0		|put size in d0
279	bsrl	mem_write
280	rts
281|
282| Check the exponent for $c000 and the upper 32 bits of the
283| mantissa for $ffffffff.  If both are true, return d0 clr
284| and store the lower n bits of the least lword of FPTEMP
285| to d0 for write out.  If not, it is a real operr, and set d0.
286|
287check_upper:
288	cmpil	#0xffffffff,FPTEMP_HI(%a6) |check if first byte is all 1's
289	bnes	true_operr	|if not all 1's then was true operr
290	cmpiw	#0xc000,FPTEMP_EX(%a6) |check if incorrectly signalled
291	beqs	not_true_operr	|branch if not true operr
292	cmpiw	#0xbfff,FPTEMP_EX(%a6) |check if incorrectly signalled
293	beqs	not_true_operr	|branch if not true operr
294true_operr:
295	movel	#1,%d0		|signal real operr
296	rts
297not_true_operr:
298	clrl	%d0		|signal no real operr
299	rts
300
301|
302| End_operr tests for operr enabled.  If not, it cleans up the stack
303| and does an rte.  If enabled, it cleans up the stack and branches
304| to the kernel operr handler with only the integer exception
305| frame on the stack and the fpu in the original exceptional state
306| with correct data written to the destination.
307|
308end_operr:
309	btstb		#operr_bit,FPCR_ENABLE(%a6)
310	beqs		not_enabled
311enabled:
312	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
313	fmovemx	USER_FP0(%a6),%fp0-%fp3
314	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
315	frestore	(%a7)+
316	unlk		%a6
317	bral		real_operr
318
319not_enabled:
320|
321| It is possible to have either inex2 or inex1 exceptions with the
322| operr.  If the inex enable bit is set in the FPCR, and either
323| inex2 or inex1 occurred, we must clean up and branch to the
324| real inex handler.
325|
326ck_inex:
327	moveb	FPCR_ENABLE(%a6),%d0
328	andb	FPSR_EXCEPT(%a6),%d0
329	andib	#0x3,%d0
330	beq	operr_exit
331|
332| Inexact enabled and reported, and we must take an inexact exception.
333|
334take_inex:
335	moveb		#INEX_VEC,EXC_VEC+1(%a6)
336	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
337	orl		#sx_mask,E_BYTE(%a6)
338	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
339	fmovemx	USER_FP0(%a6),%fp0-%fp3
340	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
341	frestore	(%a7)+
342	unlk		%a6
343	bral		real_inex
344|
345| Since operr is only an E1 exception, there is no need to frestore
346| any state back to the fpu.
347|
348operr_exit:
349	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
350	fmovemx	USER_FP0(%a6),%fp0-%fp3
351	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
352	unlk		%a6
353	bral		fpsp_done
354
355	|end
356