162306a36Sopenharmony_ci| 262306a36Sopenharmony_ci| x_unfl.sa 3.4 7/1/91 362306a36Sopenharmony_ci| 462306a36Sopenharmony_ci| fpsp_unfl --- FPSP handler for underflow exception 562306a36Sopenharmony_ci| 662306a36Sopenharmony_ci| Trap disabled results 762306a36Sopenharmony_ci| For 881/2 compatibility, sw must denormalize the intermediate 862306a36Sopenharmony_ci| result, then store the result. Denormalization is accomplished 962306a36Sopenharmony_ci| by taking the intermediate result (which is always normalized) and 1062306a36Sopenharmony_ci| shifting the mantissa right while incrementing the exponent until 1162306a36Sopenharmony_ci| it is equal to the denormalized exponent for the destination 1262306a36Sopenharmony_ci| format. After denormalization, the result is rounded to the 1362306a36Sopenharmony_ci| destination format. 1462306a36Sopenharmony_ci| 1562306a36Sopenharmony_ci| Trap enabled results 1662306a36Sopenharmony_ci| All trap disabled code applies. In addition the exceptional 1762306a36Sopenharmony_ci| operand needs to made available to the user with a bias of $6000 1862306a36Sopenharmony_ci| added to the exponent. 1962306a36Sopenharmony_ci| 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci| Copyright (C) Motorola, Inc. 1990 2262306a36Sopenharmony_ci| All Rights Reserved 2362306a36Sopenharmony_ci| 2462306a36Sopenharmony_ci| For details on the license for this file, please see the 2562306a36Sopenharmony_ci| file, README, in this same directory. 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ciX_UNFL: |idnt 2,1 | Motorola 040 Floating Point Software Package 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci |section 8 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include "fpsp.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci |xref denorm 3462306a36Sopenharmony_ci |xref round 3562306a36Sopenharmony_ci |xref store 3662306a36Sopenharmony_ci |xref g_rndpr 3762306a36Sopenharmony_ci |xref g_opcls 3862306a36Sopenharmony_ci |xref g_dfmtou 3962306a36Sopenharmony_ci |xref real_unfl 4062306a36Sopenharmony_ci |xref real_inex 4162306a36Sopenharmony_ci |xref fpsp_done 4262306a36Sopenharmony_ci |xref b1238_fix 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci .global fpsp_unfl 4562306a36Sopenharmony_cifpsp_unfl: 4662306a36Sopenharmony_ci link %a6,#-LOCAL_SIZE 4762306a36Sopenharmony_ci fsave -(%a7) 4862306a36Sopenharmony_ci moveml %d0-%d1/%a0-%a1,USER_DA(%a6) 4962306a36Sopenharmony_ci fmovemx %fp0-%fp3,USER_FP0(%a6) 5062306a36Sopenharmony_ci fmoveml %fpcr/%fpsr/%fpiar,USER_FPCR(%a6) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci| 5362306a36Sopenharmony_ci bsrl unf_res |denormalize, round & store interm op 5462306a36Sopenharmony_ci| 5562306a36Sopenharmony_ci| If underflow exceptions are not enabled, check for inexact 5662306a36Sopenharmony_ci| exception 5762306a36Sopenharmony_ci| 5862306a36Sopenharmony_ci btstb #unfl_bit,FPCR_ENABLE(%a6) 5962306a36Sopenharmony_ci beqs ck_inex 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci btstb #E3,E_BYTE(%a6) 6262306a36Sopenharmony_ci beqs no_e3_1 6362306a36Sopenharmony_ci| 6462306a36Sopenharmony_ci| Clear dirty bit on dest resister in the frame before branching 6562306a36Sopenharmony_ci| to b1238_fix. 6662306a36Sopenharmony_ci| 6762306a36Sopenharmony_ci bfextu CMDREG3B(%a6){#6:#3},%d0 |get dest reg no 6862306a36Sopenharmony_ci bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit 6962306a36Sopenharmony_ci bsrl b1238_fix |test for bug1238 case 7062306a36Sopenharmony_ci movel USER_FPSR(%a6),FPSR_SHADOW(%a6) 7162306a36Sopenharmony_ci orl #sx_mask,E_BYTE(%a6) 7262306a36Sopenharmony_cino_e3_1: 7362306a36Sopenharmony_ci moveml USER_DA(%a6),%d0-%d1/%a0-%a1 7462306a36Sopenharmony_ci fmovemx USER_FP0(%a6),%fp0-%fp3 7562306a36Sopenharmony_ci fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar 7662306a36Sopenharmony_ci frestore (%a7)+ 7762306a36Sopenharmony_ci unlk %a6 7862306a36Sopenharmony_ci bral real_unfl 7962306a36Sopenharmony_ci| 8062306a36Sopenharmony_ci| It is possible to have either inex2 or inex1 exceptions with the 8162306a36Sopenharmony_ci| unfl. If the inex enable bit is set in the FPCR, and either 8262306a36Sopenharmony_ci| inex2 or inex1 occurred, we must clean up and branch to the 8362306a36Sopenharmony_ci| real inex handler. 8462306a36Sopenharmony_ci| 8562306a36Sopenharmony_cick_inex: 8662306a36Sopenharmony_ci moveb FPCR_ENABLE(%a6),%d0 8762306a36Sopenharmony_ci andb FPSR_EXCEPT(%a6),%d0 8862306a36Sopenharmony_ci andib #0x3,%d0 8962306a36Sopenharmony_ci beqs unfl_done 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci| 9262306a36Sopenharmony_ci| Inexact enabled and reported, and we must take an inexact exception 9362306a36Sopenharmony_ci| 9462306a36Sopenharmony_citake_inex: 9562306a36Sopenharmony_ci btstb #E3,E_BYTE(%a6) 9662306a36Sopenharmony_ci beqs no_e3_2 9762306a36Sopenharmony_ci| 9862306a36Sopenharmony_ci| Clear dirty bit on dest resister in the frame before branching 9962306a36Sopenharmony_ci| to b1238_fix. 10062306a36Sopenharmony_ci| 10162306a36Sopenharmony_ci bfextu CMDREG3B(%a6){#6:#3},%d0 |get dest reg no 10262306a36Sopenharmony_ci bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit 10362306a36Sopenharmony_ci bsrl b1238_fix |test for bug1238 case 10462306a36Sopenharmony_ci movel USER_FPSR(%a6),FPSR_SHADOW(%a6) 10562306a36Sopenharmony_ci orl #sx_mask,E_BYTE(%a6) 10662306a36Sopenharmony_cino_e3_2: 10762306a36Sopenharmony_ci moveb #INEX_VEC,EXC_VEC+1(%a6) 10862306a36Sopenharmony_ci moveml USER_DA(%a6),%d0-%d1/%a0-%a1 10962306a36Sopenharmony_ci fmovemx USER_FP0(%a6),%fp0-%fp3 11062306a36Sopenharmony_ci fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar 11162306a36Sopenharmony_ci frestore (%a7)+ 11262306a36Sopenharmony_ci unlk %a6 11362306a36Sopenharmony_ci bral real_inex 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ciunfl_done: 11662306a36Sopenharmony_ci bclrb #E3,E_BYTE(%a6) 11762306a36Sopenharmony_ci beqs e1_set |if set then branch 11862306a36Sopenharmony_ci| 11962306a36Sopenharmony_ci| Clear dirty bit on dest resister in the frame before branching 12062306a36Sopenharmony_ci| to b1238_fix. 12162306a36Sopenharmony_ci| 12262306a36Sopenharmony_ci bfextu CMDREG3B(%a6){#6:#3},%d0 |get dest reg no 12362306a36Sopenharmony_ci bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit 12462306a36Sopenharmony_ci bsrl b1238_fix |test for bug1238 case 12562306a36Sopenharmony_ci movel USER_FPSR(%a6),FPSR_SHADOW(%a6) 12662306a36Sopenharmony_ci orl #sx_mask,E_BYTE(%a6) 12762306a36Sopenharmony_ci moveml USER_DA(%a6),%d0-%d1/%a0-%a1 12862306a36Sopenharmony_ci fmovemx USER_FP0(%a6),%fp0-%fp3 12962306a36Sopenharmony_ci fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar 13062306a36Sopenharmony_ci frestore (%a7)+ 13162306a36Sopenharmony_ci unlk %a6 13262306a36Sopenharmony_ci bral fpsp_done 13362306a36Sopenharmony_cie1_set: 13462306a36Sopenharmony_ci moveml USER_DA(%a6),%d0-%d1/%a0-%a1 13562306a36Sopenharmony_ci fmovemx USER_FP0(%a6),%fp0-%fp3 13662306a36Sopenharmony_ci fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar 13762306a36Sopenharmony_ci unlk %a6 13862306a36Sopenharmony_ci bral fpsp_done 13962306a36Sopenharmony_ci| 14062306a36Sopenharmony_ci| unf_res --- underflow result calculation 14162306a36Sopenharmony_ci| 14262306a36Sopenharmony_ciunf_res: 14362306a36Sopenharmony_ci bsrl g_rndpr |returns RND_PREC in d0 0=ext, 14462306a36Sopenharmony_ci| ;1=sgl, 2=dbl 14562306a36Sopenharmony_ci| ;we need the RND_PREC in the 14662306a36Sopenharmony_ci| ;upper word for round 14762306a36Sopenharmony_ci movew #0,-(%a7) 14862306a36Sopenharmony_ci movew %d0,-(%a7) |copy RND_PREC to stack 14962306a36Sopenharmony_ci| 15062306a36Sopenharmony_ci| 15162306a36Sopenharmony_ci| If the exception bit set is E3, the exceptional operand from the 15262306a36Sopenharmony_ci| fpu is in WBTEMP; else it is in FPTEMP. 15362306a36Sopenharmony_ci| 15462306a36Sopenharmony_ci btstb #E3,E_BYTE(%a6) 15562306a36Sopenharmony_ci beqs unf_E1 15662306a36Sopenharmony_ciunf_E3: 15762306a36Sopenharmony_ci lea WBTEMP(%a6),%a0 |a0 now points to operand 15862306a36Sopenharmony_ci| 15962306a36Sopenharmony_ci| Test for fsgldiv and fsglmul. If the inst was one of these, then 16062306a36Sopenharmony_ci| force the precision to extended for the denorm routine. Use 16162306a36Sopenharmony_ci| the user's precision for the round routine. 16262306a36Sopenharmony_ci| 16362306a36Sopenharmony_ci movew CMDREG3B(%a6),%d1 |check for fsgldiv or fsglmul 16462306a36Sopenharmony_ci andiw #0x7f,%d1 16562306a36Sopenharmony_ci cmpiw #0x30,%d1 |check for sgldiv 16662306a36Sopenharmony_ci beqs unf_sgl 16762306a36Sopenharmony_ci cmpiw #0x33,%d1 |check for sglmul 16862306a36Sopenharmony_ci bnes unf_cont |if not, use fpcr prec in round 16962306a36Sopenharmony_ciunf_sgl: 17062306a36Sopenharmony_ci clrl %d0 17162306a36Sopenharmony_ci movew #0x1,(%a7) |override g_rndpr precision 17262306a36Sopenharmony_ci| ;force single 17362306a36Sopenharmony_ci bras unf_cont 17462306a36Sopenharmony_ciunf_E1: 17562306a36Sopenharmony_ci lea FPTEMP(%a6),%a0 |a0 now points to operand 17662306a36Sopenharmony_ciunf_cont: 17762306a36Sopenharmony_ci bclrb #sign_bit,LOCAL_EX(%a0) |clear sign bit 17862306a36Sopenharmony_ci sne LOCAL_SGN(%a0) |store sign 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci bsrl denorm |returns denorm, a0 points to it 18162306a36Sopenharmony_ci| 18262306a36Sopenharmony_ci| WARNING: 18362306a36Sopenharmony_ci| ;d0 has guard,round sticky bit 18462306a36Sopenharmony_ci| ;make sure that it is not corrupted 18562306a36Sopenharmony_ci| ;before it reaches the round subroutine 18662306a36Sopenharmony_ci| ;also ensure that a0 isn't corrupted 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci| 18962306a36Sopenharmony_ci| Set up d1 for round subroutine d1 contains the PREC/MODE 19062306a36Sopenharmony_ci| information respectively on upper/lower register halves. 19162306a36Sopenharmony_ci| 19262306a36Sopenharmony_ci bfextu FPCR_MODE(%a6){#2:#2},%d1 |get mode from FPCR 19362306a36Sopenharmony_ci| ;mode in lower d1 19462306a36Sopenharmony_ci addl (%a7)+,%d1 |merge PREC/MODE 19562306a36Sopenharmony_ci| 19662306a36Sopenharmony_ci| WARNING: a0 and d0 are assumed to be intact between the denorm and 19762306a36Sopenharmony_ci| round subroutines. All code between these two subroutines 19862306a36Sopenharmony_ci| must not corrupt a0 and d0. 19962306a36Sopenharmony_ci| 20062306a36Sopenharmony_ci| 20162306a36Sopenharmony_ci| Perform Round 20262306a36Sopenharmony_ci| Input: a0 points to input operand 20362306a36Sopenharmony_ci| d0{31:29} has guard, round, sticky 20462306a36Sopenharmony_ci| d1{01:00} has rounding mode 20562306a36Sopenharmony_ci| d1{17:16} has rounding precision 20662306a36Sopenharmony_ci| Output: a0 points to rounded operand 20762306a36Sopenharmony_ci| 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci bsrl round |returns rounded denorm at (a0) 21062306a36Sopenharmony_ci| 21162306a36Sopenharmony_ci| Differentiate between store to memory vs. store to register 21262306a36Sopenharmony_ci| 21362306a36Sopenharmony_ciunf_store: 21462306a36Sopenharmony_ci bsrl g_opcls |returns opclass in d0{2:0} 21562306a36Sopenharmony_ci cmpib #0x3,%d0 21662306a36Sopenharmony_ci bnes not_opc011 21762306a36Sopenharmony_ci| 21862306a36Sopenharmony_ci| At this point, a store to memory is pending 21962306a36Sopenharmony_ci| 22062306a36Sopenharmony_ciopc011: 22162306a36Sopenharmony_ci bsrl g_dfmtou 22262306a36Sopenharmony_ci tstb %d0 22362306a36Sopenharmony_ci beqs ext_opc011 |If extended, do not subtract 22462306a36Sopenharmony_ci| ;If destination format is sgl/dbl, 22562306a36Sopenharmony_ci tstb LOCAL_HI(%a0) |If rounded result is normal,don't 22662306a36Sopenharmony_ci| ;subtract 22762306a36Sopenharmony_ci bmis ext_opc011 22862306a36Sopenharmony_ci subqw #1,LOCAL_EX(%a0) |account for denorm bias vs. 22962306a36Sopenharmony_ci| ;normalized bias 23062306a36Sopenharmony_ci| ; normalized denormalized 23162306a36Sopenharmony_ci| ;single $7f $7e 23262306a36Sopenharmony_ci| ;double $3ff $3fe 23362306a36Sopenharmony_ci| 23462306a36Sopenharmony_ciext_opc011: 23562306a36Sopenharmony_ci bsrl store |stores to memory 23662306a36Sopenharmony_ci bras unf_done |finish up 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci| 23962306a36Sopenharmony_ci| At this point, a store to a float register is pending 24062306a36Sopenharmony_ci| 24162306a36Sopenharmony_cinot_opc011: 24262306a36Sopenharmony_ci bsrl store |stores to float register 24362306a36Sopenharmony_ci| ;a0 is not corrupted on a store to a 24462306a36Sopenharmony_ci| ;float register. 24562306a36Sopenharmony_ci| 24662306a36Sopenharmony_ci| Set the condition codes according to result 24762306a36Sopenharmony_ci| 24862306a36Sopenharmony_ci tstl LOCAL_HI(%a0) |check upper mantissa 24962306a36Sopenharmony_ci bnes ck_sgn 25062306a36Sopenharmony_ci tstl LOCAL_LO(%a0) |check lower mantissa 25162306a36Sopenharmony_ci bnes ck_sgn 25262306a36Sopenharmony_ci bsetb #z_bit,FPSR_CC(%a6) |set condition codes if zero 25362306a36Sopenharmony_cick_sgn: 25462306a36Sopenharmony_ci btstb #sign_bit,LOCAL_EX(%a0) |check the sign bit 25562306a36Sopenharmony_ci beqs unf_done 25662306a36Sopenharmony_ci bsetb #neg_bit,FPSR_CC(%a6) 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci| 25962306a36Sopenharmony_ci| Finish. 26062306a36Sopenharmony_ci| 26162306a36Sopenharmony_ciunf_done: 26262306a36Sopenharmony_ci btstb #inex2_bit,FPSR_EXCEPT(%a6) 26362306a36Sopenharmony_ci beqs no_aunfl 26462306a36Sopenharmony_ci bsetb #aunfl_bit,FPSR_AEXCEPT(%a6) 26562306a36Sopenharmony_cino_aunfl: 26662306a36Sopenharmony_ci rts 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci |end 269