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