1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "pico/divider.h"
8 
9 // These functions save/restore divider state, so are safe to call from interrupts
div_s32s32(int32_t a,int32_t b)10 int32_t div_s32s32(int32_t a, int32_t b) {
11     return hw_divider_quotient_s32(a, b);
12 }
13 
divmod_s32s32(int32_t a,int32_t b)14 divmod_result_t divmod_s32s32(int32_t a, int32_t b) {
15     return hw_divider_divmod_s32(a, b);
16 }
17 
div_u32u32(uint32_t a,uint32_t b)18 uint32_t div_u32u32(uint32_t a, uint32_t b) {
19     return hw_divider_u32_quotient(a, b);
20 }
21 
divmod_u32u32(uint32_t a,uint32_t b)22 divmod_result_t divmod_u32u32(uint32_t a, uint32_t b) {
23     return hw_divider_divmod_u32(a, b);
24 }
25 
__sign_of_64(int32_t v)26 static inline int __sign_of_64(int32_t v) {
27     return v > 0 ? 1 : (v < 0 ? -1 : 0);
28 }
29 
30 typedef struct {
31     uint64_t quotient;
32     uint64_t remainder;
33 } qr_u64;
34 
35 typedef struct {
36     int64_t quotient;
37     int64_t remainder;
38 } qr_s64;
39 
40 // divides unsigned values a by b... (a/b) returned in low 32 bits, (a%b) in high 32 bits... results undefined for b==0
udiv64(uint64_t a,uint64_t b)41 static inline qr_u64 udiv64(uint64_t a, uint64_t b) {
42     qr_u64 rc;
43     if (!b) {
44         rc.quotient = (uint64_t)-1; // todo check this
45         rc.remainder = a;
46     } else {
47         rc.quotient = a/b;
48         rc.remainder = a%b;
49     }
50     return rc;
51 }
52 
53 // divides signed values a by b... (a/b) returned in low 32 bits, (a%b) in high 32 bits... results undefined for b==0
div64(int64_t a,int64_t b)54 static inline qr_s64 div64(int64_t a, int64_t b) {
55     qr_s64 rc;
56     if (!b) {
57         rc.quotient = (uint64_t)(-__sign_of_64(a));
58         rc.remainder = a;
59     } else {
60         rc.quotient = a/b;
61         rc.remainder = a%b;
62     }
63     return rc;
64 }
65 
div_s64s64(int64_t a,int64_t b)66 int64_t div_s64s64(int64_t a, int64_t b) {
67     qr_s64 qr = div64(a, b);
68     return qr.quotient;
69 }
70 
divmod_s64s64_rem(int64_t a,int64_t b,int64_t * rem)71 int64_t divmod_s64s64_rem(int64_t a, int64_t b, int64_t *rem) {
72     qr_s64 qr = div64(a, b);
73     *rem = qr.remainder;
74     return qr.quotient;
75 }
76 
divmod_s64s64(int64_t a,int64_t b)77 int64_t divmod_s64s64(int64_t a, int64_t b) {
78     qr_s64 qr = div64(a, b);
79     return qr.quotient;
80 }
81 
div_u64u64(uint64_t a,uint64_t b)82 uint64_t div_u64u64(uint64_t a, uint64_t b) {
83     qr_u64 qr = udiv64(a, b);
84     return qr.quotient;
85 }
86 
divmod_u64u64_rem(uint64_t a,uint64_t b,uint64_t * rem)87 uint64_t divmod_u64u64_rem(uint64_t a, uint64_t b, uint64_t *rem) {
88     qr_u64 qr = udiv64(a, b);
89     *rem = qr.remainder;
90     return qr.quotient;
91 }
92 
divmod_u64u64(uint64_t a,uint64_t b)93 uint64_t divmod_u64u64(uint64_t a, uint64_t b) {
94     qr_u64 qr = udiv64(a, b);
95     return qr.quotient;
96 }
97 
98 // these functions are slightly faster, but unsafe the divider state, so are not generally safe to be called from interrupts
99 
div_s32s32_unsafe(int32_t a,int32_t b)100 int32_t div_s32s32_unsafe(int32_t a, int32_t b) { return div_s32s32(a,b); }
divmod_s32s32_rem_unsafe(int32_t a,int32_t b,int32_t * rem)101 int32_t divmod_s32s32_rem_unsafe(int32_t a, int32_t b, int32_t *rem) { return divmod_s32s32_rem(a, b, rem); }
divmod_s32s32_unsafe(int32_t a,int32_t b)102 divmod_result_t divmod_s32s32_unsafe(int32_t a, int32_t b) { return divmod_s32s32(a, b); }
103 
div_u32u32_unsafe(uint32_t a,uint32_t b)104 uint32_t div_u32u32_unsafe(uint32_t a, uint32_t b) { return div_u32u32(a, b); }
divmod_u32u32_rem_unsafe(uint32_t a,uint32_t b,uint32_t * rem)105 uint32_t divmod_u32u32_rem_unsafe(uint32_t a, uint32_t b, uint32_t *rem) { return divmod_u32u32_rem(a, b, rem); }
divmod_u32u32_unsafe(uint32_t a,uint32_t b)106 uint64_t divmod_u32u32_unsafe(uint32_t a, uint32_t b) { return divmod_u32u32(a, b); }
107 
div_s64s64_unsafe(int64_t a,int64_t b)108 int64_t div_s64s64_unsafe(int64_t a, int64_t b) { return div_s64s64(a, b); }
divmod_s64s64_rem_unsafe(int64_t a,int64_t b,int64_t * rem)109 int64_t divmod_s64s64_rem_unsafe(int64_t a, int64_t b, int64_t *rem) { return divmod_s64s64_rem(a, b, rem); }
divmod_s64s64_unsafe(int64_t a,int64_t b)110 int64_t divmod_s64s64_unsafe(int64_t a, int64_t b) { return divmod_s64s64(a, b); }
111 
div_u64u64_unsafe(uint64_t a,uint64_t b)112 uint64_t div_u64u64_unsafe(uint64_t a, uint64_t b) { return div_u64u64(a, b); }
divmod_u64u64_rem_unsafe(uint64_t a,uint64_t b,uint64_t * rem)113 uint64_t divmod_u64u64_rem_unsafe(uint64_t a, uint64_t b, uint64_t *rem) { return divmod_u64u64_rem(a, b, rem); }
divmod_u64u64_unsafe(uint64_t a,uint64_t b)114 uint64_t divmod_u64u64_unsafe(uint64_t a, uint64_t b) { return divmod_u64u64(a, b); }
115