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