]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - arch/m68k/fpsp040/res_func.S
Linux-2.6.12-rc2
[mirror_ubuntu-bionic-kernel.git] / arch / m68k / fpsp040 / res_func.S
1 |
2 | res_func.sa 3.9 7/29/91
3 |
4 | Normalizes denormalized numbers if necessary and updates the
5 | stack frame. The function is then restored back into the
6 | machine and the 040 completes the operation. This routine
7 | is only used by the unsupported data type/format handler.
8 | (Exception vector 55).
9 |
10 | For packed move out (fmove.p fpm,<ea>) the operation is
11 | completed here; data is packed and moved to user memory.
12 | The stack is restored to the 040 only in the case of a
13 | reportable exception in the conversion.
14 |
15 |
16 | Copyright (C) Motorola, Inc. 1990
17 | All Rights Reserved
18 |
19 | THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
20 | The copyright notice above does not evidence any
21 | actual or intended publication of such source code.
22
23 RES_FUNC: |idnt 2,1 | Motorola 040 Floating Point Software Package
24
25 |section 8
26
27 #include "fpsp.h"
28
29 sp_bnds: .short 0x3f81,0x407e
30 .short 0x3f6a,0x0000
31 dp_bnds: .short 0x3c01,0x43fe
32 .short 0x3bcd,0x0000
33
34 |xref mem_write
35 |xref bindec
36 |xref get_fline
37 |xref round
38 |xref denorm
39 |xref dest_ext
40 |xref dest_dbl
41 |xref dest_sgl
42 |xref unf_sub
43 |xref nrm_set
44 |xref dnrm_lp
45 |xref ovf_res
46 |xref reg_dest
47 |xref t_ovfl
48 |xref t_unfl
49
50 .global res_func
51 .global p_move
52
53 res_func:
54 clrb DNRM_FLG(%a6)
55 clrb RES_FLG(%a6)
56 clrb CU_ONLY(%a6)
57 tstb DY_MO_FLG(%a6)
58 beqs monadic
59 dyadic:
60 btstb #7,DTAG(%a6) |if dop = norm=000, zero=001,
61 | ;inf=010 or nan=011
62 beqs monadic |then branch
63 | ;else denorm
64 | HANDLE DESTINATION DENORM HERE
65 | ;set dtag to norm
66 | ;write the tag & fpte15 to the fstack
67 leal FPTEMP(%a6),%a0
68
69 bclrb #sign_bit,LOCAL_EX(%a0)
70 sne LOCAL_SGN(%a0)
71
72 bsr nrm_set |normalize number (exp will go negative)
73 bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign
74 bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
75 beqs dpos
76 bsetb #sign_bit,LOCAL_EX(%a0)
77 dpos:
78 bfclr DTAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0
79 bsetb #4,DTAG(%a6) |set FPTE15
80 orb #0x0f,DNRM_FLG(%a6)
81 monadic:
82 leal ETEMP(%a6),%a0
83 btstb #direction_bit,CMDREG1B(%a6) |check direction
84 bne opclass3 |it is a mv out
85 |
86 | At this point, only opclass 0 and 2 possible
87 |
88 btstb #7,STAG(%a6) |if sop = norm=000, zero=001,
89 | ;inf=010 or nan=011
90 bne mon_dnrm |else denorm
91 tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would
92 bne normal |require normalization of denorm
93
94 | At this point:
95 | monadic instructions: fabs = $18 fneg = $1a ftst = $3a
96 | fmove = $00 fsmove = $40 fdmove = $44
97 | fsqrt = $05* fssqrt = $41 fdsqrt = $45
98 | (*fsqrt reencoded to $05)
99 |
100 movew CMDREG1B(%a6),%d0 |get command register
101 andil #0x7f,%d0 |strip to only command word
102 |
103 | At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
104 | fdsqrt are possible.
105 | For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
106 | For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
107 |
108 btstl #0,%d0
109 bne normal |weed out fsqrt instructions
110 |
111 | cu_norm handles fmove in instructions with normalized inputs.
112 | The routine round is used to correctly round the input for the
113 | destination precision and mode.
114 |
115 cu_norm:
116 st CU_ONLY(%a6) |set cu-only inst flag
117 movew CMDREG1B(%a6),%d0
118 andib #0x3b,%d0 |isolate bits to select inst
119 tstb %d0
120 beql cu_nmove |if zero, it is an fmove
121 cmpib #0x18,%d0
122 beql cu_nabs |if $18, it is fabs
123 cmpib #0x1a,%d0
124 beql cu_nneg |if $1a, it is fneg
125 |
126 | Inst is ftst. Check the source operand and set the cc's accordingly.
127 | No write is done, so simply rts.
128 |
129 cu_ntst:
130 movew LOCAL_EX(%a0),%d0
131 bclrl #15,%d0
132 sne LOCAL_SGN(%a0)
133 beqs cu_ntpo
134 orl #neg_mask,USER_FPSR(%a6) |set N
135 cu_ntpo:
136 cmpiw #0x7fff,%d0 |test for inf/nan
137 bnes cu_ntcz
138 tstl LOCAL_HI(%a0)
139 bnes cu_ntn
140 tstl LOCAL_LO(%a0)
141 bnes cu_ntn
142 orl #inf_mask,USER_FPSR(%a6)
143 rts
144 cu_ntn:
145 orl #nan_mask,USER_FPSR(%a6)
146 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
147 | ;snan handler
148
149 rts
150 cu_ntcz:
151 tstl LOCAL_HI(%a0)
152 bnel cu_ntsx
153 tstl LOCAL_LO(%a0)
154 bnel cu_ntsx
155 orl #z_mask,USER_FPSR(%a6)
156 cu_ntsx:
157 rts
158 |
159 | Inst is fabs. Execute the absolute value function on the input.
160 | Branch to the fmove code. If the operand is NaN, do nothing.
161 |
162 cu_nabs:
163 moveb STAG(%a6),%d0
164 btstl #5,%d0 |test for NaN or zero
165 bne wr_etemp |if either, simply write it
166 bclrb #7,LOCAL_EX(%a0) |do abs
167 bras cu_nmove |fmove code will finish
168 |
169 | Inst is fneg. Execute the negate value function on the input.
170 | Fall though to the fmove code. If the operand is NaN, do nothing.
171 |
172 cu_nneg:
173 moveb STAG(%a6),%d0
174 btstl #5,%d0 |test for NaN or zero
175 bne wr_etemp |if either, simply write it
176 bchgb #7,LOCAL_EX(%a0) |do neg
177 |
178 | Inst is fmove. This code also handles all result writes.
179 | If bit 2 is set, round is forced to double. If it is clear,
180 | and bit 6 is set, round is forced to single. If both are clear,
181 | the round precision is found in the fpcr. If the rounding precision
182 | is double or single, round the result before the write.
183 |
184 cu_nmove:
185 moveb STAG(%a6),%d0
186 andib #0xe0,%d0 |isolate stag bits
187 bne wr_etemp |if not norm, simply write it
188 btstb #2,CMDREG1B+1(%a6) |check for rd
189 bne cu_nmrd
190 btstb #6,CMDREG1B+1(%a6) |check for rs
191 bne cu_nmrs
192 |
193 | The move or operation is not with forced precision. Test for
194 | nan or inf as the input; if so, simply write it to FPn. Use the
195 | FPCR_MODE byte to get rounding on norms and zeros.
196 |
197 cu_nmnr:
198 bfextu FPCR_MODE(%a6){#0:#2},%d0
199 tstb %d0 |check for extended
200 beq cu_wrexn |if so, just write result
201 cmpib #1,%d0 |check for single
202 beq cu_nmrs |fall through to double
203 |
204 | The move is fdmove or round precision is double.
205 |
206 cu_nmrd:
207 movel #2,%d0 |set up the size for denorm
208 movew LOCAL_EX(%a0),%d1 |compare exponent to double threshold
209 andw #0x7fff,%d1
210 cmpw #0x3c01,%d1
211 bls cu_nunfl
212 bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
213 orl #0x00020000,%d1 |or in rprec (double)
214 clrl %d0 |clear g,r,s for round
215 bclrb #sign_bit,LOCAL_EX(%a0) |convert to internal format
216 sne LOCAL_SGN(%a0)
217 bsrl round
218 bfclr LOCAL_SGN(%a0){#0:#8}
219 beqs cu_nmrdc
220 bsetb #sign_bit,LOCAL_EX(%a0)
221 cu_nmrdc:
222 movew LOCAL_EX(%a0),%d1 |check for overflow
223 andw #0x7fff,%d1
224 cmpw #0x43ff,%d1
225 bge cu_novfl |take care of overflow case
226 bra cu_wrexn
227 |
228 | The move is fsmove or round precision is single.
229 |
230 cu_nmrs:
231 movel #1,%d0
232 movew LOCAL_EX(%a0),%d1
233 andw #0x7fff,%d1
234 cmpw #0x3f81,%d1
235 bls cu_nunfl
236 bfextu FPCR_MODE(%a6){#2:#2},%d1
237 orl #0x00010000,%d1
238 clrl %d0
239 bclrb #sign_bit,LOCAL_EX(%a0)
240 sne LOCAL_SGN(%a0)
241 bsrl round
242 bfclr LOCAL_SGN(%a0){#0:#8}
243 beqs cu_nmrsc
244 bsetb #sign_bit,LOCAL_EX(%a0)
245 cu_nmrsc:
246 movew LOCAL_EX(%a0),%d1
247 andw #0x7FFF,%d1
248 cmpw #0x407f,%d1
249 blt cu_wrexn
250 |
251 | The operand is above precision boundaries. Use t_ovfl to
252 | generate the correct value.
253 |
254 cu_novfl:
255 bsr t_ovfl
256 bra cu_wrexn
257 |
258 | The operand is below precision boundaries. Use denorm to
259 | generate the correct value.
260 |
261 cu_nunfl:
262 bclrb #sign_bit,LOCAL_EX(%a0)
263 sne LOCAL_SGN(%a0)
264 bsr denorm
265 bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
266 beqs cu_nucont
267 bsetb #sign_bit,LOCAL_EX(%a0)
268 cu_nucont:
269 bfextu FPCR_MODE(%a6){#2:#2},%d1
270 btstb #2,CMDREG1B+1(%a6) |check for rd
271 bne inst_d
272 btstb #6,CMDREG1B+1(%a6) |check for rs
273 bne inst_s
274 swap %d1
275 moveb FPCR_MODE(%a6),%d1
276 lsrb #6,%d1
277 swap %d1
278 bra inst_sd
279 inst_d:
280 orl #0x00020000,%d1
281 bra inst_sd
282 inst_s:
283 orl #0x00010000,%d1
284 inst_sd:
285 bclrb #sign_bit,LOCAL_EX(%a0)
286 sne LOCAL_SGN(%a0)
287 bsrl round
288 bfclr LOCAL_SGN(%a0){#0:#8}
289 beqs cu_nuflp
290 bsetb #sign_bit,LOCAL_EX(%a0)
291 cu_nuflp:
292 btstb #inex2_bit,FPSR_EXCEPT(%a6)
293 beqs cu_nuninx
294 orl #aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL
295 cu_nuninx:
296 tstl LOCAL_HI(%a0) |test for zero
297 bnes cu_nunzro
298 tstl LOCAL_LO(%a0)
299 bnes cu_nunzro
300 |
301 | The mantissa is zero from the denorm loop. Check sign and rmode
302 | to see if rounding should have occurred which would leave the lsb.
303 |
304 movel USER_FPCR(%a6),%d0
305 andil #0x30,%d0 |isolate rmode
306 cmpil #0x20,%d0
307 blts cu_nzro
308 bnes cu_nrp
309 cu_nrm:
310 tstw LOCAL_EX(%a0) |if positive, set lsb
311 bges cu_nzro
312 btstb #7,FPCR_MODE(%a6) |check for double
313 beqs cu_nincs
314 bras cu_nincd
315 cu_nrp:
316 tstw LOCAL_EX(%a0) |if positive, set lsb
317 blts cu_nzro
318 btstb #7,FPCR_MODE(%a6) |check for double
319 beqs cu_nincs
320 cu_nincd:
321 orl #0x800,LOCAL_LO(%a0) |inc for double
322 bra cu_nunzro
323 cu_nincs:
324 orl #0x100,LOCAL_HI(%a0) |inc for single
325 bra cu_nunzro
326 cu_nzro:
327 orl #z_mask,USER_FPSR(%a6)
328 moveb STAG(%a6),%d0
329 andib #0xe0,%d0
330 cmpib #0x40,%d0 |check if input was tagged zero
331 beqs cu_numv
332 cu_nunzro:
333 orl #unfl_mask,USER_FPSR(%a6) |set unfl
334 cu_numv:
335 movel (%a0),ETEMP(%a6)
336 movel 4(%a0),ETEMP_HI(%a6)
337 movel 8(%a0),ETEMP_LO(%a6)
338 |
339 | Write the result to memory, setting the fpsr cc bits. NaN and Inf
340 | bypass cu_wrexn.
341 |
342 cu_wrexn:
343 tstw LOCAL_EX(%a0) |test for zero
344 beqs cu_wrzero
345 cmpw #0x8000,LOCAL_EX(%a0) |test for zero
346 bnes cu_wreon
347 cu_wrzero:
348 orl #z_mask,USER_FPSR(%a6) |set Z bit
349 cu_wreon:
350 tstw LOCAL_EX(%a0)
351 bpl wr_etemp
352 orl #neg_mask,USER_FPSR(%a6)
353 bra wr_etemp
354
355 |
356 | HANDLE SOURCE DENORM HERE
357 |
358 | ;clear denorm stag to norm
359 | ;write the new tag & ete15 to the fstack
360 mon_dnrm:
361 |
362 | At this point, check for the cases in which normalizing the
363 | denorm produces incorrect results.
364 |
365 tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would
366 bnes nrm_src |require normalization of denorm
367
368 | At this point:
369 | monadic instructions: fabs = $18 fneg = $1a ftst = $3a
370 | fmove = $00 fsmove = $40 fdmove = $44
371 | fsqrt = $05* fssqrt = $41 fdsqrt = $45
372 | (*fsqrt reencoded to $05)
373 |
374 movew CMDREG1B(%a6),%d0 |get command register
375 andil #0x7f,%d0 |strip to only command word
376 |
377 | At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
378 | fdsqrt are possible.
379 | For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
380 | For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
381 |
382 btstl #0,%d0
383 bnes nrm_src |weed out fsqrt instructions
384 st CU_ONLY(%a6) |set cu-only inst flag
385 bra cu_dnrm |fmove, fabs, fneg, ftst
386 | ;cases go to cu_dnrm
387 nrm_src:
388 bclrb #sign_bit,LOCAL_EX(%a0)
389 sne LOCAL_SGN(%a0)
390 bsr nrm_set |normalize number (exponent will go
391 | ; negative)
392 bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign
393
394 bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
395 beqs spos
396 bsetb #sign_bit,LOCAL_EX(%a0)
397 spos:
398 bfclr STAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0
399 bsetb #4,STAG(%a6) |set ETE15
400 orb #0xf0,DNRM_FLG(%a6)
401 normal:
402 tstb DNRM_FLG(%a6) |check if any of the ops were denorms
403 bne ck_wrap |if so, check if it is a potential
404 | ;wrap-around case
405 fix_stk:
406 moveb #0xfe,CU_SAVEPC(%a6)
407 bclrb #E1,E_BYTE(%a6)
408
409 clrw NMNEXC(%a6)
410
411 st RES_FLG(%a6) |indicate that a restore is needed
412 rts
413
414 |
415 | cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
416 | ftst) completely in software without an frestore to the 040.
417 |
418 cu_dnrm:
419 st CU_ONLY(%a6)
420 movew CMDREG1B(%a6),%d0
421 andib #0x3b,%d0 |isolate bits to select inst
422 tstb %d0
423 beql cu_dmove |if zero, it is an fmove
424 cmpib #0x18,%d0
425 beql cu_dabs |if $18, it is fabs
426 cmpib #0x1a,%d0
427 beql cu_dneg |if $1a, it is fneg
428 |
429 | Inst is ftst. Check the source operand and set the cc's accordingly.
430 | No write is done, so simply rts.
431 |
432 cu_dtst:
433 movew LOCAL_EX(%a0),%d0
434 bclrl #15,%d0
435 sne LOCAL_SGN(%a0)
436 beqs cu_dtpo
437 orl #neg_mask,USER_FPSR(%a6) |set N
438 cu_dtpo:
439 cmpiw #0x7fff,%d0 |test for inf/nan
440 bnes cu_dtcz
441 tstl LOCAL_HI(%a0)
442 bnes cu_dtn
443 tstl LOCAL_LO(%a0)
444 bnes cu_dtn
445 orl #inf_mask,USER_FPSR(%a6)
446 rts
447 cu_dtn:
448 orl #nan_mask,USER_FPSR(%a6)
449 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
450 | ;snan handler
451 rts
452 cu_dtcz:
453 tstl LOCAL_HI(%a0)
454 bnel cu_dtsx
455 tstl LOCAL_LO(%a0)
456 bnel cu_dtsx
457 orl #z_mask,USER_FPSR(%a6)
458 cu_dtsx:
459 rts
460 |
461 | Inst is fabs. Execute the absolute value function on the input.
462 | Branch to the fmove code.
463 |
464 cu_dabs:
465 bclrb #7,LOCAL_EX(%a0) |do abs
466 bras cu_dmove |fmove code will finish
467 |
468 | Inst is fneg. Execute the negate value function on the input.
469 | Fall though to the fmove code.
470 |
471 cu_dneg:
472 bchgb #7,LOCAL_EX(%a0) |do neg
473 |
474 | Inst is fmove. This code also handles all result writes.
475 | If bit 2 is set, round is forced to double. If it is clear,
476 | and bit 6 is set, round is forced to single. If both are clear,
477 | the round precision is found in the fpcr. If the rounding precision
478 | is double or single, the result is zero, and the mode is checked
479 | to determine if the lsb of the result should be set.
480 |
481 cu_dmove:
482 btstb #2,CMDREG1B+1(%a6) |check for rd
483 bne cu_dmrd
484 btstb #6,CMDREG1B+1(%a6) |check for rs
485 bne cu_dmrs
486 |
487 | The move or operation is not with forced precision. Use the
488 | FPCR_MODE byte to get rounding.
489 |
490 cu_dmnr:
491 bfextu FPCR_MODE(%a6){#0:#2},%d0
492 tstb %d0 |check for extended
493 beq cu_wrexd |if so, just write result
494 cmpib #1,%d0 |check for single
495 beq cu_dmrs |fall through to double
496 |
497 | The move is fdmove or round precision is double. Result is zero.
498 | Check rmode for rp or rm and set lsb accordingly.
499 |
500 cu_dmrd:
501 bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
502 tstw LOCAL_EX(%a0) |check sign
503 blts cu_dmdn
504 cmpib #3,%d1 |check for rp
505 bne cu_dpd |load double pos zero
506 bra cu_dpdr |load double pos zero w/lsb
507 cu_dmdn:
508 cmpib #2,%d1 |check for rm
509 bne cu_dnd |load double neg zero
510 bra cu_dndr |load double neg zero w/lsb
511 |
512 | The move is fsmove or round precision is single. Result is zero.
513 | Check for rp or rm and set lsb accordingly.
514 |
515 cu_dmrs:
516 bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
517 tstw LOCAL_EX(%a0) |check sign
518 blts cu_dmsn
519 cmpib #3,%d1 |check for rp
520 bne cu_spd |load single pos zero
521 bra cu_spdr |load single pos zero w/lsb
522 cu_dmsn:
523 cmpib #2,%d1 |check for rm
524 bne cu_snd |load single neg zero
525 bra cu_sndr |load single neg zero w/lsb
526 |
527 | The precision is extended, so the result in etemp is correct.
528 | Simply set unfl (not inex2 or aunfl) and write the result to
529 | the correct fp register.
530 cu_wrexd:
531 orl #unfl_mask,USER_FPSR(%a6)
532 tstw LOCAL_EX(%a0)
533 beq wr_etemp
534 orl #neg_mask,USER_FPSR(%a6)
535 bra wr_etemp
536 |
537 | These routines write +/- zero in double format. The routines
538 | cu_dpdr and cu_dndr set the double lsb.
539 |
540 cu_dpd:
541 movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero
542 clrl LOCAL_HI(%a0)
543 clrl LOCAL_LO(%a0)
544 orl #z_mask,USER_FPSR(%a6)
545 orl #unfinx_mask,USER_FPSR(%a6)
546 bra wr_etemp
547 cu_dpdr:
548 movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero
549 clrl LOCAL_HI(%a0)
550 movel #0x800,LOCAL_LO(%a0) |with lsb set
551 orl #unfinx_mask,USER_FPSR(%a6)
552 bra wr_etemp
553 cu_dnd:
554 movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero
555 clrl LOCAL_HI(%a0)
556 clrl LOCAL_LO(%a0)
557 orl #z_mask,USER_FPSR(%a6)
558 orl #neg_mask,USER_FPSR(%a6)
559 orl #unfinx_mask,USER_FPSR(%a6)
560 bra wr_etemp
561 cu_dndr:
562 movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero
563 clrl LOCAL_HI(%a0)
564 movel #0x800,LOCAL_LO(%a0) |with lsb set
565 orl #neg_mask,USER_FPSR(%a6)
566 orl #unfinx_mask,USER_FPSR(%a6)
567 bra wr_etemp
568 |
569 | These routines write +/- zero in single format. The routines
570 | cu_dpdr and cu_dndr set the single lsb.
571 |
572 cu_spd:
573 movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero
574 clrl LOCAL_HI(%a0)
575 clrl LOCAL_LO(%a0)
576 orl #z_mask,USER_FPSR(%a6)
577 orl #unfinx_mask,USER_FPSR(%a6)
578 bra wr_etemp
579 cu_spdr:
580 movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero
581 movel #0x100,LOCAL_HI(%a0) |with lsb set
582 clrl LOCAL_LO(%a0)
583 orl #unfinx_mask,USER_FPSR(%a6)
584 bra wr_etemp
585 cu_snd:
586 movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero
587 clrl LOCAL_HI(%a0)
588 clrl LOCAL_LO(%a0)
589 orl #z_mask,USER_FPSR(%a6)
590 orl #neg_mask,USER_FPSR(%a6)
591 orl #unfinx_mask,USER_FPSR(%a6)
592 bra wr_etemp
593 cu_sndr:
594 movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero
595 movel #0x100,LOCAL_HI(%a0) |with lsb set
596 clrl LOCAL_LO(%a0)
597 orl #neg_mask,USER_FPSR(%a6)
598 orl #unfinx_mask,USER_FPSR(%a6)
599 bra wr_etemp
600
601 |
602 | This code checks for 16-bit overflow conditions on dyadic
603 | operations which are not restorable into the floating-point
604 | unit and must be completed in software. Basically, this
605 | condition exists with a very large norm and a denorm. One
606 | of the operands must be denormalized to enter this code.
607 |
608 | Flags used:
609 | DY_MO_FLG contains 0 for monadic op, $ff for dyadic
610 | DNRM_FLG contains $00 for neither op denormalized
611 | $0f for the destination op denormalized
612 | $f0 for the source op denormalized
613 | $ff for both ops denormalized
614 |
615 | The wrap-around condition occurs for add, sub, div, and cmp
616 | when
617 |
618 | abs(dest_exp - src_exp) >= $8000
619 |
620 | and for mul when
621 |
622 | (dest_exp + src_exp) < $0
623 |
624 | we must process the operation here if this case is true.
625 |
626 | The rts following the frcfpn routine is the exit from res_func
627 | for this condition. The restore flag (RES_FLG) is left clear.
628 | No frestore is done unless an exception is to be reported.
629 |
630 | For fadd:
631 | if(sign_of(dest) != sign_of(src))
632 | replace exponent of src with $3fff (keep sign)
633 | use fpu to perform dest+new_src (user's rmode and X)
634 | clr sticky
635 | else
636 | set sticky
637 | call round with user's precision and mode
638 | move result to fpn and wbtemp
639 |
640 | For fsub:
641 | if(sign_of(dest) == sign_of(src))
642 | replace exponent of src with $3fff (keep sign)
643 | use fpu to perform dest+new_src (user's rmode and X)
644 | clr sticky
645 | else
646 | set sticky
647 | call round with user's precision and mode
648 | move result to fpn and wbtemp
649 |
650 | For fdiv/fsgldiv:
651 | if(both operands are denorm)
652 | restore_to_fpu;
653 | if(dest is norm)
654 | force_ovf;
655 | else(dest is denorm)
656 | force_unf:
657 |
658 | For fcmp:
659 | if(dest is norm)
660 | N = sign_of(dest);
661 | else(dest is denorm)
662 | N = sign_of(src);
663 |
664 | For fmul:
665 | if(both operands are denorm)
666 | force_unf;
667 | if((dest_exp + src_exp) < 0)
668 | force_unf:
669 | else
670 | restore_to_fpu;
671 |
672 | local equates:
673 .set addcode,0x22
674 .set subcode,0x28
675 .set mulcode,0x23
676 .set divcode,0x20
677 .set cmpcode,0x38
678 ck_wrap:
679 | tstb DY_MO_FLG(%a6) ;check for fsqrt
680 beq fix_stk |if zero, it is fsqrt
681 movew CMDREG1B(%a6),%d0
682 andiw #0x3b,%d0 |strip to command bits
683 cmpiw #addcode,%d0
684 beq wrap_add
685 cmpiw #subcode,%d0
686 beq wrap_sub
687 cmpiw #mulcode,%d0
688 beq wrap_mul
689 cmpiw #cmpcode,%d0
690 beq wrap_cmp
691 |
692 | Inst is fdiv.
693 |
694 wrap_div:
695 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
696 beq fix_stk |restore to fpu
697 |
698 | One of the ops is denormalized. Test for wrap condition
699 | and force the result.
700 |
701 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
702 bnes div_srcd
703 div_destd:
704 bsrl ckinf_ns
705 bne fix_stk
706 bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
707 bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
708 subl %d1,%d0 |subtract dest from src
709 cmpl #0x7fff,%d0
710 blt fix_stk |if less, not wrap case
711 clrb WBTEMP_SGN(%a6)
712 movew ETEMP_EX(%a6),%d0 |find the sign of the result
713 movew FPTEMP_EX(%a6),%d1
714 eorw %d1,%d0
715 andiw #0x8000,%d0
716 beq force_unf
717 st WBTEMP_SGN(%a6)
718 bra force_unf
719
720 ckinf_ns:
721 moveb STAG(%a6),%d0 |check source tag for inf or nan
722 bra ck_in_com
723 ckinf_nd:
724 moveb DTAG(%a6),%d0 |check destination tag for inf or nan
725 ck_in_com:
726 andib #0x60,%d0 |isolate tag bits
727 cmpb #0x40,%d0 |is it inf?
728 beq nan_or_inf |not wrap case
729 cmpb #0x60,%d0 |is it nan?
730 beq nan_or_inf |yes, not wrap case?
731 cmpb #0x20,%d0 |is it a zero?
732 beq nan_or_inf |yes
733 clrl %d0
734 rts |then ; it is either a zero of norm,
735 | ;check wrap case
736 nan_or_inf:
737 moveql #-1,%d0
738 rts
739
740
741
742 div_srcd:
743 bsrl ckinf_nd
744 bne fix_stk
745 bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
746 bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
747 subl %d1,%d0 |subtract src from dest
748 cmpl #0x8000,%d0
749 blt fix_stk |if less, not wrap case
750 clrb WBTEMP_SGN(%a6)
751 movew ETEMP_EX(%a6),%d0 |find the sign of the result
752 movew FPTEMP_EX(%a6),%d1
753 eorw %d1,%d0
754 andiw #0x8000,%d0
755 beqs force_ovf
756 st WBTEMP_SGN(%a6)
757 |
758 | This code handles the case of the instruction resulting in
759 | an overflow condition.
760 |
761 force_ovf:
762 bclrb #E1,E_BYTE(%a6)
763 orl #ovfl_inx_mask,USER_FPSR(%a6)
764 clrw NMNEXC(%a6)
765 leal WBTEMP(%a6),%a0 |point a0 to memory location
766 movew CMDREG1B(%a6),%d0
767 btstl #6,%d0 |test for forced precision
768 beqs frcovf_fpcr
769 btstl #2,%d0 |check for double
770 bnes frcovf_dbl
771 movel #0x1,%d0 |inst is forced single
772 bras frcovf_rnd
773 frcovf_dbl:
774 movel #0x2,%d0 |inst is forced double
775 bras frcovf_rnd
776 frcovf_fpcr:
777 bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
778 frcovf_rnd:
779
780 | The 881/882 does not set inex2 for the following case, so the
781 | line is commented out to be compatible with 881/882
782 | tst.b %d0
783 | beq.b frcovf_x
784 | or.l #inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
785
786 |frcovf_x:
787 bsrl ovf_res |get correct result based on
788 | ;round precision/mode. This
789 | ;sets FPSR_CC correctly
790 | ;returns in external format
791 bfclr WBTEMP_SGN(%a6){#0:#8}
792 beq frcfpn
793 bsetb #sign_bit,WBTEMP_EX(%a6)
794 bra frcfpn
795 |
796 | Inst is fadd.
797 |
798 wrap_add:
799 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
800 beq fix_stk |restore to fpu
801 |
802 | One of the ops is denormalized. Test for wrap condition
803 | and complete the instruction.
804 |
805 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
806 bnes add_srcd
807 add_destd:
808 bsrl ckinf_ns
809 bne fix_stk
810 bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
811 bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
812 subl %d1,%d0 |subtract dest from src
813 cmpl #0x8000,%d0
814 blt fix_stk |if less, not wrap case
815 bra add_wrap
816 add_srcd:
817 bsrl ckinf_nd
818 bne fix_stk
819 bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
820 bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
821 subl %d1,%d0 |subtract src from dest
822 cmpl #0x8000,%d0
823 blt fix_stk |if less, not wrap case
824 |
825 | Check the signs of the operands. If they are unlike, the fpu
826 | can be used to add the norm and 1.0 with the sign of the
827 | denorm and it will correctly generate the result in extended
828 | precision. We can then call round with no sticky and the result
829 | will be correct for the user's rounding mode and precision. If
830 | the signs are the same, we call round with the sticky bit set
831 | and the result will be correct for the user's rounding mode and
832 | precision.
833 |
834 add_wrap:
835 movew ETEMP_EX(%a6),%d0
836 movew FPTEMP_EX(%a6),%d1
837 eorw %d1,%d0
838 andiw #0x8000,%d0
839 beq add_same
840 |
841 | The signs are unlike.
842 |
843 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
844 bnes add_u_srcd
845 movew FPTEMP_EX(%a6),%d0
846 andiw #0x8000,%d0
847 orw #0x3fff,%d0 |force the exponent to +/- 1
848 movew %d0,FPTEMP_EX(%a6) |in the denorm
849 movel USER_FPCR(%a6),%d0
850 andil #0x30,%d0
851 fmovel %d0,%fpcr |set up users rmode and X
852 fmovex ETEMP(%a6),%fp0
853 faddx FPTEMP(%a6),%fp0
854 leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
855 fmovel %fpsr,%d1
856 orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
857 fmovex %fp0,WBTEMP(%a6) |write result to memory
858 lsrl #4,%d0 |put rmode in lower 2 bits
859 movel USER_FPCR(%a6),%d1
860 andil #0xc0,%d1
861 lsrl #6,%d1 |put precision in upper word
862 swap %d1
863 orl %d0,%d1 |set up for round call
864 clrl %d0 |force sticky to zero
865 bclrb #sign_bit,WBTEMP_EX(%a6)
866 sne WBTEMP_SGN(%a6)
867 bsrl round |round result to users rmode & prec
868 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
869 beq frcfpnr
870 bsetb #sign_bit,WBTEMP_EX(%a6)
871 bra frcfpnr
872 add_u_srcd:
873 movew ETEMP_EX(%a6),%d0
874 andiw #0x8000,%d0
875 orw #0x3fff,%d0 |force the exponent to +/- 1
876 movew %d0,ETEMP_EX(%a6) |in the denorm
877 movel USER_FPCR(%a6),%d0
878 andil #0x30,%d0
879 fmovel %d0,%fpcr |set up users rmode and X
880 fmovex ETEMP(%a6),%fp0
881 faddx FPTEMP(%a6),%fp0
882 fmovel %fpsr,%d1
883 orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
884 leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
885 fmovex %fp0,WBTEMP(%a6) |write result to memory
886 lsrl #4,%d0 |put rmode in lower 2 bits
887 movel USER_FPCR(%a6),%d1
888 andil #0xc0,%d1
889 lsrl #6,%d1 |put precision in upper word
890 swap %d1
891 orl %d0,%d1 |set up for round call
892 clrl %d0 |force sticky to zero
893 bclrb #sign_bit,WBTEMP_EX(%a6)
894 sne WBTEMP_SGN(%a6) |use internal format for round
895 bsrl round |round result to users rmode & prec
896 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
897 beq frcfpnr
898 bsetb #sign_bit,WBTEMP_EX(%a6)
899 bra frcfpnr
900 |
901 | Signs are alike:
902 |
903 add_same:
904 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
905 bnes add_s_srcd
906 add_s_destd:
907 leal ETEMP(%a6),%a0
908 movel USER_FPCR(%a6),%d0
909 andil #0x30,%d0
910 lsrl #4,%d0 |put rmode in lower 2 bits
911 movel USER_FPCR(%a6),%d1
912 andil #0xc0,%d1
913 lsrl #6,%d1 |put precision in upper word
914 swap %d1
915 orl %d0,%d1 |set up for round call
916 movel #0x20000000,%d0 |set sticky for round
917 bclrb #sign_bit,ETEMP_EX(%a6)
918 sne ETEMP_SGN(%a6)
919 bsrl round |round result to users rmode & prec
920 bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
921 beqs add_s_dclr
922 bsetb #sign_bit,ETEMP_EX(%a6)
923 add_s_dclr:
924 leal WBTEMP(%a6),%a0
925 movel ETEMP(%a6),(%a0) |write result to wbtemp
926 movel ETEMP_HI(%a6),4(%a0)
927 movel ETEMP_LO(%a6),8(%a0)
928 tstw ETEMP_EX(%a6)
929 bgt add_ckovf
930 orl #neg_mask,USER_FPSR(%a6)
931 bra add_ckovf
932 add_s_srcd:
933 leal FPTEMP(%a6),%a0
934 movel USER_FPCR(%a6),%d0
935 andil #0x30,%d0
936 lsrl #4,%d0 |put rmode in lower 2 bits
937 movel USER_FPCR(%a6),%d1
938 andil #0xc0,%d1
939 lsrl #6,%d1 |put precision in upper word
940 swap %d1
941 orl %d0,%d1 |set up for round call
942 movel #0x20000000,%d0 |set sticky for round
943 bclrb #sign_bit,FPTEMP_EX(%a6)
944 sne FPTEMP_SGN(%a6)
945 bsrl round |round result to users rmode & prec
946 bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
947 beqs add_s_sclr
948 bsetb #sign_bit,FPTEMP_EX(%a6)
949 add_s_sclr:
950 leal WBTEMP(%a6),%a0
951 movel FPTEMP(%a6),(%a0) |write result to wbtemp
952 movel FPTEMP_HI(%a6),4(%a0)
953 movel FPTEMP_LO(%a6),8(%a0)
954 tstw FPTEMP_EX(%a6)
955 bgt add_ckovf
956 orl #neg_mask,USER_FPSR(%a6)
957 add_ckovf:
958 movew WBTEMP_EX(%a6),%d0
959 andiw #0x7fff,%d0
960 cmpiw #0x7fff,%d0
961 bne frcfpnr
962 |
963 | The result has overflowed to $7fff exponent. Set I, ovfl,
964 | and aovfl, and clr the mantissa (incorrectly set by the
965 | round routine.)
966 |
967 orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
968 clrl 4(%a0)
969 bra frcfpnr
970 |
971 | Inst is fsub.
972 |
973 wrap_sub:
974 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
975 beq fix_stk |restore to fpu
976 |
977 | One of the ops is denormalized. Test for wrap condition
978 | and complete the instruction.
979 |
980 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
981 bnes sub_srcd
982 sub_destd:
983 bsrl ckinf_ns
984 bne fix_stk
985 bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
986 bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
987 subl %d1,%d0 |subtract src from dest
988 cmpl #0x8000,%d0
989 blt fix_stk |if less, not wrap case
990 bra sub_wrap
991 sub_srcd:
992 bsrl ckinf_nd
993 bne fix_stk
994 bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
995 bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
996 subl %d1,%d0 |subtract dest from src
997 cmpl #0x8000,%d0
998 blt fix_stk |if less, not wrap case
999 |
1000 | Check the signs of the operands. If they are alike, the fpu
1001 | can be used to subtract from the norm 1.0 with the sign of the
1002 | denorm and it will correctly generate the result in extended
1003 | precision. We can then call round with no sticky and the result
1004 | will be correct for the user's rounding mode and precision. If
1005 | the signs are unlike, we call round with the sticky bit set
1006 | and the result will be correct for the user's rounding mode and
1007 | precision.
1008 |
1009 sub_wrap:
1010 movew ETEMP_EX(%a6),%d0
1011 movew FPTEMP_EX(%a6),%d1
1012 eorw %d1,%d0
1013 andiw #0x8000,%d0
1014 bne sub_diff
1015 |
1016 | The signs are alike.
1017 |
1018 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
1019 bnes sub_u_srcd
1020 movew FPTEMP_EX(%a6),%d0
1021 andiw #0x8000,%d0
1022 orw #0x3fff,%d0 |force the exponent to +/- 1
1023 movew %d0,FPTEMP_EX(%a6) |in the denorm
1024 movel USER_FPCR(%a6),%d0
1025 andil #0x30,%d0
1026 fmovel %d0,%fpcr |set up users rmode and X
1027 fmovex FPTEMP(%a6),%fp0
1028 fsubx ETEMP(%a6),%fp0
1029 fmovel %fpsr,%d1
1030 orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
1031 leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
1032 fmovex %fp0,WBTEMP(%a6) |write result to memory
1033 lsrl #4,%d0 |put rmode in lower 2 bits
1034 movel USER_FPCR(%a6),%d1
1035 andil #0xc0,%d1
1036 lsrl #6,%d1 |put precision in upper word
1037 swap %d1
1038 orl %d0,%d1 |set up for round call
1039 clrl %d0 |force sticky to zero
1040 bclrb #sign_bit,WBTEMP_EX(%a6)
1041 sne WBTEMP_SGN(%a6)
1042 bsrl round |round result to users rmode & prec
1043 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1044 beq frcfpnr
1045 bsetb #sign_bit,WBTEMP_EX(%a6)
1046 bra frcfpnr
1047 sub_u_srcd:
1048 movew ETEMP_EX(%a6),%d0
1049 andiw #0x8000,%d0
1050 orw #0x3fff,%d0 |force the exponent to +/- 1
1051 movew %d0,ETEMP_EX(%a6) |in the denorm
1052 movel USER_FPCR(%a6),%d0
1053 andil #0x30,%d0
1054 fmovel %d0,%fpcr |set up users rmode and X
1055 fmovex FPTEMP(%a6),%fp0
1056 fsubx ETEMP(%a6),%fp0
1057 fmovel %fpsr,%d1
1058 orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
1059 leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
1060 fmovex %fp0,WBTEMP(%a6) |write result to memory
1061 lsrl #4,%d0 |put rmode in lower 2 bits
1062 movel USER_FPCR(%a6),%d1
1063 andil #0xc0,%d1
1064 lsrl #6,%d1 |put precision in upper word
1065 swap %d1
1066 orl %d0,%d1 |set up for round call
1067 clrl %d0 |force sticky to zero
1068 bclrb #sign_bit,WBTEMP_EX(%a6)
1069 sne WBTEMP_SGN(%a6)
1070 bsrl round |round result to users rmode & prec
1071 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1072 beq frcfpnr
1073 bsetb #sign_bit,WBTEMP_EX(%a6)
1074 bra frcfpnr
1075 |
1076 | Signs are unlike:
1077 |
1078 sub_diff:
1079 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
1080 bnes sub_s_srcd
1081 sub_s_destd:
1082 leal ETEMP(%a6),%a0
1083 movel USER_FPCR(%a6),%d0
1084 andil #0x30,%d0
1085 lsrl #4,%d0 |put rmode in lower 2 bits
1086 movel USER_FPCR(%a6),%d1
1087 andil #0xc0,%d1
1088 lsrl #6,%d1 |put precision in upper word
1089 swap %d1
1090 orl %d0,%d1 |set up for round call
1091 movel #0x20000000,%d0 |set sticky for round
1092 |
1093 | Since the dest is the denorm, the sign is the opposite of the
1094 | norm sign.
1095 |
1096 eoriw #0x8000,ETEMP_EX(%a6) |flip sign on result
1097 tstw ETEMP_EX(%a6)
1098 bgts sub_s_dwr
1099 orl #neg_mask,USER_FPSR(%a6)
1100 sub_s_dwr:
1101 bclrb #sign_bit,ETEMP_EX(%a6)
1102 sne ETEMP_SGN(%a6)
1103 bsrl round |round result to users rmode & prec
1104 bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1105 beqs sub_s_dclr
1106 bsetb #sign_bit,ETEMP_EX(%a6)
1107 sub_s_dclr:
1108 leal WBTEMP(%a6),%a0
1109 movel ETEMP(%a6),(%a0) |write result to wbtemp
1110 movel ETEMP_HI(%a6),4(%a0)
1111 movel ETEMP_LO(%a6),8(%a0)
1112 bra sub_ckovf
1113 sub_s_srcd:
1114 leal FPTEMP(%a6),%a0
1115 movel USER_FPCR(%a6),%d0
1116 andil #0x30,%d0
1117 lsrl #4,%d0 |put rmode in lower 2 bits
1118 movel USER_FPCR(%a6),%d1
1119 andil #0xc0,%d1
1120 lsrl #6,%d1 |put precision in upper word
1121 swap %d1
1122 orl %d0,%d1 |set up for round call
1123 movel #0x20000000,%d0 |set sticky for round
1124 bclrb #sign_bit,FPTEMP_EX(%a6)
1125 sne FPTEMP_SGN(%a6)
1126 bsrl round |round result to users rmode & prec
1127 bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1128 beqs sub_s_sclr
1129 bsetb #sign_bit,FPTEMP_EX(%a6)
1130 sub_s_sclr:
1131 leal WBTEMP(%a6),%a0
1132 movel FPTEMP(%a6),(%a0) |write result to wbtemp
1133 movel FPTEMP_HI(%a6),4(%a0)
1134 movel FPTEMP_LO(%a6),8(%a0)
1135 tstw FPTEMP_EX(%a6)
1136 bgt sub_ckovf
1137 orl #neg_mask,USER_FPSR(%a6)
1138 sub_ckovf:
1139 movew WBTEMP_EX(%a6),%d0
1140 andiw #0x7fff,%d0
1141 cmpiw #0x7fff,%d0
1142 bne frcfpnr
1143 |
1144 | The result has overflowed to $7fff exponent. Set I, ovfl,
1145 | and aovfl, and clr the mantissa (incorrectly set by the
1146 | round routine.)
1147 |
1148 orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
1149 clrl 4(%a0)
1150 bra frcfpnr
1151 |
1152 | Inst is fcmp.
1153 |
1154 wrap_cmp:
1155 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
1156 beq fix_stk |restore to fpu
1157 |
1158 | One of the ops is denormalized. Test for wrap condition
1159 | and complete the instruction.
1160 |
1161 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
1162 bnes cmp_srcd
1163 cmp_destd:
1164 bsrl ckinf_ns
1165 bne fix_stk
1166 bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
1167 bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
1168 subl %d1,%d0 |subtract dest from src
1169 cmpl #0x8000,%d0
1170 blt fix_stk |if less, not wrap case
1171 tstw ETEMP_EX(%a6) |set N to ~sign_of(src)
1172 bge cmp_setn
1173 rts
1174 cmp_srcd:
1175 bsrl ckinf_nd
1176 bne fix_stk
1177 bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
1178 bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
1179 subl %d1,%d0 |subtract src from dest
1180 cmpl #0x8000,%d0
1181 blt fix_stk |if less, not wrap case
1182 tstw FPTEMP_EX(%a6) |set N to sign_of(dest)
1183 blt cmp_setn
1184 rts
1185 cmp_setn:
1186 orl #neg_mask,USER_FPSR(%a6)
1187 rts
1188
1189 |
1190 | Inst is fmul.
1191 |
1192 wrap_mul:
1193 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
1194 beq force_unf |force an underflow (really!)
1195 |
1196 | One of the ops is denormalized. Test for wrap condition
1197 | and complete the instruction.
1198 |
1199 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
1200 bnes mul_srcd
1201 mul_destd:
1202 bsrl ckinf_ns
1203 bne fix_stk
1204 bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
1205 bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
1206 addl %d1,%d0 |subtract dest from src
1207 bgt fix_stk
1208 bra force_unf
1209 mul_srcd:
1210 bsrl ckinf_nd
1211 bne fix_stk
1212 bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
1213 bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
1214 addl %d1,%d0 |subtract src from dest
1215 bgt fix_stk
1216
1217 |
1218 | This code handles the case of the instruction resulting in
1219 | an underflow condition.
1220 |
1221 force_unf:
1222 bclrb #E1,E_BYTE(%a6)
1223 orl #unfinx_mask,USER_FPSR(%a6)
1224 clrw NMNEXC(%a6)
1225 clrb WBTEMP_SGN(%a6)
1226 movew ETEMP_EX(%a6),%d0 |find the sign of the result
1227 movew FPTEMP_EX(%a6),%d1
1228 eorw %d1,%d0
1229 andiw #0x8000,%d0
1230 beqs frcunfcont
1231 st WBTEMP_SGN(%a6)
1232 frcunfcont:
1233 lea WBTEMP(%a6),%a0 |point a0 to memory location
1234 movew CMDREG1B(%a6),%d0
1235 btstl #6,%d0 |test for forced precision
1236 beqs frcunf_fpcr
1237 btstl #2,%d0 |check for double
1238 bnes frcunf_dbl
1239 movel #0x1,%d0 |inst is forced single
1240 bras frcunf_rnd
1241 frcunf_dbl:
1242 movel #0x2,%d0 |inst is forced double
1243 bras frcunf_rnd
1244 frcunf_fpcr:
1245 bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
1246 frcunf_rnd:
1247 bsrl unf_sub |get correct result based on
1248 | ;round precision/mode. This
1249 | ;sets FPSR_CC correctly
1250 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1251 beqs frcfpn
1252 bsetb #sign_bit,WBTEMP_EX(%a6)
1253 bra frcfpn
1254
1255 |
1256 | Write the result to the user's fpn. All results must be HUGE to be
1257 | written; otherwise the results would have overflowed or underflowed.
1258 | If the rounding precision is single or double, the ovf_res routine
1259 | is needed to correctly supply the max value.
1260 |
1261 frcfpnr:
1262 movew CMDREG1B(%a6),%d0
1263 btstl #6,%d0 |test for forced precision
1264 beqs frcfpn_fpcr
1265 btstl #2,%d0 |check for double
1266 bnes frcfpn_dbl
1267 movel #0x1,%d0 |inst is forced single
1268 bras frcfpn_rnd
1269 frcfpn_dbl:
1270 movel #0x2,%d0 |inst is forced double
1271 bras frcfpn_rnd
1272 frcfpn_fpcr:
1273 bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
1274 tstb %d0
1275 beqs frcfpn |if extended, write what you got
1276 frcfpn_rnd:
1277 bclrb #sign_bit,WBTEMP_EX(%a6)
1278 sne WBTEMP_SGN(%a6)
1279 bsrl ovf_res |get correct result based on
1280 | ;round precision/mode. This
1281 | ;sets FPSR_CC correctly
1282 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1283 beqs frcfpn_clr
1284 bsetb #sign_bit,WBTEMP_EX(%a6)
1285 frcfpn_clr:
1286 orl #ovfinx_mask,USER_FPSR(%a6)
1287 |
1288 | Perform the write.
1289 |
1290 frcfpn:
1291 bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register
1292 cmpib #3,%d0
1293 bles frc0123 |check if dest is fp0-fp3
1294 movel #7,%d1
1295 subl %d0,%d1
1296 clrl %d0
1297 bsetl %d1,%d0
1298 fmovemx WBTEMP(%a6),%d0
1299 rts
1300 frc0123:
1301 cmpib #0,%d0
1302 beqs frc0_dst
1303 cmpib #1,%d0
1304 beqs frc1_dst
1305 cmpib #2,%d0
1306 beqs frc2_dst
1307 frc3_dst:
1308 movel WBTEMP_EX(%a6),USER_FP3(%a6)
1309 movel WBTEMP_HI(%a6),USER_FP3+4(%a6)
1310 movel WBTEMP_LO(%a6),USER_FP3+8(%a6)
1311 rts
1312 frc2_dst:
1313 movel WBTEMP_EX(%a6),USER_FP2(%a6)
1314 movel WBTEMP_HI(%a6),USER_FP2+4(%a6)
1315 movel WBTEMP_LO(%a6),USER_FP2+8(%a6)
1316 rts
1317 frc1_dst:
1318 movel WBTEMP_EX(%a6),USER_FP1(%a6)
1319 movel WBTEMP_HI(%a6),USER_FP1+4(%a6)
1320 movel WBTEMP_LO(%a6),USER_FP1+8(%a6)
1321 rts
1322 frc0_dst:
1323 movel WBTEMP_EX(%a6),USER_FP0(%a6)
1324 movel WBTEMP_HI(%a6),USER_FP0+4(%a6)
1325 movel WBTEMP_LO(%a6),USER_FP0+8(%a6)
1326 rts
1327
1328 |
1329 | Write etemp to fpn.
1330 | A check is made on enabled and signalled snan exceptions,
1331 | and the destination is not overwritten if this condition exists.
1332 | This code is designed to make fmoveins of unsupported data types
1333 | faster.
1334 |
1335 wr_etemp:
1336 btstb #snan_bit,FPSR_EXCEPT(%a6) |if snan is set, and
1337 beqs fmoveinc |enabled, force restore
1338 btstb #snan_bit,FPCR_ENABLE(%a6) |and don't overwrite
1339 beqs fmoveinc |the dest
1340 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
1341 | ;snan handler
1342 tstb ETEMP(%a6) |check for negative
1343 blts snan_neg
1344 rts
1345 snan_neg:
1346 orl #neg_bit,USER_FPSR(%a6) |snan is negative; set N
1347 rts
1348 fmoveinc:
1349 clrw NMNEXC(%a6)
1350 bclrb #E1,E_BYTE(%a6)
1351 moveb STAG(%a6),%d0 |check if stag is inf
1352 andib #0xe0,%d0
1353 cmpib #0x40,%d0
1354 bnes fminc_cnan
1355 orl #inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I
1356 tstw LOCAL_EX(%a0) |check sign
1357 bges fminc_con
1358 orl #neg_mask,USER_FPSR(%a6)
1359 bra fminc_con
1360 fminc_cnan:
1361 cmpib #0x60,%d0 |check if stag is NaN
1362 bnes fminc_czero
1363 orl #nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaN
1364 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
1365 | ;snan handler
1366 tstw LOCAL_EX(%a0) |check sign
1367 bges fminc_con
1368 orl #neg_mask,USER_FPSR(%a6)
1369 bra fminc_con
1370 fminc_czero:
1371 cmpib #0x20,%d0 |check if zero
1372 bnes fminc_con
1373 orl #z_mask,USER_FPSR(%a6) |if zero, set Z
1374 tstw LOCAL_EX(%a0) |check sign
1375 bges fminc_con
1376 orl #neg_mask,USER_FPSR(%a6)
1377 fminc_con:
1378 bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register
1379 cmpib #3,%d0
1380 bles fp0123 |check if dest is fp0-fp3
1381 movel #7,%d1
1382 subl %d0,%d1
1383 clrl %d0
1384 bsetl %d1,%d0
1385 fmovemx ETEMP(%a6),%d0
1386 rts
1387
1388 fp0123:
1389 cmpib #0,%d0
1390 beqs fp0_dst
1391 cmpib #1,%d0
1392 beqs fp1_dst
1393 cmpib #2,%d0
1394 beqs fp2_dst
1395 fp3_dst:
1396 movel ETEMP_EX(%a6),USER_FP3(%a6)
1397 movel ETEMP_HI(%a6),USER_FP3+4(%a6)
1398 movel ETEMP_LO(%a6),USER_FP3+8(%a6)
1399 rts
1400 fp2_dst:
1401 movel ETEMP_EX(%a6),USER_FP2(%a6)
1402 movel ETEMP_HI(%a6),USER_FP2+4(%a6)
1403 movel ETEMP_LO(%a6),USER_FP2+8(%a6)
1404 rts
1405 fp1_dst:
1406 movel ETEMP_EX(%a6),USER_FP1(%a6)
1407 movel ETEMP_HI(%a6),USER_FP1+4(%a6)
1408 movel ETEMP_LO(%a6),USER_FP1+8(%a6)
1409 rts
1410 fp0_dst:
1411 movel ETEMP_EX(%a6),USER_FP0(%a6)
1412 movel ETEMP_HI(%a6),USER_FP0+4(%a6)
1413 movel ETEMP_LO(%a6),USER_FP0+8(%a6)
1414 rts
1415
1416 opclass3:
1417 st CU_ONLY(%a6)
1418 movew CMDREG1B(%a6),%d0 |check if packed moveout
1419 andiw #0x0c00,%d0 |isolate last 2 bits of size field
1420 cmpiw #0x0c00,%d0 |if size is 011 or 111, it is packed
1421 beq pack_out |else it is norm or denorm
1422 bra mv_out
1423
1424
1425 |
1426 | MOVE OUT
1427 |
1428
1429 mv_tbl:
1430 .long li
1431 .long sgp
1432 .long xp
1433 .long mvout_end |should never be taken
1434 .long wi
1435 .long dp
1436 .long bi
1437 .long mvout_end |should never be taken
1438 mv_out:
1439 bfextu CMDREG1B(%a6){#3:#3},%d1 |put source specifier in d1
1440 leal mv_tbl,%a0
1441 movel %a0@(%d1:l:4),%a0
1442 jmp (%a0)
1443
1444 |
1445 | This exit is for move-out to memory. The aunfl bit is
1446 | set if the result is inex and unfl is signalled.
1447 |
1448 mvout_end:
1449 btstb #inex2_bit,FPSR_EXCEPT(%a6)
1450 beqs no_aufl
1451 btstb #unfl_bit,FPSR_EXCEPT(%a6)
1452 beqs no_aufl
1453 bsetb #aunfl_bit,FPSR_AEXCEPT(%a6)
1454 no_aufl:
1455 clrw NMNEXC(%a6)
1456 bclrb #E1,E_BYTE(%a6)
1457 fmovel #0,%FPSR |clear any cc bits from res_func
1458 |
1459 | Return ETEMP to extended format from internal extended format so
1460 | that gen_except will have a correctly signed value for ovfl/unfl
1461 | handlers.
1462 |
1463 bfclr ETEMP_SGN(%a6){#0:#8}
1464 beqs mvout_con
1465 bsetb #sign_bit,ETEMP_EX(%a6)
1466 mvout_con:
1467 rts
1468 |
1469 | This exit is for move-out to int register. The aunfl bit is
1470 | not set in any case for this move.
1471 |
1472 mvouti_end:
1473 clrw NMNEXC(%a6)
1474 bclrb #E1,E_BYTE(%a6)
1475 fmovel #0,%FPSR |clear any cc bits from res_func
1476 |
1477 | Return ETEMP to extended format from internal extended format so
1478 | that gen_except will have a correctly signed value for ovfl/unfl
1479 | handlers.
1480 |
1481 bfclr ETEMP_SGN(%a6){#0:#8}
1482 beqs mvouti_con
1483 bsetb #sign_bit,ETEMP_EX(%a6)
1484 mvouti_con:
1485 rts
1486 |
1487 | li is used to handle a long integer source specifier
1488 |
1489
1490 li:
1491 moveql #4,%d0 |set byte count
1492
1493 btstb #7,STAG(%a6) |check for extended denorm
1494 bne int_dnrm |if so, branch
1495
1496 fmovemx ETEMP(%a6),%fp0-%fp0
1497 fcmpd #0x41dfffffffc00000,%fp0
1498 | 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
1499 fbge lo_plrg
1500 fcmpd #0xc1e0000000000000,%fp0
1501 | c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
1502 fble lo_nlrg
1503 |
1504 | at this point, the answer is between the largest pos and neg values
1505 |
1506 movel USER_FPCR(%a6),%d1 |use user's rounding mode
1507 andil #0x30,%d1
1508 fmovel %d1,%fpcr
1509 fmovel %fp0,L_SCR1(%a6) |let the 040 perform conversion
1510 fmovel %fpsr,%d1
1511 orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set
1512 bra int_wrt
1513
1514
1515 lo_plrg:
1516 movel #0x7fffffff,L_SCR1(%a6) |answer is largest positive int
1517 fbeq int_wrt |exact answer
1518 fcmpd #0x41dfffffffe00000,%fp0
1519 | 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
1520 fbge int_operr |set operr
1521 bra int_inx |set inexact
1522
1523 lo_nlrg:
1524 movel #0x80000000,L_SCR1(%a6)
1525 fbeq int_wrt |exact answer
1526 fcmpd #0xc1e0000000100000,%fp0
1527 | c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
1528 fblt int_operr |set operr
1529 bra int_inx |set inexact
1530
1531 |
1532 | wi is used to handle a word integer source specifier
1533 |
1534
1535 wi:
1536 moveql #2,%d0 |set byte count
1537
1538 btstb #7,STAG(%a6) |check for extended denorm
1539 bne int_dnrm |branch if so
1540
1541 fmovemx ETEMP(%a6),%fp0-%fp0
1542 fcmps #0x46fffe00,%fp0
1543 | 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
1544 fbge wo_plrg
1545 fcmps #0xc7000000,%fp0
1546 | c7000000 in sgl prec = c00e00008000000000000000 in ext prec
1547 fble wo_nlrg
1548
1549 |
1550 | at this point, the answer is between the largest pos and neg values
1551 |
1552 movel USER_FPCR(%a6),%d1 |use user's rounding mode
1553 andil #0x30,%d1
1554 fmovel %d1,%fpcr
1555 fmovew %fp0,L_SCR1(%a6) |let the 040 perform conversion
1556 fmovel %fpsr,%d1
1557 orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set
1558 bra int_wrt
1559
1560 wo_plrg:
1561 movew #0x7fff,L_SCR1(%a6) |answer is largest positive int
1562 fbeq int_wrt |exact answer
1563 fcmps #0x46ffff00,%fp0
1564 | 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
1565 fbge int_operr |set operr
1566 bra int_inx |set inexact
1567
1568 wo_nlrg:
1569 movew #0x8000,L_SCR1(%a6)
1570 fbeq int_wrt |exact answer
1571 fcmps #0xc7000080,%fp0
1572 | c7000080 in sgl prec = c00e00008000800000000000 in ext prec
1573 fblt int_operr |set operr
1574 bra int_inx |set inexact
1575
1576 |
1577 | bi is used to handle a byte integer source specifier
1578 |
1579
1580 bi:
1581 moveql #1,%d0 |set byte count
1582
1583 btstb #7,STAG(%a6) |check for extended denorm
1584 bne int_dnrm |branch if so
1585
1586 fmovemx ETEMP(%a6),%fp0-%fp0
1587 fcmps #0x42fe0000,%fp0
1588 | 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
1589 fbge by_plrg
1590 fcmps #0xc3000000,%fp0
1591 | c3000000 in sgl prec = c00600008000000000000000 in ext prec
1592 fble by_nlrg
1593
1594 |
1595 | at this point, the answer is between the largest pos and neg values
1596 |
1597 movel USER_FPCR(%a6),%d1 |use user's rounding mode
1598 andil #0x30,%d1
1599 fmovel %d1,%fpcr
1600 fmoveb %fp0,L_SCR1(%a6) |let the 040 perform conversion
1601 fmovel %fpsr,%d1
1602 orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set
1603 bra int_wrt
1604
1605 by_plrg:
1606 moveb #0x7f,L_SCR1(%a6) |answer is largest positive int
1607 fbeq int_wrt |exact answer
1608 fcmps #0x42ff0000,%fp0
1609 | 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
1610 fbge int_operr |set operr
1611 bra int_inx |set inexact
1612
1613 by_nlrg:
1614 moveb #0x80,L_SCR1(%a6)
1615 fbeq int_wrt |exact answer
1616 fcmps #0xc3008000,%fp0
1617 | c3008000 in sgl prec = c00600008080000000000000 in ext prec
1618 fblt int_operr |set operr
1619 bra int_inx |set inexact
1620
1621 |
1622 | Common integer routines
1623 |
1624 | int_drnrm---account for possible nonzero result for round up with positive
1625 | operand and round down for negative answer. In the first case (result = 1)
1626 | byte-width (store in d0) of result must be honored. In the second case,
1627 | -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).
1628
1629 int_dnrm:
1630 movel #0,L_SCR1(%a6) | initialize result to 0
1631 bfextu FPCR_MODE(%a6){#2:#2},%d1 | d1 is the rounding mode
1632 cmpb #2,%d1
1633 bmis int_inx | if RN or RZ, done
1634 bnes int_rp | if RP, continue below
1635 tstw ETEMP(%a6) | RM: store -1 in L_SCR1 if src is negative
1636 bpls int_inx | otherwise result is 0
1637 movel #-1,L_SCR1(%a6)
1638 bras int_inx
1639 int_rp:
1640 tstw ETEMP(%a6) | RP: store +1 of proper width in L_SCR1 if
1641 | ; source is greater than 0
1642 bmis int_inx | otherwise, result is 0
1643 lea L_SCR1(%a6),%a1 | a1 is address of L_SCR1
1644 addal %d0,%a1 | offset by destination width -1
1645 subal #1,%a1
1646 bsetb #0,(%a1) | set low bit at a1 address
1647 int_inx:
1648 oril #inx2a_mask,USER_FPSR(%a6)
1649 bras int_wrt
1650 int_operr:
1651 fmovemx %fp0-%fp0,FPTEMP(%a6) |FPTEMP must contain the extended
1652 | ;precision source that needs to be
1653 | ;converted to integer this is required
1654 | ;if the operr exception is enabled.
1655 | ;set operr/aiop (no inex2 on int ovfl)
1656
1657 oril #opaop_mask,USER_FPSR(%a6)
1658 | ;fall through to perform int_wrt
1659 int_wrt:
1660 movel EXC_EA(%a6),%a1 |load destination address
1661 tstl %a1 |check to see if it is a dest register
1662 beqs wrt_dn |write data register
1663 lea L_SCR1(%a6),%a0 |point to supervisor source address
1664 bsrl mem_write
1665 bra mvouti_end
1666
1667 wrt_dn:
1668 movel %d0,-(%sp) |d0 currently contains the size to write
1669 bsrl get_fline |get_fline returns Dn in d0
1670 andiw #0x7,%d0 |isolate register
1671 movel (%sp)+,%d1 |get size
1672 cmpil #4,%d1 |most frequent case
1673 beqs sz_long
1674 cmpil #2,%d1
1675 bnes sz_con
1676 orl #8,%d0 |add 'word' size to register#
1677 bras sz_con
1678 sz_long:
1679 orl #0x10,%d0 |add 'long' size to register#
1680 sz_con:
1681 movel %d0,%d1 |reg_dest expects size:reg in d1
1682 bsrl reg_dest |load proper data register
1683 bra mvouti_end
1684 xp:
1685 lea ETEMP(%a6),%a0
1686 bclrb #sign_bit,LOCAL_EX(%a0)
1687 sne LOCAL_SGN(%a0)
1688 btstb #7,STAG(%a6) |check for extended denorm
1689 bne xdnrm
1690 clrl %d0
1691 bras do_fp |do normal case
1692 sgp:
1693 lea ETEMP(%a6),%a0
1694 bclrb #sign_bit,LOCAL_EX(%a0)
1695 sne LOCAL_SGN(%a0)
1696 btstb #7,STAG(%a6) |check for extended denorm
1697 bne sp_catas |branch if so
1698 movew LOCAL_EX(%a0),%d0
1699 lea sp_bnds,%a1
1700 cmpw (%a1),%d0
1701 blt sp_under
1702 cmpw 2(%a1),%d0
1703 bgt sp_over
1704 movel #1,%d0 |set destination format to single
1705 bras do_fp |do normal case
1706 dp:
1707 lea ETEMP(%a6),%a0
1708 bclrb #sign_bit,LOCAL_EX(%a0)
1709 sne LOCAL_SGN(%a0)
1710
1711 btstb #7,STAG(%a6) |check for extended denorm
1712 bne dp_catas |branch if so
1713
1714 movew LOCAL_EX(%a0),%d0
1715 lea dp_bnds,%a1
1716
1717 cmpw (%a1),%d0
1718 blt dp_under
1719 cmpw 2(%a1),%d0
1720 bgt dp_over
1721
1722 movel #2,%d0 |set destination format to double
1723 | ;fall through to do_fp
1724 |
1725 do_fp:
1726 bfextu FPCR_MODE(%a6){#2:#2},%d1 |rnd mode in d1
1727 swap %d0 |rnd prec in upper word
1728 addl %d0,%d1 |d1 has PREC/MODE info
1729
1730 clrl %d0 |clear g,r,s
1731
1732 bsrl round |round
1733
1734 movel %a0,%a1
1735 movel EXC_EA(%a6),%a0
1736
1737 bfextu CMDREG1B(%a6){#3:#3},%d1 |extract destination format
1738 | ;at this point only the dest
1739 | ;formats sgl, dbl, ext are
1740 | ;possible
1741 cmpb #2,%d1
1742 bgts ddbl |double=5, extended=2, single=1
1743 bnes dsgl
1744 | ;fall through to dext
1745 dext:
1746 bsrl dest_ext
1747 bra mvout_end
1748 dsgl:
1749 bsrl dest_sgl
1750 bra mvout_end
1751 ddbl:
1752 bsrl dest_dbl
1753 bra mvout_end
1754
1755 |
1756 | Handle possible denorm or catastrophic underflow cases here
1757 |
1758 xdnrm:
1759 bsr set_xop |initialize WBTEMP
1760 bsetb #wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15
1761
1762 movel %a0,%a1
1763 movel EXC_EA(%a6),%a0 |a0 has the destination pointer
1764 bsrl dest_ext |store to memory
1765 bsetb #unfl_bit,FPSR_EXCEPT(%a6)
1766 bra mvout_end
1767
1768 sp_under:
1769 bsetb #etemp15_bit,STAG(%a6)
1770
1771 cmpw 4(%a1),%d0
1772 blts sp_catas |catastrophic underflow case
1773
1774 movel #1,%d0 |load in round precision
1775 movel #sgl_thresh,%d1 |load in single denorm threshold
1776 bsrl dpspdnrm |expects d1 to have the proper
1777 | ;denorm threshold
1778 bsrl dest_sgl |stores value to destination
1779 bsetb #unfl_bit,FPSR_EXCEPT(%a6)
1780 bra mvout_end |exit
1781
1782 dp_under:
1783 bsetb #etemp15_bit,STAG(%a6)
1784
1785 cmpw 4(%a1),%d0
1786 blts dp_catas |catastrophic underflow case
1787
1788 movel #dbl_thresh,%d1 |load in double precision threshold
1789 movel #2,%d0
1790 bsrl dpspdnrm |expects d1 to have proper
1791 | ;denorm threshold
1792 | ;expects d0 to have round precision
1793 bsrl dest_dbl |store value to destination
1794 bsetb #unfl_bit,FPSR_EXCEPT(%a6)
1795 bra mvout_end |exit
1796
1797 |
1798 | Handle catastrophic underflow cases here
1799 |
1800 sp_catas:
1801 | Temp fix for z bit set in unf_sub
1802 movel USER_FPSR(%a6),-(%a7)
1803
1804 movel #1,%d0 |set round precision to sgl
1805
1806 bsrl unf_sub |a0 points to result
1807
1808 movel (%a7)+,USER_FPSR(%a6)
1809
1810 movel #1,%d0
1811 subw %d0,LOCAL_EX(%a0) |account for difference between
1812 | ;denorm/norm bias
1813
1814 movel %a0,%a1 |a1 has the operand input
1815 movel EXC_EA(%a6),%a0 |a0 has the destination pointer
1816
1817 bsrl dest_sgl |store the result
1818 oril #unfinx_mask,USER_FPSR(%a6)
1819 bra mvout_end
1820
1821 dp_catas:
1822 | Temp fix for z bit set in unf_sub
1823 movel USER_FPSR(%a6),-(%a7)
1824
1825 movel #2,%d0 |set round precision to dbl
1826 bsrl unf_sub |a0 points to result
1827
1828 movel (%a7)+,USER_FPSR(%a6)
1829
1830 movel #1,%d0
1831 subw %d0,LOCAL_EX(%a0) |account for difference between
1832 | ;denorm/norm bias
1833
1834 movel %a0,%a1 |a1 has the operand input
1835 movel EXC_EA(%a6),%a0 |a0 has the destination pointer
1836
1837 bsrl dest_dbl |store the result
1838 oril #unfinx_mask,USER_FPSR(%a6)
1839 bra mvout_end
1840
1841 |
1842 | Handle catastrophic overflow cases here
1843 |
1844 sp_over:
1845 | Temp fix for z bit set in unf_sub
1846 movel USER_FPSR(%a6),-(%a7)
1847
1848 movel #1,%d0
1849 leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result
1850 movel ETEMP_EX(%a6),(%a0)
1851 movel ETEMP_HI(%a6),4(%a0)
1852 movel ETEMP_LO(%a6),8(%a0)
1853 bsrl ovf_res
1854
1855 movel (%a7)+,USER_FPSR(%a6)
1856
1857 movel %a0,%a1
1858 movel EXC_EA(%a6),%a0
1859 bsrl dest_sgl
1860 orl #ovfinx_mask,USER_FPSR(%a6)
1861 bra mvout_end
1862
1863 dp_over:
1864 | Temp fix for z bit set in ovf_res
1865 movel USER_FPSR(%a6),-(%a7)
1866
1867 movel #2,%d0
1868 leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result
1869 movel ETEMP_EX(%a6),(%a0)
1870 movel ETEMP_HI(%a6),4(%a0)
1871 movel ETEMP_LO(%a6),8(%a0)
1872 bsrl ovf_res
1873
1874 movel (%a7)+,USER_FPSR(%a6)
1875
1876 movel %a0,%a1
1877 movel EXC_EA(%a6),%a0
1878 bsrl dest_dbl
1879 orl #ovfinx_mask,USER_FPSR(%a6)
1880 bra mvout_end
1881
1882 |
1883 | DPSPDNRM
1884 |
1885 | This subroutine takes an extended normalized number and denormalizes
1886 | it to the given round precision. This subroutine also decrements
1887 | the input operand's exponent by 1 to account for the fact that
1888 | dest_sgl or dest_dbl expects a normalized number's bias.
1889 |
1890 | Input: a0 points to a normalized number in internal extended format
1891 | d0 is the round precision (=1 for sgl; =2 for dbl)
1892 | d1 is the single precision or double precision
1893 | denorm threshold
1894 |
1895 | Output: (In the format for dest_sgl or dest_dbl)
1896 | a0 points to the destination
1897 | a1 points to the operand
1898 |
1899 | Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
1900 |
1901 dpspdnrm:
1902 movel %d0,-(%a7) |save round precision
1903 clrl %d0 |clear initial g,r,s
1904 bsrl dnrm_lp |careful with d0, it's needed by round
1905
1906 bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode
1907 swap %d1
1908 movew 2(%a7),%d1 |set rounding precision
1909 swap %d1 |at this point d1 has PREC/MODE info
1910 bsrl round |round result, sets the inex bit in
1911 | ;USER_FPSR if needed
1912
1913 movew #1,%d0
1914 subw %d0,LOCAL_EX(%a0) |account for difference in denorm
1915 | ;vs norm bias
1916
1917 movel %a0,%a1 |a1 has the operand input
1918 movel EXC_EA(%a6),%a0 |a0 has the destination pointer
1919 addw #4,%a7 |pop stack
1920 rts
1921 |
1922 | SET_XOP initialized WBTEMP with the value pointed to by a0
1923 | input: a0 points to input operand in the internal extended format
1924 |
1925 set_xop:
1926 movel LOCAL_EX(%a0),WBTEMP_EX(%a6)
1927 movel LOCAL_HI(%a0),WBTEMP_HI(%a6)
1928 movel LOCAL_LO(%a0),WBTEMP_LO(%a6)
1929 bfclr WBTEMP_SGN(%a6){#0:#8}
1930 beqs sxop
1931 bsetb #sign_bit,WBTEMP_EX(%a6)
1932 sxop:
1933 bfclr STAG(%a6){#5:#4} |clear wbtm66,wbtm1,wbtm0,sbit
1934 rts
1935 |
1936 | P_MOVE
1937 |
1938 p_movet:
1939 .long p_move
1940 .long p_movez
1941 .long p_movei
1942 .long p_moven
1943 .long p_move
1944 p_regd:
1945 .long p_dyd0
1946 .long p_dyd1
1947 .long p_dyd2
1948 .long p_dyd3
1949 .long p_dyd4
1950 .long p_dyd5
1951 .long p_dyd6
1952 .long p_dyd7
1953
1954 pack_out:
1955 leal p_movet,%a0 |load jmp table address
1956 movew STAG(%a6),%d0 |get source tag
1957 bfextu %d0{#16:#3},%d0 |isolate source bits
1958 movel (%a0,%d0.w*4),%a0 |load a0 with routine label for tag
1959 jmp (%a0) |go to the routine
1960
1961 p_write:
1962 movel #0x0c,%d0 |get byte count
1963 movel EXC_EA(%a6),%a1 |get the destination address
1964 bsr mem_write |write the user's destination
1965 moveb #0,CU_SAVEPC(%a6) |set the cu save pc to all 0's
1966
1967 |
1968 | Also note that the dtag must be set to norm here - this is because
1969 | the 040 uses the dtag to execute the correct microcode.
1970 |
1971 bfclr DTAG(%a6){#0:#3} |set dtag to norm
1972
1973 rts
1974
1975 | Notes on handling of special case (zero, inf, and nan) inputs:
1976 | 1. Operr is not signalled if the k-factor is greater than 18.
1977 | 2. Per the manual, status bits are not set.
1978 |
1979
1980 p_move:
1981 movew CMDREG1B(%a6),%d0
1982 btstl #kfact_bit,%d0 |test for dynamic k-factor
1983 beqs statick |if clear, k-factor is static
1984 dynamick:
1985 bfextu %d0{#25:#3},%d0 |isolate register for dynamic k-factor
1986 lea p_regd,%a0
1987 movel %a0@(%d0:l:4),%a0
1988 jmp (%a0)
1989 statick:
1990 andiw #0x007f,%d0 |get k-factor
1991 bfexts %d0{#25:#7},%d0 |sign extend d0 for bindec
1992 leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
1993 bsrl bindec |perform the convert; data at a6
1994 leal FP_SCR1(%a6),%a0 |load a0 with result address
1995 bral p_write
1996 p_movez:
1997 leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
1998 clrw 2(%a0) |clear lower word of exp
1999 clrl 4(%a0) |load second lword of ZERO
2000 clrl 8(%a0) |load third lword of ZERO
2001 bra p_write |go write results
2002 p_movei:
2003 fmovel #0,%FPSR |clear aiop
2004 leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
2005 clrw 2(%a0) |clear lower word of exp
2006 bra p_write |go write the result
2007 p_moven:
2008 leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
2009 clrw 2(%a0) |clear lower word of exp
2010 bra p_write |go write the result
2011
2012 |
2013 | Routines to read the dynamic k-factor from Dn.
2014 |
2015 p_dyd0:
2016 movel USER_D0(%a6),%d0
2017 bras statick
2018 p_dyd1:
2019 movel USER_D1(%a6),%d0
2020 bras statick
2021 p_dyd2:
2022 movel %d2,%d0
2023 bras statick
2024 p_dyd3:
2025 movel %d3,%d0
2026 bras statick
2027 p_dyd4:
2028 movel %d4,%d0
2029 bras statick
2030 p_dyd5:
2031 movel %d5,%d0
2032 bras statick
2033 p_dyd6:
2034 movel %d6,%d0
2035 bra statick
2036 p_dyd7:
2037 movel %d7,%d0
2038 bra statick
2039
2040 |end