divider.h
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
40extern "C" {
41#endif
42
43typedef uint64_t divmod_result_t;
44
54static 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
69static 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
81static 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
106static 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
119static inline divmod_result_t hw_divider_result_wait(void) {
122}
123
131static inline uint32_t hw_divider_u32_quotient_wait(void) {
133 return sio_hw->div_quotient;
134}
135
143static inline int32_t hw_divider_s32_quotient_wait(void) {
145 return (int32_t)sio_hw->div_quotient;
146}
147
155static 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
169static 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
185divmod_result_t hw_divider_divmod_s32(int32_t a, int32_t b);
186
196divmod_result_t hw_divider_divmod_u32(uint32_t a, uint32_t b);
197
204inline static uint32_t to_quotient_u32(divmod_result_t r) {
205 return (uint32_t) r;
206}
207
214inline static int32_t to_quotient_s32(divmod_result_t r) {
215 return (int32_t)(uint32_t)r;
216}
217
226inline static uint32_t to_remainder_u32(divmod_result_t r) {
227 return (uint32_t)(r >> 32u);
228}
229
238inline static int32_t to_remainder_s32(divmod_result_t r) {
239 return (int32_t)(r >> 32u);
240}
241
251static inline uint32_t hw_divider_u32_quotient(uint32_t a, uint32_t b) {
253}
254
264static inline uint32_t hw_divider_u32_remainder(uint32_t a, uint32_t b) {
266}
267
277static inline int32_t hw_divider_quotient_s32(int32_t a, int32_t b) {
279}
280
290static inline int32_t hw_divider_remainder_s32(int32_t a, int32_t b) {
292}
293
297static 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
319static inline uint32_t hw_divider_u32_quotient_inlined(uint32_t a, uint32_t b) {
322 return sio_hw->div_quotient;
323}
324
334static 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
351static inline int32_t hw_divider_s32_quotient_inlined(int32_t a, int32_t b) {
354 return (int32_t)sio_hw->div_quotient;
355}
356
366static 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
374typedef struct {
375 uint32_t values[4];
377
388
398
399#ifdef __cplusplus
400}
401#endif
402
403#endif // _HARDWARE_DIVIDER_H
divmod_result_t hw_divider_divmod_u32(uint32_t a, uint32_t b)
Do an unsigned HW divide and wait for result.
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
static uint32_t to_quotient_u32(divmod_result_t r)
Efficient extraction of unsigned quotient from 32p32 fixed point.
Definition: divider.h:204
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
static uint32_t hw_divider_u32_remainder_wait(void)
Return result of last asynchronous HW divide, unsigned remainder only.
Definition: divider.h:155
static void hw_divider_divmod_u32_start(uint32_t a, uint32_t b)
Start an unsigned asynchronous divide.
Definition: divider.h:69
static void hw_divider_divmod_s32_start(int32_t a, int32_t b)
Start a signed asynchronous divide.
Definition: divider.h:54
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
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
static uint32_t hw_divider_u32_quotient_wait(void)
Return result of last asynchronous HW divide, unsigned quotient only.
Definition: divider.h:131
static divmod_result_t hw_divider_result_nowait(void)
Return result of HW divide, nowait.
Definition: divider.h:106
static int32_t to_quotient_s32(divmod_result_t r)
Efficient extraction of signed quotient from 32p32 fixed point.
Definition: divider.h:214
static int32_t to_remainder_s32(divmod_result_t r)
Efficient extraction of signed remainder from 32p32 fixed point.
Definition: divider.h:238
static void hw_divider_wait_ready(void)
Wait for a divide to complete.
Definition: divider.h:81
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
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
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
static int32_t hw_divider_s32_quotient_wait(void)
Return result of last asynchronous HW divide, signed quotient only.
Definition: divider.h:143
static divmod_result_t hw_divider_result_wait(void)
Return result of last asynchronous HW divide.
Definition: divider.h:119
static void hw_divider_pause(void)
Pause for exact amount of time needed for a asynchronous divide to complete.
Definition: divider.h:297
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
static int32_t hw_divider_s32_remainder_wait(void)
Return result of last asynchronous HW divide, signed remainder only.
Definition: divider.h:169
divmod_result_t hw_divider_divmod_s32(int32_t a, int32_t b)
Do a signed HW divide and wait for result.
static uint32_t to_remainder_u32(divmod_result_t r)
Efficient extraction of unsigned remainder from 32p32 fixed point.
Definition: divider.h:226
void hw_divider_save_state(hw_divider_state_t *dest)
Save the calling cores hardware divider state.
void hw_divider_restore_state(hw_divider_state_t *src)
Load a saved hardware divider state into the current core's hardware divider.
Definition: divider.h:374
Definition: sio.h:24