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: lround.S 2473 2015-04-09 08:10:22Z pitchumani $ */
30
31
32#if !defined(__AVR_TINY__)
33
34#include "fp32def.h"
35#include "asmdef.h"
36
37/* long lround (double A);
38     The lround() function rounds A to the nearest integer, but rounds
39     halfway cases away from zero (instead of to the nearest even integer).
40     This function is similar to round() function, but it differs in
41     type of return value and in that an overflow is possible.
42   Return:
43     The rounded long integer value. If A is infinite, NaN or an overflow
44     was, this realization returns the LONG_MIN value (0x80000000).
45
46   Algorithm roughly:
47     - split
48     - shift mantissa according to exponent
49     - add 0.5 to round
50     - restore the sign
51
52   Objections to saturation are listen in __fixunssfsi.S file.
53 */
54
55ENTRY lround
56	XCALL	_U(__fp_splitA)
57	brcs	.L_err
58  ; A is finite
59	subi	rA3, 126	; exponent field of 0.5
60	brlo	.L_zr		; A is too small
61  ; fabs(A) >= 0x0.800000p+00
62	subi	rA3, 24
63	brlo	2f		; shtft to right and round
64	breq	.L_sign		; no shift
65  ; fabs(A) >= 0x0.800000p+25
66	cpi	rA3, 8
67	brsh	.L_err		; A is too big
68
69  ; 0x0.800000p+25 <= fabs(A) <= 0x0.ffffffp+31  --> shift to left by 1..7
70	mov	r0, rA3		; shift counter
71	clr	rA3		; MSB
72  ; rA3.2.1.0 <<= r0
731:	lsl	rA0
74	rol	rA1
75	rol	rA2
76	rol	rA3
77	dec	r0
78	brne	1b
79	rjmp	.L_sign
80
81  ; quick shift to right by 8
825:	mov	r0, rA0		; save for possible round
83	mov	rA0, rA1
84	mov	rA1, rA2
85	clr	rA2
86	subi	rA3, -8
87	brne	2f
88	lsl	r0		; restore C
89	rjmp	4f		; and round
90  ; 0x0.800000p+00 <= fabs(A) <= 0x0.ffffffp+23
91  ; Shift A to right by 1 (rA3 == -1) .. 24 (rA3 == -24) positions and
92  ; round.
932:	cpi	rA3, -7
94	brlt	5b
95  ; shift to right by 1..7 (slow)
963:	lsr	rA2
97	ror	rA1
98	ror	rA0		; --> C
99	inc	rA3		; C is not changed
100	brne	3b
101  ; Round. Now flag C is set if fractional is >= 0.5
1024:	adc	rA0, r1
103	adc	rA1, r1
104	adc	rA2, r1		; rA2 was <= 0x7f, so rA3 will not changed
105
106  ; restore the sign and return
107.L_sign:
108	brtc	6f
109	com	rA3
110	com	rA2
111	com	rA1
112	neg	rA0
113	sbci	rA1, -1
114	sbci	rA2, -1
115	sbci	rA3, -1
1166:	ret
117
118.L_err:	set			; force return 0x80000000
119	XJMP	_U(__fp_szero)
120
121.L_zr:	XJMP	_U(__fp_zero)	; return 0x00000000
122
123ENDFUNC
124
125#endif /* !defined(__AVR_TINY__) */
126