1/* Copyright (c) 2007 Dmitry Xmelkov 2 All rights reserved. 3 4 Redistribution and use in source and binary forms, with or without 5 modification, are permitted provided that the following conditions are met: 6 7 * Redistributions of source code must retain the above copyright 8 notice, this list of conditions and the following disclaimer. 9 * Redistributions in binary form must reproduce the above copyright 10 notice, this list of conditions and the following disclaimer in 11 the documentation and/or other materials provided with the 12 distribution. 13 * Neither the name of the copyright holders nor the names of 14 contributors may be used to endorse or promote products derived 15 from this software without specific prior written permission. 16 17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 POSSIBILITY OF SUCH DAMAGE. */ 28 29/* $Id: lrint.S 2473 2015-04-09 08:10:22Z pitchumani $ */ 30 31#if !defined(__AVR_TINY__) 32 33#include "fp32def.h" 34#include "asmdef.h" 35 36/* long lrint (double A); 37 The lrint() function rounds A to the nearest integer, rounding the 38 halfway cases to the even integer direction. (That is both 1.5 and 39 2.5 values are rounded to 2). This function is similar to rint() 40 function, but it differs in type of return value and in that an 41 overflow is possible. 42 Return: 43 The rounded long integer value. If A is not a finite number or an 44 overflow was, this realization returns the LONG_MIN value (0x80000000). 45 46 Algorithm roughly: 47 - split 48 - shift mantissa according to exponent 49 - round (if shift was to right) 50 - restore the sign 51 */ 52 53ENTRY lrint 54 XCALL _U(__fp_splitA) 55 brcs .L_err 56 ; A is finite 57 subi rA3, 126 ; exponent field of 0.5 58 brlo .L_zr ; A is too small 59 ; fabs(A) >= 0x0.800000p+00 60 subi rA3, 24 61 brlo .L_right ; shtft to right and round 62 breq .L_sign ; no shift 63 ; fabs(A) >= 0x0.800000p+25 64 cpi rA3, 8 65 brsh .L_err ; fabs(A) is too big 66 67 ; 0x0.800000p+25 <= fabs(A) <= 0x0.ffffffp+31 --> shift to left by 1..7 68 mov r0, rA3 ; shift counter 69 clr rA3 ; MSB 70 ; rA3.2.1.0 <<= r0 711: lsl rA0 72 rol rA1 73 rol rA2 74 rol rA3 75 dec r0 76 brne 1b 77 rjmp .L_sign 78 79 ; 0x0.800000p+00 <= fabs(A) <= 0x0.ffffffp+23 80 ; Shift A to right by 1 (rA3 == -1) .. 24 (rA3 == -24) positions and 81 ; round. 82.L_right: 83 clr rAE ; accumulator for lower bits 842: cpi rA3, -7 85 brge 3f 86 ; Quick shift to right by 8. The trick with rAE is needed to save info 87 ; about the lowerest bits. This will be used to compare fraction with 88 ; 0.5 value. 89 cpse rAE, r1 90 ldi rAE, 1 91 or rAE, rA0 92 mov rA0, rA1 93 mov rA1, rA2 94 clr rA2 95 subi rA3, -8 96 brne 2b 97 rjmp .L_round 98 ; shift to right by 1..7 (slow) 993: lsr rA2 100 ror rA1 101 ror rA0 102 ror rAE 103 brcc 4f 104 ori rAE, 1 ; save flag that lowerst bits are not all 0 1054: inc rA3 106 brne 3b 107 ; round 108.L_round: 109 lsl rAE 110 brcc .L_sign ; fraction < 0.5 111 brne 7f ; fraction > 0.5 112 sbrs rA0, 0 113 rjmp .L_sign ; fraction == 0.5 and value is even 1147: subi rA0, -1 115 sbci rA1, -1 116 sbci rA2, -1 ; rA2 was <= 0x7f, so rA3 will not changed 117 118 ; restore the sign and return 119.L_sign: 120 brtc 6f 121 com rA3 122 com rA2 123 com rA1 124 neg rA0 125 sbci rA1, -1 126 sbci rA2, -1 127 sbci rA3, -1 1286: ret 129 130.L_err: set ; force return 0x80000000 131 XJMP _U(__fp_szero) 132 133.L_zr: XJMP _U(__fp_zero) ; return 0x00000000 134 135ENDFUNC 136 137#endif /* !defined(__AVR_TINY__) */ 138