summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libcpu/m68k/m68040/fpsp/res_func.S
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libcpu/m68k/m68040/fpsp/res_func.S')
-rw-r--r--c/src/lib/libcpu/m68k/m68040/fpsp/res_func.S2042
1 files changed, 0 insertions, 2042 deletions
diff --git a/c/src/lib/libcpu/m68k/m68040/fpsp/res_func.S b/c/src/lib/libcpu/m68k/m68040/fpsp/res_func.S
deleted file mode 100644
index 4afdae8a23..0000000000
--- a/c/src/lib/libcpu/m68k/m68040/fpsp/res_func.S
+++ /dev/null
@@ -1,2042 +0,0 @@
-#include "fpsp-namespace.h"
-//
-//
-// res_func.sa 3.9 7/29/91
-//
-// Normalizes denormalized numbers if necessary and updates the
-// stack frame. The function is then restored back into the
-// machine and the 040 completes the operation. This routine
-// is only used by the unsupported data type/format handler.
-// (Exception vector 55).
-//
-// For packed move out (fmove.p fpm,<ea>) the operation is
-// completed here; data is packed and moved to user memory.
-// The stack is restored to the 040 only in the case of a
-// reportable exception in the conversion.
-//
-//
-// Copyright (C) Motorola, Inc. 1990
-// All Rights Reserved
-//
-// THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
-// The copyright notice above does not evidence any
-// actual or intended publication of such source code.
-
-RES_FUNC: //idnt 2,1 | Motorola 040 Floating Point Software Package
-
- |section 8
-
-#include "fpsp.defs"
-
-sp_bnds: .short 0x3f81,0x407e
- .short 0x3f6a,0x0000
-dp_bnds: .short 0x3c01,0x43fe
- .short 0x3bcd,0x0000
-
- |xref mem_write
- |xref bindec
- |xref get_fline
- |xref round
- |xref denorm
- |xref dest_ext
- |xref dest_dbl
- |xref dest_sgl
- |xref unf_sub
- |xref nrm_set
- |xref dnrm_lp
- |xref ovf_res
- |xref reg_dest
- |xref t_ovfl
- |xref t_unfl
-
- .global res_func
- .global p_move
-
-res_func:
- clrb DNRM_FLG(%a6)
- clrb RES_FLG(%a6)
- clrb CU_ONLY(%a6)
- tstb DY_MO_FLG(%a6)
- beqs monadic
-dyadic:
- btstb #7,DTAG(%a6) //if dop = norm=000, zero=001,
-// ;inf=010 or nan=011
- beqs monadic //then branch
-// ;else denorm
-// HANDLE DESTINATION DENORM HERE
-// ;set dtag to norm
-// ;write the tag & fpte15 to the fstack
- leal FPTEMP(%a6),%a0
-
- bclrb #sign_bit,LOCAL_EX(%a0)
- sne LOCAL_SGN(%a0)
-
- bsr nrm_set //normalize number (exp will go negative)
- bclrb #sign_bit,LOCAL_EX(%a0) //get rid of false sign
- bfclr LOCAL_SGN(%a0){#0:#8} //change back to IEEE ext format
- beqs dpos
- bsetb #sign_bit,LOCAL_EX(%a0)
-dpos:
- bfclr DTAG(%a6){#0:#4} //set tag to normalized, FPTE15 = 0
- bsetb #4,DTAG(%a6) //set FPTE15
- orb #0x0f,DNRM_FLG(%a6)
-monadic:
- leal ETEMP(%a6),%a0
- btstb #direction_bit,CMDREG1B(%a6) //check direction
- bne opclass3 //it is a mv out
-//
-// At this point, only opclass 0 and 2 possible
-//
- btstb #7,STAG(%a6) //if sop = norm=000, zero=001,
-// ;inf=010 or nan=011
- bne mon_dnrm //else denorm
- tstb DY_MO_FLG(%a6) //all cases of dyadic instructions would
- bne normal //require normalization of denorm
-
-// At this point:
-// monadic instructions: fabs = $18 fneg = $1a ftst = $3a
-// fmove = $00 fsmove = $40 fdmove = $44
-// fsqrt = $05* fssqrt = $41 fdsqrt = $45
-// (*fsqrt reencoded to $05)
-//
- movew CMDREG1B(%a6),%d0 //get command register
- andil #0x7f,%d0 //strip to only command word
-//
-// At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
-// fdsqrt are possible.
-// For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
-// For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
-//
- btstl #0,%d0
- bne normal //weed out fsqrt instructions
-//
-// cu_norm handles fmove in instructions with normalized inputs.
-// The routine round is used to correctly round the input for the
-// destination precision and mode.
-//
-cu_norm:
- st CU_ONLY(%a6) //set cu-only inst flag
- movew CMDREG1B(%a6),%d0
- andib #0x3b,%d0 //isolate bits to select inst
- tstb %d0
- beql cu_nmove //if zero, it is an fmove
- cmpib #0x18,%d0
- beql cu_nabs //if $18, it is fabs
- cmpib #0x1a,%d0
- beql cu_nneg //if $1a, it is fneg
-//
-// Inst is ftst. Check the source operand and set the cc's accordingly.
-// No write is done, so simply rts.
-//
-cu_ntst:
- movew LOCAL_EX(%a0),%d0
- bclrl #15,%d0
- sne LOCAL_SGN(%a0)
- beqs cu_ntpo
- orl #neg_mask,USER_FPSR(%a6) //set N
-cu_ntpo:
- cmpiw #0x7fff,%d0 //test for inf/nan
- bnes cu_ntcz
- tstl LOCAL_HI(%a0)
- bnes cu_ntn
- tstl LOCAL_LO(%a0)
- bnes cu_ntn
- orl #inf_mask,USER_FPSR(%a6)
- rts
-cu_ntn:
- orl #nan_mask,USER_FPSR(%a6)
- movel ETEMP_EX(%a6),FPTEMP_EX(%a6) //set up fptemp sign for
-// ;snan handler
-
- rts
-cu_ntcz:
- tstl LOCAL_HI(%a0)
- bnel cu_ntsx
- tstl LOCAL_LO(%a0)
- bnel cu_ntsx
- orl #z_mask,USER_FPSR(%a6)
-cu_ntsx:
- rts
-//
-// Inst is fabs. Execute the absolute value function on the input.
-// Branch to the fmove code. If the operand is NaN, do nothing.
-//
-cu_nabs:
- moveb STAG(%a6),%d0
- btstl #5,%d0 //test for NaN or zero
- bne wr_etemp //if either, simply write it
- bclrb #7,LOCAL_EX(%a0) //do abs
- bras cu_nmove //fmove code will finish
-//
-// Inst is fneg. Execute the negate value function on the input.
-// Fall though to the fmove code. If the operand is NaN, do nothing.
-//
-cu_nneg:
- moveb STAG(%a6),%d0
- btstl #5,%d0 //test for NaN or zero
- bne wr_etemp //if either, simply write it
- bchgb #7,LOCAL_EX(%a0) //do neg
-//
-// Inst is fmove. This code also handles all result writes.
-// If bit 2 is set, round is forced to double. If it is clear,
-// and bit 6 is set, round is forced to single. If both are clear,
-// the round precision is found in the fpcr. If the rounding precision
-// is double or single, round the result before the write.
-//
-cu_nmove:
- moveb STAG(%a6),%d0
- andib #0xe0,%d0 //isolate stag bits
- bne wr_etemp //if not norm, simply write it
- btstb #2,CMDREG1B+1(%a6) //check for rd
- bne cu_nmrd
- btstb #6,CMDREG1B+1(%a6) //check for rs
- bne cu_nmrs
-//
-// The move or operation is not with forced precision. Test for
-// nan or inf as the input; if so, simply write it to FPn. Use the
-// FPCR_MODE byte to get rounding on norms and zeros.
-//
-cu_nmnr:
- bfextu FPCR_MODE(%a6){#0:#2},%d0
- tstb %d0 //check for extended
- beq cu_wrexn //if so, just write result
- cmpib #1,%d0 //check for single
- beq cu_nmrs //fall through to double
-//
-// The move is fdmove or round precision is double.
-//
-cu_nmrd:
- movel #2,%d0 //set up the size for denorm
- movew LOCAL_EX(%a0),%d1 //compare exponent to double threshold
- andw #0x7fff,%d1
- cmpw #0x3c01,%d1
- bls cu_nunfl
- bfextu FPCR_MODE(%a6){#2:#2},%d1 //get rmode
- orl #0x00020000,%d1 //or in rprec (double)
- clrl %d0 //clear g,r,s for round
- bclrb #sign_bit,LOCAL_EX(%a0) //convert to internal format
- sne LOCAL_SGN(%a0)
- bsrl round
- bfclr LOCAL_SGN(%a0){#0:#8}
- beqs cu_nmrdc
- bsetb #sign_bit,LOCAL_EX(%a0)
-cu_nmrdc:
- movew LOCAL_EX(%a0),%d1 //check for overflow
- andw #0x7fff,%d1
- cmpw #0x43ff,%d1
- bge cu_novfl //take care of overflow case
- bra cu_wrexn
-//
-// The move is fsmove or round precision is single.
-//
-cu_nmrs:
- movel #1,%d0
- movew LOCAL_EX(%a0),%d1
- andw #0x7fff,%d1
- cmpw #0x3f81,%d1
- bls cu_nunfl
- bfextu FPCR_MODE(%a6){#2:#2},%d1
- orl #0x00010000,%d1
- clrl %d0
- bclrb #sign_bit,LOCAL_EX(%a0)
- sne LOCAL_SGN(%a0)
- bsrl round
- bfclr LOCAL_SGN(%a0){#0:#8}
- beqs cu_nmrsc
- bsetb #sign_bit,LOCAL_EX(%a0)
-cu_nmrsc:
- movew LOCAL_EX(%a0),%d1
- andw #0x7FFF,%d1
- cmpw #0x407f,%d1
- blt cu_wrexn
-//
-// The operand is above precision boundaries. Use t_ovfl to
-// generate the correct value.
-//
-cu_novfl:
- bsr t_ovfl
- bra cu_wrexn
-//
-// The operand is below precision boundaries. Use denorm to
-// generate the correct value.
-//
-cu_nunfl:
- bclrb #sign_bit,LOCAL_EX(%a0)
- sne LOCAL_SGN(%a0)
- bsr denorm
- bfclr LOCAL_SGN(%a0){#0:#8} //change back to IEEE ext format
- beqs cu_nucont
- bsetb #sign_bit,LOCAL_EX(%a0)
-cu_nucont:
- bfextu FPCR_MODE(%a6){#2:#2},%d1
- btstb #2,CMDREG1B+1(%a6) //check for rd
- bne inst_d
- btstb #6,CMDREG1B+1(%a6) //check for rs
- bne inst_s
- swap %d1
- moveb FPCR_MODE(%a6),%d1
- lsrb #6,%d1
- swap %d1
- bra inst_sd
-inst_d:
- orl #0x00020000,%d1
- bra inst_sd
-inst_s:
- orl #0x00010000,%d1
-inst_sd:
- bclrb #sign_bit,LOCAL_EX(%a0)
- sne LOCAL_SGN(%a0)
- bsrl round
- bfclr LOCAL_SGN(%a0){#0:#8}
- beqs cu_nuflp
- bsetb #sign_bit,LOCAL_EX(%a0)
-cu_nuflp:
- btstb #inex2_bit,FPSR_EXCEPT(%a6)
- beqs cu_nuninx
- orl #aunfl_mask,USER_FPSR(%a6) //if the round was inex, set AUNFL
-cu_nuninx:
- tstl LOCAL_HI(%a0) //test for zero
- bnes cu_nunzro
- tstl LOCAL_LO(%a0)
- bnes cu_nunzro
-//
-// The mantissa is zero from the denorm loop. Check sign and rmode
-// to see if rounding should have occurred which would leave the lsb.
-//
- movel USER_FPCR(%a6),%d0
- andil #0x30,%d0 //isolate rmode
- cmpil #0x20,%d0
- blts cu_nzro
- bnes cu_nrp
-cu_nrm:
- tstw LOCAL_EX(%a0) //if positive, set lsb
- bges cu_nzro
- btstb #7,FPCR_MODE(%a6) //check for double
- beqs cu_nincs
- bras cu_nincd
-cu_nrp:
- tstw LOCAL_EX(%a0) //if positive, set lsb
- blts cu_nzro
- btstb #7,FPCR_MODE(%a6) //check for double
- beqs cu_nincs
-cu_nincd:
- orl #0x800,LOCAL_LO(%a0) //inc for double
- bra cu_nunzro
-cu_nincs:
- orl #0x100,LOCAL_HI(%a0) //inc for single
- bra cu_nunzro
-cu_nzro:
- orl #z_mask,USER_FPSR(%a6)
- moveb STAG(%a6),%d0
- andib #0xe0,%d0
- cmpib #0x40,%d0 //check if input was tagged zero
- beqs cu_numv
-cu_nunzro:
- orl #unfl_mask,USER_FPSR(%a6) //set unfl
-cu_numv:
- movel (%a0),ETEMP(%a6)
- movel 4(%a0),ETEMP_HI(%a6)
- movel 8(%a0),ETEMP_LO(%a6)
-//
-// Write the result to memory, setting the fpsr cc bits. NaN and Inf
-// bypass cu_wrexn.
-//
-cu_wrexn:
- tstw LOCAL_EX(%a0) //test for zero
- beqs cu_wrzero
- cmpw #0x8000,LOCAL_EX(%a0) //test for zero
- bnes cu_wreon
-cu_wrzero:
- orl #z_mask,USER_FPSR(%a6) //set Z bit
-cu_wreon:
- tstw LOCAL_EX(%a0)
- bpl wr_etemp
- orl #neg_mask,USER_FPSR(%a6)
- bra wr_etemp
-
-//
-// HANDLE SOURCE DENORM HERE
-//
-// ;clear denorm stag to norm
-// ;write the new tag & ete15 to the fstack
-mon_dnrm:
-//
-// At this point, check for the cases in which normalizing the
-// denorm produces incorrect results.
-//
- tstb DY_MO_FLG(%a6) //all cases of dyadic instructions would
- bnes nrm_src //require normalization of denorm
-
-// At this point:
-// monadic instructions: fabs = $18 fneg = $1a ftst = $3a
-// fmove = $00 fsmove = $40 fdmove = $44
-// fsqrt = $05* fssqrt = $41 fdsqrt = $45
-// (*fsqrt reencoded to $05)
-//
- movew CMDREG1B(%a6),%d0 //get command register
- andil #0x7f,%d0 //strip to only command word
-//
-// At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
-// fdsqrt are possible.
-// For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
-// For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
-//
- btstl #0,%d0
- bnes nrm_src //weed out fsqrt instructions
- st CU_ONLY(%a6) //set cu-only inst flag
- bra cu_dnrm //fmove, fabs, fneg, ftst
-// ;cases go to cu_dnrm
-nrm_src:
- bclrb #sign_bit,LOCAL_EX(%a0)
- sne LOCAL_SGN(%a0)
- bsr nrm_set //normalize number (exponent will go
-// ; negative)
- bclrb #sign_bit,LOCAL_EX(%a0) //get rid of false sign
-
- bfclr LOCAL_SGN(%a0){#0:#8} //change back to IEEE ext format
- beqs spos
- bsetb #sign_bit,LOCAL_EX(%a0)
-spos:
- bfclr STAG(%a6){#0:#4} //set tag to normalized, FPTE15 = 0
- bsetb #4,STAG(%a6) //set ETE15
- orb #0xf0,DNRM_FLG(%a6)
-normal:
- tstb DNRM_FLG(%a6) //check if any of the ops were denorms
- bne ck_wrap //if so, check if it is a potential
-// ;wrap-around case
-fix_stk:
- moveb #0xfe,CU_SAVEPC(%a6)
- bclrb #E1,E_BYTE(%a6)
-
- clrw NMNEXC(%a6)
-
- st RES_FLG(%a6) //indicate that a restore is needed
- rts
-
-//
-// cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
-// ftst) completely in software without an frestore to the 040.
-//
-cu_dnrm:
- st CU_ONLY(%a6)
- movew CMDREG1B(%a6),%d0
- andib #0x3b,%d0 //isolate bits to select inst
- tstb %d0
- beql cu_dmove //if zero, it is an fmove
- cmpib #0x18,%d0
- beql cu_dabs //if $18, it is fabs
- cmpib #0x1a,%d0
- beql cu_dneg //if $1a, it is fneg
-//
-// Inst is ftst. Check the source operand and set the cc's accordingly.
-// No write is done, so simply rts.
-//
-cu_dtst:
- movew LOCAL_EX(%a0),%d0
- bclrl #15,%d0
- sne LOCAL_SGN(%a0)
- beqs cu_dtpo
- orl #neg_mask,USER_FPSR(%a6) //set N
-cu_dtpo:
- cmpiw #0x7fff,%d0 //test for inf/nan
- bnes cu_dtcz
- tstl LOCAL_HI(%a0)
- bnes cu_dtn
- tstl LOCAL_LO(%a0)
- bnes cu_dtn
- orl #inf_mask,USER_FPSR(%a6)
- rts
-cu_dtn:
- orl #nan_mask,USER_FPSR(%a6)
- movel ETEMP_EX(%a6),FPTEMP_EX(%a6) //set up fptemp sign for
-// ;snan handler
- rts
-cu_dtcz:
- tstl LOCAL_HI(%a0)
- bnel cu_dtsx
- tstl LOCAL_LO(%a0)
- bnel cu_dtsx
- orl #z_mask,USER_FPSR(%a6)
-cu_dtsx:
- rts
-//
-// Inst is fabs. Execute the absolute value function on the input.
-// Branch to the fmove code.
-//
-cu_dabs:
- bclrb #7,LOCAL_EX(%a0) //do abs
- bras cu_dmove //fmove code will finish
-//
-// Inst is fneg. Execute the negate value function on the input.
-// Fall though to the fmove code.
-//
-cu_dneg:
- bchgb #7,LOCAL_EX(%a0) //do neg
-//
-// Inst is fmove. This code also handles all result writes.
-// If bit 2 is set, round is forced to double. If it is clear,
-// and bit 6 is set, round is forced to single. If both are clear,
-// the round precision is found in the fpcr. If the rounding precision
-// is double or single, the result is zero, and the mode is checked
-// to determine if the lsb of the result should be set.
-//
-cu_dmove:
- btstb #2,CMDREG1B+1(%a6) //check for rd
- bne cu_dmrd
- btstb #6,CMDREG1B+1(%a6) //check for rs
- bne cu_dmrs
-//
-// The move or operation is not with forced precision. Use the
-// FPCR_MODE byte to get rounding.
-//
-cu_dmnr:
- bfextu FPCR_MODE(%a6){#0:#2},%d0
- tstb %d0 //check for extended
- beq cu_wrexd //if so, just write result
- cmpib #1,%d0 //check for single
- beq cu_dmrs //fall through to double
-//
-// The move is fdmove or round precision is double. Result is zero.
-// Check rmode for rp or rm and set lsb accordingly.
-//
-cu_dmrd:
- bfextu FPCR_MODE(%a6){#2:#2},%d1 //get rmode
- tstw LOCAL_EX(%a0) //check sign
- blts cu_dmdn
- cmpib #3,%d1 //check for rp
- bne cu_dpd //load double pos zero
- bra cu_dpdr //load double pos zero w/lsb
-cu_dmdn:
- cmpib #2,%d1 //check for rm
- bne cu_dnd //load double neg zero
- bra cu_dndr //load double neg zero w/lsb
-//
-// The move is fsmove or round precision is single. Result is zero.
-// Check for rp or rm and set lsb accordingly.
-//
-cu_dmrs:
- bfextu FPCR_MODE(%a6){#2:#2},%d1 //get rmode
- tstw LOCAL_EX(%a0) //check sign
- blts cu_dmsn
- cmpib #3,%d1 //check for rp
- bne cu_spd //load single pos zero
- bra cu_spdr //load single pos zero w/lsb
-cu_dmsn:
- cmpib #2,%d1 //check for rm
- bne cu_snd //load single neg zero
- bra cu_sndr //load single neg zero w/lsb
-//
-// The precision is extended, so the result in etemp is correct.
-// Simply set unfl (not inex2 or aunfl) and write the result to
-// the correct fp register.
-cu_wrexd:
- orl #unfl_mask,USER_FPSR(%a6)
- tstw LOCAL_EX(%a0)
- beq wr_etemp
- orl #neg_mask,USER_FPSR(%a6)
- bra wr_etemp
-//
-// These routines write +/- zero in double format. The routines
-// cu_dpdr and cu_dndr set the double lsb.
-//
-cu_dpd:
- movel #0x3c010000,LOCAL_EX(%a0) //force pos double zero
- clrl LOCAL_HI(%a0)
- clrl LOCAL_LO(%a0)
- orl #z_mask,USER_FPSR(%a6)
- orl #unfinx_mask,USER_FPSR(%a6)
- bra wr_etemp
-cu_dpdr:
- movel #0x3c010000,LOCAL_EX(%a0) //force pos double zero
- clrl LOCAL_HI(%a0)
- movel #0x800,LOCAL_LO(%a0) //with lsb set
- orl #unfinx_mask,USER_FPSR(%a6)
- bra wr_etemp
-cu_dnd:
- movel #0xbc010000,LOCAL_EX(%a0) //force pos double zero
- clrl LOCAL_HI(%a0)
- clrl LOCAL_LO(%a0)
- orl #z_mask,USER_FPSR(%a6)
- orl #neg_mask,USER_FPSR(%a6)
- orl #unfinx_mask,USER_FPSR(%a6)
- bra wr_etemp
-cu_dndr:
- movel #0xbc010000,LOCAL_EX(%a0) //force pos double zero
- clrl LOCAL_HI(%a0)
- movel #0x800,LOCAL_LO(%a0) //with lsb set
- orl #neg_mask,USER_FPSR(%a6)
- orl #unfinx_mask,USER_FPSR(%a6)
- bra wr_etemp
-//
-// These routines write +/- zero in single format. The routines
-// cu_dpdr and cu_dndr set the single lsb.
-//
-cu_spd:
- movel #0x3f810000,LOCAL_EX(%a0) //force pos single zero
- clrl LOCAL_HI(%a0)
- clrl LOCAL_LO(%a0)
- orl #z_mask,USER_FPSR(%a6)
- orl #unfinx_mask,USER_FPSR(%a6)
- bra wr_etemp
-cu_spdr:
- movel #0x3f810000,LOCAL_EX(%a0) //force pos single zero
- movel #0x100,LOCAL_HI(%a0) //with lsb set
- clrl LOCAL_LO(%a0)
- orl #unfinx_mask,USER_FPSR(%a6)
- bra wr_etemp
-cu_snd:
- movel #0xbf810000,LOCAL_EX(%a0) //force pos single zero
- clrl LOCAL_HI(%a0)
- clrl LOCAL_LO(%a0)
- orl #z_mask,USER_FPSR(%a6)
- orl #neg_mask,USER_FPSR(%a6)
- orl #unfinx_mask,USER_FPSR(%a6)
- bra wr_etemp
-cu_sndr:
- movel #0xbf810000,LOCAL_EX(%a0) //force pos single zero
- movel #0x100,LOCAL_HI(%a0) //with lsb set
- clrl LOCAL_LO(%a0)
- orl #neg_mask,USER_FPSR(%a6)
- orl #unfinx_mask,USER_FPSR(%a6)
- bra wr_etemp
-
-//
-// This code checks for 16-bit overflow conditions on dyadic
-// operations which are not restorable into the floating-point
-// unit and must be completed in software. Basically, this
-// condition exists with a very large norm and a denorm. One
-// of the operands must be denormalized to enter this code.
-//
-// Flags used:
-// DY_MO_FLG contains 0 for monadic op, $ff for dyadic
-// DNRM_FLG contains $00 for neither op denormalized
-// $0f for the destination op denormalized
-// $f0 for the source op denormalized
-// $ff for both ops denormalized
-//
-// The wrap-around condition occurs for add, sub, div, and cmp
-// when
-//
-// abs(dest_exp - src_exp) >= $8000
-//
-// and for mul when
-//
-// (dest_exp + src_exp) < $0
-//
-// we must process the operation here if this case is true.
-//
-// The rts following the frcfpn routine is the exit from res_func
-// for this condition. The restore flag (RES_FLG) is left clear.
-// No frestore is done unless an exception is to be reported.
-//
-// For fadd:
-// if(sign_of(dest) != sign_of(src))
-// replace exponent of src with $3fff (keep sign)
-// use fpu to perform dest+new_src (user's rmode and X)
-// clr sticky
-// else
-// set sticky
-// call round with user's precision and mode
-// move result to fpn and wbtemp
-//
-// For fsub:
-// if(sign_of(dest) == sign_of(src))
-// replace exponent of src with $3fff (keep sign)
-// use fpu to perform dest+new_src (user's rmode and X)
-// clr sticky
-// else
-// set sticky
-// call round with user's precision and mode
-// move result to fpn and wbtemp
-//
-// For fdiv/fsgldiv:
-// if(both operands are denorm)
-// restore_to_fpu;
-// if(dest is norm)
-// force_ovf;
-// else(dest is denorm)
-// force_unf:
-//
-// For fcmp:
-// if(dest is norm)
-// N = sign_of(dest);
-// else(dest is denorm)
-// N = sign_of(src);
-//
-// For fmul:
-// if(both operands are denorm)
-// force_unf;
-// if((dest_exp + src_exp) < 0)
-// force_unf:
-// else
-// restore_to_fpu;
-//
-// local equates:
- .set addcode,0x22
- .set subcode,0x28
- .set mulcode,0x23
- .set divcode,0x20
- .set cmpcode,0x38
-ck_wrap:
- | tstb DY_MO_FLG(%a6) ;check for fsqrt
- beq fix_stk //if zero, it is fsqrt
- movew CMDREG1B(%a6),%d0
- andiw #0x3b,%d0 //strip to command bits
- cmpiw #addcode,%d0
- beq wrap_add
- cmpiw #subcode,%d0
- beq wrap_sub
- cmpiw #mulcode,%d0
- beq wrap_mul
- cmpiw #cmpcode,%d0
- beq wrap_cmp
-//
-// Inst is fdiv.
-//
-wrap_div:
- cmpb #0xff,DNRM_FLG(%a6) //if both ops denorm,
- beq fix_stk //restore to fpu
-//
-// One of the ops is denormalized. Test for wrap condition
-// and force the result.
-//
- cmpb #0x0f,DNRM_FLG(%a6) //check for dest denorm
- bnes div_srcd
-div_destd:
- bsrl ckinf_ns
- bne fix_stk
- bfextu ETEMP_EX(%a6){#1:#15},%d0 //get src exp (always pos)
- bfexts FPTEMP_EX(%a6){#1:#15},%d1 //get dest exp (always neg)
- subl %d1,%d0 //subtract dest from src
- cmpl #0x7fff,%d0
- blt fix_stk //if less, not wrap case
- clrb WBTEMP_SGN(%a6)
- movew ETEMP_EX(%a6),%d0 //find the sign of the result
- movew FPTEMP_EX(%a6),%d1
- eorw %d1,%d0
- andiw #0x8000,%d0
- beq force_unf
- st WBTEMP_SGN(%a6)
- bra force_unf
-
-ckinf_ns:
- moveb STAG(%a6),%d0 //check source tag for inf or nan
- bra ck_in_com
-ckinf_nd:
- moveb DTAG(%a6),%d0 //check destination tag for inf or nan
-ck_in_com:
- andib #0x60,%d0 //isolate tag bits
- cmpb #0x40,%d0 //is it inf?
- beq nan_or_inf //not wrap case
- cmpb #0x60,%d0 //is it nan?
- beq nan_or_inf //yes, not wrap case?
- cmpb #0x20,%d0 //is it a zero?
- beq nan_or_inf //yes
- clrl %d0
- rts //then ; it is either a zero of norm,
-// ;check wrap case
-nan_or_inf:
- moveql #-1,%d0
- rts
-
-
-
-div_srcd:
- bsrl ckinf_nd
- bne fix_stk
- bfextu FPTEMP_EX(%a6){#1:#15},%d0 //get dest exp (always pos)
- bfexts ETEMP_EX(%a6){#1:#15},%d1 //get src exp (always neg)
- subl %d1,%d0 //subtract src from dest
- cmpl #0x8000,%d0
- blt fix_stk //if less, not wrap case
- clrb WBTEMP_SGN(%a6)
- movew ETEMP_EX(%a6),%d0 //find the sign of the result
- movew FPTEMP_EX(%a6),%d1
- eorw %d1,%d0
- andiw #0x8000,%d0
- beqs force_ovf
- st WBTEMP_SGN(%a6)
-//
-// This code handles the case of the instruction resulting in
-// an overflow condition.
-//
-force_ovf:
- bclrb #E1,E_BYTE(%a6)
- orl #ovfl_inx_mask,USER_FPSR(%a6)
- clrw NMNEXC(%a6)
- leal WBTEMP(%a6),%a0 //point a0 to memory location
- movew CMDREG1B(%a6),%d0
- btstl #6,%d0 //test for forced precision
- beqs frcovf_fpcr
- btstl #2,%d0 //check for double
- bnes frcovf_dbl
- movel #0x1,%d0 //inst is forced single
- bras frcovf_rnd
-frcovf_dbl:
- movel #0x2,%d0 //inst is forced double
- bras frcovf_rnd
-frcovf_fpcr:
- bfextu FPCR_MODE(%a6){#0:#2},%d0 //inst not forced - use fpcr prec
-frcovf_rnd:
-
-// The 881/882 does not set inex2 for the following case, so the
-// line is commented out to be compatible with 881/882
-// tst.b %d0
-// beq.b frcovf_x
-// or.l #inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
-
-//frcovf_x:
- bsrl ovf_res //get correct result based on
-// ;round precision/mode. This
-// ;sets FPSR_CC correctly
-// ;returns in external format
- bfclr WBTEMP_SGN(%a6){#0:#8}
- beq frcfpn
- bsetb #sign_bit,WBTEMP_EX(%a6)
- bra frcfpn
-//
-// Inst is fadd.
-//
-wrap_add:
- cmpb #0xff,DNRM_FLG(%a6) //if both ops denorm,
- beq fix_stk //restore to fpu
-//
-// One of the ops is denormalized. Test for wrap condition
-// and complete the instruction.
-//
- cmpb #0x0f,DNRM_FLG(%a6) //check for dest denorm
- bnes add_srcd
-add_destd:
- bsrl ckinf_ns
- bne fix_stk
- bfextu ETEMP_EX(%a6){#1:#15},%d0 //get src exp (always pos)
- bfexts FPTEMP_EX(%a6){#1:#15},%d1 //get dest exp (always neg)
- subl %d1,%d0 //subtract dest from src
- cmpl #0x8000,%d0
- blt fix_stk //if less, not wrap case
- bra add_wrap
-add_srcd:
- bsrl ckinf_nd
- bne fix_stk
- bfextu FPTEMP_EX(%a6){#1:#15},%d0 //get dest exp (always pos)
- bfexts ETEMP_EX(%a6){#1:#15},%d1 //get src exp (always neg)
- subl %d1,%d0 //subtract src from dest
- cmpl #0x8000,%d0
- blt fix_stk //if less, not wrap case
-//
-// Check the signs of the operands. If they are unlike, the fpu
-// can be used to add the norm and 1.0 with the sign of the
-// denorm and it will correctly generate the result in extended
-// precision. We can then call round with no sticky and the result
-// will be correct for the user's rounding mode and precision. If
-// the signs are the same, we call round with the sticky bit set
-// and the result will be correct for the user's rounding mode and
-// precision.
-//
-add_wrap:
- movew ETEMP_EX(%a6),%d0
- movew FPTEMP_EX(%a6),%d1
- eorw %d1,%d0
- andiw #0x8000,%d0
- beq add_same
-//
-// The signs are unlike.
-//
- cmpb #0x0f,DNRM_FLG(%a6) //is dest the denorm?
- bnes add_u_srcd
- movew FPTEMP_EX(%a6),%d0
- andiw #0x8000,%d0
- orw #0x3fff,%d0 //force the exponent to +/- 1
- movew %d0,FPTEMP_EX(%a6) //in the denorm
- movel USER_FPCR(%a6),%d0
- andil #0x30,%d0
- fmovel %d0,%fpcr //set up users rmode and X
- fmovex ETEMP(%a6),%fp0
- faddx FPTEMP(%a6),%fp0
- leal WBTEMP(%a6),%a0 //point a0 to wbtemp in frame
- fmovel %fpsr,%d1
- orl %d1,USER_FPSR(%a6) //capture cc's and inex from fadd
- fmovex %fp0,WBTEMP(%a6) //write result to memory
- lsrl #4,%d0 //put rmode in lower 2 bits
- movel USER_FPCR(%a6),%d1
- andil #0xc0,%d1
- lsrl #6,%d1 //put precision in upper word
- swap %d1
- orl %d0,%d1 //set up for round call
- clrl %d0 //force sticky to zero
- bclrb #sign_bit,WBTEMP_EX(%a6)
- sne WBTEMP_SGN(%a6)
- bsrl round //round result to users rmode & prec
- bfclr WBTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
- beq frcfpnr
- bsetb #sign_bit,WBTEMP_EX(%a6)
- bra frcfpnr
-add_u_srcd:
- movew ETEMP_EX(%a6),%d0
- andiw #0x8000,%d0
- orw #0x3fff,%d0 //force the exponent to +/- 1
- movew %d0,ETEMP_EX(%a6) //in the denorm
- movel USER_FPCR(%a6),%d0
- andil #0x30,%d0
- fmovel %d0,%fpcr //set up users rmode and X
- fmovex ETEMP(%a6),%fp0
- faddx FPTEMP(%a6),%fp0
- fmovel %fpsr,%d1
- orl %d1,USER_FPSR(%a6) //capture cc's and inex from fadd
- leal WBTEMP(%a6),%a0 //point a0 to wbtemp in frame
- fmovex %fp0,WBTEMP(%a6) //write result to memory
- lsrl #4,%d0 //put rmode in lower 2 bits
- movel USER_FPCR(%a6),%d1
- andil #0xc0,%d1
- lsrl #6,%d1 //put precision in upper word
- swap %d1
- orl %d0,%d1 //set up for round call
- clrl %d0 //force sticky to zero
- bclrb #sign_bit,WBTEMP_EX(%a6)
- sne WBTEMP_SGN(%a6) //use internal format for round
- bsrl round //round result to users rmode & prec
- bfclr WBTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
- beq frcfpnr
- bsetb #sign_bit,WBTEMP_EX(%a6)
- bra frcfpnr
-//
-// Signs are alike:
-//
-add_same:
- cmpb #0x0f,DNRM_FLG(%a6) //is dest the denorm?
- bnes add_s_srcd
-add_s_destd:
- leal ETEMP(%a6),%a0
- movel USER_FPCR(%a6),%d0
- andil #0x30,%d0
- lsrl #4,%d0 //put rmode in lower 2 bits
- movel USER_FPCR(%a6),%d1
- andil #0xc0,%d1
- lsrl #6,%d1 //put precision in upper word
- swap %d1
- orl %d0,%d1 //set up for round call
- movel #0x20000000,%d0 //set sticky for round
- bclrb #sign_bit,ETEMP_EX(%a6)
- sne ETEMP_SGN(%a6)
- bsrl round //round result to users rmode & prec
- bfclr ETEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
- beqs add_s_dclr
- bsetb #sign_bit,ETEMP_EX(%a6)
-add_s_dclr:
- leal WBTEMP(%a6),%a0
- movel ETEMP(%a6),(%a0) //write result to wbtemp
- movel ETEMP_HI(%a6),4(%a0)
- movel ETEMP_LO(%a6),8(%a0)
- tstw ETEMP_EX(%a6)
- bgt add_ckovf
- orl #neg_mask,USER_FPSR(%a6)
- bra add_ckovf
-add_s_srcd:
- leal FPTEMP(%a6),%a0
- movel USER_FPCR(%a6),%d0
- andil #0x30,%d0
- lsrl #4,%d0 //put rmode in lower 2 bits
- movel USER_FPCR(%a6),%d1
- andil #0xc0,%d1
- lsrl #6,%d1 //put precision in upper word
- swap %d1
- orl %d0,%d1 //set up for round call
- movel #0x20000000,%d0 //set sticky for round
- bclrb #sign_bit,FPTEMP_EX(%a6)
- sne FPTEMP_SGN(%a6)
- bsrl round //round result to users rmode & prec
- bfclr FPTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
- beqs add_s_sclr
- bsetb #sign_bit,FPTEMP_EX(%a6)
-add_s_sclr:
- leal WBTEMP(%a6),%a0
- movel FPTEMP(%a6),(%a0) //write result to wbtemp
- movel FPTEMP_HI(%a6),4(%a0)
- movel FPTEMP_LO(%a6),8(%a0)
- tstw FPTEMP_EX(%a6)
- bgt add_ckovf
- orl #neg_mask,USER_FPSR(%a6)
-add_ckovf:
- movew WBTEMP_EX(%a6),%d0
- andiw #0x7fff,%d0
- cmpiw #0x7fff,%d0
- bne frcfpnr
-//
-// The result has overflowed to $7fff exponent. Set I, ovfl,
-// and aovfl, and clr the mantissa (incorrectly set by the
-// round routine.)
-//
- orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
- clrl 4(%a0)
- bra frcfpnr
-//
-// Inst is fsub.
-//
-wrap_sub:
- cmpb #0xff,DNRM_FLG(%a6) //if both ops denorm,
- beq fix_stk //restore to fpu
-//
-// One of the ops is denormalized. Test for wrap condition
-// and complete the instruction.
-//
- cmpb #0x0f,DNRM_FLG(%a6) //check for dest denorm
- bnes sub_srcd
-sub_destd:
- bsrl ckinf_ns
- bne fix_stk
- bfextu ETEMP_EX(%a6){#1:#15},%d0 //get src exp (always pos)
- bfexts FPTEMP_EX(%a6){#1:#15},%d1 //get dest exp (always neg)
- subl %d1,%d0 //subtract src from dest
- cmpl #0x8000,%d0
- blt fix_stk //if less, not wrap case
- bra sub_wrap
-sub_srcd:
- bsrl ckinf_nd
- bne fix_stk
- bfextu FPTEMP_EX(%a6){#1:#15},%d0 //get dest exp (always pos)
- bfexts ETEMP_EX(%a6){#1:#15},%d1 //get src exp (always neg)
- subl %d1,%d0 //subtract dest from src
- cmpl #0x8000,%d0
- blt fix_stk //if less, not wrap case
-//
-// Check the signs of the operands. If they are alike, the fpu
-// can be used to subtract from the norm 1.0 with the sign of the
-// denorm and it will correctly generate the result in extended
-// precision. We can then call round with no sticky and the result
-// will be correct for the user's rounding mode and precision. If
-// the signs are unlike, we call round with the sticky bit set
-// and the result will be correct for the user's rounding mode and
-// precision.
-//
-sub_wrap:
- movew ETEMP_EX(%a6),%d0
- movew FPTEMP_EX(%a6),%d1
- eorw %d1,%d0
- andiw #0x8000,%d0
- bne sub_diff
-//
-// The signs are alike.
-//
- cmpb #0x0f,DNRM_FLG(%a6) //is dest the denorm?
- bnes sub_u_srcd
- movew FPTEMP_EX(%a6),%d0
- andiw #0x8000,%d0
- orw #0x3fff,%d0 //force the exponent to +/- 1
- movew %d0,FPTEMP_EX(%a6) //in the denorm
- movel USER_FPCR(%a6),%d0
- andil #0x30,%d0
- fmovel %d0,%fpcr //set up users rmode and X
- fmovex FPTEMP(%a6),%fp0
- fsubx ETEMP(%a6),%fp0
- fmovel %fpsr,%d1
- orl %d1,USER_FPSR(%a6) //capture cc's and inex from fadd
- leal WBTEMP(%a6),%a0 //point a0 to wbtemp in frame
- fmovex %fp0,WBTEMP(%a6) //write result to memory
- lsrl #4,%d0 //put rmode in lower 2 bits
- movel USER_FPCR(%a6),%d1
- andil #0xc0,%d1
- lsrl #6,%d1 //put precision in upper word
- swap %d1
- orl %d0,%d1 //set up for round call
- clrl %d0 //force sticky to zero
- bclrb #sign_bit,WBTEMP_EX(%a6)
- sne WBTEMP_SGN(%a6)
- bsrl round //round result to users rmode & prec
- bfclr WBTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
- beq frcfpnr
- bsetb #sign_bit,WBTEMP_EX(%a6)
- bra frcfpnr
-sub_u_srcd:
- movew ETEMP_EX(%a6),%d0
- andiw #0x8000,%d0
- orw #0x3fff,%d0 //force the exponent to +/- 1
- movew %d0,ETEMP_EX(%a6) //in the denorm
- movel USER_FPCR(%a6),%d0
- andil #0x30,%d0
- fmovel %d0,%fpcr //set up users rmode and X
- fmovex FPTEMP(%a6),%fp0
- fsubx ETEMP(%a6),%fp0
- fmovel %fpsr,%d1
- orl %d1,USER_FPSR(%a6) //capture cc's and inex from fadd
- leal WBTEMP(%a6),%a0 //point a0 to wbtemp in frame
- fmovex %fp0,WBTEMP(%a6) //write result to memory
- lsrl #4,%d0 //put rmode in lower 2 bits
- movel USER_FPCR(%a6),%d1
- andil #0xc0,%d1
- lsrl #6,%d1 //put precision in upper word
- swap %d1
- orl %d0,%d1 //set up for round call
- clrl %d0 //force sticky to zero
- bclrb #sign_bit,WBTEMP_EX(%a6)
- sne WBTEMP_SGN(%a6)
- bsrl round //round result to users rmode & prec
- bfclr WBTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
- beq frcfpnr
- bsetb #sign_bit,WBTEMP_EX(%a6)
- bra frcfpnr
-//
-// Signs are unlike:
-//
-sub_diff:
- cmpb #0x0f,DNRM_FLG(%a6) //is dest the denorm?
- bnes sub_s_srcd
-sub_s_destd:
- leal ETEMP(%a6),%a0
- movel USER_FPCR(%a6),%d0
- andil #0x30,%d0
- lsrl #4,%d0 //put rmode in lower 2 bits
- movel USER_FPCR(%a6),%d1
- andil #0xc0,%d1
- lsrl #6,%d1 //put precision in upper word
- swap %d1
- orl %d0,%d1 //set up for round call
- movel #0x20000000,%d0 //set sticky for round
-//
-// Since the dest is the denorm, the sign is the opposite of the
-// norm sign.
-//
- eoriw #0x8000,ETEMP_EX(%a6) //flip sign on result
- tstw ETEMP_EX(%a6)
- bgts sub_s_dwr
- orl #neg_mask,USER_FPSR(%a6)
-sub_s_dwr:
- bclrb #sign_bit,ETEMP_EX(%a6)
- sne ETEMP_SGN(%a6)
- bsrl round //round result to users rmode & prec
- bfclr ETEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
- beqs sub_s_dclr
- bsetb #sign_bit,ETEMP_EX(%a6)
-sub_s_dclr:
- leal WBTEMP(%a6),%a0
- movel ETEMP(%a6),(%a0) //write result to wbtemp
- movel ETEMP_HI(%a6),4(%a0)
- movel ETEMP_LO(%a6),8(%a0)
- bra sub_ckovf
-sub_s_srcd:
- leal FPTEMP(%a6),%a0
- movel USER_FPCR(%a6),%d0
- andil #0x30,%d0
- lsrl #4,%d0 //put rmode in lower 2 bits
- movel USER_FPCR(%a6),%d1
- andil #0xc0,%d1
- lsrl #6,%d1 //put precision in upper word
- swap %d1
- orl %d0,%d1 //set up for round call
- movel #0x20000000,%d0 //set sticky for round
- bclrb #sign_bit,FPTEMP_EX(%a6)
- sne FPTEMP_SGN(%a6)
- bsrl round //round result to users rmode & prec
- bfclr FPTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
- beqs sub_s_sclr
- bsetb #sign_bit,FPTEMP_EX(%a6)
-sub_s_sclr:
- leal WBTEMP(%a6),%a0
- movel FPTEMP(%a6),(%a0) //write result to wbtemp
- movel FPTEMP_HI(%a6),4(%a0)
- movel FPTEMP_LO(%a6),8(%a0)
- tstw FPTEMP_EX(%a6)
- bgt sub_ckovf
- orl #neg_mask,USER_FPSR(%a6)
-sub_ckovf:
- movew WBTEMP_EX(%a6),%d0
- andiw #0x7fff,%d0
- cmpiw #0x7fff,%d0
- bne frcfpnr
-//
-// The result has overflowed to $7fff exponent. Set I, ovfl,
-// and aovfl, and clr the mantissa (incorrectly set by the
-// round routine.)
-//
- orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
- clrl 4(%a0)
- bra frcfpnr
-//
-// Inst is fcmp.
-//
-wrap_cmp:
- cmpb #0xff,DNRM_FLG(%a6) //if both ops denorm,
- beq fix_stk //restore to fpu
-//
-// One of the ops is denormalized. Test for wrap condition
-// and complete the instruction.
-//
- cmpb #0x0f,DNRM_FLG(%a6) //check for dest denorm
- bnes cmp_srcd
-cmp_destd:
- bsrl ckinf_ns
- bne fix_stk
- bfextu ETEMP_EX(%a6){#1:#15},%d0 //get src exp (always pos)
- bfexts FPTEMP_EX(%a6){#1:#15},%d1 //get dest exp (always neg)
- subl %d1,%d0 //subtract dest from src
- cmpl #0x8000,%d0
- blt fix_stk //if less, not wrap case
- tstw ETEMP_EX(%a6) //set N to ~sign_of(src)
- bge cmp_setn
- rts
-cmp_srcd:
- bsrl ckinf_nd
- bne fix_stk
- bfextu FPTEMP_EX(%a6){#1:#15},%d0 //get dest exp (always pos)
- bfexts ETEMP_EX(%a6){#1:#15},%d1 //get src exp (always neg)
- subl %d1,%d0 //subtract src from dest
- cmpl #0x8000,%d0
- blt fix_stk //if less, not wrap case
- tstw FPTEMP_EX(%a6) //set N to sign_of(dest)
- blt cmp_setn
- rts
-cmp_setn:
- orl #neg_mask,USER_FPSR(%a6)
- rts
-
-//
-// Inst is fmul.
-//
-wrap_mul:
- cmpb #0xff,DNRM_FLG(%a6) //if both ops denorm,
- beq force_unf //force an underflow (really!)
-//
-// One of the ops is denormalized. Test for wrap condition
-// and complete the instruction.
-//
- cmpb #0x0f,DNRM_FLG(%a6) //check for dest denorm
- bnes mul_srcd
-mul_destd:
- bsrl ckinf_ns
- bne fix_stk
- bfextu ETEMP_EX(%a6){#1:#15},%d0 //get src exp (always pos)
- bfexts FPTEMP_EX(%a6){#1:#15},%d1 //get dest exp (always neg)
- addl %d1,%d0 //subtract dest from src
- bgt fix_stk
- bra force_unf
-mul_srcd:
- bsrl ckinf_nd
- bne fix_stk
- bfextu FPTEMP_EX(%a6){#1:#15},%d0 //get dest exp (always pos)
- bfexts ETEMP_EX(%a6){#1:#15},%d1 //get src exp (always neg)
- addl %d1,%d0 //subtract src from dest
- bgt fix_stk
-
-//
-// This code handles the case of the instruction resulting in
-// an underflow condition.
-//
-force_unf:
- bclrb #E1,E_BYTE(%a6)
- orl #unfinx_mask,USER_FPSR(%a6)
- clrw NMNEXC(%a6)
- clrb WBTEMP_SGN(%a6)
- movew ETEMP_EX(%a6),%d0 //find the sign of the result
- movew FPTEMP_EX(%a6),%d1
- eorw %d1,%d0
- andiw #0x8000,%d0
- beqs frcunfcont
- st WBTEMP_SGN(%a6)
-frcunfcont:
- lea WBTEMP(%a6),%a0 //point a0 to memory location
- movew CMDREG1B(%a6),%d0
- btstl #6,%d0 //test for forced precision
- beqs frcunf_fpcr
- btstl #2,%d0 //check for double
- bnes frcunf_dbl
- movel #0x1,%d0 //inst is forced single
- bras frcunf_rnd
-frcunf_dbl:
- movel #0x2,%d0 //inst is forced double
- bras frcunf_rnd
-frcunf_fpcr:
- bfextu FPCR_MODE(%a6){#0:#2},%d0 //inst not forced - use fpcr prec
-frcunf_rnd:
- bsrl unf_sub //get correct result based on
-// ;round precision/mode. This
-// ;sets FPSR_CC correctly
- bfclr WBTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
- beqs frcfpn
- bsetb #sign_bit,WBTEMP_EX(%a6)
- bra frcfpn
-
-//
-// Write the result to the user's fpn. All results must be HUGE to be
-// written; otherwise the results would have overflowed or underflowed.
-// If the rounding precision is single or double, the ovf_res routine
-// is needed to correctly supply the max value.
-//
-frcfpnr:
- movew CMDREG1B(%a6),%d0
- btstl #6,%d0 //test for forced precision
- beqs frcfpn_fpcr
- btstl #2,%d0 //check for double
- bnes frcfpn_dbl
- movel #0x1,%d0 //inst is forced single
- bras frcfpn_rnd
-frcfpn_dbl:
- movel #0x2,%d0 //inst is forced double
- bras frcfpn_rnd
-frcfpn_fpcr:
- bfextu FPCR_MODE(%a6){#0:#2},%d0 //inst not forced - use fpcr prec
- tstb %d0
- beqs frcfpn //if extended, write what you got
-frcfpn_rnd:
- bclrb #sign_bit,WBTEMP_EX(%a6)
- sne WBTEMP_SGN(%a6)
- bsrl ovf_res //get correct result based on
-// ;round precision/mode. This
-// ;sets FPSR_CC correctly
- bfclr WBTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
- beqs frcfpn_clr
- bsetb #sign_bit,WBTEMP_EX(%a6)
-frcfpn_clr:
- orl #ovfinx_mask,USER_FPSR(%a6)
-//
-// Perform the write.
-//
-frcfpn:
- bfextu CMDREG1B(%a6){#6:#3},%d0 //extract fp destination register
- cmpib #3,%d0
- bles frc0123 //check if dest is fp0-fp3
- movel #7,%d1
- subl %d0,%d1
- clrl %d0
- bsetl %d1,%d0
- fmovemx WBTEMP(%a6),%d0
- rts
-frc0123:
- cmpib #0,%d0
- beqs frc0_dst
- cmpib #1,%d0
- beqs frc1_dst
- cmpib #2,%d0
- beqs frc2_dst
-frc3_dst:
- movel WBTEMP_EX(%a6),USER_FP3(%a6)
- movel WBTEMP_HI(%a6),USER_FP3+4(%a6)
- movel WBTEMP_LO(%a6),USER_FP3+8(%a6)
- rts
-frc2_dst:
- movel WBTEMP_EX(%a6),USER_FP2(%a6)
- movel WBTEMP_HI(%a6),USER_FP2+4(%a6)
- movel WBTEMP_LO(%a6),USER_FP2+8(%a6)
- rts
-frc1_dst:
- movel WBTEMP_EX(%a6),USER_FP1(%a6)
- movel WBTEMP_HI(%a6),USER_FP1+4(%a6)
- movel WBTEMP_LO(%a6),USER_FP1+8(%a6)
- rts
-frc0_dst:
- movel WBTEMP_EX(%a6),USER_FP0(%a6)
- movel WBTEMP_HI(%a6),USER_FP0+4(%a6)
- movel WBTEMP_LO(%a6),USER_FP0+8(%a6)
- rts
-
-//
-// Write etemp to fpn.
-// A check is made on enabled and signalled snan exceptions,
-// and the destination is not overwritten if this condition exists.
-// This code is designed to make fmoveins of unsupported data types
-// faster.
-//
-wr_etemp:
- btstb #snan_bit,FPSR_EXCEPT(%a6) //if snan is set, and
- beqs fmoveinc //enabled, force restore
- btstb #snan_bit,FPCR_ENABLE(%a6) //and don't overwrite
- beqs fmoveinc //the dest
- movel ETEMP_EX(%a6),FPTEMP_EX(%a6) //set up fptemp sign for
-// ;snan handler
- tstb ETEMP(%a6) //check for negative
- blts snan_neg
- rts
-snan_neg:
- orl #neg_bit,USER_FPSR(%a6) //snan is negative; set N
- rts
-fmoveinc:
- clrw NMNEXC(%a6)
- bclrb #E1,E_BYTE(%a6)
- moveb STAG(%a6),%d0 //check if stag is inf
- andib #0xe0,%d0
- cmpib #0x40,%d0
- bnes fminc_cnan
- orl #inf_mask,USER_FPSR(%a6) //if inf, nothing yet has set I
- tstw LOCAL_EX(%a0) //check sign
- bges fminc_con
- orl #neg_mask,USER_FPSR(%a6)
- bra fminc_con
-fminc_cnan:
- cmpib #0x60,%d0 //check if stag is NaN
- bnes fminc_czero
- orl #nan_mask,USER_FPSR(%a6) //if nan, nothing yet has set NaN
- movel ETEMP_EX(%a6),FPTEMP_EX(%a6) //set up fptemp sign for
-// ;snan handler
- tstw LOCAL_EX(%a0) //check sign
- bges fminc_con
- orl #neg_mask,USER_FPSR(%a6)
- bra fminc_con
-fminc_czero:
- cmpib #0x20,%d0 //check if zero
- bnes fminc_con
- orl #z_mask,USER_FPSR(%a6) //if zero, set Z
- tstw LOCAL_EX(%a0) //check sign
- bges fminc_con
- orl #neg_mask,USER_FPSR(%a6)
-fminc_con:
- bfextu CMDREG1B(%a6){#6:#3},%d0 //extract fp destination register
- cmpib #3,%d0
- bles fp0123 //check if dest is fp0-fp3
- movel #7,%d1
- subl %d0,%d1
- clrl %d0
- bsetl %d1,%d0
- fmovemx ETEMP(%a6),%d0
- rts
-
-fp0123:
- cmpib #0,%d0
- beqs fp0_dst
- cmpib #1,%d0
- beqs fp1_dst
- cmpib #2,%d0
- beqs fp2_dst
-fp3_dst:
- movel ETEMP_EX(%a6),USER_FP3(%a6)
- movel ETEMP_HI(%a6),USER_FP3+4(%a6)
- movel ETEMP_LO(%a6),USER_FP3+8(%a6)
- rts
-fp2_dst:
- movel ETEMP_EX(%a6),USER_FP2(%a6)
- movel ETEMP_HI(%a6),USER_FP2+4(%a6)
- movel ETEMP_LO(%a6),USER_FP2+8(%a6)
- rts
-fp1_dst:
- movel ETEMP_EX(%a6),USER_FP1(%a6)
- movel ETEMP_HI(%a6),USER_FP1+4(%a6)
- movel ETEMP_LO(%a6),USER_FP1+8(%a6)
- rts
-fp0_dst:
- movel ETEMP_EX(%a6),USER_FP0(%a6)
- movel ETEMP_HI(%a6),USER_FP0+4(%a6)
- movel ETEMP_LO(%a6),USER_FP0+8(%a6)
- rts
-
-opclass3:
- st CU_ONLY(%a6)
- movew CMDREG1B(%a6),%d0 //check if packed moveout
- andiw #0x0c00,%d0 //isolate last 2 bits of size field
- cmpiw #0x0c00,%d0 //if size is 011 or 111, it is packed
- beq pack_out //else it is norm or denorm
- bra mv_out
-
-
-//
-// MOVE OUT
-//
-
-mv_tbl:
- .long li
- .long sgp
- .long xp
- .long mvout_end //should never be taken
- .long wi
- .long dp
- .long bi
- .long mvout_end //should never be taken
-mv_out:
- bfextu CMDREG1B(%a6){#3:#3},%d1 //put source specifier in d1
- leal mv_tbl,%a0
- movel %a0@(%d1:l:4),%a0
- jmp (%a0)
-
-//
-// This exit is for move-out to memory. The aunfl bit is
-// set if the result is inex and unfl is signalled.
-//
-mvout_end:
- btstb #inex2_bit,FPSR_EXCEPT(%a6)
- beqs no_aufl
- btstb #unfl_bit,FPSR_EXCEPT(%a6)
- beqs no_aufl
- bsetb #aunfl_bit,FPSR_AEXCEPT(%a6)
-no_aufl:
- clrw NMNEXC(%a6)
- bclrb #E1,E_BYTE(%a6)
- fmovel #0,%FPSR //clear any cc bits from res_func
-//
-// Return ETEMP to extended format from internal extended format so
-// that gen_except will have a correctly signed value for ovfl/unfl
-// handlers.
-//
- bfclr ETEMP_SGN(%a6){#0:#8}
- beqs mvout_con
- bsetb #sign_bit,ETEMP_EX(%a6)
-mvout_con:
- rts
-//
-// This exit is for move-out to int register. The aunfl bit is
-// not set in any case for this move.
-//
-mvouti_end:
- clrw NMNEXC(%a6)
- bclrb #E1,E_BYTE(%a6)
- fmovel #0,%FPSR //clear any cc bits from res_func
-//
-// Return ETEMP to extended format from internal extended format so
-// that gen_except will have a correctly signed value for ovfl/unfl
-// handlers.
-//
- bfclr ETEMP_SGN(%a6){#0:#8}
- beqs mvouti_con
- bsetb #sign_bit,ETEMP_EX(%a6)
-mvouti_con:
- rts
-//
-// li is used to handle a long integer source specifier
-//
-
-li:
- moveql #4,%d0 //set byte count
-
- btstb #7,STAG(%a6) //check for extended denorm
- bne int_dnrm //if so, branch
-
- fmovemx ETEMP(%a6),%fp0-%fp0
- fcmpd #0x41dfffffffc00000,%fp0
-// 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
- fbge lo_plrg
- fcmpd #0xc1e0000000000000,%fp0
-// c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
- fble lo_nlrg
-//
-// at this point, the answer is between the largest pos and neg values
-//
- movel USER_FPCR(%a6),%d1 //use user's rounding mode
- andil #0x30,%d1
- fmovel %d1,%fpcr
- fmovel %fp0,L_SCR1(%a6) //let the 040 perform conversion
- fmovel %fpsr,%d1
- orl %d1,USER_FPSR(%a6) //capture inex2/ainex if set
- bra int_wrt
-
-
-lo_plrg:
- movel #0x7fffffff,L_SCR1(%a6) //answer is largest positive int
- fbeq int_wrt //exact answer
- fcmpd #0x41dfffffffe00000,%fp0
-// 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
- fbge int_operr //set operr
- bra int_inx //set inexact
-
-lo_nlrg:
- movel #0x80000000,L_SCR1(%a6)
- fbeq int_wrt //exact answer
- fcmpd #0xc1e0000000100000,%fp0
-// c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
- fblt int_operr //set operr
- bra int_inx //set inexact
-
-//
-// wi is used to handle a word integer source specifier
-//
-
-wi:
- moveql #2,%d0 //set byte count
-
- btstb #7,STAG(%a6) //check for extended denorm
- bne int_dnrm //branch if so
-
- fmovemx ETEMP(%a6),%fp0-%fp0
- fcmps #0x46fffe00,%fp0
-// 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
- fbge wo_plrg
- fcmps #0xc7000000,%fp0
-// c7000000 in sgl prec = c00e00008000000000000000 in ext prec
- fble wo_nlrg
-
-//
-// at this point, the answer is between the largest pos and neg values
-//
- movel USER_FPCR(%a6),%d1 //use user's rounding mode
- andil #0x30,%d1
- fmovel %d1,%fpcr
- fmovew %fp0,L_SCR1(%a6) //let the 040 perform conversion
- fmovel %fpsr,%d1
- orl %d1,USER_FPSR(%a6) //capture inex2/ainex if set
- bra int_wrt
-
-wo_plrg:
- movew #0x7fff,L_SCR1(%a6) //answer is largest positive int
- fbeq int_wrt //exact answer
- fcmps #0x46ffff00,%fp0
-// 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
- fbge int_operr //set operr
- bra int_inx //set inexact
-
-wo_nlrg:
- movew #0x8000,L_SCR1(%a6)
- fbeq int_wrt //exact answer
- fcmps #0xc7000080,%fp0
-// c7000080 in sgl prec = c00e00008000800000000000 in ext prec
- fblt int_operr //set operr
- bra int_inx //set inexact
-
-//
-// bi is used to handle a byte integer source specifier
-//
-
-bi:
- moveql #1,%d0 //set byte count
-
- btstb #7,STAG(%a6) //check for extended denorm
- bne int_dnrm //branch if so
-
- fmovemx ETEMP(%a6),%fp0-%fp0
- fcmps #0x42fe0000,%fp0
-// 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
- fbge by_plrg
- fcmps #0xc3000000,%fp0
-// c3000000 in sgl prec = c00600008000000000000000 in ext prec
- fble by_nlrg
-
-//
-// at this point, the answer is between the largest pos and neg values
-//
- movel USER_FPCR(%a6),%d1 //use user's rounding mode
- andil #0x30,%d1
- fmovel %d1,%fpcr
- fmoveb %fp0,L_SCR1(%a6) //let the 040 perform conversion
- fmovel %fpsr,%d1
- orl %d1,USER_FPSR(%a6) //capture inex2/ainex if set
- bra int_wrt
-
-by_plrg:
- moveb #0x7f,L_SCR1(%a6) //answer is largest positive int
- fbeq int_wrt //exact answer
- fcmps #0x42ff0000,%fp0
-// 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
- fbge int_operr //set operr
- bra int_inx //set inexact
-
-by_nlrg:
- moveb #0x80,L_SCR1(%a6)
- fbeq int_wrt //exact answer
- fcmps #0xc3008000,%fp0
-// c3008000 in sgl prec = c00600008080000000000000 in ext prec
- fblt int_operr //set operr
- bra int_inx //set inexact
-
-//
-// Common integer routines
-//
-// int_drnrm---account for possible nonzero result for round up with positive
-// operand and round down for negative answer. In the first case (result = 1)
-// byte-width (store in d0) of result must be honored. In the second case,
-// -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).
-
-int_dnrm:
- movel #0,L_SCR1(%a6) // initialize result to 0
- bfextu FPCR_MODE(%a6){#2:#2},%d1 // d1 is the rounding mode
- cmpb #2,%d1
- bmis int_inx // if RN or RZ, done
- bnes int_rp // if RP, continue below
- tstw ETEMP(%a6) // RM: store -1 in L_SCR1 if src is negative
- bpls int_inx // otherwise result is 0
- movel #-1,L_SCR1(%a6)
- bras int_inx
-int_rp:
- tstw ETEMP(%a6) // RP: store +1 of proper width in L_SCR1 if
-// ; source is greater than 0
- bmis int_inx // otherwise, result is 0
- lea L_SCR1(%a6),%a1 // a1 is address of L_SCR1
- addal %d0,%a1 // offset by destination width -1
- subal #1,%a1
- bsetb #0,(%a1) // set low bit at a1 address
-int_inx:
- oril #inx2a_mask,USER_FPSR(%a6)
- bras int_wrt
-int_operr:
- fmovemx %fp0-%fp0,FPTEMP(%a6) //FPTEMP must contain the extended
-// ;precision source that needs to be
-// ;converted to integer this is required
-// ;if the operr exception is enabled.
-// ;set operr/aiop (no inex2 on int ovfl)
-
- oril #opaop_mask,USER_FPSR(%a6)
-// ;fall through to perform int_wrt
-int_wrt:
- movel EXC_EA(%a6),%a1 //load destination address
- tstl %a1 //check to see if it is a dest register
- beqs wrt_dn //write data register
- lea L_SCR1(%a6),%a0 //point to supervisor source address
- bsrl mem_write
- bra mvouti_end
-
-wrt_dn:
- movel %d0,-(%sp) //d0 currently contains the size to write
- bsrl get_fline //get_fline returns Dn in d0
- andiw #0x7,%d0 //isolate register
- movel (%sp)+,%d1 //get size
- cmpil #4,%d1 //most frequent case
- beqs sz_long
- cmpil #2,%d1
- bnes sz_con
- orl #8,%d0 //add 'word' size to register#
- bras sz_con
-sz_long:
- orl #0x10,%d0 //add 'long' size to register#
-sz_con:
- movel %d0,%d1 //reg_dest expects size:reg in d1
- bsrl reg_dest //load proper data register
- bra mvouti_end
-xp:
- lea ETEMP(%a6),%a0
- bclrb #sign_bit,LOCAL_EX(%a0)
- sne LOCAL_SGN(%a0)
- btstb #7,STAG(%a6) //check for extended denorm
- bne xdnrm
- clrl %d0
- bras do_fp //do normal case
-sgp:
- lea ETEMP(%a6),%a0
- bclrb #sign_bit,LOCAL_EX(%a0)
- sne LOCAL_SGN(%a0)
- btstb #7,STAG(%a6) //check for extended denorm
- bne sp_catas //branch if so
- movew LOCAL_EX(%a0),%d0
- lea sp_bnds,%a1
- cmpw (%a1),%d0
- blt sp_under
- cmpw 2(%a1),%d0
- bgt sp_over
- movel #1,%d0 //set destination format to single
- bras do_fp //do normal case
-dp:
- lea ETEMP(%a6),%a0
- bclrb #sign_bit,LOCAL_EX(%a0)
- sne LOCAL_SGN(%a0)
-
- btstb #7,STAG(%a6) //check for extended denorm
- bne dp_catas //branch if so
-
- movew LOCAL_EX(%a0),%d0
- lea dp_bnds,%a1
-
- cmpw (%a1),%d0
- blt dp_under
- cmpw 2(%a1),%d0
- bgt dp_over
-
- movel #2,%d0 //set destination format to double
-// ;fall through to do_fp
-//
-do_fp:
- bfextu FPCR_MODE(%a6){#2:#2},%d1 //rnd mode in d1
- swap %d0 //rnd prec in upper word
- addl %d0,%d1 //d1 has PREC/MODE info
-
- clrl %d0 //clear g,r,s
-
- bsrl round //round
-
- movel %a0,%a1
- movel EXC_EA(%a6),%a0
-
- bfextu CMDREG1B(%a6){#3:#3},%d1 //extract destination format
-// ;at this point only the dest
-// ;formats sgl, dbl, ext are
-// ;possible
- cmpb #2,%d1
- bgts ddbl //double=5, extended=2, single=1
- bnes dsgl
-// ;fall through to dext
-dext:
- bsrl dest_ext
- bra mvout_end
-dsgl:
- bsrl dest_sgl
- bra mvout_end
-ddbl:
- bsrl dest_dbl
- bra mvout_end
-
-//
-// Handle possible denorm or catastrophic underflow cases here
-//
-xdnrm:
- bsr set_xop //initialize WBTEMP
- bsetb #wbtemp15_bit,WB_BYTE(%a6) //set wbtemp15
-
- movel %a0,%a1
- movel EXC_EA(%a6),%a0 //a0 has the destination pointer
- bsrl dest_ext //store to memory
- bsetb #unfl_bit,FPSR_EXCEPT(%a6)
- bra mvout_end
-
-sp_under:
- bsetb #etemp15_bit,STAG(%a6)
-
- cmpw 4(%a1),%d0
- blts sp_catas //catastrophic underflow case
-
- movel #1,%d0 //load in round precision
- movel #sgl_thresh,%d1 //load in single denorm threshold
- bsrl dpspdnrm //expects d1 to have the proper
-// ;denorm threshold
- bsrl dest_sgl //stores value to destination
- bsetb #unfl_bit,FPSR_EXCEPT(%a6)
- bra mvout_end //exit
-
-dp_under:
- bsetb #etemp15_bit,STAG(%a6)
-
- cmpw 4(%a1),%d0
- blts dp_catas //catastrophic underflow case
-
- movel #dbl_thresh,%d1 //load in double precision threshold
- movel #2,%d0
- bsrl dpspdnrm //expects d1 to have proper
-// ;denorm threshold
-// ;expects d0 to have round precision
- bsrl dest_dbl //store value to destination
- bsetb #unfl_bit,FPSR_EXCEPT(%a6)
- bra mvout_end //exit
-
-//
-// Handle catastrophic underflow cases here
-//
-sp_catas:
-// Temp fix for z bit set in unf_sub
- movel USER_FPSR(%a6),-(%a7)
-
- movel #1,%d0 //set round precision to sgl
-
- bsrl unf_sub //a0 points to result
-
- movel (%a7)+,USER_FPSR(%a6)
-
- movel #1,%d0
- subw %d0,LOCAL_EX(%a0) //account for difference between
-// ;denorm/norm bias
-
- movel %a0,%a1 //a1 has the operand input
- movel EXC_EA(%a6),%a0 //a0 has the destination pointer
-
- bsrl dest_sgl //store the result
- oril #unfinx_mask,USER_FPSR(%a6)
- bra mvout_end
-
-dp_catas:
-// Temp fix for z bit set in unf_sub
- movel USER_FPSR(%a6),-(%a7)
-
- movel #2,%d0 //set round precision to dbl
- bsrl unf_sub //a0 points to result
-
- movel (%a7)+,USER_FPSR(%a6)
-
- movel #1,%d0
- subw %d0,LOCAL_EX(%a0) //account for difference between
-// ;denorm/norm bias
-
- movel %a0,%a1 //a1 has the operand input
- movel EXC_EA(%a6),%a0 //a0 has the destination pointer
-
- bsrl dest_dbl //store the result
- oril #unfinx_mask,USER_FPSR(%a6)
- bra mvout_end
-
-//
-// Handle catastrophic overflow cases here
-//
-sp_over:
-// Temp fix for z bit set in unf_sub
- movel USER_FPSR(%a6),-(%a7)
-
- movel #1,%d0
- leal FP_SCR1(%a6),%a0 //use FP_SCR1 for creating result
- movel ETEMP_EX(%a6),(%a0)
- movel ETEMP_HI(%a6),4(%a0)
- movel ETEMP_LO(%a6),8(%a0)
- bsrl ovf_res
-
- movel (%a7)+,USER_FPSR(%a6)
-
- movel %a0,%a1
- movel EXC_EA(%a6),%a0
- bsrl dest_sgl
- orl #ovfinx_mask,USER_FPSR(%a6)
- bra mvout_end
-
-dp_over:
-// Temp fix for z bit set in ovf_res
- movel USER_FPSR(%a6),-(%a7)
-
- movel #2,%d0
- leal FP_SCR1(%a6),%a0 //use FP_SCR1 for creating result
- movel ETEMP_EX(%a6),(%a0)
- movel ETEMP_HI(%a6),4(%a0)
- movel ETEMP_LO(%a6),8(%a0)
- bsrl ovf_res
-
- movel (%a7)+,USER_FPSR(%a6)
-
- movel %a0,%a1
- movel EXC_EA(%a6),%a0
- bsrl dest_dbl
- orl #ovfinx_mask,USER_FPSR(%a6)
- bra mvout_end
-
-//
-// DPSPDNRM
-//
-// This subroutine takes an extended normalized number and denormalizes
-// it to the given round precision. This subroutine also decrements
-// the input operand's exponent by 1 to account for the fact that
-// dest_sgl or dest_dbl expects a normalized number's bias.
-//
-// Input: a0 points to a normalized number in internal extended format
-// d0 is the round precision (=1 for sgl; =2 for dbl)
-// d1 is the the single precision or double precision
-// denorm threshold
-//
-// Output: (In the format for dest_sgl or dest_dbl)
-// a0 points to the destination
-// a1 points to the operand
-//
-// Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
-//
-dpspdnrm:
- movel %d0,-(%a7) //save round precision
- clrl %d0 //clear initial g,r,s
- bsrl dnrm_lp //careful with d0, it's needed by round
-
- bfextu FPCR_MODE(%a6){#2:#2},%d1 //get rounding mode
- swap %d1
- movew 2(%a7),%d1 //set rounding precision
- swap %d1 //at this point d1 has PREC/MODE info
- bsrl round //round result, sets the inex bit in
-// ;USER_FPSR if needed
-
- movew #1,%d0
- subw %d0,LOCAL_EX(%a0) //account for difference in denorm
-// ;vs norm bias
-
- movel %a0,%a1 //a1 has the operand input
- movel EXC_EA(%a6),%a0 //a0 has the destination pointer
- addw #4,%a7 //pop stack
- rts
-//
-// SET_XOP initialized WBTEMP with the value pointed to by a0
-// input: a0 points to input operand in the internal extended format
-//
-set_xop:
- movel LOCAL_EX(%a0),WBTEMP_EX(%a6)
- movel LOCAL_HI(%a0),WBTEMP_HI(%a6)
- movel LOCAL_LO(%a0),WBTEMP_LO(%a6)
- bfclr WBTEMP_SGN(%a6){#0:#8}
- beqs sxop
- bsetb #sign_bit,WBTEMP_EX(%a6)
-sxop:
- bfclr STAG(%a6){#5:#4} //clear wbtm66,wbtm1,wbtm0,sbit
- rts
-//
-// P_MOVE
-//
-p_movet:
- .long p_move
- .long p_movez
- .long p_movei
- .long p_moven
- .long p_move
-p_regd:
- .long p_dyd0
- .long p_dyd1
- .long p_dyd2
- .long p_dyd3
- .long p_dyd4
- .long p_dyd5
- .long p_dyd6
- .long p_dyd7
-
-pack_out:
- leal p_movet,%a0 //load jmp table address
- movew STAG(%a6),%d0 //get source tag
- bfextu %d0{#16:#3},%d0 //isolate source bits
- movel (%a0,%d0.w*4),%a0 //load a0 with routine label for tag
- jmp (%a0) //go to the routine
-
-p_write:
- movel #0x0c,%d0 //get byte count
- movel EXC_EA(%a6),%a1 //get the destination address
- bsr mem_write //write the user's destination
- moveb #0,CU_SAVEPC(%a6) //set the cu save pc to all 0's
-
-//
-// Also note that the dtag must be set to norm here - this is because
-// the 040 uses the dtag to execute the correct microcode.
-//
- bfclr DTAG(%a6){#0:#3} //set dtag to norm
-
- rts
-
-// Notes on handling of special case (zero, inf, and nan) inputs:
-// 1. Operr is not signalled if the k-factor is greater than 18.
-// 2. Per the manual, status bits are not set.
-//
-
-p_move:
- movew CMDREG1B(%a6),%d0
- btstl #kfact_bit,%d0 //test for dynamic k-factor
- beqs statick //if clear, k-factor is static
-dynamick:
- bfextu %d0{#25:#3},%d0 //isolate register for dynamic k-factor
- lea p_regd,%a0
- movel %a0@(%d0:l:4),%a0
- jmp (%a0)
-statick:
- andiw #0x007f,%d0 //get k-factor
- bfexts %d0{#25:#7},%d0 //sign extend d0 for bindec
- leal ETEMP(%a6),%a0 //a0 will point to the packed decimal
- bsrl bindec //perform the convert; data at a6
- leal FP_SCR1(%a6),%a0 //load a0 with result address
- bral p_write
-p_movez:
- leal ETEMP(%a6),%a0 //a0 will point to the packed decimal
- clrw 2(%a0) //clear lower word of exp
- clrl 4(%a0) //load second lword of ZERO
- clrl 8(%a0) //load third lword of ZERO
- bra p_write //go write results
-p_movei:
- fmovel #0,%FPSR //clear aiop
- leal ETEMP(%a6),%a0 //a0 will point to the packed decimal
- clrw 2(%a0) //clear lower word of exp
- bra p_write //go write the result
-p_moven:
- leal ETEMP(%a6),%a0 //a0 will point to the packed decimal
- clrw 2(%a0) //clear lower word of exp
- bra p_write //go write the result
-
-//
-// Routines to read the dynamic k-factor from Dn.
-//
-p_dyd0:
- movel USER_D0(%a6),%d0
- bras statick
-p_dyd1:
- movel USER_D1(%a6),%d0
- bras statick
-p_dyd2:
- movel %d2,%d0
- bras statick
-p_dyd3:
- movel %d3,%d0
- bras statick
-p_dyd4:
- movel %d4,%d0
- bras statick
-p_dyd5:
- movel %d5,%d0
- bras statick
-p_dyd6:
- movel %d6,%d0
- bra statick
-p_dyd7:
- movel %d7,%d0
- bra statick
-
- |end