xref: /netbsd/sys/arch/m68k/fpsp/round.sa (revision bf9ec67e)
1*	$NetBSD: round.sa,v 1.3 1994/10/26 07:49:24 cgd Exp $
2
3*	MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
4*	M68000 Hi-Performance Microprocessor Division
5*	M68040 Software Package
6*
7*	M68040 Software Package Copyright (c) 1993, 1994 Motorola Inc.
8*	All rights reserved.
9*
10*	THE SOFTWARE is provided on an "AS IS" basis and without warranty.
11*	To the maximum extent permitted by applicable law,
12*	MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
13*	INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
14*	PARTICULAR PURPOSE and any warranty against infringement with
15*	regard to the SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF)
16*	and any accompanying written materials.
17*
18*	To the maximum extent permitted by applicable law,
19*	IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
20*	(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS
21*	PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR
22*	OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE
23*	SOFTWARE.  Motorola assumes no responsibility for the maintenance
24*	and support of the SOFTWARE.
25*
26*	You are hereby granted a copyright license to use, modify, and
27*	distribute the SOFTWARE so long as this entire notice is retained
28*	without alteration in any modified and/or redistributed versions,
29*	and that such modified versions are clearly identified as such.
30*	No licenses are granted by implication, estoppel or otherwise
31*	under any patents or trademarks of Motorola, Inc.
32
33*
34*	round.sa 3.4 7/29/91
35*
36*	handle rounding and normalization tasks
37*
38
39ROUND	IDNT    2,1 Motorola 040 Floating Point Software Package
40
41	section	8
42
43	include	fpsp.h
44
45*
46*	round --- round result according to precision/mode
47*
48*	a0 points to the input operand in the internal extended format
49*	d1(high word) contains rounding precision:
50*		ext = $0000xxxx
51*		sgl = $0001xxxx
52*		dbl = $0002xxxx
53*	d1(low word) contains rounding mode:
54*		RN  = $xxxx0000
55*		RZ  = $xxxx0001
56*		RM  = $xxxx0010
57*		RP  = $xxxx0011
58*	d0{31:29} contains the g,r,s bits (extended)
59*
60*	On return the value pointed to by a0 is correctly rounded,
61*	a0 is preserved and the g-r-s bits in d0 are cleared.
62*	The result is not typed - the tag field is invalid.  The
63*	result is still in the internal extended format.
64*
65*	The INEX bit of USER_FPSR will be set if the rounded result was
66*	inexact (i.e. if any of the g-r-s bits were set).
67*
68
69	xdef	round
70round:
71* If g=r=s=0 then result is exact and round is done, else set
72* the inex flag in status reg and continue.
73*
74	bsr.b	ext_grs			;this subroutine looks at the
75*					:rounding precision and sets
76*					;the appropriate g-r-s bits.
77	tst.l	d0			;if grs are zero, go force
78	bne.w	rnd_cont		;lower bits to zero for size
79
80	swap	d1			;set up d1.w for round prec.
81	bra.w	truncate
82
83rnd_cont:
84*
85* Use rounding mode as an index into a jump table for these modes.
86*
87	or.l	#inx2a_mask,USER_FPSR(a6) ;set inex2/ainex
88	lea	mode_tab,a1
89	move.l	(a1,d1.w*4),a1
90	jmp	(a1)
91*
92* Jump table indexed by rounding mode in d1.w.  All following assumes
93* grs != 0.
94*
95mode_tab:
96	dc.l	rnd_near
97	dc.l	rnd_zero
98	dc.l	rnd_mnus
99	dc.l	rnd_plus
100*
101*	ROUND PLUS INFINITY
102*
103*	If sign of fp number = 0 (positive), then add 1 to l.
104*
105rnd_plus:
106	swap 	d1			;set up d1 for round prec.
107	tst.b	LOCAL_SGN(a0)		;check for sign
108	bmi.w	truncate		;if positive then truncate
109	move.l	#$ffffffff,d0		;force g,r,s to be all f's
110	lea	add_to_l,a1
111	move.l	(a1,d1.w*4),a1
112	jmp	(a1)
113*
114*	ROUND MINUS INFINITY
115*
116*	If sign of fp number = 1 (negative), then add 1 to l.
117*
118rnd_mnus:
119	swap 	d1			;set up d1 for round prec.
120	tst.b	LOCAL_SGN(a0)		;check for sign
121	bpl.w	truncate		;if negative then truncate
122	move.l	#$ffffffff,d0		;force g,r,s to be all f's
123	lea	add_to_l,a1
124	move.l	(a1,d1.w*4),a1
125	jmp	(a1)
126*
127*	ROUND ZERO
128*
129*	Always truncate.
130rnd_zero:
131	swap 	d1			;set up d1 for round prec.
132	bra.w	truncate
133*
134*
135*	ROUND NEAREST
136*
137*	If (g=1), then add 1 to l and if (r=s=0), then clear l
138*	Note that this will round to even in case of a tie.
139*
140rnd_near:
141	swap 	d1			;set up d1 for round prec.
142	add.l	d0,d0			;shift g-bit to c-bit
143	bcc.w	truncate		;if (g=1) then
144	lea	add_to_l,a1
145	move.l	(a1,d1.w*4),a1
146	jmp	(a1)
147
148*
149*	ext_grs --- extract guard, round and sticky bits
150*
151* Input:	d1 =		PREC:ROUND
152* Output:  	d0{31:29}=	guard, round, sticky
153*
154* The ext_grs extract the guard/round/sticky bits according to the
155* selected rounding precision. It is called by the round subroutine
156* only.  All registers except d0 are kept intact. d0 becomes an
157* updated guard,round,sticky in d0{31:29}
158*
159* Notes: the ext_grs uses the round PREC, and therefore has to swap d1
160*	 prior to usage, and needs to restore d1 to original.
161*
162ext_grs:
163	swap	d1			;have d1.w point to round precision
164	tst.w	d1
165	bne.b	sgl_or_dbl
166	bra.b	end_ext_grs
167
168sgl_or_dbl:
169	movem.l	d2/d3,-(a7)		;make some temp registers
170	cmpi.w	#1,d1
171	bne.b	grs_dbl
172grs_sgl:
173	bfextu	LOCAL_HI(a0){24:2},d3	;sgl prec. g-r are 2 bits right
174	move.l	#30,d2			;of the sgl prec. limits
175	lsl.l	d2,d3			;shift g-r bits to MSB of d3
176	move.l	LOCAL_HI(a0),d2		;get word 2 for s-bit test
177	andi.l	#$0000003f,d2		;s bit is the or of all other
178	bne.b	st_stky			;bits to the right of g-r
179	tst.l	LOCAL_LO(a0)		;test lower mantissa
180	bne.b	st_stky			;if any are set, set sticky
181	tst.l	d0			;test original g,r,s
182	bne.b	st_stky			;if any are set, set sticky
183	bra.b	end_sd			;if words 3 and 4 are clr, exit
184grs_dbl:
185	bfextu	LOCAL_LO(a0){21:2},d3	;dbl-prec. g-r are 2 bits right
186	move.l	#30,d2			;of the dbl prec. limits
187	lsl.l	d2,d3			;shift g-r bits to the MSB of d3
188	move.l	LOCAL_LO(a0),d2		;get lower mantissa  for s-bit test
189	andi.l	#$000001ff,d2		;s bit is the or-ing of all
190	bne.b	st_stky			;other bits to the right of g-r
191	tst.l	d0			;test word original g,r,s
192	bne.b	st_stky			;if any are set, set sticky
193	bra.b	end_sd			;if clear, exit
194st_stky:
195	bset	#rnd_stky_bit,d3
196end_sd:
197	move.l	d3,d0			;return grs to d0
198	movem.l	(a7)+,d2/d3		;restore scratch registers
199end_ext_grs:
200	swap	d1			;restore d1 to original
201	rts
202
203********************  Local Equates
204ad_1_sgl equ	$00000100	constant to add 1 to l-bit in sgl prec
205ad_1_dbl equ	$00000800	constant to add 1 to l-bit in dbl prec
206
207
208*Jump table for adding 1 to the l-bit indexed by rnd prec
209
210add_to_l:
211	dc.l	add_ext
212	dc.l	add_sgl
213	dc.l	add_dbl
214	dc.l	add_dbl
215*
216*	ADD SINGLE
217*
218add_sgl:
219	add.l	#ad_1_sgl,LOCAL_HI(a0)
220	bcc.b	scc_clr			;no mantissa overflow
221	roxr.w  LOCAL_HI(a0)		;shift v-bit back in
222	roxr.w  LOCAL_HI+2(a0)		;shift v-bit back in
223	add.w	#$1,LOCAL_EX(a0)	;and incr exponent
224scc_clr:
225	tst.l	d0			;test for rs = 0
226	bne.b	sgl_done
227	andi.w  #$fe00,LOCAL_HI+2(a0)	;clear the l-bit
228sgl_done:
229	andi.l	#$ffffff00,LOCAL_HI(a0) ;truncate bits beyond sgl limit
230	clr.l	LOCAL_LO(a0)		;clear d2
231	rts
232
233*
234*	ADD EXTENDED
235*
236add_ext:
237	addq.l  #1,LOCAL_LO(a0)		;add 1 to l-bit
238	bcc.b	xcc_clr			;test for carry out
239	addq.l  #1,LOCAL_HI(a0)		;propogate carry
240	bcc.b	xcc_clr
241	roxr.w  LOCAL_HI(a0)		;mant is 0 so restore v-bit
242	roxr.w  LOCAL_HI+2(a0)		;mant is 0 so restore v-bit
243	roxr.w	LOCAL_LO(a0)
244	roxr.w	LOCAL_LO+2(a0)
245	add.w	#$1,LOCAL_EX(a0)	;and inc exp
246xcc_clr:
247	tst.l	d0			;test rs = 0
248	bne.b	add_ext_done
249	andi.b	#$fe,LOCAL_LO+3(a0)	;clear the l bit
250add_ext_done:
251	rts
252*
253*	ADD DOUBLE
254*
255add_dbl:
256	add.l	#ad_1_dbl,LOCAL_LO(a0)
257	bcc.b	dcc_clr
258	addq.l	#1,LOCAL_HI(a0)		;propogate carry
259	bcc.b	dcc_clr
260	roxr.w	LOCAL_HI(a0)		;mant is 0 so restore v-bit
261	roxr.w	LOCAL_HI+2(a0)		;mant is 0 so restore v-bit
262	roxr.w	LOCAL_LO(a0)
263	roxr.w	LOCAL_LO+2(a0)
264	add.w	#$1,LOCAL_EX(a0)	;incr exponent
265dcc_clr:
266	tst.l	d0			;test for rs = 0
267	bne.b	dbl_done
268	andi.w	#$f000,LOCAL_LO+2(a0)	;clear the l-bit
269
270dbl_done:
271	andi.l	#$fffff800,LOCAL_LO(a0) ;truncate bits beyond dbl limit
272	rts
273
274error:
275	rts
276*
277* Truncate all other bits
278*
279trunct:
280	dc.l	end_rnd
281	dc.l	sgl_done
282	dc.l	dbl_done
283	dc.l	dbl_done
284
285truncate:
286	lea	trunct,a1
287	move.l	(a1,d1.w*4),a1
288	jmp	(a1)
289
290end_rnd:
291	rts
292
293*
294*	NORMALIZE
295*
296* These routines (nrm_zero & nrm_set) normalize the unnorm.  This
297* is done by shifting the mantissa left while decrementing the
298* exponent.
299*
300* NRM_SET shifts and decrements until there is a 1 set in the integer
301* bit of the mantissa (msb in d1).
302*
303* NRM_ZERO shifts and decrements until there is a 1 set in the integer
304* bit of the mantissa (msb in d1) unless this would mean the exponent
305* would go less than 0.  In that case the number becomes a denorm - the
306* exponent (d0) is set to 0 and the mantissa (d1 & d2) is not
307* normalized.
308*
309* Note that both routines have been optimized (for the worst case) and
310* therefore do not have the easy to follow decrement/shift loop.
311*
312*	NRM_ZERO
313*
314*	Distance to first 1 bit in mantissa = X
315*	Distance to 0 from exponent = Y
316*	If X < Y
317*	Then
318*	  nrm_set
319*	Else
320*	  shift mantissa by Y
321*	  set exponent = 0
322*
323*input:
324*	FP_SCR1 = exponent, ms mantissa part, ls mantissa part
325*output:
326*	L_SCR1{4} = fpte15 or ete15 bit
327*
328	xdef	nrm_zero
329nrm_zero:
330	move.w	LOCAL_EX(a0),d0
331	cmp.w   #64,d0          ;see if exp > 64
332	bmi.b	d0_less
333	bsr	nrm_set		;exp > 64 so exp won't exceed 0
334	rts
335d0_less:
336	movem.l	d2/d3/d5/d6,-(a7)
337	move.l	LOCAL_HI(a0),d1
338	move.l	LOCAL_LO(a0),d2
339
340	bfffo	d1{0:32},d3	;get the distance to the first 1
341*				;in ms mant
342	beq.b	ms_clr		;branch if no bits were set
343	cmp.w	d3,d0		;of X>Y
344	bmi.b	greater		;then exp will go past 0 (neg) if
345*				;it is just shifted
346	bsr	nrm_set		;else exp won't go past 0
347	movem.l	(a7)+,d2/d3/d5/d6
348	rts
349greater:
350	move.l	d2,d6		;save ls mant in d6
351	lsl.l	d0,d2		;shift ls mant by count
352	lsl.l	d0,d1		;shift ms mant by count
353	move.l	#32,d5
354	sub.l	d0,d5		;make op a denorm by shifting bits
355	lsr.l	d5,d6		;by the number in the exp, then
356*				;set exp = 0.
357	or.l	d6,d1		;shift the ls mant bits into the ms mant
358	clr.l	d0		;same as if decremented exp to 0
359*				;while shifting
360	move.w	d0,LOCAL_EX(a0)
361	move.l	d1,LOCAL_HI(a0)
362	move.l	d2,LOCAL_LO(a0)
363	movem.l	(a7)+,d2/d3/d5/d6
364	rts
365ms_clr:
366	bfffo	d2{0:32},d3	;check if any bits set in ls mant
367	beq.b	all_clr		;branch if none set
368	add.w	#32,d3
369	cmp.w	d3,d0		;if X>Y
370	bmi.b	greater		;then branch
371	bsr	nrm_set		;else exp won't go past 0
372	movem.l	(a7)+,d2/d3/d5/d6
373	rts
374all_clr:
375	clr.w	LOCAL_EX(a0)	;no mantissa bits set. Set exp = 0.
376	movem.l	(a7)+,d2/d3/d5/d6
377	rts
378*
379*	NRM_SET
380*
381	xdef	nrm_set
382nrm_set:
383	move.l	d7,-(a7)
384	bfffo	LOCAL_HI(a0){0:32},d7 ;find first 1 in ms mant to d7)
385	beq.b	lower		;branch if ms mant is all 0's
386
387	move.l	d6,-(a7)
388
389	sub.w	d7,LOCAL_EX(a0)	;sub exponent by count
390	move.l	LOCAL_HI(a0),d0	;d0 has ms mant
391	move.l	LOCAL_LO(a0),d1 ;d1 has ls mant
392
393	lsl.l	d7,d0		;shift first 1 to j bit position
394	move.l	d1,d6		;copy ls mant into d6
395	lsl.l	d7,d6		;shift ls mant by count
396	move.l	d6,LOCAL_LO(a0)	;store ls mant into memory
397	moveq.l	#32,d6
398	sub.l	d7,d6		;continue shift
399	lsr.l	d6,d1		;shift off all bits but those that will
400*				;be shifted into ms mant
401	or.l	d1,d0		;shift the ls mant bits into the ms mant
402	move.l	d0,LOCAL_HI(a0)	;store ms mant into memory
403	movem.l	(a7)+,d7/d6	;restore registers
404	rts
405
406*
407* We get here if ms mant was = 0, and we assume ls mant has bits
408* set (otherwise this would have been tagged a zero not a denorm).
409*
410lower:
411	move.w	LOCAL_EX(a0),d0	;d0 has exponent
412	move.l	LOCAL_LO(a0),d1	;d1 has ls mant
413	sub.w	#32,d0		;account for ms mant being all zeros
414	bfffo	d1{0:32},d7	;find first 1 in ls mant to d7)
415	sub.w	d7,d0		;subtract shift count from exp
416	lsl.l	d7,d1		;shift first 1 to integer bit in ms mant
417	move.w	d0,LOCAL_EX(a0)	;store ms mant
418	move.l	d1,LOCAL_HI(a0)	;store exp
419	clr.l	LOCAL_LO(a0)	;clear ls mant
420	move.l	(a7)+,d7
421	rts
422*
423*	denorm --- denormalize an intermediate result
424*
425*	Used by underflow.
426*
427* Input:
428*	a0	 points to the operand to be denormalized
429*		 (in the internal extended format)
430*
431*	d0: 	 rounding precision
432* Output:
433*	a0	 points to the denormalized result
434*		 (in the internal extended format)
435*
436*	d0 	is guard,round,sticky
437*
438* d0 comes into this routine with the rounding precision. It
439* is then loaded with the denormalized exponent threshold for the
440* rounding precision.
441*
442
443	xdef	denorm
444denorm:
445	btst.b	#6,LOCAL_EX(a0)	;check for exponents between $7fff-$4000
446	beq.b	no_sgn_ext
447	bset.b	#7,LOCAL_EX(a0)	;sign extend if it is so
448no_sgn_ext:
449
450	tst.b	d0		;if 0 then extended precision
451	bne.b	not_ext		;else branch
452
453	clr.l	d1		;load d1 with ext threshold
454	clr.l	d0		;clear the sticky flag
455	bsr	dnrm_lp		;denormalize the number
456	tst.b	d1		;check for inex
457	beq.w	no_inex		;if clr, no inex
458	bra.b	dnrm_inex	;if set, set inex
459
460not_ext:
461	cmpi.l	#1,d0		;if 1 then single precision
462	beq.b	load_sgl	;else must be 2, double prec
463
464load_dbl:
465	move.w	#dbl_thresh,d1	;put copy of threshold in d1
466	move.l	d1,d0		;copy d1 into d0
467	sub.w	LOCAL_EX(a0),d0	;diff = threshold - exp
468	cmp.w	#67,d0		;if diff > 67 (mant + grs bits)
469	bpl.b	chk_stky	;then branch (all bits would be
470*				; shifted off in denorm routine)
471	clr.l	d0		;else clear the sticky flag
472	bsr	dnrm_lp		;denormalize the number
473	tst.b	d1		;check flag
474	beq.b	no_inex		;if clr, no inex
475	bra.b	dnrm_inex	;if set, set inex
476
477load_sgl:
478	move.w	#sgl_thresh,d1	;put copy of threshold in d1
479	move.l	d1,d0		;copy d1 into d0
480	sub.w	LOCAL_EX(a0),d0	;diff = threshold - exp
481	cmp.w	#67,d0		;if diff > 67 (mant + grs bits)
482	bpl.b	chk_stky	;then branch (all bits would be
483*				; shifted off in denorm routine)
484	clr.l	d0		;else clear the sticky flag
485	bsr	dnrm_lp		;denormalize the number
486	tst.b	d1		;check flag
487	beq.b	no_inex		;if clr, no inex
488	bra.b	dnrm_inex	;if set, set inex
489
490chk_stky:
491	tst.l	LOCAL_HI(a0)	;check for any bits set
492	bne.b	set_stky
493	tst.l	LOCAL_LO(a0)	;check for any bits set
494	bne.b	set_stky
495	bra.b	clr_mant
496set_stky:
497	or.l	#inx2a_mask,USER_FPSR(a6) ;set inex2/ainex
498	move.l	#$20000000,d0	;set sticky bit in return value
499clr_mant:
500	move.w	d1,LOCAL_EX(a0)		;load exp with threshold
501	clr.l	LOCAL_HI(a0) 	;set d1 = 0 (ms mantissa)
502	clr.l	LOCAL_LO(a0)		;set d2 = 0 (ms mantissa)
503	rts
504dnrm_inex:
505	or.l	#inx2a_mask,USER_FPSR(a6) ;set inex2/ainex
506no_inex:
507	rts
508
509*
510*	dnrm_lp --- normalize exponent/mantissa to specified threshhold
511*
512* Input:
513*	a0		points to the operand to be denormalized
514*	d0{31:29} 	initial guard,round,sticky
515*	d1{15:0}	denormalization threshold
516* Output:
517*	a0		points to the denormalized operand
518*	d0{31:29}	final guard,round,sticky
519*	d1.b		inexact flag:  all ones means inexact result
520*
521* The LOCAL_LO and LOCAL_GRS parts of the value are copied to FP_SCR2
522* so that bfext can be used to extract the new low part of the mantissa.
523* Dnrm_lp can be called with a0 pointing to ETEMP or WBTEMP and there
524* is no LOCAL_GRS scratch word following it on the fsave frame.
525*
526	xdef	dnrm_lp
527dnrm_lp:
528	move.l	d2,-(sp)		;save d2 for temp use
529	btst.b	#E3,E_BYTE(a6)		;test for type E3 exception
530	beq.b	not_E3			;not type E3 exception
531	bfextu	WBTEMP_GRS(a6){6:3},d2	;extract guard,round, sticky  bit
532	move.l	#29,d0
533	lsl.l	d0,d2			;shift g,r,s to their postions
534	move.l	d2,d0
535not_E3:
536	move.l	(sp)+,d2		;restore d2
537	move.l	LOCAL_LO(a0),FP_SCR2+LOCAL_LO(a6)
538	move.l	d0,FP_SCR2+LOCAL_GRS(a6)
539	move.l	d1,d0			;copy the denorm threshold
540	sub.w	LOCAL_EX(a0),d1		;d1 = threshold - uns exponent
541	ble.b	no_lp			;d1 <= 0
542	cmp.w	#32,d1
543	blt.b	case_1			;0 = d1 < 32
544	cmp.w	#64,d1
545	blt.b	case_2			;32 <= d1 < 64
546	bra.w	case_3			;d1 >= 64
547*
548* No normalization necessary
549*
550no_lp:
551	clr.b	d1			;set no inex2 reported
552	move.l	FP_SCR2+LOCAL_GRS(a6),d0	;restore original g,r,s
553	rts
554*
555* case (0<d1<32)
556*
557case_1:
558	move.l	d2,-(sp)
559	move.w	d0,LOCAL_EX(a0)		;exponent = denorm threshold
560	move.l	#32,d0
561	sub.w	d1,d0			;d0 = 32 - d1
562	bfextu	LOCAL_EX(a0){d0:32},d2
563	bfextu	d2{d1:d0},d2		;d2 = new LOCAL_HI
564	bfextu	LOCAL_HI(a0){d0:32},d1	;d1 = new LOCAL_LO
565	bfextu	FP_SCR2+LOCAL_LO(a6){d0:32},d0	;d0 = new G,R,S
566	move.l	d2,LOCAL_HI(a0)		;store new LOCAL_HI
567	move.l	d1,LOCAL_LO(a0)		;store new LOCAL_LO
568	clr.b	d1
569	bftst	d0{2:30}
570	beq.b	c1nstky
571	bset.l	#rnd_stky_bit,d0
572	st.b	d1
573c1nstky:
574	move.l	FP_SCR2+LOCAL_GRS(a6),d2	;restore original g,r,s
575	andi.l	#$e0000000,d2		;clear all but G,R,S
576	tst.l	d2			;test if original G,R,S are clear
577	beq.b	grs_clear
578	or.l	#$20000000,d0		;set sticky bit in d0
579grs_clear:
580	andi.l	#$e0000000,d0		;clear all but G,R,S
581	move.l	(sp)+,d2
582	rts
583*
584* case (32<=d1<64)
585*
586case_2:
587	move.l	d2,-(sp)
588	move.w	d0,LOCAL_EX(a0)		;unsigned exponent = threshold
589	sub.w	#32,d1			;d1 now between 0 and 32
590	move.l	#32,d0
591	sub.w	d1,d0			;d0 = 32 - d1
592	bfextu	LOCAL_EX(a0){d0:32},d2
593	bfextu	d2{d1:d0},d2		;d2 = new LOCAL_LO
594	bfextu	LOCAL_HI(a0){d0:32},d1	;d1 = new G,R,S
595	bftst	d1{2:30}
596	bne.b	c2_sstky		;bra if sticky bit to be set
597	bftst	FP_SCR2+LOCAL_LO(a6){d0:32}
598	bne.b	c2_sstky		;bra if sticky bit to be set
599	move.l	d1,d0
600	clr.b	d1
601	bra.b	end_c2
602c2_sstky:
603	move.l	d1,d0
604	bset.l	#rnd_stky_bit,d0
605	st.b	d1
606end_c2:
607	clr.l	LOCAL_HI(a0)		;store LOCAL_HI = 0
608	move.l	d2,LOCAL_LO(a0)		;store LOCAL_LO
609	move.l	FP_SCR2+LOCAL_GRS(a6),d2	;restore original g,r,s
610	andi.l	#$e0000000,d2		;clear all but G,R,S
611	tst.l	d2			;test if original G,R,S are clear
612	beq.b	clear_grs
613	or.l	#$20000000,d0		;set sticky bit in d0
614clear_grs:
615	andi.l	#$e0000000,d0		;get rid of all but G,R,S
616	move.l	(sp)+,d2
617	rts
618*
619* d1 >= 64 Force the exponent to be the denorm threshold with the
620* correct sign.
621*
622case_3:
623	move.w	d0,LOCAL_EX(a0)
624	tst.w	LOCAL_SGN(a0)
625	bge.b	c3con
626c3neg:
627	or.l	#$80000000,LOCAL_EX(a0)
628c3con:
629	cmp.w	#64,d1
630	beq.b	sixty_four
631	cmp.w	#65,d1
632	beq.b	sixty_five
633*
634* Shift value is out of range.  Set d1 for inex2 flag and
635* return a zero with the given threshold.
636*
637	clr.l	LOCAL_HI(a0)
638	clr.l	LOCAL_LO(a0)
639	move.l	#$20000000,d0
640	st.b	d1
641	rts
642
643sixty_four:
644	move.l	LOCAL_HI(a0),d0
645	bfextu	d0{2:30},d1
646	andi.l	#$c0000000,d0
647	bra.b	c3com
648
649sixty_five:
650	move.l	LOCAL_HI(a0),d0
651	bfextu	d0{1:31},d1
652	andi.l	#$80000000,d0
653	lsr.l	#1,d0			;shift high bit into R bit
654
655c3com:
656	tst.l	d1
657	bne.b	c3ssticky
658	tst.l	LOCAL_LO(a0)
659	bne.b	c3ssticky
660	tst.b	FP_SCR2+LOCAL_GRS(a6)
661	bne.b	c3ssticky
662	clr.b	d1
663	bra.b	c3end
664
665c3ssticky:
666	bset.l	#rnd_stky_bit,d0
667	st.b	d1
668c3end:
669	clr.l	LOCAL_HI(a0)
670	clr.l	LOCAL_LO(a0)
671	rts
672
673	end
674