xref: /optee_os/lib/libutils/isoc/arch/arm/arm32_aeabi_ldivmod.c (revision dc0f4ec2074a459f7bf6279e19dd3a68f86468f1)
1*1bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2abe38974SJens Wiklander /*
3abe38974SJens Wiklander  * Copyright (c) 2015, STMicroelectronics International N.V.
4abe38974SJens Wiklander  */
5abe38974SJens Wiklander 
6abe38974SJens Wiklander /* struct lqr - stores qutient/remainder to handle divmod EABI interfaces. */
7abe38974SJens Wiklander struct lqr {
8abe38974SJens Wiklander 	unsigned long long q;	/* computed quotient */
9abe38974SJens Wiklander 	unsigned long long r;	/* computed remainder */
10abe38974SJens Wiklander 	unsigned q_n;		/* specficies if quotient shall be negative */
11abe38974SJens Wiklander 	unsigned r_n;		/* specficies if remainder shall be negative */
12abe38974SJens Wiklander };
13abe38974SJens Wiklander 
14abe38974SJens Wiklander static void ul_div_qr(unsigned long long numerator,
15abe38974SJens Wiklander 		unsigned long long denominator, struct lqr *qr);
16abe38974SJens Wiklander 
17abe38974SJens Wiklander 
division_lqr(unsigned long long n,unsigned long long p,struct lqr * qr)18abe38974SJens Wiklander static void division_lqr(unsigned long long n, unsigned long long p,
19abe38974SJens Wiklander 		struct lqr *qr)
20abe38974SJens Wiklander {
21abe38974SJens Wiklander 	unsigned long long i = 1, q = 0;
22abe38974SJens Wiklander 	if (p == 0) {
23abe38974SJens Wiklander 		qr->r = 0xFFFFFFFFFFFFFFFFULL;	/* division by 0 */
24abe38974SJens Wiklander 		return;
25abe38974SJens Wiklander 	}
26abe38974SJens Wiklander 
27abe38974SJens Wiklander 	while ((p >> 63) == 0) {
28abe38974SJens Wiklander 		i = i << 1;	/* count the max division steps */
29abe38974SJens Wiklander 		p = p << 1;     /* increase p until it has maximum size*/
30abe38974SJens Wiklander 	}
31abe38974SJens Wiklander 
32abe38974SJens Wiklander 	while (i > 0) {
33abe38974SJens Wiklander 		q = q << 1;	/* write bit in q at index (size-1) */
34abe38974SJens Wiklander 		if (n >= p) {
35abe38974SJens Wiklander 			n -= p;
36abe38974SJens Wiklander 			q++;
37abe38974SJens Wiklander 		}
38abe38974SJens Wiklander 		p = p >> 1;	/* decrease p */
39abe38974SJens Wiklander 		i = i >> 1;	/* decrease remaining size in q */
40abe38974SJens Wiklander 	}
41abe38974SJens Wiklander 	qr->r = n;
42abe38974SJens Wiklander 	qr->q = q;
43abe38974SJens Wiklander }
44abe38974SJens Wiklander 
ul_div_qr(unsigned long long numerator,unsigned long long denominator,struct lqr * qr)45abe38974SJens Wiklander static void ul_div_qr(unsigned long long numerator,
46abe38974SJens Wiklander 		unsigned long long denominator, struct lqr *qr)
47abe38974SJens Wiklander {
48abe38974SJens Wiklander 
49abe38974SJens Wiklander 	division_lqr(numerator, denominator, qr);
50abe38974SJens Wiklander 
51abe38974SJens Wiklander 	/* negate quotient and/or remainder according to requester */
52abe38974SJens Wiklander 	if (qr->q_n)
53abe38974SJens Wiklander 		qr->q = -qr->q;
54abe38974SJens Wiklander 	if (qr->r_n)
55abe38974SJens Wiklander 		qr->r = -qr->r;
56abe38974SJens Wiklander }
57abe38974SJens Wiklander 
58abe38974SJens Wiklander struct asm_ulqr {
59abe38974SJens Wiklander 	unsigned long long v0;
60abe38974SJens Wiklander 	unsigned long long v1;
61abe38974SJens Wiklander };
62abe38974SJens Wiklander 
63abe38974SJens Wiklander /* called from assembly function __aeabi_uldivmod */
64abe38974SJens Wiklander void __ul_divmod(struct asm_ulqr *asm_ulqr);
__ul_divmod(struct asm_ulqr * asm_ulqr)65abe38974SJens Wiklander void __ul_divmod(struct asm_ulqr *asm_ulqr)
66abe38974SJens Wiklander {
67abe38974SJens Wiklander 	unsigned long long numerator = asm_ulqr->v0;
68abe38974SJens Wiklander 	unsigned long long denominator = asm_ulqr->v1;
69abe38974SJens Wiklander 	struct lqr qr = { .q_n = 0, .r_n = 0 };
70abe38974SJens Wiklander 
71abe38974SJens Wiklander 	ul_div_qr(numerator, denominator, &qr);
72abe38974SJens Wiklander 
73abe38974SJens Wiklander 	asm_ulqr->v0 = qr.q;
74abe38974SJens Wiklander 	asm_ulqr->v1 = qr.r;
75abe38974SJens Wiklander }
76abe38974SJens Wiklander 
77abe38974SJens Wiklander struct asm_lqr {
78abe38974SJens Wiklander 	long long v0;
79abe38974SJens Wiklander 	long long v1;
80abe38974SJens Wiklander };
81abe38974SJens Wiklander 
82abe38974SJens Wiklander /* called from assembly function __aeabi_ldivmod */
83abe38974SJens Wiklander void __l_divmod(struct asm_lqr *asm_lqr);
__l_divmod(struct asm_lqr * asm_lqr)84abe38974SJens Wiklander void __l_divmod(struct asm_lqr *asm_lqr)
85abe38974SJens Wiklander {
86abe38974SJens Wiklander 	long long numerator = asm_lqr->v0;
87abe38974SJens Wiklander 	long long denominator = asm_lqr->v1;
88abe38974SJens Wiklander 	struct lqr qr = { .q_n = 0, .r_n = 0 };
89abe38974SJens Wiklander 
90abe38974SJens Wiklander 	if (((numerator < 0) && (denominator > 0)) ||
91abe38974SJens Wiklander 	    ((numerator > 0) && (denominator < 0)))
92abe38974SJens Wiklander 		qr.q_n = 1;	/* quotient shall be negate */
93abe38974SJens Wiklander 	if (numerator < 0) {
94abe38974SJens Wiklander 		numerator = -numerator;
95abe38974SJens Wiklander 		qr.r_n = 1;	/* remainder shall be negate */
96abe38974SJens Wiklander 	}
97abe38974SJens Wiklander 	if (denominator < 0)
98abe38974SJens Wiklander 		denominator = -denominator;
99abe38974SJens Wiklander 
100abe38974SJens Wiklander 	ul_div_qr(numerator, denominator, &qr);
101abe38974SJens Wiklander 
102abe38974SJens Wiklander 	asm_lqr->v0 = qr.q;
103abe38974SJens Wiklander 	asm_lqr->v1 = qr.r;
104abe38974SJens Wiklander }
105