| | |
| | x_unfl.sa 3.4 7/1/91 |
| | |
| | fpsp_unfl --- FPSP handler for underflow exception |
| | |
| | Trap disabled results |
| | For 881/2 compatibility, sw must denormalize the intermediate |
| | result, then store the result. Denormalization is accomplished |
| | by taking the intermediate result (which is always normalized) and |
| | shifting the mantissa right while incrementing the exponent until |
| | it is equal to the denormalized exponent for the destination |
| | format. After denormalization, the result is rounded to the |
| | destination format. |
| | |
| | Trap enabled results |
| | All trap disabled code applies. In addition the exceptional |
| | operand needs to made available to the user with a bias of $6000 |
| | added to the exponent. |
| | |
| |
| | 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. |
| |
| X_UNFL: |idnt 2,1 | Motorola 040 Floating Point Software Package |
| |
| |section 8 |
| |
| #include "fpsp.h" |
| |
| |xref denorm |
| |xref round |
| |xref store |
| |xref g_rndpr |
| |xref g_opcls |
| |xref g_dfmtou |
| |xref real_unfl |
| |xref real_inex |
| |xref fpsp_done |
| |xref b1238_fix |
| |
| .global fpsp_unfl |
| fpsp_unfl: |
| link %a6,#-LOCAL_SIZE |
| fsave -(%a7) |
| moveml %d0-%d1/%a0-%a1,USER_DA(%a6) |
| fmovemx %fp0-%fp3,USER_FP0(%a6) |
| fmoveml %fpcr/%fpsr/%fpiar,USER_FPCR(%a6) |
| |
| | |
| bsrl unf_res |denormalize, round & store interm op |
| | |
| | If underflow exceptions are not enabled, check for inexact |
| | exception |
| | |
| btstb #unfl_bit,FPCR_ENABLE(%a6) |
| beqs ck_inex |
| |
| btstb #E3,E_BYTE(%a6) |
| beqs no_e3_1 |
| | |
| | Clear dirty bit on dest resister in the frame before branching |
| | to b1238_fix. |
| | |
| bfextu CMDREG3B(%a6){#6:#3},%d0 |get dest reg no |
| bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit |
| bsrl b1238_fix |test for bug1238 case |
| movel USER_FPSR(%a6),FPSR_SHADOW(%a6) |
| orl #sx_mask,E_BYTE(%a6) |
| no_e3_1: |
| moveml USER_DA(%a6),%d0-%d1/%a0-%a1 |
| fmovemx USER_FP0(%a6),%fp0-%fp3 |
| fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar |
| frestore (%a7)+ |
| unlk %a6 |
| bral real_unfl |
| | |
| | It is possible to have either inex2 or inex1 exceptions with the |
| | unfl. If the inex enable bit is set in the FPCR, and either |
| | inex2 or inex1 occurred, we must clean up and branch to the |
| | real inex handler. |
| | |
| ck_inex: |
| moveb FPCR_ENABLE(%a6),%d0 |
| andb FPSR_EXCEPT(%a6),%d0 |
| andib #0x3,%d0 |
| beqs unfl_done |
| |
| | |
| | Inexact enabled and reported, and we must take an inexact exception |
| | |
| take_inex: |
| btstb #E3,E_BYTE(%a6) |
| beqs no_e3_2 |
| | |
| | Clear dirty bit on dest resister in the frame before branching |
| | to b1238_fix. |
| | |
| bfextu CMDREG3B(%a6){#6:#3},%d0 |get dest reg no |
| bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit |
| bsrl b1238_fix |test for bug1238 case |
| movel USER_FPSR(%a6),FPSR_SHADOW(%a6) |
| orl #sx_mask,E_BYTE(%a6) |
| no_e3_2: |
| moveb #INEX_VEC,EXC_VEC+1(%a6) |
| moveml USER_DA(%a6),%d0-%d1/%a0-%a1 |
| fmovemx USER_FP0(%a6),%fp0-%fp3 |
| fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar |
| frestore (%a7)+ |
| unlk %a6 |
| bral real_inex |
| |
| unfl_done: |
| bclrb #E3,E_BYTE(%a6) |
| beqs e1_set |if set then branch |
| | |
| | Clear dirty bit on dest resister in the frame before branching |
| | to b1238_fix. |
| | |
| bfextu CMDREG3B(%a6){#6:#3},%d0 |get dest reg no |
| bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit |
| bsrl b1238_fix |test for bug1238 case |
| movel USER_FPSR(%a6),FPSR_SHADOW(%a6) |
| orl #sx_mask,E_BYTE(%a6) |
| moveml USER_DA(%a6),%d0-%d1/%a0-%a1 |
| fmovemx USER_FP0(%a6),%fp0-%fp3 |
| fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar |
| frestore (%a7)+ |
| unlk %a6 |
| bral fpsp_done |
| e1_set: |
| moveml USER_DA(%a6),%d0-%d1/%a0-%a1 |
| fmovemx USER_FP0(%a6),%fp0-%fp3 |
| fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar |
| unlk %a6 |
| bral fpsp_done |
| | |
| | unf_res --- underflow result calculation |
| | |
| unf_res: |
| bsrl g_rndpr |returns RND_PREC in d0 0=ext, |
| | ;1=sgl, 2=dbl |
| | ;we need the RND_PREC in the |
| | ;upper word for round |
| movew #0,-(%a7) |
| movew %d0,-(%a7) |copy RND_PREC to stack |
| | |
| | |
| | If the exception bit set is E3, the exceptional operand from the |
| | fpu is in WBTEMP; else it is in FPTEMP. |
| | |
| btstb #E3,E_BYTE(%a6) |
| beqs unf_E1 |
| unf_E3: |
| lea WBTEMP(%a6),%a0 |a0 now points to operand |
| | |
| | Test for fsgldiv and fsglmul. If the inst was one of these, then |
| | force the precision to extended for the denorm routine. Use |
| | the user's precision for the round routine. |
| | |
| movew CMDREG3B(%a6),%d1 |check for fsgldiv or fsglmul |
| andiw #0x7f,%d1 |
| cmpiw #0x30,%d1 |check for sgldiv |
| beqs unf_sgl |
| cmpiw #0x33,%d1 |check for sglmul |
| bnes unf_cont |if not, use fpcr prec in round |
| unf_sgl: |
| clrl %d0 |
| movew #0x1,(%a7) |override g_rndpr precision |
| | ;force single |
| bras unf_cont |
| unf_E1: |
| lea FPTEMP(%a6),%a0 |a0 now points to operand |
| unf_cont: |
| bclrb #sign_bit,LOCAL_EX(%a0) |clear sign bit |
| sne LOCAL_SGN(%a0) |store sign |
| |
| bsrl denorm |returns denorm, a0 points to it |
| | |
| | WARNING: |
| | ;d0 has guard,round sticky bit |
| | ;make sure that it is not corrupted |
| | ;before it reaches the round subroutine |
| | ;also ensure that a0 isn't corrupted |
| |
| | |
| | Set up d1 for round subroutine d1 contains the PREC/MODE |
| | information respectively on upper/lower register halves. |
| | |
| bfextu FPCR_MODE(%a6){#2:#2},%d1 |get mode from FPCR |
| | ;mode in lower d1 |
| addl (%a7)+,%d1 |merge PREC/MODE |
| | |
| | WARNING: a0 and d0 are assumed to be intact between the denorm and |
| | round subroutines. All code between these two subroutines |
| | must not corrupt a0 and d0. |
| | |
| | |
| | Perform Round |
| | Input: a0 points to input operand |
| | d0{31:29} has guard, round, sticky |
| | d1{01:00} has rounding mode |
| | d1{17:16} has rounding precision |
| | Output: a0 points to rounded operand |
| | |
| |
| bsrl round |returns rounded denorm at (a0) |
| | |
| | Differentiate between store to memory vs. store to register |
| | |
| unf_store: |
| bsrl g_opcls |returns opclass in d0{2:0} |
| cmpib #0x3,%d0 |
| bnes not_opc011 |
| | |
| | At this point, a store to memory is pending |
| | |
| opc011: |
| bsrl g_dfmtou |
| tstb %d0 |
| beqs ext_opc011 |If extended, do not subtract |
| | ;If destination format is sgl/dbl, |
| tstb LOCAL_HI(%a0) |If rounded result is normal,don't |
| | ;subtract |
| bmis ext_opc011 |
| subqw #1,LOCAL_EX(%a0) |account for denorm bias vs. |
| | ;normalized bias |
| | ; normalized denormalized |
| | ;single $7f $7e |
| | ;double $3ff $3fe |
| | |
| ext_opc011: |
| bsrl store |stores to memory |
| bras unf_done |finish up |
| |
| | |
| | At this point, a store to a float register is pending |
| | |
| not_opc011: |
| bsrl store |stores to float register |
| | ;a0 is not corrupted on a store to a |
| | ;float register. |
| | |
| | Set the condition codes according to result |
| | |
| tstl LOCAL_HI(%a0) |check upper mantissa |
| bnes ck_sgn |
| tstl LOCAL_LO(%a0) |check lower mantissa |
| bnes ck_sgn |
| bsetb #z_bit,FPSR_CC(%a6) |set condition codes if zero |
| ck_sgn: |
| btstb #sign_bit,LOCAL_EX(%a0) |check the sign bit |
| beqs unf_done |
| bsetb #neg_bit,FPSR_CC(%a6) |
| |
| | |
| | Finish. |
| | |
| unf_done: |
| btstb #inex2_bit,FPSR_EXCEPT(%a6) |
| beqs no_aunfl |
| bsetb #aunfl_bit,FPSR_AEXCEPT(%a6) |
| no_aunfl: |
| rts |
| |
| |end |