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 | 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.
23 RES_FUNC: |idnt 2,1 | Motorola 040 Floating Point Software Package
29 sp_bnds: .short 0x3f81,0x407e
31 dp_bnds: .short 0x3c01,0x43fe
60 btstb #7,DTAG(%a6) |if dop = norm=000, zero=001,
62 beqs monadic |then branch
64 | HANDLE DESTINATION DENORM HERE
66 | ;write the tag & fpte15 to the fstack
69 bclrb #sign_bit,LOCAL_EX(%a0)
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
76 bsetb #sign_bit,LOCAL_EX(%a0)
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)
83 btstb #direction_bit,CMDREG1B(%a6) |check direction
84 bne opclass3 |it is a mv out
86 | At this point, only opclass 0 and 2 possible
88 btstb #7,STAG(%a6) |if sop = norm=000, zero=001,
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
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)
100 movew CMDREG1B(%a6),%d0 |get command register
101 andil #0x7f,%d0 |strip to only command word
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)
109 bne normal |weed out fsqrt instructions
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.
116 st CU_ONLY(%a6) |set cu-only inst flag
117 movew CMDREG1B(%a6),%d0
118 andib #0x3b,%d0 |isolate bits to select inst
120 beql cu_nmove |if zero, it is an fmove
122 beql cu_nabs |if $18, it is fabs
124 beql cu_nneg |if $1a, it is fneg
126 | Inst is ftst. Check the source operand and set the cc's accordingly.
127 | No write is done, so simply rts.
130 movew LOCAL_EX(%a0),%d0
134 orl #neg_mask,USER_FPSR(%a6) |set N
136 cmpiw #0x7fff,%d0 |test for inf/nan
142 orl #inf_mask,USER_FPSR(%a6)
145 orl #nan_mask,USER_FPSR(%a6)
146 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
155 orl #z_mask,USER_FPSR(%a6)
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.
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
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.
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
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.
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
190 btstb #6,CMDREG1B+1(%a6) |check for rs
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.
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
204 | The move is fdmove or round precision is double.
207 movel #2,%d0 |set up the size for denorm
208 movew LOCAL_EX(%a0),%d1 |compare exponent to double threshold
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
218 bfclr LOCAL_SGN(%a0){#0:#8}
220 bsetb #sign_bit,LOCAL_EX(%a0)
222 movew LOCAL_EX(%a0),%d1 |check for overflow
225 bge cu_novfl |take care of overflow case
228 | The move is fsmove or round precision is single.
232 movew LOCAL_EX(%a0),%d1
236 bfextu FPCR_MODE(%a6){#2:#2},%d1
239 bclrb #sign_bit,LOCAL_EX(%a0)
242 bfclr LOCAL_SGN(%a0){#0:#8}
244 bsetb #sign_bit,LOCAL_EX(%a0)
246 movew LOCAL_EX(%a0),%d1
251 | The operand is above precision boundaries. Use t_ovfl to
252 | generate the correct value.
258 | The operand is below precision boundaries. Use denorm to
259 | generate the correct value.
262 bclrb #sign_bit,LOCAL_EX(%a0)
265 bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
267 bsetb #sign_bit,LOCAL_EX(%a0)
269 bfextu FPCR_MODE(%a6){#2:#2},%d1
270 btstb #2,CMDREG1B+1(%a6) |check for rd
272 btstb #6,CMDREG1B+1(%a6) |check for rs
275 moveb FPCR_MODE(%a6),%d1
285 bclrb #sign_bit,LOCAL_EX(%a0)
288 bfclr LOCAL_SGN(%a0){#0:#8}
290 bsetb #sign_bit,LOCAL_EX(%a0)
292 btstb #inex2_bit,FPSR_EXCEPT(%a6)
294 orl #aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL
296 tstl LOCAL_HI(%a0) |test for zero
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.
304 movel USER_FPCR(%a6),%d0
305 andil #0x30,%d0 |isolate rmode
310 tstw LOCAL_EX(%a0) |if positive, set lsb
312 btstb #7,FPCR_MODE(%a6) |check for double
316 tstw LOCAL_EX(%a0) |if positive, set lsb
318 btstb #7,FPCR_MODE(%a6) |check for double
321 orl #0x800,LOCAL_LO(%a0) |inc for double
324 orl #0x100,LOCAL_HI(%a0) |inc for single
327 orl #z_mask,USER_FPSR(%a6)
330 cmpib #0x40,%d0 |check if input was tagged zero
333 orl #unfl_mask,USER_FPSR(%a6) |set unfl
335 movel (%a0),ETEMP(%a6)
336 movel 4(%a0),ETEMP_HI(%a6)
337 movel 8(%a0),ETEMP_LO(%a6)
339 | Write the result to memory, setting the fpsr cc bits. NaN and Inf
343 tstw LOCAL_EX(%a0) |test for zero
345 cmpw #0x8000,LOCAL_EX(%a0) |test for zero
348 orl #z_mask,USER_FPSR(%a6) |set Z bit
352 orl #neg_mask,USER_FPSR(%a6)
356 | HANDLE SOURCE DENORM HERE
358 | ;clear denorm stag to norm
359 | ;write the new tag & ete15 to the fstack
362 | At this point, check for the cases in which normalizing the
363 | denorm produces incorrect results.
365 tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would
366 bnes nrm_src |require normalization of denorm
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)
374 movew CMDREG1B(%a6),%d0 |get command register
375 andil #0x7f,%d0 |strip to only command word
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)
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
388 bclrb #sign_bit,LOCAL_EX(%a0)
390 bsr nrm_set |normalize number (exponent will go
392 bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign
394 bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
396 bsetb #sign_bit,LOCAL_EX(%a0)
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)
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
406 moveb #0xfe,CU_SAVEPC(%a6)
407 bclrb #E1,E_BYTE(%a6)
411 st RES_FLG(%a6) |indicate that a restore is needed
415 | cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
416 | ftst) completely in software without an frestore to the 040.
420 movew CMDREG1B(%a6),%d0
421 andib #0x3b,%d0 |isolate bits to select inst
423 beql cu_dmove |if zero, it is an fmove
425 beql cu_dabs |if $18, it is fabs
427 beql cu_dneg |if $1a, it is fneg
429 | Inst is ftst. Check the source operand and set the cc's accordingly.
430 | No write is done, so simply rts.
433 movew LOCAL_EX(%a0),%d0
437 orl #neg_mask,USER_FPSR(%a6) |set N
439 cmpiw #0x7fff,%d0 |test for inf/nan
445 orl #inf_mask,USER_FPSR(%a6)
448 orl #nan_mask,USER_FPSR(%a6)
449 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
457 orl #z_mask,USER_FPSR(%a6)
461 | Inst is fabs. Execute the absolute value function on the input.
462 | Branch to the fmove code.
465 bclrb #7,LOCAL_EX(%a0) |do abs
466 bras cu_dmove |fmove code will finish
468 | Inst is fneg. Execute the negate value function on the input.
469 | Fall though to the fmove code.
472 bchgb #7,LOCAL_EX(%a0) |do neg
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.
482 btstb #2,CMDREG1B+1(%a6) |check for rd
484 btstb #6,CMDREG1B+1(%a6) |check for rs
487 | The move or operation is not with forced precision. Use the
488 | FPCR_MODE byte to get rounding.
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
497 | The move is fdmove or round precision is double. Result is zero.
498 | Check rmode for rp or rm and set lsb accordingly.
501 bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
502 tstw LOCAL_EX(%a0) |check sign
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
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
512 | The move is fsmove or round precision is single. Result is zero.
513 | Check for rp or rm and set lsb accordingly.
516 bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
517 tstw LOCAL_EX(%a0) |check sign
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
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
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.
531 orl #unfl_mask,USER_FPSR(%a6)
534 orl #neg_mask,USER_FPSR(%a6)
537 | These routines write +/- zero in double format. The routines
538 | cu_dpdr and cu_dndr set the double lsb.
541 movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero
544 orl #z_mask,USER_FPSR(%a6)
545 orl #unfinx_mask,USER_FPSR(%a6)
548 movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero
550 movel #0x800,LOCAL_LO(%a0) |with lsb set
551 orl #unfinx_mask,USER_FPSR(%a6)
554 movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero
557 orl #z_mask,USER_FPSR(%a6)
558 orl #neg_mask,USER_FPSR(%a6)
559 orl #unfinx_mask,USER_FPSR(%a6)
562 movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero
564 movel #0x800,LOCAL_LO(%a0) |with lsb set
565 orl #neg_mask,USER_FPSR(%a6)
566 orl #unfinx_mask,USER_FPSR(%a6)
569 | These routines write +/- zero in single format. The routines
570 | cu_dpdr and cu_dndr set the single lsb.
573 movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero
576 orl #z_mask,USER_FPSR(%a6)
577 orl #unfinx_mask,USER_FPSR(%a6)
580 movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero
581 movel #0x100,LOCAL_HI(%a0) |with lsb set
583 orl #unfinx_mask,USER_FPSR(%a6)
586 movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero
589 orl #z_mask,USER_FPSR(%a6)
590 orl #neg_mask,USER_FPSR(%a6)
591 orl #unfinx_mask,USER_FPSR(%a6)
594 movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero
595 movel #0x100,LOCAL_HI(%a0) |with lsb set
597 orl #neg_mask,USER_FPSR(%a6)
598 orl #unfinx_mask,USER_FPSR(%a6)
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.
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
615 | The wrap-around condition occurs for add, sub, div, and cmp
618 | abs(dest_exp - src_exp) >= $8000
622 | (dest_exp + src_exp) < $0
624 | we must process the operation here if this case is true.
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.
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)
637 | call round with user's precision and mode
638 | move result to fpn and wbtemp
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)
647 | call round with user's precision and mode
648 | move result to fpn and wbtemp
651 | if(both operands are denorm)
655 | else(dest is denorm)
661 | else(dest is denorm)
665 | if(both operands are denorm)
667 | if((dest_exp + src_exp) < 0)
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
695 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
696 beq fix_stk |restore to fpu
698 | One of the ops is denormalized. Test for wrap condition
699 | and force the result.
701 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
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
710 blt fix_stk |if less, not wrap case
712 movew ETEMP_EX(%a6),%d0 |find the sign of the result
713 movew FPTEMP_EX(%a6),%d1
721 moveb STAG(%a6),%d0 |check source tag for inf or nan
724 moveb DTAG(%a6),%d0 |check destination tag for inf or nan
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?
734 rts |then ; it is either a zero of norm,
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
749 blt fix_stk |if less, not wrap case
751 movew ETEMP_EX(%a6),%d0 |find the sign of the result
752 movew FPTEMP_EX(%a6),%d1
758 | This code handles the case of the instruction resulting in
759 | an overflow condition.
762 bclrb #E1,E_BYTE(%a6)
763 orl #ovfl_inx_mask,USER_FPSR(%a6)
765 leal WBTEMP(%a6),%a0 |point a0 to memory location
766 movew CMDREG1B(%a6),%d0
767 btstl #6,%d0 |test for forced precision
769 btstl #2,%d0 |check for double
771 movel #0x1,%d0 |inst is forced single
774 movel #0x2,%d0 |inst is forced double
777 bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
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
784 | or.l #inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
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}
793 bsetb #sign_bit,WBTEMP_EX(%a6)
799 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
800 beq fix_stk |restore to fpu
802 | One of the ops is denormalized. Test for wrap condition
803 | and complete the instruction.
805 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
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
814 blt fix_stk |if less, not wrap case
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
823 blt fix_stk |if less, not wrap case
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
835 movew ETEMP_EX(%a6),%d0
836 movew FPTEMP_EX(%a6),%d1
841 | The signs are unlike.
843 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
845 movew FPTEMP_EX(%a6),%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
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
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
861 lsrl #6,%d1 |put precision in upper word
863 orl %d0,%d1 |set up for round call
864 clrl %d0 |force sticky to zero
865 bclrb #sign_bit,WBTEMP_EX(%a6)
867 bsrl round |round result to users rmode & prec
868 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
870 bsetb #sign_bit,WBTEMP_EX(%a6)
873 movew ETEMP_EX(%a6),%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
879 fmovel %d0,%fpcr |set up users rmode and X
880 fmovex ETEMP(%a6),%fp0
881 faddx FPTEMP(%a6),%fp0
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
889 lsrl #6,%d1 |put precision in upper word
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
898 bsetb #sign_bit,WBTEMP_EX(%a6)
904 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
908 movel USER_FPCR(%a6),%d0
910 lsrl #4,%d0 |put rmode in lower 2 bits
911 movel USER_FPCR(%a6),%d1
913 lsrl #6,%d1 |put precision in upper word
915 orl %d0,%d1 |set up for round call
916 movel #0x20000000,%d0 |set sticky for round
917 bclrb #sign_bit,ETEMP_EX(%a6)
919 bsrl round |round result to users rmode & prec
920 bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
922 bsetb #sign_bit,ETEMP_EX(%a6)
925 movel ETEMP(%a6),(%a0) |write result to wbtemp
926 movel ETEMP_HI(%a6),4(%a0)
927 movel ETEMP_LO(%a6),8(%a0)
930 orl #neg_mask,USER_FPSR(%a6)
934 movel USER_FPCR(%a6),%d0
936 lsrl #4,%d0 |put rmode in lower 2 bits
937 movel USER_FPCR(%a6),%d1
939 lsrl #6,%d1 |put precision in upper word
941 orl %d0,%d1 |set up for round call
942 movel #0x20000000,%d0 |set sticky for round
943 bclrb #sign_bit,FPTEMP_EX(%a6)
945 bsrl round |round result to users rmode & prec
946 bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
948 bsetb #sign_bit,FPTEMP_EX(%a6)
951 movel FPTEMP(%a6),(%a0) |write result to wbtemp
952 movel FPTEMP_HI(%a6),4(%a0)
953 movel FPTEMP_LO(%a6),8(%a0)
956 orl #neg_mask,USER_FPSR(%a6)
958 movew WBTEMP_EX(%a6),%d0
963 | The result has overflowed to $7fff exponent. Set I, ovfl,
964 | and aovfl, and clr the mantissa (incorrectly set by the
967 orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
974 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
975 beq fix_stk |restore to fpu
977 | One of the ops is denormalized. Test for wrap condition
978 | and complete the instruction.
980 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
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
989 blt fix_stk |if less, not wrap case
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
998 blt fix_stk |if less, not wrap case
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
1010 movew ETEMP_EX(%a6),%d0
1011 movew FPTEMP_EX(%a6),%d1
1016 | The signs are alike.
1018 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
1020 movew FPTEMP_EX(%a6),%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
1026 fmovel %d0,%fpcr |set up users rmode and X
1027 fmovex FPTEMP(%a6),%fp0
1028 fsubx ETEMP(%a6),%fp0
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
1036 lsrl #6,%d1 |put precision in upper word
1038 orl %d0,%d1 |set up for round call
1039 clrl %d0 |force sticky to zero
1040 bclrb #sign_bit,WBTEMP_EX(%a6)
1042 bsrl round |round result to users rmode & prec
1043 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1045 bsetb #sign_bit,WBTEMP_EX(%a6)
1048 movew ETEMP_EX(%a6),%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
1054 fmovel %d0,%fpcr |set up users rmode and X
1055 fmovex FPTEMP(%a6),%fp0
1056 fsubx ETEMP(%a6),%fp0
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
1064 lsrl #6,%d1 |put precision in upper word
1066 orl %d0,%d1 |set up for round call
1067 clrl %d0 |force sticky to zero
1068 bclrb #sign_bit,WBTEMP_EX(%a6)
1070 bsrl round |round result to users rmode & prec
1071 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1073 bsetb #sign_bit,WBTEMP_EX(%a6)
1079 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
1083 movel USER_FPCR(%a6),%d0
1085 lsrl #4,%d0 |put rmode in lower 2 bits
1086 movel USER_FPCR(%a6),%d1
1088 lsrl #6,%d1 |put precision in upper word
1090 orl %d0,%d1 |set up for round call
1091 movel #0x20000000,%d0 |set sticky for round
1093 | Since the dest is the denorm, the sign is the opposite of the
1096 eoriw #0x8000,ETEMP_EX(%a6) |flip sign on result
1099 orl #neg_mask,USER_FPSR(%a6)
1101 bclrb #sign_bit,ETEMP_EX(%a6)
1103 bsrl round |round result to users rmode & prec
1104 bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1106 bsetb #sign_bit,ETEMP_EX(%a6)
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)
1114 leal FPTEMP(%a6),%a0
1115 movel USER_FPCR(%a6),%d0
1117 lsrl #4,%d0 |put rmode in lower 2 bits
1118 movel USER_FPCR(%a6),%d1
1120 lsrl #6,%d1 |put precision in upper word
1122 orl %d0,%d1 |set up for round call
1123 movel #0x20000000,%d0 |set sticky for round
1124 bclrb #sign_bit,FPTEMP_EX(%a6)
1126 bsrl round |round result to users rmode & prec
1127 bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
1129 bsetb #sign_bit,FPTEMP_EX(%a6)
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)
1137 orl #neg_mask,USER_FPSR(%a6)
1139 movew WBTEMP_EX(%a6),%d0
1144 | The result has overflowed to $7fff exponent. Set I, ovfl,
1145 | and aovfl, and clr the mantissa (incorrectly set by the
1148 orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
1155 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
1156 beq fix_stk |restore to fpu
1158 | One of the ops is denormalized. Test for wrap condition
1159 | and complete the instruction.
1161 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
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
1170 blt fix_stk |if less, not wrap case
1171 tstw ETEMP_EX(%a6) |set N to ~sign_of(src)
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
1181 blt fix_stk |if less, not wrap case
1182 tstw FPTEMP_EX(%a6) |set N to sign_of(dest)
1186 orl #neg_mask,USER_FPSR(%a6)
1193 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
1194 beq force_unf |force an underflow (really!)
1196 | One of the ops is denormalized. Test for wrap condition
1197 | and complete the instruction.
1199 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
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
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
1218 | This code handles the case of the instruction resulting in
1219 | an underflow condition.
1222 bclrb #E1,E_BYTE(%a6)
1223 orl #unfinx_mask,USER_FPSR(%a6)
1225 clrb WBTEMP_SGN(%a6)
1226 movew ETEMP_EX(%a6),%d0 |find the sign of the result
1227 movew FPTEMP_EX(%a6),%d1
1233 lea WBTEMP(%a6),%a0 |point a0 to memory location
1234 movew CMDREG1B(%a6),%d0
1235 btstl #6,%d0 |test for forced precision
1237 btstl #2,%d0 |check for double
1239 movel #0x1,%d0 |inst is forced single
1242 movel #0x2,%d0 |inst is forced double
1245 bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
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
1252 bsetb #sign_bit,WBTEMP_EX(%a6)
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.
1262 movew CMDREG1B(%a6),%d0
1263 btstl #6,%d0 |test for forced precision
1265 btstl #2,%d0 |check for double
1267 movel #0x1,%d0 |inst is forced single
1270 movel #0x2,%d0 |inst is forced double
1273 bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
1275 beqs frcfpn |if extended, write what you got
1277 bclrb #sign_bit,WBTEMP_EX(%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
1284 bsetb #sign_bit,WBTEMP_EX(%a6)
1286 orl #ovfinx_mask,USER_FPSR(%a6)
1288 | Perform the write.
1291 bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register
1293 bles frc0123 |check if dest is fp0-fp3
1298 fmovemx WBTEMP(%a6),%d0
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)
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)
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)
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)
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
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
1342 tstb ETEMP(%a6) |check for negative
1346 orl #neg_bit,USER_FPSR(%a6) |snan is negative; set N
1350 bclrb #E1,E_BYTE(%a6)
1351 moveb STAG(%a6),%d0 |check if stag is inf
1355 orl #inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I
1356 tstw LOCAL_EX(%a0) |check sign
1358 orl #neg_mask,USER_FPSR(%a6)
1361 cmpib #0x60,%d0 |check if stag is NaN
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
1366 tstw LOCAL_EX(%a0) |check sign
1368 orl #neg_mask,USER_FPSR(%a6)
1371 cmpib #0x20,%d0 |check if zero
1373 orl #z_mask,USER_FPSR(%a6) |if zero, set Z
1374 tstw LOCAL_EX(%a0) |check sign
1376 orl #neg_mask,USER_FPSR(%a6)
1378 bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register
1380 bles fp0123 |check if dest is fp0-fp3
1385 fmovemx ETEMP(%a6),%d0
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)
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)
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)
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)
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
1433 .long mvout_end |should never be taken
1437 .long mvout_end |should never be taken
1439 bfextu CMDREG1B(%a6){#3:#3},%d1 |put source specifier in d1
1441 movel %a0@(%d1:l:4),%a0
1445 | This exit is for move-out to memory. The aunfl bit is
1446 | set if the result is inex and unfl is signalled.
1449 btstb #inex2_bit,FPSR_EXCEPT(%a6)
1451 btstb #unfl_bit,FPSR_EXCEPT(%a6)
1453 bsetb #aunfl_bit,FPSR_AEXCEPT(%a6)
1456 bclrb #E1,E_BYTE(%a6)
1457 fmovel #0,%FPSR |clear any cc bits from res_func
1459 | Return ETEMP to extended format from internal extended format so
1460 | that gen_except will have a correctly signed value for ovfl/unfl
1463 bfclr ETEMP_SGN(%a6){#0:#8}
1465 bsetb #sign_bit,ETEMP_EX(%a6)
1469 | This exit is for move-out to int register. The aunfl bit is
1470 | not set in any case for this move.
1474 bclrb #E1,E_BYTE(%a6)
1475 fmovel #0,%FPSR |clear any cc bits from res_func
1477 | Return ETEMP to extended format from internal extended format so
1478 | that gen_except will have a correctly signed value for ovfl/unfl
1481 bfclr ETEMP_SGN(%a6){#0:#8}
1483 bsetb #sign_bit,ETEMP_EX(%a6)
1487 | li is used to handle a long integer source specifier
1491 moveql #4,%d0 |set byte count
1493 btstb #7,STAG(%a6) |check for extended denorm
1494 bne int_dnrm |if so, branch
1496 fmovemx ETEMP(%a6),%fp0-%fp0
1497 fcmpd #0x41dfffffffc00000,%fp0
1498 | 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
1500 fcmpd #0xc1e0000000000000,%fp0
1501 | c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
1504 | at this point, the answer is between the largest pos and neg values
1506 movel USER_FPCR(%a6),%d1 |use user's rounding mode
1509 fmovel %fp0,L_SCR1(%a6) |let the 040 perform conversion
1511 orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set
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
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
1532 | wi is used to handle a word integer source specifier
1536 moveql #2,%d0 |set byte count
1538 btstb #7,STAG(%a6) |check for extended denorm
1539 bne int_dnrm |branch if so
1541 fmovemx ETEMP(%a6),%fp0-%fp0
1542 fcmps #0x46fffe00,%fp0
1543 | 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
1545 fcmps #0xc7000000,%fp0
1546 | c7000000 in sgl prec = c00e00008000000000000000 in ext prec
1550 | at this point, the answer is between the largest pos and neg values
1552 movel USER_FPCR(%a6),%d1 |use user's rounding mode
1555 fmovew %fp0,L_SCR1(%a6) |let the 040 perform conversion
1557 orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set
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
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
1577 | bi is used to handle a byte integer source specifier
1581 moveql #1,%d0 |set byte count
1583 btstb #7,STAG(%a6) |check for extended denorm
1584 bne int_dnrm |branch if so
1586 fmovemx ETEMP(%a6),%fp0-%fp0
1587 fcmps #0x42fe0000,%fp0
1588 | 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
1590 fcmps #0xc3000000,%fp0
1591 | c3000000 in sgl prec = c00600008000000000000000 in ext prec
1595 | at this point, the answer is between the largest pos and neg values
1597 movel USER_FPCR(%a6),%d1 |use user's rounding mode
1600 fmoveb %fp0,L_SCR1(%a6) |let the 040 perform conversion
1602 orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set
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
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
1622 | Common integer routines
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).
1630 movel #0,L_SCR1(%a6) | initialize result to 0
1631 bfextu FPCR_MODE(%a6){#2:#2},%d1 | d1 is the rounding mode
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)
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
1646 bsetb #0,(%a1) | set low bit at a1 address
1648 oril #inx2a_mask,USER_FPSR(%a6)
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)
1657 oril #opaop_mask,USER_FPSR(%a6)
1658 | ;fall through to perform 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
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
1676 orl #8,%d0 |add 'word' size to register#
1679 orl #0x10,%d0 |add 'long' size to register#
1681 movel %d0,%d1 |reg_dest expects size:reg in d1
1682 bsrl reg_dest |load proper data register
1686 bclrb #sign_bit,LOCAL_EX(%a0)
1688 btstb #7,STAG(%a6) |check for extended denorm
1691 bras do_fp |do normal case
1694 bclrb #sign_bit,LOCAL_EX(%a0)
1696 btstb #7,STAG(%a6) |check for extended denorm
1697 bne sp_catas |branch if so
1698 movew LOCAL_EX(%a0),%d0
1704 movel #1,%d0 |set destination format to single
1705 bras do_fp |do normal case
1708 bclrb #sign_bit,LOCAL_EX(%a0)
1711 btstb #7,STAG(%a6) |check for extended denorm
1712 bne dp_catas |branch if so
1714 movew LOCAL_EX(%a0),%d0
1722 movel #2,%d0 |set destination format to double
1723 | ;fall through to 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
1730 clrl %d0 |clear g,r,s
1735 movel EXC_EA(%a6),%a0
1737 bfextu CMDREG1B(%a6){#3:#3},%d1 |extract destination format
1738 | ;at this point only the dest
1739 | ;formats sgl, dbl, ext are
1742 bgts ddbl |double=5, extended=2, single=1
1744 | ;fall through to dext
1756 | Handle possible denorm or catastrophic underflow cases here
1759 bsr set_xop |initialize WBTEMP
1760 bsetb #wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15
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)
1769 bsetb #etemp15_bit,STAG(%a6)
1772 blts sp_catas |catastrophic underflow case
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
1778 bsrl dest_sgl |stores value to destination
1779 bsetb #unfl_bit,FPSR_EXCEPT(%a6)
1783 bsetb #etemp15_bit,STAG(%a6)
1786 blts dp_catas |catastrophic underflow case
1788 movel #dbl_thresh,%d1 |load in double precision threshold
1790 bsrl dpspdnrm |expects d1 to have proper
1792 | ;expects d0 to have round precision
1793 bsrl dest_dbl |store value to destination
1794 bsetb #unfl_bit,FPSR_EXCEPT(%a6)
1798 | Handle catastrophic underflow cases here
1801 | Temp fix for z bit set in unf_sub
1802 movel USER_FPSR(%a6),-(%a7)
1804 movel #1,%d0 |set round precision to sgl
1806 bsrl unf_sub |a0 points to result
1808 movel (%a7)+,USER_FPSR(%a6)
1811 subw %d0,LOCAL_EX(%a0) |account for difference between
1814 movel %a0,%a1 |a1 has the operand input
1815 movel EXC_EA(%a6),%a0 |a0 has the destination pointer
1817 bsrl dest_sgl |store the result
1818 oril #unfinx_mask,USER_FPSR(%a6)
1822 | Temp fix for z bit set in unf_sub
1823 movel USER_FPSR(%a6),-(%a7)
1825 movel #2,%d0 |set round precision to dbl
1826 bsrl unf_sub |a0 points to result
1828 movel (%a7)+,USER_FPSR(%a6)
1831 subw %d0,LOCAL_EX(%a0) |account for difference between
1834 movel %a0,%a1 |a1 has the operand input
1835 movel EXC_EA(%a6),%a0 |a0 has the destination pointer
1837 bsrl dest_dbl |store the result
1838 oril #unfinx_mask,USER_FPSR(%a6)
1842 | Handle catastrophic overflow cases here
1845 | Temp fix for z bit set in unf_sub
1846 movel USER_FPSR(%a6),-(%a7)
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)
1855 movel (%a7)+,USER_FPSR(%a6)
1858 movel EXC_EA(%a6),%a0
1860 orl #ovfinx_mask,USER_FPSR(%a6)
1864 | Temp fix for z bit set in ovf_res
1865 movel USER_FPSR(%a6),-(%a7)
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)
1874 movel (%a7)+,USER_FPSR(%a6)
1877 movel EXC_EA(%a6),%a0
1879 orl #ovfinx_mask,USER_FPSR(%a6)
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.
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
1895 | Output: (In the format for dest_sgl or dest_dbl)
1896 | a0 points to the destination
1897 | a1 points to the operand
1899 | Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
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
1906 bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode
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
1914 subw %d0,LOCAL_EX(%a0) |account for difference in denorm
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
1922 | SET_XOP initialized WBTEMP with the value pointed to by a0
1923 | input: a0 points to input operand in the internal extended format
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}
1931 bsetb #sign_bit,WBTEMP_EX(%a6)
1933 bfclr STAG(%a6){#5:#4} |clear wbtm66,wbtm1,wbtm0,sbit
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
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
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.
1971 bfclr DTAG(%a6){#0:#3} |set dtag to norm
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.
1981 movew CMDREG1B(%a6),%d0
1982 btstl #kfact_bit,%d0 |test for dynamic k-factor
1983 beqs statick |if clear, k-factor is static
1985 bfextu %d0{#25:#3},%d0 |isolate register for dynamic k-factor
1987 movel %a0@(%d0:l:4),%a0
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
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
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
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
2013 | Routines to read the dynamic k-factor from Dn.
2016 movel USER_D0(%a6),%d0
2019 movel USER_D1(%a6),%d0