Source code for hwt.hdl.frameTmplUtils

from typing import Tuple

from hwt.doc_markers import internal
from hwt.hdl.transPart import TransPart
from hwt.hdl.transTmpl import OneOfTransaction


[docs]@internal def iterSort(iterators, cmpFn): """ Sort items from iterators(generators) by alwas selecting item with lowest value (min first) :return: generator of tuples (origin index, item) where origin index is index of iterator in "iterators" from where item commes from """ actual = [] _iterators = [] for i, it in enumerate(iterators): try: a = next(it) _iterators.append((i, it)) actual.append(a) except StopIteration: continue while True: if not _iterators: return elif len(_iterators) == 1: originIndex, it = _iterators[0] yield originIndex, actual[0] for item in it: yield originIndex, item return # select minimum and iterator from where it comes from minimum = None minimumIndex = None secondMin = None for i, val in enumerate(actual): skipSecMinCheck = False if minimum is None: minimum = val minimumIndex = i elif cmpFn(val, minimum): secondMin = minimum minimum = val minimumIndex = i skipSecMinCheck = True elif not skipSecMinCheck and ( secondMin is None or cmpFn(val, secondMin)): secondMin = val actualI, actualIt = _iterators[minimumIndex] while not cmpFn(secondMin, minimum): yield (actualI, minimum) try: minimum = next(actualIt) except StopIteration: minimum = None break # consume from actual iterator while if minimum is None: del _iterators[minimumIndex] del actual[minimumIndex] else: # minimum is not minimum anymore actual[minimumIndex] = minimum
[docs]class TransPartGroup(list): """ Abstract parent class for groups of TransParts """
[docs] def setIsLast(self, val: bool) -> None: self._isLast = val
[docs] def isLastPart(self) -> bool: """ :return: True if this part is last in parts derived from original field else False """ return self._isLast
[docs] def getBusWordBitRange(self) -> Tuple[int, int]: """ :return: bit range which contains data of this part on bus data signal """ offset = self.startOfPart % self.parent.wordWidth return (offset + self.bit_length(), offset)
[docs] def bit_length(self): return self.endOfPart - self.startOfPart
def __repr__(self): return "<%s %s>" % (self.__class__.__name__, list.__repr__(self))
[docs]class ChoicesOfFrameParts(TransPartGroup): """ List of ChoiceOfFrameParts One of ChoiceOfFrameParts is used to represent the word, item depends on context :ivar ~.origin: OneOfTransaction instance :ivar ~.startOfPart: bit addr of start of this group of frame parts :ivar ~.endOfPart: bit addr of end of this group of frame parts :ivar ~._isLast: flag which means this is the last part of original union """
[docs] def __init__(self, startOfPart: int, origin: OneOfTransaction): self.origin = origin self.startOfPart = startOfPart self.endOfPart = None self._isLast = False super(ChoicesOfFrameParts, self).__init__()
[docs] def resolveEnd(self): end = self.startOfPart for items in self: if items: end = max(end, max(itm.endOfPart for itm in items)) self.endOfPart = end
[docs]class ChoiceOfFrameParts(list): """ :ivar ~.origin: ChoicesOfFrameParts instance :ivar ~.tmpl: TransTmpl which was item generated from """
[docs] def __init__(self, origin, tmpl): self.origin = origin self.tmpl = tmpl
def __repr__(self): return "<%s %s>" % (self.__class__.__name__, list.__repr__(self))
[docs]def groupIntoChoices(splitsOnWord, wordWidth: int, origin: OneOfTransaction): """ :param splitsOnWord: list of lists of parts (fields splited on word boundaries) :return: generators of ChoicesOfFrameParts for each word which are not crossing word boundaries """ def cmpWordIndex(a, b): return a.startOfPart // wordWidth < b.startOfPart // wordWidth actual = None itCnt = len(splitsOnWord) for i, item in iterSort(splitsOnWord, cmpWordIndex): _actualW = item.startOfPart // wordWidth if actual is None: # first pass actual = ChoicesOfFrameParts(item.startOfPart, origin) actual.extend( ChoiceOfFrameParts(actual, origin.possibleTransactions[_i]) for _i in range(itCnt)) actualW = _actualW elif _actualW > actualW: actual.resolveEnd() yield actual actual = ChoicesOfFrameParts(item.startOfPart, origin) actual.extend( ChoiceOfFrameParts(actual, origin.possibleTransactions[_i]) for _i in range(itCnt)) actualW = _actualW actual[i].append(item) if actual is not None: actual.setIsLast(True) actual.resolveEnd() yield actual
[docs]class TransTmplWordIterator(): """ Iterator which reinterprets any structure as generator of bits of specified width """
[docs] def __init__(self, wordWidth): self.wordWidth = wordWidth
[docs] def fullWordCnt(self, start: int, end: int): """Count of complete words between two addresses """ assert end >= start, (start, end) gap = max(0, (end - start) - (start % self.wordWidth)) return gap // self.wordWidth
[docs] def groupByWordIndex(self, transaction: 'TransTmpl', offset: int): """ Group transaction parts splited on words to words :param transaction: TransTmpl instance which parts should be grupped into words :return: generator of tuples (wordIndex, list of transaction parts in this word) """ actualW = None partsInWord = [] wordWidth = self.wordWidth for item in self.splitOnWords(transaction, offset): _actualW = item.startOfPart // wordWidth if actualW is None: actualW = _actualW partsInWord.append(item) elif _actualW > actualW: yield (actualW, partsInWord) actualW = _actualW partsInWord = [item, ] else: partsInWord.append(item) if partsInWord: yield (actualW, partsInWord)
[docs] @internal def splitOnWords(self, transaction, addrOffset=0): """ :return: generator of TransPart instance """ wordWidth = self.wordWidth end = addrOffset for tmp in transaction.walkFlatten(offset=addrOffset): if isinstance(tmp, OneOfTransaction): # unions split = [self.splitOnWords(ch, end) for ch in tmp.possibleTransactions] yield from groupIntoChoices(split, wordWidth, tmp) end = addrOffset + tmp.possibleTransactions[0].bitAddrEnd else: # constant size types (base, end), tmpl = tmp startOfPart = base while startOfPart != end: wordIndex = startOfPart // wordWidth endOfWord = (wordIndex + 1) * wordWidth endOfPart = min(endOfWord, end) inFieldOffset = startOfPart - base yield TransPart(self, tmpl, False, startOfPart, endOfPart, inFieldOffset) startOfPart = endOfPart