📄 round.s
字号:
|| round.sa 3.4 7/29/91|| handle rounding and normalization tasks|||| Copyright (C) Motorola, Inc. 1990| All Rights Reserved|| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA | The copyright notice above does not evidence any | actual or intended publication of such source code.|ROUND idnt 2,1 | Motorola 040 Floating Point Software Package |section 8 .include "fpsp.h"|| round --- round result according to precision/mode|| a0 points to the input operand in the internal extended format | d1(high word) contains rounding precision:| ext = $0000xxxx| sgl = $0001xxxx| dbl = $0002xxxx| d1(low word) contains rounding mode:| RN = $xxxx0000| RZ = $xxxx0001| RM = $xxxx0010| RP = $xxxx0011| d0{31:29} contains the g,r,s bits (extended)|| On return the value pointed to by a0 is correctly rounded,| a0 is preserved and the g-r-s bits in d0 are cleared.| The result is not typed - the tag field is invalid. The| result is still in the internal extended format.|| The INEX bit of USER_FPSR will be set if the rounded result was| inexact (i.e. if any of the g-r-s bits were set).| .global roundround:| If g=r=s=0 then result is exact and round is done, else set | the inex flag in status reg and continue. | bsrs ext_grs |this subroutine looks at the | :rounding precision and sets | ;the appropriate g-r-s bits. tstl %d0 |if grs are zero, go force bne rnd_cont |lower bits to zero for size swap %d1 |set up d1.w for round prec. bra truncaternd_cont:|| Use rounding mode as an index into a jump table for these modes.| orl #inx2a_mask,USER_FPSR(%a6) |set inex2/ainex lea mode_tab,%a1 movel (%a1,%d1.w*4),%a1 jmp (%a1)|| Jump table indexed by rounding mode in d1.w. All following assumes| grs != 0.|mode_tab: .long rnd_near .long rnd_zero .long rnd_mnus .long rnd_plus|| ROUND PLUS INFINITY|| If sign of fp number = 0 (positive), then add 1 to l.|rnd_plus: swap %d1 |set up d1 for round prec. tstb LOCAL_SGN(%a0) |check for sign bmi truncate |if positive then truncate movel #0xffffffff,%d0 |force g,r,s to be all f's lea add_to_l,%a1 movel (%a1,%d1.w*4),%a1 jmp (%a1)|| ROUND MINUS INFINITY|| If sign of fp number = 1 (negative), then add 1 to l.|rnd_mnus: swap %d1 |set up d1 for round prec. tstb LOCAL_SGN(%a0) |check for sign bpl truncate |if negative then truncate movel #0xffffffff,%d0 |force g,r,s to be all f's lea add_to_l,%a1 movel (%a1,%d1.w*4),%a1 jmp (%a1)|| ROUND ZERO|| Always truncate.rnd_zero: swap %d1 |set up d1 for round prec. bra truncate||| ROUND NEAREST|| If (g=1), then add 1 to l and if (r=s=0), then clear l| Note that this will round to even in case of a tie.|rnd_near: swap %d1 |set up d1 for round prec. asll #1,%d0 |shift g-bit to c-bit bcc truncate |if (g=1) then lea add_to_l,%a1 movel (%a1,%d1.w*4),%a1 jmp (%a1)|| ext_grs --- extract guard, round and sticky bits|| Input: d1 = PREC:ROUND| Output: d0{31:29}= guard, round, sticky|| The ext_grs extract the guard/round/sticky bits according to the| selected rounding precision. It is called by the round subroutine| only. All registers except d0 are kept intact. d0 becomes an | updated guard,round,sticky in d0{31:29}|| Notes: the ext_grs uses the round PREC, and therefore has to swap d1| prior to usage, and needs to restore d1 to original.|ext_grs: swap %d1 |have d1.w point to round precision cmpiw #0,%d1 bnes sgl_or_dbl bras end_ext_grs sgl_or_dbl: moveml %d2/%d3,-(%a7) |make some temp registers cmpiw #1,%d1 bnes grs_dblgrs_sgl: bfextu LOCAL_HI(%a0){#24:#2},%d3 |sgl prec. g-r are 2 bits right movel #30,%d2 |of the sgl prec. limits lsll %d2,%d3 |shift g-r bits to MSB of d3 movel LOCAL_HI(%a0),%d2 |get word 2 for s-bit test andil #0x0000003f,%d2 |s bit is the or of all other bnes st_stky |bits to the right of g-r tstl LOCAL_LO(%a0) |test lower mantissa bnes st_stky |if any are set, set sticky tstl %d0 |test original g,r,s bnes st_stky |if any are set, set sticky bras end_sd |if words 3 and 4 are clr, exitgrs_dbl: bfextu LOCAL_LO(%a0){#21:#2},%d3 |dbl-prec. g-r are 2 bits right movel #30,%d2 |of the dbl prec. limits lsll %d2,%d3 |shift g-r bits to the MSB of d3 movel LOCAL_LO(%a0),%d2 |get lower mantissa for s-bit test andil #0x000001ff,%d2 |s bit is the or-ing of all bnes st_stky |other bits to the right of g-r tstl %d0 |test word original g,r,s bnes st_stky |if any are set, set sticky bras end_sd |if clear, exitst_stky: bset #rnd_stky_bit,%d3end_sd: movel %d3,%d0 |return grs to d0 moveml (%a7)+,%d2/%d3 |restore scratch registersend_ext_grs: swap %d1 |restore d1 to original rts|******************* Local Equates .set ad_1_sgl,0x00000100 | constant to add 1 to l-bit in sgl prec .set ad_1_dbl,0x00000800 | constant to add 1 to l-bit in dbl prec|Jump table for adding 1 to the l-bit indexed by rnd precadd_to_l: .long add_ext .long add_sgl .long add_dbl .long add_dbl|| ADD SINGLE|add_sgl: addl #ad_1_sgl,LOCAL_HI(%a0) bccs scc_clr |no mantissa overflow roxrw LOCAL_HI(%a0) |shift v-bit back in roxrw LOCAL_HI+2(%a0) |shift v-bit back in addw #0x1,LOCAL_EX(%a0) |and incr exponentscc_clr: tstl %d0 |test for rs = 0 bnes sgl_done andiw #0xfe00,LOCAL_HI+2(%a0) |clear the l-bitsgl_done: andil #0xffffff00,LOCAL_HI(%a0) |truncate bits beyond sgl limit clrl LOCAL_LO(%a0) |clear d2 rts|| ADD EXTENDED|add_ext: addql #1,LOCAL_LO(%a0) |add 1 to l-bit bccs xcc_clr |test for carry out addql #1,LOCAL_HI(%a0) |propagate carry bccs xcc_clr roxrw LOCAL_HI(%a0) |mant is 0 so restore v-bit roxrw LOCAL_HI+2(%a0) |mant is 0 so restore v-bit roxrw LOCAL_LO(%a0) roxrw LOCAL_LO+2(%a0) addw #0x1,LOCAL_EX(%a0) |and inc expxcc_clr: tstl %d0 |test rs = 0 bnes add_ext_done andib #0xfe,LOCAL_LO+3(%a0) |clear the l bitadd_ext_done: rts|| ADD DOUBLE|add_dbl: addl #ad_1_dbl,LOCAL_LO(%a0) bccs dcc_clr addql #1,LOCAL_HI(%a0) |propagate carry bccs dcc_clr roxrw LOCAL_HI(%a0) |mant is 0 so restore v-bit roxrw LOCAL_HI+2(%a0) |mant is 0 so restore v-bit roxrw LOCAL_LO(%a0) roxrw LOCAL_LO+2(%a0) addw #0x1,LOCAL_EX(%a0) |incr exponentdcc_clr: tstl %d0 |test for rs = 0 bnes dbl_done andiw #0xf000,LOCAL_LO+2(%a0) |clear the l-bitdbl_done: andil #0xfffff800,LOCAL_LO(%a0) |truncate bits beyond dbl limit rtserror: rts|| Truncate all other bits|trunct: .long end_rnd .long sgl_done .long dbl_done .long dbl_donetruncate: lea trunct,%a1 movel (%a1,%d1.w*4),%a1 jmp (%a1)end_rnd: rts|| NORMALIZE|| These routines (nrm_zero & nrm_set) normalize the unnorm. This | is done by shifting the mantissa left while decrementing the | exponent.|| NRM_SET shifts and decrements until there is a 1 set in the integer | bit of the mantissa (msb in d1).|| NRM_ZERO shifts and decrements until there is a 1 set in the integer | bit of the mantissa (msb in d1) unless this would mean the exponent | would go less than 0. In that case the number becomes a denorm - the | exponent (d0) is set to 0 and the mantissa (d1 & d2) is not | normalized.|| Note that both routines have been optimized (for the worst case) and | therefore do not have the easy to follow decrement/shift loop.|| NRM_ZERO|| Distance to first 1 bit in mantissa = X| Distance to 0 from exponent = Y| If X < Y| Then| nrm_set| Else| shift mantissa by Y| set exponent = 0||input:| FP_SCR1 = exponent, ms mantissa part, ls mantissa part|output:| L_SCR1{4} = fpte15 or ete15 bit| .global nrm_zeronrm_zero: movew LOCAL_EX(%a0),%d0 cmpw #64,%d0 |see if exp > 64 bmis d0_less bsr nrm_set |exp > 64 so exp won't exceed 0 rtsd0_less: moveml %d2/%d3/%d5/%d6,-(%a7) movel LOCAL_HI(%a0),%d1 movel LOCAL_LO(%a0),%d2 bfffo %d1{#0:#32},%d3 |get the distance to the first 1 | ;in ms mant beqs ms_clr |branch if no bits were set cmpw %d3,%d0 |of X>Y bmis greater |then exp will go past 0 (neg) if | ;it is just shifted bsr nrm_set |else exp won't go past 0 moveml (%a7)+,%d2/%d3/%d5/%d6 rts greater:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -