Merge with /pub/scm/linux/kernel/git/sfrench/cifs-2.6.git/
[linux-2.6] / arch / m68k / fpsp040 / scale.S
1 |
2 |       scale.sa 3.3 7/30/91
3 |
4 |       The entry point sSCALE computes the destination operand
5 |       scaled by the source operand.  If the absolute value of
6 |       the source operand is (>= 2^14) an overflow or underflow
7 |       is returned.
8 |
9 |       The entry point sscale is called from do_func to emulate
10 |       the fscale unimplemented instruction.
11 |
12 |       Input: Double-extended destination operand in FPTEMP,
13 |               double-extended source operand in ETEMP.
14 |
15 |       Output: The function returns scale(X,Y) to fp0.
16 |
17 |       Modifies: fp0.
18 |
19 |       Algorithm:
20 |
21 |               Copyright (C) Motorola, Inc. 1990
22 |                       All Rights Reserved
23 |
24 |       THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
25 |       The copyright notice above does not evidence any
26 |       actual or intended publication of such source code.
27
28 |SCALE    idnt    2,1 | Motorola 040 Floating Point Software Package
29
30         |section        8
31
32 #include "fpsp.h"
33
34         |xref   t_ovfl2
35         |xref   t_unfl
36         |xref   round
37         |xref   t_resdnrm
38
39 SRC_BNDS: .short        0x3fff,0x400c
40
41 |
42 | This entry point is used by the unimplemented instruction exception
43 | handler.
44 |
45 |
46 |
47 |       FSCALE
48 |
49         .global sscale
50 sscale:
51         fmovel          #0,%fpcr                |clr user enabled exc
52         clrl            %d1
53         movew           FPTEMP(%a6),%d1 |get dest exponent
54         smi             L_SCR1(%a6)     |use L_SCR1 to hold sign
55         andil           #0x7fff,%d1     |strip sign
56         movew           ETEMP(%a6),%d0  |check src bounds
57         andiw           #0x7fff,%d0     |clr sign bit
58         cmp2w           SRC_BNDS,%d0
59         bccs            src_in
60         cmpiw           #0x400c,%d0     |test for too large
61         bge             src_out
62 |
63 | The source input is below 1, so we check for denormalized numbers
64 | and set unfl.
65 |
66 src_small:
67         moveb           DTAG(%a6),%d0
68         andib           #0xe0,%d0
69         tstb            %d0
70         beqs            no_denorm
71         st              STORE_FLG(%a6)  |dest already contains result
72         orl             #unfl_mask,USER_FPSR(%a6) |set UNFL
73 den_done:
74         leal            FPTEMP(%a6),%a0
75         bra             t_resdnrm
76 no_denorm:
77         fmovel          USER_FPCR(%a6),%FPCR
78         fmovex          FPTEMP(%a6),%fp0        |simply return dest
79         rts
80
81
82 |
83 | Source is within 2^14 range.  To perform the int operation,
84 | move it to d0.
85 |
86 src_in:
87         fmovex          ETEMP(%a6),%fp0 |move in src for int
88         fmovel          #rz_mode,%fpcr  |force rz for src conversion
89         fmovel          %fp0,%d0                |int src to d0
90         fmovel          #0,%FPSR                |clr status from above
91         tstw            ETEMP(%a6)      |check src sign
92         blt             src_neg
93 |
94 | Source is positive.  Add the src to the dest exponent.
95 | The result can be denormalized, if src = 0, or overflow,
96 | if the result of the add sets a bit in the upper word.
97 |
98 src_pos:
99         tstw            %d1             |check for denorm
100         beq             dst_dnrm
101         addl            %d0,%d1         |add src to dest exp
102         beqs            denorm          |if zero, result is denorm
103         cmpil           #0x7fff,%d1     |test for overflow
104         bges            ovfl
105         tstb            L_SCR1(%a6)
106         beqs            spos_pos
107         orw             #0x8000,%d1
108 spos_pos:
109         movew           %d1,FPTEMP(%a6) |result in FPTEMP
110         fmovel          USER_FPCR(%a6),%FPCR
111         fmovex          FPTEMP(%a6),%fp0        |write result to fp0
112         rts
113 ovfl:
114         tstb            L_SCR1(%a6)
115         beqs            sovl_pos
116         orw             #0x8000,%d1
117 sovl_pos:
118         movew           FPTEMP(%a6),ETEMP(%a6)  |result in ETEMP
119         movel           FPTEMP_HI(%a6),ETEMP_HI(%a6)
120         movel           FPTEMP_LO(%a6),ETEMP_LO(%a6)
121         bra             t_ovfl2
122
123 denorm:
124         tstb            L_SCR1(%a6)
125         beqs            den_pos
126         orw             #0x8000,%d1
127 den_pos:
128         tstl            FPTEMP_HI(%a6)  |check j bit
129         blts            nden_exit       |if set, not denorm
130         movew           %d1,ETEMP(%a6)  |input expected in ETEMP
131         movel           FPTEMP_HI(%a6),ETEMP_HI(%a6)
132         movel           FPTEMP_LO(%a6),ETEMP_LO(%a6)
133         orl             #unfl_bit,USER_FPSR(%a6)        |set unfl
134         leal            ETEMP(%a6),%a0
135         bra             t_resdnrm
136 nden_exit:
137         movew           %d1,FPTEMP(%a6) |result in FPTEMP
138         fmovel          USER_FPCR(%a6),%FPCR
139         fmovex          FPTEMP(%a6),%fp0        |write result to fp0
140         rts
141
142 |
143 | Source is negative.  Add the src to the dest exponent.
144 | (The result exponent will be reduced).  The result can be
145 | denormalized.
146 |
147 src_neg:
148         addl            %d0,%d1         |add src to dest
149         beqs            denorm          |if zero, result is denorm
150         blts            fix_dnrm        |if negative, result is
151 |                                       ;needing denormalization
152         tstb            L_SCR1(%a6)
153         beqs            sneg_pos
154         orw             #0x8000,%d1
155 sneg_pos:
156         movew           %d1,FPTEMP(%a6) |result in FPTEMP
157         fmovel          USER_FPCR(%a6),%FPCR
158         fmovex          FPTEMP(%a6),%fp0        |write result to fp0
159         rts
160
161
162 |
163 | The result exponent is below denorm value.  Test for catastrophic
164 | underflow and force zero if true.  If not, try to shift the
165 | mantissa right until a zero exponent exists.
166 |
167 fix_dnrm:
168         cmpiw           #0xffc0,%d1     |lower bound for normalization
169         blt             fix_unfl        |if lower, catastrophic unfl
170         movew           %d1,%d0         |use d0 for exp
171         movel           %d2,-(%a7)      |free d2 for norm
172         movel           FPTEMP_HI(%a6),%d1
173         movel           FPTEMP_LO(%a6),%d2
174         clrl            L_SCR2(%a6)
175 fix_loop:
176         addw            #1,%d0          |drive d0 to 0
177         lsrl            #1,%d1          |while shifting the
178         roxrl           #1,%d2          |mantissa to the right
179         bccs            no_carry
180         st              L_SCR2(%a6)     |use L_SCR2 to capture inex
181 no_carry:
182         tstw            %d0             |it is finished when
183         blts            fix_loop        |d0 is zero or the mantissa
184         tstb            L_SCR2(%a6)
185         beqs            tst_zero
186         orl             #unfl_inx_mask,USER_FPSR(%a6)
187 |                                       ;set unfl, aunfl, ainex
188 |
189 | Test for zero. If zero, simply use fmove to return +/- zero
190 | to the fpu.
191 |
192 tst_zero:
193         clrw            FPTEMP_EX(%a6)
194         tstb            L_SCR1(%a6)     |test for sign
195         beqs            tst_con
196         orw             #0x8000,FPTEMP_EX(%a6) |set sign bit
197 tst_con:
198         movel           %d1,FPTEMP_HI(%a6)
199         movel           %d2,FPTEMP_LO(%a6)
200         movel           (%a7)+,%d2
201         tstl            %d1
202         bnes            not_zero
203         tstl            FPTEMP_LO(%a6)
204         bnes            not_zero
205 |
206 | Result is zero.  Check for rounding mode to set lsb.  If the
207 | mode is rp, and the zero is positive, return smallest denorm.
208 | If the mode is rm, and the zero is negative, return smallest
209 | negative denorm.
210 |
211         btstb           #5,FPCR_MODE(%a6) |test if rm or rp
212         beqs            no_dir
213         btstb           #4,FPCR_MODE(%a6) |check which one
214         beqs            zer_rm
215 zer_rp:
216         tstb            L_SCR1(%a6)     |check sign
217         bnes            no_dir          |if set, neg op, no inc
218         movel           #1,FPTEMP_LO(%a6) |set lsb
219         bras            sm_dnrm
220 zer_rm:
221         tstb            L_SCR1(%a6)     |check sign
222         beqs            no_dir          |if clr, neg op, no inc
223         movel           #1,FPTEMP_LO(%a6) |set lsb
224         orl             #neg_mask,USER_FPSR(%a6) |set N
225         bras            sm_dnrm
226 no_dir:
227         fmovel          USER_FPCR(%a6),%FPCR
228         fmovex          FPTEMP(%a6),%fp0        |use fmove to set cc's
229         rts
230
231 |
232 | The rounding mode changed the zero to a smallest denorm. Call
233 | t_resdnrm with exceptional operand in ETEMP.
234 |
235 sm_dnrm:
236         movel           FPTEMP_EX(%a6),ETEMP_EX(%a6)
237         movel           FPTEMP_HI(%a6),ETEMP_HI(%a6)
238         movel           FPTEMP_LO(%a6),ETEMP_LO(%a6)
239         leal            ETEMP(%a6),%a0
240         bra             t_resdnrm
241
242 |
243 | Result is still denormalized.
244 |
245 not_zero:
246         orl             #unfl_mask,USER_FPSR(%a6) |set unfl
247         tstb            L_SCR1(%a6)     |check for sign
248         beqs            fix_exit
249         orl             #neg_mask,USER_FPSR(%a6) |set N
250 fix_exit:
251         bras            sm_dnrm
252
253
254 |
255 | The result has underflowed to zero. Return zero and set
256 | unfl, aunfl, and ainex.
257 |
258 fix_unfl:
259         orl             #unfl_inx_mask,USER_FPSR(%a6)
260         btstb           #5,FPCR_MODE(%a6) |test if rm or rp
261         beqs            no_dir2
262         btstb           #4,FPCR_MODE(%a6) |check which one
263         beqs            zer_rm2
264 zer_rp2:
265         tstb            L_SCR1(%a6)     |check sign
266         bnes            no_dir2         |if set, neg op, no inc
267         clrl            FPTEMP_EX(%a6)
268         clrl            FPTEMP_HI(%a6)
269         movel           #1,FPTEMP_LO(%a6) |set lsb
270         bras            sm_dnrm         |return smallest denorm
271 zer_rm2:
272         tstb            L_SCR1(%a6)     |check sign
273         beqs            no_dir2         |if clr, neg op, no inc
274         movew           #0x8000,FPTEMP_EX(%a6)
275         clrl            FPTEMP_HI(%a6)
276         movel           #1,FPTEMP_LO(%a6) |set lsb
277         orl             #neg_mask,USER_FPSR(%a6) |set N
278         bra             sm_dnrm         |return smallest denorm
279
280 no_dir2:
281         tstb            L_SCR1(%a6)
282         bges            pos_zero
283 neg_zero:
284         clrl            FP_SCR1(%a6)    |clear the exceptional operand
285         clrl            FP_SCR1+4(%a6)  |for gen_except.
286         clrl            FP_SCR1+8(%a6)
287         fmoves          #0x80000000,%fp0
288         rts
289 pos_zero:
290         clrl            FP_SCR1(%a6)    |clear the exceptional operand
291         clrl            FP_SCR1+4(%a6)  |for gen_except.
292         clrl            FP_SCR1+8(%a6)
293         fmoves          #0x00000000,%fp0
294         rts
295
296 |
297 | The destination is a denormalized number.  It must be handled
298 | by first shifting the bits in the mantissa until it is normalized,
299 | then adding the remainder of the source to the exponent.
300 |
301 dst_dnrm:
302         moveml          %d2/%d3,-(%a7)
303         movew           FPTEMP_EX(%a6),%d1
304         movel           FPTEMP_HI(%a6),%d2
305         movel           FPTEMP_LO(%a6),%d3
306 dst_loop:
307         tstl            %d2             |test for normalized result
308         blts            dst_norm        |exit loop if so
309         tstl            %d0             |otherwise, test shift count
310         beqs            dst_fin         |if zero, shifting is done
311         subil           #1,%d0          |dec src
312         lsll            #1,%d3
313         roxll           #1,%d2
314         bras            dst_loop
315 |
316 | Destination became normalized.  Simply add the remaining
317 | portion of the src to the exponent.
318 |
319 dst_norm:
320         addw            %d0,%d1         |dst is normalized; add src
321         tstb            L_SCR1(%a6)
322         beqs            dnrm_pos
323         orl             #0x8000,%d1
324 dnrm_pos:
325         movemw          %d1,FPTEMP_EX(%a6)
326         moveml          %d2,FPTEMP_HI(%a6)
327         moveml          %d3,FPTEMP_LO(%a6)
328         fmovel          USER_FPCR(%a6),%FPCR
329         fmovex          FPTEMP(%a6),%fp0
330         moveml          (%a7)+,%d2/%d3
331         rts
332
333 |
334 | Destination remained denormalized.  Call t_excdnrm with
335 | exceptional operand in ETEMP.
336 |
337 dst_fin:
338         tstb            L_SCR1(%a6)     |check for sign
339         beqs            dst_exit
340         orl             #neg_mask,USER_FPSR(%a6) |set N
341         orl             #0x8000,%d1
342 dst_exit:
343         movemw          %d1,ETEMP_EX(%a6)
344         moveml          %d2,ETEMP_HI(%a6)
345         moveml          %d3,ETEMP_LO(%a6)
346         orl             #unfl_mask,USER_FPSR(%a6) |set unfl
347         moveml          (%a7)+,%d2/%d3
348         leal            ETEMP(%a6),%a0
349         bra             t_resdnrm
350
351 |
352 | Source is outside of 2^14 range.  Test the sign and branch
353 | to the appropriate exception handler.
354 |
355 src_out:
356         tstb            L_SCR1(%a6)
357         beqs            scro_pos
358         orl             #0x8000,%d1
359 scro_pos:
360         movel           FPTEMP_HI(%a6),ETEMP_HI(%a6)
361         movel           FPTEMP_LO(%a6),ETEMP_LO(%a6)
362         tstw            ETEMP(%a6)
363         blts            res_neg
364 res_pos:
365         movew           %d1,ETEMP(%a6)  |result in ETEMP
366         bra             t_ovfl2
367 res_neg:
368         movew           %d1,ETEMP(%a6)  |result in ETEMP
369         leal            ETEMP(%a6),%a0
370         bra             t_unfl
371         |end