From: Jacob Lifshay Date: Fri, 22 Oct 2021 05:58:33 +0000 (-0700) Subject: move SimdScope to separate file X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=96f15c29e57a41f1cdd480493da25826d84f7153;p=ieee754fpu.git move SimdScope to separate file --- diff --git a/src/ieee754/part/simd_scope.py b/src/ieee754/part/simd_scope.py new file mode 100644 index 00000000..a7f355d7 --- /dev/null +++ b/src/ieee754/part/simd_scope.py @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: LGPL-3-or-later +# See Notices.txt for copyright information + + +from ieee754.part.util import (DEFAULT_FP_PART_COUNTS, + DEFAULT_INT_PART_COUNTS, + FpElWid, IntElWid, SimdMap) +from nmigen.hdl.ast import Signal + + +class SimdScope: + """The global scope object for SimdSignal and friends + + Members: + * part_counts: SimdMap + a map from `ElWid` values `k` to the number of parts in an element + when `self.elwid == k`. Values should be minimized, since higher values + often create bigger circuits. + + Example: + # here, an I8 element is 1 part wide + part_counts = {ElWid.I8: 1, ElWid.I16: 2, ElWid.I32: 4, ElWid.I64: 8} + + Another Example: + # here, an F16 element is 1 part wide + part_counts = {ElWid.F16: 1, ElWid.BF16: 1, ElWid.F32: 2, ElWid.F64: 4} + * simd_full_width_hint: int + the default value for SimdLayout's full_width argument, the full number + of bits in a SIMD value. + * elwid: ElWid or nmigen Value with a shape of some ElWid class + the current elwid (simd element type) + """ + + __SCOPE_STACK = [] + + @classmethod + def get(cls): + """get the current SimdScope. + + Example: + SimdScope.get(None) is None + SimdScope.get() raises ValueError + with SimdScope(...) as s: + SimdScope.get() is s + """ + if len(cls.__SCOPE_STACK) > 0: + retval = cls.__SCOPE_STACK[-1] + assert isinstance(retval, SimdScope), "inconsistent scope stack" + return retval + raise ValueError("not in a `with SimdScope()` statement") + + def __enter__(self): + self.__SCOPE_STACK.append(self) + return self + + def __exit__(self, exc_type, exc_value, traceback): + assert self.__SCOPE_STACK.pop() is self, "inconsistent scope stack" + return False + + def __init__(self, *, simd_full_width_hint=64, elwid=None, + part_counts=None, elwid_type=IntElWid, scalar=False): + # TODO: add more arguments/members and processing for integration with + self.simd_full_width_hint = simd_full_width_hint + if isinstance(elwid, (IntElWid, FpElWid)): + elwid_type = type(elwid) + if part_counts is None: + part_counts = SimdMap({elwid: 1}) + assert issubclass(elwid_type, (IntElWid, FpElWid)) + self.elwid_type = elwid_type + scalar_elwid = elwid_type(0) + if part_counts is None: + if scalar: + part_counts = SimdMap({scalar_elwid: 1}) + elif issubclass(elwid_type, FpElWid): + part_counts = DEFAULT_FP_PART_COUNTS + else: + part_counts = DEFAULT_INT_PART_COUNTS + + def check(elwid, part_count): + assert type(elwid) == elwid_type, "inconsistent ElWid types" + part_count = int(part_count) + assert part_count != 0 and (part_count & (part_count - 1)) == 0,\ + "part_counts values must all be powers of two" + return part_count + + self.part_counts = SimdMap.map_with_elwid(check, part_counts) + self.full_part_count = max(part_counts.values()) + assert self.simd_full_width_hint % self.full_part_count == 0,\ + "simd_full_width_hint must be a multiple of full_part_count" + if elwid is not None: + self.elwid = elwid + elif scalar: + self.elwid = scalar_elwid + else: + self.elwid = Signal(elwid_type) + + def __repr__(self): + return (f"SimdScope(\n" + f" simd_full_width_hint={self.simd_full_width_hint},\n" + f" elwid={self.elwid},\n" + f" elwid_type={self.elwid_type},\n" + f" part_counts={self.part_counts},\n" + f" full_part_count={self.full_part_count})") diff --git a/src/ieee754/part/util.py b/src/ieee754/part/util.py index 8cadf8c1..095fb1b9 100644 --- a/src/ieee754/part/util.py +++ b/src/ieee754/part/util.py @@ -6,9 +6,6 @@ from typing import Mapping import operator import math from types import MappingProxyType -from contextlib import contextmanager - -from nmigen.hdl.ast import Signal class ElWid(Enum): @@ -300,98 +297,3 @@ DEFAULT_INT_PART_COUNTS = SimdMap({ _check_for_missing_elwidths("XLEN") _check_for_missing_elwidths("DEFAULT_FP_PART_COUNTS", FpElWid) _check_for_missing_elwidths("DEFAULT_INT_PART_COUNTS", IntElWid) - - -class SimdScope: - """The global scope object for SimdSignal and friends - - Members: - * part_counts: SimdMap - a map from `ElWid` values `k` to the number of parts in an element - when `self.elwid == k`. Values should be minimized, since higher values - often create bigger circuits. - - Example: - # here, an I8 element is 1 part wide - part_counts = {ElWid.I8: 1, ElWid.I16: 2, ElWid.I32: 4, ElWid.I64: 8} - - Another Example: - # here, an F16 element is 1 part wide - part_counts = {ElWid.F16: 1, ElWid.BF16: 1, ElWid.F32: 2, ElWid.F64: 4} - * simd_full_width_hint: int - the default value for SimdLayout's full_width argument, the full number - of bits in a SIMD value. - * elwid: ElWid or nmigen Value with a shape of some ElWid class - the current elwid (simd element type) - """ - - __SCOPE_STACK = [] - - @classmethod - def get(cls): - """get the current SimdScope. - - Example: - SimdScope.get(None) is None - SimdScope.get() raises ValueError - with SimdScope(...) as s: - SimdScope.get() is s - """ - if len(cls.__SCOPE_STACK) > 0: - retval = cls.__SCOPE_STACK[-1] - assert isinstance(retval, SimdScope), "inconsistent scope stack" - return retval - raise ValueError("not in a `with SimdScope()` statement") - - def __enter__(self): - self.__SCOPE_STACK.append(self) - return self - - def __exit__(self, exc_type, exc_value, traceback): - assert self.__SCOPE_STACK.pop() is self, "inconsistent scope stack" - return False - - def __init__(self, *, simd_full_width_hint=64, elwid=None, - part_counts=None, elwid_type=IntElWid, scalar=False): - # TODO: add more arguments/members and processing for integration with - self.simd_full_width_hint = simd_full_width_hint - if isinstance(elwid, (IntElWid, FpElWid)): - elwid_type = type(elwid) - if part_counts is None: - part_counts = SimdMap({elwid: 1}) - assert issubclass(elwid_type, (IntElWid, FpElWid)) - self.elwid_type = elwid_type - scalar_elwid = elwid_type(0) - if part_counts is None: - if scalar: - part_counts = SimdMap({scalar_elwid: 1}) - elif issubclass(elwid_type, FpElWid): - part_counts = DEFAULT_FP_PART_COUNTS - else: - part_counts = DEFAULT_INT_PART_COUNTS - - def check(elwid, part_count): - assert type(elwid) == elwid_type, "inconsistent ElWid types" - part_count = int(part_count) - assert part_count != 0 and (part_count & (part_count - 1)) == 0,\ - "part_counts values must all be powers of two" - return part_count - - self.part_counts = SimdMap.map_with_elwid(check, part_counts) - self.full_part_count = max(part_counts.values()) - assert self.simd_full_width_hint % self.full_part_count == 0,\ - "simd_full_width_hint must be a multiple of full_part_count" - if elwid is not None: - self.elwid = elwid - elif scalar: - self.elwid = scalar_elwid - else: - self.elwid = Signal(elwid_type) - - def __repr__(self): - return (f"SimdScope(\n" - f" simd_full_width_hint={self.simd_full_width_hint},\n" - f" elwid={self.elwid},\n" - f" elwid_type={self.elwid_type},\n" - f" part_counts={self.part_counts},\n" - f" full_part_count={self.full_part_count})")