summaryrefslogtreecommitdiff
path: root/sys/arch/m68k/fpsp/x_operr.sa
blob: dec7e6365760d5ea0a41a39fa23ce1fd6f1af531 (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
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
*	$OpenBSD: x_operr.sa,v 1.2 1996/05/29 21:05:47 niklas Exp $
*	$NetBSD: x_operr.sa,v 1.4 1994/10/26 07:50:24 cgd Exp $

*	MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
*	M68000 Hi-Performance Microprocessor Division
*	M68040 Software Package 
*
*	M68040 Software Package Copyright (c) 1993, 1994 Motorola Inc.
*	All rights reserved.
*
*	THE SOFTWARE is provided on an "AS IS" basis and without warranty.
*	To the maximum extent permitted by applicable law,
*	MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
*	INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
*	PARTICULAR PURPOSE and any warranty against infringement with
*	regard to the SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF)
*	and any accompanying written materials. 
*
*	To the maximum extent permitted by applicable law,
*	IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
*	(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS
*	PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR
*	OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE
*	SOFTWARE.  Motorola assumes no responsibility for the maintenance
*	and support of the SOFTWARE.  
*
*	You are hereby granted a copyright license to use, modify, and
*	distribute the SOFTWARE so long as this entire notice is retained
*	without alteration in any modified and/or redistributed versions,
*	and that such modified versions are clearly identified as such.
*	No licenses are granted by implication, estoppel or otherwise
*	under any patents or trademarks of Motorola, Inc.

*
*	x_operr.sa 3.5 7/1/91
*
*	fpsp_operr --- FPSP handler for operand error exception
*
*	See 68040 User's Manual pp. 9-44f
*
* Note 1: For trap disabled 040 does the following:
* If the dest is a fp reg, then an extended precision non_signaling
* NAN is stored in the dest reg.  If the dest format is b, w, or l and
* the source op is a NAN, then garbage is stored as the result (actually
* the upper 32 bits of the mantissa are sent to the integer unit). If
* the dest format is integer (b, w, l) and the operr is caused by
* integer overflow, or the source op is inf, then the result stored is
* garbage.
* There are three cases in which operr is incorrectly signaled on the 
* 040.  This occurs for move_out of format b, w, or l for the largest 
* negative integer (-2^7 for b, -2^15 for w, -2^31 for l).
*
*	  On opclass = 011 fmove.(b,w,l) that causes a conversion
*	  overflow -> OPERR, the exponent in wbte (and fpte) is:
*		byte    56 - (62 - exp)
*		word    48 - (62 - exp)
*		long    32 - (62 - exp)
*
*			where exp = (true exp) - 1
*
*  So, wbtemp and fptemp will contain the following on erroneoulsy
*	  signalled operr:
*			fpts = 1
*			fpte = $4000  (15 bit externally)
*		byte	fptm = $ffffffff ffffff80
*		word	fptm = $ffffffff ffff8000
*		long	fptm = $ffffffff 80000000
*
* Note 2: For trap enabled 040 does the following:
* If the inst is move_out, then same as Note 1.
* If the inst is not move_out, the dest is not modified.
* The exceptional operand is not defined for integer overflow 
* during a move_out.
*

X_OPERR	IDNT    2,1 Motorola 040 Floating Point Software Package

	section	8

	include	fpsp.h

	xref	mem_write
	xref	real_operr
	xref	real_inex
	xref	get_fline
	xref	fpsp_done
	xref	reg_dest

	xdef	fpsp_operr
fpsp_operr:
*
	link		a6,#-LOCAL_SIZE
	fsave		-(a7)
	movem.l		d0-d1/a0-a1,USER_DA(a6)
	fmovem.x	fp0-fp3,USER_FP0(a6)
	fmovem.l	fpcr/fpsr/fpiar,USER_FPCR(a6)

*
* Check if this is an opclass 3 instruction.
*  If so, fall through, else branch to operr_end
*
	btst.b	#TFLAG,T_BYTE(a6)
	beq.b	operr_end

*
* If the destination size is B,W,or L, the operr must be 
* handled here.
*
	move.l	CMDREG1B(a6),d0
	bfextu	d0{3:3},d0	;0=long, 4=word, 6=byte
	tst.b	d0		;determine size; check long
	beq.w	operr_long
	cmpi.b	#4,d0		;check word
	beq.w	operr_word
	cmpi.b	#6,d0		;check byte
	beq.w	operr_byte

*
* The size is not B,W,or L, so the operr is handled by the 
* kernel handler.  Set the operr bits and clean up, leaving
* only the integer exception frame on the stack, and the 
* fpu in the original exceptional state.
*
operr_end:
	bset.b		#operr_bit,FPSR_EXCEPT(a6)
	bset.b		#aiop_bit,FPSR_AEXCEPT(a6)

	movem.l		USER_DA(a6),d0-d1/a0-a1
	fmovem.x	USER_FP0(a6),fp0-fp3
	fmovem.l	USER_FPCR(a6),fpcr/fpsr/fpiar
	frestore	(a7)+
	unlk		a6
	bra.l		real_operr

operr_long:
	moveq.l	#4,d1		;write size to d1
	move.b	STAG(a6),d0	;test stag for nan
	andi.b	#$e0,d0		;clr all but tag
	cmpi.b	#$60,d0		;check for nan
	beq	operr_nan	
	cmpi.l	#$80000000,FPTEMP_LO(a6) ;test if ls lword is special
	bne.b	chklerr		;if not equal, check for incorrect operr
	bsr	check_upper	;check if exp and ms mant are special
	tst.l	d0
	bne.b	chklerr		;if d0 is true, check for incorrect operr
	move.l	#$80000000,d0	;store special case result
	bsr	operr_store
	bra.w	not_enabled	;clean and exit
*
*	CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE
*
chklerr:
	move.w	FPTEMP_EX(a6),d0
	and.w	#$7FFF,d0	;ignore sign bit
	cmp.w	#$3FFE,d0	;this is the only possible exponent value
	bne.b	chklerr2
fixlong:
	move.l	FPTEMP_LO(a6),d0
	bsr	operr_store
	bra.w	not_enabled
chklerr2:
	move.w	FPTEMP_EX(a6),d0
	and.w	#$7FFF,d0	;ignore sign bit
	cmp.w	#$4000,d0
	bcc.w	store_max	;exponent out of range

	move.l	FPTEMP_LO(a6),d0
	and.l	#$7FFF0000,d0	;look for all 1's on bits 30-16
	cmp.l	#$7FFF0000,d0
	beq.b	fixlong

	tst.l	FPTEMP_LO(a6)
	bpl.b	chklepos
	cmp.l	#$FFFFFFFF,FPTEMP_HI(a6)
	beq.b	fixlong
	bra.w	store_max
chklepos:
	tst.l	FPTEMP_HI(a6)
	beq.b	fixlong
	bra.w	store_max

operr_word:
	moveq.l	#2,d1		;write size to d1
	move.b	STAG(a6),d0	;test stag for nan
	andi.b	#$e0,d0		;clr all but tag
	cmpi.b	#$60,d0		;check for nan
	beq.w	operr_nan	
	cmpi.l	#$ffff8000,FPTEMP_LO(a6) ;test if ls lword is special
	bne.b	chkwerr		;if not equal, check for incorrect operr
	bsr	check_upper	;check if exp and ms mant are special
	tst.l	d0
	bne.b	chkwerr		;if d0 is true, check for incorrect operr
	move.l	#$80000000,d0	;store special case result
	bsr	operr_store
	bra.w	not_enabled	;clean and exit
*
*	CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE
*
chkwerr:
	move.w	FPTEMP_EX(a6),d0
	and.w	#$7FFF,d0	;ignore sign bit
	cmp.w	#$3FFE,d0	;this is the only possible exponent value
	bne.b	store_max
	move.l	FPTEMP_LO(a6),d0
	swap	d0
	bsr	operr_store
	bra.w	not_enabled

operr_byte:
	moveq.l	#1,d1		;write size to d1
	move.b	STAG(a6),d0	;test stag for nan
	andi.b	#$e0,d0		;clr all but tag
	cmpi.b	#$60,d0		;check for nan
	beq.b	operr_nan	
	cmpi.l	#$ffffff80,FPTEMP_LO(a6) ;test if ls lword is special
	bne.b	chkberr		;if not equal, check for incorrect operr
	bsr	check_upper	;check if exp and ms mant are special
	tst.l	d0
	bne.b	chkberr		;if d0 is true, check for incorrect operr
	move.l	#$80000000,d0	;store special case result
	bsr	operr_store
	bra.w	not_enabled	;clean and exit
*
*	CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE
*
chkberr:
	move.w	FPTEMP_EX(a6),d0
	and.w	#$7FFF,d0	;ignore sign bit
	cmp.w	#$3FFE,d0	;this is the only possible exponent value
	bne.b	store_max
	move.l	FPTEMP_LO(a6),d0
	asl.l	#8,d0
	swap	d0
	bsr	operr_store
	bra.w	not_enabled

*
* This operr condition is not of the special case.  Set operr
* and aiop and write the portion of the nan to memory for the
* given size.
*
operr_nan:
	or.l	#opaop_mask,USER_FPSR(a6) ;set operr & aiop

	move.l	ETEMP_HI(a6),d0	;output will be from upper 32 bits
	bsr	operr_store
	bra	end_operr
*
* Store_max loads the max pos or negative for the size, sets
* the operr and aiop bits, and clears inex and ainex, incorrectly
* set by the 040.
*
store_max:
	or.l	#opaop_mask,USER_FPSR(a6) ;set operr & aiop
	bclr.b	#inex2_bit,FPSR_EXCEPT(a6)
	bclr.b	#ainex_bit,FPSR_AEXCEPT(a6)
	fmove.l	#0,FPSR
	
	tst.w	FPTEMP_EX(a6)	;check sign
	blt.b	load_neg
	move.l	#$7fffffff,d0
	bsr	operr_store
	bra	end_operr
load_neg:
	move.l	#$80000000,d0
	bsr	operr_store
	bra	end_operr

*
* This routine stores the data in d0, for the given size in d1,
* to memory or data register as required.  A read of the fline
* is required to determine the destination.
*
operr_store:
	move.l	d0,L_SCR1(a6)	;move write data to L_SCR1
	move.l	d1,-(a7)	;save register size
	bsr.l	get_fline	;fline returned in d0
	move.l	(a7)+,d1
	bftst	d0{26:3}		;if mode is zero, dest is Dn
	bne.b	dest_mem
*
* Destination is Dn.  Get register number from d0. Data is on
* the stack at (a7). D1 has size: 1=byte,2=word,4=long/single
*
	andi.l	#7,d0		;isolate register number
	cmpi.l	#4,d1
	beq.b	op_long		;the most frequent case
	cmpi.l	#2,d1
	bne.b	op_con
	or.l	#8,d0
	bra.b	op_con
op_long:
	or.l	#$10,d0
op_con:
	move.l	d0,d1		;format size:reg for reg_dest
	bra.l	reg_dest	;call to reg_dest returns to caller
*				;of operr_store
*
* Destination is memory.  Get <ea> from integer exception frame
* and call mem_write.
*
dest_mem:
	lea.l	L_SCR1(a6),a0	;put ptr to write data in a0
	move.l	EXC_EA(a6),a1	;put user destination address in a1
	move.l	d1,d0		;put size in d0
	bsr.l	mem_write
	rts
*
* Check the exponent for $c000 and the upper 32 bits of the 
* mantissa for $ffffffff.  If both are true, return d0 clr
* and store the lower n bits of the least lword of FPTEMP
* to d0 for write out.  If not, it is a real operr, and set d0.
*
check_upper:
	cmpi.l	#$ffffffff,FPTEMP_HI(a6) ;check if first byte is all 1's
	bne.b	true_operr	;if not all 1's then was true operr
	cmpi.w	#$c000,FPTEMP_EX(a6) ;check if incorrectly signalled
	beq.b	not_true_operr	;branch if not true operr
	cmpi.w	#$bfff,FPTEMP_EX(a6) ;check if incorrectly signalled
	beq.b	not_true_operr	;branch if not true operr
true_operr:
	move.l	#1,d0		;signal real operr
	rts
not_true_operr:
	clr.l	d0		;signal no real operr
	rts

*
* End_operr tests for operr enabled.  If not, it cleans up the stack
* and does an rte.  If enabled, it cleans up the stack and branches
* to the kernel operr handler with only the integer exception
* frame on the stack and the fpu in the original exceptional state
* with correct data written to the destination.
*
end_operr:
	btst.b		#operr_bit,FPCR_ENABLE(a6)
	beq.b		not_enabled
enabled:
	movem.l		USER_DA(a6),d0-d1/a0-a1
	fmovem.x	USER_FP0(a6),fp0-fp3
	fmovem.l	USER_FPCR(a6),fpcr/fpsr/fpiar
	frestore	(a7)+
	unlk		a6
	bra.l		real_operr

not_enabled:
*
* It is possible to have either inex2 or inex1 exceptions with the
* operr.  If the inex enable bit is set in the FPCR, and either
* inex2 or inex1 occured, we must clean up and branch to the
* real inex handler.
*
ck_inex:
	move.b	FPCR_ENABLE(a6),d0
	and.b	FPSR_EXCEPT(a6),d0
	andi.b	#$3,d0
	beq.w	operr_exit
*
* Inexact enabled and reported, and we must take an inexact exception.
*
take_inex:
	move.b		#INEX_VEC,EXC_VEC+1(a6)
	move.l		USER_FPSR(a6),FPSR_SHADOW(a6)
	or.l		#sx_mask,E_BYTE(a6)
	movem.l		USER_DA(a6),d0-d1/a0-a1
	fmovem.x	USER_FP0(a6),fp0-fp3
	fmovem.l	USER_FPCR(a6),fpcr/fpsr/fpiar
	frestore	(a7)+
	unlk		a6
	bra.l		real_inex
*
* Since operr is only an E1 exception, there is no need to frestore
* any state back to the fpu.
*
operr_exit:
	movem.l		USER_DA(a6),d0-d1/a0-a1
	fmovem.x	USER_FP0(a6),fp0-fp3
	fmovem.l	USER_FPCR(a6),fpcr/fpsr/fpiar
	unlk		a6
	bra.l		fpsp_done

	end