📄 round.s
字号:
//// $Id: round.S,v 1.1 1998/12/14 23:15:23 joel Exp $//// 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.defs"//// 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -