* $NetBSD: res_func.sa,v 1.5 2001/09/16 16:34:32 wiz Exp $
* MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
* M68000 Hi-Performance Microprocessor Division
* M68040 Software Package
*
* M68040 Software Package Copyright (c) 1993, 1994 Motorola Inc.
* All rights reserved.
*
* THE SOFTWARE is provided on an "AS IS" basis and without warranty.
* To the maximum extent permitted by applicable law,
* MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
* PARTICULAR PURPOSE and any warranty against infringement with
* regard to the SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF)
* and any accompanying written materials.
*
* To the maximum extent permitted by applicable law,
* IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
* (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS
* PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR
* OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE
* SOFTWARE. Motorola assumes no responsibility for the maintenance
* and support of the SOFTWARE.
*
* You are hereby granted a copyright license to use, modify, and
* distribute the SOFTWARE so long as this entire notice is retained
* without alteration in any modified and/or redistributed versions,
* and that such modified versions are clearly identified as such.
* No licenses are granted by implication, estoppel or otherwise
* under any patents or trademarks of Motorola, Inc.
*
* 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.
*
RES_FUNC IDNT 2,1 Motorola 040 Floating Point Software Package
section 8
include fpsp.h
sp_bnds: dc.w $3f81,$407e
dc.w $3f6a,$0000
dp_bnds: dc.w $3c01,$43fe
dc.w $3bcd,$0000
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
xdef res_func
xdef p_move
res_func:
clr.b DNRM_FLG(a6)
clr.b RES_FLG(a6)
clr.b CU_ONLY(a6)
tst.b DY_MO_FLG(a6)
beq.b monadic
dyadic:
btst.b #7,DTAG(a6) ;if dop = norm=000, zero=001,
* ;inf=010 or nan=011
beq.b monadic ;then branch
* ;else denorm
* HANDLE DESTINATION DENORM HERE
* ;set dtag to norm
* ;write the tag & fpte15 to the fstack
lea.l FPTEMP(a6),a0
bclr.b #sign_bit,LOCAL_EX(a0)
sne LOCAL_SGN(a0)
bsr nrm_set ;normalize number (exp will go negative)
bclr.b #sign_bit,LOCAL_EX(a0) ;get rid of false sign
bfclr LOCAL_SGN(a0){0:8} ;change back to IEEE ext format
beq.b dpos
bset.b #sign_bit,LOCAL_EX(a0)
dpos:
bfclr DTAG(a6){0:4} ;set tag to normalized, FPTE15 = 0
bset.b #4,DTAG(a6) ;set FPTE15
or.b #$0f,DNRM_FLG(a6)
monadic:
lea.l ETEMP(a6),a0
btst.b #direction_bit,CMDREG1B(a6) ;check direction
bne.w opclass3 ;it is a mv out
*
* At this point, only oplcass 0 and 2 possible
*
btst.b #7,STAG(a6) ;if sop = norm=000, zero=001,
* ;inf=010 or nan=011
bne.w mon_dnrm ;else denorm
tst.b DY_MO_FLG(a6) ;all cases of dyadic instructions would
bne.w 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)
*
move.w CMDREG1B(a6),d0 ;get command register
andi.l #$7f,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)
*
btst.l #0,d0
bne.w 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
move.w CMDREG1B(a6),d0
andi.b #$3b,d0 ;isolate bits to select inst
tst.b d0
beq.l cu_nmove ;if zero, it is an fmove
cmpi.b #$18,d0
beq.l cu_nabs ;if $18, it is fabs
cmpi.b #$1a,d0
beq.l 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:
move.w LOCAL_EX(a0),d0
bclr.l #15,d0
sne LOCAL_SGN(a0)
beq.b cu_ntpo
or.l #neg_mask,USER_FPSR(a6) ;set N
cu_ntpo:
cmpi.w #$7fff,d0 ;test for inf/nan
bne.b cu_ntcz
tst.l LOCAL_HI(a0)
bne.b cu_ntn
tst.l LOCAL_LO(a0)
bne.b cu_ntn
or.l #inf_mask,USER_FPSR(a6)
rts
cu_ntn:
or.l #nan_mask,USER_FPSR(a6)
move.l ETEMP_EX(a6),FPTEMP_EX(a6) ;set up fptemp sign for
* ;snan handler
rts
cu_ntcz:
tst.l LOCAL_HI(a0)
bne.l cu_ntsx
tst.l LOCAL_LO(a0)
bne.l cu_ntsx
or.l #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:
move.b STAG(a6),d0
btst.l #5,d0 ;test for NaN or zero
bne wr_etemp ;if either, simply write it
bclr.b #7,LOCAL_EX(a0) ;do abs
bra.b 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:
move.b STAG(a6),d0
btst.l #5,d0 ;test for NaN or zero
bne wr_etemp ;if either, simply write it
bchg.b #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:
move.b STAG(a6),d0
andi.b #$e0,d0 ;isolate stag bits
bne wr_etemp ;if not norm, simply write it
btst.b #2,CMDREG1B+1(a6) ;check for rd
bne cu_nmrd
btst.b #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
tst.b d0 ;check for extended
beq cu_wrexn ;if so, just write result
cmpi.b #1,d0 ;check for single
beq cu_nmrs ;fall through to double
*
* The move is fdmove or round precision is double.
*
cu_nmrd:
move.l #2,d0 ;set up the size for denorm
move.w LOCAL_EX(a0),d1 ;compare exponent to double threshold
and.w #$7fff,d1
cmp.w #$3c01,d1
bls cu_nunfl
bfextu FPCR_MODE(a6){2:2},d1 ;get rmode
or.l #$00020000,d1 ;or in rprec (double)
clr.l d0 ;clear g,r,s for round
bclr.b #sign_bit,LOCAL_EX(a0) ;convert to internal format
sne LOCAL_SGN(a0)
bsr.l round
bfclr LOCAL_SGN(a0){0:8}
beq.b cu_nmrdc
bset.b #sign_bit,LOCAL_EX(a0)
cu_nmrdc:
move.w LOCAL_EX(a0),d1 ;check for overflow
and.w #$7fff,d1
cmp.w #$43ff,d1
bge cu_novfl ;take care of overflow case
bra.w cu_wrexn
*
* The move is fsmove or round precision is single.
*
cu_nmrs:
move.l #1,d0
move.w LOCAL_EX(a0),d1
and.w #$7fff,d1
cmp.w #$3f81,d1
bls cu_nunfl
bfextu FPCR_MODE(a6){2:2},d1
or.l #$00010000,d1
clr.l d0
bclr.b #sign_bit,LOCAL_EX(a0)
sne LOCAL_SGN(a0)
bsr.l round
bfclr LOCAL_SGN(a0){0:8}
beq.b cu_nmrsc
bset.b #sign_bit,LOCAL_EX(a0)
cu_nmrsc:
move.w LOCAL_EX(a0),d1
and.w #$7FFF,d1
cmp.w #$407f,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:
bclr.b #sign_bit,LOCAL_EX(a0)
sne LOCAL_SGN(a0)
bsr denorm
bfclr LOCAL_SGN(a0){0:8} ;change back to IEEE ext format
beq.b cu_nucont
bset.b #sign_bit,LOCAL_EX(a0)
cu_nucont:
bfextu FPCR_MODE(a6){2:2},d1
btst.b #2,CMDREG1B+1(a6) ;check for rd
bne inst_d
btst.b #6,CMDREG1B+1(a6) ;check for rs
bne inst_s
swap d1
move.b FPCR_MODE(a6),d1
lsr.b #6,d1
swap d1
bra inst_sd
inst_d:
or.l #$00020000,d1
bra inst_sd
inst_s:
or.l #$00010000,d1
inst_sd:
bclr.b #sign_bit,LOCAL_EX(a0)
sne LOCAL_SGN(a0)
bsr.l round
bfclr LOCAL_SGN(a0){0:8}
beq.b cu_nuflp
bset.b #sign_bit,LOCAL_EX(a0)
cu_nuflp:
btst.b #inex2_bit,FPSR_EXCEPT(a6)
beq.b cu_nuninx
or.l #aunfl_mask,USER_FPSR(a6) ;if the round was inex, set AUNFL
cu_nuninx:
tst.l LOCAL_HI(a0) ;test for zero
bne.b cu_nunzro
tst.l LOCAL_LO(a0)
bne.b 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.
*
move.l USER_FPCR(a6),d0
andi.l #$30,d0 ;isolate rmode
cmpi.l #$20,d0
blt.b cu_nzro
bne.b cu_nrp
cu_nrm:
tst.w LOCAL_EX(a0) ;if positive, set lsb
bge.b cu_nzro
btst.b #7,FPCR_MODE(a6) ;check for double
beq.b cu_nincs
bra.b cu_nincd
cu_nrp:
tst.w LOCAL_EX(a0) ;if positive, set lsb
blt.b cu_nzro
btst.b #7,FPCR_MODE(a6) ;check for double
beq.b cu_nincs
cu_nincd:
or.l #$800,LOCAL_LO(a0) ;inc for double
bra cu_nunzro
cu_nincs:
or.l #$100,LOCAL_HI(a0) ;inc for single
bra cu_nunzro
cu_nzro:
or.l #z_mask,USER_FPSR(a6)
move.b STAG(a6),d0
andi.b #$e0,d0
cmpi.b #$40,d0 ;check if input was tagged zero
beq.b cu_numv
cu_nunzro:
or.l #unfl_mask,USER_FPSR(a6) ;set unfl
cu_numv:
move.l (a0),ETEMP(a6)
move.l 4(a0),ETEMP_HI(a6)
move.l 8(a0),ETEMP_LO(a6)
*
* Write the result to memory, setting the fpsr cc bits. NaN and Inf
* bypass cu_wrexn.
*
cu_wrexn:
tst.w LOCAL_EX(a0) ;test for zero
beq.b cu_wrzero
cmp.w #$8000,LOCAL_EX(a0) ;test for zero
bne.b cu_wreon
cu_wrzero:
or.l #z_mask,USER_FPSR(a6) ;set Z bit
cu_wreon:
tst.w LOCAL_EX(a0)
bpl wr_etemp
or.l #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.
*
tst.b DY_MO_FLG(a6) ;all cases of dyadic instructions would
bne.b 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)
*
move.w CMDREG1B(a6),d0 ;get command register
andi.l #$7f,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)
*
btst.l #0,d0
bne.b 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:
bclr.b #sign_bit,LOCAL_EX(a0)
sne LOCAL_SGN(a0)
bsr nrm_set ;normalize number (exponent will go
* ; negative)
bclr.b #sign_bit,LOCAL_EX(a0) ;get rid of false sign
bfclr LOCAL_SGN(a0){0:8} ;change back to IEEE ext format
beq.b spos
bset.b #sign_bit,LOCAL_EX(a0)
spos:
bfclr STAG(a6){0:4} ;set tag to normalized, FPTE15 = 0
bset.b #4,STAG(a6) ;set ETE15
or.b #$f0,DNRM_FLG(a6)
normal:
tst.b 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:
move.b #$fe,CU_SAVEPC(a6)
bclr.b #E1,E_BYTE(a6)
clr.w NMNEXC(a6)
st.b RES_FLG(a6) ;indicate that a restore is needed
rts
*
* cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
* ftst) completly in software without an frestore to the 040.
*
cu_dnrm:
st.b CU_ONLY(a6)
move.w CMDREG1B(a6),d0
andi.b #$3b,d0 ;isolate bits to select inst
tst.b d0
beq.l cu_dmove ;if zero, it is an fmove
cmpi.b #$18,d0
beq.l cu_dabs ;if $18, it is fabs
cmpi.b #$1a,d0
beq.l 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:
move.w LOCAL_EX(a0),d0
bclr.l #15,d0
sne LOCAL_SGN(a0)
beq.b cu_dtpo
or.l #neg_mask,USER_FPSR(a6) ;set N
cu_dtpo:
cmpi.w #$7fff,d0 ;test for inf/nan
bne.b cu_dtcz
tst.l LOCAL_HI(a0)
bne.b cu_dtn
tst.l LOCAL_LO(a0)
bne.b cu_dtn
or.l #inf_mask,USER_FPSR(a6)
rts
cu_dtn:
or.l #nan_mask,USER_FPSR(a6)
move.l ETEMP_EX(a6),FPTEMP_EX(a6) ;set up fptemp sign for
* ;snan handler
rts
cu_dtcz:
tst.l LOCAL_HI(a0)
bne.l cu_dtsx
tst.l LOCAL_LO(a0)
bne.l cu_dtsx
or.l #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:
bclr.b #7,LOCAL_EX(a0) ;do abs
bra.b 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:
bchg.b #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:
btst.b #2,CMDREG1B+1(a6) ;check for rd
bne cu_dmrd
btst.b #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
tst.b d0 ;check for extended
beq cu_wrexd ;if so, just write result
cmpi.b #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
tst.w LOCAL_EX(a0) ;check sign
blt.b cu_dmdn
cmpi.b #3,d1 ;check for rp
bne cu_dpd ;load double pos zero
bra cu_dpdr ;load double pos zero w/lsb
cu_dmdn:
cmpi.b #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
tst.w LOCAL_EX(a0) ;check sign
blt.b cu_dmsn
cmpi.b #3,d1 ;check for rp
bne cu_spd ;load single pos zero
bra cu_spdr ;load single pos zero w/lsb
cu_dmsn:
cmpi.b #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:
or.l #unfl_mask,USER_FPSR(a6)
tst.w LOCAL_EX(a0)
beq wr_etemp
or.l #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:
move.l #$3c010000,LOCAL_EX(a0) ;force pos double zero
clr.l LOCAL_HI(a0)
clr.l LOCAL_LO(a0)
or.l #z_mask,USER_FPSR(a6)
or.l #unfinx_mask,USER_FPSR(a6)
bra wr_etemp
cu_dpdr:
move.l #$3c010000,LOCAL_EX(a0) ;force pos double zero
clr.l LOCAL_HI(a0)
move.l #$800,LOCAL_LO(a0) ;with lsb set
or.l #unfinx_mask,USER_FPSR(a6)
bra wr_etemp
cu_dnd:
move.l #$bc010000,LOCAL_EX(a0) ;force pos double zero
clr.l LOCAL_HI(a0)
clr.l LOCAL_LO(a0)
or.l #z_mask,USER_FPSR(a6)
or.l #neg_mask,USER_FPSR(a6)
or.l #unfinx_mask,USER_FPSR(a6)
bra wr_etemp
cu_dndr:
move.l #$bc010000,LOCAL_EX(a0) ;force pos double zero
clr.l LOCAL_HI(a0)
move.l #$800,LOCAL_LO(a0) ;with lsb set
or.l #neg_mask,USER_FPSR(a6)
or.l #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:
move.l #$3f810000,LOCAL_EX(a0) ;force pos single zero
clr.l LOCAL_HI(a0)
clr.l LOCAL_LO(a0)
or.l #z_mask,USER_FPSR(a6)
or.l #unfinx_mask,USER_FPSR(a6)
bra wr_etemp
cu_spdr:
move.l #$3f810000,LOCAL_EX(a0) ;force pos single zero
move.l #$100,LOCAL_HI(a0) ;with lsb set
clr.l LOCAL_LO(a0)
or.l #unfinx_mask,USER_FPSR(a6)
bra wr_etemp
cu_snd:
move.l #$bf810000,LOCAL_EX(a0) ;force pos single zero
clr.l LOCAL_HI(a0)
clr.l LOCAL_LO(a0)
or.l #z_mask,USER_FPSR(a6)
or.l #neg_mask,USER_FPSR(a6)
or.l #unfinx_mask,USER_FPSR(a6)
bra wr_etemp
cu_sndr:
move.l #$bf810000,LOCAL_EX(a0) ;force pos single zero
move.l #$100,LOCAL_HI(a0) ;with lsb set
clr.l LOCAL_LO(a0)
or.l #neg_mask,USER_FPSR(a6)
or.l #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 denormalzed
*
* 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:
addcode equ $22
subcode equ $28
mulcode equ $23
divcode equ $20
cmpcode equ $38
ck_wrap:
tst.b DY_MO_FLG(a6) ;check for fsqrt
beq fix_stk ;if zero, it is fsqrt
move.w CMDREG1B(a6),d0
andi.w #$3b,d0 ;strip to command bits
cmpi.w #addcode,d0
beq wrap_add
cmpi.w #subcode,d0
beq wrap_sub
cmpi.w #mulcode,d0
beq wrap_mul
cmpi.w #cmpcode,d0
beq wrap_cmp
*
* Inst is fdiv.
*
wrap_div:
cmp.b #$ff,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.
*
cmp.b #$0f,DNRM_FLG(a6) ;check for dest denorm
bne.b div_srcd
div_destd:
bsr.l 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)
sub.l d1,d0 ;subtract dest from src
cmp.l #$7fff,d0
blt fix_stk ;if less, not wrap case
clr.b WBTEMP_SGN(a6)
move.w ETEMP_EX(a6),d0 ;find the sign of the result
move.w FPTEMP_EX(a6),d1
eor.w d1,d0
andi.w #$8000,d0
beq force_unf
st.b WBTEMP_SGN(a6)
bra force_unf
ckinf_ns:
move.b STAG(a6),d0 ;check source tag for inf or nan
bra ck_in_com
ckinf_nd:
move.b DTAG(a6),d0 ;check destination tag for inf or nan
ck_in_com:
andi.b #$60,d0 ;isolate tag bits
cmp.b #$40,d0 ;is it inf?
beq nan_or_inf ;not wrap case
cmp.b #$60,d0 ;is it nan?
beq nan_or_inf ;yes, not wrap case?
cmp.b #$20,d0 ;is it a zero?
beq nan_or_inf ;yes
clr.l d0
rts ;then it is either a zero of norm,
* ;check wrap case
nan_or_inf:
moveq.l #-1,d0
rts
div_srcd:
bsr.l 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)
sub.l d1,d0 ;subtract src from dest
cmp.l #$8000,d0
blt fix_stk ;if less, not wrap case
clr.b WBTEMP_SGN(a6)
move.w ETEMP_EX(a6),d0 ;find the sign of the result
move.w FPTEMP_EX(a6),d1
eor.w d1,d0
andi.w #$8000,d0
beq.b force_ovf
st.b WBTEMP_SGN(a6)
*
* This code handles the case of the instruction resulting in
* an overflow condition.
*
force_ovf:
bclr.b #E1,E_BYTE(a6)
or.l #ovfl_inx_mask,USER_FPSR(a6)
clr.w NMNEXC(a6)
lea.l WBTEMP(a6),a0 ;point a0 to memory location
move.w CMDREG1B(a6),d0
btst.l #6,d0 ;test for forced precision
beq.b frcovf_fpcr
btst.l #2,d0 ;check for double
bne.b frcovf_dbl
move.l #$1,d0 ;inst is forced single
bra.b frcovf_rnd
frcovf_dbl:
move.l #$2,d0 ;inst is forced double
bra.b 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:
bsr.l 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
bset.b #sign_bit,WBTEMP_EX(a6)
bra frcfpn
*
* Inst is fadd.
*
wrap_add:
cmp.b #$ff,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.
*
cmp.b #$0f,DNRM_FLG(a6) ;check for dest denorm
bne.b add_srcd
add_destd:
bsr.l 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)
sub.l d1,d0 ;subtract dest from src
cmp.l #$8000,d0
blt fix_stk ;if less, not wrap case
bra add_wrap
add_srcd:
bsr.l 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)
sub.l d1,d0 ;subtract src from dest
cmp.l #$8000,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 correctfor the user's rounding mode and
* precision.
*
add_wrap:
move.w ETEMP_EX(a6),d0
move.w FPTEMP_EX(a6),d1
eor.w d1,d0
andi.w #$8000,d0
beq add_same
*
* The signs are unlike.
*
cmp.b #$0f,DNRM_FLG(a6) ;is dest the denorm?
bne.b add_u_srcd
move.w FPTEMP_EX(a6),d0
andi.w #$8000,d0
or.w #$3fff,d0 ;force the exponent to +/- 1
move.w d0,FPTEMP_EX(a6) ;in the denorm
move.l USER_FPCR(a6),d0
andi.l #$30,d0
fmove.l d0,fpcr ;set up users rmode and X
fmove.x ETEMP(a6),fp0
fadd.x FPTEMP(a6),fp0
lea.l WBTEMP(a6),a0 ;point a0 to wbtemp in frame
fmove.l fpsr,d1
or.l d1,USER_FPSR(a6) ;capture cc's and inex from fadd
fmove.x fp0,WBTEMP(a6) ;write result to memory
lsr.l #4,d0 ;put rmode in lower 2 bits
move.l USER_FPCR(a6),d1
andi.l #$c0,d1
lsr.l #6,d1 ;put precision in upper word
swap d1
or.l d0,d1 ;set up for round call
clr.l d0 ;force sticky to zero
bclr.b #sign_bit,WBTEMP_EX(a6)
sne WBTEMP_SGN(a6)
bsr.l round ;round result to users rmode & prec
bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format
beq frcfpnr
bset.b #sign_bit,WBTEMP_EX(a6)
bra frcfpnr
add_u_srcd:
move.w ETEMP_EX(a6),d0
andi.w #$8000,d0
or.w #$3fff,d0 ;force the exponent to +/- 1
move.w d0,ETEMP_EX(a6) ;in the denorm
move.l USER_FPCR(a6),d0
andi.l #$30,d0
fmove.l d0,fpcr ;set up users rmode and X
fmove.x ETEMP(a6),fp0
fadd.x FPTEMP(a6),fp0
fmove.l fpsr,d1
or.l d1,USER_FPSR(a6) ;capture cc's and inex from fadd
lea.l WBTEMP(a6),a0 ;point a0 to wbtemp in frame
fmove.x fp0,WBTEMP(a6) ;write result to memory
lsr.l #4,d0 ;put rmode in lower 2 bits
move.l USER_FPCR(a6),d1
andi.l #$c0,d1
lsr.l #6,d1 ;put precision in upper word
swap d1
or.l d0,d1 ;set up for round call
clr.l d0 ;force sticky to zero
bclr.b #sign_bit,WBTEMP_EX(a6)
sne WBTEMP_SGN(a6) ;use internal format for round
bsr.l round ;round result to users rmode & prec
bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format
beq frcfpnr
bset.b #sign_bit,WBTEMP_EX(a6)
bra frcfpnr
*
* Signs are alike:
*
add_same:
cmp.b #$0f,DNRM_FLG(a6) ;is dest the denorm?
bne.b add_s_srcd
add_s_destd:
lea.l ETEMP(a6),a0
move.l USER_FPCR(a6),d0
andi.l #$30,d0
lsr.l #4,d0 ;put rmode in lower 2 bits
move.l USER_FPCR(a6),d1
andi.l #$c0,d1
lsr.l #6,d1 ;put precision in upper word
swap d1
or.l d0,d1 ;set up for round call
move.l #$20000000,d0 ;set sticky for round
bclr.b #sign_bit,ETEMP_EX(a6)
sne ETEMP_SGN(a6)
bsr.l round ;round result to users rmode & prec
bfclr ETEMP_SGN(a6){0:8} ;convert back to IEEE ext format
beq.b add_s_dclr
bset.b #sign_bit,ETEMP_EX(a6)
add_s_dclr:
lea.l WBTEMP(a6),a0
move.l ETEMP(a6),(a0) ;write result to wbtemp
move.l ETEMP_HI(a6),4(a0)
move.l ETEMP_LO(a6),8(a0)
tst.w ETEMP_EX(a6)
bgt add_ckovf
or.l #neg_mask,USER_FPSR(a6)
bra add_ckovf
add_s_srcd:
lea.l FPTEMP(a6),a0
move.l USER_FPCR(a6),d0
andi.l #$30,d0
lsr.l #4,d0 ;put rmode in lower 2 bits
move.l USER_FPCR(a6),d1
andi.l #$c0,d1
lsr.l #6,d1 ;put precision in upper word
swap d1
or.l d0,d1 ;set up for round call
move.l #$20000000,d0 ;set sticky for round
bclr.b #sign_bit,FPTEMP_EX(a6)
sne FPTEMP_SGN(a6)
bsr.l round ;round result to users rmode & prec
bfclr FPTEMP_SGN(a6){0:8} ;convert back to IEEE ext format
beq.b add_s_sclr
bset.b #sign_bit,FPTEMP_EX(a6)
add_s_sclr:
lea.l WBTEMP(a6),a0
move.l FPTEMP(a6),(a0) ;write result to wbtemp
move.l FPTEMP_HI(a6),4(a0)
move.l FPTEMP_LO(a6),8(a0)
tst.w FPTEMP_EX(a6)
bgt add_ckovf
or.l #neg_mask,USER_FPSR(a6)
add_ckovf:
move.w WBTEMP_EX(a6),d0
andi.w #$7fff,d0
cmpi.w #$7fff,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.)
*
or.l #inf_mask+ovfl_inx_mask,USER_FPSR(a6)
clr.l 4(a0)
bra frcfpnr
*
* Inst is fsub.
*
wrap_sub:
cmp.b #$ff,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.
*
cmp.b #$0f,DNRM_FLG(a6) ;check for dest denorm
bne.b sub_srcd
sub_destd:
bsr.l 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)
sub.l d1,d0 ;subtract src from dest
cmp.l #$8000,d0
blt fix_stk ;if less, not wrap case
bra sub_wrap
sub_srcd:
bsr.l 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)
sub.l d1,d0 ;subtract dest from src
cmp.l #$8000,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 correctfor the user's rounding mode and
* precision.
*
sub_wrap:
move.w ETEMP_EX(a6),d0
move.w FPTEMP_EX(a6),d1
eor.w d1,d0
andi.w #$8000,d0
bne sub_diff
*
* The signs are alike.
*
cmp.b #$0f,DNRM_FLG(a6) ;is dest the denorm?
bne.b sub_u_srcd
move.w FPTEMP_EX(a6),d0
andi.w #$8000,d0
or.w #$3fff,d0 ;force the exponent to +/- 1
move.w d0,FPTEMP_EX(a6) ;in the denorm
move.l USER_FPCR(a6),d0
andi.l #$30,d0
fmove.l d0,fpcr ;set up users rmode and X
fmove.x FPTEMP(a6),fp0
fsub.x ETEMP(a6),fp0
fmove.l fpsr,d1
or.l d1,USER_FPSR(a6) ;capture cc's and inex from fadd
lea.l WBTEMP(a6),a0 ;point a0 to wbtemp in frame
fmove.x fp0,WBTEMP(a6) ;write result to memory
lsr.l #4,d0 ;put rmode in lower 2 bits
move.l USER_FPCR(a6),d1
andi.l #$c0,d1
lsr.l #6,d1 ;put precision in upper word
swap d1
or.l d0,d1 ;set up for round call
clr.l d0 ;force sticky to zero
bclr.b #sign_bit,WBTEMP_EX(a6)
sne WBTEMP_SGN(a6)
bsr.l round ;round result to users rmode & prec
bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format
beq frcfpnr
bset.b #sign_bit,WBTEMP_EX(a6)
bra frcfpnr
sub_u_srcd:
move.w ETEMP_EX(a6),d0
andi.w #$8000,d0
or.w #$3fff,d0 ;force the exponent to +/- 1
move.w d0,ETEMP_EX(a6) ;in the denorm
move.l USER_FPCR(a6),d0
andi.l #$30,d0
fmove.l d0,fpcr ;set up users rmode and X
fmove.x FPTEMP(a6),fp0
fsub.x ETEMP(a6),fp0
fmove.l fpsr,d1
or.l d1,USER_FPSR(a6) ;capture cc's and inex from fadd
lea.l WBTEMP(a6),a0 ;point a0 to wbtemp in frame
fmove.x fp0,WBTEMP(a6) ;write result to memory
lsr.l #4,d0 ;put rmode in lower 2 bits
move.l USER_FPCR(a6),d1
andi.l #$c0,d1
lsr.l #6,d1 ;put precision in upper word
swap d1
or.l d0,d1 ;set up for round call
clr.l d0 ;force sticky to zero
bclr.b #sign_bit,WBTEMP_EX(a6)
sne WBTEMP_SGN(a6)
bsr.l round ;round result to users rmode & prec
bfclr WBTEMP_SGN(a6){0:8} ;convert back to IEEE ext format
beq frcfpnr
bset.b #sign_bit,WBTEMP_EX(a6)
bra frcfpnr
*
* Signs are unlike:
*
sub_diff:
cmp.b #$0f,DNRM_FLG(a6) ;is dest the denorm?
bne.b sub_s_srcd
sub_s_destd:
lea.l ETEMP(a6),a0
move.l USER_FPCR(a6),d0
andi.l #$30,d0
lsr.l #4,d0 ;put rmode in lower 2 bits
move.l USER_FPCR(a6),d1
andi.l #$c0,d1
lsr.l #6,d1 ;put precision in upper word
swap d1
or.l d0,d1 ;set up for round call
move.l #$20000000,d0 ;set sticky for round
*
* Since the dest is the denorm, the sign is the opposite of the
* norm sign.
*
eori.w #$8000,ETEMP_EX(a6) ;flip sign on result
tst.w ETEMP_EX(a6)
bgt.b sub_s_dwr
or.l #neg_mask,USER_FPSR(a6)
sub_s_dwr:
bclr.b #sign_bit,ETEMP_EX(a6)
sne ETEMP_SGN(a6)
bsr.l round ;round result to users rmode & prec
bfclr ETEMP_SGN(a6){0:8} ;convert back to IEEE ext format
beq.b sub_s_dclr
bset.b #sign_bit,ETEMP_EX(a6)
sub_s_dclr:
lea.l WBTEMP(a6),a0
move.l ETEMP(a6),(a0) ;write result to wbtemp
move.l ETEMP_HI(a6),4(a0)
move.l ETEMP_LO(a6),8(a0)
bra sub_ckovf
sub_s_srcd:
lea.l FPTEMP(a6),a0
move.l USER_FPCR(a6),d0
andi.l #$30,d0
lsr.l #4,d0 ;put rmode in lower 2 bits
move.l USER_FPCR(a6),d1
andi.l #$c0,d1
lsr.l #6,d1 ;put precision in upper word
swap d1
or.l d0,d1 ;set up for round call
move.l #$20000000,d0 ;set sticky for round
bclr.b #sign_bit,FPTEMP_EX(a6)
sne FPTEMP_SGN(a6)
bsr.l round ;round result to users rmode & prec
bfclr FPTEMP_SGN(a6){0:8} ;convert back to IEEE ext format
beq.b sub_s_sclr
bset.b #sign_bit,FPTEMP_EX(a6)
sub_s_sclr:
lea.l WBTEMP(a6),a0
move.l FPTEMP(a6),(a0) ;write result to wbtemp
move.l FPTEMP_HI(a6),4(a0)
move.l FPTEMP_LO(a6),8(a0)
tst.w FPTEMP_EX(a6)
bgt sub_ckovf
or.l #neg_mask,USER_FPSR(a6)
sub_ckovf:
move.w WBTEMP_EX(a6),d0
andi.w #$7fff,d0
cmpi.w #$7fff,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.)
*
or.l #inf_mask+ovfl_inx_mask,USER_FPSR(a6)
clr.l 4(a0)
bra frcfpnr
*
* Inst is fcmp.
*
wrap_cmp:
cmp.b #$ff,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.
*
cmp.b #$0f,DNRM_FLG(a6) ;check for dest denorm
bne.b cmp_srcd
cmp_destd:
bsr.l 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)
sub.l d1,d0 ;subtract dest from src
cmp.l #$8000,d0
blt fix_stk ;if less, not wrap case
tst.w ETEMP_EX(a6) ;set N to ~sign_of(src)
bge cmp_setn
rts
cmp_srcd:
bsr.l 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)
sub.l d1,d0 ;subtract src from dest
cmp.l #$8000,d0
blt fix_stk ;if less, not wrap case
tst.w FPTEMP_EX(a6) ;set N to sign_of(dest)
blt cmp_setn
rts
cmp_setn:
or.l #neg_mask,USER_FPSR(a6)
rts
*
* Inst is fmul.
*
wrap_mul:
cmp.b #$ff,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.
*
cmp.b #$0f,DNRM_FLG(a6) ;check for dest denorm
bne.b mul_srcd
mul_destd:
bsr.l 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)
add.l d1,d0 ;subtract dest from src
bgt fix_stk
bra force_unf
mul_srcd:
bsr.l 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)
add.l d1,d0 ;subtract src from dest
bgt fix_stk
*
* This code handles the case of the instruction resulting in
* an underflow condition.
*
force_unf:
bclr.b #E1,E_BYTE(a6)
or.l #unfinx_mask,USER_FPSR(a6)
clr.w NMNEXC(a6)
clr.b WBTEMP_SGN(a6)
move.w ETEMP_EX(a6),d0 ;find the sign of the result
move.w FPTEMP_EX(a6),d1
eor.w d1,d0
andi.w #$8000,d0
beq.b frcunfcont
st.b WBTEMP_SGN(a6)
frcunfcont:
lea WBTEMP(a6),a0 ;point a0 to memory location
move.w CMDREG1B(a6),d0
btst.l #6,d0 ;test for forced precision
beq.b frcunf_fpcr
btst.l #2,d0 ;check for double
bne.b frcunf_dbl
move.l #$1,d0 ;inst is forced single
bra.b frcunf_rnd
frcunf_dbl:
move.l #$2,d0 ;inst is forced double
bra.b frcunf_rnd
frcunf_fpcr:
bfextu FPCR_MODE(a6){0:2},d0 ;inst not forced - use fpcr prec
frcunf_rnd:
bsr.l 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
beq.b frcfpn
bset.b #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:
move.w CMDREG1B(a6),d0
btst.l #6,d0 ;test for forced precision
beq.b frcfpn_fpcr
btst.l #2,d0 ;check for double
bne.b frcfpn_dbl
move.l #$1,d0 ;inst is forced single
bra.b frcfpn_rnd
frcfpn_dbl:
move.l #$2,d0 ;inst is forced double
bra.b frcfpn_rnd
frcfpn_fpcr:
bfextu FPCR_MODE(a6){0:2},d0 ;inst not forced - use fpcr prec
tst.b d0
beq.b frcfpn ;if extended, write what you got
frcfpn_rnd:
bclr.b #sign_bit,WBTEMP_EX(a6)
sne WBTEMP_SGN(a6)
bsr.l 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
beq.b frcfpn_clr
bset.b #sign_bit,WBTEMP_EX(a6)
frcfpn_clr:
or.l #ovfinx_mask,USER_FPSR(a6)
*
* Perform the write.
*
frcfpn:
bfextu CMDREG1B(a6){6:3},d0 ;extract fp destination register
cmpi.b #3,d0
ble.b frc0123 ;check if dest is fp0-fp3
move.l #7,d1
sub.l d0,d1
clr.l d0
bset.l d1,d0
fmovem.x WBTEMP(a6),d0
rts
frc0123:
tst.b d0
beq.b frc0_dst
cmpi.b #1,d0
beq.b frc1_dst
cmpi.b #2,d0
beq.b frc2_dst
frc3_dst:
move.l WBTEMP_EX(a6),USER_FP3(a6)
move.l WBTEMP_HI(a6),USER_FP3+4(a6)
move.l WBTEMP_LO(a6),USER_FP3+8(a6)
rts
frc2_dst:
move.l WBTEMP_EX(a6),USER_FP2(a6)
move.l WBTEMP_HI(a6),USER_FP2+4(a6)
move.l WBTEMP_LO(a6),USER_FP2+8(a6)
rts
frc1_dst:
move.l WBTEMP_EX(a6),USER_FP1(a6)
move.l WBTEMP_HI(a6),USER_FP1+4(a6)
move.l WBTEMP_LO(a6),USER_FP1+8(a6)
rts
frc0_dst:
move.l WBTEMP_EX(a6),USER_FP0(a6)
move.l WBTEMP_HI(a6),USER_FP0+4(a6)
move.l 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:
btst.b #snan_bit,FPSR_EXCEPT(a6) ;if snan is set, and
beq.b fmoveinc ;enabled, force restore
btst.b #snan_bit,FPCR_ENABLE(a6) ;and don't overwrite
beq.b fmoveinc ;the dest
move.l ETEMP_EX(a6),FPTEMP_EX(a6) ;set up fptemp sign for
* ;snan handler
tst.b ETEMP(a6) ;check for negative
blt.b snan_neg
rts
snan_neg:
or.l #neg_bit,USER_FPSR(a6) ;snan is negative; set N
rts
fmoveinc:
clr.w NMNEXC(a6)
bclr.b #E1,E_BYTE(a6)
move.b STAG(a6),d0 ;check if stag is inf
andi.b #$e0,d0
cmpi.b #$40,d0
bne.b fminc_cnan
or.l #inf_mask,USER_FPSR(a6) ;if inf, nothing yet has set I
tst.w LOCAL_EX(a0) ;check sign
bge.b fminc_con
or.l #neg_mask,USER_FPSR(a6)
bra fminc_con
fminc_cnan:
cmpi.b #$60,d0 ;check if stag is NaN
bne.b fminc_czero
or.l #nan_mask,USER_FPSR(a6) ;if nan, nothing yet has set NaN
move.l ETEMP_EX(a6),FPTEMP_EX(a6) ;set up fptemp sign for
* ;snan handler
tst.w LOCAL_EX(a0) ;check sign
bge.b fminc_con
or.l #neg_mask,USER_FPSR(a6)
bra fminc_con
fminc_czero:
cmpi.b #$20,d0 ;check if zero
bne.b fminc_con
or.l #z_mask,USER_FPSR(a6) ;if zero, set Z
tst.w LOCAL_EX(a0) ;check sign
bge.b fminc_con
or.l #neg_mask,USER_FPSR(a6)
fminc_con:
bfextu CMDREG1B(a6){6:3},d0 ;extract fp destination register
cmpi.b #3,d0
ble.b fp0123 ;check if dest is fp0-fp3
move.l #7,d1
sub.l d0,d1
clr.l d0
bset.l d1,d0
fmovem.x ETEMP(a6),d0
rts
fp0123:
tst.b d0
beq.b fp0_dst
cmpi.b #1,d0
beq.b fp1_dst
cmpi.b #2,d0
beq.b fp2_dst
fp3_dst:
move.l ETEMP_EX(a6),USER_FP3(a6)
move.l ETEMP_HI(a6),USER_FP3+4(a6)
move.l ETEMP_LO(a6),USER_FP3+8(a6)
rts
fp2_dst:
move.l ETEMP_EX(a6),USER_FP2(a6)
move.l ETEMP_HI(a6),USER_FP2+4(a6)
move.l ETEMP_LO(a6),USER_FP2+8(a6)
rts
fp1_dst:
move.l ETEMP_EX(a6),USER_FP1(a6)
move.l ETEMP_HI(a6),USER_FP1+4(a6)
move.l ETEMP_LO(a6),USER_FP1+8(a6)
rts
fp0_dst:
move.l ETEMP_EX(a6),USER_FP0(a6)
move.l ETEMP_HI(a6),USER_FP0+4(a6)
move.l ETEMP_LO(a6),USER_FP0+8(a6)
rts
opclass3:
st.b CU_ONLY(a6)
move.w CMDREG1B(a6),d0 ;check if packed moveout
andi.w #$0c00,d0 ;isolate last 2 bits of size field
cmpi.w #$0c00,d0 ;if size is 011 or 111, it is packed
beq.w pack_out ;else it is norm or denorm
bra.w mv_out
*
* MOVE OUT
*
mv_tbl:
dc.l li
dc.l sgp
dc.l xp
dc.l mvout_end ;should never be taken
dc.l wi
dc.l dp
dc.l bi
dc.l mvout_end ;should never be taken
mv_out:
bfextu CMDREG1B(a6){3:3},d1 ;put source specifier in d1
lea.l mv_tbl,a0
move.l (a0,d1*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:
btst.b #inex2_bit,FPSR_EXCEPT(a6)
beq.b no_aufl
btst.b #unfl_bit,FPSR_EXCEPT(a6)
beq.b no_aufl
bset.b #aunfl_bit,FPSR_AEXCEPT(a6)
no_aufl:
clr.w NMNEXC(a6)
bclr.b #E1,E_BYTE(a6)
fmove.l #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}
beq.b mvout_con
bset.b #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:
clr.w NMNEXC(a6)
bclr.b #E1,E_BYTE(a6)
fmove.l #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}
beq.b mvouti_con
bset.b #sign_bit,ETEMP_EX(a6)
mvouti_con:
rts
*
* li is used to handle a long integer source specifier
*
li:
moveq.l #4,d0 ;set byte count
btst.b #7,STAG(a6) ;check for extended denorm
bne.w int_dnrm ;if so, branch
fmovem.x ETEMP(a6),fp0
fcmp.d #:41dfffffffc00000,fp0
* 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
fbge.w lo_plrg
fcmp.d #:c1e0000000000000,fp0
* c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
fble.w lo_nlrg
*
* at this point, the answer is between the largest pos and neg values
*
move.l USER_FPCR(a6),d1 ;use user's rounding mode
andi.l #$30,d1
fmove.l d1,fpcr
fmove.l fp0,L_SCR1(a6) ;let the 040 perform conversion
fmove.l fpsr,d1
or.l d1,USER_FPSR(a6) ;capture inex2/ainex if set
bra.w int_wrt
lo_plrg:
move.l #$7fffffff,L_SCR1(a6) ;answer is largest positive int
fbeq.w int_wrt ;exact answer
fcmp.d #:41dfffffffe00000,fp0
* 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
fbge.w int_operr ;set operr
bra.w int_inx ;set inexact
lo_nlrg:
move.l #$80000000,L_SCR1(a6)
fbeq.w int_wrt ;exact answer
fcmp.d #:c1e0000000100000,fp0
* c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
fblt.w int_operr ;set operr
bra.w int_inx ;set inexact
*
* wi is used to handle a word integer source specifier
*
wi:
moveq.l #2,d0 ;set byte count
btst.b #7,STAG(a6) ;check for extended denorm
bne.w int_dnrm ;branch if so
fmovem.x ETEMP(a6),fp0
fcmp.s #:46fffe00,fp0
* 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
fbge.w wo_plrg
fcmp.s #:c7000000,fp0
* c7000000 in sgl prec = c00e00008000000000000000 in ext prec
fble.w wo_nlrg
*
* at this point, the answer is between the largest pos and neg values
*
move.l USER_FPCR(a6),d1 ;use user's rounding mode
andi.l #$30,d1
fmove.l d1,fpcr
fmove.w fp0,L_SCR1(a6) ;let the 040 perform conversion
fmove.l fpsr,d1
or.l d1,USER_FPSR(a6) ;capture inex2/ainex if set
bra.w int_wrt
wo_plrg:
move.w #$7fff,L_SCR1(a6) ;answer is largest positive int
fbeq.w int_wrt ;exact answer
fcmp.s #:46ffff00,fp0
* 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
fbge.w int_operr ;set operr
bra.w int_inx ;set inexact
wo_nlrg:
move.w #$8000,L_SCR1(a6)
fbeq.w int_wrt ;exact answer
fcmp.s #:c7000080,fp0
* c7000080 in sgl prec = c00e00008000800000000000 in ext prec
fblt.w int_operr ;set operr
bra.w int_inx ;set inexact
*
* bi is used to handle a byte integer source specifier
*
bi:
moveq.l #1,d0 ;set byte count
btst.b #7,STAG(a6) ;check for extended denorm
bne.w int_dnrm ;branch if so
fmovem.x ETEMP(a6),fp0
fcmp.s #:42fe0000,fp0
* 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
fbge.w by_plrg
fcmp.s #:c3000000,fp0
* c3000000 in sgl prec = c00600008000000000000000 in ext prec
fble.w by_nlrg
*
* at this point, the answer is between the largest pos and neg values
*
move.l USER_FPCR(a6),d1 ;use user's rounding mode
andi.l #$30,d1
fmove.l d1,fpcr
fmove.b fp0,L_SCR1(a6) ;let the 040 perform conversion
fmove.l fpsr,d1
or.l d1,USER_FPSR(a6) ;capture inex2/ainex if set
bra.w int_wrt
by_plrg:
move.b #$7f,L_SCR1(a6) ;answer is largest positive int
fbeq.w int_wrt ;exact answer
fcmp.s #:42ff0000,fp0
* 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
fbge.w int_operr ;set operr
bra.w int_inx ;set inexact
by_nlrg:
move.b #$80,L_SCR1(a6)
fbeq.w int_wrt ;exact answer
fcmp.s #:c3008000,fp0
* c3008000 in sgl prec = c00600008080000000000000 in ext prec
fblt.w int_operr ;set operr
bra.w 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:
clr.l L_SCR1(a6) ; initialize result to 0
bfextu FPCR_MODE(a6){2:2},d1 ; d1 is the rounding mode
cmp.b #2,d1
bmi.b int_inx ; if RN or RZ, done
bne.b int_rp ; if RP, continue below
tst.w ETEMP(a6) ; RM: store -1 in L_SCR1 if src is negative
bpl.b int_inx ; otherwise result is 0
move.l #-1,L_SCR1(a6)
bra.b int_inx
int_rp:
tst.w ETEMP(a6) ; RP: store +1 of proper width in L_SCR1 if
* ; source is greater than 0
bmi.b int_inx ; otherwise, result is 0
lea L_SCR1(a6),a1 ; a1 is address of L_SCR1
adda.l d0,a1 ; offset by destination width -1
suba.l #1,a1
bset.b #0,(a1) ; set low bit at a1 address
int_inx:
ori.l #inx2a_mask,USER_FPSR(a6)
bra.b int_wrt
int_operr:
fmovem.x 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)
ori.l #opaop_mask,USER_FPSR(a6)
* ;fall through to perform int_wrt
int_wrt:
move.l EXC_EA(a6),a1 ;load destination address
tst.l a1 ;check to see if it is a dest register
beq.b wrt_dn ;write data register
lea L_SCR1(a6),a0 ;point to supervisor source address
bsr.l mem_write
bra.w mvouti_end
wrt_dn:
move.l d0,-(sp) ;d0 currently contains the size to write
bsr.l get_fline ;get_fline returns Dn in d0
andi.w #$7,d0 ;isolate register
move.l (sp)+,d1 ;get size
cmpi.l #4,d1 ;most frequent case
beq.b sz_long
cmpi.l #2,d1
bne.b sz_con
or.l #8,d0 ;add 'word' size to register#
bra.b sz_con
sz_long:
or.l #$10,d0 ;add 'long' size to register#
sz_con:
move.l d0,d1 ;reg_dest expects size:reg in d1
bsr.l reg_dest ;load proper data register
bra.w mvouti_end
xp:
lea ETEMP(a6),a0
bclr.b #sign_bit,LOCAL_EX(a0)
sne LOCAL_SGN(a0)
btst.b #7,STAG(a6) ;check for extended denorm
bne.w xdnrm
clr.l d0
bra.b do_fp ;do normal case
sgp:
lea ETEMP(a6),a0
bclr.b #sign_bit,LOCAL_EX(a0)
sne LOCAL_SGN(a0)
btst.b #7,STAG(a6) ;check for extended denorm
bne.w sp_catas ;branch if so
move.w LOCAL_EX(a0),d0
lea sp_bnds,a1
cmp.w (a1),d0
blt.w sp_under
cmp.w 2(a1),d0
bgt.w sp_over
move.l #1,d0 ;set destination format to single
bra.b do_fp ;do normal case
dp:
lea ETEMP(a6),a0
bclr.b #sign_bit,LOCAL_EX(a0)
sne LOCAL_SGN(a0)
btst.b #7,STAG(a6) ;check for extended denorm
bne.w dp_catas ;branch if so
move.w LOCAL_EX(a0),d0
lea dp_bnds,a1
cmp.w (a1),d0
blt.w dp_under
cmp.w 2(a1),d0
bgt.w dp_over
move.l #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
add.l d0,d1 ;d1 has PREC/MODE info
clr.l d0 ;clear g,r,s
bsr.l round ;round
move.l a0,a1
move.l 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
cmp.b #2,d1
bgt.b ddbl ;double=5, extended=2, single=1
bne.b dsgl
* ;fall through to dext
dext:
bsr.l dest_ext
bra.w mvout_end
dsgl:
bsr.l dest_sgl
bra.w mvout_end
ddbl:
bsr.l dest_dbl
bra.w mvout_end
*
* Handle possible denorm or catastrophic underflow cases here
*
xdnrm:
bsr.w set_xop ;initialize WBTEMP
bset.b #wbtemp15_bit,WB_BYTE(a6) ;set wbtemp15
move.l a0,a1
move.l EXC_EA(a6),a0 ;a0 has the destination pointer
bsr.l dest_ext ;store to memory
bset.b #unfl_bit,FPSR_EXCEPT(a6)
bra.w mvout_end
sp_under:
bset.b #etemp15_bit,STAG(a6)
cmp.w 4(a1),d0
blt.b sp_catas ;catastrophic underflow case
move.l #1,d0 ;load in round precision
move.l #sgl_thresh,d1 ;load in single denorm threshold
bsr.l dpspdnrm ;expects d1 to have the proper
* ;denorm threshold
bsr.l dest_sgl ;stores value to destination
bset.b #unfl_bit,FPSR_EXCEPT(a6)
bra.w mvout_end ;exit
dp_under:
bset.b #etemp15_bit,STAG(a6)
cmp.w 4(a1),d0
blt.b dp_catas ;catastrophic underflow case
move.l #dbl_thresh,d1 ;load in double precision threshold
move.l #2,d0
bsr.l dpspdnrm ;expects d1 to have proper
* ;denorm threshold
* ;expects d0 to have round precision
bsr.l dest_dbl ;store value to destination
bset.b #unfl_bit,FPSR_EXCEPT(a6)
bra.w mvout_end ;exit
*
* Handle catastrophic underflow cases here
*
sp_catas:
* Temp fix for z bit set in unf_sub
move.l USER_FPSR(a6),-(a7)
move.l #1,d0 ;set round precision to sgl
bsr.l unf_sub ;a0 points to result
move.l (a7)+,USER_FPSR(a6)
move.l #1,d0
sub.w d0,LOCAL_EX(a0) ;account for difference between
* ;denorm/norm bias
move.l a0,a1 ;a1 has the operand input
move.l EXC_EA(a6),a0 ;a0 has the destination pointer
bsr.l dest_sgl ;store the result
ori.l #unfinx_mask,USER_FPSR(a6)
bra.w mvout_end
dp_catas:
* Temp fix for z bit set in unf_sub
move.l USER_FPSR(a6),-(a7)
move.l #2,d0 ;set round precision to dbl
bsr.l unf_sub ;a0 points to result
move.l (a7)+,USER_FPSR(a6)
move.l #1,d0
sub.w d0,LOCAL_EX(a0) ;account for difference between
* ;denorm/norm bias
move.l a0,a1 ;a1 has the operand input
move.l EXC_EA(a6),a0 ;a0 has the destination pointer
bsr.l dest_dbl ;store the result
ori.l #unfinx_mask,USER_FPSR(a6)
bra.w mvout_end
*
* Handle catastrophic overflow cases here
*
sp_over:
* Temp fix for z bit set in unf_sub
move.l USER_FPSR(a6),-(a7)
move.l #1,d0
lea.l FP_SCR1(a6),a0 ;use FP_SCR1 for creating result
move.l ETEMP_EX(a6),(a0)
move.l ETEMP_HI(a6),4(a0)
move.l ETEMP_LO(a6),8(a0)
bsr.l ovf_res
move.l (a7)+,USER_FPSR(a6)
move.l a0,a1
move.l EXC_EA(a6),a0
bsr.l dest_sgl
or.l #ovfinx_mask,USER_FPSR(a6)
bra.w mvout_end
dp_over:
* Temp fix for z bit set in ovf_res
move.l USER_FPSR(a6),-(a7)
move.l #2,d0
lea.l FP_SCR1(a6),a0 ;use FP_SCR1 for creating result
move.l ETEMP_EX(a6),(a0)
move.l ETEMP_HI(a6),4(a0)
move.l ETEMP_LO(a6),8(a0)
bsr.l ovf_res
move.l (a7)+,USER_FPSR(a6)
move.l a0,a1
move.l EXC_EA(a6),a0
bsr.l dest_dbl
or.l #ovfinx_mask,USER_FPSR(a6)
bra.w 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:
move.l d0,-(a7) ;save round precision
clr.l d0 ;clear initial g,r,s
bsr.l dnrm_lp ;careful with d0, it's needed by round
bfextu FPCR_MODE(a6){2:2},d1 ;get rounding mode
swap d1
move.w 2(a7),d1 ;set rounding precision
swap d1 ;at this point d1 has PREC/MODE info
bsr.l round ;round result, sets the inex bit in
* ;USER_FPSR if needed
move.w #1,d0
sub.w d0,LOCAL_EX(a0) ;account for difference in denorm
* ;vs norm bias
move.l a0,a1 ;a1 has the operand input
move.l EXC_EA(a6),a0 ;a0 has the destination pointer
addq.l #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:
move.l LOCAL_EX(a0),WBTEMP_EX(a6)
move.l LOCAL_HI(a0),WBTEMP_HI(a6)
move.l LOCAL_LO(a0),WBTEMP_LO(a6)
bfclr WBTEMP_SGN(a6){0:8}
beq.b sxop
bset.b #sign_bit,WBTEMP_EX(a6)
sxop:
bfclr STAG(a6){5:4} ;clear wbtm66,wbtm1,wbtm0,sbit
rts
*
* P_MOVE
*
p_movet:
dc.l p_move
dc.l p_movez
dc.l p_movei
dc.l p_moven
dc.l p_move
p_regd:
dc.l p_dyd0
dc.l p_dyd1
dc.l p_dyd2
dc.l p_dyd3
dc.l p_dyd4
dc.l p_dyd5
dc.l p_dyd6
dc.l p_dyd7
pack_out:
lea.l p_movet,a0 ;load jmp table address
move.w STAG(a6),d0 ;get source tag
bfextu d0{16:3},d0 ;isolate source bits
move.l (a0,d0.w*4),a0 ;load a0 with routine label for tag
jmp (a0) ;go to the routine
p_write:
move.l #$0c,d0 ;get byte count
move.l EXC_EA(a6),a1 ;get the destination address
bsr mem_write ;write the user's destination
clr.b 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:
move.w CMDREG1B(a6),d0
btst.l #kfact_bit,d0 ;test for dynamic k-factor
beq.b statick ;if clear, k-factor is static
dynamick:
bfextu d0{25:3},d0 ;isolate register for dynamic k-factor
lea p_regd,a0
move.l (a0,d0*4),a0
jmp (a0)
statick:
andi.w #$007f,d0 ;get k-factor
bfexts d0{25:7},d0 ;sign extend d0 for bindec
lea.l ETEMP(a6),a0 ;a0 will point to the packed decimal
bsr.l bindec ;perform the convert; data at a6
lea.l FP_SCR1(a6),a0 ;load a0 with result address
bra.l p_write
p_movez:
lea.l ETEMP(a6),a0 ;a0 will point to the packed decimal
clr.w 2(a0) ;clear lower word of exp
clr.l 4(a0) ;load second lword of ZERO
clr.l 8(a0) ;load third lword of ZERO
bra.w p_write ;go write results
p_movei:
fmove.l #0,FPSR ;clear aiop
lea.l ETEMP(a6),a0 ;a0 will point to the packed decimal
clr.w 2(a0) ;clear lower word of exp
bra.w p_write ;go write the result
p_moven:
lea.l ETEMP(a6),a0 ;a0 will point to the packed decimal
clr.w 2(a0) ;clear lower word of exp
bra.w p_write ;go write the result
*
* Routines to read the dynamic k-factor from Dn.
*
p_dyd0:
move.l USER_D0(a6),d0
bra.b statick
p_dyd1:
move.l USER_D1(a6),d0
bra.b statick
p_dyd2:
move.l d2,d0
bra.b statick
p_dyd3:
move.l d3,d0
bra.b statick
p_dyd4:
move.l d4,d0
bra.b statick
p_dyd5:
move.l d5,d0
bra.b statick
p_dyd6:
move.l d6,d0
bra.w statick
p_dyd7:
move.l d7,d0
bra.w statick
end