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