| // Copyright lowRISC contributors. | |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. | |
| // SPDX-License-Identifier: Apache-2.0 | |
| #include "sw/device/lib/base/math.h" | |
| #include <stddef.h> | |
| uint64_t udiv64_slow(uint64_t a, uint64_t b, uint64_t *rem_out) { | |
| uint64_t quot = 0, rem = 0; | |
| // Schoolbook long division in base 2. See | |
| // https://en.wikipedia.org/wiki/Long_division to recall precisely how this | |
| // works. This algorithm is a bit different from the elementary school base-10 | |
| // version, since we can use shifts instead of multiplication. | |
| // | |
| // If `b` is zero, `quot == -1` and `rem == a`. This should not be relied | |
| // upon. | |
| size_t bits = sizeof(uint64_t) * 8; | |
| for (size_t i = 0; i < bits; ++i) { | |
| rem <<= 1; | |
| quot <<= 1; | |
| rem |= (a >> (bits - i - 1)) & 1; | |
| // We need to keep bringing down zeros until `rem`, the running total, is | |
| // large enough that we can subtract off `b`; this tells us the value we | |
| // would have had to multiply `a` by to produce this current step in the | |
| // division. | |
| if (rem >= b) { | |
| rem -= b; | |
| quot |= 1; | |
| } | |
| } | |
| if (rem_out != NULL) { | |
| *rem_out = rem; | |
| } | |
| return quot; | |
| } |