def toFn(a, b): return SLICE.from_py(slice(a, b, 1))
def __getitem__(self, key): """ [] operator :attention: Table below is for litle endian bit order (MSB:LSB) which is default. This is **reversed** as it is in pure python where it is [0, len(self)]. :attention: slice on slice f signal is automatically reduced to single slice +-----------------------------+----------------------------------------------------------------------------------+ | a[up:low] | items low through up; a[16:8] selects upper byte from 16b vector a | +-----------------------------+----------------------------------------------------------------------------------+ | a[up:] | low is automatically substituted with 0; a[8:] will select lower 8 bits | +-----------------------------+----------------------------------------------------------------------------------+ | a[:end] | up is automatically substituted; a[:8] will select upper byte from 16b vector a | +-----------------------------+----------------------------------------------------------------------------------+ | a[:], a[-1], a[-2:], a[:-2] | raises NotImplementedError (not implemented due to complicated support in hdl) | +-----------+----------------------------------------------------------------------------------------------------+ """ st = self._dtype length = st.bit_length() if length == 1 and not st.force_vector: # assert not indexing on single bit raise TypeError("indexing on single bit") if isinstance(key, slice): key = slice_to_SLICE(key, length) isSLICE = True else: isSLICE = isinstance(key, Slice.getValueCls()) if isSLICE: # :note: downto notation start = key.val.start stop = key.val.stop if key.val.step != -1: raise NotImplementedError() startIsVal = isinstance(start, HValue) stopIsVal = isinstance(stop, HValue) indexesareHValues = startIsVal and stopIsVal else: key = toHVal(key, INT) iamVal = isinstance(self, HValue) iAmResultOfIndexing = (not iamVal and len(self.drivers) == 1 and isinstance(self.origin, Operator) and self.origin.operator == AllOps.INDEX) Bits = self._dtype.__class__ if isSLICE: if indexesareHValues and start.val == length and stop.val == 0: # selecting all bits no conversion needed return self if iAmResultOfIndexing: # try reduce self and parent slice to one original, parentIndex = self.origin.operands if isinstance(parentIndex._dtype, Slice): parentLower = parentIndex.val.stop start = start + parentLower stop = stop + parentLower return original[start:stop] # check start boundaries if startIsVal: _start = int(start) if _start < 0 or _start > length: raise IndexError(_start, length) # check end boundaries if stopIsVal: _stop = int(stop) if _stop < 0 or _stop > length: raise IndexError(_stop, length) # check width of selected range if startIsVal and stopIsVal and _start - _stop <= 0: raise IndexError(_start, _stop) if iamVal: if isinstance(key, SLICE.getValueCls()): key = key.val v = Bits3val.__getitem__(self, key) if v._dtype.bit_length() == 1 and not v._dtype.force_vector: assert v._dtype is not self._dtype v._dtype.force_vector = True return v else: key = SLICE.from_py(slice(start, stop, -1)) _resWidth = start - stop resT = Bits(bit_length=_resWidth, force_vector=True, signed=st.signed, negated=st.negated) elif isinstance(key, Bits.getValueCls()): if key._is_full_valid(): # check index range _v = int(key) if _v < 0 or _v > length - 1: raise IndexError(_v) if iAmResultOfIndexing: original, parentIndex = self.origin.operands if isinstance(parentIndex._dtype, Slice): parentLower = parentIndex.val.stop return original[parentLower + _v] if iamVal: return Bits3val.__getitem__(self, key) resT = BIT elif isinstance(key, RtlSignalBase): t = key._dtype if isinstance(t, Slice): resT = Bits(bit_length=key.staticEval()._size(), force_vector=True, signed=st.signed, negated=st.negated) elif isinstance(t, Bits): resT = BIT else: raise TypeError("Index operation not implemented" " for index of type %r" % (t)) else: raise TypeError("Index operation not implemented for index %r" % (key)) if st.negated and resT is BIT: resT = BIT_N return Operator.withRes(AllOps.INDEX, [self, key], resT)
def downtoFn(a, b): return SLICE.from_py(slice(a, b, -1))
def resolve_final_parts_from_splitpoints_and_parts(signal_parts): # :type: Dict[RtlSignal, Dict[Tuple[Tuple[int, int], ...], Union[HValue, RtlSignal]]] final_signal_parts = {} # split part intervals to non-overlapping chunks for s, parts in sorted(signal_parts.items(), key=lambda x: RtlSignal_sort_key(x[0])): split_point = resolve_splitpoints(s, parts) split_point = sorted(split_point) # prepare part signals new_parts = [] new_parts_dict = {} split_i = 0 end = 0 # :attention: parts are likely to contain parts with same indexes for indexes, can_directly_replace_with_src_expr, src in sorted( parts, key=lambda x: x[0]): if len(indexes) != 1: raise NotImplementedError() i = indexes[0] split_p = split_point[split_i] if isinstance(i, BitsVal): low = int(i) high = low + 1 index_key = ((high, low), ) else: assert isinstance(i, SliceVal), (s, i) if i.val.step != -1: raise NotImplementedError(s, i) high, low = int(i.val.start), int(i.val.stop) index_key = ((high, low), ) while split_p < low: # some parts at the beginning are skiped # that means that that part is not driven by anything # and we need to check default and nop value part_indexes = (SLICE.from_py(slice(low, split_p, -1)), ) _src = construct_tmp_dst_sig_for_slice(s, part_indexes, None, False) new_parts.append(_src) _index_key = ((low, split_p), ) new_parts_dict[_index_key] = _src, True split_i += 1 split_p = split_point[split_i] this_start_split_p_i = split_i if split_p > low: # some parts at the beginning were already resolved # This can happen if there was some part which started on some <= index and overlaps with this part. try: _, _can_directly_replace_with_src_expr = new_parts_dict[ index_key] assert not _can_directly_replace_with_src_expr, (s, index_key) # was already resolved and checked no need to check it again continue except KeyError: pass for i in range(split_i, -1, -1): _sp = split_point[i] if _sp == low: this_start_split_p_i = i assert split_point[this_start_split_p_i] == low # just at the start of this slice next_split_p = split_point[this_start_split_p_i + 1] assert next_split_p <= high, "The next split point can be at most end of current part" if next_split_p == high: assert this_start_split_p_i == split_i, "We should see this part for the first time or the split_i should already be higher" # all bits on this slice are alwyas driven at once, we can instantiate whole part assert split_p == low _src = construct_tmp_dst_sig_for_slice( s, indexes, src, not can_directly_replace_with_src_expr) new_parts.append(_src) assert index_key not in new_parts_dict, (s, index_key) new_parts_dict[ index_key] = _src, can_directly_replace_with_src_expr split_i += 1 else: # list of part keys for later search _split_parts = [] prev_sp = split_point[this_start_split_p_i] dst_offset = low assert not can_directly_replace_with_src_expr # continue instanciating parts until we reach the end of this part for sp_i, sp in zip( range(this_start_split_p_i + 1, len(split_point)), islice(split_point, this_start_split_p_i + 1, None)): # need to generate sub slice # because this slice has actually multiple individualy driven parts # we need to generate all slice parts because there could be a case where only some sub parts are # driven elsewhere and we would othervise resolve those segments as a constantly driven # but they are in fact driven from this slice if sp > high: break part_key = ((sp, prev_sp), ) if sp_i <= split_i: # check if the slice is not driven from some top level constant assignment # which would result is multiple drivers of this slice assert src is None existing_part, _can_directly_replace_with_src_expr = new_parts_dict[ part_key] assert not _can_directly_replace_with_src_expr, ( s, low, high, existing_part) assert not can_directly_replace_with_src_expr, ( s, low, high, existing_part) assert isinstance(existing_part, RtlSignal), (s, low, high, existing_part) else: assert sp_i == split_i + 1, (s, sp_i, split_i) # get actual input signal if src is None: _src = None else: _src = src[sp - dst_offset:prev_sp - dst_offset] part_indexes = (SLICE.from_py(slice(sp, prev_sp, -1)), ) _src = construct_tmp_dst_sig_for_slice( s, part_indexes, _src, True) new_parts.append(_src) new_parts_dict[ part_key] = _src, can_directly_replace_with_src_expr split_i += 1 _split_parts.append(part_key) prev_sp = sp new_parts_dict[index_key] = _split_parts, False end = max(end, high) if end < split_point[-1]: # something unconnected at the end high, low = split_point[-1], end part_indexes = (SLICE.from_py(slice(high, low, -1)), ) _src = construct_tmp_dst_sig_for_slice(s, part_indexes, None, False) new_parts.append(_src) index_key = ((high, low), ) new_parts_dict[index_key] = _src, True # construct assignment of concatenation from all parts assert new_parts, (s, parts) s(Concat(*reversed(new_parts))) final_signal_parts[s] = new_parts_dict return final_signal_parts