1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _HARDWARE_DIVIDER_H
8 #define _HARDWARE_DIVIDER_H
9 
10 #include "pico/types.h"
11 
12 typedef uint64_t divmod_result_t;
13 
__sign_of(int32_t v)14 static inline int __sign_of(int32_t v) {
15     return v > 0 ? 1 : (v < 0 ? -1 : 0);
16 }
17 
18 // divides unsigned values a by b... (a/b) returned in low 32 bits, (a%b) in high 32 bits... results undefined for b==0
hw_divider_divmod_u32(uint32_t a,uint32_t b)19 static inline uint64_t hw_divider_divmod_u32(uint32_t a, uint32_t b) {
20     if (!b) return (((uint64_t)a)<<32u) | (uint32_t)(-1); // todo check this
21     return (((uint64_t)(a%b))<<32u) | (a/b);
22 }
23 
24 // divides signed values a by b... (a/b) returned in low 32 bits, (a%b) in high 32 bits... results undefined for b==0
hw_divider_divmod_s32(int32_t a,int32_t b)25 static inline uint64_t hw_divider_divmod_s32(int32_t a, int32_t b) {
26     if (!b) return (((uint64_t)a)<<32u) | (uint32_t)(-__sign_of(a));
27     return (((uint64_t)(a%b))<<32u) | (uint32_t)(a/b);
28 }
29 
30 extern __thread divmod_result_t hw_divider_result_threadlocal;
31 
hw_divider_divmod_s32_start(int32_t a,int32_t b)32 static inline void hw_divider_divmod_s32_start(int32_t a, int32_t b) {
33     hw_divider_result_threadlocal = hw_divider_divmod_s32(a, b);
34 }
35 
hw_divider_divmod_u32_start(uint32_t a,uint32_t b)36 static inline void hw_divider_divmod_u32_start(uint32_t a, uint32_t b) {
37     hw_divider_result_threadlocal = hw_divider_divmod_u32(a, b);
38 }
39 
hw_divider_result_wait()40 static inline divmod_result_t hw_divider_result_wait() {
41     return hw_divider_result_threadlocal;
42 }
43 
hw_divider_result_nowait()44 static inline uint64_t hw_divider_result_nowait() {
45     return hw_divider_result_threadlocal;
46 }
47 
to_quotient_u32(unsigned long long int r)48 inline static uint32_t to_quotient_u32(unsigned long long int r) {
49     return (uint32_t) r;
50 }
51 
to_quotient_s32(unsigned long long int r)52 inline static int32_t to_quotient_s32(unsigned long long int r) {
53     return (int32_t)(uint32_t)r;
54 }
55 
to_remainder_u32(unsigned long long int r)56 inline static uint32_t to_remainder_u32(unsigned long long int r) {
57     return (uint32_t)(r >> 32u);
58 }
59 
to_remainder_s32(unsigned long long int r)60 inline static int32_t to_remainder_s32(unsigned long long int r) {
61     return (int32_t)(r >> 32u);
62 }
63 
hw_divider_u32_quotient_wait()64 static inline uint32_t hw_divider_u32_quotient_wait() {
65     return to_quotient_u32(hw_divider_result_wait());
66 }
67 
hw_divider_u32_remainder_wait()68 static inline uint32_t hw_divider_u32_remainder_wait() {
69     return to_remainder_u32(hw_divider_result_wait());
70 }
71 
hw_divider_s32_quotient_wait()72 static inline int32_t hw_divider_s32_quotient_wait() {
73     return to_quotient_s32(hw_divider_result_wait());
74 }
75 
hw_divider_s32_remainder_wait()76 static inline int32_t hw_divider_s32_remainder_wait() {
77     return to_remainder_s32(hw_divider_result_wait());
78 }
79 
hw_divider_u32_quotient(uint32_t a,uint32_t b)80 static inline uint32_t hw_divider_u32_quotient(uint32_t a, uint32_t b) {
81     return b ? (a / b) : (uint32_t)(-1);
82 }
83 
hw_divider_u32_remainder(uint32_t a,uint32_t b)84 static inline uint32_t hw_divider_u32_remainder(uint32_t a, uint32_t b) {
85     return b ? (a % b) : a;
86 }
87 
hw_divider_s32_quotient(int32_t a,int32_t b)88 static inline int32_t hw_divider_s32_quotient(int32_t a, int32_t b) {
89     return b ? (a / b) : -__sign_of(a);
90 }
91 
hw_divider_s32_remainder(int32_t a,int32_t b)92 static inline int32_t hw_divider_s32_remainder(int32_t a, int32_t b) {
93     return b ? (a % b) : a;
94 }
95 
hw_divider_u32_quotient_inlined(uint32_t a,uint32_t b)96 static inline uint32_t hw_divider_u32_quotient_inlined(uint32_t a, uint32_t b) {
97     return hw_divider_u32_quotient(a,b);
98 }
99 
hw_divider_u32_remainder_inlined(uint32_t a,uint32_t b)100 static inline uint32_t hw_divider_u32_remainder_inlined(uint32_t a, uint32_t b) {
101     return hw_divider_u32_remainder(a,b);
102 }
103 
hw_divider_s32_quotient_inlined(int32_t a,int32_t b)104 static inline int32_t hw_divider_s32_quotient_inlined(int32_t a, int32_t b) {
105     return hw_divider_s32_quotient(a,b);
106 }
107 
hw_divider_s32_remainder_inlined(int32_t a,int32_t b)108 static inline int32_t hw_divider_s32_remainder_inlined(int32_t a, int32_t b) {
109     return hw_divider_s32_remainder(a,b);
110 }
111 
112 typedef uint64_t hw_divider_state_t;
113 
hw_divider_save_state(hw_divider_state_t * dest)114 static inline void hw_divider_save_state(hw_divider_state_t *dest) {
115     *dest = hw_divider_result_threadlocal;
116 }
117 
hw_divider_restore_state(hw_divider_state_t * src)118 static inline void hw_divider_restore_state(hw_divider_state_t *src) {
119     hw_divider_result_threadlocal = *src;
120 }
121 
122 #endif // _HARDWARE_DIVIDER_H
123