1 # SPDX-License-Identifier: LGPL-3-or-later
2 # See Notices.txt for copyright information
5 from ieee754
.part
.util
import (DEFAULT_FP_PART_COUNTS
,
6 DEFAULT_INT_PART_COUNTS
,
7 FpElWid
, IntElWid
, SimdMap
)
8 from nmigen
.hdl
.ast
import Signal
12 """The global scope object for SimdSignal and friends
15 * part_counts: SimdMap
16 a map from `ElWid` values `k` to the number of parts in an element
17 when `self.elwid == k`. Values should be minimized, since higher values
18 often create bigger circuits.
21 # here, an I8 element is 1 part wide
22 part_counts = {ElWid.I8: 1, ElWid.I16: 2, ElWid.I32: 4, ElWid.I64: 8}
25 # here, an F16 element is 1 part wide
26 part_counts = {ElWid.F16: 1, ElWid.BF16: 1, ElWid.F32: 2, ElWid.F64: 4}
27 * simd_full_width_hint: int
28 the default value for SimdLayout's full_width argument, the full number
29 of bits in a SIMD value.
30 * elwid: ElWid or nmigen Value with a shape of some ElWid class
31 the current elwid (simd element type)
38 """get the current SimdScope.
41 SimdScope.get(None) is None
42 SimdScope.get() raises ValueError
43 with SimdScope(...) as s:
46 if len(cls
.__SCOPE
_STACK
) > 0:
47 retval
= cls
.__SCOPE
_STACK
[-1]
48 assert isinstance(retval
, SimdScope
), "inconsistent scope stack"
50 raise ValueError("not in a `with SimdScope()` statement")
53 self
.__SCOPE
_STACK
.append(self
)
56 def __exit__(self
, exc_type
, exc_value
, traceback
):
57 assert self
.__SCOPE
_STACK
.pop() is self
, "inconsistent scope stack"
60 def __init__(self
, *, simd_full_width_hint
=64, elwid
=None,
61 part_counts
=None, elwid_type
=IntElWid
, scalar
=False):
62 # TODO: add more arguments/members and processing for integration with
63 self
.simd_full_width_hint
= simd_full_width_hint
64 if isinstance(elwid
, (IntElWid
, FpElWid
)):
65 elwid_type
= type(elwid
)
66 if part_counts
is None:
67 part_counts
= SimdMap({elwid
: 1})
68 assert issubclass(elwid_type
, (IntElWid
, FpElWid
))
69 self
.elwid_type
= elwid_type
70 scalar_elwid
= elwid_type(0)
71 if part_counts
is None:
73 part_counts
= SimdMap({scalar_elwid
: 1})
74 elif issubclass(elwid_type
, FpElWid
):
75 part_counts
= DEFAULT_FP_PART_COUNTS
77 part_counts
= DEFAULT_INT_PART_COUNTS
79 def check(elwid
, part_count
):
80 assert type(elwid
) == elwid_type
, "inconsistent ElWid types"
81 part_count
= int(part_count
)
82 assert part_count
!= 0 and (part_count
& (part_count
- 1)) == 0,\
83 "part_counts values must all be powers of two"
86 self
.part_counts
= SimdMap
.map_with_elwid(check
, part_counts
)
87 self
.full_part_count
= max(part_counts
.values())
88 assert self
.simd_full_width_hint
% self
.full_part_count
== 0,\
89 "simd_full_width_hint must be a multiple of full_part_count"
93 self
.elwid
= scalar_elwid
95 self
.elwid
= Signal(elwid_type
)
98 return (f
"SimdScope(\n"
99 f
" simd_full_width_hint={self.simd_full_width_hint},\n"
100 f
" elwid={self.elwid},\n"
101 f
" elwid_type={self.elwid_type},\n"
102 f
" part_counts={self.part_counts},\n"
103 f
" full_part_count={self.full_part_count})")