Files
seL4/tools/reciprocal.py
Gerwin Klein e9b9f821b6 tools: types + python3 tweaks for reciprocal.py
- add type annotations for pylance/strict
- replace xrange by range for python3
- point out that you need 128-bit intermediate for 64-bit
  division by multiplication

There should be no behaviour change.

Signed-off-by: Gerwin Klein <gerwin.klein@proofcraft.systems>
2026-04-05 11:51:54 +10:00

63 lines
2.0 KiB
Python
Executable File

#!/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.
# Note that you need an intermediate value that is 128 bits wide for the
# multiplication if want to guarantee absence of overflow when you have a 64 bit
# divisor.
from __future__ import annotations
import argparse
import sys
def magicgu(nmax: int, d: int) -> tuple[int, int]:
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: int) -> int:
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 range(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))