|
7 | 7 | #ifndef _HARDWARE_DIVIDER_H |
8 | 8 | #define _HARDWARE_DIVIDER_H |
9 | 9 |
|
10 | | -#include "pico/types.h" |
| 10 | +#include "pico.h" |
| 11 | + |
| 12 | +#ifdef __cplusplus |
| 13 | +extern "C" { |
| 14 | +#endif |
11 | 15 |
|
12 | 16 | typedef uint64_t divmod_result_t; |
13 | 17 |
|
14 | 18 | static inline int __sign_of(int32_t v) { |
15 | 19 | return v > 0 ? 1 : (v < 0 ? -1 : 0); |
16 | 20 | } |
17 | 21 |
|
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 |
19 | | -static inline uint64_t hw_divider_divmod_u32(uint32_t a, uint32_t b) { |
| 22 | +/*! \brief Do an unsigned HW divide and wait for result |
| 23 | + * \ingroup hardware_divider |
| 24 | + * |
| 25 | + * Divide \p a by \p b, wait for calculation to complete, return result as a pair of 32-bit quotient/remainder values. |
| 26 | + * |
| 27 | + * \param a The dividend |
| 28 | + * \param b The divisor |
| 29 | + * \return Results of divide as a pair of 32-bit quotient/remainder values. |
| 30 | + */ |
| 31 | +static inline divmod_result_t hw_divider_divmod_u32(uint32_t a, uint32_t b) { |
20 | 32 | if (!b) return (((uint64_t)a)<<32u) | (uint32_t)(-1); // todo check this |
21 | 33 | return (((uint64_t)(a%b))<<32u) | (a/b); |
22 | 34 | } |
23 | 35 |
|
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 |
25 | | -static inline uint64_t hw_divider_divmod_s32(int32_t a, int32_t b) { |
| 36 | +/*! \brief Do a signed HW divide and wait for result |
| 37 | + * \ingroup hardware_divider |
| 38 | + * |
| 39 | + * Divide \p a by \p b, wait for calculation to complete, return result as a pair of 32-bit quotient/remainder values. |
| 40 | + * |
| 41 | + * \param a The dividend |
| 42 | + * \param b The divisor |
| 43 | + * \return Results of divide as a pair of 32-bit quotient/remainder values. |
| 44 | + */ |
| 45 | +static inline divmod_result_t hw_divider_divmod_s32(int32_t a, int32_t b) { |
26 | 46 | if (!b) return (((uint64_t)a)<<32u) | (uint32_t)(-__sign_of(a)); |
27 | 47 | return (((uint64_t)(a%b))<<32u) | (uint32_t)(a/b); |
28 | 48 | } |
29 | 49 |
|
30 | 50 | extern __thread divmod_result_t hw_divider_result_threadlocal; |
31 | 51 |
|
| 52 | +/*! \brief Start a signed asynchronous divide |
| 53 | + * \ingroup hardware_divider |
| 54 | + * |
| 55 | + * Start a divide of the specified signed parameters. You should wait for 8 cycles (__div_pause()) or wait for the ready bit to be set |
| 56 | + * (hw_divider_wait_ready()) prior to reading the results. |
| 57 | + * |
| 58 | + * \param a The dividend |
| 59 | + * \param b The divisor |
| 60 | + */ |
32 | 61 | static inline void hw_divider_divmod_s32_start(int32_t a, int32_t b) { |
33 | 62 | hw_divider_result_threadlocal = hw_divider_divmod_s32(a, b); |
34 | 63 | } |
35 | 64 |
|
| 65 | +/*! \brief Start an unsigned asynchronous divide |
| 66 | + * \ingroup hardware_divider |
| 67 | + * |
| 68 | + * Start a divide of the specified unsigned parameters. You should wait for 8 cycles (__div_pause()) or wait for the ready bit to be set |
| 69 | + * (hw_divider_wait_ready()) prior to reading the results. |
| 70 | + * |
| 71 | + * \param a The dividend |
| 72 | + * \param b The divisor |
| 73 | + */ |
36 | 74 | static inline void hw_divider_divmod_u32_start(uint32_t a, uint32_t b) { |
37 | 75 | hw_divider_result_threadlocal = hw_divider_divmod_u32(a, b); |
38 | 76 | } |
39 | 77 |
|
40 | | -static inline divmod_result_t hw_divider_result_wait() { |
| 78 | +/*! \brief Return result of last asynchronous HW divide |
| 79 | + * \ingroup hardware_divider |
| 80 | + * |
| 81 | + * This function waits for the result to be ready by calling hw_divider_wait_ready(). |
| 82 | + * |
| 83 | + * \return Current result. Most significant 32 bits are the remainder, lower 32 bits are the quotient. |
| 84 | + */ |
| 85 | +static inline divmod_result_t hw_divider_result_wait(void) { |
41 | 86 | return hw_divider_result_threadlocal; |
42 | 87 | } |
43 | 88 |
|
44 | | -static inline uint64_t hw_divider_result_nowait() { |
| 89 | +/*! \brief Return result of HW divide, nowait |
| 90 | + * \ingroup hardware_divider |
| 91 | + * |
| 92 | + * \note This is UNSAFE in that the calculation may not have been completed. |
| 93 | + * |
| 94 | + * \return Current result. Most significant 32 bits are the remainder, lower 32 bits are the quotient. |
| 95 | + */ |
| 96 | +static inline divmod_result_t hw_divider_result_nowait(void) { |
45 | 97 | return hw_divider_result_threadlocal; |
46 | 98 | } |
47 | 99 |
|
48 | | -inline static uint32_t to_quotient_u32(unsigned long long int r) { |
| 100 | +/*! \brief Wait for a divide to complete |
| 101 | + * \ingroup hardware_divider |
| 102 | + * |
| 103 | + * Wait for a divide to complete |
| 104 | + */ |
| 105 | +static inline void hw_divider_wait_ready(void) {} |
| 106 | + |
| 107 | + |
| 108 | +/*! \brief Efficient extraction of unsigned quotient from 32p32 fixed point |
| 109 | + * \ingroup hardware_divider |
| 110 | + * |
| 111 | + * \param r A pair of 32-bit quotient/remainder values. |
| 112 | + * \return Unsigned quotient |
| 113 | + */ |
| 114 | +inline static uint32_t to_quotient_u32(divmod_result_t r) { |
49 | 115 | return (uint32_t) r; |
50 | 116 | } |
51 | 117 |
|
52 | | -inline static int32_t to_quotient_s32(unsigned long long int r) { |
| 118 | +/*! \brief Efficient extraction of signed quotient from 32p32 fixed point |
| 119 | + * \ingroup hardware_divider |
| 120 | + * |
| 121 | + * \param r A pair of 32-bit quotient/remainder values. |
| 122 | + * \return Unsigned quotient |
| 123 | + */ |
| 124 | +inline static int32_t to_quotient_s32(divmod_result_t r) { |
53 | 125 | return (int32_t)(uint32_t)r; |
54 | 126 | } |
55 | 127 |
|
56 | | -inline static uint32_t to_remainder_u32(unsigned long long int r) { |
| 128 | +/*! \brief Efficient extraction of unsigned remainder from 32p32 fixed point |
| 129 | + * \ingroup hardware_divider |
| 130 | + * |
| 131 | + * \param r A pair of 32-bit quotient/remainder values. |
| 132 | + * \return Unsigned remainder |
| 133 | + * |
| 134 | + * \note On Arm this is just a 32 bit register move or a nop |
| 135 | + */ |
| 136 | +inline static uint32_t to_remainder_u32(divmod_result_t r) { |
57 | 137 | return (uint32_t)(r >> 32u); |
58 | 138 | } |
59 | 139 |
|
60 | | -inline static int32_t to_remainder_s32(unsigned long long int r) { |
| 140 | +/*! \brief Efficient extraction of signed remainder from 32p32 fixed point |
| 141 | + * \ingroup hardware_divider |
| 142 | + * |
| 143 | + * \param r A pair of 32-bit quotient/remainder values. |
| 144 | + * \return Signed remainder |
| 145 | + * |
| 146 | + * \note On arm this is just a 32 bit register move or a nop |
| 147 | + */ |
| 148 | +inline static int32_t to_remainder_s32(divmod_result_t r) { |
61 | 149 | return (int32_t)(r >> 32u); |
62 | 150 | } |
63 | 151 |
|
64 | | -static inline uint32_t hw_divider_u32_quotient_wait() { |
65 | | - return to_quotient_u32(hw_divider_result_wait()); |
| 152 | +static inline void hw_divider_pause(void) {} |
| 153 | + |
| 154 | +/*! \brief Do an unsigned HW divide, wait for result, return quotient |
| 155 | + * \ingroup hardware_divider |
| 156 | + * |
| 157 | + * Divide \p a by \p b, wait for calculation to complete, return quotient. |
| 158 | + * |
| 159 | + * \param a The dividend |
| 160 | + * \param b The divisor |
| 161 | + * \return Quotient results of the divide |
| 162 | + */ |
| 163 | +static inline uint32_t hw_divider_u32_quotient(uint32_t a, uint32_t b) { |
| 164 | + return b ? (a / b) : (uint32_t)(-1); |
66 | 165 | } |
67 | 166 |
|
68 | | -static inline uint32_t hw_divider_u32_remainder_wait() { |
69 | | - return to_remainder_u32(hw_divider_result_wait()); |
| 167 | +/*! \brief Do an unsigned HW divide, wait for result, return remainder |
| 168 | + * \ingroup hardware_divider |
| 169 | + * |
| 170 | + * Divide \p a by \p b, wait for calculation to complete, return remainder. |
| 171 | + * |
| 172 | + * \param a The dividend |
| 173 | + * \param b The divisor |
| 174 | + * \return Remainder results of the divide |
| 175 | + */ |
| 176 | +static inline uint32_t hw_divider_u32_remainder(uint32_t a, uint32_t b) { |
| 177 | + return b ? (a % b) : a; |
70 | 178 | } |
71 | 179 |
|
72 | | -static inline int32_t hw_divider_s32_quotient_wait() { |
73 | | - return to_quotient_s32(hw_divider_result_wait()); |
| 180 | +/*! \brief Do a signed HW divide, wait for result, return quotient |
| 181 | + * \ingroup hardware_divider |
| 182 | + * |
| 183 | + * Divide \p a by \p b, wait for calculation to complete, return quotient. |
| 184 | + * |
| 185 | + * \param a The dividend |
| 186 | + * \param b The divisor |
| 187 | + * \return Quotient results of the divide |
| 188 | + */ |
| 189 | +static inline int32_t hw_divider_quotient_s32(int32_t a, int32_t b) { |
| 190 | + return to_quotient_s32(hw_divider_divmod_s32(a, b)); |
74 | 191 | } |
75 | 192 |
|
76 | | -static inline int32_t hw_divider_s32_remainder_wait() { |
77 | | - return to_remainder_s32(hw_divider_result_wait()); |
| 193 | +/*! \brief Do a signed HW divide, wait for result, return remainder |
| 194 | + * \ingroup hardware_divider |
| 195 | + * |
| 196 | + * Divide \p a by \p b, wait for calculation to complete, return remainder. |
| 197 | + * |
| 198 | + * \param a The dividend |
| 199 | + * \param b The divisor |
| 200 | + * \return Remainder results of the divide |
| 201 | + */ |
| 202 | +static inline int32_t hw_divider_remainder_s32(int32_t a, int32_t b) { |
| 203 | + return b ? (a % b) : a; |
78 | 204 | } |
79 | 205 |
|
80 | | -static inline uint32_t hw_divider_u32_quotient(uint32_t a, uint32_t b) { |
81 | | - return b ? (a / b) : (uint32_t)(-1); |
| 206 | +/*! \brief Return result of last asynchronous HW divide, unsigned quotient only |
| 207 | + * \ingroup hardware_divider |
| 208 | + * |
| 209 | + * This function waits for the result to be ready by calling hw_divider_wait_ready(). |
| 210 | + * |
| 211 | + * \return Current unsigned quotient result. |
| 212 | + */ |
| 213 | +static inline uint32_t hw_divider_u32_quotient_wait(void) { |
| 214 | + return to_quotient_u32(hw_divider_result_wait()); |
82 | 215 | } |
83 | 216 |
|
84 | | -static inline uint32_t hw_divider_u32_remainder(uint32_t a, uint32_t b) { |
85 | | - return b ? (a % b) : a; |
| 217 | +/*! \brief Return result of last asynchronous HW divide, signed quotient only |
| 218 | + * \ingroup hardware_divider |
| 219 | + * |
| 220 | + * This function waits for the result to be ready by calling hw_divider_wait_ready(). |
| 221 | + * |
| 222 | + * \return Current signed quotient result. |
| 223 | + */ |
| 224 | +static inline int32_t hw_divider_s32_quotient_wait(void) { |
| 225 | + return to_remainder_u32(hw_divider_result_wait()); |
86 | 226 | } |
87 | 227 |
|
88 | | -static inline int32_t hw_divider_s32_quotient(int32_t a, int32_t b) { |
89 | | - return b ? (a / b) : -__sign_of(a); |
| 228 | +/*! \brief Return result of last asynchronous HW divide, unsigned remainder only |
| 229 | + * \ingroup hardware_divider |
| 230 | + * |
| 231 | + * This function waits for the result to be ready by calling hw_divider_wait_ready(). |
| 232 | + * |
| 233 | + * \return Current unsigned remainder result. |
| 234 | + */ |
| 235 | +static inline uint32_t hw_divider_u32_remainder_wait(void) { |
| 236 | + return to_quotient_s32(hw_divider_result_wait()); |
90 | 237 | } |
91 | 238 |
|
92 | | -static inline int32_t hw_divider_s32_remainder(int32_t a, int32_t b) { |
93 | | - return b ? (a % b) : a; |
| 239 | +/*! \brief Return result of last asynchronous HW divide, signed remainder only |
| 240 | + * \ingroup hardware_divider |
| 241 | + * |
| 242 | + * This function waits for the result to be ready by calling hw_divider_wait_ready(). |
| 243 | + * |
| 244 | + * \return Current remainder results. |
| 245 | + */ |
| 246 | +static inline int32_t hw_divider_s32_remainder_wait(void) { |
| 247 | + return to_remainder_s32(hw_divider_result_wait()); |
94 | 248 | } |
95 | 249 |
|
| 250 | +/*! \brief Do a hardware unsigned HW divide, wait for result, return quotient |
| 251 | + * \ingroup hardware_divider |
| 252 | + * |
| 253 | + * Divide \p a by \p b, wait for calculation to complete, return quotient. |
| 254 | + * |
| 255 | + * \param a The dividend |
| 256 | + * \param b The divisor |
| 257 | + * \return Quotient result of the divide |
| 258 | + */ |
96 | 259 | static inline uint32_t hw_divider_u32_quotient_inlined(uint32_t a, uint32_t b) { |
97 | 260 | return hw_divider_u32_quotient(a,b); |
98 | 261 | } |
99 | 262 |
|
| 263 | +/*! \brief Do a hardware unsigned HW divide, wait for result, return remainder |
| 264 | + * \ingroup hardware_divider |
| 265 | + * |
| 266 | + * Divide \p a by \p b, wait for calculation to complete, return remainder. |
| 267 | + * |
| 268 | + * \param a The dividend |
| 269 | + * \param b The divisor |
| 270 | + * \return Remainder result of the divide |
| 271 | + */ |
100 | 272 | static inline uint32_t hw_divider_u32_remainder_inlined(uint32_t a, uint32_t b) { |
101 | 273 | return hw_divider_u32_remainder(a,b); |
102 | 274 | } |
103 | 275 |
|
| 276 | +/*! \brief Do a hardware signed HW divide, wait for result, return quotient |
| 277 | + * \ingroup hardware_divider |
| 278 | + * |
| 279 | + * Divide \p a by \p b, wait for calculation to complete, return quotient. |
| 280 | + * |
| 281 | + * \param a The dividend |
| 282 | + * \param b The divisor |
| 283 | + * \return Quotient result of the divide |
| 284 | + */ |
104 | 285 | static inline int32_t hw_divider_s32_quotient_inlined(int32_t a, int32_t b) { |
105 | | - return hw_divider_s32_quotient(a,b); |
| 286 | + return hw_divider_quotient_s32(a,b); |
106 | 287 | } |
107 | 288 |
|
| 289 | +/*! \brief Do a hardware signed HW divide, wait for result, return remainder |
| 290 | + * \ingroup hardware_divider |
| 291 | + * |
| 292 | + * Divide \p a by \p b, wait for calculation to complete, return remainder. |
| 293 | + * |
| 294 | + * \param a The dividend |
| 295 | + * \param b The divisor |
| 296 | + * \return Remainder result of the divide |
| 297 | + */ |
108 | 298 | static inline int32_t hw_divider_s32_remainder_inlined(int32_t a, int32_t b) { |
109 | | - return hw_divider_s32_remainder(a,b); |
| 299 | + return hw_divider_remainder_s32(a,b); |
110 | 300 | } |
111 | 301 |
|
112 | 302 | typedef uint64_t hw_divider_state_t; |
113 | 303 |
|
114 | | -static inline void hw_divider_save_state(hw_divider_state_t *dest) { |
| 304 | +/*! \brief Save the calling cores hardware divider state |
| 305 | + * \ingroup hardware_divider |
| 306 | + * |
| 307 | + * Copy the current core's hardware divider state into the provided structure. This method |
| 308 | + * waits for the divider results to be stable, then copies them to memory. |
| 309 | + * They can be restored via hw_divider_restore_state() |
| 310 | + * |
| 311 | + * \param dest the location to store the divider state |
| 312 | + */ |
| 313 | + static inline void hw_divider_save_state(hw_divider_state_t *dest) { |
115 | 314 | *dest = hw_divider_result_threadlocal; |
116 | 315 | } |
117 | 316 |
|
118 | | -static inline void hw_divider_restore_state(hw_divider_state_t *src) { |
| 317 | +/*! \brief Load a saved hardware divider state into the current core's hardware divider |
| 318 | + * \ingroup hardware_divider |
| 319 | + * |
| 320 | + * Copy the passed hardware divider state into the hardware divider. |
| 321 | + * |
| 322 | + * \param src the location to load the divider state from |
| 323 | + */ |
| 324 | + static inline void hw_divider_restore_state(hw_divider_state_t *src) { |
119 | 325 | hw_divider_result_threadlocal = *src; |
120 | 326 | } |
121 | 327 |
|
| 328 | +#ifdef __cplusplus |
| 329 | +} |
| 330 | +#endif |
122 | 331 | #endif // _HARDWARE_DIVIDER_H |
0 commit comments