1 # SPDX-License-Identifier: LGPL-2.1-or-later
2 # See Notices.txt for copyright information
4 from nmutil
.plain_data
import plain_data
5 from nmigen
.hdl
.ast
import Cat
, Const
, Shape
, Signal
, SignalKey
, Value
, ValueKey
6 from nmigen
.hdl
.dsl
import Module
7 from nmigen
.hdl
.ir
import Elaboratable
8 from ieee754
.part
.partsig
import SimdSignal
11 @plain_data(frozen
=True, unsafe_hash
=True)
16 """get the value of this bit as a nmigen `Value`"""
17 raise NotImplementedError("called abstract method")
20 @plain_data(frozen
=True, unsafe_hash
=True)
22 __slots__
= "src", "bit_index"
24 def __init__(self
, src
, bit_index
):
25 if not isinstance(src
, ValueKey
):
27 assert isinstance(bit_index
, int)
28 assert bit_index
in range(len(src
.value
))
30 self
.bit_index
= bit_index
33 """get the value of this bit as a nmigen `Value`"""
34 return self
.src
.value
[self
.bit_index
]
36 def get_assign_target_sig(self
):
37 """get the Signal that assigning to this bit would assign to"""
38 if isinstance(self
.src
.value
, Signal
):
40 raise TypeError("not a valid assignment target")
42 def assign(self
, value
, signals_map
):
43 sig
= self
.get_assign_target_sig()
44 return signals_map
[SignalKey(sig
)][self
.bit_index
].eq(value
)
47 @plain_data(frozen
=True, unsafe_hash
=True)
51 def __init__(self
, bit
):
55 return Const(self
.bit
, 1)
58 @plain_data(frozen
=True)
66 def __init__(self
, bits
=()):
69 assert isinstance(bit
, Bit
)
73 def from_const(value
, width
):
74 return Swizzle(ConstBit((value
& (1 << i
)) != 0) for i
in range(width
))
77 def from_value(value
):
78 value
= Value
.cast(value
)
79 if isinstance(value
, Const
):
80 return Swizzle
.from_const(value
.value
, len(value
))
81 return Swizzle(ValueBit(value
, i
) for i
in range(len(value
)))
84 return Cat(*(bit
.get_value() for bit
in self
.bits
))
87 return self
.bits
[-1] if len(self
.bits
) != 0 else ConstBit(False)
89 def convert_u_to(self
, shape
):
90 shape
= Shape
.cast(shape
)
91 additional
= shape
.width
- len(self
.bits
)
92 self
.bits
[shape
.width
:] = [ConstBit(False)] * additional
94 def convert_s_to(self
, shape
):
95 shape
= Shape
.cast(shape
)
96 additional
= shape
.width
- len(self
.bits
)
97 self
.bits
[shape
.width
:] = [self
.get_sign()] * additional
99 def __getitem__(self
, key
):
100 if isinstance(key
, int):
101 return Swizzle([self
.bits
[key
]])
102 assert isinstance(key
, slice)
103 return Swizzle(self
.bits
[key
])
105 def __add__(self
, other
):
106 if isinstance(other
, Swizzle
):
107 return Swizzle(self
.bits
+ other
.bits
)
108 return NotImplemented
110 def __radd__(self
, other
):
111 if isinstance(other
, Swizzle
):
112 return Swizzle(other
.bits
+ self
.bits
)
113 return NotImplemented
115 def __iadd__(self
, other
):
116 assert isinstance(other
, Swizzle
)
117 self
.bits
+= other
.bits
120 def get_assign_target_sigs(self
):
122 assert isinstance(b
, ValueBit
)
123 yield b
.get_assign_target_sig()
126 @plain_data(frozen
=True)
128 """should be elwid or something similar.
129 importantly, all SimdSignals that are used together must have equal
134 possible_values: FrozenSet[int]
136 __slots__
= "value", "possible_values"
139 def from_simd_signal(simd_signal
):
140 if isinstance(simd_signal
, SwizzledSimdValue
):
141 return simd_signal
.swizzle_key
143 # can't just be PartitionPoints, since those vary between
144 # SimdSignals with different padding
145 raise NotImplementedError("TODO: implement extracting a SwizzleKey "
148 def __init__(self
, value
, possible_values
):
149 self
.value
= ValueKey(value
)
151 shape
= self
.value
.value
.shape()
152 for value
in possible_values
:
153 if isinstance(value
, int):
154 assert value
== Const
.normalize(value
, shape
)
156 value
= Value
.cast(value
)
157 assert isinstance(value
, Const
)
159 pvalues
.append(value
)
160 assert len(pvalues
) != 0, "SwizzleKey can't have zero possible values"
161 self
.possible_values
= frozenset(pvalues
)
164 class ResolveSwizzle(Elaboratable
):
165 def __init__(self
, swizzled_simd_value
):
166 assert isinstance(swizzled_simd_value
, SwizzledSimdValue
)
167 self
.swizzled_simd_value
= swizzled_simd_value
169 def elaborate(self
, platform
):
171 swizzle_key
= self
.swizzled_simd_value
.swizzle_key
172 swizzles
= self
.swizzled_simd_value
.swizzles
173 output
= self
.swizzled_simd_value
.sig
174 with m
.Switch(swizzle_key
.value
):
175 for k
in sorted(swizzle_key
.possible_values
):
176 swizzle
= swizzles
[k
]
178 m
.d
.comb
+= output
.eq(swizzle
.get_value())
182 class AssignSwizzle(Elaboratable
):
183 def __init__(self
, swizzled_simd_value
, src_sig
):
184 assert isinstance(swizzled_simd_value
, SwizzledSimdValue
)
185 self
.swizzled_simd_value
= swizzled_simd_value
186 assert isinstance(src_sig
, Signal
)
187 self
.src_sig
= src_sig
188 self
.converted_src_sig
= Signal
.like(swizzled_simd_value
._sig
_internal
)
189 targets
= swizzled_simd_value
._get
_assign
_target
_sigs
()
190 targets
= sorted({SignalKey(s
) for s
in targets
})
193 return Signal
.like(s
.signal
, name
=f
"outputs_{i}")
194 self
.outputs
= {s
: make_sig(i
, s
) for i
, s
in enumerate(targets
)}
196 def elaborate(self
, platform
):
198 swizzle_key
= self
.swizzled_simd_value
.swizzle_key
199 swizzles
= self
.swizzled_simd_value
.swizzles
200 for k
, v
in self
.outputs
.items():
201 m
.d
.comb
+= v
.eq(k
.signal
)
202 m
.d
.comb
+= self
.converted_src_sig
.eq(self
.src_sig
)
203 with m
.Switch(swizzle_key
.value
):
204 for k
in sorted(swizzle_key
.possible_values
):
205 swizzle
= swizzles
[k
]
207 for index
, bit
in enumerate(swizzle
.bits
):
208 rhs
= self
.converted_src_sig
[index
]
209 assert isinstance(bit
, ValueBit
)
210 m
.d
.comb
+= bit
.assign(rhs
, self
.outputs
)
214 class SwizzledSimdValue(SimdSignal
):
215 """the result of any number of Cat and Slice operations on
216 Signals/SimdSignals. This is specifically intended to support assignment
217 to Cat and Slice, but is also useful for reducing the number of muxes
218 chained together down to a single layer of muxes."""
222 def from_simd_signal(simd_signal
):
223 if isinstance(simd_signal
, SwizzledSimdValue
):
225 assert isinstance(simd_signal
, SimdSignal
)
226 swizzle_key
= SwizzleKey
.from_simd_signal(simd_signal
)
227 swizzle
= Swizzle
.from_value(simd_signal
.sig
)
228 retval
= SwizzledSimdValue(swizzle_key
, swizzle
)
229 retval
.set_module(simd_signal
.m
)
233 def __do_splat(swizzle_key
, value
):
234 """splat a non-simd value, returning a SimdSignal"""
235 raise NotImplementedError("TODO: need splat implementation")
237 def __do_convert_rhs_to_simd_signal_like_self(self
, rhs
):
238 """convert a value to be a SimdSignal of the same layout/shape as self,
239 returning a SimdSignal."""
240 raise NotImplementedError("TODO: need conversion implementation")
243 def from_value(swizzle_key
, value
):
244 if not isinstance(value
, SimdSignal
):
245 value
= SwizzledSimdValue
.__do
_splat
(swizzle_key
, value
)
246 retval
= SwizzledSimdValue
.from_simd_signal(value
)
247 assert swizzle_key
== retval
.swizzle_key
251 def __make_name(cls
):
253 cls
.__next
_id
= id_
+ 1
254 return f
"swizzle_{id_}"
256 def __init__(self
, swizzle_key
, swizzles
):
257 assert isinstance(swizzle_key
, SwizzleKey
)
258 self
.swizzle_key
= swizzle_key
259 possible_keys
= swizzle_key
.possible_values
260 if isinstance(swizzles
, Swizzle
):
261 self
.swizzles
= {k
: swizzles
for k
in possible_keys
}
264 for k
in possible_keys
:
265 swizzle
= swizzles
[k
]
266 assert isinstance(swizzle
, Swizzle
)
267 self
.swizzles
[k
] = swizzle
269 for swizzle
in self
.swizzles
.values():
271 width
= len(swizzle
.bits
)
272 assert width
== len(swizzle
.bits
), \
273 "inconsistent swizzle widths"
274 assert width
is not None
275 self
.__sig
_need
_setup
= False # ignore accesses during __init__
276 super().__init
__(swizzle_key
.value
, width
, name
="output")
277 self
.__sig
_need
_setup
= True
281 # override sig to handle lazily adding the ResolveSwizzle submodule
282 if self
.__sig
_need
_setup
:
283 self
.__sig
_need
_setup
= False
284 submodule
= ResolveSwizzle(self
)
285 setattr(self
.m
.submodules
, self
.__make
_name
(), submodule
)
286 return self
._sig
_internal
289 def sig(self
, value
):
290 assert isinstance(value
, Signal
)
291 self
._sig
_internal
= value
293 def _get_assign_target_sigs(self
):
294 for swizzle
in self
.swizzles
.values():
295 yield from swizzle
.get_assign_target_sigs()
297 def __Assign__(self
, val
, *, src_loc_at
=0):
298 rhs
= self
.__do
_convert
_rhs
_to
_simd
_signal
_like
_self
(val
)
299 assert isinstance(rhs
, SimdSignal
)
300 submodule
= AssignSwizzle(self
, rhs
.sig
)
301 setattr(self
.m
.submodules
, self
.__make
_name
(), submodule
)
302 return [k
.signal
.eq(v
) for k
, v
in submodule
.outputs
.items()]
304 def __Cat__(self
, *args
, src_loc_at
=0):
305 raise NotImplementedError("TODO: implement")
307 def __Slice__(self
, start
, stop
, *, src_loc_at
=0):
308 raise NotImplementedError("TODO: implement")