1 * $NetBSD: res_func.sa,v 1.4 2000/03/13 23:52:32 soren Exp $
3 * MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
4 * M68000 Hi-Performance Microprocessor Division
5 * M68040 Software Package
7 * M68040 Software Package Copyright (c) 1993, 1994 Motorola Inc.
10 * THE SOFTWARE is provided on an "AS IS" basis and without warranty.
11 * To the maximum extent permitted by applicable law,
12 * MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
13 * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
14 * PARTICULAR PURPOSE and any warranty against infringement with
15 * regard to the SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF)
16 * and any accompanying written materials.
18 * To the maximum extent permitted by applicable law,
19 * IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
20 * (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS
21 * PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR
22 * OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE
23 * SOFTWARE. Motorola assumes no responsibility for the maintenance
24 * and support of the SOFTWARE.
26 * You are hereby granted a copyright license to use, modify, and
27 * distribute the SOFTWARE so long as this entire notice is retained
28 * without alteration in any modified and/or redistributed versions,
29 * and that such modified versions are clearly identified as such.
30 * No licenses are granted by implication, estoppel or otherwise
31 * under any patents or trademarks of Motorola, Inc.
34 * res_func.sa 3.9 7/29/91
36 * Normalizes denormalized numbers if necessary and updates the
37 * stack frame. The function is then restored back into the
38 * machine and the 040 completes the operation. This routine
39 * is only used by the unsupported data type/format handler.
40 * (Exception vector 55).
42 * For packed move out (fmove.p fpm,<ea>) the operation is
43 * completed here; data is packed and moved to user memory.
44 * The stack is restored to the 040 only in the case of a
45 * reportable exception in the conversion.
48 RES_FUNC IDNT 2,1 Motorola 040 Floating Point Software Package
54 sp_bnds: dc.w $3f81,$407e
56 dp_bnds: dc.w $3c01,$43fe
85 btst.b #7,DTAG(a6) ;if dop = norm=000, zero=001,
87 beq.b monadic ;then branch
89 * HANDLE DESTINATION DENORM HERE
91 * ;write the tag & fpte15 to the fstack
94 bclr.b #sign_bit,LOCAL_EX(a0)
97 bsr nrm_set ;normalize number (exp will go negative)
98 bclr.b #sign_bit,LOCAL_EX(a0) ;get rid of false sign
99 bfclr LOCAL_SGN(a0){0:8} ;change back to IEEE ext format
101 bset.b #sign_bit,LOCAL_EX(a0)
103 bfclr DTAG(a6){0:4} ;set tag to normalized, FPTE15 = 0
104 bset.b #4,DTAG(a6) ;set FPTE15
105 or.b #$0f,DNRM_FLG(a6)
108 btst.b #direction_bit,CMDREG1B(a6) ;check direction
109 bne.w opclass3 ;it is a mv out
111 * At this point, only oplcass 0 and 2 possible
113 btst.b #7,STAG(a6) ;if sop = norm=000, zero=001,
114 * ;inf=010 or nan=011
115 bne.w mon_dnrm ;else denorm
116 tst.b DY_MO_FLG(a6) ;all cases of dyadic instructions would
117 bne.w normal ;require normalization of denorm
120 * monadic instructions: fabs = $18 fneg = $1a ftst = $3a
121 * fmove = $00 fsmove = $40 fdmove = $44
122 * fsqrt = $05* fssqrt = $41 fdsqrt = $45
123 * (*fsqrt reencoded to $05)
125 move.w CMDREG1B(a6),d0 ;get command register
126 andi.l #$7f,d0 ;strip to only command word
128 * At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
129 * fdsqrt are possible.
130 * For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
131 * For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
134 bne.w normal ;weed out fsqrt instructions
136 * cu_norm handles fmove in instructions with normalized inputs.
137 * The routine round is used to correctly round the input for the
138 * destination precision and mode.
141 st CU_ONLY(a6) ;set cu-only inst flag
142 move.w CMDREG1B(a6),d0
143 andi.b #$3b,d0 ;isolate bits to select inst
145 beq.l cu_nmove ;if zero, it is an fmove
147 beq.l cu_nabs ;if $18, it is fabs
149 beq.l cu_nneg ;if $1a, it is fneg
151 * Inst is ftst. Check the source operand and set the cc's accordingly.
152 * No write is done, so simply rts.
155 move.w LOCAL_EX(a0),d0
159 or.l #neg_mask,USER_FPSR(a6) ;set N
161 cmpi.w #$7fff,d0 ;test for inf/nan
167 or.l #inf_mask,USER_FPSR(a6)
170 or.l #nan_mask,USER_FPSR(a6)
171 move.l ETEMP_EX(a6),FPTEMP_EX(a6) ;set up fptemp sign for
180 or.l #z_mask,USER_FPSR(a6)
184 * Inst is fabs. Execute the absolute value function on the input.
185 * Branch to the fmove code. If the operand is NaN, do nothing.
189 btst.l #5,d0 ;test for NaN or zero
190 bne wr_etemp ;if either, simply write it
191 bclr.b #7,LOCAL_EX(a0) ;do abs
192 bra.b cu_nmove ;fmove code will finish
194 * Inst is fneg. Execute the negate value function on the input.
195 * Fall though to the fmove code. If the operand is NaN, do nothing.
199 btst.l #5,d0 ;test for NaN or zero
200 bne wr_etemp ;if either, simply write it
201 bchg.b #7,LOCAL_EX(a0) ;do neg
203 * Inst is fmove. This code also handles all result writes.
204 * If bit 2 is set, round is forced to double. If it is clear,
205 * and bit 6 is set, round is forced to single. If both are clear,
206 * the round precision is found in the fpcr. If the rounding precision
207 * is double or single, round the result before the write.
211 andi.b #$e0,d0 ;isolate stag bits
212 bne wr_etemp ;if not norm, simply write it
213 btst.b #2,CMDREG1B+1(a6) ;check for rd
215 btst.b #6,CMDREG1B+1(a6) ;check for rs
218 * The move or operation is not with forced precision. Test for
219 * nan or inf as the input; if so, simply write it to FPn. Use the
220 * FPCR_MODE byte to get rounding on norms and zeros.
223 bfextu FPCR_MODE(a6){0:2},d0
224 tst.b d0 ;check for extended
225 beq cu_wrexn ;if so, just write result
226 cmpi.b #1,d0 ;check for single
227 beq cu_nmrs ;fall through to double
229 * The move is fdmove or round precision is double.
232 move.l #2,d0 ;set up the size for denorm
233 move.w LOCAL_EX(a0),d1 ;compare exponent to double threshold
237 bfextu FPCR_MODE(a6){2:2},d1 ;get rmode
238 or.l #$00020000,d1 ;or in rprec (double)
239 clr.l d0 ;clear g,r,s for round
240 bclr.b #sign_bit,LOCAL_EX(a0) ;convert to internal format
243 bfclr LOCAL_SGN(a0){0:8}
245 bset.b #sign_bit,LOCAL_EX(a0)
247 move.w LOCAL_EX(a0),d1 ;check for overflow
250 bge cu_novfl ;take care of overflow case
253 * The move is fsmove or round precision is single.
257 move.w LOCAL_EX(a0),d1
261 bfextu FPCR_MODE(a6){2:2},d1
264 bclr.b #sign_bit,LOCAL_EX(a0)
267 bfclr LOCAL_SGN(a0){0:8}
269 bset.b #sign_bit,LOCAL_EX(a0)
271 move.w LOCAL_EX(a0),d1
276 * The operand is above precision boundaries. Use t_ovfl to
277 * generate the correct value.
283 * The operand is below precision boundaries. Use denorm to
284 * generate the correct value.
287 bclr.b #sign_bit,LOCAL_EX(a0)
290 bfclr LOCAL_SGN(a0){0:8} ;change back to IEEE ext format
292 bset.b #sign_bit,LOCAL_EX(a0)
294 bfextu FPCR_MODE(a6){2:2},d1
295 btst.b #2,CMDREG1B+1(a6) ;check for rd
297 btst.b #6,CMDREG1B+1(a6) ;check for rs
300 move.b FPCR_MODE(a6),d1
310 bclr.b #sign_bit,LOCAL_EX(a0)
313 bfclr LOCAL_SGN(a0){0:8}
315 bset.b #sign_bit,LOCAL_EX(a0)
317 btst.b #inex2_bit,FPSR_EXCEPT(a6)
319 or.l #aunfl_mask,USER_FPSR(a6) ;if the round was inex, set AUNFL
321 tst.l LOCAL_HI(a0) ;test for zero
326 * The mantissa is zero from the denorm loop. Check sign and rmode
327 * to see if rounding should have occurred which would leave the lsb.
329 move.l USER_FPCR(a6),d0
330 andi.l #$30,d0 ;isolate rmode
335 tst.w LOCAL_EX(a0) ;if positive, set lsb
337 btst.b #7,FPCR_MODE(a6) ;check for double
341 tst.w LOCAL_EX(a0) ;if positive, set lsb
343 btst.b #7,FPCR_MODE(a6) ;check for double
346 or.l #$800,LOCAL_LO(a0) ;inc for double
349 or.l #$100,LOCAL_HI(a0) ;inc for single
352 or.l #z_mask,USER_FPSR(a6)
355 cmpi.b #$40,d0 ;check if input was tagged zero
358 or.l #unfl_mask,USER_FPSR(a6) ;set unfl
360 move.l (a0),ETEMP(a6)
361 move.l 4(a0),ETEMP_HI(a6)
362 move.l 8(a0),ETEMP_LO(a6)
364 * Write the result to memory, setting the fpsr cc bits. NaN and Inf
368 tst.w LOCAL_EX(a0) ;test for zero
370 cmp.w #$8000,LOCAL_EX(a0) ;test for zero
373 or.l #z_mask,USER_FPSR(a6) ;set Z bit
377 or.l #neg_mask,USER_FPSR(a6)
381 * HANDLE SOURCE DENORM HERE
383 * ;clear denorm stag to norm
384 * ;write the new tag & ete15 to the fstack
387 * At this point, check for the cases in which normalizing the
388 * denorm produces incorrect results.
390 tst.b DY_MO_FLG(a6) ;all cases of dyadic instructions would
391 bne.b nrm_src ;require normalization of denorm
394 * monadic instructions: fabs = $18 fneg = $1a ftst = $3a
395 * fmove = $00 fsmove = $40 fdmove = $44
396 * fsqrt = $05* fssqrt = $41 fdsqrt = $45
397 * (*fsqrt reencoded to $05)
399 move.w CMDREG1B(a6),d0 ;get command register
400 andi.l #$7f,d0 ;strip to only command word
402 * At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
403 * fdsqrt are possible.
404 * For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
405 * For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
408 bne.b nrm_src ;weed out fsqrt instructions
409 st CU_ONLY(a6) ;set cu-only inst flag
410 bra cu_dnrm ;fmove, fabs, fneg, ftst
411 * ;cases go to cu_dnrm
413 bclr.b #sign_bit,LOCAL_EX(a0)
415 bsr nrm_set ;normalize number (exponent will go
417 bclr.b #sign_bit,LOCAL_EX(a0) ;get rid of false sign
419 bfclr LOCAL_SGN(a0){0:8} ;change back to IEEE ext format
421 bset.b #sign_bit,LOCAL_EX(a0)
423 bfclr STAG(a6){0:4} ;set tag to normalized, FPTE15 = 0
424 bset.b #4,STAG(a6) ;set ETE15
425 or.b #$f0,DNRM_FLG(a6)
427 tst.b DNRM_FLG(a6) ;check if any of the ops were denorms
428 bne ck_wrap ;if so, check if it is a potential
431 move.b #$fe,CU_SAVEPC(a6)
432 bclr.b #E1,E_BYTE(a6)
436 st.b RES_FLG(a6) ;indicate that a restore is needed
440 * cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
441 * ftst) completly in software without an frestore to the 040.
445 move.w CMDREG1B(a6),d0
446 andi.b #$3b,d0 ;isolate bits to select inst
448 beq.l cu_dmove ;if zero, it is an fmove
450 beq.l cu_dabs ;if $18, it is fabs
452 beq.l cu_dneg ;if $1a, it is fneg
454 * Inst is ftst. Check the source operand and set the cc's accordingly.
455 * No write is done, so simply rts.
458 move.w LOCAL_EX(a0),d0
462 or.l #neg_mask,USER_FPSR(a6) ;set N
464 cmpi.w #$7fff,d0 ;test for inf/nan
470 or.l #inf_mask,USER_FPSR(a6)
473 or.l #nan_mask,USER_FPSR(a6)
474 move.l ETEMP_EX(a6),FPTEMP_EX(a6) ;set up fptemp sign for
482 or.l #z_mask,USER_FPSR(a6)
486 * Inst is fabs. Execute the absolute value function on the input.
487 * Branch to the fmove code.
490 bclr.b #7,LOCAL_EX(a0) ;do abs
491 bra.b cu_dmove ;fmove code will finish
493 * Inst is fneg. Execute the negate value function on the input.
494 * Fall though to the fmove code.
497 bchg.b #7,LOCAL_EX(a0) ;do neg
499 * Inst is fmove. This code also handles all result writes.
500 * If bit 2 is set, round is forced to double. If it is clear,
501 * and bit 6 is set, round is forced to single. If both are clear,
502 * the round precision is found in the fpcr. If the rounding precision
503 * is double or single, the result is zero, and the mode is checked
504 * to determine if the lsb of the result should be set.
507 btst.b #2,CMDREG1B+1(a6) ;check for rd
509 btst.b #6,CMDREG1B+1(a6) ;check for rs
512 * The move or operation is not with forced precision. Use the
513 * FPCR_MODE byte to get rounding.
516 bfextu FPCR_MODE(a6){0:2},d0
517 tst.b d0 ;check for extended
518 beq cu_wrexd ;if so, just write result
519 cmpi.b #1,d0 ;check for single
520 beq cu_dmrs ;fall through to double
522 * The move is fdmove or round precision is double. Result is zero.
523 * Check rmode for rp or rm and set lsb accordingly.
526 bfextu FPCR_MODE(a6){2:2},d1 ;get rmode
527 tst.w LOCAL_EX(a0) ;check sign
529 cmpi.b #3,d1 ;check for rp
530 bne cu_dpd ;load double pos zero
531 bra cu_dpdr ;load double pos zero w/lsb
533 cmpi.b #2,d1 ;check for rm
534 bne cu_dnd ;load double neg zero
535 bra cu_dndr ;load double neg zero w/lsb
537 * The move is fsmove or round precision is single. Result is zero.
538 * Check for rp or rm and set lsb accordingly.
541 bfextu FPCR_MODE(a6){2:2},d1 ;get rmode
542 tst.w LOCAL_EX(a0) ;check sign
544 cmpi.b #3,d1 ;check for rp
545 bne cu_spd ;load single pos zero
546 bra cu_spdr ;load single pos zero w/lsb
548 cmpi.b #2,d1 ;check for rm
549 bne cu_snd ;load single neg zero
550 bra cu_sndr ;load single neg zero w/lsb
552 * The precision is extended, so the result in etemp is correct.
553 * Simply set unfl (not inex2 or aunfl) and write the result to
554 * the correct fp register.
556 or.l #unfl_mask,USER_FPSR(a6)
559 or.l #neg_mask,USER_FPSR(a6)
562 * These routines write +/- zero in double format. The routines
563 * cu_dpdr and cu_dndr set the double lsb.
566 move.l #$3c010000,LOCAL_EX(a0) ;force pos double zero
569 or.l #z_mask,USER_FPSR(a6)
570 or.l #unfinx_mask,USER_FPSR(a6)
573 move.l #$3c010000,LOCAL_EX(a0) ;force pos double zero
575 move.l #$800,LOCAL_LO(a0) ;with lsb set
576 or.l #unfinx_mask,USER_FPSR(a6)
579 move.l #$bc010000,LOCAL_EX(a0) ;force pos double zero
582 or.l #z_mask,USER_FPSR(a6)
583 or.l #neg_mask,USER_FPSR(a6)
584 or.l #unfinx_mask,USER_FPSR(a6)
587 move.l #$bc010000,LOCAL_EX(a0) ;force pos double zero
589 move.l #$800,LOCAL_LO(a0) ;with lsb set
590 or.l #neg_mask,USER_FPSR(a6)
591 or.l #unfinx_mask,USER_FPSR(a6)
594 * These routines write +/- zero in single format. The routines
595 * cu_dpdr and cu_dndr set the single lsb.
598 move.l #$3f810000,LOCAL_EX(a0) ;force pos single zero
601 or.l #z_mask,USER_FPSR(a6)
602 or.l #unfinx_mask,USER_FPSR(a6)
605 move.l #$3f810000,LOCAL_EX(a0) ;force pos single zero
606 move.l #$100,LOCAL_HI(a0) ;with lsb set
608 or.l #unfinx_mask,USER_FPSR(a6)
611 move.l #$bf810000,LOCAL_EX(a0) ;force pos single zero
614 or.l #z_mask,USER_FPSR(a6)
615 or.l #neg_mask,USER_FPSR(a6)
616 or.l #unfinx_mask,USER_FPSR(a6)
619 move.l #$bf810000,LOCAL_EX(a0) ;force pos single zero
620 move.l #$100,LOCAL_HI(a0) ;with lsb set
622 or.l #neg_mask,USER_FPSR(a6)
623 or.l #unfinx_mask,USER_FPSR(a6)
627 * This code checks for 16-bit overflow conditions on dyadic
628 * operations which are not restorable into the floating-point
629 * unit and must be completed in software. Basically, this
630 * condition exists with a very large norm and a denorm. One
631 * of the operands must be denormalized to enter this code.
634 * DY_MO_FLG contains 0 for monadic op, $ff for dyadic
635 * DNRM_FLG contains $00 for neither op denormalized
636 * $0f for the destination op denormalized
637 * $f0 for the source op denormalized
638 * $ff for both ops denormalzed
640 * The wrap-around condition occurs for add, sub, div, and cmp
643 * abs(dest_exp - src_exp) >= $8000
647 * (dest_exp + src_exp) < $0
649 * we must process the operation here if this case is true.
651 * The rts following the frcfpn routine is the exit from res_func
652 * for this condition. The restore flag (RES_FLG) is left clear.
653 * No frestore is done unless an exception is to be reported.
656 * if(sign_of(dest) != sign_of(src))
657 * replace exponent of src with $3fff (keep sign)
658 * use fpu to perform dest+new_src (user's rmode and X)
662 * call round with user's precision and mode
663 * move result to fpn and wbtemp
666 * if(sign_of(dest) == sign_of(src))
667 * replace exponent of src with $3fff (keep sign)
668 * use fpu to perform dest+new_src (user's rmode and X)
672 * call round with user's precision and mode
673 * move result to fpn and wbtemp
676 * if(both operands are denorm)
680 * else(dest is denorm)
686 * else(dest is denorm)
690 * if(both operands are denorm)
692 * if((dest_exp + src_exp) < 0)
704 tst.b DY_MO_FLG(a6) ;check for fsqrt
705 beq fix_stk ;if zero, it is fsqrt
706 move.w CMDREG1B(a6),d0
707 andi.w #$3b,d0 ;strip to command bits
720 cmp.b #$ff,DNRM_FLG(a6) ;if both ops denorm,
721 beq fix_stk ;restore to fpu
723 * One of the ops is denormalized. Test for wrap condition
724 * and force the result.
726 cmp.b #$0f,DNRM_FLG(a6) ;check for dest denorm
731 bfextu ETEMP_EX(a6){1:15},d0 ;get src exp (always pos)
732 bfexts FPTEMP_EX(a6){1:15},d1 ;get dest exp (always neg)
733 sub.l d1,d0 ;subtract dest from src
735 blt fix_stk ;if less, not wrap case
737 move.w ETEMP_EX(a6),d0 ;find the sign of the result
738 move.w FPTEMP_EX(a6),d1
746 move.b STAG(a6),d0 ;check source tag for inf or nan
749 move.b DTAG(a6),d0 ;check destination tag for inf or nan
751 andi.b #$60,d0 ;isolate tag bits
752 cmp.b #$40,d0 ;is it inf?
753 beq nan_or_inf ;not wrap case
754 cmp.b #$60,d0 ;is it nan?
755 beq nan_or_inf ;yes, not wrap case?
756 cmp.b #$20,d0 ;is it a zero?
759 rts ;then it is either a zero of norm,
770 bfextu FPTEMP_EX(a6){1:15},d0 ;get dest exp (always pos)
771 bfexts ETEMP_EX(a6){1:15},d1 ;get src exp (always neg)
772 sub.l d1,d0 ;subtract src from dest
774 blt fix_stk ;if less, not wrap case
776 move.w ETEMP_EX(a6),d0 ;find the sign of the result
777 move.w FPTEMP_EX(a6),d1
783 * This code handles the case of the instruction resulting in
784 * an overflow condition.
787 bclr.b #E1,E_BYTE(a6)
788 or.l #ovfl_inx_mask,USER_FPSR(a6)
790 lea.l WBTEMP(a6),a0 ;point a0 to memory location
791 move.w CMDREG1B(a6),d0
792 btst.l #6,d0 ;test for forced precision
794 btst.l #2,d0 ;check for double
796 move.l #$1,d0 ;inst is forced single
799 move.l #$2,d0 ;inst is forced double
802 bfextu FPCR_MODE(a6){0:2},d0 ;inst not forced - use fpcr prec
805 * The 881/882 does not set inex2 for the following case, so the
806 * line is commented out to be compatible with 881/882
809 * or.l #inex2_mask,USER_FPSR(a6) ;if prec is s or d, set inex2
812 bsr.l ovf_res ;get correct result based on
813 * ;round precision/mode. This
814 * ;sets FPSR_CC correctly
815 * ;returns in external format
816 bfclr WBTEMP_SGN(a6){0:8}
818 bset.b #sign_bit,WBTEMP_EX(a6)
824 cmp.b #$ff,DNRM_FLG(a6) ;if both ops denorm,
825 beq fix_stk ;restore to fpu
827 * One of the ops is denormalized. Test for wrap condition
828 * and complete the instruction.
830 cmp.b #$0f,DNRM_FLG(a6) ;check for dest denorm
835 bfextu ETEMP_EX(a6){1:15},d0 ;get src exp (always pos)
836 bfexts FPTEMP_EX(a6){1:15},d1 ;get dest exp (always neg)
837 sub.l d1,d0 ;subtract dest from src
839 blt fix_stk ;if less, not wrap case
844 bfextu FPTEMP_EX(a6){1:15},d0 ;get dest exp (always pos)
845 bfexts ETEMP_EX(a6){1:15},d1 ;get src exp (always neg)
846 sub.l d1,d0 ;subtract src from dest
848 blt fix_stk ;if less, not wrap case
850 * Check the signs of the operands. If they are unlike, the fpu
851 * can be used to add the norm and 1.0 with the sign of the
852 * denorm and it will correctly generate the result in extended
853 * precision. We can then call round with no sticky and the result
854 * will be correct for the user's rounding mode and precision. If
855 * the signs are the same, we call round with the sticky bit set
856 * and the result will be correctfor the user's rounding mode and
860 move.w ETEMP_EX(a6),d0
861 move.w FPTEMP_EX(a6),d1
866 * The signs are unlike.
868 cmp.b #$0f,DNRM_FLG(a6) ;is dest the denorm?
870 move.w FPTEMP_EX(a6),d0
872 or.w #$3fff,d0 ;force the exponent to +/- 1
873 move.w d0,FPTEMP_EX(a6) ;in the denorm
874 move.l USER_FPCR(a6),d0
876 fmove.l d0,fpcr ;set up users rmode and X
877 fmove.x ETEMP(a6),fp0
878 fadd.x FPTEMP(a6),fp0
879 lea.l WBTEMP(a6),a0 ;point a0 to wbtemp in frame
881 or.l d1,USER_FPSR(a6) ;capture cc's and inex from fadd
882 fmove.x fp0,WBTEMP(a6) ;write result to memory
883 lsr.l #4,d0 ;put rmode in lower 2 bits
884 move.l USER_FPCR(a6),d1
886 lsr.l #6,d1 ;put precision in upper word
888 or.l d0,d1 ;set up for round call
889 clr.l d0 ;force sticky to zero
890 bclr.b #sign_bit,WBTEMP_EX(a6)
892 bsr.l round ;round result to users rmode & prec
893 bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format
895 bset.b #sign_bit,WBTEMP_EX(a6)
898 move.w ETEMP_EX(a6),d0
900 or.w #$3fff,d0 ;force the exponent to +/- 1
901 move.w d0,ETEMP_EX(a6) ;in the denorm
902 move.l USER_FPCR(a6),d0
904 fmove.l d0,fpcr ;set up users rmode and X
905 fmove.x ETEMP(a6),fp0
906 fadd.x FPTEMP(a6),fp0
908 or.l d1,USER_FPSR(a6) ;capture cc's and inex from fadd
909 lea.l WBTEMP(a6),a0 ;point a0 to wbtemp in frame
910 fmove.x fp0,WBTEMP(a6) ;write result to memory
911 lsr.l #4,d0 ;put rmode in lower 2 bits
912 move.l USER_FPCR(a6),d1
914 lsr.l #6,d1 ;put precision in upper word
916 or.l d0,d1 ;set up for round call
917 clr.l d0 ;force sticky to zero
918 bclr.b #sign_bit,WBTEMP_EX(a6)
919 sne WBTEMP_SGN(a6) ;use internal format for round
920 bsr.l round ;round result to users rmode & prec
921 bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format
923 bset.b #sign_bit,WBTEMP_EX(a6)
929 cmp.b #$0f,DNRM_FLG(a6) ;is dest the denorm?
933 move.l USER_FPCR(a6),d0
935 lsr.l #4,d0 ;put rmode in lower 2 bits
936 move.l USER_FPCR(a6),d1
938 lsr.l #6,d1 ;put precision in upper word
940 or.l d0,d1 ;set up for round call
941 move.l #$20000000,d0 ;set sticky for round
942 bclr.b #sign_bit,ETEMP_EX(a6)
944 bsr.l round ;round result to users rmode & prec
945 bfclr ETEMP_SGN(a6){0:8} ;convert back to IEEE ext format
947 bset.b #sign_bit,ETEMP_EX(a6)
950 move.l ETEMP(a6),(a0) ;write result to wbtemp
951 move.l ETEMP_HI(a6),4(a0)
952 move.l ETEMP_LO(a6),8(a0)
955 or.l #neg_mask,USER_FPSR(a6)
959 move.l USER_FPCR(a6),d0
961 lsr.l #4,d0 ;put rmode in lower 2 bits
962 move.l USER_FPCR(a6),d1
964 lsr.l #6,d1 ;put precision in upper word
966 or.l d0,d1 ;set up for round call
967 move.l #$20000000,d0 ;set sticky for round
968 bclr.b #sign_bit,FPTEMP_EX(a6)
970 bsr.l round ;round result to users rmode & prec
971 bfclr FPTEMP_SGN(a6){0:8} ;convert back to IEEE ext format
973 bset.b #sign_bit,FPTEMP_EX(a6)
976 move.l FPTEMP(a6),(a0) ;write result to wbtemp
977 move.l FPTEMP_HI(a6),4(a0)
978 move.l FPTEMP_LO(a6),8(a0)
981 or.l #neg_mask,USER_FPSR(a6)
983 move.w WBTEMP_EX(a6),d0
988 * The result has overflowed to $7fff exponent. Set I, ovfl,
989 * and aovfl, and clr the mantissa (incorrectly set by the
992 or.l #inf_mask+ovfl_inx_mask,USER_FPSR(a6)
999 cmp.b #$ff,DNRM_FLG(a6) ;if both ops denorm,
1000 beq fix_stk ;restore to fpu
1002 * One of the ops is denormalized. Test for wrap condition
1003 * and complete the instruction.
1005 cmp.b #$0f,DNRM_FLG(a6) ;check for dest denorm
1010 bfextu ETEMP_EX(a6){1:15},d0 ;get src exp (always pos)
1011 bfexts FPTEMP_EX(a6){1:15},d1 ;get dest exp (always neg)
1012 sub.l d1,d0 ;subtract src from dest
1014 blt fix_stk ;if less, not wrap case
1019 bfextu FPTEMP_EX(a6){1:15},d0 ;get dest exp (always pos)
1020 bfexts ETEMP_EX(a6){1:15},d1 ;get src exp (always neg)
1021 sub.l d1,d0 ;subtract dest from src
1023 blt fix_stk ;if less, not wrap case
1025 * Check the signs of the operands. If they are alike, the fpu
1026 * can be used to subtract from the norm 1.0 with the sign of the
1027 * denorm and it will correctly generate the result in extended
1028 * precision. We can then call round with no sticky and the result
1029 * will be correct for the user's rounding mode and precision. If
1030 * the signs are unlike, we call round with the sticky bit set
1031 * and the result will be correctfor the user's rounding mode and
1035 move.w ETEMP_EX(a6),d0
1036 move.w FPTEMP_EX(a6),d1
1041 * The signs are alike.
1043 cmp.b #$0f,DNRM_FLG(a6) ;is dest the denorm?
1045 move.w FPTEMP_EX(a6),d0
1047 or.w #$3fff,d0 ;force the exponent to +/- 1
1048 move.w d0,FPTEMP_EX(a6) ;in the denorm
1049 move.l USER_FPCR(a6),d0
1051 fmove.l d0,fpcr ;set up users rmode and X
1052 fmove.x FPTEMP(a6),fp0
1053 fsub.x ETEMP(a6),fp0
1055 or.l d1,USER_FPSR(a6) ;capture cc's and inex from fadd
1056 lea.l WBTEMP(a6),a0 ;point a0 to wbtemp in frame
1057 fmove.x fp0,WBTEMP(a6) ;write result to memory
1058 lsr.l #4,d0 ;put rmode in lower 2 bits
1059 move.l USER_FPCR(a6),d1
1061 lsr.l #6,d1 ;put precision in upper word
1063 or.l d0,d1 ;set up for round call
1064 clr.l d0 ;force sticky to zero
1065 bclr.b #sign_bit,WBTEMP_EX(a6)
1067 bsr.l round ;round result to users rmode & prec
1068 bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format
1070 bset.b #sign_bit,WBTEMP_EX(a6)
1073 move.w ETEMP_EX(a6),d0
1075 or.w #$3fff,d0 ;force the exponent to +/- 1
1076 move.w d0,ETEMP_EX(a6) ;in the denorm
1077 move.l USER_FPCR(a6),d0
1079 fmove.l d0,fpcr ;set up users rmode and X
1080 fmove.x FPTEMP(a6),fp0
1081 fsub.x ETEMP(a6),fp0
1083 or.l d1,USER_FPSR(a6) ;capture cc's and inex from fadd
1084 lea.l WBTEMP(a6),a0 ;point a0 to wbtemp in frame
1085 fmove.x fp0,WBTEMP(a6) ;write result to memory
1086 lsr.l #4,d0 ;put rmode in lower 2 bits
1087 move.l USER_FPCR(a6),d1
1089 lsr.l #6,d1 ;put precision in upper word
1091 or.l d0,d1 ;set up for round call
1092 clr.l d0 ;force sticky to zero
1093 bclr.b #sign_bit,WBTEMP_EX(a6)
1095 bsr.l round ;round result to users rmode & prec
1096 bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format
1098 bset.b #sign_bit,WBTEMP_EX(a6)
1104 cmp.b #$0f,DNRM_FLG(a6) ;is dest the denorm?
1108 move.l USER_FPCR(a6),d0
1110 lsr.l #4,d0 ;put rmode in lower 2 bits
1111 move.l USER_FPCR(a6),d1
1113 lsr.l #6,d1 ;put precision in upper word
1115 or.l d0,d1 ;set up for round call
1116 move.l #$20000000,d0 ;set sticky for round
1118 * Since the dest is the denorm, the sign is the opposite of the
1121 eori.w #$8000,ETEMP_EX(a6) ;flip sign on result
1124 or.l #neg_mask,USER_FPSR(a6)
1126 bclr.b #sign_bit,ETEMP_EX(a6)
1128 bsr.l round ;round result to users rmode & prec
1129 bfclr ETEMP_SGN(a6){0:8} ;convert back to IEEE ext format
1131 bset.b #sign_bit,ETEMP_EX(a6)
1134 move.l ETEMP(a6),(a0) ;write result to wbtemp
1135 move.l ETEMP_HI(a6),4(a0)
1136 move.l ETEMP_LO(a6),8(a0)
1140 move.l USER_FPCR(a6),d0
1142 lsr.l #4,d0 ;put rmode in lower 2 bits
1143 move.l USER_FPCR(a6),d1
1145 lsr.l #6,d1 ;put precision in upper word
1147 or.l d0,d1 ;set up for round call
1148 move.l #$20000000,d0 ;set sticky for round
1149 bclr.b #sign_bit,FPTEMP_EX(a6)
1151 bsr.l round ;round result to users rmode & prec
1152 bfclr FPTEMP_SGN(a6){0:8} ;convert back to IEEE ext format
1154 bset.b #sign_bit,FPTEMP_EX(a6)
1157 move.l FPTEMP(a6),(a0) ;write result to wbtemp
1158 move.l FPTEMP_HI(a6),4(a0)
1159 move.l FPTEMP_LO(a6),8(a0)
1162 or.l #neg_mask,USER_FPSR(a6)
1164 move.w WBTEMP_EX(a6),d0
1169 * The result has overflowed to $7fff exponent. Set I, ovfl,
1170 * and aovfl, and clr the mantissa (incorrectly set by the
1173 or.l #inf_mask+ovfl_inx_mask,USER_FPSR(a6)
1180 cmp.b #$ff,DNRM_FLG(a6) ;if both ops denorm,
1181 beq fix_stk ;restore to fpu
1183 * One of the ops is denormalized. Test for wrap condition
1184 * and complete the instruction.
1186 cmp.b #$0f,DNRM_FLG(a6) ;check for dest denorm
1191 bfextu ETEMP_EX(a6){1:15},d0 ;get src exp (always pos)
1192 bfexts FPTEMP_EX(a6){1:15},d1 ;get dest exp (always neg)
1193 sub.l d1,d0 ;subtract dest from src
1195 blt fix_stk ;if less, not wrap case
1196 tst.w ETEMP_EX(a6) ;set N to ~sign_of(src)
1202 bfextu FPTEMP_EX(a6){1:15},d0 ;get dest exp (always pos)
1203 bfexts ETEMP_EX(a6){1:15},d1 ;get src exp (always neg)
1204 sub.l d1,d0 ;subtract src from dest
1206 blt fix_stk ;if less, not wrap case
1207 tst.w FPTEMP_EX(a6) ;set N to sign_of(dest)
1211 or.l #neg_mask,USER_FPSR(a6)
1218 cmp.b #$ff,DNRM_FLG(a6) ;if both ops denorm,
1219 beq force_unf ;force an underflow (really!)
1221 * One of the ops is denormalized. Test for wrap condition
1222 * and complete the instruction.
1224 cmp.b #$0f,DNRM_FLG(a6) ;check for dest denorm
1229 bfextu ETEMP_EX(a6){1:15},d0 ;get src exp (always pos)
1230 bfexts FPTEMP_EX(a6){1:15},d1 ;get dest exp (always neg)
1231 add.l d1,d0 ;subtract dest from src
1237 bfextu FPTEMP_EX(a6){1:15},d0 ;get dest exp (always pos)
1238 bfexts ETEMP_EX(a6){1:15},d1 ;get src exp (always neg)
1239 add.l d1,d0 ;subtract src from dest
1243 * This code handles the case of the instruction resulting in
1244 * an underflow condition.
1247 bclr.b #E1,E_BYTE(a6)
1248 or.l #unfinx_mask,USER_FPSR(a6)
1250 clr.b WBTEMP_SGN(a6)
1251 move.w ETEMP_EX(a6),d0 ;find the sign of the result
1252 move.w FPTEMP_EX(a6),d1
1258 lea WBTEMP(a6),a0 ;point a0 to memory location
1259 move.w CMDREG1B(a6),d0
1260 btst.l #6,d0 ;test for forced precision
1262 btst.l #2,d0 ;check for double
1264 move.l #$1,d0 ;inst is forced single
1267 move.l #$2,d0 ;inst is forced double
1270 bfextu FPCR_MODE(a6){0:2},d0 ;inst not forced - use fpcr prec
1272 bsr.l unf_sub ;get correct result based on
1273 * ;round precision/mode. This
1274 * ;sets FPSR_CC correctly
1275 bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format
1277 bset.b #sign_bit,WBTEMP_EX(a6)
1281 * Write the result to the user's fpn. All results must be HUGE to be
1282 * written; otherwise the results would have overflowed or underflowed.
1283 * If the rounding precision is single or double, the ovf_res routine
1284 * is needed to correctly supply the max value.
1287 move.w CMDREG1B(a6),d0
1288 btst.l #6,d0 ;test for forced precision
1290 btst.l #2,d0 ;check for double
1292 move.l #$1,d0 ;inst is forced single
1295 move.l #$2,d0 ;inst is forced double
1298 bfextu FPCR_MODE(a6){0:2},d0 ;inst not forced - use fpcr prec
1300 beq.b frcfpn ;if extended, write what you got
1302 bclr.b #sign_bit,WBTEMP_EX(a6)
1304 bsr.l ovf_res ;get correct result based on
1305 * ;round precision/mode. This
1306 * ;sets FPSR_CC correctly
1307 bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format
1309 bset.b #sign_bit,WBTEMP_EX(a6)
1311 or.l #ovfinx_mask,USER_FPSR(a6)
1313 * Perform the write.
1316 bfextu CMDREG1B(a6){6:3},d0 ;extract fp destination register
1318 ble.b frc0123 ;check if dest is fp0-fp3
1323 fmovem.x WBTEMP(a6),d0
1333 move.l WBTEMP_EX(a6),USER_FP3(a6)
1334 move.l WBTEMP_HI(a6),USER_FP3+4(a6)
1335 move.l WBTEMP_LO(a6),USER_FP3+8(a6)
1338 move.l WBTEMP_EX(a6),USER_FP2(a6)
1339 move.l WBTEMP_HI(a6),USER_FP2+4(a6)
1340 move.l WBTEMP_LO(a6),USER_FP2+8(a6)
1343 move.l WBTEMP_EX(a6),USER_FP1(a6)
1344 move.l WBTEMP_HI(a6),USER_FP1+4(a6)
1345 move.l WBTEMP_LO(a6),USER_FP1+8(a6)
1348 move.l WBTEMP_EX(a6),USER_FP0(a6)
1349 move.l WBTEMP_HI(a6),USER_FP0+4(a6)
1350 move.l WBTEMP_LO(a6),USER_FP0+8(a6)
1354 * Write etemp to fpn.
1355 * A check is made on enabled and signalled snan exceptions,
1356 * and the destination is not overwritten if this condition exists.
1357 * This code is designed to make fmoveins of unsupported data types
1361 btst.b #snan_bit,FPSR_EXCEPT(a6) ;if snan is set, and
1362 beq.b fmoveinc ;enabled, force restore
1363 btst.b #snan_bit,FPCR_ENABLE(a6) ;and don't overwrite
1364 beq.b fmoveinc ;the dest
1365 move.l ETEMP_EX(a6),FPTEMP_EX(a6) ;set up fptemp sign for
1367 tst.b ETEMP(a6) ;check for negative
1371 or.l #neg_bit,USER_FPSR(a6) ;snan is negative; set N
1375 bclr.b #E1,E_BYTE(a6)
1376 move.b STAG(a6),d0 ;check if stag is inf
1380 or.l #inf_mask,USER_FPSR(a6) ;if inf, nothing yet has set I
1381 tst.w LOCAL_EX(a0) ;check sign
1383 or.l #neg_mask,USER_FPSR(a6)
1386 cmpi.b #$60,d0 ;check if stag is NaN
1388 or.l #nan_mask,USER_FPSR(a6) ;if nan, nothing yet has set NaN
1389 move.l ETEMP_EX(a6),FPTEMP_EX(a6) ;set up fptemp sign for
1391 tst.w LOCAL_EX(a0) ;check sign
1393 or.l #neg_mask,USER_FPSR(a6)
1396 cmpi.b #$20,d0 ;check if zero
1398 or.l #z_mask,USER_FPSR(a6) ;if zero, set Z
1399 tst.w LOCAL_EX(a0) ;check sign
1401 or.l #neg_mask,USER_FPSR(a6)
1403 bfextu CMDREG1B(a6){6:3},d0 ;extract fp destination register
1405 ble.b fp0123 ;check if dest is fp0-fp3
1410 fmovem.x ETEMP(a6),d0
1421 move.l ETEMP_EX(a6),USER_FP3(a6)
1422 move.l ETEMP_HI(a6),USER_FP3+4(a6)
1423 move.l ETEMP_LO(a6),USER_FP3+8(a6)
1426 move.l ETEMP_EX(a6),USER_FP2(a6)
1427 move.l ETEMP_HI(a6),USER_FP2+4(a6)
1428 move.l ETEMP_LO(a6),USER_FP2+8(a6)
1431 move.l ETEMP_EX(a6),USER_FP1(a6)
1432 move.l ETEMP_HI(a6),USER_FP1+4(a6)
1433 move.l ETEMP_LO(a6),USER_FP1+8(a6)
1436 move.l ETEMP_EX(a6),USER_FP0(a6)
1437 move.l ETEMP_HI(a6),USER_FP0+4(a6)
1438 move.l ETEMP_LO(a6),USER_FP0+8(a6)
1443 move.w CMDREG1B(a6),d0 ;check if packed moveout
1444 andi.w #$0c00,d0 ;isolate last 2 bits of size field
1445 cmpi.w #$0c00,d0 ;if size is 011 or 111, it is packed
1446 beq.w pack_out ;else it is norm or denorm
1458 dc.l mvout_end ;should never be taken
1462 dc.l mvout_end ;should never be taken
1464 bfextu CMDREG1B(a6){3:3},d1 ;put source specifier in d1
1470 * This exit is for move-out to memory. The aunfl bit is
1471 * set if the result is inex and unfl is signalled.
1474 btst.b #inex2_bit,FPSR_EXCEPT(a6)
1476 btst.b #unfl_bit,FPSR_EXCEPT(a6)
1478 bset.b #aunfl_bit,FPSR_AEXCEPT(a6)
1481 bclr.b #E1,E_BYTE(a6)
1482 fmove.l #0,FPSR ;clear any cc bits from res_func
1484 * Return ETEMP to extended format from internal extended format so
1485 * that gen_except will have a correctly signed value for ovfl/unfl
1488 bfclr ETEMP_SGN(a6){0:8}
1490 bset.b #sign_bit,ETEMP_EX(a6)
1494 * This exit is for move-out to int register. The aunfl bit is
1495 * not set in any case for this move.
1499 bclr.b #E1,E_BYTE(a6)
1500 fmove.l #0,FPSR ;clear any cc bits from res_func
1502 * Return ETEMP to extended format from internal extended format so
1503 * that gen_except will have a correctly signed value for ovfl/unfl
1506 bfclr ETEMP_SGN(a6){0:8}
1508 bset.b #sign_bit,ETEMP_EX(a6)
1512 * li is used to handle a long integer source specifier
1516 moveq.l #4,d0 ;set byte count
1518 btst.b #7,STAG(a6) ;check for extended denorm
1519 bne.w int_dnrm ;if so, branch
1521 fmovem.x ETEMP(a6),fp0
1522 fcmp.d #:41dfffffffc00000,fp0
1523 * 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
1525 fcmp.d #:c1e0000000000000,fp0
1526 * c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
1529 * at this point, the answer is between the largest pos and neg values
1531 move.l USER_FPCR(a6),d1 ;use user's rounding mode
1534 fmove.l fp0,L_SCR1(a6) ;let the 040 perform conversion
1536 or.l d1,USER_FPSR(a6) ;capture inex2/ainex if set
1541 move.l #$7fffffff,L_SCR1(a6) ;answer is largest positive int
1542 fbeq.w int_wrt ;exact answer
1543 fcmp.d #:41dfffffffe00000,fp0
1544 * 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
1545 fbge.w int_operr ;set operr
1546 bra.w int_inx ;set inexact
1549 move.l #$80000000,L_SCR1(a6)
1550 fbeq.w int_wrt ;exact answer
1551 fcmp.d #:c1e0000000100000,fp0
1552 * c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
1553 fblt.w int_operr ;set operr
1554 bra.w int_inx ;set inexact
1557 * wi is used to handle a word integer source specifier
1561 moveq.l #2,d0 ;set byte count
1563 btst.b #7,STAG(a6) ;check for extended denorm
1564 bne.w int_dnrm ;branch if so
1566 fmovem.x ETEMP(a6),fp0
1567 fcmp.s #:46fffe00,fp0
1568 * 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
1570 fcmp.s #:c7000000,fp0
1571 * c7000000 in sgl prec = c00e00008000000000000000 in ext prec
1575 * at this point, the answer is between the largest pos and neg values
1577 move.l USER_FPCR(a6),d1 ;use user's rounding mode
1580 fmove.w fp0,L_SCR1(a6) ;let the 040 perform conversion
1582 or.l d1,USER_FPSR(a6) ;capture inex2/ainex if set
1586 move.w #$7fff,L_SCR1(a6) ;answer is largest positive int
1587 fbeq.w int_wrt ;exact answer
1588 fcmp.s #:46ffff00,fp0
1589 * 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
1590 fbge.w int_operr ;set operr
1591 bra.w int_inx ;set inexact
1594 move.w #$8000,L_SCR1(a6)
1595 fbeq.w int_wrt ;exact answer
1596 fcmp.s #:c7000080,fp0
1597 * c7000080 in sgl prec = c00e00008000800000000000 in ext prec
1598 fblt.w int_operr ;set operr
1599 bra.w int_inx ;set inexact
1602 * bi is used to handle a byte integer source specifier
1606 moveq.l #1,d0 ;set byte count
1608 btst.b #7,STAG(a6) ;check for extended denorm
1609 bne.w int_dnrm ;branch if so
1611 fmovem.x ETEMP(a6),fp0
1612 fcmp.s #:42fe0000,fp0
1613 * 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
1615 fcmp.s #:c3000000,fp0
1616 * c3000000 in sgl prec = c00600008000000000000000 in ext prec
1620 * at this point, the answer is between the largest pos and neg values
1622 move.l USER_FPCR(a6),d1 ;use user's rounding mode
1625 fmove.b fp0,L_SCR1(a6) ;let the 040 perform conversion
1627 or.l d1,USER_FPSR(a6) ;capture inex2/ainex if set
1631 move.b #$7f,L_SCR1(a6) ;answer is largest positive int
1632 fbeq.w int_wrt ;exact answer
1633 fcmp.s #:42ff0000,fp0
1634 * 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
1635 fbge.w int_operr ;set operr
1636 bra.w int_inx ;set inexact
1639 move.b #$80,L_SCR1(a6)
1640 fbeq.w int_wrt ;exact answer
1641 fcmp.s #:c3008000,fp0
1642 * c3008000 in sgl prec = c00600008080000000000000 in ext prec
1643 fblt.w int_operr ;set operr
1644 bra.w int_inx ;set inexact
1647 * Common integer routines
1649 * int_drnrm---account for possible nonzero result for round up with positive
1650 * operand and round down for negative answer. In the first case (result = 1)
1651 * byte-width (store in d0) of result must be honored. In the second case,
1652 * -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).
1655 clr.l L_SCR1(a6) ; initialize result to 0
1656 bfextu FPCR_MODE(a6){2:2},d1 ; d1 is the rounding mode
1658 bmi.b int_inx ; if RN or RZ, done
1659 bne.b int_rp ; if RP, continue below
1660 tst.w ETEMP(a6) ; RM: store -1 in L_SCR1 if src is negative
1661 bpl.b int_inx ; otherwise result is 0
1662 move.l #-1,L_SCR1(a6)
1665 tst.w ETEMP(a6) ; RP: store +1 of proper width in L_SCR1 if
1666 * ; source is greater than 0
1667 bmi.b int_inx ; otherwise, result is 0
1668 lea L_SCR1(a6),a1 ; a1 is address of L_SCR1
1669 adda.l d0,a1 ; offset by destination width -1
1671 bset.b #0,(a1) ; set low bit at a1 address
1673 ori.l #inx2a_mask,USER_FPSR(a6)
1676 fmovem.x fp0,FPTEMP(a6) ;FPTEMP must contain the extended
1677 * ;precision source that needs to be
1678 * ;converted to integer this is required
1679 * ;if the operr exception is enabled.
1680 * ;set operr/aiop (no inex2 on int ovfl)
1682 ori.l #opaop_mask,USER_FPSR(a6)
1683 * ;fall through to perform int_wrt
1685 move.l EXC_EA(a6),a1 ;load destination address
1686 tst.l a1 ;check to see if it is a dest register
1687 beq.b wrt_dn ;write data register
1688 lea L_SCR1(a6),a0 ;point to supervisor source address
1693 move.l d0,-(sp) ;d0 currently contains the size to write
1694 bsr.l get_fline ;get_fline returns Dn in d0
1695 andi.w #$7,d0 ;isolate register
1696 move.l (sp)+,d1 ;get size
1697 cmpi.l #4,d1 ;most frequent case
1701 or.l #8,d0 ;add 'word' size to register#
1704 or.l #$10,d0 ;add 'long' size to register#
1706 move.l d0,d1 ;reg_dest expects size:reg in d1
1707 bsr.l reg_dest ;load proper data register
1711 bclr.b #sign_bit,LOCAL_EX(a0)
1713 btst.b #7,STAG(a6) ;check for extended denorm
1716 bra.b do_fp ;do normal case
1719 bclr.b #sign_bit,LOCAL_EX(a0)
1721 btst.b #7,STAG(a6) ;check for extended denorm
1722 bne.w sp_catas ;branch if so
1723 move.w LOCAL_EX(a0),d0
1729 move.l #1,d0 ;set destination format to single
1730 bra.b do_fp ;do normal case
1733 bclr.b #sign_bit,LOCAL_EX(a0)
1736 btst.b #7,STAG(a6) ;check for extended denorm
1737 bne.w dp_catas ;branch if so
1739 move.w LOCAL_EX(a0),d0
1747 move.l #2,d0 ;set destination format to double
1748 * ;fall through to do_fp
1751 bfextu FPCR_MODE(a6){2:2},d1 ;rnd mode in d1
1752 swap d0 ;rnd prec in upper word
1753 add.l d0,d1 ;d1 has PREC/MODE info
1755 clr.l d0 ;clear g,r,s
1760 move.l EXC_EA(a6),a0
1762 bfextu CMDREG1B(a6){3:3},d1 ;extract destination format
1763 * ;at this point only the dest
1764 * ;formats sgl, dbl, ext are
1767 bgt.b ddbl ;double=5, extended=2, single=1
1769 * ;fall through to dext
1781 * Handle possible denorm or catastrophic underflow cases here
1784 bsr.w set_xop ;initialize WBTEMP
1785 bset.b #wbtemp15_bit,WB_BYTE(a6) ;set wbtemp15
1788 move.l EXC_EA(a6),a0 ;a0 has the destination pointer
1789 bsr.l dest_ext ;store to memory
1790 bset.b #unfl_bit,FPSR_EXCEPT(a6)
1794 bset.b #etemp15_bit,STAG(a6)
1797 blt.b sp_catas ;catastrophic underflow case
1799 move.l #1,d0 ;load in round precision
1800 move.l #sgl_thresh,d1 ;load in single denorm threshold
1801 bsr.l dpspdnrm ;expects d1 to have the proper
1803 bsr.l dest_sgl ;stores value to destination
1804 bset.b #unfl_bit,FPSR_EXCEPT(a6)
1805 bra.w mvout_end ;exit
1808 bset.b #etemp15_bit,STAG(a6)
1811 blt.b dp_catas ;catastrophic underflow case
1813 move.l #dbl_thresh,d1 ;load in double precision threshold
1815 bsr.l dpspdnrm ;expects d1 to have proper
1817 * ;expects d0 to have round precision
1818 bsr.l dest_dbl ;store value to destination
1819 bset.b #unfl_bit,FPSR_EXCEPT(a6)
1820 bra.w mvout_end ;exit
1823 * Handle catastrophic underflow cases here
1826 * Temp fix for z bit set in unf_sub
1827 move.l USER_FPSR(a6),-(a7)
1829 move.l #1,d0 ;set round precision to sgl
1831 bsr.l unf_sub ;a0 points to result
1833 move.l (a7)+,USER_FPSR(a6)
1836 sub.w d0,LOCAL_EX(a0) ;account for difference between
1839 move.l a0,a1 ;a1 has the operand input
1840 move.l EXC_EA(a6),a0 ;a0 has the destination pointer
1842 bsr.l dest_sgl ;store the result
1843 ori.l #unfinx_mask,USER_FPSR(a6)
1847 * Temp fix for z bit set in unf_sub
1848 move.l USER_FPSR(a6),-(a7)
1850 move.l #2,d0 ;set round precision to dbl
1851 bsr.l unf_sub ;a0 points to result
1853 move.l (a7)+,USER_FPSR(a6)
1856 sub.w d0,LOCAL_EX(a0) ;account for difference between
1859 move.l a0,a1 ;a1 has the operand input
1860 move.l EXC_EA(a6),a0 ;a0 has the destination pointer
1862 bsr.l dest_dbl ;store the result
1863 ori.l #unfinx_mask,USER_FPSR(a6)
1867 * Handle catastrophic overflow cases here
1870 * Temp fix for z bit set in unf_sub
1871 move.l USER_FPSR(a6),-(a7)
1874 lea.l FP_SCR1(a6),a0 ;use FP_SCR1 for creating result
1875 move.l ETEMP_EX(a6),(a0)
1876 move.l ETEMP_HI(a6),4(a0)
1877 move.l ETEMP_LO(a6),8(a0)
1880 move.l (a7)+,USER_FPSR(a6)
1883 move.l EXC_EA(a6),a0
1885 or.l #ovfinx_mask,USER_FPSR(a6)
1889 * Temp fix for z bit set in ovf_res
1890 move.l USER_FPSR(a6),-(a7)
1893 lea.l FP_SCR1(a6),a0 ;use FP_SCR1 for creating result
1894 move.l ETEMP_EX(a6),(a0)
1895 move.l ETEMP_HI(a6),4(a0)
1896 move.l ETEMP_LO(a6),8(a0)
1899 move.l (a7)+,USER_FPSR(a6)
1902 move.l EXC_EA(a6),a0
1904 or.l #ovfinx_mask,USER_FPSR(a6)
1910 * This subroutine takes an extended normalized number and denormalizes
1911 * it to the given round precision. This subroutine also decrements
1912 * the input operand's exponent by 1 to account for the fact that
1913 * dest_sgl or dest_dbl expects a normalized number's bias.
1915 * Input: a0 points to a normalized number in internal extended format
1916 * d0 is the round precision (=1 for sgl; =2 for dbl)
1917 * d1 is the single precision or double precision
1920 * Output: (In the format for dest_sgl or dest_dbl)
1921 * a0 points to the destination
1922 * a1 points to the operand
1924 * Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
1927 move.l d0,-(a7) ;save round precision
1928 clr.l d0 ;clear initial g,r,s
1929 bsr.l dnrm_lp ;careful with d0, it's needed by round
1931 bfextu FPCR_MODE(a6){2:2},d1 ;get rounding mode
1933 move.w 2(a7),d1 ;set rounding precision
1934 swap d1 ;at this point d1 has PREC/MODE info
1935 bsr.l round ;round result, sets the inex bit in
1936 * ;USER_FPSR if needed
1939 sub.w d0,LOCAL_EX(a0) ;account for difference in denorm
1942 move.l a0,a1 ;a1 has the operand input
1943 move.l EXC_EA(a6),a0 ;a0 has the destination pointer
1944 addq.l #4,a7 ;pop stack
1947 * SET_XOP initialized WBTEMP with the value pointed to by a0
1948 * input: a0 points to input operand in the internal extended format
1951 move.l LOCAL_EX(a0),WBTEMP_EX(a6)
1952 move.l LOCAL_HI(a0),WBTEMP_HI(a6)
1953 move.l LOCAL_LO(a0),WBTEMP_LO(a6)
1954 bfclr WBTEMP_SGN(a6){0:8}
1956 bset.b #sign_bit,WBTEMP_EX(a6)
1958 bfclr STAG(a6){5:4} ;clear wbtm66,wbtm1,wbtm0,sbit
1980 lea.l p_movet,a0 ;load jmp table address
1981 move.w STAG(a6),d0 ;get source tag
1982 bfextu d0{16:3},d0 ;isolate source bits
1983 move.l (a0,d0.w*4),a0 ;load a0 with routine label for tag
1984 jmp (a0) ;go to the routine
1987 move.l #$0c,d0 ;get byte count
1988 move.l EXC_EA(a6),a1 ;get the destination address
1989 bsr mem_write ;write the user's destination
1990 clr.b CU_SAVEPC(a6) ;set the cu save pc to all 0's
1993 * Also note that the dtag must be set to norm here - this is because
1994 * the 040 uses the dtag to execute the correct microcode.
1996 bfclr DTAG(a6){0:3} ;set dtag to norm
2000 * Notes on handling of special case (zero, inf, and nan) inputs:
2001 * 1. Operr is not signalled if the k-factor is greater than 18.
2002 * 2. Per the manual, status bits are not set.
2006 move.w CMDREG1B(a6),d0
2007 btst.l #kfact_bit,d0 ;test for dynamic k-factor
2008 beq.b statick ;if clear, k-factor is static
2010 bfextu d0{25:3},d0 ;isolate register for dynamic k-factor
2015 andi.w #$007f,d0 ;get k-factor
2016 bfexts d0{25:7},d0 ;sign extend d0 for bindec
2017 lea.l ETEMP(a6),a0 ;a0 will point to the packed decimal
2018 bsr.l bindec ;perform the convert; data at a6
2019 lea.l FP_SCR1(a6),a0 ;load a0 with result address
2022 lea.l ETEMP(a6),a0 ;a0 will point to the packed decimal
2023 clr.w 2(a0) ;clear lower word of exp
2024 clr.l 4(a0) ;load second lword of ZERO
2025 clr.l 8(a0) ;load third lword of ZERO
2026 bra.w p_write ;go write results
2028 fmove.l #0,FPSR ;clear aiop
2029 lea.l ETEMP(a6),a0 ;a0 will point to the packed decimal
2030 clr.w 2(a0) ;clear lower word of exp
2031 bra.w p_write ;go write the result
2033 lea.l ETEMP(a6),a0 ;a0 will point to the packed decimal
2034 clr.w 2(a0) ;clear lower word of exp
2035 bra.w p_write ;go write the result
2038 * Routines to read the dynamic k-factor from Dn.
2041 move.l USER_D0(a6),d0
2044 move.l USER_D1(a6),d0