162306a36Sopenharmony_ci| 262306a36Sopenharmony_ci| round.sa 3.4 7/29/91 362306a36Sopenharmony_ci| 462306a36Sopenharmony_ci| handle rounding and normalization tasks 562306a36Sopenharmony_ci| 662306a36Sopenharmony_ci| 762306a36Sopenharmony_ci| 862306a36Sopenharmony_ci| Copyright (C) Motorola, Inc. 1990 962306a36Sopenharmony_ci| All Rights Reserved 1062306a36Sopenharmony_ci| 1162306a36Sopenharmony_ci| For details on the license for this file, please see the 1262306a36Sopenharmony_ci| file, README, in this same directory. 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci|ROUND idnt 2,1 | Motorola 040 Floating Point Software Package 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci |section 8 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "fpsp.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci| 2162306a36Sopenharmony_ci| round --- round result according to precision/mode 2262306a36Sopenharmony_ci| 2362306a36Sopenharmony_ci| a0 points to the input operand in the internal extended format 2462306a36Sopenharmony_ci| d1(high word) contains rounding precision: 2562306a36Sopenharmony_ci| ext = $0000xxxx 2662306a36Sopenharmony_ci| sgl = $0001xxxx 2762306a36Sopenharmony_ci| dbl = $0002xxxx 2862306a36Sopenharmony_ci| d1(low word) contains rounding mode: 2962306a36Sopenharmony_ci| RN = $xxxx0000 3062306a36Sopenharmony_ci| RZ = $xxxx0001 3162306a36Sopenharmony_ci| RM = $xxxx0010 3262306a36Sopenharmony_ci| RP = $xxxx0011 3362306a36Sopenharmony_ci| d0{31:29} contains the g,r,s bits (extended) 3462306a36Sopenharmony_ci| 3562306a36Sopenharmony_ci| On return the value pointed to by a0 is correctly rounded, 3662306a36Sopenharmony_ci| a0 is preserved and the g-r-s bits in d0 are cleared. 3762306a36Sopenharmony_ci| The result is not typed - the tag field is invalid. The 3862306a36Sopenharmony_ci| result is still in the internal extended format. 3962306a36Sopenharmony_ci| 4062306a36Sopenharmony_ci| The INEX bit of USER_FPSR will be set if the rounded result was 4162306a36Sopenharmony_ci| inexact (i.e. if any of the g-r-s bits were set). 4262306a36Sopenharmony_ci| 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci .global round 4562306a36Sopenharmony_ciround: 4662306a36Sopenharmony_ci| If g=r=s=0 then result is exact and round is done, else set 4762306a36Sopenharmony_ci| the inex flag in status reg and continue. 4862306a36Sopenharmony_ci| 4962306a36Sopenharmony_ci bsrs ext_grs |this subroutine looks at the 5062306a36Sopenharmony_ci| :rounding precision and sets 5162306a36Sopenharmony_ci| ;the appropriate g-r-s bits. 5262306a36Sopenharmony_ci tstl %d0 |if grs are zero, go force 5362306a36Sopenharmony_ci bne rnd_cont |lower bits to zero for size 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci swap %d1 |set up d1.w for round prec. 5662306a36Sopenharmony_ci bra truncate 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cirnd_cont: 5962306a36Sopenharmony_ci| 6062306a36Sopenharmony_ci| Use rounding mode as an index into a jump table for these modes. 6162306a36Sopenharmony_ci| 6262306a36Sopenharmony_ci orl #inx2a_mask,USER_FPSR(%a6) |set inex2/ainex 6362306a36Sopenharmony_ci lea mode_tab,%a1 6462306a36Sopenharmony_ci movel (%a1,%d1.w*4),%a1 6562306a36Sopenharmony_ci jmp (%a1) 6662306a36Sopenharmony_ci| 6762306a36Sopenharmony_ci| Jump table indexed by rounding mode in d1.w. All following assumes 6862306a36Sopenharmony_ci| grs != 0. 6962306a36Sopenharmony_ci| 7062306a36Sopenharmony_cimode_tab: 7162306a36Sopenharmony_ci .long rnd_near 7262306a36Sopenharmony_ci .long rnd_zero 7362306a36Sopenharmony_ci .long rnd_mnus 7462306a36Sopenharmony_ci .long rnd_plus 7562306a36Sopenharmony_ci| 7662306a36Sopenharmony_ci| ROUND PLUS INFINITY 7762306a36Sopenharmony_ci| 7862306a36Sopenharmony_ci| If sign of fp number = 0 (positive), then add 1 to l. 7962306a36Sopenharmony_ci| 8062306a36Sopenharmony_cirnd_plus: 8162306a36Sopenharmony_ci swap %d1 |set up d1 for round prec. 8262306a36Sopenharmony_ci tstb LOCAL_SGN(%a0) |check for sign 8362306a36Sopenharmony_ci bmi truncate |if positive then truncate 8462306a36Sopenharmony_ci movel #0xffffffff,%d0 |force g,r,s to be all f's 8562306a36Sopenharmony_ci lea add_to_l,%a1 8662306a36Sopenharmony_ci movel (%a1,%d1.w*4),%a1 8762306a36Sopenharmony_ci jmp (%a1) 8862306a36Sopenharmony_ci| 8962306a36Sopenharmony_ci| ROUND MINUS INFINITY 9062306a36Sopenharmony_ci| 9162306a36Sopenharmony_ci| If sign of fp number = 1 (negative), then add 1 to l. 9262306a36Sopenharmony_ci| 9362306a36Sopenharmony_cirnd_mnus: 9462306a36Sopenharmony_ci swap %d1 |set up d1 for round prec. 9562306a36Sopenharmony_ci tstb LOCAL_SGN(%a0) |check for sign 9662306a36Sopenharmony_ci bpl truncate |if negative then truncate 9762306a36Sopenharmony_ci movel #0xffffffff,%d0 |force g,r,s to be all f's 9862306a36Sopenharmony_ci lea add_to_l,%a1 9962306a36Sopenharmony_ci movel (%a1,%d1.w*4),%a1 10062306a36Sopenharmony_ci jmp (%a1) 10162306a36Sopenharmony_ci| 10262306a36Sopenharmony_ci| ROUND ZERO 10362306a36Sopenharmony_ci| 10462306a36Sopenharmony_ci| Always truncate. 10562306a36Sopenharmony_cirnd_zero: 10662306a36Sopenharmony_ci swap %d1 |set up d1 for round prec. 10762306a36Sopenharmony_ci bra truncate 10862306a36Sopenharmony_ci| 10962306a36Sopenharmony_ci| 11062306a36Sopenharmony_ci| ROUND NEAREST 11162306a36Sopenharmony_ci| 11262306a36Sopenharmony_ci| If (g=1), then add 1 to l and if (r=s=0), then clear l 11362306a36Sopenharmony_ci| Note that this will round to even in case of a tie. 11462306a36Sopenharmony_ci| 11562306a36Sopenharmony_cirnd_near: 11662306a36Sopenharmony_ci swap %d1 |set up d1 for round prec. 11762306a36Sopenharmony_ci asll #1,%d0 |shift g-bit to c-bit 11862306a36Sopenharmony_ci bcc truncate |if (g=1) then 11962306a36Sopenharmony_ci lea add_to_l,%a1 12062306a36Sopenharmony_ci movel (%a1,%d1.w*4),%a1 12162306a36Sopenharmony_ci jmp (%a1) 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci| 12462306a36Sopenharmony_ci| ext_grs --- extract guard, round and sticky bits 12562306a36Sopenharmony_ci| 12662306a36Sopenharmony_ci| Input: d1 = PREC:ROUND 12762306a36Sopenharmony_ci| Output: d0{31:29}= guard, round, sticky 12862306a36Sopenharmony_ci| 12962306a36Sopenharmony_ci| The ext_grs extract the guard/round/sticky bits according to the 13062306a36Sopenharmony_ci| selected rounding precision. It is called by the round subroutine 13162306a36Sopenharmony_ci| only. All registers except d0 are kept intact. d0 becomes an 13262306a36Sopenharmony_ci| updated guard,round,sticky in d0{31:29} 13362306a36Sopenharmony_ci| 13462306a36Sopenharmony_ci| Notes: the ext_grs uses the round PREC, and therefore has to swap d1 13562306a36Sopenharmony_ci| prior to usage, and needs to restore d1 to original. 13662306a36Sopenharmony_ci| 13762306a36Sopenharmony_ciext_grs: 13862306a36Sopenharmony_ci swap %d1 |have d1.w point to round precision 13962306a36Sopenharmony_ci cmpiw #0,%d1 14062306a36Sopenharmony_ci bnes sgl_or_dbl 14162306a36Sopenharmony_ci bras end_ext_grs 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cisgl_or_dbl: 14462306a36Sopenharmony_ci moveml %d2/%d3,-(%a7) |make some temp registers 14562306a36Sopenharmony_ci cmpiw #1,%d1 14662306a36Sopenharmony_ci bnes grs_dbl 14762306a36Sopenharmony_cigrs_sgl: 14862306a36Sopenharmony_ci bfextu LOCAL_HI(%a0){#24:#2},%d3 |sgl prec. g-r are 2 bits right 14962306a36Sopenharmony_ci movel #30,%d2 |of the sgl prec. limits 15062306a36Sopenharmony_ci lsll %d2,%d3 |shift g-r bits to MSB of d3 15162306a36Sopenharmony_ci movel LOCAL_HI(%a0),%d2 |get word 2 for s-bit test 15262306a36Sopenharmony_ci andil #0x0000003f,%d2 |s bit is the or of all other 15362306a36Sopenharmony_ci bnes st_stky |bits to the right of g-r 15462306a36Sopenharmony_ci tstl LOCAL_LO(%a0) |test lower mantissa 15562306a36Sopenharmony_ci bnes st_stky |if any are set, set sticky 15662306a36Sopenharmony_ci tstl %d0 |test original g,r,s 15762306a36Sopenharmony_ci bnes st_stky |if any are set, set sticky 15862306a36Sopenharmony_ci bras end_sd |if words 3 and 4 are clr, exit 15962306a36Sopenharmony_cigrs_dbl: 16062306a36Sopenharmony_ci bfextu LOCAL_LO(%a0){#21:#2},%d3 |dbl-prec. g-r are 2 bits right 16162306a36Sopenharmony_ci movel #30,%d2 |of the dbl prec. limits 16262306a36Sopenharmony_ci lsll %d2,%d3 |shift g-r bits to the MSB of d3 16362306a36Sopenharmony_ci movel LOCAL_LO(%a0),%d2 |get lower mantissa for s-bit test 16462306a36Sopenharmony_ci andil #0x000001ff,%d2 |s bit is the or-ing of all 16562306a36Sopenharmony_ci bnes st_stky |other bits to the right of g-r 16662306a36Sopenharmony_ci tstl %d0 |test word original g,r,s 16762306a36Sopenharmony_ci bnes st_stky |if any are set, set sticky 16862306a36Sopenharmony_ci bras end_sd |if clear, exit 16962306a36Sopenharmony_cist_stky: 17062306a36Sopenharmony_ci bset #rnd_stky_bit,%d3 17162306a36Sopenharmony_ciend_sd: 17262306a36Sopenharmony_ci movel %d3,%d0 |return grs to d0 17362306a36Sopenharmony_ci moveml (%a7)+,%d2/%d3 |restore scratch registers 17462306a36Sopenharmony_ciend_ext_grs: 17562306a36Sopenharmony_ci swap %d1 |restore d1 to original 17662306a36Sopenharmony_ci rts 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci|******************* Local Equates 17962306a36Sopenharmony_ci .set ad_1_sgl,0x00000100 | constant to add 1 to l-bit in sgl prec 18062306a36Sopenharmony_ci .set ad_1_dbl,0x00000800 | constant to add 1 to l-bit in dbl prec 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci|Jump table for adding 1 to the l-bit indexed by rnd prec 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ciadd_to_l: 18662306a36Sopenharmony_ci .long add_ext 18762306a36Sopenharmony_ci .long add_sgl 18862306a36Sopenharmony_ci .long add_dbl 18962306a36Sopenharmony_ci .long add_dbl 19062306a36Sopenharmony_ci| 19162306a36Sopenharmony_ci| ADD SINGLE 19262306a36Sopenharmony_ci| 19362306a36Sopenharmony_ciadd_sgl: 19462306a36Sopenharmony_ci addl #ad_1_sgl,LOCAL_HI(%a0) 19562306a36Sopenharmony_ci bccs scc_clr |no mantissa overflow 19662306a36Sopenharmony_ci roxrw LOCAL_HI(%a0) |shift v-bit back in 19762306a36Sopenharmony_ci roxrw LOCAL_HI+2(%a0) |shift v-bit back in 19862306a36Sopenharmony_ci addw #0x1,LOCAL_EX(%a0) |and incr exponent 19962306a36Sopenharmony_ciscc_clr: 20062306a36Sopenharmony_ci tstl %d0 |test for rs = 0 20162306a36Sopenharmony_ci bnes sgl_done 20262306a36Sopenharmony_ci andiw #0xfe00,LOCAL_HI+2(%a0) |clear the l-bit 20362306a36Sopenharmony_cisgl_done: 20462306a36Sopenharmony_ci andil #0xffffff00,LOCAL_HI(%a0) |truncate bits beyond sgl limit 20562306a36Sopenharmony_ci clrl LOCAL_LO(%a0) |clear d2 20662306a36Sopenharmony_ci rts 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci| 20962306a36Sopenharmony_ci| ADD EXTENDED 21062306a36Sopenharmony_ci| 21162306a36Sopenharmony_ciadd_ext: 21262306a36Sopenharmony_ci addql #1,LOCAL_LO(%a0) |add 1 to l-bit 21362306a36Sopenharmony_ci bccs xcc_clr |test for carry out 21462306a36Sopenharmony_ci addql #1,LOCAL_HI(%a0) |propagate carry 21562306a36Sopenharmony_ci bccs xcc_clr 21662306a36Sopenharmony_ci roxrw LOCAL_HI(%a0) |mant is 0 so restore v-bit 21762306a36Sopenharmony_ci roxrw LOCAL_HI+2(%a0) |mant is 0 so restore v-bit 21862306a36Sopenharmony_ci roxrw LOCAL_LO(%a0) 21962306a36Sopenharmony_ci roxrw LOCAL_LO+2(%a0) 22062306a36Sopenharmony_ci addw #0x1,LOCAL_EX(%a0) |and inc exp 22162306a36Sopenharmony_cixcc_clr: 22262306a36Sopenharmony_ci tstl %d0 |test rs = 0 22362306a36Sopenharmony_ci bnes add_ext_done 22462306a36Sopenharmony_ci andib #0xfe,LOCAL_LO+3(%a0) |clear the l bit 22562306a36Sopenharmony_ciadd_ext_done: 22662306a36Sopenharmony_ci rts 22762306a36Sopenharmony_ci| 22862306a36Sopenharmony_ci| ADD DOUBLE 22962306a36Sopenharmony_ci| 23062306a36Sopenharmony_ciadd_dbl: 23162306a36Sopenharmony_ci addl #ad_1_dbl,LOCAL_LO(%a0) 23262306a36Sopenharmony_ci bccs dcc_clr 23362306a36Sopenharmony_ci addql #1,LOCAL_HI(%a0) |propagate carry 23462306a36Sopenharmony_ci bccs dcc_clr 23562306a36Sopenharmony_ci roxrw LOCAL_HI(%a0) |mant is 0 so restore v-bit 23662306a36Sopenharmony_ci roxrw LOCAL_HI+2(%a0) |mant is 0 so restore v-bit 23762306a36Sopenharmony_ci roxrw LOCAL_LO(%a0) 23862306a36Sopenharmony_ci roxrw LOCAL_LO+2(%a0) 23962306a36Sopenharmony_ci addw #0x1,LOCAL_EX(%a0) |incr exponent 24062306a36Sopenharmony_cidcc_clr: 24162306a36Sopenharmony_ci tstl %d0 |test for rs = 0 24262306a36Sopenharmony_ci bnes dbl_done 24362306a36Sopenharmony_ci andiw #0xf000,LOCAL_LO+2(%a0) |clear the l-bit 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cidbl_done: 24662306a36Sopenharmony_ci andil #0xfffff800,LOCAL_LO(%a0) |truncate bits beyond dbl limit 24762306a36Sopenharmony_ci rts 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cierror: 25062306a36Sopenharmony_ci rts 25162306a36Sopenharmony_ci| 25262306a36Sopenharmony_ci| Truncate all other bits 25362306a36Sopenharmony_ci| 25462306a36Sopenharmony_citrunct: 25562306a36Sopenharmony_ci .long end_rnd 25662306a36Sopenharmony_ci .long sgl_done 25762306a36Sopenharmony_ci .long dbl_done 25862306a36Sopenharmony_ci .long dbl_done 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_citruncate: 26162306a36Sopenharmony_ci lea trunct,%a1 26262306a36Sopenharmony_ci movel (%a1,%d1.w*4),%a1 26362306a36Sopenharmony_ci jmp (%a1) 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ciend_rnd: 26662306a36Sopenharmony_ci rts 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci| 26962306a36Sopenharmony_ci| NORMALIZE 27062306a36Sopenharmony_ci| 27162306a36Sopenharmony_ci| These routines (nrm_zero & nrm_set) normalize the unnorm. This 27262306a36Sopenharmony_ci| is done by shifting the mantissa left while decrementing the 27362306a36Sopenharmony_ci| exponent. 27462306a36Sopenharmony_ci| 27562306a36Sopenharmony_ci| NRM_SET shifts and decrements until there is a 1 set in the integer 27662306a36Sopenharmony_ci| bit of the mantissa (msb in d1). 27762306a36Sopenharmony_ci| 27862306a36Sopenharmony_ci| NRM_ZERO shifts and decrements until there is a 1 set in the integer 27962306a36Sopenharmony_ci| bit of the mantissa (msb in d1) unless this would mean the exponent 28062306a36Sopenharmony_ci| would go less than 0. In that case the number becomes a denorm - the 28162306a36Sopenharmony_ci| exponent (d0) is set to 0 and the mantissa (d1 & d2) is not 28262306a36Sopenharmony_ci| normalized. 28362306a36Sopenharmony_ci| 28462306a36Sopenharmony_ci| Note that both routines have been optimized (for the worst case) and 28562306a36Sopenharmony_ci| therefore do not have the easy to follow decrement/shift loop. 28662306a36Sopenharmony_ci| 28762306a36Sopenharmony_ci| NRM_ZERO 28862306a36Sopenharmony_ci| 28962306a36Sopenharmony_ci| Distance to first 1 bit in mantissa = X 29062306a36Sopenharmony_ci| Distance to 0 from exponent = Y 29162306a36Sopenharmony_ci| If X < Y 29262306a36Sopenharmony_ci| Then 29362306a36Sopenharmony_ci| nrm_set 29462306a36Sopenharmony_ci| Else 29562306a36Sopenharmony_ci| shift mantissa by Y 29662306a36Sopenharmony_ci| set exponent = 0 29762306a36Sopenharmony_ci| 29862306a36Sopenharmony_ci|input: 29962306a36Sopenharmony_ci| FP_SCR1 = exponent, ms mantissa part, ls mantissa part 30062306a36Sopenharmony_ci|output: 30162306a36Sopenharmony_ci| L_SCR1{4} = fpte15 or ete15 bit 30262306a36Sopenharmony_ci| 30362306a36Sopenharmony_ci .global nrm_zero 30462306a36Sopenharmony_cinrm_zero: 30562306a36Sopenharmony_ci movew LOCAL_EX(%a0),%d0 30662306a36Sopenharmony_ci cmpw #64,%d0 |see if exp > 64 30762306a36Sopenharmony_ci bmis d0_less 30862306a36Sopenharmony_ci bsr nrm_set |exp > 64 so exp won't exceed 0 30962306a36Sopenharmony_ci rts 31062306a36Sopenharmony_cid0_less: 31162306a36Sopenharmony_ci moveml %d2/%d3/%d5/%d6,-(%a7) 31262306a36Sopenharmony_ci movel LOCAL_HI(%a0),%d1 31362306a36Sopenharmony_ci movel LOCAL_LO(%a0),%d2 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci bfffo %d1{#0:#32},%d3 |get the distance to the first 1 31662306a36Sopenharmony_ci| ;in ms mant 31762306a36Sopenharmony_ci beqs ms_clr |branch if no bits were set 31862306a36Sopenharmony_ci cmpw %d3,%d0 |of X>Y 31962306a36Sopenharmony_ci bmis greater |then exp will go past 0 (neg) if 32062306a36Sopenharmony_ci| ;it is just shifted 32162306a36Sopenharmony_ci bsr nrm_set |else exp won't go past 0 32262306a36Sopenharmony_ci moveml (%a7)+,%d2/%d3/%d5/%d6 32362306a36Sopenharmony_ci rts 32462306a36Sopenharmony_cigreater: 32562306a36Sopenharmony_ci movel %d2,%d6 |save ls mant in d6 32662306a36Sopenharmony_ci lsll %d0,%d2 |shift ls mant by count 32762306a36Sopenharmony_ci lsll %d0,%d1 |shift ms mant by count 32862306a36Sopenharmony_ci movel #32,%d5 32962306a36Sopenharmony_ci subl %d0,%d5 |make op a denorm by shifting bits 33062306a36Sopenharmony_ci lsrl %d5,%d6 |by the number in the exp, then 33162306a36Sopenharmony_ci| ;set exp = 0. 33262306a36Sopenharmony_ci orl %d6,%d1 |shift the ls mant bits into the ms mant 33362306a36Sopenharmony_ci movel #0,%d0 |same as if decremented exp to 0 33462306a36Sopenharmony_ci| ;while shifting 33562306a36Sopenharmony_ci movew %d0,LOCAL_EX(%a0) 33662306a36Sopenharmony_ci movel %d1,LOCAL_HI(%a0) 33762306a36Sopenharmony_ci movel %d2,LOCAL_LO(%a0) 33862306a36Sopenharmony_ci moveml (%a7)+,%d2/%d3/%d5/%d6 33962306a36Sopenharmony_ci rts 34062306a36Sopenharmony_cims_clr: 34162306a36Sopenharmony_ci bfffo %d2{#0:#32},%d3 |check if any bits set in ls mant 34262306a36Sopenharmony_ci beqs all_clr |branch if none set 34362306a36Sopenharmony_ci addw #32,%d3 34462306a36Sopenharmony_ci cmpw %d3,%d0 |if X>Y 34562306a36Sopenharmony_ci bmis greater |then branch 34662306a36Sopenharmony_ci bsr nrm_set |else exp won't go past 0 34762306a36Sopenharmony_ci moveml (%a7)+,%d2/%d3/%d5/%d6 34862306a36Sopenharmony_ci rts 34962306a36Sopenharmony_ciall_clr: 35062306a36Sopenharmony_ci movew #0,LOCAL_EX(%a0) |no mantissa bits set. Set exp = 0. 35162306a36Sopenharmony_ci moveml (%a7)+,%d2/%d3/%d5/%d6 35262306a36Sopenharmony_ci rts 35362306a36Sopenharmony_ci| 35462306a36Sopenharmony_ci| NRM_SET 35562306a36Sopenharmony_ci| 35662306a36Sopenharmony_ci .global nrm_set 35762306a36Sopenharmony_cinrm_set: 35862306a36Sopenharmony_ci movel %d7,-(%a7) 35962306a36Sopenharmony_ci bfffo LOCAL_HI(%a0){#0:#32},%d7 |find first 1 in ms mant to d7) 36062306a36Sopenharmony_ci beqs lower |branch if ms mant is all 0's 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci movel %d6,-(%a7) 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci subw %d7,LOCAL_EX(%a0) |sub exponent by count 36562306a36Sopenharmony_ci movel LOCAL_HI(%a0),%d0 |d0 has ms mant 36662306a36Sopenharmony_ci movel LOCAL_LO(%a0),%d1 |d1 has ls mant 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci lsll %d7,%d0 |shift first 1 to j bit position 36962306a36Sopenharmony_ci movel %d1,%d6 |copy ls mant into d6 37062306a36Sopenharmony_ci lsll %d7,%d6 |shift ls mant by count 37162306a36Sopenharmony_ci movel %d6,LOCAL_LO(%a0) |store ls mant into memory 37262306a36Sopenharmony_ci moveql #32,%d6 37362306a36Sopenharmony_ci subl %d7,%d6 |continue shift 37462306a36Sopenharmony_ci lsrl %d6,%d1 |shift off all bits but those that will 37562306a36Sopenharmony_ci| ;be shifted into ms mant 37662306a36Sopenharmony_ci orl %d1,%d0 |shift the ls mant bits into the ms mant 37762306a36Sopenharmony_ci movel %d0,LOCAL_HI(%a0) |store ms mant into memory 37862306a36Sopenharmony_ci moveml (%a7)+,%d7/%d6 |restore registers 37962306a36Sopenharmony_ci rts 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci| 38262306a36Sopenharmony_ci| We get here if ms mant was = 0, and we assume ls mant has bits 38362306a36Sopenharmony_ci| set (otherwise this would have been tagged a zero not a denorm). 38462306a36Sopenharmony_ci| 38562306a36Sopenharmony_cilower: 38662306a36Sopenharmony_ci movew LOCAL_EX(%a0),%d0 |d0 has exponent 38762306a36Sopenharmony_ci movel LOCAL_LO(%a0),%d1 |d1 has ls mant 38862306a36Sopenharmony_ci subw #32,%d0 |account for ms mant being all zeros 38962306a36Sopenharmony_ci bfffo %d1{#0:#32},%d7 |find first 1 in ls mant to d7) 39062306a36Sopenharmony_ci subw %d7,%d0 |subtract shift count from exp 39162306a36Sopenharmony_ci lsll %d7,%d1 |shift first 1 to integer bit in ms mant 39262306a36Sopenharmony_ci movew %d0,LOCAL_EX(%a0) |store ms mant 39362306a36Sopenharmony_ci movel %d1,LOCAL_HI(%a0) |store exp 39462306a36Sopenharmony_ci clrl LOCAL_LO(%a0) |clear ls mant 39562306a36Sopenharmony_ci movel (%a7)+,%d7 39662306a36Sopenharmony_ci rts 39762306a36Sopenharmony_ci| 39862306a36Sopenharmony_ci| denorm --- denormalize an intermediate result 39962306a36Sopenharmony_ci| 40062306a36Sopenharmony_ci| Used by underflow. 40162306a36Sopenharmony_ci| 40262306a36Sopenharmony_ci| Input: 40362306a36Sopenharmony_ci| a0 points to the operand to be denormalized 40462306a36Sopenharmony_ci| (in the internal extended format) 40562306a36Sopenharmony_ci| 40662306a36Sopenharmony_ci| d0: rounding precision 40762306a36Sopenharmony_ci| Output: 40862306a36Sopenharmony_ci| a0 points to the denormalized result 40962306a36Sopenharmony_ci| (in the internal extended format) 41062306a36Sopenharmony_ci| 41162306a36Sopenharmony_ci| d0 is guard,round,sticky 41262306a36Sopenharmony_ci| 41362306a36Sopenharmony_ci| d0 comes into this routine with the rounding precision. It 41462306a36Sopenharmony_ci| is then loaded with the denormalized exponent threshold for the 41562306a36Sopenharmony_ci| rounding precision. 41662306a36Sopenharmony_ci| 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci .global denorm 41962306a36Sopenharmony_cidenorm: 42062306a36Sopenharmony_ci btstb #6,LOCAL_EX(%a0) |check for exponents between $7fff-$4000 42162306a36Sopenharmony_ci beqs no_sgn_ext 42262306a36Sopenharmony_ci bsetb #7,LOCAL_EX(%a0) |sign extend if it is so 42362306a36Sopenharmony_cino_sgn_ext: 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci cmpib #0,%d0 |if 0 then extended precision 42662306a36Sopenharmony_ci bnes not_ext |else branch 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci clrl %d1 |load d1 with ext threshold 42962306a36Sopenharmony_ci clrl %d0 |clear the sticky flag 43062306a36Sopenharmony_ci bsr dnrm_lp |denormalize the number 43162306a36Sopenharmony_ci tstb %d1 |check for inex 43262306a36Sopenharmony_ci beq no_inex |if clr, no inex 43362306a36Sopenharmony_ci bras dnrm_inex |if set, set inex 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cinot_ext: 43662306a36Sopenharmony_ci cmpil #1,%d0 |if 1 then single precision 43762306a36Sopenharmony_ci beqs load_sgl |else must be 2, double prec 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ciload_dbl: 44062306a36Sopenharmony_ci movew #dbl_thresh,%d1 |put copy of threshold in d1 44162306a36Sopenharmony_ci movel %d1,%d0 |copy d1 into d0 44262306a36Sopenharmony_ci subw LOCAL_EX(%a0),%d0 |diff = threshold - exp 44362306a36Sopenharmony_ci cmpw #67,%d0 |if diff > 67 (mant + grs bits) 44462306a36Sopenharmony_ci bpls chk_stky |then branch (all bits would be 44562306a36Sopenharmony_ci| ; shifted off in denorm routine) 44662306a36Sopenharmony_ci clrl %d0 |else clear the sticky flag 44762306a36Sopenharmony_ci bsr dnrm_lp |denormalize the number 44862306a36Sopenharmony_ci tstb %d1 |check flag 44962306a36Sopenharmony_ci beqs no_inex |if clr, no inex 45062306a36Sopenharmony_ci bras dnrm_inex |if set, set inex 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ciload_sgl: 45362306a36Sopenharmony_ci movew #sgl_thresh,%d1 |put copy of threshold in d1 45462306a36Sopenharmony_ci movel %d1,%d0 |copy d1 into d0 45562306a36Sopenharmony_ci subw LOCAL_EX(%a0),%d0 |diff = threshold - exp 45662306a36Sopenharmony_ci cmpw #67,%d0 |if diff > 67 (mant + grs bits) 45762306a36Sopenharmony_ci bpls chk_stky |then branch (all bits would be 45862306a36Sopenharmony_ci| ; shifted off in denorm routine) 45962306a36Sopenharmony_ci clrl %d0 |else clear the sticky flag 46062306a36Sopenharmony_ci bsr dnrm_lp |denormalize the number 46162306a36Sopenharmony_ci tstb %d1 |check flag 46262306a36Sopenharmony_ci beqs no_inex |if clr, no inex 46362306a36Sopenharmony_ci bras dnrm_inex |if set, set inex 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cichk_stky: 46662306a36Sopenharmony_ci tstl LOCAL_HI(%a0) |check for any bits set 46762306a36Sopenharmony_ci bnes set_stky 46862306a36Sopenharmony_ci tstl LOCAL_LO(%a0) |check for any bits set 46962306a36Sopenharmony_ci bnes set_stky 47062306a36Sopenharmony_ci bras clr_mant 47162306a36Sopenharmony_ciset_stky: 47262306a36Sopenharmony_ci orl #inx2a_mask,USER_FPSR(%a6) |set inex2/ainex 47362306a36Sopenharmony_ci movel #0x20000000,%d0 |set sticky bit in return value 47462306a36Sopenharmony_ciclr_mant: 47562306a36Sopenharmony_ci movew %d1,LOCAL_EX(%a0) |load exp with threshold 47662306a36Sopenharmony_ci movel #0,LOCAL_HI(%a0) |set d1 = 0 (ms mantissa) 47762306a36Sopenharmony_ci movel #0,LOCAL_LO(%a0) |set d2 = 0 (ms mantissa) 47862306a36Sopenharmony_ci rts 47962306a36Sopenharmony_cidnrm_inex: 48062306a36Sopenharmony_ci orl #inx2a_mask,USER_FPSR(%a6) |set inex2/ainex 48162306a36Sopenharmony_cino_inex: 48262306a36Sopenharmony_ci rts 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci| 48562306a36Sopenharmony_ci| dnrm_lp --- normalize exponent/mantissa to specified threshold 48662306a36Sopenharmony_ci| 48762306a36Sopenharmony_ci| Input: 48862306a36Sopenharmony_ci| a0 points to the operand to be denormalized 48962306a36Sopenharmony_ci| d0{31:29} initial guard,round,sticky 49062306a36Sopenharmony_ci| d1{15:0} denormalization threshold 49162306a36Sopenharmony_ci| Output: 49262306a36Sopenharmony_ci| a0 points to the denormalized operand 49362306a36Sopenharmony_ci| d0{31:29} final guard,round,sticky 49462306a36Sopenharmony_ci| d1.b inexact flag: all ones means inexact result 49562306a36Sopenharmony_ci| 49662306a36Sopenharmony_ci| The LOCAL_LO and LOCAL_GRS parts of the value are copied to FP_SCR2 49762306a36Sopenharmony_ci| so that bfext can be used to extract the new low part of the mantissa. 49862306a36Sopenharmony_ci| Dnrm_lp can be called with a0 pointing to ETEMP or WBTEMP and there 49962306a36Sopenharmony_ci| is no LOCAL_GRS scratch word following it on the fsave frame. 50062306a36Sopenharmony_ci| 50162306a36Sopenharmony_ci .global dnrm_lp 50262306a36Sopenharmony_cidnrm_lp: 50362306a36Sopenharmony_ci movel %d2,-(%sp) |save d2 for temp use 50462306a36Sopenharmony_ci btstb #E3,E_BYTE(%a6) |test for type E3 exception 50562306a36Sopenharmony_ci beqs not_E3 |not type E3 exception 50662306a36Sopenharmony_ci bfextu WBTEMP_GRS(%a6){#6:#3},%d2 |extract guard,round, sticky bit 50762306a36Sopenharmony_ci movel #29,%d0 50862306a36Sopenharmony_ci lsll %d0,%d2 |shift g,r,s to their positions 50962306a36Sopenharmony_ci movel %d2,%d0 51062306a36Sopenharmony_cinot_E3: 51162306a36Sopenharmony_ci movel (%sp)+,%d2 |restore d2 51262306a36Sopenharmony_ci movel LOCAL_LO(%a0),FP_SCR2+LOCAL_LO(%a6) 51362306a36Sopenharmony_ci movel %d0,FP_SCR2+LOCAL_GRS(%a6) 51462306a36Sopenharmony_ci movel %d1,%d0 |copy the denorm threshold 51562306a36Sopenharmony_ci subw LOCAL_EX(%a0),%d1 |d1 = threshold - uns exponent 51662306a36Sopenharmony_ci bles no_lp |d1 <= 0 51762306a36Sopenharmony_ci cmpw #32,%d1 51862306a36Sopenharmony_ci blts case_1 |0 = d1 < 32 51962306a36Sopenharmony_ci cmpw #64,%d1 52062306a36Sopenharmony_ci blts case_2 |32 <= d1 < 64 52162306a36Sopenharmony_ci bra case_3 |d1 >= 64 52262306a36Sopenharmony_ci| 52362306a36Sopenharmony_ci| No normalization necessary 52462306a36Sopenharmony_ci| 52562306a36Sopenharmony_cino_lp: 52662306a36Sopenharmony_ci clrb %d1 |set no inex2 reported 52762306a36Sopenharmony_ci movel FP_SCR2+LOCAL_GRS(%a6),%d0 |restore original g,r,s 52862306a36Sopenharmony_ci rts 52962306a36Sopenharmony_ci| 53062306a36Sopenharmony_ci| case (0<d1<32) 53162306a36Sopenharmony_ci| 53262306a36Sopenharmony_cicase_1: 53362306a36Sopenharmony_ci movel %d2,-(%sp) 53462306a36Sopenharmony_ci movew %d0,LOCAL_EX(%a0) |exponent = denorm threshold 53562306a36Sopenharmony_ci movel #32,%d0 53662306a36Sopenharmony_ci subw %d1,%d0 |d0 = 32 - d1 53762306a36Sopenharmony_ci bfextu LOCAL_EX(%a0){%d0:#32},%d2 53862306a36Sopenharmony_ci bfextu %d2{%d1:%d0},%d2 |d2 = new LOCAL_HI 53962306a36Sopenharmony_ci bfextu LOCAL_HI(%a0){%d0:#32},%d1 |d1 = new LOCAL_LO 54062306a36Sopenharmony_ci bfextu FP_SCR2+LOCAL_LO(%a6){%d0:#32},%d0 |d0 = new G,R,S 54162306a36Sopenharmony_ci movel %d2,LOCAL_HI(%a0) |store new LOCAL_HI 54262306a36Sopenharmony_ci movel %d1,LOCAL_LO(%a0) |store new LOCAL_LO 54362306a36Sopenharmony_ci clrb %d1 54462306a36Sopenharmony_ci bftst %d0{#2:#30} 54562306a36Sopenharmony_ci beqs c1nstky 54662306a36Sopenharmony_ci bsetl #rnd_stky_bit,%d0 54762306a36Sopenharmony_ci st %d1 54862306a36Sopenharmony_cic1nstky: 54962306a36Sopenharmony_ci movel FP_SCR2+LOCAL_GRS(%a6),%d2 |restore original g,r,s 55062306a36Sopenharmony_ci andil #0xe0000000,%d2 |clear all but G,R,S 55162306a36Sopenharmony_ci tstl %d2 |test if original G,R,S are clear 55262306a36Sopenharmony_ci beqs grs_clear 55362306a36Sopenharmony_ci orl #0x20000000,%d0 |set sticky bit in d0 55462306a36Sopenharmony_cigrs_clear: 55562306a36Sopenharmony_ci andil #0xe0000000,%d0 |clear all but G,R,S 55662306a36Sopenharmony_ci movel (%sp)+,%d2 55762306a36Sopenharmony_ci rts 55862306a36Sopenharmony_ci| 55962306a36Sopenharmony_ci| case (32<=d1<64) 56062306a36Sopenharmony_ci| 56162306a36Sopenharmony_cicase_2: 56262306a36Sopenharmony_ci movel %d2,-(%sp) 56362306a36Sopenharmony_ci movew %d0,LOCAL_EX(%a0) |unsigned exponent = threshold 56462306a36Sopenharmony_ci subw #32,%d1 |d1 now between 0 and 32 56562306a36Sopenharmony_ci movel #32,%d0 56662306a36Sopenharmony_ci subw %d1,%d0 |d0 = 32 - d1 56762306a36Sopenharmony_ci bfextu LOCAL_EX(%a0){%d0:#32},%d2 56862306a36Sopenharmony_ci bfextu %d2{%d1:%d0},%d2 |d2 = new LOCAL_LO 56962306a36Sopenharmony_ci bfextu LOCAL_HI(%a0){%d0:#32},%d1 |d1 = new G,R,S 57062306a36Sopenharmony_ci bftst %d1{#2:#30} 57162306a36Sopenharmony_ci bnes c2_sstky |bra if sticky bit to be set 57262306a36Sopenharmony_ci bftst FP_SCR2+LOCAL_LO(%a6){%d0:#32} 57362306a36Sopenharmony_ci bnes c2_sstky |bra if sticky bit to be set 57462306a36Sopenharmony_ci movel %d1,%d0 57562306a36Sopenharmony_ci clrb %d1 57662306a36Sopenharmony_ci bras end_c2 57762306a36Sopenharmony_cic2_sstky: 57862306a36Sopenharmony_ci movel %d1,%d0 57962306a36Sopenharmony_ci bsetl #rnd_stky_bit,%d0 58062306a36Sopenharmony_ci st %d1 58162306a36Sopenharmony_ciend_c2: 58262306a36Sopenharmony_ci clrl LOCAL_HI(%a0) |store LOCAL_HI = 0 58362306a36Sopenharmony_ci movel %d2,LOCAL_LO(%a0) |store LOCAL_LO 58462306a36Sopenharmony_ci movel FP_SCR2+LOCAL_GRS(%a6),%d2 |restore original g,r,s 58562306a36Sopenharmony_ci andil #0xe0000000,%d2 |clear all but G,R,S 58662306a36Sopenharmony_ci tstl %d2 |test if original G,R,S are clear 58762306a36Sopenharmony_ci beqs clear_grs 58862306a36Sopenharmony_ci orl #0x20000000,%d0 |set sticky bit in d0 58962306a36Sopenharmony_ciclear_grs: 59062306a36Sopenharmony_ci andil #0xe0000000,%d0 |get rid of all but G,R,S 59162306a36Sopenharmony_ci movel (%sp)+,%d2 59262306a36Sopenharmony_ci rts 59362306a36Sopenharmony_ci| 59462306a36Sopenharmony_ci| d1 >= 64 Force the exponent to be the denorm threshold with the 59562306a36Sopenharmony_ci| correct sign. 59662306a36Sopenharmony_ci| 59762306a36Sopenharmony_cicase_3: 59862306a36Sopenharmony_ci movew %d0,LOCAL_EX(%a0) 59962306a36Sopenharmony_ci tstw LOCAL_SGN(%a0) 60062306a36Sopenharmony_ci bges c3con 60162306a36Sopenharmony_cic3neg: 60262306a36Sopenharmony_ci orl #0x80000000,LOCAL_EX(%a0) 60362306a36Sopenharmony_cic3con: 60462306a36Sopenharmony_ci cmpw #64,%d1 60562306a36Sopenharmony_ci beqs sixty_four 60662306a36Sopenharmony_ci cmpw #65,%d1 60762306a36Sopenharmony_ci beqs sixty_five 60862306a36Sopenharmony_ci| 60962306a36Sopenharmony_ci| Shift value is out of range. Set d1 for inex2 flag and 61062306a36Sopenharmony_ci| return a zero with the given threshold. 61162306a36Sopenharmony_ci| 61262306a36Sopenharmony_ci clrl LOCAL_HI(%a0) 61362306a36Sopenharmony_ci clrl LOCAL_LO(%a0) 61462306a36Sopenharmony_ci movel #0x20000000,%d0 61562306a36Sopenharmony_ci st %d1 61662306a36Sopenharmony_ci rts 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cisixty_four: 61962306a36Sopenharmony_ci movel LOCAL_HI(%a0),%d0 62062306a36Sopenharmony_ci bfextu %d0{#2:#30},%d1 62162306a36Sopenharmony_ci andil #0xc0000000,%d0 62262306a36Sopenharmony_ci bras c3com 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cisixty_five: 62562306a36Sopenharmony_ci movel LOCAL_HI(%a0),%d0 62662306a36Sopenharmony_ci bfextu %d0{#1:#31},%d1 62762306a36Sopenharmony_ci andil #0x80000000,%d0 62862306a36Sopenharmony_ci lsrl #1,%d0 |shift high bit into R bit 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_cic3com: 63162306a36Sopenharmony_ci tstl %d1 63262306a36Sopenharmony_ci bnes c3ssticky 63362306a36Sopenharmony_ci tstl LOCAL_LO(%a0) 63462306a36Sopenharmony_ci bnes c3ssticky 63562306a36Sopenharmony_ci tstb FP_SCR2+LOCAL_GRS(%a6) 63662306a36Sopenharmony_ci bnes c3ssticky 63762306a36Sopenharmony_ci clrb %d1 63862306a36Sopenharmony_ci bras c3end 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cic3ssticky: 64162306a36Sopenharmony_ci bsetl #rnd_stky_bit,%d0 64262306a36Sopenharmony_ci st %d1 64362306a36Sopenharmony_cic3end: 64462306a36Sopenharmony_ci clrl LOCAL_HI(%a0) 64562306a36Sopenharmony_ci clrl LOCAL_LO(%a0) 64662306a36Sopenharmony_ci rts 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci |end 649