Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/arch/m68k/fpsp040/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 51 kB image not shown  

Quelle  res_func.S   Sprache: Sparc

 
|
| 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
|
|       For details on the license for this file, please see the
|       file, README, in this same directory.

RES_FUNC:    |idnt    2,1 | Motorola 040 Floating Point Software Package

 |section 8

#include "fpsp.h"

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 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

Messung V0.5
C=100 H=100 G=100

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.