2 | res_func.sa 3.9 7/29/91
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).
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.
16 | Copyright (C) Motorola, Inc. 1990
19 | For details on the license for this file, please see the
20 | file, README, in this same directory.
22 RES_FUNC: |idnt 2,1 | Motorola 040 Floating Point Software Package
28 sp_bnds: .short 0x3f81,0x407e
30 dp_bnds: .short 0x3c01,0x43fe
59 btstb #7,DTAG(%a6) |if dop = norm=000, zero=001,
61 beqs monadic |then branch
63 | HANDLE DESTINATION DENORM HERE
65 | ;write the tag & fpte15 to the fstack
68 bclrb #sign_bit,LOCAL_EX(%a0)
71 bsr nrm_set |normalize number (exp will go negative)
72 bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign
73 bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
75 bsetb #sign_bit,LOCAL_EX(%a0)
77 bfclr DTAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0
78 bsetb #4,DTAG(%a6) |set FPTE15
79 orb #0x0f,DNRM_FLG(%a6)
82 btstb #direction_bit,CMDREG1B(%a6) |check direction
83 bne opclass3 |it is a mv out
85 | At this point, only opclass 0 and 2 possible
87 btstb #7,STAG(%a6) |if sop = norm=000, zero=001,
89 bne mon_dnrm |else denorm
90 tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would
91 bne normal |require normalization of denorm
94 | monadic instructions: fabs = $18 fneg = $1a ftst = $3a
95 | fmove = $00 fsmove = $40 fdmove = $44
96 | fsqrt = $05* fssqrt = $41 fdsqrt = $45
97 | (*fsqrt reencoded to $05)
99 movew CMDREG1B(%a6),%d0 |get command register
100 andil #0x7f,%d0 |strip to only command word
102 | At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
103 | fdsqrt are possible.
104 | For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
105 | For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
108 bne normal |weed out fsqrt instructions
110 | cu_norm handles fmove in instructions with normalized inputs.
111 | The routine round is used to correctly round the input for the
112 | destination precision and mode.
115 st CU_ONLY(%a6) |set cu-only inst flag
116 movew CMDREG1B(%a6),%d0
117 andib #0x3b,%d0 |isolate bits to select inst
119 beql cu_nmove |if zero, it is an fmove
121 beql cu_nabs |if $18, it is fabs
123 beql cu_nneg |if $1a, it is fneg
125 | Inst is ftst. Check the source operand and set the cc's accordingly.
126 | No write is done, so simply rts.
129 movew LOCAL_EX(%a0),%d0
133 orl #neg_mask,USER_FPSR(%a6) |set N
135 cmpiw #0x7fff,%d0 |test for inf/nan
141 orl #inf_mask,USER_FPSR(%a6)
144 orl #nan_mask,USER_FPSR(%a6)
145 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
154 orl #z_mask,USER_FPSR(%a6)
158 | Inst is fabs. Execute the absolute value function on the input.
159 | Branch to the fmove code. If the operand is NaN, do nothing.
163 btstl #5,%d0 |test for NaN or zero
164 bne wr_etemp |if either, simply write it
165 bclrb #7,LOCAL_EX(%a0) |do abs
166 bras cu_nmove |fmove code will finish
168 | Inst is fneg. Execute the negate value function on the input.
169 | Fall though to the fmove code. If the operand is NaN, do nothing.
173 btstl #5,%d0 |test for NaN or zero
174 bne wr_etemp |if either, simply write it
175 bchgb #7,LOCAL_EX(%a0) |do neg
177 | Inst is fmove. This code also handles all result writes.
178 | If bit 2 is set, round is forced to double. If it is clear,
179 | and bit 6 is set, round is forced to single. If both are clear,
180 | the round precision is found in the fpcr. If the rounding precision
181 | is double or single, round the result before the write.
185 andib #0xe0,%d0 |isolate stag bits
186 bne wr_etemp |if not norm, simply write it
187 btstb #2,CMDREG1B+1(%a6) |check for rd
189 btstb #6,CMDREG1B+1(%a6) |check for rs
192 | The move or operation is not with forced precision. Test for
193 | nan or inf as the input; if so, simply write it to FPn. Use the
194 | FPCR_MODE byte to get rounding on norms and zeros.
197 bfextu FPCR_MODE(%a6){#0:#2},%d0
198 tstb %d0 |check for extended
199 beq cu_wrexn |if so, just write result
200 cmpib #1,%d0 |check for single
201 beq cu_nmrs |fall through to double
203 | The move is fdmove or round precision is double.
206 movel #2,%d0 |set up the size for denorm
207 movew LOCAL_EX(%a0),%d1 |compare exponent to double threshold
211 bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
212 orl #0x00020000,%d1 |or in rprec (double)
213 clrl %d0 |clear g,r,s for round
214 bclrb #sign_bit,LOCAL_EX(%a0) |convert to internal format
217 bfclr LOCAL_SGN(%a0){#0:#8}
219 bsetb #sign_bit,LOCAL_EX(%a0)
221 movew LOCAL_EX(%a0),%d1 |check for overflow
224 bge cu_novfl |take care of overflow case
227 | The move is fsmove or round precision is single.
231 movew LOCAL_EX(%a0),%d1
235 bfextu FPCR_MODE(%a6){#2:#2},%d1
238 bclrb #sign_bit,LOCAL_EX(%a0)
241 bfclr LOCAL_SGN(%a0){#0:#8}
243 bsetb #sign_bit,LOCAL_EX(%a0)
245 movew LOCAL_EX(%a0),%d1
250 | The operand is above precision boundaries. Use t_ovfl to
251 | generate the correct value.
257 | The operand is below precision boundaries. Use denorm to
258 | generate the correct value.
261 bclrb #sign_bit,LOCAL_EX(%a0)
264 bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
266 bsetb #sign_bit,LOCAL_EX(%a0)
268 bfextu FPCR_MODE(%a6){#2:#2},%d1
269 btstb #2,CMDREG1B+1(%a6) |check for rd
271 btstb #6,CMDREG1B+1(%a6) |check for rs
274 moveb FPCR_MODE(%a6),%d1
284 bclrb #sign_bit,LOCAL_EX(%a0)
287 bfclr LOCAL_SGN(%a0){#0:#8}
289 bsetb #sign_bit,LOCAL_EX(%a0)
291 btstb #inex2_bit,FPSR_EXCEPT(%a6)
293 orl #aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL
295 tstl LOCAL_HI(%a0) |test for zero
300 | The mantissa is zero from the denorm loop. Check sign and rmode
301 | to see if rounding should have occurred which would leave the lsb.
303 movel USER_FPCR(%a6),%d0
304 andil #0x30,%d0 |isolate rmode
309 tstw LOCAL_EX(%a0) |if positive, set lsb
311 btstb #7,FPCR_MODE(%a6) |check for double
315 tstw LOCAL_EX(%a0) |if positive, set lsb
317 btstb #7,FPCR_MODE(%a6) |check for double
320 orl #0x800,LOCAL_LO(%a0) |inc for double
323 orl #0x100,LOCAL_HI(%a0) |inc for single
326 orl #z_mask,USER_FPSR(%a6)
329 cmpib #0x40,%d0 |check if input was tagged zero
332 orl #unfl_mask,USER_FPSR(%a6) |set unfl
334 movel (%a0),ETEMP(%a6)
335 movel 4(%a0),ETEMP_HI(%a6)
336 movel 8(%a0),ETEMP_LO(%a6)
338 | Write the result to memory, setting the fpsr cc bits. NaN and Inf
342 tstw LOCAL_EX(%a0) |test for zero
344 cmpw #0x8000,LOCAL_EX(%a0) |test for zero
347 orl #z_mask,USER_FPSR(%a6) |set Z bit
351 orl #neg_mask,USER_FPSR(%a6)
355 | HANDLE SOURCE DENORM HERE
357 | ;clear denorm stag to norm
358 | ;write the new tag & ete15 to the fstack
361 | At this point, check for the cases in which normalizing the
362 | denorm produces incorrect results.
364 tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would
365 bnes nrm_src |require normalization of denorm
368 | monadic instructions: fabs = $18 fneg = $1a ftst = $3a
369 | fmove = $00 fsmove = $40 fdmove = $44
370 | fsqrt = $05* fssqrt = $41 fdsqrt = $45
371 | (*fsqrt reencoded to $05)
373 movew CMDREG1B(%a6),%d0 |get command register
374 andil #0x7f,%d0 |strip to only command word
376 | At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
377 | fdsqrt are possible.
378 | For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
379 | For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
382 bnes nrm_src |weed out fsqrt instructions
383 st CU_ONLY(%a6) |set cu-only inst flag
384 bra cu_dnrm |fmove, fabs, fneg, ftst
385 | ;cases go to cu_dnrm
387 bclrb #sign_bit,LOCAL_EX(%a0)
389 bsr nrm_set |normalize number (exponent will go
391 bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign
393 bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
395 bsetb #sign_bit,LOCAL_EX(%a0)
397 bfclr STAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0
398 bsetb #4,STAG(%a6) |set ETE15
399 orb #0xf0,DNRM_FLG(%a6)
401 tstb DNRM_FLG(%a6) |check if any of the ops were denorms
402 bne ck_wrap |if so, check if it is a potential
405 moveb #0xfe,CU_SAVEPC(%a6)
406 bclrb #E1,E_BYTE(%a6)
410 st RES_FLG(%a6) |indicate that a restore is needed
414 | cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
415 | ftst) completely in software without an frestore to the 040.
419 movew CMDREG1B(%a6),%d0
420 andib #0x3b,%d0 |isolate bits to select inst
422 beql cu_dmove |if zero, it is an fmove
424 beql cu_dabs |if $18, it is fabs
426 beql cu_dneg |if $1a, it is fneg
428 | Inst is ftst. Check the source operand and set the cc's accordingly.
429 | No write is done, so simply rts.
432 movew LOCAL_EX(%a0),%d0
436 orl #neg_mask,USER_FPSR(%a6) |set N
438 cmpiw #0x7fff,%d0 |test for inf/nan
444 orl #inf_mask,USER_FPSR(%a6)
447 orl #nan_mask,USER_FPSR(%a6)
448 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
456 orl #z_mask,USER_FPSR(%a6)
460 | Inst is fabs. Execute the absolute value function on the input.
461 | Branch to the fmove code.
464 bclrb #7,LOCAL_EX(%a0) |do abs
465 bras cu_dmove |fmove code will finish
467 | Inst is fneg. Execute the negate value function on the input.
468 | Fall though to the fmove code.
471 bchgb #7,LOCAL_EX(%a0) |do neg
473 | Inst is fmove. This code also handles all result writes.
474 | If bit 2 is set, round is forced to double. If it is clear,
475 | and bit 6 is set, round is forced to single. If both are clear,
476 | the round precision is found in the fpcr. If the rounding precision
477 | is double or single, the result is zero, and the mode is checked
478 | to determine if the lsb of the result should be set.
481 btstb #2,CMDREG1B+1(%a6) |check for rd
483 btstb #6,CMDREG1B+1(%a6) |check for rs
486 | The move or operation is not with forced precision. Use the
487 | FPCR_MODE byte to get rounding.
490 bfextu FPCR_MODE(%a6){#0:#2},%d0
491 tstb %d0 |check for extended
492 beq cu_wrexd |if so, just write result
493 cmpib #1,%d0 |check for single
494 beq cu_dmrs |fall through to double
496 | The move is fdmove or round precision is double. Result is zero.
497 | Check rmode for rp or rm and set lsb accordingly.
500 bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
501 tstw LOCAL_EX(%a0) |check sign
503 cmpib #3,%d1 |check for rp
504 bne cu_dpd |load double pos zero
505 bra cu_dpdr |load double pos zero w/lsb
507 cmpib #2,%d1 |check for rm
508 bne cu_dnd |load double neg zero
509 bra cu_dndr |load double neg zero w/lsb
511 | The move is fsmove or round precision is single. Result is zero.
512 | Check for rp or rm and set lsb accordingly.
515 bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
516 tstw LOCAL_EX(%a0) |check sign
518 cmpib #3,%d1 |check for rp
519 bne cu_spd |load single pos zero
520 bra cu_spdr |load single pos zero w/lsb
522 cmpib #2,%d1 |check for rm
523 bne cu_snd |load single neg zero
524 bra cu_sndr |load single neg zero w/lsb
526 | The precision is extended, so the result in etemp is correct.
527 | Simply set unfl (not inex2 or aunfl) and write the result to
528 | the correct fp register.
530 orl #unfl_mask,USER_FPSR(%a6)
533 orl #neg_mask,USER_FPSR(%a6)
536 | These routines write +/- zero in double format. The routines
537 | cu_dpdr and cu_dndr set the double lsb.
540 movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero
543 orl #z_mask,USER_FPSR(%a6)
544 orl #unfinx_mask,USER_FPSR(%a6)
547 movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero
549 movel #0x800,LOCAL_LO(%a0) |with lsb set
550 orl #unfinx_mask,USER_FPSR(%a6)
553 movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero
556 orl #z_mask,USER_FPSR(%a6)
557 orl #neg_mask,USER_FPSR(%a6)
558 orl #unfinx_mask,USER_FPSR(%a6)
561 movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero
563 movel #0x800,LOCAL_LO(%a0) |with lsb set
564 orl #neg_mask,USER_FPSR(%a6)
565 orl #unfinx_mask,USER_FPSR(%a6)
568 | These routines write +/- zero in single format. The routines
569 | cu_dpdr and cu_dndr set the single lsb.
572 movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero
575 orl #z_mask,USER_FPSR(%a6)
576 orl #unfinx_mask,USER_FPSR(%a6)
579 movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero
580 movel #0x100,LOCAL_HI(%a0) |with lsb set
582 orl #unfinx_mask,USER_FPSR(%a6)
585 movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero
588 orl #z_mask,USER_FPSR(%a6)
589 orl #neg_mask,USER_FPSR(%a6)
590 orl #unfinx_mask,USER_FPSR(%a6)
593 movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero
594 movel #0x100,LOCAL_HI(%a0) |with lsb set
596 orl #neg_mask,USER_FPSR(%a6)
597 orl #unfinx_mask,USER_FPSR(%a6)
601 | This code checks for 16-bit overflow conditions on dyadic
602 | operations which are not restorable into the floating-point
603 | unit and must be completed in software. Basically, this
604 | condition exists with a very large norm and a denorm. One
605 | of the operands must be denormalized to enter this code.
608 | DY_MO_FLG contains 0 for monadic op, $ff for dyadic
609 | DNRM_FLG contains $00 for neither op denormalized
610 | $0f for the destination op denormalized
611 | $f0 for the source op denormalized
612 | $ff for both ops denormalized
614 | The wrap-around condition occurs for add, sub, div, and cmp
617 | abs(dest_exp - src_exp) >= $8000
621 | (dest_exp + src_exp) < $0
623 | we must process the operation here if this case is true.
625 | The rts following the frcfpn routine is the exit from res_func
626 | for this condition. The restore flag (RES_FLG) is left clear.
627 | No frestore is done unless an exception is to be reported.
630 | if(sign_of(dest) != sign_of(src))
631 | replace exponent of src with $3fff (keep sign)
632 | use fpu to perform dest+new_src (user's rmode and X)
636 | call round with user's precision and mode
637 | move result to fpn and wbtemp
640 | if(sign_of(dest) == sign_of(src))
641 | replace exponent of src with $3fff (keep sign)
642 | use fpu to perform dest+new_src (user's rmode and X)
646 | call round with user's precision and mode
647 | move result to fpn and wbtemp
650 | if(both operands are denorm)
654 | else(dest is denorm)
660 | else(dest is denorm)
664 | if(both operands are denorm)
666 | if((dest_exp + src_exp) < 0)
678 | tstb DY_MO_FLG(%a6) ;check for fsqrt
679 beq fix_stk |if zero, it is fsqrt
680 movew CMDREG1B(%a6),%d0
681 andiw #0x3b,%d0 |strip to command bits
694 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
695 beq fix_stk |restore to fpu
697 | One of the ops is denormalized. Test for wrap condition
698 | and force the result.
700 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
705 bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
706 bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
707 subl %d1,%d0 |subtract dest from src
709 blt fix_stk |if less, not wrap case
711 movew ETEMP_EX(%a6),%d0 |find the sign of the result
712 movew FPTEMP_EX(%a6),%d1
720 moveb STAG(%a6),%d0 |check source tag for inf or nan
723 moveb DTAG(%a6),%d0 |check destination tag for inf or nan
725 andib #0x60,%d0 |isolate tag bits
726 cmpb #0x40,%d0 |is it inf?
727 beq nan_or_inf |not wrap case
728 cmpb #0x60,%d0 |is it nan?
729 beq nan_or_inf |yes, not wrap case?
730 cmpb #0x20,%d0 |is it a zero?
733 rts |then ; it is either a zero of norm,
744 bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
745 bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
746 subl %d1,%d0 |subtract src from dest
748 blt fix_stk |if less, not wrap case
750 movew ETEMP_EX(%a6),%d0 |find the sign of the result
751 movew FPTEMP_EX(%a6),%d1
757 | This code handles the case of the instruction resulting in
758 | an overflow condition.
761 bclrb #E1,E_BYTE(%a6)
762 orl #ovfl_inx_mask,USER_FPSR(%a6)
764 leal WBTEMP(%a6),%a0 |point a0 to memory location
765 movew CMDREG1B(%a6),%d0
766 btstl #6,%d0 |test for forced precision
768 btstl #2,%d0 |check for double
770 movel #0x1,%d0 |inst is forced single
773 movel #0x2,%d0 |inst is forced double
776 bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
779 | The 881/882 does not set inex2 for the following case, so the
780 | line is commented out to be compatible with 881/882
783 | or.l #inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
786 bsrl ovf_res |get correct result based on
787 | ;round precision/mode. This
788 | ;sets FPSR_CC correctly
789 | ;returns in external format
790 bfclr WBTEMP_SGN(%a6){#0:#8}
792 bsetb #sign_bit,WBTEMP_EX(%a6)
798 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
799 beq fix_stk |restore to fpu
801 | One of the ops is denormalized. Test for wrap condition
802 | and complete the instruction.
804 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
809 bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
810 bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
811 subl %d1,%d0 |subtract dest from src
813 blt fix_stk |if less, not wrap case
818 bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
819 bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
820 subl %d1,%d0 |subtract src from dest
822 blt fix_stk |if less, not wrap case
824 | Check the signs of the operands. If they are unlike, the fpu
825 | can be used to add the norm and 1.0 with the sign of the
826 | denorm and it will correctly generate the result in extended
827 | precision. We can then call round with no sticky and the result
828 | will be correct for the user's rounding mode and precision. If
829 | the signs are the same, we call round with the sticky bit set
830 | and the result will be correct for the user's rounding mode and
834 movew ETEMP_EX(%a6),%d0
835 movew FPTEMP_EX(%a6),%d1
840 | The signs are unlike.
842 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
844 movew FPTEMP_EX(%a6),%d0
846 orw #0x3fff,%d0 |force the exponent to +/- 1
847 movew %d0,FPTEMP_EX(%a6) |in the denorm
848 movel USER_FPCR(%a6),%d0
850 fmovel %d0,%fpcr |set up users rmode and X
851 fmovex ETEMP(%a6),%fp0
852 faddx FPTEMP(%a6),%fp0
853 leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
855 orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
856 fmovex %fp0,WBTEMP(%a6) |write result to memory
857 lsrl #4,%d0 |put rmode in lower 2 bits
858 movel USER_FPCR(%a6),%d1
860 lsrl #6,%d1 |put precision in upper word
862 orl %d0,%d1 |set up for round call
863 clrl %d0 |force sticky to zero
864 bclrb #sign_bit,WBTEMP_EX(%a6)
866 bsrl round |round result to users rmode & prec
867 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
869 bsetb #sign_bit,WBTEMP_EX(%a6)
872 movew ETEMP_EX(%a6),%d0
874 orw #0x3fff,%d0 |force the exponent to +/- 1
875 movew %d0,ETEMP_EX(%a6) |in the denorm
876 movel USER_FPCR(%a6),%d0
878 fmovel %d0,%fpcr |set up users rmode and X
879 fmovex ETEMP(%a6),%fp0
880 faddx FPTEMP(%a6),%fp0
882 orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
883 leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
884 fmovex %fp0,WBTEMP(%a6) |write result to memory
885 lsrl #4,%d0 |put rmode in lower 2 bits
886 movel USER_FPCR(%a6),%d1
888 lsrl #6,%d1 |put precision in upper word
890 orl %d0,%d1 |set up for round call
891 clrl %d0 |force sticky to zero
892 bclrb #sign_bit,WBTEMP_EX(%a6)
893 sne WBTEMP_SGN(%a6) |use internal format for round
894 bsrl round |round result to users rmode & prec
895 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
897 bsetb #sign_bit,WBTEMP_EX(%a6)
903 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
907 movel USER_FPCR(%a6),%d0
909 lsrl #4,%d0 |put rmode in lower 2 bits
910 movel USER_FPCR(%a6),%d1
912 lsrl #6,%d1 |put precision in upper word
914 orl %d0,%d1 |set up for round call
915 movel #0x20000000,%d0 |set sticky for round
916 bclrb #sign_bit,ETEMP_EX(%a6)
918 bsrl round |round result to users rmode & prec
919 bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
921 bsetb #sign_bit,ETEMP_EX(%a6)
924 movel ETEMP(%a6),(%a0) |write result to wbtemp
925 movel ETEMP_HI(%a6),4(%a0)
926 movel ETEMP_LO(%a6),8(%a0)
929 orl #neg_mask,USER_FPSR(%a6)
933 movel USER_FPCR(%a6),%d0
935 lsrl #4,%d0 |put rmode in lower 2 bits
936 movel USER_FPCR(%a6),%d1
938 lsrl #6,%d1 |put precision in upper word
940 orl %d0,%d1 |set up for round call
941 movel #0x20000000,%d0 |set sticky for round
942 bclrb #sign_bit,FPTEMP_EX(%a6)
944 bsrl round |round result to users rmode & prec
945 bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
947 bsetb #sign_bit,FPTEMP_EX(%a6)
950 movel FPTEMP(%a6),(%a0) |write result to wbtemp
951 movel FPTEMP_HI(%a6),4(%a0)
952 movel FPTEMP_LO(%a6),8(%a0)
955 orl #neg_mask,USER_FPSR(%a6)
957 movew WBTEMP_EX(%a6),%d0
962 | The result has overflowed to $7fff exponent. Set I, ovfl,
963 | and aovfl, and clr the mantissa (incorrectly set by the
966 orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
973 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
974 beq fix_stk |restore to fpu
976 | One of the ops is denormalized. Test for wrap condition
977 | and complete the instruction.
979 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
984 bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
985 bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
986 subl %d1,%d0 |subtract src from dest
988 blt fix_stk |if less, not wrap case
993 bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
994 bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
995 subl %d1,%d0 |subtract dest from src
997 blt fix_stk |if less, not wrap case
999 | Check the signs of the operands. If they are alike, the fpu
1000 | can be used to subtract from the norm 1.0 with the sign of the
1001 | denorm and it will correctly generate the result in extended
1002 | precision. We can then call round with no sticky and the result
1003 | will be correct for the user's rounding mode and precision. If
1004 | the signs are unlike, we call round with the sticky bit set
1005 | and the result will be correct for the user's rounding mode and
1009 movew ETEMP_EX(%a6),%d0
1010 movew FPTEMP_EX(%a6),%d1
1015 | The signs are alike.
1017 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
1019 movew FPTEMP_EX(%a6),%d0
1021 orw #0x3fff,%d0 |force the exponent to +/- 1
1022 movew %d0,FPTEMP_EX(%a6) |in the denorm
1023 movel USER_FPCR(%a6),%d0
1025 fmovel %d0,%fpcr |set up users rmode and X
1026 fmovex FPTEMP(%a6),%fp0
1027 fsubx ETEMP(%a6),%fp0
1029 orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
1030 leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
1031 fmovex %fp0,WBTEMP(%a6) |write result to memory
1032 lsrl #4,%d0 |put rmode in lower 2 bits
1033 movel USER_FPCR(%a6),%d1
1035 lsrl #6,%d1 |put precision in upper word
1037 orl %d0,%d1 |set up for round call
1038 clrl %d0 |force sticky to zero
1039 bclrb #sign_bit,WBTEMP_EX(%a6)
1041 bsrl round |round result to users rmode & prec
1042 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1044 bsetb #sign_bit,WBTEMP_EX(%a6)
1047 movew ETEMP_EX(%a6),%d0
1049 orw #0x3fff,%d0 |force the exponent to +/- 1
1050 movew %d0,ETEMP_EX(%a6) |in the denorm
1051 movel USER_FPCR(%a6),%d0
1053 fmovel %d0,%fpcr |set up users rmode and X
1054 fmovex FPTEMP(%a6),%fp0
1055 fsubx ETEMP(%a6),%fp0
1057 orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
1058 leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
1059 fmovex %fp0,WBTEMP(%a6) |write result to memory
1060 lsrl #4,%d0 |put rmode in lower 2 bits
1061 movel USER_FPCR(%a6),%d1
1063 lsrl #6,%d1 |put precision in upper word
1065 orl %d0,%d1 |set up for round call
1066 clrl %d0 |force sticky to zero
1067 bclrb #sign_bit,WBTEMP_EX(%a6)
1069 bsrl round |round result to users rmode & prec
1070 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1072 bsetb #sign_bit,WBTEMP_EX(%a6)
1078 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
1082 movel USER_FPCR(%a6),%d0
1084 lsrl #4,%d0 |put rmode in lower 2 bits
1085 movel USER_FPCR(%a6),%d1
1087 lsrl #6,%d1 |put precision in upper word
1089 orl %d0,%d1 |set up for round call
1090 movel #0x20000000,%d0 |set sticky for round
1092 | Since the dest is the denorm, the sign is the opposite of the
1095 eoriw #0x8000,ETEMP_EX(%a6) |flip sign on result
1098 orl #neg_mask,USER_FPSR(%a6)
1100 bclrb #sign_bit,ETEMP_EX(%a6)
1102 bsrl round |round result to users rmode & prec
1103 bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1105 bsetb #sign_bit,ETEMP_EX(%a6)
1107 leal WBTEMP(%a6),%a0
1108 movel ETEMP(%a6),(%a0) |write result to wbtemp
1109 movel ETEMP_HI(%a6),4(%a0)
1110 movel ETEMP_LO(%a6),8(%a0)
1113 leal FPTEMP(%a6),%a0
1114 movel USER_FPCR(%a6),%d0
1116 lsrl #4,%d0 |put rmode in lower 2 bits
1117 movel USER_FPCR(%a6),%d1
1119 lsrl #6,%d1 |put precision in upper word
1121 orl %d0,%d1 |set up for round call
1122 movel #0x20000000,%d0 |set sticky for round
1123 bclrb #sign_bit,FPTEMP_EX(%a6)
1125 bsrl round |round result to users rmode & prec
1126 bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1128 bsetb #sign_bit,FPTEMP_EX(%a6)
1130 leal WBTEMP(%a6),%a0
1131 movel FPTEMP(%a6),(%a0) |write result to wbtemp
1132 movel FPTEMP_HI(%a6),4(%a0)
1133 movel FPTEMP_LO(%a6),8(%a0)
1136 orl #neg_mask,USER_FPSR(%a6)
1138 movew WBTEMP_EX(%a6),%d0
1143 | The result has overflowed to $7fff exponent. Set I, ovfl,
1144 | and aovfl, and clr the mantissa (incorrectly set by the
1147 orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
1154 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
1155 beq fix_stk |restore to fpu
1157 | One of the ops is denormalized. Test for wrap condition
1158 | and complete the instruction.
1160 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
1165 bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
1166 bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
1167 subl %d1,%d0 |subtract dest from src
1169 blt fix_stk |if less, not wrap case
1170 tstw ETEMP_EX(%a6) |set N to ~sign_of(src)
1176 bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
1177 bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
1178 subl %d1,%d0 |subtract src from dest
1180 blt fix_stk |if less, not wrap case
1181 tstw FPTEMP_EX(%a6) |set N to sign_of(dest)
1185 orl #neg_mask,USER_FPSR(%a6)
1192 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
1193 beq force_unf |force an underflow (really!)
1195 | One of the ops is denormalized. Test for wrap condition
1196 | and complete the instruction.
1198 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
1203 bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
1204 bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
1205 addl %d1,%d0 |subtract dest from src
1211 bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
1212 bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
1213 addl %d1,%d0 |subtract src from dest
1217 | This code handles the case of the instruction resulting in
1218 | an underflow condition.
1221 bclrb #E1,E_BYTE(%a6)
1222 orl #unfinx_mask,USER_FPSR(%a6)
1224 clrb WBTEMP_SGN(%a6)
1225 movew ETEMP_EX(%a6),%d0 |find the sign of the result
1226 movew FPTEMP_EX(%a6),%d1
1232 lea WBTEMP(%a6),%a0 |point a0 to memory location
1233 movew CMDREG1B(%a6),%d0
1234 btstl #6,%d0 |test for forced precision
1236 btstl #2,%d0 |check for double
1238 movel #0x1,%d0 |inst is forced single
1241 movel #0x2,%d0 |inst is forced double
1244 bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
1246 bsrl unf_sub |get correct result based on
1247 | ;round precision/mode. This
1248 | ;sets FPSR_CC correctly
1249 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1251 bsetb #sign_bit,WBTEMP_EX(%a6)
1255 | Write the result to the user's fpn. All results must be HUGE to be
1256 | written; otherwise the results would have overflowed or underflowed.
1257 | If the rounding precision is single or double, the ovf_res routine
1258 | is needed to correctly supply the max value.
1261 movew CMDREG1B(%a6),%d0
1262 btstl #6,%d0 |test for forced precision
1264 btstl #2,%d0 |check for double
1266 movel #0x1,%d0 |inst is forced single
1269 movel #0x2,%d0 |inst is forced double
1272 bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
1274 beqs frcfpn |if extended, write what you got
1276 bclrb #sign_bit,WBTEMP_EX(%a6)
1278 bsrl ovf_res |get correct result based on
1279 | ;round precision/mode. This
1280 | ;sets FPSR_CC correctly
1281 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1283 bsetb #sign_bit,WBTEMP_EX(%a6)
1285 orl #ovfinx_mask,USER_FPSR(%a6)
1287 | Perform the write.
1290 bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register
1292 bles frc0123 |check if dest is fp0-fp3
1297 fmovemx WBTEMP(%a6),%d0
1307 movel WBTEMP_EX(%a6),USER_FP3(%a6)
1308 movel WBTEMP_HI(%a6),USER_FP3+4(%a6)
1309 movel WBTEMP_LO(%a6),USER_FP3+8(%a6)
1312 movel WBTEMP_EX(%a6),USER_FP2(%a6)
1313 movel WBTEMP_HI(%a6),USER_FP2+4(%a6)
1314 movel WBTEMP_LO(%a6),USER_FP2+8(%a6)
1317 movel WBTEMP_EX(%a6),USER_FP1(%a6)
1318 movel WBTEMP_HI(%a6),USER_FP1+4(%a6)
1319 movel WBTEMP_LO(%a6),USER_FP1+8(%a6)
1322 movel WBTEMP_EX(%a6),USER_FP0(%a6)
1323 movel WBTEMP_HI(%a6),USER_FP0+4(%a6)
1324 movel WBTEMP_LO(%a6),USER_FP0+8(%a6)
1328 | Write etemp to fpn.
1329 | A check is made on enabled and signalled snan exceptions,
1330 | and the destination is not overwritten if this condition exists.
1331 | This code is designed to make fmoveins of unsupported data types
1335 btstb #snan_bit,FPSR_EXCEPT(%a6) |if snan is set, and
1336 beqs fmoveinc |enabled, force restore
1337 btstb #snan_bit,FPCR_ENABLE(%a6) |and don't overwrite
1338 beqs fmoveinc |the dest
1339 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
1341 tstb ETEMP(%a6) |check for negative
1345 orl #neg_bit,USER_FPSR(%a6) |snan is negative; set N
1349 bclrb #E1,E_BYTE(%a6)
1350 moveb STAG(%a6),%d0 |check if stag is inf
1354 orl #inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I
1355 tstw LOCAL_EX(%a0) |check sign
1357 orl #neg_mask,USER_FPSR(%a6)
1360 cmpib #0x60,%d0 |check if stag is NaN
1362 orl #nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaN
1363 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
1365 tstw LOCAL_EX(%a0) |check sign
1367 orl #neg_mask,USER_FPSR(%a6)
1370 cmpib #0x20,%d0 |check if zero
1372 orl #z_mask,USER_FPSR(%a6) |if zero, set Z
1373 tstw LOCAL_EX(%a0) |check sign
1375 orl #neg_mask,USER_FPSR(%a6)
1377 bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register
1379 bles fp0123 |check if dest is fp0-fp3
1384 fmovemx ETEMP(%a6),%d0
1395 movel ETEMP_EX(%a6),USER_FP3(%a6)
1396 movel ETEMP_HI(%a6),USER_FP3+4(%a6)
1397 movel ETEMP_LO(%a6),USER_FP3+8(%a6)
1400 movel ETEMP_EX(%a6),USER_FP2(%a6)
1401 movel ETEMP_HI(%a6),USER_FP2+4(%a6)
1402 movel ETEMP_LO(%a6),USER_FP2+8(%a6)
1405 movel ETEMP_EX(%a6),USER_FP1(%a6)
1406 movel ETEMP_HI(%a6),USER_FP1+4(%a6)
1407 movel ETEMP_LO(%a6),USER_FP1+8(%a6)
1410 movel ETEMP_EX(%a6),USER_FP0(%a6)
1411 movel ETEMP_HI(%a6),USER_FP0+4(%a6)
1412 movel ETEMP_LO(%a6),USER_FP0+8(%a6)
1417 movew CMDREG1B(%a6),%d0 |check if packed moveout
1418 andiw #0x0c00,%d0 |isolate last 2 bits of size field
1419 cmpiw #0x0c00,%d0 |if size is 011 or 111, it is packed
1420 beq pack_out |else it is norm or denorm
1432 .long mvout_end |should never be taken
1436 .long mvout_end |should never be taken
1438 bfextu CMDREG1B(%a6){#3:#3},%d1 |put source specifier in d1
1440 movel %a0@(%d1:l:4),%a0
1444 | This exit is for move-out to memory. The aunfl bit is
1445 | set if the result is inex and unfl is signalled.
1448 btstb #inex2_bit,FPSR_EXCEPT(%a6)
1450 btstb #unfl_bit,FPSR_EXCEPT(%a6)
1452 bsetb #aunfl_bit,FPSR_AEXCEPT(%a6)
1455 bclrb #E1,E_BYTE(%a6)
1456 fmovel #0,%FPSR |clear any cc bits from res_func
1458 | Return ETEMP to extended format from internal extended format so
1459 | that gen_except will have a correctly signed value for ovfl/unfl
1462 bfclr ETEMP_SGN(%a6){#0:#8}
1464 bsetb #sign_bit,ETEMP_EX(%a6)
1468 | This exit is for move-out to int register. The aunfl bit is
1469 | not set in any case for this move.
1473 bclrb #E1,E_BYTE(%a6)
1474 fmovel #0,%FPSR |clear any cc bits from res_func
1476 | Return ETEMP to extended format from internal extended format so
1477 | that gen_except will have a correctly signed value for ovfl/unfl
1480 bfclr ETEMP_SGN(%a6){#0:#8}
1482 bsetb #sign_bit,ETEMP_EX(%a6)
1486 | li is used to handle a long integer source specifier
1490 moveql #4,%d0 |set byte count
1492 btstb #7,STAG(%a6) |check for extended denorm
1493 bne int_dnrm |if so, branch
1495 fmovemx ETEMP(%a6),%fp0-%fp0
1496 fcmpd #0x41dfffffffc00000,%fp0
1497 | 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
1499 fcmpd #0xc1e0000000000000,%fp0
1500 | c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
1503 | at this point, the answer is between the largest pos and neg values
1505 movel USER_FPCR(%a6),%d1 |use user's rounding mode
1508 fmovel %fp0,L_SCR1(%a6) |let the 040 perform conversion
1510 orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set
1515 movel #0x7fffffff,L_SCR1(%a6) |answer is largest positive int
1516 fbeq int_wrt |exact answer
1517 fcmpd #0x41dfffffffe00000,%fp0
1518 | 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
1519 fbge int_operr |set operr
1520 bra int_inx |set inexact
1523 movel #0x80000000,L_SCR1(%a6)
1524 fbeq int_wrt |exact answer
1525 fcmpd #0xc1e0000000100000,%fp0
1526 | c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
1527 fblt int_operr |set operr
1528 bra int_inx |set inexact
1531 | wi is used to handle a word integer source specifier
1535 moveql #2,%d0 |set byte count
1537 btstb #7,STAG(%a6) |check for extended denorm
1538 bne int_dnrm |branch if so
1540 fmovemx ETEMP(%a6),%fp0-%fp0
1541 fcmps #0x46fffe00,%fp0
1542 | 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
1544 fcmps #0xc7000000,%fp0
1545 | c7000000 in sgl prec = c00e00008000000000000000 in ext prec
1549 | at this point, the answer is between the largest pos and neg values
1551 movel USER_FPCR(%a6),%d1 |use user's rounding mode
1554 fmovew %fp0,L_SCR1(%a6) |let the 040 perform conversion
1556 orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set
1560 movew #0x7fff,L_SCR1(%a6) |answer is largest positive int
1561 fbeq int_wrt |exact answer
1562 fcmps #0x46ffff00,%fp0
1563 | 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
1564 fbge int_operr |set operr
1565 bra int_inx |set inexact
1568 movew #0x8000,L_SCR1(%a6)
1569 fbeq int_wrt |exact answer
1570 fcmps #0xc7000080,%fp0
1571 | c7000080 in sgl prec = c00e00008000800000000000 in ext prec
1572 fblt int_operr |set operr
1573 bra int_inx |set inexact
1576 | bi is used to handle a byte integer source specifier
1580 moveql #1,%d0 |set byte count
1582 btstb #7,STAG(%a6) |check for extended denorm
1583 bne int_dnrm |branch if so
1585 fmovemx ETEMP(%a6),%fp0-%fp0
1586 fcmps #0x42fe0000,%fp0
1587 | 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
1589 fcmps #0xc3000000,%fp0
1590 | c3000000 in sgl prec = c00600008000000000000000 in ext prec
1594 | at this point, the answer is between the largest pos and neg values
1596 movel USER_FPCR(%a6),%d1 |use user's rounding mode
1599 fmoveb %fp0,L_SCR1(%a6) |let the 040 perform conversion
1601 orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set
1605 moveb #0x7f,L_SCR1(%a6) |answer is largest positive int
1606 fbeq int_wrt |exact answer
1607 fcmps #0x42ff0000,%fp0
1608 | 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
1609 fbge int_operr |set operr
1610 bra int_inx |set inexact
1613 moveb #0x80,L_SCR1(%a6)
1614 fbeq int_wrt |exact answer
1615 fcmps #0xc3008000,%fp0
1616 | c3008000 in sgl prec = c00600008080000000000000 in ext prec
1617 fblt int_operr |set operr
1618 bra int_inx |set inexact
1621 | Common integer routines
1623 | int_drnrm---account for possible nonzero result for round up with positive
1624 | operand and round down for negative answer. In the first case (result = 1)
1625 | byte-width (store in d0) of result must be honored. In the second case,
1626 | -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).
1629 movel #0,L_SCR1(%a6) | initialize result to 0
1630 bfextu FPCR_MODE(%a6){#2:#2},%d1 | d1 is the rounding mode
1632 bmis int_inx | if RN or RZ, done
1633 bnes int_rp | if RP, continue below
1634 tstw ETEMP(%a6) | RM: store -1 in L_SCR1 if src is negative
1635 bpls int_inx | otherwise result is 0
1636 movel #-1,L_SCR1(%a6)
1639 tstw ETEMP(%a6) | RP: store +1 of proper width in L_SCR1 if
1640 | ; source is greater than 0
1641 bmis int_inx | otherwise, result is 0
1642 lea L_SCR1(%a6),%a1 | a1 is address of L_SCR1
1643 addal %d0,%a1 | offset by destination width -1
1645 bsetb #0,(%a1) | set low bit at a1 address
1647 oril #inx2a_mask,USER_FPSR(%a6)
1650 fmovemx %fp0-%fp0,FPTEMP(%a6) |FPTEMP must contain the extended
1651 | ;precision source that needs to be
1652 | ;converted to integer this is required
1653 | ;if the operr exception is enabled.
1654 | ;set operr/aiop (no inex2 on int ovfl)
1656 oril #opaop_mask,USER_FPSR(%a6)
1657 | ;fall through to perform int_wrt
1659 movel EXC_EA(%a6),%a1 |load destination address
1660 tstl %a1 |check to see if it is a dest register
1661 beqs wrt_dn |write data register
1662 lea L_SCR1(%a6),%a0 |point to supervisor source address
1667 movel %d0,-(%sp) |d0 currently contains the size to write
1668 bsrl get_fline |get_fline returns Dn in d0
1669 andiw #0x7,%d0 |isolate register
1670 movel (%sp)+,%d1 |get size
1671 cmpil #4,%d1 |most frequent case
1675 orl #8,%d0 |add 'word' size to register#
1678 orl #0x10,%d0 |add 'long' size to register#
1680 movel %d0,%d1 |reg_dest expects size:reg in d1
1681 bsrl reg_dest |load proper data register
1685 bclrb #sign_bit,LOCAL_EX(%a0)
1687 btstb #7,STAG(%a6) |check for extended denorm
1690 bras do_fp |do normal case
1693 bclrb #sign_bit,LOCAL_EX(%a0)
1695 btstb #7,STAG(%a6) |check for extended denorm
1696 bne sp_catas |branch if so
1697 movew LOCAL_EX(%a0),%d0
1703 movel #1,%d0 |set destination format to single
1704 bras do_fp |do normal case
1707 bclrb #sign_bit,LOCAL_EX(%a0)
1710 btstb #7,STAG(%a6) |check for extended denorm
1711 bne dp_catas |branch if so
1713 movew LOCAL_EX(%a0),%d0
1721 movel #2,%d0 |set destination format to double
1722 | ;fall through to do_fp
1725 bfextu FPCR_MODE(%a6){#2:#2},%d1 |rnd mode in d1
1726 swap %d0 |rnd prec in upper word
1727 addl %d0,%d1 |d1 has PREC/MODE info
1729 clrl %d0 |clear g,r,s
1734 movel EXC_EA(%a6),%a0
1736 bfextu CMDREG1B(%a6){#3:#3},%d1 |extract destination format
1737 | ;at this point only the dest
1738 | ;formats sgl, dbl, ext are
1741 bgts ddbl |double=5, extended=2, single=1
1743 | ;fall through to dext
1755 | Handle possible denorm or catastrophic underflow cases here
1758 bsr set_xop |initialize WBTEMP
1759 bsetb #wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15
1762 movel EXC_EA(%a6),%a0 |a0 has the destination pointer
1763 bsrl dest_ext |store to memory
1764 bsetb #unfl_bit,FPSR_EXCEPT(%a6)
1768 bsetb #etemp15_bit,STAG(%a6)
1771 blts sp_catas |catastrophic underflow case
1773 movel #1,%d0 |load in round precision
1774 movel #sgl_thresh,%d1 |load in single denorm threshold
1775 bsrl dpspdnrm |expects d1 to have the proper
1777 bsrl dest_sgl |stores value to destination
1778 bsetb #unfl_bit,FPSR_EXCEPT(%a6)
1782 bsetb #etemp15_bit,STAG(%a6)
1785 blts dp_catas |catastrophic underflow case
1787 movel #dbl_thresh,%d1 |load in double precision threshold
1789 bsrl dpspdnrm |expects d1 to have proper
1791 | ;expects d0 to have round precision
1792 bsrl dest_dbl |store value to destination
1793 bsetb #unfl_bit,FPSR_EXCEPT(%a6)
1797 | Handle catastrophic underflow cases here
1800 | Temp fix for z bit set in unf_sub
1801 movel USER_FPSR(%a6),-(%a7)
1803 movel #1,%d0 |set round precision to sgl
1805 bsrl unf_sub |a0 points to result
1807 movel (%a7)+,USER_FPSR(%a6)
1810 subw %d0,LOCAL_EX(%a0) |account for difference between
1813 movel %a0,%a1 |a1 has the operand input
1814 movel EXC_EA(%a6),%a0 |a0 has the destination pointer
1816 bsrl dest_sgl |store the result
1817 oril #unfinx_mask,USER_FPSR(%a6)
1821 | Temp fix for z bit set in unf_sub
1822 movel USER_FPSR(%a6),-(%a7)
1824 movel #2,%d0 |set round precision to dbl
1825 bsrl unf_sub |a0 points to result
1827 movel (%a7)+,USER_FPSR(%a6)
1830 subw %d0,LOCAL_EX(%a0) |account for difference between
1833 movel %a0,%a1 |a1 has the operand input
1834 movel EXC_EA(%a6),%a0 |a0 has the destination pointer
1836 bsrl dest_dbl |store the result
1837 oril #unfinx_mask,USER_FPSR(%a6)
1841 | Handle catastrophic overflow cases here
1844 | Temp fix for z bit set in unf_sub
1845 movel USER_FPSR(%a6),-(%a7)
1848 leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result
1849 movel ETEMP_EX(%a6),(%a0)
1850 movel ETEMP_HI(%a6),4(%a0)
1851 movel ETEMP_LO(%a6),8(%a0)
1854 movel (%a7)+,USER_FPSR(%a6)
1857 movel EXC_EA(%a6),%a0
1859 orl #ovfinx_mask,USER_FPSR(%a6)
1863 | Temp fix for z bit set in ovf_res
1864 movel USER_FPSR(%a6),-(%a7)
1867 leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result
1868 movel ETEMP_EX(%a6),(%a0)
1869 movel ETEMP_HI(%a6),4(%a0)
1870 movel ETEMP_LO(%a6),8(%a0)
1873 movel (%a7)+,USER_FPSR(%a6)
1876 movel EXC_EA(%a6),%a0
1878 orl #ovfinx_mask,USER_FPSR(%a6)
1884 | This subroutine takes an extended normalized number and denormalizes
1885 | it to the given round precision. This subroutine also decrements
1886 | the input operand's exponent by 1 to account for the fact that
1887 | dest_sgl or dest_dbl expects a normalized number's bias.
1889 | Input: a0 points to a normalized number in internal extended format
1890 | d0 is the round precision (=1 for sgl; =2 for dbl)
1891 | d1 is the single precision or double precision
1894 | Output: (In the format for dest_sgl or dest_dbl)
1895 | a0 points to the destination
1896 | a1 points to the operand
1898 | Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
1901 movel %d0,-(%a7) |save round precision
1902 clrl %d0 |clear initial g,r,s
1903 bsrl dnrm_lp |careful with d0, it's needed by round
1905 bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode
1907 movew 2(%a7),%d1 |set rounding precision
1908 swap %d1 |at this point d1 has PREC/MODE info
1909 bsrl round |round result, sets the inex bit in
1910 | ;USER_FPSR if needed
1913 subw %d0,LOCAL_EX(%a0) |account for difference in denorm
1916 movel %a0,%a1 |a1 has the operand input
1917 movel EXC_EA(%a6),%a0 |a0 has the destination pointer
1918 addw #4,%a7 |pop stack
1921 | SET_XOP initialized WBTEMP with the value pointed to by a0
1922 | input: a0 points to input operand in the internal extended format
1925 movel LOCAL_EX(%a0),WBTEMP_EX(%a6)
1926 movel LOCAL_HI(%a0),WBTEMP_HI(%a6)
1927 movel LOCAL_LO(%a0),WBTEMP_LO(%a6)
1928 bfclr WBTEMP_SGN(%a6){#0:#8}
1930 bsetb #sign_bit,WBTEMP_EX(%a6)
1932 bfclr STAG(%a6){#5:#4} |clear wbtm66,wbtm1,wbtm0,sbit
1954 leal p_movet,%a0 |load jmp table address
1955 movew STAG(%a6),%d0 |get source tag
1956 bfextu %d0{#16:#3},%d0 |isolate source bits
1957 movel (%a0,%d0.w*4),%a0 |load a0 with routine label for tag
1958 jmp (%a0) |go to the routine
1961 movel #0x0c,%d0 |get byte count
1962 movel EXC_EA(%a6),%a1 |get the destination address
1963 bsr mem_write |write the user's destination
1964 moveb #0,CU_SAVEPC(%a6) |set the cu save pc to all 0's
1967 | Also note that the dtag must be set to norm here - this is because
1968 | the 040 uses the dtag to execute the correct microcode.
1970 bfclr DTAG(%a6){#0:#3} |set dtag to norm
1974 | Notes on handling of special case (zero, inf, and nan) inputs:
1975 | 1. Operr is not signalled if the k-factor is greater than 18.
1976 | 2. Per the manual, status bits are not set.
1980 movew CMDREG1B(%a6),%d0
1981 btstl #kfact_bit,%d0 |test for dynamic k-factor
1982 beqs statick |if clear, k-factor is static
1984 bfextu %d0{#25:#3},%d0 |isolate register for dynamic k-factor
1986 movel %a0@(%d0:l:4),%a0
1989 andiw #0x007f,%d0 |get k-factor
1990 bfexts %d0{#25:#7},%d0 |sign extend d0 for bindec
1991 leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
1992 bsrl bindec |perform the convert; data at a6
1993 leal FP_SCR1(%a6),%a0 |load a0 with result address
1996 leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
1997 clrw 2(%a0) |clear lower word of exp
1998 clrl 4(%a0) |load second lword of ZERO
1999 clrl 8(%a0) |load third lword of ZERO
2000 bra p_write |go write results
2002 fmovel #0,%FPSR |clear aiop
2003 leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
2004 clrw 2(%a0) |clear lower word of exp
2005 bra p_write |go write the result
2007 leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
2008 clrw 2(%a0) |clear lower word of exp
2009 bra p_write |go write the result
2012 | Routines to read the dynamic k-factor from Dn.
2015 movel USER_D0(%a6),%d0
2018 movel USER_D1(%a6),%d0