summaryrefslogtreecommitdiff
path: root/sys/arch/m68k/fpsp/scale.sa
blob: e94fded546df61e7c93b76b06e9be4ff01d0850d (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
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
*	$NetBSD: scale.sa,v 1.3 1994/10/26 07:49:34 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.

*
*	scale.sa 3.3 7/30/91
*
*	The entry point sSCALE computes the destination operand
*	scaled by the source operand.  If the absoulute value of
*	the source operand is (>= 2^14) an overflow or underflow
*	is returned.
*
*	The entry point sscale is called from do_func to emulate
*	the fscale unimplemented instruction.
*
*	Input: Double-extended destination operand in FPTEMP, 
*		double-extended source operand in ETEMP.
*
*	Output: The function returns scale(X,Y) to fp0.
*
*	Modifies: fp0.
*
*	Algorithm:
*		

SCALE    IDNT    2,1 Motorola 040 Floating Point Software Package

	section	8

	include	fpsp.h

	xref	t_ovfl2
	xref	t_unfl
	xref	round
	xref	t_resdnrm

SRC_BNDS dc.w	$3fff,$400c

*
* This entry point is used by the unimplemented instruction exception
* handler.
*
*
*
*	FSCALE
*
	xdef	sscale
sscale:
	fmove.l		#0,fpcr		;clr user enabled exc
	clr.l		d1
	move.w		FPTEMP(a6),d1	;get dest exponent
	smi		L_SCR1(a6)	;use L_SCR1 to hold sign
	andi.l		#$7fff,d1	;strip sign
	move.w		ETEMP(a6),d0	;check src bounds
	andi.w		#$7fff,d0	;clr sign bit
	cmp2.w		SRC_BNDS,d0
	bcc.b		src_in
	cmpi.w		#$400c,d0	;test for too large
	bge.w		src_out
*
* The source input is below 1, so we check for denormalized numbers
* and set unfl.
*
src_small:
	move.b		DTAG(a6),d0
	andi.b		#$e0,d0
	tst.b		d0
	beq.b		no_denorm
	st		STORE_FLG(a6)	;dest already contains result
	or.l		#unfl_mask,USER_FPSR(a6) ;set UNFL
den_done:
	lea.l		FPTEMP(a6),a0
	bra		t_resdnrm
no_denorm:
	fmove.l		USER_FPCR(a6),FPCR
	fmove.x		FPTEMP(a6),fp0	;simply return dest
	rts


*
* Source is within 2^14 range.  To perform the int operation,
* move it to d0.
*
src_in:
	fmove.x		ETEMP(a6),fp0	;move in src for int
	fmove.l		#rz_mode,fpcr	;force rz for src conversion
	fmove.l		fp0,d0		;int src to d0
	fmove.l		#0,FPSR		;clr status from above
	tst.w		ETEMP(a6)	;check src sign
	blt.w		src_neg
*
* Source is positive.  Add the src to the dest exponent.
* The result can be denormalized, if src = 0, or overflow,
* if the result of the add sets a bit in the upper word.
*
src_pos:
	tst.w		d1		;check for denorm
	beq.w		dst_dnrm
	add.l		d0,d1		;add src to dest exp
	beq.b		denorm		;if zero, result is denorm
	cmpi.l		#$7fff,d1	;test for overflow
	bge.b		ovfl
	tst.b		L_SCR1(a6)
	beq.b		spos_pos
	or.w		#$8000,d1
spos_pos:
	move.w		d1,FPTEMP(a6)	;result in FPTEMP
	fmove.l		USER_FPCR(a6),FPCR
	fmove.x		FPTEMP(a6),fp0	;write result to fp0
	rts
ovfl:
	tst.b		L_SCR1(a6)
	beq.b		sovl_pos
	or.w		#$8000,d1
sovl_pos:
	move.w		FPTEMP(a6),ETEMP(a6)	;result in ETEMP
	move.l		FPTEMP_HI(a6),ETEMP_HI(a6)
	move.l		FPTEMP_LO(a6),ETEMP_LO(a6)
	bra		t_ovfl2

denorm:
	tst.b		L_SCR1(a6)
	beq.b		den_pos
	or.w		#$8000,d1
den_pos:
	tst.l		FPTEMP_HI(a6)	;check j bit
	blt.b		nden_exit	;if set, not denorm
	move.w		d1,ETEMP(a6)	;input expected in ETEMP
	move.l		FPTEMP_HI(a6),ETEMP_HI(a6)
	move.l		FPTEMP_LO(a6),ETEMP_LO(a6)
	or.l		#unfl_bit,USER_FPSR(a6)	;set unfl
	lea.l		ETEMP(a6),a0
	bra		t_resdnrm
nden_exit:
	move.w		d1,FPTEMP(a6)	;result in FPTEMP
	fmove.l		USER_FPCR(a6),FPCR
	fmove.x		FPTEMP(a6),fp0	;write result to fp0
	rts

*
* Source is negative.  Add the src to the dest exponent.
* (The result exponent will be reduced).  The result can be
* denormalized.
*
src_neg:
	add.l		d0,d1		;add src to dest
	beq.b		denorm		;if zero, result is denorm
	blt.b		fix_dnrm	;if negative, result is 
*					;needing denormalization
	tst.b		L_SCR1(a6)
	beq.b		sneg_pos
	or.w		#$8000,d1
sneg_pos:
	move.w		d1,FPTEMP(a6)	;result in FPTEMP
	fmove.l		USER_FPCR(a6),FPCR
	fmove.x		FPTEMP(a6),fp0	;write result to fp0
	rts


*
* The result exponent is below denorm value.  Test for catastrophic
* underflow and force zero if true.  If not, try to shift the 
* mantissa right until a zero exponent exists.
*
fix_dnrm:
	cmpi.w		#$ffc0,d1	;lower bound for normalization
	blt.w		fix_unfl	;if lower, catastrophic unfl
	move.w		d1,d0		;use d0 for exp
	move.l		d2,-(a7)	;free d2 for norm
	move.l		FPTEMP_HI(a6),d1
	move.l		FPTEMP_LO(a6),d2
	clr.l		L_SCR2(a6)
fix_loop:
	add.w		#1,d0		;drive d0 to 0
	lsr.l		#1,d1		;while shifting the
	roxr.l		#1,d2		;mantissa to the right
	bcc.b		no_carry
	st		L_SCR2(a6)	;use L_SCR2 to capture inex
no_carry:
	tst.w		d0		;it is finished when
	blt.b		fix_loop	;d0 is zero or the mantissa
	tst.b		L_SCR2(a6)
	beq.b		tst_zero
	or.l		#unfl_inx_mask,USER_FPSR(a6)
*					;set unfl, aunfl, ainex
*
* Test for zero. If zero, simply use fmove to return +/- zero
* to the fpu.
*
tst_zero:
	clr.w		FPTEMP_EX(a6)
	tst.b		L_SCR1(a6)	;test for sign
	beq.b		tst_con
	or.w		#$8000,FPTEMP_EX(a6) ;set sign bit
tst_con:
	move.l		d1,FPTEMP_HI(a6)
	move.l		d2,FPTEMP_LO(a6)
	move.l		(a7)+,d2
	tst.l		d1
	bne.b		not_zero
	tst.l		FPTEMP_LO(a6)
	bne.b		not_zero
*
* Result is zero.  Check for rounding mode to set lsb.  If the
* mode is rp, and the zero is positive, return smallest denorm.
* If the mode is rm, and the zero is negative, return smallest
* negative denorm.
*
	btst.b		#5,FPCR_MODE(a6) ;test if rm or rp
	beq.b		no_dir
	btst.b		#4,FPCR_MODE(a6) ;check which one
	beq.b		zer_rm
zer_rp:
	tst.b		L_SCR1(a6)	;check sign
	bne.b		no_dir		;if set, neg op, no inc
	move.l		#1,FPTEMP_LO(a6) ;set lsb
	bra.b		sm_dnrm
zer_rm:
	tst.b		L_SCR1(a6)	;check sign
	beq.b		no_dir		;if clr, neg op, no inc
	move.l		#1,FPTEMP_LO(a6) ;set lsb
	or.l		#neg_mask,USER_FPSR(a6) ;set N
	bra.b		sm_dnrm
no_dir:
	fmove.l		USER_FPCR(a6),FPCR
	fmove.x		FPTEMP(a6),fp0	;use fmove to set cc's
	rts

*
* The rounding mode changed the zero to a smallest denorm. Call 
* t_resdnrm with exceptional operand in ETEMP.
*
sm_dnrm:
	move.l		FPTEMP_EX(a6),ETEMP_EX(a6)
	move.l		FPTEMP_HI(a6),ETEMP_HI(a6)
	move.l		FPTEMP_LO(a6),ETEMP_LO(a6)
	lea.l		ETEMP(a6),a0
	bra		t_resdnrm

*
* Result is still denormalized.
*
not_zero:
	or.l		#unfl_mask,USER_FPSR(a6) ;set unfl
	tst.b		L_SCR1(a6)	;check for sign
	beq.b		fix_exit
	or.l		#neg_mask,USER_FPSR(a6) ;set N
fix_exit:
	bra.b		sm_dnrm

	
*
* The result has underflowed to zero. Return zero and set
* unfl, aunfl, and ainex.
*
fix_unfl:
	or.l		#unfl_inx_mask,USER_FPSR(a6)
	btst.b		#5,FPCR_MODE(a6) ;test if rm or rp
	beq.b		no_dir2
	btst.b		#4,FPCR_MODE(a6) ;check which one
	beq.b		zer_rm2
zer_rp2:
	tst.b		L_SCR1(a6)	;check sign
	bne.b		no_dir2		;if set, neg op, no inc
	clr.l		FPTEMP_EX(a6)
	clr.l		FPTEMP_HI(a6)
	move.l		#1,FPTEMP_LO(a6) ;set lsb
	bra.b		sm_dnrm		;return smallest denorm
zer_rm2:
	tst.b		L_SCR1(a6)	;check sign
	beq.b		no_dir2		;if clr, neg op, no inc
	move.w		#$8000,FPTEMP_EX(a6)
	clr.l		FPTEMP_HI(a6)
	move.l		#1,FPTEMP_LO(a6) ;set lsb
	or.l		#neg_mask,USER_FPSR(a6) ;set N
	bra.w		sm_dnrm		;return smallest denorm

no_dir2:
	tst.b		L_SCR1(a6)
	bge.b		pos_zero
neg_zero:
	clr.l		FP_SCR1(a6)	;clear the exceptional operand
	clr.l		FP_SCR1+4(a6)	;for gen_except.
	clr.l		FP_SCR1+8(a6)
	fmove.s		#:80000000,fp0	
	rts
pos_zero:
	clr.l		FP_SCR1(a6)	;clear the exceptional operand
	clr.l		FP_SCR1+4(a6)	;for gen_except.
	clr.l		FP_SCR1+8(a6)
	fmove.s		#:00000000,fp0
	rts

*
* The destination is a denormalized number.  It must be handled
* by first shifting the bits in the mantissa until it is normalized,
* then adding the remainder of the source to the exponent.
*
dst_dnrm:
	movem.l		d2/d3,-(a7)	
	move.w		FPTEMP_EX(a6),d1
	move.l		FPTEMP_HI(a6),d2
	move.l		FPTEMP_LO(a6),d3
dst_loop:
	tst.l		d2		;test for normalized result
	blt.b		dst_norm	;exit loop if so
	tst.l		d0		;otherwise, test shift count
	beq.b		dst_fin		;if zero, shifting is done
	subq.l		#1,d0		;dec src
	add.l		d3,d3
	addx.l		d2,d2
	bra.b		dst_loop
*
* Destination became normalized.  Simply add the remaining 
* portion of the src to the exponent.
*
dst_norm:
	add.w		d0,d1		;dst is normalized; add src
	tst.b		L_SCR1(a6)
	beq.b		dnrm_pos
	or.w		#$8000,d1
dnrm_pos:
	movem.w		d1,FPTEMP_EX(a6)
	movem.l		d2,FPTEMP_HI(a6)
	movem.l		d3,FPTEMP_LO(a6)
	fmove.l		USER_FPCR(a6),FPCR
	fmove.x		FPTEMP(a6),fp0
	movem.l		(a7)+,d2/d3
	rts

*
* Destination remained denormalized.  Call t_excdnrm with
* exceptional operand in ETEMP.
*
dst_fin:
	tst.b		L_SCR1(a6)	;check for sign
	beq.b		dst_exit
	or.l		#neg_mask,USER_FPSR(a6) ;set N
	or.w		#$8000,d1
dst_exit:
	movem.w		d1,ETEMP_EX(a6)
	movem.l		d2,ETEMP_HI(a6)
	movem.l		d3,ETEMP_LO(a6)
	or.l		#unfl_mask,USER_FPSR(a6) ;set unfl
	movem.l		(a7)+,d2/d3
	lea.l		ETEMP(a6),a0
	bra		t_resdnrm

*
* Source is outside of 2^14 range.  Test the sign and branch
* to the appropriate exception handler.
*
src_out:
	tst.b		L_SCR1(a6)
	beq.b		scro_pos
	or.w		#$8000,d1
scro_pos:
	move.l		FPTEMP_HI(a6),ETEMP_HI(a6)
	move.l		FPTEMP_LO(a6),ETEMP_LO(a6)
	tst.w		ETEMP(a6)
	blt.b		res_neg
res_pos:
	move.w		d1,ETEMP(a6)	;result in ETEMP
	bra		t_ovfl2
res_neg:
	move.w		d1,ETEMP(a6)	;result in ETEMP
	lea.l		ETEMP(a6),a0
	bra		t_unfl
	end