Source code for hwt.math

from copy import copy
import math
from typing import List, Union

from hwt.doc_markers import hwt_expr_producer
from hwt.hdl.const import HConst
from hwt.hdl.types.bits import HBits
from hwt.hdl.types.hdlType import HdlType
from hwt.mainBases import HwIOBase
from hwt.mainBases import RtlSignalBase
from pyMathBitPrecise.bit_utils import mask

AnyHValue = Union[HConst, RtlSignalBase, HwIOBase]


[docs] def inRange(n: Union[int, AnyHValue], start: Union[int, AnyHValue], end: Union[int, AnyHValue]): """ Check if n is in range <start, end) """ res = (n >= start) if isinstance(n, (RtlSignalBase, HwIOBase, HConst)) and\ (not isinstance(end, int) or end < 2 ** n._dtype.bit_length()): res = res & (n < end) return res
[docs] def toPow2Ceil(x: int): """ Get the smallest 2**N where 2**N >= x """ i = 0 while 2 ** i < x: i += 1 return 2 ** i
[docs] def toPow2Floor(n: int): """ Get the largest 2**N where 2**N <= x """ if n < 1: return 0 exponent = int(math.log2(n)) return 2 ** exponent
[docs] def addressAlignBestEffort(record_width: int, bus_data_width: int): """ Optionally extend the record width to be power of 2 and to consume smallest amount of memory possible. """ if 2 * record_width <= bus_data_width: # multiple records in bus data word records_in_bus_word = math.floor(bus_data_width / record_width) record_width = bus_data_width // records_in_bus_word bus_words_in_record = 1 else: # record in a 1+ bus data words bus_words_in_record = math.ceil(record_width / bus_data_width) # in order to make item indexable we need to have size which is 2**X bus_words_in_record = toPow2Ceil(bus_words_in_record) record_width = bus_data_width * bus_words_in_record records_in_bus_word = 1 return record_width, records_in_bus_word, bus_words_in_record
[docs] def log2ceil(x: Union[int, float]): """ Returns no of bits required to store x-1 for example x=8 returns 3 """ if not isinstance(x, (int, float)): x = int(x) if x == 0 or x == 1: res = 1 else: res = math.ceil(math.log2(x)) return res
[docs] def isPow2(num: Union[int, float]) -> bool: """ Check if number or constant is power of two """ if not isinstance(num, int): num = int(num) return num != 0 and ((num & (num - 1)) == 0)
[docs] def sizeof(_type: HdlType) -> int: "get size of type in bytes" s = _type.bit_length() return math.ceil(s / 8)
[docs] def shiftIntArray(values: List[Union[int, "HBitsConst"]], item_width: int, shift: int): """ :param values: array of values which will be shifted as a whole :param item_width: a bit length of a single item in array :param shift: specifies how many bits the array should be shifted, << is a positive shift, >> is a negative shift """ if shift == 0: return copy(values) new_v = [] t = HBits(item_width) if shift > 0: # << for _ in range(shift // item_width): new_v.append(None) prev = None for v in values: if v is None and prev is None: _v = None else: if prev is None: prev = t.from_py(None) if v is None: v = t.from_py(None) elif isinstance(prev, HConst) and not isinstance(v, HConst): v = t.from_py(v) _v = (v << shift) | (prev >> (item_width - shift)) new_v.append(_v) prev = v if prev is None: v = None else: v = prev >> (item_width - shift) new_v.append(v) else: # shift < 0, >> nextIt = iter(values) for v in values: try: nv = next(nextIt) except StopIteration: nv = None if nv is None and v is None: _v = None else: if nv is None: nv = t.from_py(None) if v is None: v = t.from_py(None) _v = (v >> shift) | (nv & mask(shift)) new_v.append(_v) return new_v
[docs] @hwt_expr_producer def hMin(a: AnyHValue, b: AnyHValue): minOpFn = getattr(a, "__min__", None) if minOpFn: return minOpFn(b) c = a < b if isinstance(c, bool): return a if c else b else: return c._ternary(a, b)
[docs] @hwt_expr_producer def hMax(a: AnyHValue, b: AnyHValue): opFn = getattr(a, "__max__", None) if opFn: return opFn(b) c = a > b if isinstance(c, bool): return a if c else b else: return c._ternary(a, b)