raise TypeError # :nocov:
def _prepare_value_for_Slice(self, value):
- if isinstance(value, (ast.Signal, ast.Slice, ast.Cat)):
+ if isinstance(value, (ast.Signal, ast.Slice, ast._InternalCat)):
sigspec = self(value)
else:
sigspec = self.s.rtlil.wire(len(value), src=_src(value.src_loc))
return wire_next or wire_curr
def _prepare_value_for_Slice(self, value):
- assert isinstance(value, (ast.Signal, ast.Slice, ast.Cat))
+ assert isinstance(value, (ast.Signal, ast.Slice, ast._InternalCat))
return self(value)
def on_Part(self, value):
"Shape", "signed", "unsigned",
"Value", "Const", "C", "AnyConst", "AnySeq", "Operator", "Mux", "Part", "Slice", "Cat", "Repl",
"Array", "ArrayProxy",
- "_InternalSwitch", "_InternalAssign", "_InternalRepl",
+ "_InternalSwitch", "_InternalAssign", "_InternalRepl", "_InternalCat",
"Signal", "ClockSignal", "ResetSignal",
"UserValue", "ValueCastable",
"Sample", "Past", "Stable", "Rose", "Fell", "Initial",
def __Repl__(self, count, *, src_loc_at=0):
return _InternalRepl(self, count, src_loc_at=src_loc_at)
+ def __Cat__(self, *args, src_loc_at=0):
+ args = [self] + list(args)
+ return _InternalCat(*args, src_loc_at=src_loc_at)
+
def __Mux__(self, val1, val0):
return _InternalMux(self, val1, val0)
@final
-class Cat(Value):
+def Cat(*args, src_loc_at=0):
+ """Concatenate values.
+
+ Behaviour is required to be identical to _InternalCat.
+ The first argument "defines" the way that all others are
+ handled. If the first argument is derived from UserValue,
+ it is not downcast to a type Value because doing so would
+ lose the opportunity for "redirection" (Value.__Cat__ would
+ always be called).
+ """
+ # flatten the args and convert to tuple (not a generator)
+ args = tuple(flatten(args))
+ # check if there are no arguments (zero-length Signal).
+ if len(args) == 0:
+ return _InternalCat(*args, src_loc_at=src_loc_at)
+ # determine if the first is a UserValue.
+ if isinstance(args[0], UserValue):
+ first = args[0] # take UserValue directly, do not downcast
+ else:
+ first = Value.cast(args[0]) # ok to downcast to Value
+ # all other arguments are safe to downcast to Value
+ rest = [Value.cast(v) for v in flatten(args[1:])]
+ # assume first item defines the "handling" for all others
+ return first.__Cat__(*rest, src_loc_at=src_loc_at)
+
+
+class _InternalCat(Value):
"""Concatenate values.
Form a compound ``Value`` from several smaller ones by concatenation.
elif isinstance(self.value, Part):
self._hash = hash((ValueKey(self.value.value), ValueKey(self.value.offset),
self.value.width, self.value.stride))
- elif isinstance(self.value, Cat):
+ elif isinstance(self.value, _InternalCat):
self._hash = hash(tuple(ValueKey(o) for o in self.value.parts))
elif isinstance(self.value, ArrayProxy):
self._hash = hash((ValueKey(self.value.index),
ValueKey(self.value.offset) == ValueKey(other.value.offset) and
self.value.width == other.value.width and
self.value.stride == other.value.stride)
- elif isinstance(self.value, Cat):
+ elif isinstance(self.value, _InternalCat):
return all(ValueKey(a) == ValueKey(b)
for a, b in zip(self.value.parts, other.value.parts))
elif isinstance(self.value, ArrayProxy):