Austin Schuh | 208337d | 2022-01-01 14:29:11 -0800 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. |
| 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | */ |
| 6 | |
| 7 | #include "pico/divider.h" |
| 8 | |
| 9 | // These functions save/restore divider state, so are safe to call from interrupts |
| 10 | int32_t div_s32s32(int32_t a, int32_t b) { |
| 11 | return hw_divider_s32_quotient(a, b); |
| 12 | } |
| 13 | |
| 14 | divmod_result_t divmod_s32s32(int32_t a, int32_t b) { |
| 15 | return hw_divider_divmod_s32(a, b); |
| 16 | } |
| 17 | |
| 18 | uint32_t div_u32u32(uint32_t a, uint32_t b) { |
| 19 | return hw_divider_u32_quotient(a, b); |
| 20 | } |
| 21 | |
| 22 | divmod_result_t divmod_u32u32(uint32_t a, uint32_t b) { |
| 23 | return hw_divider_divmod_u32(a, b); |
| 24 | } |
| 25 | |
| 26 | static inline int __sign_of_64(int32_t v) { |
| 27 | return v > 0 ? 1 : (v < 0 ? -1 : 0); |
| 28 | } |
| 29 | |
| 30 | typedef struct { |
| 31 | uint64_t quotient; |
| 32 | uint64_t remainder; |
| 33 | } qr_u64; |
| 34 | |
| 35 | typedef struct { |
| 36 | int64_t quotient; |
| 37 | int64_t remainder; |
| 38 | } qr_s64; |
| 39 | |
| 40 | // divides unsigned values a by b... (a/b) returned in low 32 bits, (a%b) in high 32 bits... results undefined for b==0 |
| 41 | static inline qr_u64 udiv64(uint64_t a, uint64_t b) { |
| 42 | qr_u64 rc; |
| 43 | if (!b) { |
| 44 | rc.quotient = (uint64_t)-1; // todo check this |
| 45 | rc.remainder = a; |
| 46 | } else { |
| 47 | rc.quotient = a/b; |
| 48 | rc.remainder = a%b; |
| 49 | } |
| 50 | return rc; |
| 51 | } |
| 52 | |
| 53 | // divides signed values a by b... (a/b) returned in low 32 bits, (a%b) in high 32 bits... results undefined for b==0 |
| 54 | static inline qr_s64 div64(int64_t a, int64_t b) { |
| 55 | qr_s64 rc; |
| 56 | if (!b) { |
| 57 | rc.quotient = (uint64_t)(-__sign_of_64(a)); |
| 58 | rc.remainder = a; |
| 59 | } else { |
| 60 | rc.quotient = a/b; |
| 61 | rc.remainder = a%b; |
| 62 | } |
| 63 | return rc; |
| 64 | } |
| 65 | |
| 66 | int64_t div_s64s64(int64_t a, int64_t b) { |
| 67 | qr_s64 qr = div64(a, b); |
| 68 | return qr.quotient; |
| 69 | } |
| 70 | |
| 71 | int64_t divmod_s64s64_rem(int64_t a, int64_t b, int64_t *rem) { |
| 72 | qr_s64 qr = div64(a, b); |
| 73 | *rem = qr.remainder; |
| 74 | return qr.quotient; |
| 75 | } |
| 76 | |
| 77 | int64_t divmod_s64s64(int64_t a, int64_t b) { |
| 78 | qr_s64 qr = div64(a, b); |
| 79 | return qr.quotient; |
| 80 | } |
| 81 | |
| 82 | uint64_t div_u64u64(uint64_t a, uint64_t b) { |
| 83 | qr_u64 qr = udiv64(a, b); |
| 84 | return qr.quotient; |
| 85 | } |
| 86 | |
| 87 | uint64_t divmod_u64u64_rem(uint64_t a, uint64_t b, uint64_t *rem) { |
| 88 | qr_u64 qr = udiv64(a, b); |
| 89 | *rem = qr.remainder; |
| 90 | return qr.quotient; |
| 91 | } |
| 92 | |
| 93 | uint64_t divmod_u64u64(uint64_t a, uint64_t b) { |
| 94 | qr_u64 qr = udiv64(a, b); |
| 95 | return qr.quotient; |
| 96 | } |
| 97 | |
| 98 | // these functions are slightly faster, but unsafe the divider state, so are not generally safe to be called from interrupts |
| 99 | |
| 100 | int32_t div_s32s32_unsafe(int32_t a, int32_t b) { return div_s32s32(a,b); } |
| 101 | int32_t divmod_s32s32_rem_unsafe(int32_t a, int32_t b, int32_t *rem) { return divmod_s32s32_rem(a, b, rem); } |
| 102 | int64_t divmod_s32s32_unsafe(int32_t a, int32_t b) { return divmod_s32s32(a, b); } |
| 103 | |
| 104 | uint32_t div_u32u32_unsafe(uint32_t a, uint32_t b) { return div_u32u32(a, b); } |
| 105 | uint32_t divmod_u32u32_rem_unsafe(uint32_t a, uint32_t b, uint32_t *rem) { return divmod_u32u32_rem(a, b, rem); } |
| 106 | uint64_t divmod_u32u32_unsafe(uint32_t a, uint32_t b) { return divmod_u32u32(a, b); } |
| 107 | |
| 108 | int64_t div_s64s64_unsafe(int64_t a, int64_t b) { return div_s64s64(a, b); } |
| 109 | int64_t divmod_s64s64_rem_unsafe(int64_t a, int64_t b, int64_t *rem) { return divmod_s64s64_rem(a, b, rem); } |
| 110 | int64_t divmod_s64s64_unsafe(int64_t a, int64_t b) { return divmod_s64s64(a, b); } |
| 111 | |
| 112 | uint64_t div_u64u64_unsafe(uint64_t a, uint64_t b) { return div_u64u64(a, b); } |
| 113 | uint64_t divmod_u64u64_rem_unsafe(uint64_t a, uint64_t b, uint64_t *rem) { return divmod_u64u64_rem(a, b, rem); } |
| 114 | uint64_t divmod_u64u64_unsafe(uint64_t a, uint64_t b) { return divmod_u64u64(a, b); } |