@web-font-path: "roboto-debian.css";
v2.2.0 (RP2040)
Loading...
Searching...
No Matches
divider.h
Go to the documentation of this file.
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_DIVIDER_H
#define _HARDWARE_DIVIDER_H
#include "pico.h"
#if HAS_SIO_DIVIDER
#include "hardware/structs/sio.h"
#else
#define PICO_EMULATE_DIVIDER 1
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef uint64_t divmod_result_t;
#if PICO_EMULATE_DIVIDER
extern divmod_result_t hw_divider_results[NUM_CORES];
static inline int __sign_of(int32_t v) {
return v > 0 ? 1 : (v < 0 ? -1 : 0);
}
#endif
#if !PICO_EMULATE_DIVIDER
divmod_result_t hw_divider_divmod_s32(int32_t a, int32_t b);
#else
static inline divmod_result_t hw_divider_divmod_s32(int32_t a, int32_t b) {
if (!b) return (((uint64_t)a)<<32u) | (uint32_t)(-__sign_of(a));
return (((uint64_t)(a%b))<<32u) | (uint32_t)(a/b);
}
#endif
#if !PICO_EMULATE_DIVIDER
divmod_result_t hw_divider_divmod_u32(uint32_t a, uint32_t b);
#else
static inline divmod_result_t hw_divider_divmod_u32(uint32_t a, uint32_t b) {
if (!b) return (((uint64_t)a)<<32u) | (uint32_t)(-1); // todo check this
return (((uint64_t)(a%b))<<32u) | (a/b);
}
#endif
static inline void hw_divider_divmod_s32_start(int32_t a, int32_t b) {
#if !PICO_EMULATE_DIVIDER
check_hw_layout( sio_hw_t, div_sdividend, SIO_DIV_SDIVIDEND_OFFSET);
sio_hw->div_sdividend = (uint32_t)a;
sio_hw->div_sdivisor = (uint32_t)b;
#else
hw_divider_results[get_core_num()] = hw_divider_divmod_s32(a, b);
#endif
}
static inline void hw_divider_divmod_u32_start(uint32_t a, uint32_t b) {
#if !PICO_EMULATE_DIVIDER
check_hw_layout(
sio_hw_t, div_udividend, SIO_DIV_UDIVIDEND_OFFSET);
sio_hw->div_udividend = a;
sio_hw->div_udivisor = b;
#else
hw_divider_results[get_core_num()] = hw_divider_divmod_u32(a, b);
#endif
}
static inline void hw_divider_wait_ready(void) {
#if !PICO_EMULATE_DIVIDER
// this is #1 in lsr below
static_assert(SIO_DIV_CSR_READY_BITS == 1, "");
// we use one less register and instruction than gcc which uses a TST instruction
uint32_t tmp; // allow compiler to pick scratch register
pico_default_asm_volatile (
"hw_divider_result_loop_%=:"
"ldr %0, [%1, %2]\n\t"
"lsrs %0, %0, #1\n\t"
"bcc hw_divider_result_loop_%=\n\t"
: "=&l" (tmp)
: "l" (sio_hw), "I" (SIO_DIV_CSR_OFFSET)
: "cc"
);
#endif
}
static inline divmod_result_t hw_divider_result_nowait(void) {
#if !PICO_EMULATE_DIVIDER
// as ugly as this looks it is actually quite efficient
divmod_result_t rc = ((divmod_result_t) sio_hw->div_remainder) << 32u;
rc |= sio_hw->div_quotient;
return rc;
#else
return hw_divider_results[get_core_num()];
#endif
}
static inline divmod_result_t hw_divider_result_wait(void) {
hw_divider_wait_ready();
return hw_divider_result_nowait();
}
inline static uint32_t to_quotient_u32(divmod_result_t r) {
return (uint32_t) r;
}
inline static int32_t to_quotient_s32(divmod_result_t r) {
return (int32_t)(uint32_t)r;
}
inline static uint32_t to_remainder_u32(divmod_result_t r) {
return (uint32_t)(r >> 32u);
}
inline static int32_t to_remainder_s32(divmod_result_t r) {
return (int32_t)(r >> 32u);
}
static inline uint32_t hw_divider_u32_quotient_wait(void) {
#if !PICO_EMULATE_DIVIDER
hw_divider_wait_ready();
return sio_hw->div_quotient;
#else
return to_quotient_u32(hw_divider_result_wait());
#endif
}
static inline int32_t hw_divider_s32_quotient_wait(void) {
#if !PICO_EMULATE_DIVIDER
hw_divider_wait_ready();
return (int32_t)sio_hw->div_quotient;
#else
return to_quotient_s32(hw_divider_result_wait());
#endif
}
static inline uint32_t hw_divider_u32_remainder_wait(void) {
#if !PICO_EMULATE_DIVIDER
hw_divider_wait_ready();
uint32_t rc = sio_hw->div_remainder;
sio_hw->div_quotient; // must read quotient to cooperate with other SDK code
return rc;
#else
return to_remainder_u32(hw_divider_result_wait());
#endif
}
static inline int32_t hw_divider_s32_remainder_wait(void) {
#if !PICO_EMULATE_DIVIDER
hw_divider_wait_ready();
int32_t rc = (int32_t)sio_hw->div_remainder;
sio_hw->div_quotient; // must read quotient to cooperate with other SDK code
return rc;
#else
return to_remainder_s32(hw_divider_result_wait());
#endif
}
static inline uint32_t hw_divider_u32_quotient(uint32_t a, uint32_t b) {
#if !PICO_EMULATE_DIVIDER
return to_quotient_u32(hw_divider_divmod_u32(a, b));
#else
return b ? (a / b) : (uint32_t)(-1);
#endif
}
static inline uint32_t hw_divider_u32_remainder(uint32_t a, uint32_t b) {
#if !PICO_EMULATE_DIVIDER
return to_remainder_u32(hw_divider_divmod_u32(a, b));
#else
return b ? (a % b) : a;
#endif
}
static inline int32_t hw_divider_quotient_s32(int32_t a, int32_t b) {
#if !PICO_EMULATE_DIVIDER
return to_quotient_s32(hw_divider_divmod_s32(a, b));
#else
return b ? (a / b) : -1;
#endif
}
static inline int32_t hw_divider_remainder_s32(int32_t a, int32_t b) {
#if !PICO_EMULATE_DIVIDER
return to_remainder_s32(hw_divider_divmod_s32(a, b));
#else
return b ? (a % b) : a;
#endif
}
static inline void hw_divider_pause(void) {
#if !PICO_EMULATE_DIVIDER
pico_default_asm_volatile(
"b _1_%=\n"
"_1_%=:\n"
"b _2_%=\n"
"_2_%=:\n"
"b _3_%=\n"
"_3_%=:\n"
"b _4_%=\n"
"_4_%=:\n"
:::);
#endif
}
static inline uint32_t hw_divider_u32_quotient_inlined(uint32_t a, uint32_t b) {
#if !PICO_EMULATE_DIVIDER
hw_divider_divmod_u32_start(a, b);
hw_divider_pause();
return sio_hw->div_quotient;
#else
return hw_divider_u32_quotient(a,b);
#endif
}
static inline uint32_t hw_divider_u32_remainder_inlined(uint32_t a, uint32_t b) {
#if !PICO_EMULATE_DIVIDER
hw_divider_divmod_u32_start(a, b);
hw_divider_pause();
uint32_t rc = sio_hw->div_remainder;
sio_hw->div_quotient; // must read quotient to cooperate with other SDK code
return rc;
#else
return hw_divider_u32_remainder(a,b);
#endif
}
static inline int32_t hw_divider_s32_quotient_inlined(int32_t a, int32_t b) {
#if !PICO_EMULATE_DIVIDER
hw_divider_divmod_s32_start(a, b);
hw_divider_pause();
return (int32_t)sio_hw->div_quotient;
#else
return hw_divider_quotient_s32(a,b);
#endif
}
static inline int32_t hw_divider_s32_remainder_inlined(int32_t a, int32_t b) {
#if !PICO_EMULATE_DIVIDER
hw_divider_divmod_s32_start(a, b);
hw_divider_pause();
int32_t rc = (int32_t)sio_hw->div_remainder;
sio_hw->div_quotient; // must read quotient to cooperate with other SDK code
return rc;
#else
return hw_divider_remainder_s32(a,b);
#endif
}
#if !PICO_EMULATE_DIVIDER
typedef struct {
uint32_t values[4];
} hw_divider_state_t;
#else
typedef uint64_t hw_divider_state_t;
#endif
#if !PICO_EMULATE_DIVIDER
void hw_divider_save_state(hw_divider_state_t *dest);
#else
static inline void hw_divider_save_state(hw_divider_state_t *dest) {
*dest = hw_divider_results[get_core_num()];
}
#endif
#if !PICO_EMULATE_DIVIDER
void hw_divider_restore_state(hw_divider_state_t *src);
#else
static inline void hw_divider_restore_state(hw_divider_state_t *src) {
hw_divider_results[get_core_num()] = *src;
}
#endif
#ifdef __cplusplus
}
#endif
#endif // _HARDWARE_DIVIDER_H
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:348
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:198
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:440
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:276
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:126
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:107
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:365
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:419
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:244
hw_divider_result_nowait
static divmod_result_t hw_divider_result_nowait(void)
Return result of HW divide, nowait.
Definition divider.h:169
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:208
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:232
hw_divider_divmod_s32
static divmod_result_t hw_divider_divmod_s32(int32_t a, int32_t b)
Do a signed HW divide and wait for result.
Definition divider.h:74
hw_divider_wait_ready
static void hw_divider_wait_ready(void)
Wait for a divide to complete.
Definition divider.h:142
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:459
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:314
hw_divider_restore_state
static 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:506
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:331
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:260
hw_divider_save_state
static void hw_divider_save_state(hw_divider_state_t *dest)
Save the calling cores hardware divider state.
Definition divider.h:491
hw_divider_result_wait
static divmod_result_t hw_divider_result_wait(void)
Return result of last asynchronous HW divide.
Definition divider.h:187
hw_divider_divmod_u32
static divmod_result_t hw_divider_divmod_u32(uint32_t a, uint32_t b)
Do an unsigned HW divide and wait for result.
Definition divider.h:92
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:376
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:400
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:294
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:220
get_core_num
static __force_inline uint get_core_num(void)
Get the current core number.
Definition platform.h:114
pico.h
sio_hw_t
Definition sio.h:28