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