divider.h
Go to the documentation of this file.
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.h"
11 #include "hardware/structs/sio.h"
12 
39 #ifdef __cplusplus
40 extern "C" {
41 #endif
42 
43 typedef uint64_t divmod_result_t;
44 
54 static inline void hw_divider_divmod_s32_start(int32_t a, int32_t b) {
55  check_hw_layout( sio_hw_t, div_sdividend, SIO_DIV_SDIVIDEND_OFFSET);
56  sio_hw->div_sdividend = (uint32_t)a;
57  sio_hw->div_sdivisor = (uint32_t)b;
58 }
59 
69 static inline void hw_divider_divmod_u32_start(uint32_t a, uint32_t b) {
70  check_hw_layout(
71  sio_hw_t, div_udividend, SIO_DIV_UDIVIDEND_OFFSET);
72  sio_hw->div_udividend = a;
73  sio_hw->div_udivisor = b;
74 }
75 
81 static inline void hw_divider_wait_ready(void) {
82  // this is #1 in lsr below
83  static_assert(SIO_DIV_CSR_READY_BITS == 1, "");
84 
85  // we use one less register and instruction than gcc which uses a TST instruction
86 
87  uint32_t tmp; // allow compiler to pick scratch register
88  asm volatile (
89  "hw_divider_result_loop_%=:"
90  "ldr %0, [%1, %2]\n\t"
91  "lsr %0, #1\n\t"
92  "bcc hw_divider_result_loop_%=\n\t"
93  : "=&l" (tmp)
94  : "l" (sio_hw), "I" (SIO_DIV_CSR_OFFSET)
95  :
96  );
97 }
98 
106 static inline divmod_result_t hw_divider_result_nowait(void) {
107  // as ugly as this looks it is actually quite efficient
108  divmod_result_t rc = (((divmod_result_t) sio_hw->div_remainder) << 32u) | sio_hw->div_quotient;
109  return rc;
110 }
111 
119 static inline divmod_result_t hw_divider_result_wait(void) {
121  return hw_divider_result_nowait();
122 }
123 
131 static inline uint32_t hw_divider_u32_quotient_wait(void) {
133  return sio_hw->div_quotient;
134 }
135 
143 static inline int32_t hw_divider_s32_quotient_wait(void) {
145  return (int32_t)sio_hw->div_quotient;
146 }
147 
155 static inline uint32_t hw_divider_u32_remainder_wait(void) {
157  uint32_t rc = sio_hw->div_remainder;
158  sio_hw->div_quotient; // must read quotient to cooperate with other SDK code
159  return rc;
160 }
161 
169 static inline int32_t hw_divider_s32_remainder_wait(void) {
171  int32_t rc = (int32_t)sio_hw->div_remainder;
172  sio_hw->div_quotient; // must read quotient to cooperate with other SDK code
173  return rc;
174 }
175 
185 divmod_result_t hw_divider_divmod_s32(int32_t a, int32_t b);
186 
196 divmod_result_t hw_divider_divmod_u32(uint32_t a, uint32_t b);
197 
204 inline static uint32_t to_quotient_u32(divmod_result_t r) {
205  return (uint32_t) r;
206 }
207 
214 inline static int32_t to_quotient_s32(divmod_result_t r) {
215  return (int32_t)(uint32_t)r;
216 }
217 
226 inline static uint32_t to_remainder_u32(divmod_result_t r) {
227  return (uint32_t)(r >> 32u);
228 }
229 
238 inline static int32_t to_remainder_s32(divmod_result_t r) {
239  return (int32_t)(r >> 32u);
240 }
241 
251 static inline uint32_t hw_divider_u32_quotient(uint32_t a, uint32_t b) {
253 }
254 
264 static inline uint32_t hw_divider_u32_remainder(uint32_t a, uint32_t b) {
266 }
267 
277 static inline int32_t hw_divider_quotient_s32(int32_t a, int32_t b) {
279 }
280 
290 static inline int32_t hw_divider_remainder_s32(int32_t a, int32_t b) {
292 }
293 
297 static inline void hw_divider_pause(void) {
298  asm volatile (
299  "b _1_%=\n"
300  "_1_%=:\n"
301  "b _2_%=\n"
302  "_2_%=:\n"
303  "b _3_%=\n"
304  "_3_%=:\n"
305  "b _4_%=\n"
306  "_4_%=:\n"
307  :: : );
308 }
309 
319 static inline uint32_t hw_divider_u32_quotient_inlined(uint32_t a, uint32_t b) {
322  return sio_hw->div_quotient;
323 }
324 
334 static inline uint32_t hw_divider_u32_remainder_inlined(uint32_t a, uint32_t b) {
337  uint32_t rc = sio_hw->div_remainder;
338  sio_hw->div_quotient; // must read quotient to cooperate with other SDK code
339  return rc;
340 }
341 
351 static inline int32_t hw_divider_s32_quotient_inlined(int32_t a, int32_t b) {
354  return (int32_t)sio_hw->div_quotient;
355 }
356 
366 static inline int32_t hw_divider_s32_remainder_inlined(int32_t a, int32_t b) {
369  int32_t rc = (int32_t)sio_hw->div_remainder;
370  sio_hw->div_quotient; // must read quotient to cooperate with other SDK code
371  return rc;
372 }
373 
374 typedef struct {
375  uint32_t values[4];
377 
388 
398 
399 #ifdef __cplusplus
400 }
401 #endif
402 
403 #endif // _HARDWARE_DIVIDER_H
hw_divider_save_state
void hw_divider_save_state(hw_divider_state_t *dest)
Save the calling cores hardware divider state.
hw_divider_result_nowait
static divmod_result_t hw_divider_result_nowait(void)
Return result of HW divide, nowait.
Definition: divider.h:106
hw_divider_u32_remainder_wait
static uint32_t hw_divider_u32_remainder_wait(void)
Return result of last asynchronous HW divide, unsigned remainder only.
Definition: divider.h:155
hw_divider_u32_remainder_inlined
static uint32_t hw_divider_u32_remainder_inlined(uint32_t a, uint32_t b)
Do a hardware unsigned HW divide, wait for result, return remainder.
Definition: divider.h:334
to_remainder_s32
static int32_t to_remainder_s32(divmod_result_t r)
Efficient extraction of signed remainder from 32p32 fixed point.
Definition: divider.h:238
hw_divider_s32_remainder_inlined
static int32_t hw_divider_s32_remainder_inlined(int32_t a, int32_t b)
Do a hardware signed HW divide, wait for result, return remainder.
Definition: divider.h:366
to_quotient_u32
static uint32_t to_quotient_u32(divmod_result_t r)
Efficient extraction of unsigned quotient from 32p32 fixed point.
Definition: divider.h:204
to_quotient_s32
static int32_t to_quotient_s32(divmod_result_t r)
Efficient extraction of signed quotient from 32p32 fixed point.
Definition: divider.h:214
hw_divider_state_t
Definition: divider.h:374
to_remainder_u32
static uint32_t to_remainder_u32(divmod_result_t r)
Efficient extraction of unsigned remainder from 32p32 fixed point.
Definition: divider.h:226
hw_divider_wait_ready
static void hw_divider_wait_ready(void)
Wait for a divide to complete.
Definition: divider.h:81
hw_divider_u32_quotient_wait
static uint32_t hw_divider_u32_quotient_wait(void)
Return result of last asynchronous HW divide, unsigned quotient only.
Definition: divider.h:131
hw_divider_u32_quotient
static uint32_t hw_divider_u32_quotient(uint32_t a, uint32_t b)
Do an unsigned HW divide, wait for result, return quotient.
Definition: divider.h:251
sio_hw_t
Definition: sio.h:24
hw_divider_remainder_s32
static int32_t hw_divider_remainder_s32(int32_t a, int32_t b)
Do a signed HW divide, wait for result, return remainder.
Definition: divider.h:290
hw_divider_quotient_s32
static int32_t hw_divider_quotient_s32(int32_t a, int32_t b)
Do a signed HW divide, wait for result, return quotient.
Definition: divider.h:277
hw_divider_divmod_u32
divmod_result_t hw_divider_divmod_u32(uint32_t a, uint32_t b)
Do an unsigned HW divide and wait for result.
hw_divider_restore_state
void hw_divider_restore_state(hw_divider_state_t *src)
Load a saved hardware divider state into the current core's hardware divider.
hw_divider_u32_quotient_inlined
static uint32_t hw_divider_u32_quotient_inlined(uint32_t a, uint32_t b)
Do a hardware unsigned HW divide, wait for result, return quotient.
Definition: divider.h:319
hw_divider_s32_quotient_inlined
static int32_t hw_divider_s32_quotient_inlined(int32_t a, int32_t b)
Do a hardware signed HW divide, wait for result, return quotient.
Definition: divider.h:351
pico.h
hw_divider_pause
static void hw_divider_pause(void)
Pause for exact amount of time needed for a asynchronous divide to complete.
Definition: divider.h:297
hw_divider_u32_remainder
static uint32_t hw_divider_u32_remainder(uint32_t a, uint32_t b)
Do an unsigned HW divide, wait for result, return remainder.
Definition: divider.h:264
hw_divider_s32_remainder_wait
static int32_t hw_divider_s32_remainder_wait(void)
Return result of last asynchronous HW divide, signed remainder only.
Definition: divider.h:169
hw_divider_result_wait
static divmod_result_t hw_divider_result_wait(void)
Return result of last asynchronous HW divide.
Definition: divider.h:119
hw_divider_divmod_s32
divmod_result_t hw_divider_divmod_s32(int32_t a, int32_t b)
Do a signed HW divide and wait for result.
hw_divider_s32_quotient_wait
static int32_t hw_divider_s32_quotient_wait(void)
Return result of last asynchronous HW divide, signed quotient only.
Definition: divider.h:143
hw_divider_divmod_u32_start
static void hw_divider_divmod_u32_start(uint32_t a, uint32_t b)
Start an unsigned asynchronous divide.
Definition: divider.h:69
hw_divider_divmod_s32_start
static void hw_divider_divmod_s32_start(int32_t a, int32_t b)
Start a signed asynchronous divide.
Definition: divider.h:54