#!/usr/bin/env python3 # # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) # # SPDX-License-Identifier: GPL-2.0-only # # this script can be used to calculate the reciprocal for # unsigned division of an unknown 64 bit value by a known 64bit # constant. It is used to calculate the correct magic numbers # for fixed cpu times on arm in order to do 64 bit division to calculate # ticks -> microseconds. # for details on how this script works, # see Hacker's delight, Chapter 10, unsigned division. from math import floor, ceil import argparse import sys from past.builtins import xrange # now unsigned def magicgu(nmax, d): nc = ((nmax + 1)//d)*d - 1 nbits = len(bin(nmax)) - 2 for p in range(0, 2*nbits + 1): if 2**p > nc*(d - 1 - (2**p - 1) % d): m = (2**p + d - 1 - (2**p - 1) % d)//d return (m, p) print("Can't find p, something is wrong.") sys.exit(1) def do_div(n): return ((n + add_ind) * magic) >> shift_amt if __name__ == "__main__": parser = argparse.ArgumentParser( description="Generate magic numbers for emulating 64-bit division with multiplication by reciprocal using algorithm from Hacker's Delight, chapter 10.") parser.add_argument("--divisor", type=int, required=True, help="Devisor to calculate magic numbers for") args = parser.parse_args() magic, shift_amt = magicgu(2**32 - 1, args.divisor) print("magic number is: %d, shift amount is %d" % (magic, shift_amt)) add_ind = 0 print("Doing sanity check") # sanity check for i in xrange(2**32-1): q1, q2 = (i / args.divisor, do_div(i)) if int(q1) != q2: print("Combination failed %d %d %d" % i, q1, q2) sys.exit(-1) print("Success! Use (n * %d) >> %d to calculate n / %d" % (magic, shift_amt, args.divisor)) print("magic number is: %d, shift amount is %d" % (magic, shift_amt))